diff --git a/.editorconfig b/.editorconfig index 40381bd6a77..f00ed01c2e3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,6 @@ trim_trailing_whitespace = true # The indent size used in the `package.json` file cannot be changed # https://github.com/npm/npm/pull/3180#issuecomment-16336516 -[{.travis.yml,npm-shrinkwrap.json,package.json}] +[{*.yml,*.yaml,npm-shrinkwrap.json,package.json}] indent_style = space indent_size = 2 diff --git a/.github/classifier.yml b/.github/classifier.yml index b3199eb0752..50c280cf4bf 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -6,40 +6,40 @@ accessibility: [], api: [], css-less-sass: [], - debug: [ isidorn ], - editor: [ alexandrudima ], + debug: [ weinand ], + editor: [], editor-brackets: [], - editor-clipboard: [ rebornix ], + editor-clipboard: [], editor-colors: [], - editor-contrib: [ rebornix ], + editor-contrib: [], editor-core: [], - editor-find-widget: [ rebornix ], + editor-find-widget: [], editor-folding: [], - editor-ime: [ rebornix ], - editor-indentation: [ rebornix ], + editor-ime: [], + editor-indentation: [], editor-input: [], editor-minimap: [], editor-multicursor: [], editor-wrapping: [], emmet: [ ramya-rao-a ], error-list: [], - extensions: [], git: [ joaomoreno ], hot-exit: [ Tyriar ], - html: [], + html: [ aeschli ], i18n: [], install-update: [], integrated-terminal: [ Tyriar ], javascript: [ mjbvz ], json: [], languages basic: [], - markdown: [], + markdown: [ mjbvz ], + merge-conflict: [ chrmarti ], perf-profile: [], php: [ roblourens ], search: [ roblourens ], snippets: [ jrieken ], - tasks: [], + tasks: [ dbaeumer ], typescript: [ mjbvz ], - workbench: [], + workbench: [ bpasero, isidorn, sandy081] } } diff --git a/.github/new_release.yml b/.github/new_release.yml index 790633b1f1f..e54d1a8aba0 100644 --- a/.github/new_release.yml +++ b/.github/new_release.yml @@ -1,5 +1,5 @@ { newReleaseLabel: 'new release', - newReleases: ['1.15'], - perform: true + newReleases: ['1.17.2'], + perform: false } \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index b552f3ee567..70cdee4c6f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,14 @@ os: - linux - osx +cache: + directories: + - $HOME/.npm + notifications: email: false + webhooks: + - http://vscode-test-probot.westus.cloudapp.azure.com:3450/travis/notifications addons: apt: @@ -27,24 +33,26 @@ before_install: - git submodule update --init --recursive - git clone --depth 1 https://github.com/creationix/nvm.git ./.nvm - source ./.nvm/nvm.sh - - nvm install 7.4.0 - - nvm use 7.4.0 + - nvm install 7.9.0 + - nvm use 7.9.0 - npm config set python `which python` - - npm install -g gulp - if [ $TRAVIS_OS_NAME == "linux" ]; then export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0; sh -e /etc/init.d/xvfb start; sleep 3; fi + # Make npm logs less verbose + - npm config set depth 0 + - npm config set loglevel warn install: - ./scripts/npm.sh install script: - - gulp hygiene --silent - - gulp electron --silent - - gulp compile --silent --max_old_space_size=4096 - - gulp optimize-vscode --silent --max_old_space_size=4096 + - node_modules/.bin/gulp hygiene + - node_modules/.bin/gulp electron --silent + - node_modules/.bin/gulp compile --silent --max_old_space_size=4096 + - node_modules/.bin/gulp optimize-vscode --silent --max_old_space_size=4096 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./scripts/test.sh --coverage --reporter dot; else ./scripts/test.sh --reporter dot; fi - ./scripts/test-integration.sh diff --git a/.vscode/launch.json b/.vscode/launch.json index 5665ba67416..efe1edad82e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,12 +6,12 @@ "type": "node", "request": "launch", "name": "Gulp Build", - "program": "${workspaceRoot}/node_modules/gulp/bin/gulp.js", + "program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js", "stopOnEntry": true, "args": [ "watch-extension:json-client" ], - "cwd": "${workspaceRoot}" + "cwd": "${workspaceFolder}" }, { "type": "node", @@ -21,7 +21,7 @@ "port": 5870, "restart": true, "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -31,7 +31,7 @@ "protocol": "inspector", "port": 5871, "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -41,7 +41,7 @@ "name": "Attach to Search Process", "port": 5876, "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -51,7 +51,7 @@ "protocol": "inspector", "port": 5874, "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -61,7 +61,7 @@ "protocol": "inspector", "port": 5875, "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -70,12 +70,12 @@ "name": "VS Code Emmet Tests", "runtimeExecutable": "${execPath}", "args": [ - "${workspaceRoot}/extensions/emmet/test-fixtures", - "--extensionDevelopmentPath=${workspaceRoot}/extensions/emmet", - "--extensionTestsPath=${workspaceRoot}/extensions/emmet/out/test" + "${workspaceFolder}/extensions/emmet/test-fixtures", + "--extensionDevelopmentPath=${workspaceFolder}/extensions/emmet", + "--extensionTestsPath=${workspaceFolder}/extensions/emmet/out/test" ], "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -84,12 +84,12 @@ "name": "VS Code API Tests", "runtimeExecutable": "${execPath}", "args": [ - "${workspaceRoot}/extensions/vscode-api-tests/testWorkspace", - "--extensionDevelopmentPath=${workspaceRoot}/extensions/vscode-api-tests", - "--extensionTestsPath=${workspaceRoot}/extensions/vscode-api-tests/out" + "${workspaceFolder}/extensions/vscode-api-tests/testWorkspace", + "--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode-api-tests", + "--extensionTestsPath=${workspaceFolder}/extensions/vscode-api-tests/out" ], "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -98,12 +98,12 @@ "name": "VS Code Tokenizer Tests", "runtimeExecutable": "${execPath}", "args": [ - "${workspaceRoot}/extensions/vscode-colorize-tests/test", - "--extensionDevelopmentPath=${workspaceRoot}/extensions/vscode-colorize-tests", - "--extensionTestsPath=${workspaceRoot}/extensions/vscode-colorize-tests/out" + "${workspaceFolder}/extensions/vscode-colorize-tests/test", + "--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode-colorize-tests", + "--extensionTestsPath=${workspaceFolder}/extensions/vscode-colorize-tests/out" ], "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { @@ -117,30 +117,30 @@ "request": "launch", "name": "Launch VS Code", "windows": { - "runtimeExecutable": "${workspaceRoot}/scripts/code.bat" + "runtimeExecutable": "${workspaceFolder}/scripts/code.bat" }, "osx": { - "runtimeExecutable": "${workspaceRoot}/scripts/code.sh" + "runtimeExecutable": "${workspaceFolder}/scripts/code.sh" }, "linux": { - "runtimeExecutable": "${workspaceRoot}/scripts/code.sh" + "runtimeExecutable": "${workspaceFolder}/scripts/code.sh" }, "urlFilter": "*index.html*", "runtimeArgs": [ "--inspect=5875" ], - "webRoot": "${workspaceRoot}" + "webRoot": "${workspaceFolder}" }, { "type": "node", "request": "launch", "name": "Git Unit Tests", "protocol": "inspector", - "program": "${workspaceRoot}/extensions/git/node_modules/mocha/bin/_mocha", + "program": "${workspaceFolder}/extensions/git/node_modules/mocha/bin/_mocha", "stopOnEntry": false, - "cwd": "${workspaceRoot}/extensions/git", + "cwd": "${workspaceFolder}/extensions/git", "outFiles": [ - "${workspaceRoot}/extensions/git/out/**/*.js" + "${workspaceFolder}/extensions/git/out/**/*.js" ] }, { @@ -148,38 +148,38 @@ "request": "launch", "name": "Unit Tests", "protocol": "inspector", - "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", - "runtimeExecutable": "${workspaceRoot}/.build/electron/Code - OSS.app/Contents/MacOS/Electron", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "runtimeExecutable": "${workspaceFolder}/.build/electron/Code - OSS.app/Contents/MacOS/Electron", "windows": { - "runtimeExecutable": "${workspaceRoot}/.build/electron/Code - OSS.exe" + "runtimeExecutable": "${workspaceFolder}/.build/electron/Code - OSS.exe" }, "linux": { - "runtimeExecutable": "${workspaceRoot}/.build/electron/code-oss" + "runtimeExecutable": "${workspaceFolder}/.build/electron/code-oss" }, "stopOnEntry": false, "args": [ "--timeout", "2000" ], - "cwd": "${workspaceRoot}", + "cwd": "${workspaceFolder}", "env": { "ELECTRON_RUN_AS_NODE": "true" }, "outFiles": [ - "${workspaceRoot}/out/**/*.js" + "${workspaceFolder}/out/**/*.js" ] }, { "type": "node", "request": "launch", "name": "Launch Smoke Test", - "program": "${workspaceRoot}/test/smoke/out/main.js", - "cwd": "${workspaceRoot}/test/smoke", + "program": "${workspaceFolder}/test/smoke/out/main.js", + "cwd": "${workspaceFolder}/test/smoke", "timeout": 240000, "port": 9999, "args": [ "-l", - "${workspaceRoot}/.build/electron/Code - OSS.app/Contents/MacOS/Electron" + "${workspaceFolder}/.build/electron/Code - OSS.app/Contents/MacOS/Electron" ], "outFiles": [ "${cwd}/out/**/*.js" diff --git a/.vscode/settings.json b/.vscode/settings.json index 39adc0e7f24..0d85ac560db 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,9 @@ "**/node_modules": true, "**/bower_components": true, ".build/**": true, - "out*/**": true, + "out/**": true, + "out-build/**": true, + "out-vscode/**": true, "i18n/**": true, "extensions/**/out/**": true, "test/smoke/out/**": true @@ -27,9 +29,9 @@ "lcov.watch": [ { "pattern": "**/*.test.js", - "command": "${workspaceRoot}/scripts/test.sh --coverage --run ${file}", + "command": "${workspaceFolder}/scripts/test.sh --coverage --run ${file}", "windows": { - "command": "${workspaceRoot}\\scripts\\test.bat --coverage --run ${file}" + "command": "${workspaceFolder}\\scripts\\test.bat --coverage --run ${file}" } } ] diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 45d4995aa65..2239597b1f3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -33,11 +33,11 @@ "task": "tslint", "label": "Run tslint", "problemMatcher": [ - "$tslint4" + "$tslint5" ] }, { - "taskName": "Run tests", + "label": "Run tests", "type": "shell", "command": "./scripts/test.sh", "windows": { @@ -50,7 +50,7 @@ } }, { - "taskName": "Run Dev", + "label": "Run Dev", "type": "shell", "command": "./scripts/code.sh", "windows": { diff --git a/README.md b/README.md index 670195c3c92..5ea45fe3c75 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ a code editor with what developers need for their core edit-build-debug cycle. Code provides comprehensive editing and debugging support, an extensibility model, and lightweight integration with existing tools. -VS Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [VS Code's website](https://code.visualstudio.com/Download). To get the latest releases everyday, you can install the [Insiders version of VS Code](https://code.visualstudio.com/insiders). This builds from the master branch and is updated at least daily. +VS Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [VS Code's website](https://code.visualstudio.com/Download). To get the latest releases every day, you can install the [Insiders version of VS Code](https://code.visualstudio.com/insiders). This builds from the master branch and is updated at least daily.

VS Code in action @@ -30,6 +30,7 @@ please see the document [How to Contribute](https://github.com/Microsoft/vscode/ * [The development workflow, including debugging and running tests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#development-workflow) * [Coding Guidelines](https://github.com/Microsoft/vscode/wiki/Coding-Guidelines) * [Submitting pull requests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#pull-requests) +* [Contributing to translations](https://aka.ms/vscodeloc) Please see also our [Code of Conduct](CODE_OF_CONDUCT.md). diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index f34e2aaf808..4a73d4a61eb 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -26,42 +26,41 @@ This project incorporates components from the projects listed below. The origina 19. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) 20. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) 21. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) -22. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) -23. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) -24. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) -25. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) -26. language-docker (https://github.com/moby/moby) -27. language-go version 0.39.0 (https://github.com/atom/language-go) -28. language-less (https://github.com/atom/language-less) -29. language-php (https://github.com/atom/language-php) -30. language-rust version 0.4.9 (https://github.com/zargony/atom-language-rust) -31. MagicStack/MagicPython (https://github.com/MagicStack/MagicPython) -32. Microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/Microsoft/TypeScript-TmLanguage) -33. octicons-code version 3.1.0 (https://octicons.github.com) -34. octicons-font version 3.1.0 (https://octicons.github.com) -35. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) -36. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) -37. string_scorer version 0.1.20 (https://github.com/joshaven/string_score) -38. sublimehq/Packages (https://github.com/sublimehq/Packages) -39. SublimeText/PowerShell (https://github.com/SublimeText/PowerShell) -40. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) -41. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) -42. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) -43. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) -44. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) -45. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) -46. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) -47. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) -48. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) -49. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) -50. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) -51. textmate/r.tmbundle (https://github.com/textmate/r.tmbundle) +22. Ikuyadeu/vscode-R (https://github.com/Ikuyadeu/vscode-R) +23. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) +24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) +25. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) +26. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) +27. language-docker (https://github.com/moby/moby) +28. language-go version 0.39.0 (https://github.com/atom/language-go) +29. language-less (https://github.com/atom/language-less) +30. language-php (https://github.com/atom/language-php) +31. language-rust version 0.4.9 (https://github.com/zargony/atom-language-rust) +32. MagicStack/MagicPython (https://github.com/MagicStack/MagicPython) +33. Microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/Microsoft/TypeScript-TmLanguage) +34. Microsoft/vscode-mssql (https://github.com/Microsoft/vscode-mssql) +35. octicons-code version 3.1.0 (https://octicons.github.com) +36. octicons-font version 3.1.0 (https://octicons.github.com) +37. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) +38. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) +39. sublimehq/Packages (https://github.com/sublimehq/Packages) +40. SublimeText/PowerShell (https://github.com/SublimeText/PowerShell) +41. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) +42. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) +43. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) +44. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) +45. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) +46. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) +47. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) +48. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) +49. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) +50. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) +51. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) 52. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) 53. textmate/shellscript.tmbundle (https://github.com/textmate/shellscript.tmbundle) -54. textmate/sql.tmbundle (https://github.com/textmate/sql.tmbundle) -55. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) -56. TypeScript-TmLanguage version 0.1.8 (https://github.com/Microsoft/TypeScript-TmLanguage) -57. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) +54. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) +55. TypeScript-TmLanguage version 0.1.8 (https://github.com/Microsoft/TypeScript-TmLanguage) +56. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) %% atom/language-c NOTICES AND INFORMATION BEGIN HERE @@ -694,6 +693,32 @@ without specific, written prior permission. Title to copyright in this document ========================================= END OF HTML 5.1 W3C Working Draft NOTICES AND INFORMATION +%% Ikuyadeu/vscode-R NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2017 Yuki Ueda + +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. +========================================= +END OF Ikuyadeu/vscode-R NOTICES AND INFORMATION + %% Ionic documentation NOTICES AND INFORMATION BEGIN HERE ========================================= Copyright Drifty Co. http://drifty.com/. @@ -1238,187 +1263,46 @@ END OF MagicStack/MagicPython NOTICES AND INFORMATION %% Microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE ========================================= -Copyright (c) Microsoft Corporation. All rights reserved. +Copyright (c) Microsoft Corporation +All rights reserved. - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +MIT License - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +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: - 1. Definitions. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND 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. ========================================= END OF Microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION +%% Microsoft/vscode-mssql NOTICES AND INFORMATION BEGIN HERE +========================================= +------------------------------------------ START OF LICENSE ----------------------------------------- +vscode-mssql +Copyright (c) Microsoft Corporation +All rights reserved. +MIT License +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 Sanjay Nagamangalam +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. +----------------------------------------------- END OF LICENSE ------------------------------------------ +========================================= +END OF Microsoft/vscode-mssql NOTICES AND INFORMATION + %% octicons-code NOTICES AND INFORMATION BEGIN HERE ========================================= The MIT License (MIT) @@ -1587,31 +1471,6 @@ SOFTWARE. ========================================= END OF shaders-tmLanguage NOTICES AND INFORMATION -%% string_scorer NOTICES AND INFORMATION BEGIN HERE -========================================= -This software is released under the MIT license: - -Copyright (c) Joshaven Potter - -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. -========================================= -END OF string_scorer NOTICES AND INFORMATION - %% sublimehq/Packages NOTICES AND INFORMATION BEGIN HERE ========================================= Copyright (c) Sublime Packages project authors @@ -1851,19 +1710,6 @@ to the base-name name of the original file, and an extension of txt, html, or si ========================================= END OF textmate/perl.tmbundle NOTICES AND INFORMATION -%% textmate/r.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-r.tmbundle project authors - -If not otherwise specified (see below), files in this folder fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. -========================================= -END OF textmate/r.tmbundle NOTICES AND INFORMATION - %% textmate/ruby.tmbundle NOTICES AND INFORMATION BEGIN HERE ========================================= Copyright (c) textmate-ruby.tmbundle project authors @@ -1900,24 +1746,6 @@ to the base-name name of the original file, and an extension of txt, html, or si ========================================= END OF textmate/shellscript.tmbundle NOTICES AND INFORMATION -%% textmate/sql.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-sql.tmbundle project authors - -If not otherwise specified (see below), files in this folder fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/sql.tmbundle NOTICES AND INFORMATION - %% textmate/yaml.tmbundle NOTICES AND INFORMATION BEGIN HERE ========================================= Copyright (c) 2015 FichteFoll @@ -1943,184 +1771,28 @@ END OF textmate/yaml.tmbundle NOTICES AND INFORMATION %% TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE ========================================= -Copyright (c) Microsoft Corporation. All rights reserved. +Copyright (c) Microsoft Corporation +All rights reserved. - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +MIT License - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +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: - 1. Definitions. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND 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. ========================================= END OF TypeScript-TmLanguage NOTICES AND INFORMATION diff --git a/appveyor.yml b/appveyor.yml index 49e80fed313..5c5c23c776a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,14 +2,16 @@ environment: ELECTRON_RUN_AS_NODE: 1 VSCODE_BUILD_VERBOSE: true +cache: + - '%APPDATA%\npm-cache' + install: - - ps: Install-Product node 7.4.0 x64 + - ps: Install-Product node 7.9.0 x64 - npm install -g npm@4 --silent - - npm install -g gulp mocha --silent build_script: - .\scripts\npm.bat install - - gulp electron + - .\node_modules\.bin\gulp electron - npm run compile test_script: diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 97b1ab8367e..056dc86065e 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -12,6 +12,7 @@ const gulptslint = require('gulp-tslint'); const gulpeslint = require('gulp-eslint'); const tsfmt = require('typescript-formatter'); const tslint = require('tslint'); +const vfs = require('vinyl-fs'); /** * Hygiene works by creating cascading subsets of all our files and @@ -54,6 +55,7 @@ const indentationFilter = [ '!**/*.md', '!**/*.ps1', '!**/*.template', + '!**/*.yaml', '!**/*.yml', '!**/lib/**', '!extensions/**/*.d.ts', @@ -93,6 +95,7 @@ const copyrightFilter = [ '!**/*.opts', '!**/*.disabled', '!build/**/*.init', + '!resources/linux/snap/snapcraft.yaml', '!resources/win32/bin/code.js', '!extensions/markdown/media/tomorrow.css', '!extensions/html/server/src/modes/typescript/*' @@ -120,7 +123,8 @@ const tslintFilter = [ '!**/node_modules/**', '!extensions/typescript/test/colorize-fixtures/**', '!extensions/vscode-api-tests/testWorkspace/**', - '!extensions/**/*.test.ts' + '!extensions/**/*.test.ts', + '!extensions/html/server/lib/jquery.d.ts' ]; const copyrightHeader = [ @@ -130,19 +134,8 @@ const copyrightHeader = [ ' *--------------------------------------------------------------------------------------------*/' ].join('\n'); -function reportFailures(failures) { - failures.forEach(failure => { - const name = failure.name || failure.fileName; - const position = failure.startPosition; - const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line; - const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character; - - console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`); - }); -} - gulp.task('eslint', () => { - return gulp.src(all, { base: '.' }) + return vfs.src(all, { base: '.', follow: true, allowEmpty: true }) .pipe(filter(eslintFilter)) .pipe(gulpeslint('src/.eslintrc')) .pipe(gulpeslint.formatEach('compact')) @@ -150,12 +143,12 @@ gulp.task('eslint', () => { }); gulp.task('tslint', () => { - const options = { summarizeFailureOutput: true }; + const options = { emitError: false }; - return gulp.src(all, { base: '.' }) + return vfs.src(all, { base: '.', follow: true, allowEmpty: true }) .pipe(filter(tslintFilter)) .pipe(gulptslint({ rulesDirectory: 'build/lib/tslint' })) - .pipe(gulptslint.report(reportFailures, options)); + .pipe(gulptslint.report(options)); }); const hygiene = exports.hygiene = (some, options) => { @@ -216,6 +209,17 @@ const hygiene = exports.hygiene = (some, options) => { cb(err); }); }); + + function reportFailures(failures) { + failures.forEach(failure => { + const name = failure.name || failure.fileName; + const position = failure.startPosition; + const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line; + const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character; + + console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`); + }); + } const tsl = es.through(function (file) { const configuration = tslint.Configuration.findConfiguration(null, '.'); @@ -233,7 +237,7 @@ const hygiene = exports.hygiene = (some, options) => { this.emit('data', file); }); - const result = gulp.src(some || all, { base: '.' }) + const result = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true }) .pipe(filter(f => !f.stat.isDirectory())) .pipe(filter(eolFilter)) .pipe(options.skipEOL ? es.through() : eol) @@ -253,8 +257,16 @@ const hygiene = exports.hygiene = (some, options) => { .pipe(gulpeslint.formatEach('compact')) .pipe(gulpeslint.failAfterError()); + let count = 0; return es.merge(typescript, javascript) - .pipe(es.through(null, function () { + .pipe(es.through(function (data) { + count++; + if (count % 10 === 0) { + process.stdout.write('.'); + } + this.emit('data', data); + }, function () { + process.stdout.write('\n'); if (errorCount > 0) { this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.'); } else { @@ -263,7 +275,7 @@ const hygiene = exports.hygiene = (some, options) => { })); }; -gulp.task('hygiene', () => hygiene()); +gulp.task('hygiene', () => hygiene('')); // this allows us to run hygiene as a git pre-commit hook if (require.main === module) { @@ -296,11 +308,13 @@ if (require.main === module) { .split(/\r?\n/) .filter(l => !!l); - hygiene(some, { skipEOL: skipEOL }).on('error', err => { - console.error(); - console.error(err); - process.exit(1); - }); + if (some.length > 0) { + hygiene(some, { skipEOL: skipEOL }).on('error', err => { + console.error(); + console.error(err); + process.exit(1); + }); + } }); }); } diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index ff6bb258b62..bb04933439a 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -7,6 +7,8 @@ const gulp = require('gulp'); const fs = require('fs'); +const os = require('os'); +const cp = require('child_process'); const path = require('path'); const es = require('event-stream'); const azure = require('gulp-azure-storage'); @@ -43,8 +45,8 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.17.0' }, - { name: 'ms-vscode.node-debug2', version: '1.17.0' } + { name: 'ms-vscode.node-debug', version: '1.18.3' }, + { name: 'ms-vscode.node-debug2', version: '1.18.4' } ]; const excludedExtensions = [ @@ -66,7 +68,7 @@ const vscodeResources = [ 'out-build/bootstrap-amd.js', 'out-build/paths.js', 'out-build/vs/**/*.{svg,png,cur,html}', - 'out-build/vs/base/node/startupTimers.js', + 'out-build/vs/base/common/performance.js', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh}', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/workbench/browser/media/*-theme.css', @@ -136,6 +138,7 @@ const config = { role: 'Editor', ostypes: ["TEXT", "utxt", "TUTX", "****"], extensions: ["ascx", "asp", "aspx", "bash", "bash_login", "bash_logout", "bash_profile", "bashrc", "bat", "bowerrc", "c", "cc", "clj", "cljs", "cljx", "clojure", "cmd", "code-workspace", "coffee", "config", "cpp", "cs", "cshtml", "csproj", "css", "csx", "ctp", "cxx", "dockerfile", "dot", "dtd", "editorconfig", "edn", "eyaml", "eyml", "fs", "fsi", "fsscript", "fsx", "gemspec", "gitattributes", "gitconfig", "gitignore", "go", "h", "handlebars", "hbs", "hh", "hpp", "htm", "html", "hxx", "ini", "jade", "jav", "java", "js", "jscsrc", "jshintrc", "jshtm", "json", "jsp", "less", "lua", "m", "makefile", "markdown", "md", "mdoc", "mdown", "mdtext", "mdtxt", "mdwn", "mkd", "mkdn", "ml", "mli", "php", "phtml", "pl", "pl6", "pm", "pm6", "pod", "pp", "profile", "properties", "ps1", "psd1", "psgi", "psm1", "py", "r", "rb", "rhistory", "rprofile", "rs", "rt", "scss", "sh", "shtml", "sql", "svg", "svgz", "t", "ts", "txt", "vb", "wxi", "wxl", "wxs", "xaml", "xcodeproj", "xcworkspace", "xml", "yaml", "yml", "zlogin", "zlogout", "zprofile", "zsh", "zshenv", "zshrc"], + utis: ['public.source-code'], iconFile: 'resources/darwin/code_file.icns' }], darwinBundleURLTypes: [{ @@ -271,9 +274,10 @@ function packageTask(platform, arch, opts) { const packageJsonStream = gulp.src(['package.json'], { base: '.' }) .pipe(json({ name, version })); + const settingsSearchBuildId = getBuildNumber(); const date = new Date().toISOString(); const productJsonStream = gulp.src(['product.json'], { base: '.' }) - .pipe(json({ commit, date, checksums })); + .pipe(json({ commit, date, checksums, settingsSearchBuildId })); const license = gulp.src(['LICENSES.chromium.html', 'LICENSE.txt', 'ThirdPartyNotices.txt', 'licenses/**'], { base: '.' }); @@ -297,6 +301,7 @@ function packageTask(platform, arch, opts) { .pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js'])) .pipe(util.cleanNodeModule('v8-profiler', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js'])) + .pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/**'])) .pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a'])) .pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node'])); @@ -443,3 +448,136 @@ gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], () => { prefix: commit + '/' })); }); + +const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json'); +gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () => { + const branch = process.env.BUILD_SOURCEBRANCH; + if (!branch.endsWith('/master') && !branch.startsWith('release/')) { + console.log(`Only runs on master and release branches, not ${branch}`); + return; + } + + if (!fs.existsSync(allConfigDetailsPath)) { + console.error(`configuration file at ${allConfigDetailsPath} does not exist`); + return; + } + + const settingsSearchBuildId = getBuildNumber(); + if (!settingsSearchBuildId) { + console.error('Failed to compute build number'); + return; + } + + return gulp.src(allConfigDetailsPath) + .pipe(azure.upload({ + account: process.env.AZURE_STORAGE_ACCOUNT, + key: process.env.AZURE_STORAGE_ACCESS_KEY, + container: 'configuration', + prefix: `${settingsSearchBuildId}/${commit}/` + })); +}); + +function getBuildNumber() { + const previous = getPreviousVersion(packageJson.version); + if (!previous) { + return 0; + } + + try { + const out = cp.execSync(`git rev-list ${previous}..HEAD --count`); + const count = parseInt(out.toString()); + return versionStringToNumber(packageJson.version) * 1e4 + count; + } catch (e) { + console.error('Could not determine build number: ' + e.toString()); + return 0; + } +} + +/** + * Given 1.17.2, return 1.17.1 + * 1.18.0 => 1.17.2. + * 2.0.0 => 1.18.0 (or the highest 1.x) + */ +function getPreviousVersion(versionStr) { + function tagExists(tagName) { + try { + cp.execSync(`git rev-parse ${tagName}`, { stdio: 'ignore' }); + return true; + } catch (e) { + return false; + } + } + + function getLastTagFromBase(semverArr, componentToTest) { + const baseVersion = semverArr.join('.'); + if (!tagExists(baseVersion)) { + console.error('Failed to find tag for base version, ' + baseVersion); + return null; + } + + let goodTag; + do { + goodTag = semverArr.join('.'); + semverArr[componentToTest]++; + } while (tagExists(semverArr.join('.'))); + + return goodTag; + } + + const semverArr = versionStr.split('.'); + if (semverArr[2] > 0) { + semverArr[2]--; + return semverArr.join('.'); + } else if (semverArr[1] > 0) { + semverArr[1]--; + return getLastTagFromBase(semverArr, 2); + } else { + semverArr[0]--; + return getLastTagFromBase(semverArr, 1); + } +} + +function versionStringToNumber(versionStr) { + const semverRegex = /(\d+)\.(\d+)\.(\d+)/; + const match = versionStr.match(semverRegex); + if (!match) { + return 0; + } + + return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); +} + +gulp.task('generate-vscode-configuration', () => { + return new Promise((resolve, reject) => { + const buildDir = process.env['AGENT_BUILDDIRECTORY']; + if (!buildDir) { + return reject(new Error('$AGENT_BUILDDIRECTORY not set')); + } + + const userDataDir = path.join(os.tmpdir(), 'tmpuserdata'); + const extensionsDir = path.join(os.tmpdir(), 'tmpextdir'); + const appPath = path.join(buildDir, 'VSCode-darwin/Visual\\ Studio\\ Code\\ -\\ Insiders.app/Contents/Resources/app/bin/code'); + const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`); + + const timer = setTimeout(() => { + codeProc.kill(); + reject(new Error('export-default-configuration process timed out')); + }, 10 * 1000); + + codeProc.stdout.on('data', d => console.log(d.toString())); + codeProc.stderr.on('data', d => console.log(d.toString())); + + codeProc.on('exit', () => { + clearTimeout(timer); + resolve(); + }); + + codeProc.on('error', err => { + clearTimeout(timer); + reject(err); + }); + }).catch(e => { + // Don't fail the build + console.error(e.toString()); + }); +}); diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 54c73a538c2..ee92561849e 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -55,6 +55,7 @@ function prepareDebPackage(arch) { .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@ICON@@', product.applicationName)) .pipe(rename('usr/share/applications/' + product.applicationName + '.desktop')); const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' }) @@ -131,6 +132,7 @@ function prepareRpmPackage(arch) { .pipe(replace('@@NAME_LONG@@', product.nameLong)) .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@ICON@@', product.applicationName)) .pipe(rename('BUILD/usr/share/applications/' + product.applicationName + '.desktop')); const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' }) @@ -178,6 +180,50 @@ function buildRpmPackage(arch) { 'cp "' + rpmOut + '/$(ls ' + rpmOut + ')" ' + destination + '/' ]); } +function getSnapBuildPath(arch) { + return `.build/linux/snap/${arch}/${product.applicationName}-${arch}`; +} + +function prepareSnapPackage(arch) { + const binaryDir = '../VSCode-linux-' + arch; + const destination = getSnapBuildPath(arch); + + return function () { + const desktop = gulp.src('resources/linux/code.desktop', { base: '.' }) + .pipe(replace('@@NAME_LONG@@', product.nameLong)) + .pipe(replace('@@NAME_SHORT@@', product.nameShort)) + .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@ICON@@', `/usr/share/pixmaps/${product.applicationName}.png`)) + .pipe(rename(`usr/share/applications/${product.applicationName}.desktop`)); + + const icon = gulp.src('resources/linux/code.png', { base: '.' }) + .pipe(rename(`usr/share/pixmaps/${product.applicationName}.png`)); + + const code = gulp.src(binaryDir + '/**/*', { base: binaryDir }) + .pipe(rename(function (p) { p.dirname = 'usr/share/' + product.applicationName + '/' + p.dirname; })); + + const snapcraft = gulp.src('resources/linux/snap/snapcraft.yaml', { base: '.' }) + .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(replace('@@VERSION@@', packageJson.version)) + .pipe(rename('snap/snapcraft.yaml')); + + const electronLaunch = gulp.src('resources/linux/snap/electron-launch', { base: '.' }) + .pipe(rename('electron-launch')); + + const all = es.merge(desktop, icon, code, snapcraft, electronLaunch); + + return all.pipe(vfs.dest(destination)); + }; +} + +function buildSnapPackage(arch) { + const snapBuildPath = getSnapBuildPath(arch); + + return shell.task([ + `chmod +x ${snapBuildPath}/electron-launch`, + `cd ${snapBuildPath} && snapcraft snap` + ]); +} function getFlatpakArch(arch) { return { x64: 'x86_64', ia32: 'i386', arm: 'arm' }[arch]; @@ -258,6 +304,12 @@ gulp.task('clean-vscode-linux-arm-deb', util.rimraf('.build/linux/deb/armhf')); gulp.task('clean-vscode-linux-ia32-rpm', util.rimraf('.build/linux/rpm/i386')); gulp.task('clean-vscode-linux-x64-rpm', util.rimraf('.build/linux/rpm/x86_64')); gulp.task('clean-vscode-linux-arm-rpm', util.rimraf('.build/linux/rpm/armhf')); +gulp.task('clean-vscode-linux-ia32-snap', util.rimraf('.build/linux/snap/x64')); +gulp.task('clean-vscode-linux-x64-snap', util.rimraf('.build/linux/snap/x64')); +gulp.task('clean-vscode-linux-arm-snap', util.rimraf('.build/linux/snap/x64')); +gulp.task('clean-vscode-linux-ia32-flatpak', util.rimraf('.build/linux/flatpak/i386')); +gulp.task('clean-vscode-linux-x64-flatpak', util.rimraf('.build/linux/flatpak/x86_64')); +gulp.task('clean-vscode-linux-arm-flatpak', util.rimraf('.build/linux/flatpak/arm')); gulp.task('vscode-linux-ia32-prepare-deb', ['clean-vscode-linux-ia32-deb'], prepareDebPackage('ia32')); gulp.task('vscode-linux-x64-prepare-deb', ['clean-vscode-linux-x64-deb'], prepareDebPackage('x64')); @@ -273,14 +325,16 @@ gulp.task('vscode-linux-ia32-build-rpm', ['vscode-linux-ia32-prepare-rpm'], buil gulp.task('vscode-linux-x64-build-rpm', ['vscode-linux-x64-prepare-rpm'], buildRpmPackage('x64')); gulp.task('vscode-linux-arm-build-rpm', ['vscode-linux-arm-prepare-rpm'], buildRpmPackage('arm')); -gulp.task('clean-vscode-linux-ia32-flatpak', util.rimraf('.build/linux/flatpak/i386')); -gulp.task('clean-vscode-linux-x64-flatpak', util.rimraf('.build/linux/flatpak/x86_64')); -gulp.task('clean-vscode-linux-arm-flatpak', util.rimraf('.build/linux/flatpak/arm')); +gulp.task('vscode-linux-ia32-prepare-snap', ['clean-vscode-linux-ia32-snap'], prepareSnapPackage('ia32')); +gulp.task('vscode-linux-x64-prepare-snap', ['clean-vscode-linux-x64-snap'], prepareSnapPackage('x64')); +gulp.task('vscode-linux-arm-prepare-snap', ['clean-vscode-linux-arm-snap'], prepareSnapPackage('arm')); +gulp.task('vscode-linux-ia32-build-snap', ['vscode-linux-ia32-prepare-snap'], buildSnapPackage('ia32')); +gulp.task('vscode-linux-x64-build-snap', ['vscode-linux-x64-prepare-snap'], buildSnapPackage('x64')); +gulp.task('vscode-linux-arm-build-snap', ['vscode-linux-arm-prepare-snap'], buildSnapPackage('arm')); gulp.task('vscode-linux-ia32-prepare-flatpak', ['clean-vscode-linux-ia32-flatpak'], prepareFlatpak('ia32')); gulp.task('vscode-linux-x64-prepare-flatpak', ['clean-vscode-linux-x64-flatpak'], prepareFlatpak('x64')); gulp.task('vscode-linux-arm-prepare-flatpak', ['clean-vscode-linux-arm-flatpak'], prepareFlatpak('arm')); - gulp.task('vscode-linux-ia32-flatpak', ['vscode-linux-ia32-prepare-flatpak'], buildFlatpak('ia32')); gulp.task('vscode-linux-x64-flatpak', ['vscode-linux-x64-prepare-flatpak'], buildFlatpak('x64')); gulp.task('vscode-linux-arm-flatpak', ['vscode-linux-arm-prepare-flatpak'], buildFlatpak('arm')); diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 393438d2bfd..0e4c15c7408 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -130,10 +130,6 @@ "name": "vs/workbench/parts/update", "project": "vscode-workbench" }, - { - "name": "vs/workbench/parts/views", - "project": "vscode-workbench" - }, { "name": "vs/workbench/parts/watermark", "project": "vscode-workbench" @@ -190,9 +186,17 @@ "name": "vs/workbench/services/textMate", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/workspace", + "project": "vscode-workbench" + }, + { + "name": "vs/workbench/services/decorations", + "project": "vscode-workbench" + }, { "name": "setup_messages", "project": "vscode-workbench" } ] -} \ No newline at end of file +} diff --git a/build/lib/tslint/allowAsyncRule.js b/build/lib/tslint/allowAsyncRule.js deleted file mode 100644 index a27d2870779..00000000000 --- a/build/lib/tslint/allowAsyncRule.js +++ /dev/null @@ -1,59 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -var __extends = (this && this.__extends) || (function () { - var extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var ts = require("typescript"); -var Lint = require("tslint"); -var Rule = /** @class */ (function (_super) { - __extends(Rule, _super); - function Rule() { - return _super !== null && _super.apply(this, arguments) || this; - } - Rule.prototype.apply = function (sourceFile) { - var allowed = this.getOptions().ruleArguments[0]; - return this.applyWithWalker(new AsyncRuleWalker(sourceFile, this.getOptions(), allowed)); - }; - return Rule; -}(Lint.Rules.AbstractRule)); -exports.Rule = Rule; -var AsyncRuleWalker = /** @class */ (function (_super) { - __extends(AsyncRuleWalker, _super); - function AsyncRuleWalker(file, opts, allowed) { - var _this = _super.call(this, file, opts) || this; - _this.allowed = allowed; - return _this; - } - AsyncRuleWalker.prototype.visitMethodDeclaration = function (node) { - this.visitFunctionLikeDeclaration(node); - }; - AsyncRuleWalker.prototype.visitFunctionDeclaration = function (node) { - this.visitFunctionLikeDeclaration(node); - }; - AsyncRuleWalker.prototype.visitFunctionLikeDeclaration = function (node) { - var _this = this; - var flags = ts.getCombinedModifierFlags(node); - if (!(flags & ts.ModifierFlags.Async)) { - return; - } - var path = node.getSourceFile().path; - var pathParts = path.split(/\\|\//); - if (pathParts.some(function (part) { return _this.allowed.some(function (allowed) { return part === allowed; }); })) { - return; - } - var message = "You are not allowed to use async function in this layer. Allowed layers are: [" + this.allowed + "]"; - this.addFailureAtNode(node, message); - }; - return AsyncRuleWalker; -}(Lint.RuleWalker)); diff --git a/build/lib/tslint/allowAsyncRule.ts b/build/lib/tslint/allowAsyncRule.ts deleted file mode 100644 index e61765bf53d..00000000000 --- a/build/lib/tslint/allowAsyncRule.ts +++ /dev/null @@ -1,47 +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 ts from 'typescript'; -import * as Lint from 'tslint'; - -export class Rule extends Lint.Rules.AbstractRule { - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - const allowed = this.getOptions().ruleArguments[0] as string[]; - return this.applyWithWalker(new AsyncRuleWalker(sourceFile, this.getOptions(), allowed)); - } -} - -class AsyncRuleWalker extends Lint.RuleWalker { - - constructor(file: ts.SourceFile, opts: Lint.IOptions, private allowed: string[]) { - super(file, opts); - } - - protected visitMethodDeclaration(node: ts.MethodDeclaration): void { - this.visitFunctionLikeDeclaration(node); - } - - protected visitFunctionDeclaration(node: ts.FunctionDeclaration): void { - this.visitFunctionLikeDeclaration(node); - } - - private visitFunctionLikeDeclaration(node: ts.FunctionLikeDeclaration) { - const flags = ts.getCombinedModifierFlags(node); - - if (!(flags & ts.ModifierFlags.Async)) { - return; - } - - const path = (node.getSourceFile() as any).path; - const pathParts = path.split(/\\|\//); - - if (pathParts.some(part => this.allowed.some(allowed => part === allowed))) { - return; - } - - const message = `You are not allowed to use async function in this layer. Allowed layers are: [${this.allowed}]`; - this.addFailureAtNode(node, message); - } -} diff --git a/build/lib/tslint/noUnexternalizedStringsRule.js b/build/lib/tslint/noUnexternalizedStringsRule.js index d1d3c76b8ea..2925f0a0c63 100644 --- a/build/lib/tslint/noUnexternalizedStringsRule.js +++ b/build/lib/tslint/noUnexternalizedStringsRule.js @@ -88,10 +88,11 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) { var info = this.findDescribingParent(node); // Ignore strings in import and export nodes. if (info && info.isImport && doubleQuoted) { - this.addFailureAtNode(node, NoUnexternalizedStringsRuleWalker.ImportFailureMessage, new Lint.Fix(NoUnexternalizedStringsRuleWalker.ImportFailureMessage, [ - this.createReplacement(node.getStart(), 1, '\''), - this.createReplacement(node.getStart() + text.length - 1, 1, '\''), - ])); + var fix = [ + Lint.Replacement.replaceFromTo(node.getStart(), 1, '\''), + Lint.Replacement.replaceFromTo(node.getStart() + text.length - 1, 1, '\''), + ]; + this.addFailureAtNode(node, NoUnexternalizedStringsRuleWalker.ImportFailureMessage, fix); return; } var callInfo = info ? info.callInfo : null; @@ -101,8 +102,9 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) { } if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) { var s = node.getText(); - var replacement = new Lint.Replacement(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s.substring(1, s.length - 1) + "', " + s + ")"); - var fix = new Lint.Fix('Unexternalitzed string', [replacement]); + var fix = [ + Lint.Replacement.replaceFromTo(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s.substring(1, s.length - 1) + "', " + s + ")"), + ]; this.addFailure(this.createFailure(node.getStart(), node.getWidth(), "Unexternalized string found: " + node.getText(), fix)); return; } diff --git a/build/lib/tslint/noUnexternalizedStringsRule.ts b/build/lib/tslint/noUnexternalizedStringsRule.ts index 172db4d6b12..7b12df97596 100644 --- a/build/lib/tslint/noUnexternalizedStringsRule.ts +++ b/build/lib/tslint/noUnexternalizedStringsRule.ts @@ -104,13 +104,14 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker { let info = this.findDescribingParent(node); // Ignore strings in import and export nodes. if (info && info.isImport && doubleQuoted) { + const fix = [ + Lint.Replacement.replaceFromTo(node.getStart(), 1, '\''), + Lint.Replacement.replaceFromTo(node.getStart() + text.length - 1, 1, '\''), + ]; this.addFailureAtNode( node, NoUnexternalizedStringsRuleWalker.ImportFailureMessage, - new Lint.Fix(NoUnexternalizedStringsRuleWalker.ImportFailureMessage, [ - this.createReplacement(node.getStart(), 1, '\''), - this.createReplacement(node.getStart() + text.length - 1, 1, '\''), - ]) + fix ); return; } @@ -122,8 +123,9 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker { if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) { const s = node.getText(); - const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), `nls.localize('KEY-${s.substring(1, s.length - 1)}', ${s})`); - const fix = new Lint.Fix('Unexternalitzed string', [replacement]); + const fix = [ + Lint.Replacement.replaceFromTo(node.getStart(), node.getWidth(), `nls.localize('KEY-${s.substring(1, s.length - 1)}', ${s})`), + ]; this.addFailure(this.createFailure(node.getStart(), node.getWidth(), `Unexternalized string found: ${node.getText()}`, fix)); return; } diff --git a/build/lib/watch/index.js b/build/lib/watch/index.js index bed579ec075..93d9babc2de 100644 --- a/build/lib/watch/index.js +++ b/build/lib/watch/index.js @@ -19,14 +19,15 @@ function handleDeletions() { let watch = void 0; -if (!process.env['VSCODE_USE_LEGACY_WATCH']) { - try { - watch = require('./watch-nsfw'); - } catch (err) { - console.warn('Could not load our cross platform file watcher: ' + err.toString()); - console.warn('Falling back to our platform specific watcher...'); - } -} +// Disabled due to https://github.com/Microsoft/vscode/issues/36214 +// if (!process.env['VSCODE_USE_LEGACY_WATCH']) { +// try { +// watch = require('./watch-nsfw'); +// } catch (err) { +// console.warn('Could not load our cross platform file watcher: ' + err.toString()); +// console.warn('Falling back to our platform specific watcher...'); +// } +// } if (!watch) { watch = process.platform === 'win32' ? require('./watch-win32') : require('gulp-watch'); diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index cdaee801a9c..da006b6bce4 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -34,7 +34,7 @@ declare module monaco { #include(vs/base/common/winjs.base.d.ts): TValueCallback, ProgressCallback, Promise #include(vs/base/common/cancellation): CancellationTokenSource, CancellationToken -#include(vs/base/common/uri): URI +#include(vs/base/common/uri): URI, UriComponents #include(vs/editor/common/standalone/standaloneBase): KeyCode, KeyMod #include(vs/base/common/htmlContent): IMarkdownString #include(vs/base/browser/keyboardEvent): IKeyboardEvent diff --git a/build/monaco/package.json b/build/monaco/package.json index 4cc3beb09b8..e1a427322d0 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -13,10 +13,10 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "devDependencies": { - "@types/minimist": "^1.2.0", - "@types/mocha": "^2.2.39", - "@types/semver": "^5.3.30", - "@types/sinon": "^1.16.34", + "@types/minimist": "1.2.0", + "@types/mocha": "2.2.39", + "@types/semver": "5.3.30", + "@types/sinon": "1.16.34", "debounce": "^1.0.0", "eslint": "^3.4.0", "event-stream": "^3.1.7", @@ -48,7 +48,7 @@ "sinon": "^1.17.2", "source-map": "^0.4.4", "tslint": "^4.3.1", - "typescript": "2.5.2", + "typescript": "2.6.1", "typescript-formatter": "4.0.1", "underscore": "^1.8.2", "vinyl": "^0.4.5", diff --git a/build/npm/update-all-grammars.js b/build/npm/update-all-grammars.js index cfea912c3b1..9f85530caf5 100644 --- a/build/npm/update-all-grammars.js +++ b/build/npm/update-all-grammars.js @@ -54,7 +54,7 @@ const extensions = [ 'scss', 'shaderlab', 'shellscript', - // 'sql', customized, PRs pending + 'sql', 'swift', 'typescript', 'vb', diff --git a/build/npm/update-grammar.js b/build/npm/update-grammar.js index fca60d83242..9d0cad11dc7 100644 --- a/build/npm/update-grammar.js +++ b/build/npm/update-grammar.js @@ -22,7 +22,7 @@ function getOptions(urlString) { headers: { 'User-Agent': 'NodeJS' } - } + }; } function download(url, redirectCount) { @@ -100,7 +100,9 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) { result.version = 'https://github.com/' + repoId + '/commit/' + info.commitSha; } for (let key in grammar) { - result[key] = grammar[key]; + if (!result.hasOwnProperty(key)) { + result[key] = grammar[key]; + } } try { @@ -116,7 +118,7 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar) { }); }, console.error); -} +}; if (path.basename(process.argv[1]) === 'update-grammar.js') { for (var i = 3; i < process.argv.length; i += 2) { diff --git a/build/package.json b/build/package.json index d94f9aad64a..9936a4ac9f1 100644 --- a/build/package.json +++ b/build/package.json @@ -2,18 +2,18 @@ "name": "code-oss-dev-build", "version": "1.0.0", "devDependencies": { - "@types/azure": "^0.9.18", - "@types/documentdb": "^1.10.1", - "@types/es6-collections": "^0.5.30", - "@types/es6-promise": "0.0.32", + "@types/azure": "0.9.19", + "@types/documentdb": "1.10.2", + "@types/es6-collections": "0.5.31", + "@types/es6-promise": "0.0.33", "@types/mime": "0.0.29", - "@types/node": "^7.0.13", - "@types/xml2js": "^0.0.33", + "@types/node": "8.0.33", + "@types/xml2js": "0.0.33", "azure-storage": "^2.1.0", "documentdb": "^1.11.0", "mime": "^1.3.4", "minimist": "^1.2.0", - "typescript": "2.5.2", + "typescript": "2.6.1", "xml2js": "^0.4.17" }, "scripts": { diff --git a/build/tfs/common/enqueue.ts b/build/tfs/common/enqueue.ts index 61e1171f2eb..f781737313f 100644 --- a/build/tfs/common/enqueue.ts +++ b/build/tfs/common/enqueue.ts @@ -52,20 +52,20 @@ function isBuildSigned(quality: string, commit: string): Promise { }); } -async function waitForSignedBuild(quality: string, commit: string): Promise { - let retries = 0; +// async function waitForSignedBuild(quality: string, commit: string): Promise { +// let retries = 0; - while (retries < 180) { - if (await isBuildSigned(quality, commit)) { - return; - } +// while (retries < 180) { +// if (await isBuildSigned(quality, commit)) { +// return; +// } - await new Promise(c => setTimeout(c, 10000)); - retries++; - } +// await new Promise(c => setTimeout(c, 10000)); +// retries++; +// } - throw new Error('Timed out waiting for signed build'); -} +// throw new Error('Timed out waiting for signed build'); +// } async function main(quality: string): Promise { const commit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim(); @@ -73,10 +73,10 @@ async function main(quality: string): Promise { console.log(`Queueing signing request for '${quality}/${commit}'...`); await queueSigningRequest(quality, commit); - console.log('Waiting on signed build...'); - await waitForSignedBuild(quality, commit); + // console.log('Waiting on signed build...'); + // await waitForSignedBuild(quality, commit); - console.log('Found signed build!'); + // console.log('Found signed build!'); } main(process.argv[2]).catch(err => { diff --git a/build/tfs/common/publish.ts b/build/tfs/common/publish.ts index d959159dc86..e4cbdc80f0e 100644 --- a/build/tfs/common/publish.ts +++ b/build/tfs/common/publish.ts @@ -68,6 +68,7 @@ interface Asset { mooncakeUrl: string; hash: string; sha256hash: string; + size: number; } function createOrUpdate(commit: string, quality: string, platform: string, type: string, release: NewDocument, asset: Asset, isUpdate: boolean): Promise { @@ -156,7 +157,7 @@ async function publish(commit: string, quality: string, platform: string, type: console.log('Publishing...'); console.log('Quality:', quality); - console.log('Platforn:', platform); + console.log('Platform:', platform); console.log('Type:', type); console.log('Name:', name); console.log('Version:', version); @@ -165,6 +166,11 @@ async function publish(commit: string, quality: string, platform: string, type: console.log('Is Released:', isReleased); console.log('File:', file); + const stat = await new Promise((c, e) => fs.stat(file, (err, stat) => err ? e(err) : c(stat))); + const size = stat.size; + + console.log('Size:', size); + const stream = fs.createReadStream(file); const [sha1hash, sha256hash] = await Promise.all([hashStream('sha1', stream), hashStream('sha256', stream)]); @@ -224,7 +230,8 @@ async function publish(commit: string, quality: string, platform: string, type: url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`, mooncakeUrl: `${process.env['MOONCAKE_CDN_URL']}/${quality}/${blobName}`, hash: sha1hash, - sha256hash + sha256hash, + size }; const release = { diff --git a/build/tfs/darwin/build.sh b/build/tfs/darwin/build.sh index acbb849d4b3..df7ee5e0b16 100755 --- a/build/tfs/darwin/build.sh +++ b/build/tfs/darwin/build.sh @@ -37,5 +37,19 @@ step "Run unit tests" \ step "Run integration tests" \ ./scripts/test-integration.sh +# function smoketest { +# ARTIFACTS="$AGENT_BUILDDIRECTORY/smoketest-artifacts" +# rm -rf $ARTIFACTS + +# [[ "$VSCODE_QUALITY" == "insider" ]] && VSCODE_APPNAME="Visual Studio Code - Insiders" || VSCODE_APPNAME="Visual Studio Code" +# npm run smoketest -- --build "$AGENT_BUILDDIRECTORY/VSCode-darwin/$VSCODE_APPNAME.app" --log $ARTIFACTS +# } + +# step "Run smoke test" \ +# smoketest + step "Publish release" \ ./build/tfs/darwin/release.sh + +step "Generate and upload configuration.json" \ + npm run gulp -- upload-vscode-configuration diff --git a/build/tfs/darwin/release.sh b/build/tfs/darwin/release.sh index 24ed4c30a78..4dfecac7dd9 100755 --- a/build/tfs/darwin/release.sh +++ b/build/tfs/darwin/release.sh @@ -20,7 +20,7 @@ rm -rf $UNSIGNEDZIP zip -r -X -y $UNSIGNEDZIP *) step "Upload unsigned archive" \ - node build/tfs/common/publish.js --upload-only $VSCODE_QUALITY darwin archive-unsigned VSCode-darwin-$VSCODE_QUALITY-unsigned.zip $VERSION false $UNSIGNEDZIP + node build/tfs/common/publish.js $VSCODE_QUALITY darwin archive-unsigned VSCode-darwin-$VSCODE_QUALITY-unsigned.zip $VERSION false $UNSIGNEDZIP step "Sign build" \ node build/tfs/common/enqueue.js $VSCODE_QUALITY \ No newline at end of file diff --git a/build/tfs/darwin/smoketest.sh b/build/tfs/darwin/smoketest.sh deleted file mode 100755 index 125201c12b5..00000000000 --- a/build/tfs/darwin/smoketest.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -. ./build/tfs/common/node.sh -. ./scripts/env.sh -. ./build/tfs/common/common.sh - -export VSCODE_MIXIN_PASSWORD="$1" -VSO_PAT="$2" - -echo "machine monacotools.visualstudio.com password $VSO_PAT" > ~/.netrc - -step "Install dependencies" \ - npm install - -step "Mix in repository from vscode-distro" \ - npm run gulp -- mixin - -step "Install distro dependencies" \ - node build/tfs/common/installDistro.js - -step "Build minified & upload source maps" \ - npm run gulp -- vscode-darwin-min - -step "Run smoke test" \ - pushd test/smoke - npm install - npm run smoketest -- --build "$AGENT_BUILDDIRECTORY/VSCode-darwin/Visual Studio Code - Insiders.app/Contents/MacOS/Electron" - popd \ No newline at end of file diff --git a/build/tfs/linux/.gitignore b/build/tfs/linux/.gitignore index 0f46fa7086a..5ca5f22fc5a 100644 --- a/build/tfs/linux/.gitignore +++ b/build/tfs/linux/.gitignore @@ -1 +1,2 @@ -pat \ No newline at end of file +pat +*.js \ No newline at end of file diff --git a/build/tfs/linux/build.sh b/build/tfs/linux/build.sh index b3d1825c2d9..f138b5d237e 100755 --- a/build/tfs/linux/build.sh +++ b/build/tfs/linux/build.sh @@ -39,5 +39,22 @@ step "Build minified" \ step "Run unit tests" \ ./scripts/test.sh --build --reporter dot +# function smoketest { +# id -u testuser &>/dev/null || (useradd -m testuser; chpasswd <<< testuser:testpassword) +# sudo -i -u testuser -- sh -c 'git config --global user.name "VS Code Agent" && git config --global user.email "monacotools@microsoft.com"' + +# ARTIFACTS="$AGENT_BUILDDIRECTORY/smoketest-artifacts" +# rm -rf $ARTIFACTS +# mkdir -p $ARTIFACTS +# chown -R testuser $ARTIFACTS + +# ps -o pid= -u testuser | xargs sudo kill -9 +# DISPLAY=:10 sudo -i -u testuser -- sh -c "cd $BUILD_SOURCESDIRECTORY/test/smoke && ./node_modules/.bin/mocha --build $AGENT_BUILDDIRECTORY/VSCode-linux-$ARCH --log $ARTIFACTS" +# # DISPLAY=:10 sudo -i -u testuser -- sh -c "cd /vso/work/1/s/test/smoke && ./node_modules/.bin/mocha --build /vso/work/1/VSCode-linux-ia32" +# } + +# step "Run smoke test" \ +# smoketest + step "Publish release" \ ./build/tfs/linux/release.sh diff --git a/build/tfs/linux/frozen-check.ts b/build/tfs/linux/frozen-check.ts new file mode 100644 index 00000000000..489a24dc28a --- /dev/null +++ b/build/tfs/linux/frozen-check.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { DocumentClient } from 'documentdb'; + +interface Config { + id: string; + frozen: boolean; +} + +function createDefaultConfig(quality: string): Config { + return { + id: quality, + frozen: false + }; +} + +function getConfig(quality: string): Promise { + const client = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT'], { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); + const collection = 'dbs/builds/colls/config'; + const query = { + query: `SELECT TOP 1 * FROM c WHERE c.id = @quality`, + parameters: [ + { name: '@quality', value: quality } + ] + }; + + return new Promise((c, e) => { + client.queryDocuments(collection, query).toArray((err, results) => { + if (err && err.code !== 409) { return e(err); } + + c(!results || results.length === 0 ? createDefaultConfig(quality) : results[0] as any as Config); + }); + }); +} + +getConfig(process.argv[2]) + .then(c => console.log(c.frozen), e => console.error(e)); \ No newline at end of file diff --git a/build/tfs/linux/ia32/Dockerfile b/build/tfs/linux/ia32/Dockerfile index b309a1e940f..25d621d99fb 100644 --- a/build/tfs/linux/ia32/Dockerfile +++ b/build/tfs/linux/ia32/Dockerfile @@ -40,6 +40,9 @@ ADD xvfb.init /etc/init.d/xvfb RUN chmod +x /etc/init.d/xvfb RUN update-rc.d xvfb defaults +# dbus +RUN ln -sf /bin/dbus-daemon /usr/bin/dbus-daemon + # nvm ENV NVM_DIR /usr/local/nvm RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash @@ -47,4 +50,4 @@ RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | b # for libsecret ENV PKG_CONFIG_PATH /usr/lib/i386-linux-gnu/pkgconfig -CMD (service xvfb start; export DISPLAY=:10; ./start.sh) \ No newline at end of file +CMD (service xvfb start; service dbus start; export DISPLAY=:10; ./start.sh) \ No newline at end of file diff --git a/build/tfs/linux/release.sh b/build/tfs/linux/release.sh index 41f6d35e675..a89eb5cc41c 100755 --- a/build/tfs/linux/release.sh +++ b/build/tfs/linux/release.sh @@ -9,6 +9,9 @@ step "Build Debian package" \ step "Build RPM package" \ npm run gulp -- "vscode-linux-$ARCH-build-rpm" +# step "Build snap package" \ +# npm run gulp -- "vscode-linux-$ARCH-build-snap" + (cd $BUILD_SOURCESDIRECTORY/build/tfs/common && \ step "Install build dependencies" \ npm install --unsafe-perm) @@ -49,8 +52,15 @@ RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME" step "Publish RPM package" \ node build/tfs/common/publish.js $VSCODE_QUALITY $PLATFORM_RPM package $RPM_FILENAME $VERSION true $RPM_PATH +# SNAP_FILENAME="$(ls $REPO/.build/linux/snap/$ARCH/ | grep .snap)" +# SNAP_PATH="$REPO/.build/linux/snap/$ARCH/$SNAP_FILENAME" + +IS_FROZEN="$(node build/tfs/linux/frozen-check.js $VSCODE_QUALITY)" + if [ -z "$VSCODE_QUALITY" ]; then echo "VSCODE_QUALITY is not set, skipping repo package publish" +elif [ "$IS_FROZEN" = "true" ]; then + echo "$VSCODE_QUALITY is frozen, skipping repo package publish" else if [ "$BUILD_SOURCEBRANCH" = "master" ] || [ "$BUILD_SOURCEBRANCH" = "refs/heads/master" ]; then if [[ $BUILD_QUEUEDBY = *"Project Collection Service Accounts"* || $BUILD_QUEUEDBY = *"Microsoft.VisualStudio.Services.TFS"* ]]; then diff --git a/build/tfs/linux/repoapi_client.sh b/build/tfs/linux/repoapi_client.sh index b214ef10726..3d98dd22d55 100755 --- a/build/tfs/linux/repoapi_client.sh +++ b/build/tfs/linux/repoapi_client.sh @@ -1,6 +1,6 @@ #!/bin/bash -e # This is a VERY basic script for Create/Delete operations on repos and packages -# +# cmd=$1 urls=urls.txt defaultPackageFile=new_package.json @@ -53,7 +53,7 @@ function ParseConfigFile { fi BailIfFileMissing "$configFile" secretContents=$(cat "$configFile") - + server=$(ParseFromJson .server) protocol=$(ParseFromJson .protocol) port=$(ParseFromJson .port) @@ -135,14 +135,14 @@ function AddPackageByUrl rm -f $tmpFile $tmpOut Bail "File is not a valid deb/rpm package $url" fi - + rm -f $tmpFile $tmpOut if [ -z "$pkgName" ]; then Bail "Unable to parse package name for $url" elif [ -z "$pkgVer" ]; then Bail "Unable to parse package version number for $url" fi - + # Create Package .json file escapedUrl=$(echo "$url" | sed 's/\//\\\//g' | sed 's/\&/\\\&/g') cp $defaultPackageFile.template $defaultPackageFile @@ -153,7 +153,7 @@ function AddPackageByUrl # Perform Upload AddPackage $defaultPackageFile # Cleanup - rm -f $defaultPackageFile + rm -f $defaultPackageFile } # Upload multiple packages by reading urls line-by-line from the specified file diff --git a/build/tfs/linux/smoketest.sh b/build/tfs/linux/smoketest.sh deleted file mode 100644 index b9f84c2a04a..00000000000 --- a/build/tfs/linux/smoketest.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -set -e - -. ./build/tfs/common/node.sh -. ./scripts/env.sh -. ./build/tfs/common/common.sh - -export ARCH="$1" -export VSCODE_MIXIN_PASSWORD="$2" -VSO_PAT="$3" - -echo "machine monacotools.visualstudio.com password $VSO_PAT" > ~/.netrc - -step "Install dependencies" \ - npm install --arch=$ARCH --unsafe-perm - -step "Mix in repository from vscode-distro" \ - npm run gulp -- mixin - -step "Get Electron" \ - npm run gulp -- "electron-$ARCH" - -step "Install distro dependencies" \ - node build/tfs/common/installDistro.js --arch=$ARCH - -step "Build minified" \ - npm run gulp -- "vscode-linux-$ARCH-min" - -function configureEnvironment { - id -u testuser &>/dev/null || (useradd -m testuser; chpasswd <<< testuser:testpassword) - sudo -i -u testuser git config --global user.name "VS Code Agent" - sudo -i -u testuser git config --global user.email "monacotools@microsoft.com" - chown -R testuser $AGENT_BUILDDIRECTORY -} - -step "Configure environment" \ - configureEnvironment - -function runSmokeTest { - cd test/smoke && sudo -u testuser ../../node_modules/.bin/mocha --build "$AGENT_BUILDDIRECTORY/VSCode-linux-ia32/code-insiders" -} - -step "Run smoke test" \ - runSmokeTest - diff --git a/build/tfs/linux/x64/Dockerfile b/build/tfs/linux/x64/Dockerfile index 4fef9acb19a..ae9190c29db 100644 --- a/build/tfs/linux/x64/Dockerfile +++ b/build/tfs/linux/x64/Dockerfile @@ -36,8 +36,11 @@ ADD xvfb.init /etc/init.d/xvfb RUN chmod +x /etc/init.d/xvfb RUN update-rc.d xvfb defaults +# dbus +RUN ln -sf /bin/dbus-daemon /usr/bin/dbus-daemon + # nvm ENV NVM_DIR /usr/local/nvm RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash -CMD (service xvfb start; export DISPLAY=:10; ./start.sh) \ No newline at end of file +CMD (service xvfb start; service dbus start; export DISPLAY=:10; ./start.sh) \ No newline at end of file diff --git a/build/tfs/win32/1_build.ps1 b/build/tfs/win32/1_build.ps1 index 0090920d506..c7fb712e18f 100644 --- a/build/tfs/win32/1_build.ps1 +++ b/build/tfs/win32/1_build.ps1 @@ -52,4 +52,11 @@ step "Run unit tests" { # exec { & .\scripts\test-integration.bat } # } +# step "Run smoke test" { +# $Artifacts = "$env:AGENT_BUILDDIRECTORY\smoketest-artifacts" +# Remove-Item -Recurse -Force -ErrorAction Ignore $Artifacts + +# exec { & npm run smoketest -- --build "$env:AGENT_BUILDDIRECTORY\VSCode-win32-$global:arch" --log "$Artifacts" } +# } + done diff --git a/build/tfs/win32/build_unsigned.ps1 b/build/tfs/win32/build_unsigned.ps1 new file mode 100644 index 00000000000..207f633999c --- /dev/null +++ b/build/tfs/win32/build_unsigned.ps1 @@ -0,0 +1,85 @@ +Param( + [string]$arch, + [string]$mixinPassword, + [string]$vsoPAT, + [string]$storageKey, + [string]$mooncakeStorageKey, + [string]$documentDbKey +) + +. .\build\tfs\win32\node.ps1 +. .\scripts\env.ps1 +. .\build\tfs\win32\lib.ps1 + +# Create a _netrc file to download distro dependencies +# In order to get _netrc to work, we need a HOME variable setup +"machine monacotools.visualstudio.com password ${vsoPAT}" | Out-File "$env:HOME\_netrc" -Encoding ASCII + +# Set the right architecture +$env:npm_config_arch="$arch" + +step "Install dependencies" { + exec { & npm install } +} + +step "Hygiene" { + exec { & npm run gulp -- hygiene } +} + +$env:VSCODE_MIXIN_PASSWORD = $mixinPassword +step "Mix in repository from vscode-distro" { + exec { & npm run gulp -- mixin } +} + +step "Get Electron" { + exec { & npm run gulp -- "electron-$global:arch" } +} + +step "Install distro dependencies" { + exec { & node build\tfs\common\installDistro.js } +} + +step "Build minified" { + exec { & npm run gulp -- "vscode-win32-$global:arch-min" } +} + +step "Run unit tests" { + exec { & .\scripts\test.bat --build --reporter dot } +} + +step "Run smoke test" { + $Artifacts = "$env:AGENT_BUILDDIRECTORY\smoketest-artifacts" + Remove-Item -Recurse -Force -ErrorAction Ignore $Artifacts + + exec { & npm run smoketest -- --build "$env:AGENT_BUILDDIRECTORY\VSCode-win32-$global:arch" --log "$Artifacts" } +} + +step "Create archive and setup package" { + exec { & npm run gulp -- "vscode-win32-$global:arch-archive" "vscode-win32-$global:arch-setup" } +} + +$Repo = "$(pwd)" +$Root = "$Repo\.." +$Exe = "$Repo\.build\win32-$arch\setup\VSCodeSetup.exe" +$Zip = "$Repo\.build\win32-$arch\archive\VSCode-win32-$arch.zip" +$Build = "$Root\VSCode-win32-$arch" + +# get version +$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json +$Version = $PackageJson.version +$Quality = "$env:VSCODE_QUALITY" +$env:AZURE_STORAGE_ACCESS_KEY_2 = $storageKey +$env:MOONCAKE_STORAGE_ACCESS_KEY = $mooncakeStorageKey +$env:AZURE_DOCUMENTDB_MASTERKEY = $documentDbKey + +$assetPlatform = if ($arch -eq "ia32") { "win32" } else { "win32-x64" } + +step "Publish UNSIGNED archive" { + exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform-archive" archive-unsigned "VSCode-win32-$global:arch-$Version-unsigned.zip" $Version false $Zip } +} + +step "Publish UNSIGNED setup package" { + exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform" setup-unsigned "VSCodeSetup-$global:arch-$Version-unsigned.exe" $Version false $Exe } +} + +done diff --git a/build/tfs/win32/smoketest.ps1 b/build/tfs/win32/smoketest.ps1 deleted file mode 100644 index 3628dacb222..00000000000 --- a/build/tfs/win32/smoketest.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -Param( - [string]$arch, - [string]$mixinPassword, - [string]$vsoPAT -) - -. .\build\tfs\win32\node.ps1 -. .\scripts\env.ps1 -. .\build\tfs\win32\lib.ps1 - -# Create a _netrc file to download distro dependencies -# In order to get _netrc to work, we need a HOME variable setup -$env:HOME = $env:USERPROFILE -"machine monacotools.visualstudio.com password ${vsoPAT}" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII - -# Set the right architecture -$env:npm_config_arch = "$arch" - -step "Install dependencies" { - exec { & npm install } -} - -$env:VSCODE_MIXIN_PASSWORD = $mixinPassword -step "Mix in repository from vscode-distro" { - exec { & npm run gulp -- mixin } -} - -step "Get Electron" { - exec { & npm run gulp -- "electron-$global:arch" } -} - -step "Install distro dependencies" { - exec { & node build\tfs\common\installDistro.js } -} - -step "Build minified" { - exec { & npm run gulp -- "vscode-win32-$global:arch-min" } -} - -step "Run smoke test" { - exec { & Push-Location test\smoke } - exec { & npm install } - exec { & npm run smoketest -- --build "$env:AGENT_BUILDDIRECTORY\VSCode-win32-$global:arch\Code - Insiders.exe" } - exec { & Pop-Location } -} - -done \ No newline at end of file diff --git a/build/win32/code.iss b/build/win32/code.iss index 73b031fe643..57239c1f677 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -19,6 +19,7 @@ OutputBaseFilename=VSCodeSetup Compression=lzma SolidCompression=yes AppMutex={#AppMutex} +SetupMutex={#AppMutex}setup WizardImageFile={#RepoDir}\resources\win32\inno-big.bmp WizardSmallImageFile={#RepoDir}\resources\win32\inno-small.bmp SetupIconFile={#RepoDir}\resources\win32\code.ico @@ -122,6 +123,12 @@ Root: HKCR; Subkey: "{#RegValueName}.bashrc"; ValueType: string; ValueName: ""; Root: HKCR; Subkey: "{#RegValueName}.bashrc\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"; Tasks: associatewithfiles Root: HKCR; Subkey: "{#RegValueName}.bashrc\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles +Root: HKCR; Subkey: ".bib\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles +Root: HKCR; Subkey: ".bib\OpenWithProgids"; ValueType: string; ValueName: "{#RegValueName}.bib"; ValueData: ""; Flags: uninsdeletevalue; Tasks: associatewithfiles +Root: HKCR; Subkey: "{#RegValueName}.bib"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,BibTeX}"; Flags: uninsdeletekey; Tasks: associatewithfiles +Root: HKCR; Subkey: "{#RegValueName}.bib\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"; Tasks: associatewithfiles +Root: HKCR; Subkey: "{#RegValueName}.bib\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: associatewithfiles + Root: HKCR; Subkey: ".bowerrc\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles Root: HKCR; Subkey: ".bowerrc\OpenWithProgids"; ValueType: string; ValueName: "{#RegValueName}.bowerrc"; ValueData: ""; Flags: uninsdeletevalue; Tasks: associatewithfiles Root: HKCR; Subkey: "{#RegValueName}.bowerrc"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,Bower RC}"; Flags: uninsdeletekey; Tasks: associatewithfiles diff --git a/extensions/bat/language-configuration.json b/extensions/bat/language-configuration.json index 8b1695d8ec2..2fb5445a34a 100644 --- a/extensions/bat/language-configuration.json +++ b/extensions/bat/language-configuration.json @@ -18,5 +18,11 @@ ["[", "]"], ["(", ")"], ["\"", "\""] - ] -} \ No newline at end of file + ], + "folding": { + "markers": { + "start": "^\\s*(::\\s*|REM\\s+)#region", + "end": "^\\s*(::\\s*|REM\\s+)#endregion" + } + } +} diff --git a/extensions/clojure/language-configuration.json b/extensions/clojure/language-configuration.json index 004e1dbd95b..24f52480015 100644 --- a/extensions/clojure/language-configuration.json +++ b/extensions/clojure/language-configuration.json @@ -18,5 +18,8 @@ ["[", "]"], ["(", ")"], ["\"", "\""] - ] + ], + "folding": { + "offSide": true + } } \ No newline at end of file diff --git a/extensions/coffeescript/language-configuration.json b/extensions/coffeescript/language-configuration.json index 745427eacfb..8c7fbd458df 100644 --- a/extensions/coffeescript/language-configuration.json +++ b/extensions/coffeescript/language-configuration.json @@ -21,5 +21,8 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "offSide": true + } } \ No newline at end of file diff --git a/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json b/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json index 0ce25622610..a67f88487ed 100644 --- a/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json +++ b/extensions/coffeescript/syntaxes/coffeescript.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/atom/language-coffee-script/commit/087e41aeef03b52615ef5c9e159a4b98e813f8a6", + "version": "https://github.com/atom/language-coffee-script/commit/c0dbeede971ff5391ec1d94d4ea5d94e60d7e3e3", "scopeName": "source.coffee", "name": "CoffeeScript", "fileTypes": [ @@ -17,35 +17,22 @@ "firstLineMatch": "(?x)\n# Hashbang\n^\\#!.*(?:\\s|\\/)\n coffee\n(?:$|\\s)\n|\n# Modeline\n(?i:\n # Emacs\n -\\*-(?:\\s*(?=[^:;\\s]+\\s*-\\*-)|(?:.*?[;\\s]|(?<=-\\*-))mode\\s*:\\s*)\n coffee\n (?=[\\s;]|(?]?\\d+|m)?|\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s*set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=\n coffee\n (?=\\s|:|$)\n)", "patterns": [ { - "captures": { - "1": { - "name": "variable.parameter.function.coffee" - }, - "2": { - "name": "storage.type.function.coffee" - } - }, - "comment": "match stuff like: a -> … ", - "match": "(\\([^()]*?\\))\\s*([=-]>)", - "name": "meta.inline.function.coffee" - }, - { + "match": "(new)\\s+(?:(?:(class)\\s+(\\w+(?:\\.\\w*)*)?)|(\\w+(?:\\.\\w*)*))", + "name": "meta.class.instance.constructor.coffee", "captures": { "1": { "name": "keyword.operator.new.coffee" }, - "4": { + "2": { "name": "storage.type.class.coffee" }, - "6": { + "3": { "name": "entity.name.type.instance.coffee" }, - "7": { + "4": { "name": "entity.name.type.instance.coffee" } - }, - "match": "(new)\\s+(((class)(\\s+(\\w+(?:\\.\\w*)*))?)|(\\w+(?:\\.\\w*)*))", - "name": "meta.class.instance.constructor" + } }, { "begin": "'''", @@ -60,7 +47,7 @@ "name": "punctuation.definition.string.end.coffee" } }, - "name": "string.quoted.heredoc.coffee", + "name": "string.quoted.single.heredoc.coffee", "patterns": [ { "captures": { @@ -103,34 +90,38 @@ ] }, { - "begin": "`", - "beginCaptures": { - "0": { + "match": "(`)(.*)(`)", + "name": "string.quoted.script.coffee", + "captures": { + "1": { "name": "punctuation.definition.string.begin.coffee" - } - }, - "end": "`", - "endCaptures": { - "0": { + }, + "2": { + "name": "source.js.embedded.coffee", + "patterns": [ + { + "include": "source.js" + } + ] + }, + "3": { "name": "punctuation.definition.string.end.coffee" } - }, - "name": "string.quoted.script.coffee", - "contentName": "source.embedded.js", - "patterns": [ - { - "include": "source.js" - } - ] + } }, { "begin": "(?>>?|(?*%+\\-&^])?=(?!>)|[!%^*\\/~?:]|\\-?\\-(?!>)|\\+\\+?|<>|<|>|&&?|\\.\\.\\.?|\\|\\|?|\\b(?=]))(?!(\\s*\\(.*\\))?\\s*([=-]>))", - "captures": { + "begin": "(?x)\n(?<=\\s|^)((@)?[a-zA-Z_$][\\w$]*)\n\\s*([:=])\\s*\n(?=(\\([^\\(\\)]*\\)\\s*)?[=-]>)", + "beginCaptures": { "1": { - "name": "variable.assignment.coffee" + "name": "entity.name.function.coffee" }, "2": { - "name": "punctuation.separator.key-value" + "name": "variable.other.readwrite.instance.coffee" }, "3": { - "name": "keyword.operator.coffee" + "name": "keyword.operator.assignment.coffee" } - } + }, + "end": "[=-]>", + "endCaptures": { + "0": { + "name": "storage.type.function.coffee" + } + }, + "name": "meta.function.coffee", + "patterns": [ + { + "include": "#function_params" + } + ] + }, + { + "begin": "(?x)\n(?<=\\s|^)(?:((')([^']*?)('))|((\")([^\"]*?)(\")))\n\\s*([:=])\\s*\n(?=(\\([^\\(\\)]*\\)\\s*)?[=-]>)", + "beginCaptures": { + "1": { + "name": "string.quoted.single.coffee" + }, + "2": { + "name": "punctuation.definition.string.begin.coffee" + }, + "3": { + "name": "entity.name.function.coffee" + }, + "4": { + "name": "punctuation.definition.string.end.coffee" + }, + "5": { + "name": "string.quoted.double.coffee" + }, + "6": { + "name": "punctuation.definition.string.begin.coffee" + }, + "7": { + "name": "entity.name.function.coffee" + }, + "8": { + "name": "punctuation.definition.string.end.coffee" + }, + "9": { + "name": "keyword.operator.assignment.coffee" + } + }, + "end": "[=-]>", + "endCaptures": { + "0": { + "name": "storage.type.function.coffee" + } + }, + "name": "meta.function.coffee", + "patterns": [ + { + "include": "#function_params" + } + ] + }, + { + "begin": "(?=(\\([^\\(\\)]*\\)\\s*)?[=-]>)", + "end": "[=-]>", + "endCaptures": { + "0": { + "name": "storage.type.function.coffee" + } + }, + "name": "meta.function.inline.coffee", + "patterns": [ + { + "include": "#function_params" + } + ] }, { "begin": "(?<=\\s|^)({)(?=[^'\"#]+?}[\\s\\]}]*=)", @@ -221,9 +284,9 @@ "name": "punctuation.definition.destructuring.begin.bracket.curly.coffee" } }, - "end": "(})", + "end": "}", "endCaptures": { - "1": { + "0": { "name": "punctuation.definition.destructuring.end.bracket.curly.coffee" } }, @@ -233,7 +296,8 @@ "include": "$self" }, { - "include": "#variable_name" + "match": "[a-zA-Z$_]\\w*", + "name": "variable.assignment.coffee" } ] }, @@ -244,9 +308,9 @@ "name": "punctuation.definition.destructuring.begin.bracket.square.coffee" } }, - "end": "(\\])", + "end": "\\]", "endCaptures": { - "1": { + "0": { "name": "punctuation.definition.destructuring.end.bracket.square.coffee" } }, @@ -256,25 +320,11 @@ "include": "$self" }, { - "include": "#variable_name" + "match": "[a-zA-Z$_]\\w*", + "name": "variable.assignment.coffee" } ] }, - { - "match": "(?x)\n(?<=^|\\s)\n(?=@?[a-zA-Z\\$_])\n@?([a-zA-Z\\$_]\\w*)(\\$|:|\\.)?\\s*\n(?=[:=](\\s*\\(.*\\))?\\s*([=-]>))", - "captures": { - "1": { - "name": "entity.name.function.coffee" - }, - "3": { - "name": "variable.parameter.function.coffee" - }, - "4": { - "name": "storage.type.function.coffee" - } - }, - "name": "meta.function.coffee" - }, { "match": "\\b(?|\\-\\d|\\[|\\{|\"|'))|(?=\\())", - "captures": { - "4": { - "name": "entity.name.function.coffee" - } - } - }, - { - "match": "[=-]>", - "name": "storage.type.function.coffee" - }, { "match": "\\b(?|\\-\\d|\\[|{|\"|'))", + "end": "(?=\\s*(?|\\-\\d|\\[|{|\"|')))", + "beginCaptures": { + "1": { + "name": "variable.other.readwrite.instance.coffee" + }, + "2": { + "patterns": [ + { + "include": "#function_names" + } + ] + } + }, + "end": "(?=\\s*(?|\\-\\d|\\[|{|\"|')))", + "beginCaptures": { + "1": { + "name": "punctuation.separator.method.period.coffee" + }, + "2": { + "name": "keyword.operator.prototype.coffee" + }, + "3": { + "patterns": [ + { + "include": "#method_names" + } + ] + } + }, + "end": "(?=\\s*(?>=|>>>=|\\|=)", + "captures": { + "1": { + "name": "variable.assignment.coffee" + }, + "2": { + "name": "keyword.operator.assignment.compound.bitwise.coffee" + } + } + }, + { + "match": "<<|>>>|>>", + "name": "keyword.operator.bitwise.shift.coffee" + }, + { + "match": "!=|<=|>=|==|<|>", + "name": "keyword.operator.comparison.coffee" + }, + { + "match": "&&|!|\\|\\|", + "name": "keyword.operator.logical.coffee" + }, + { + "match": "&|\\||\\^|~", + "name": "keyword.operator.bitwise.coffee" + }, + { + "match": "([a-zA-Z$_][\\w$]*)?\\s*(=|:(?!:))(?![>=])", + "captures": { + "1": { + "name": "variable.assignment.coffee" + }, + "2": { + "name": "keyword.operator.assignment.coffee" + } + } + }, + { + "match": "--", + "name": "keyword.operator.decrement.coffee" + }, + { + "match": "\\+\\+", + "name": "keyword.operator.increment.coffee" + }, + { + "match": "\\.\\.\\.", + "name": "keyword.operator.splat.coffee" + }, + { + "match": "\\?", + "name": "keyword.operator.existential.coffee" + }, + { + "match": "%|\\*|/|-|\\+", + "name": "keyword.operator.coffee" + }, + { + "match": "(?x)\n\\b(?", - "t": "source.coffee meta.inline.function.coffee storage.type.function.coffee", + "t": "source.coffee meta.function.coffee storage.type.function.coffee", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -166,7 +188,7 @@ }, { "c": ":", - "t": "source.coffee keyword.operator.coffee", + "t": "source.coffee meta.function.coffee keyword.operator.assignment.coffee", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -177,7 +199,7 @@ }, { "c": " ", - "t": "source.coffee", + "t": "source.coffee meta.function.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -187,19 +209,30 @@ } }, { - "c": "()", - "t": "source.coffee meta.inline.function.coffee variable.parameter.function.coffee", + "c": "(", + "t": "source.coffee meta.function.coffee meta.parameters.coffee punctuation.definition.parameters.begin.bracket.round.coffee", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.coffee meta.function.coffee meta.parameters.coffee punctuation.definition.parameters.end.bracket.round.coffee", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" } }, { "c": " ", - "t": "source.coffee meta.inline.function.coffee", + "t": "source.coffee meta.function.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -210,7 +243,7 @@ }, { "c": "=>", - "t": "source.coffee meta.inline.function.coffee storage.type.function.coffee", + "t": "source.coffee meta.function.coffee storage.type.function.coffee", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -232,7 +265,7 @@ }, { "c": "alert", - "t": "source.coffee entity.name.function.coffee", + "t": "source.coffee meta.function-call.coffee entity.name.function.coffee", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -243,7 +276,7 @@ }, { "c": " ", - "t": "source.coffee", + "t": "source.coffee meta.function-call.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -254,7 +287,7 @@ }, { "c": "\"", - "t": "source.coffee string.quoted.double.coffee punctuation.definition.string.begin.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee punctuation.definition.string.begin.coffee", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -265,7 +298,7 @@ }, { "c": "Drive ", - "t": "source.coffee string.quoted.double.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -276,18 +309,18 @@ }, { "c": "#{", - "t": "source.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", "r": { - "dark_plus": "punctuation.section.embedded.coffee: #569CD6", - "light_plus": "punctuation.section.embedded.coffee: #0000FF", - "dark_vs": "punctuation.section.embedded.coffee: #569CD6", - "light_vs": "punctuation.section.embedded.coffee: #0000FF", - "hc_black": "punctuation.section.embedded.coffee: #569CD6" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "@name", - "t": "source.coffee string.quoted.double.coffee source.coffee.embedded.source variable.other.readwrite.instance.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee source.coffee.embedded.source variable.other.readwrite.instance.coffee", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -298,18 +331,18 @@ }, { "c": "}", - "t": "source.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", "r": { - "dark_plus": "punctuation.section.embedded.coffee: #569CD6", - "light_plus": "punctuation.section.embedded.coffee: #0000FF", - "dark_vs": "punctuation.section.embedded.coffee: #569CD6", - "light_vs": "punctuation.section.embedded.coffee: #0000FF", - "hc_black": "punctuation.section.embedded.coffee: #569CD6" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "\"", - "t": "source.coffee string.quoted.double.coffee punctuation.definition.string.end.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee punctuation.definition.string.end.coffee", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -419,7 +452,7 @@ }, { "c": ":", - "t": "source.coffee keyword.operator.coffee", + "t": "source.coffee meta.function.coffee keyword.operator.assignment.coffee", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -430,7 +463,7 @@ }, { "c": " ", - "t": "source.coffee", + "t": "source.coffee meta.function.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -440,19 +473,30 @@ } }, { - "c": "()", - "t": "source.coffee meta.inline.function.coffee variable.parameter.function.coffee", + "c": "(", + "t": "source.coffee meta.function.coffee meta.parameters.coffee punctuation.definition.parameters.begin.bracket.round.coffee", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.coffee meta.function.coffee meta.parameters.coffee punctuation.definition.parameters.end.bracket.round.coffee", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" } }, { "c": " ", - "t": "source.coffee meta.inline.function.coffee", + "t": "source.coffee meta.function.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -463,7 +507,7 @@ }, { "c": "=>", - "t": "source.coffee meta.inline.function.coffee storage.type.function.coffee", + "t": "source.coffee meta.function.coffee storage.type.function.coffee", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -485,7 +529,7 @@ }, { "c": "alert", - "t": "source.coffee entity.name.function.coffee", + "t": "source.coffee meta.function-call.coffee entity.name.function.coffee", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -496,7 +540,7 @@ }, { "c": " ", - "t": "source.coffee", + "t": "source.coffee meta.function-call.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -507,7 +551,7 @@ }, { "c": "\"", - "t": "source.coffee string.quoted.double.coffee punctuation.definition.string.begin.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee punctuation.definition.string.begin.coffee", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -518,7 +562,7 @@ }, { "c": "Driving ", - "t": "source.coffee string.quoted.double.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -529,18 +573,18 @@ }, { "c": "#{", - "t": "source.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", "r": { - "dark_plus": "punctuation.section.embedded.coffee: #569CD6", - "light_plus": "punctuation.section.embedded.coffee: #0000FF", - "dark_vs": "punctuation.section.embedded.coffee: #569CD6", - "light_vs": "punctuation.section.embedded.coffee: #0000FF", - "hc_black": "punctuation.section.embedded.coffee: #569CD6" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "@name", - "t": "source.coffee string.quoted.double.coffee source.coffee.embedded.source variable.other.readwrite.instance.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee source.coffee.embedded.source variable.other.readwrite.instance.coffee", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -551,18 +595,18 @@ }, { "c": "}", - "t": "source.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee source.coffee.embedded.source punctuation.section.embedded.coffee", "r": { - "dark_plus": "punctuation.section.embedded.coffee: #569CD6", - "light_plus": "punctuation.section.embedded.coffee: #0000FF", - "dark_vs": "punctuation.section.embedded.coffee: #569CD6", - "light_vs": "punctuation.section.embedded.coffee: #0000FF", - "hc_black": "punctuation.section.embedded.coffee: #569CD6" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "\"", - "t": "source.coffee string.quoted.double.coffee punctuation.definition.string.end.coffee", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee string.quoted.double.coffee punctuation.definition.string.end.coffee", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -595,7 +639,7 @@ }, { "c": "=", - "t": "source.coffee keyword.operator.coffee", + "t": "source.coffee keyword.operator.assignment.coffee", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -617,7 +661,7 @@ }, { "c": "new", - "t": "source.coffee meta.class.instance.constructor keyword.operator.new.coffee", + "t": "source.coffee meta.class.instance.constructor.coffee keyword.operator.new.coffee", "r": { "dark_plus": "keyword.operator.new: #569CD6", "light_plus": "keyword.operator.new: #0000FF", @@ -628,7 +672,7 @@ }, { "c": " ", - "t": "source.coffee meta.class.instance.constructor", + "t": "source.coffee meta.class.instance.constructor.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -639,7 +683,7 @@ }, { "c": "Car", - "t": "source.coffee meta.class.instance.constructor entity.name.type.instance.coffee", + "t": "source.coffee meta.class.instance.constructor.coffee entity.name.type.instance.coffee", "r": { "dark_plus": "entity.name.type: #4EC9B0", "light_plus": "entity.name.type: #267F99", @@ -716,7 +760,7 @@ }, { "c": "onTheRoad", - "t": "source.coffee entity.name.function.coffee", + "t": "source.coffee meta.function-call.coffee entity.name.function.coffee", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -726,8 +770,8 @@ } }, { - "c": "()", - "t": "source.coffee meta.brace.round.coffee", + "c": "(", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee punctuation.definition.arguments.begin.bracket.round.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -737,7 +781,18 @@ } }, { - "c": " c", + "c": ")", + "t": "source.coffee meta.function-call.coffee meta.arguments.coffee punctuation.definition.arguments.end.bracket.round.coffee", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", "t": "source.coffee", "r": { "dark_plus": "default: #D4D4D4", @@ -747,9 +802,20 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": "c", + "t": "source.coffee variable.other.object.coffee", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, { "c": ".", - "t": "source.coffee meta.delimiter.method.period.coffee", + "t": "source.coffee meta.method-call.coffee punctuation.separator.method.period.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -760,7 +826,7 @@ }, { "c": "drive", - "t": "source.coffee entity.name.function.coffee", + "t": "source.coffee meta.method-call.coffee entity.name.function.coffee", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -770,8 +836,19 @@ } }, { - "c": "()", - "t": "source.coffee meta.brace.round.coffee", + "c": "(", + "t": "source.coffee meta.method-call.coffee meta.arguments.coffee punctuation.definition.arguments.begin.bracket.round.coffee", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.coffee meta.method-call.coffee meta.arguments.coffee punctuation.definition.arguments.end.bracket.round.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -804,7 +881,7 @@ }, { "c": "=", - "t": "source.coffee keyword.operator.coffee", + "t": "source.coffee keyword.operator.assignment.coffee", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -837,7 +914,7 @@ }, { "c": "new", - "t": "source.coffee meta.class.instance.constructor keyword.operator.new.coffee", + "t": "source.coffee meta.class.instance.constructor.coffee keyword.operator.new.coffee", "r": { "dark_plus": "keyword.operator.new: #569CD6", "light_plus": "keyword.operator.new: #0000FF", @@ -848,7 +925,7 @@ }, { "c": " ", - "t": "source.coffee meta.class.instance.constructor", + "t": "source.coffee meta.class.instance.constructor.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -859,7 +936,7 @@ }, { "c": "Car", - "t": "source.coffee meta.class.instance.constructor entity.name.type.instance.coffee", + "t": "source.coffee meta.class.instance.constructor.coffee entity.name.type.instance.coffee", "r": { "dark_plus": "entity.name.type: #4EC9B0", "light_plus": "entity.name.type: #267F99", @@ -925,7 +1002,7 @@ }, { "c": "[", - "t": "source.coffee meta.brace.square.coffee", + "t": "source.coffee punctuation.definition.array.begin.bracket.square.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -936,7 +1013,7 @@ }, { "c": "1", - "t": "source.coffee constant.numeric.coffee", + "t": "source.coffee constant.numeric.decimal.coffee", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -947,7 +1024,7 @@ }, { "c": "..", - "t": "source.coffee keyword.operator.coffee", + "t": "source.coffee keyword.operator.slice.inclusive.coffee", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -958,7 +1035,7 @@ }, { "c": "100", - "t": "source.coffee constant.numeric.coffee", + "t": "source.coffee constant.numeric.decimal.coffee", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -969,7 +1046,7 @@ }, { "c": "]", - "t": "source.coffee meta.brace.square.coffee", + "t": "source.coffee punctuation.definition.array.end.bracket.square.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1013,7 +1090,7 @@ }, { "c": "=", - "t": "source.coffee keyword.operator.coffee", + "t": "source.coffee meta.function.coffee keyword.operator.assignment.coffee", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1024,7 +1101,7 @@ }, { "c": " ", - "t": "source.coffee", + "t": "source.coffee meta.function.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1034,8 +1111,19 @@ } }, { - "c": "(vehicles)", - "t": "source.coffee meta.inline.function.coffee variable.parameter.function.coffee", + "c": "(", + "t": "source.coffee meta.function.coffee meta.parameters.coffee punctuation.definition.parameters.begin.bracket.round.coffee", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "vehicles", + "t": "source.coffee meta.function.coffee meta.parameters.coffee variable.parameter.function.coffee", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1044,9 +1132,20 @@ "hc_black": "variable: #9CDCFE" } }, + { + "c": ")", + "t": "source.coffee meta.function.coffee meta.parameters.coffee punctuation.definition.parameters.end.bracket.round.coffee", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, { "c": " ", - "t": "source.coffee meta.inline.function.coffee", + "t": "source.coffee meta.function.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1057,7 +1156,7 @@ }, { "c": "->", - "t": "source.coffee meta.inline.function.coffee storage.type.function.coffee", + "t": "source.coffee meta.function.coffee storage.type.function.coffee", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -1079,7 +1178,7 @@ }, { "c": "[", - "t": "source.coffee meta.brace.square.coffee", + "t": "source.coffee punctuation.definition.array.begin.bracket.square.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1090,18 +1189,18 @@ }, { "c": "vehicle", - "t": "source.coffee", + "t": "source.coffee variable.other.object.coffee", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "variable: #9CDCFE" } }, { "c": ".", - "t": "source.coffee meta.delimiter.method.period.coffee", + "t": "source.coffee meta.method-call.coffee punctuation.separator.method.period.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1112,7 +1211,7 @@ }, { "c": "drive", - "t": "source.coffee entity.name.function.coffee", + "t": "source.coffee meta.method-call.coffee entity.name.function.coffee", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1122,8 +1221,19 @@ } }, { - "c": "()", - "t": "source.coffee meta.brace.round.coffee", + "c": "(", + "t": "source.coffee meta.method-call.coffee meta.arguments.coffee punctuation.definition.arguments.begin.bracket.round.coffee", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.coffee meta.method-call.coffee meta.arguments.coffee punctuation.definition.arguments.end.bracket.round.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1189,7 +1299,7 @@ }, { "c": "]", - "t": "source.coffee meta.brace.square.coffee", + "t": "source.coffee punctuation.definition.array.end.bracket.square.coffee", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1222,7 +1332,7 @@ }, { "c": "=", - "t": "source.coffee keyword.operator.coffee", + "t": "source.coffee keyword.operator.assignment.coffee", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1244,7 +1354,7 @@ }, { "c": "///", - "t": "source.coffee string.regexp.coffee punctuation.definition.string.begin.coffee", + "t": "source.coffee string.regexp.multiline.coffee punctuation.definition.string.begin.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1255,7 +1365,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1266,10 +1376,10 @@ }, { "c": "(", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.definition.group.regexp: #CE9178", + "light_plus": "punctuation.definition.group.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -1277,21 +1387,21 @@ }, { "c": "\\d", - "t": "source.coffee string.regexp.coffee meta.group.regexp constant.character.character-class.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp constant.character.character-class.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.character-class.regexp: #D16969", + "light_plus": "constant.character.character-class.regexp: #811F3F", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { "c": "+", - "t": "source.coffee string.regexp.coffee meta.group.regexp keyword.operator.quantifier.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp keyword.operator.quantifier.regexp", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", + "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", + "light_plus": "keyword.operator.quantifier.regexp: #000000", "dark_vs": "keyword.operator: #D4D4D4", "light_vs": "keyword.operator: #000000", "hc_black": "keyword.operator: #D4D4D4" @@ -1299,10 +1409,10 @@ }, { "c": ")", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.definition.group.regexp: #CE9178", + "light_plus": "punctuation.definition.group.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -1310,7 +1420,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1321,7 +1431,7 @@ }, { "c": "#", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1332,7 +1442,7 @@ }, { "c": " numbers", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1343,7 +1453,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1354,10 +1464,10 @@ }, { "c": "(", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.definition.group.regexp: #CE9178", + "light_plus": "punctuation.definition.group.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -1365,21 +1475,21 @@ }, { "c": "\\w", - "t": "source.coffee string.regexp.coffee meta.group.regexp constant.character.character-class.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp constant.character.character-class.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.character-class.regexp: #D16969", + "light_plus": "constant.character.character-class.regexp: #811F3F", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { "c": "*", - "t": "source.coffee string.regexp.coffee meta.group.regexp keyword.operator.quantifier.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp keyword.operator.quantifier.regexp", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", + "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", + "light_plus": "keyword.operator.quantifier.regexp: #000000", "dark_vs": "keyword.operator: #D4D4D4", "light_vs": "keyword.operator: #000000", "hc_black": "keyword.operator: #D4D4D4" @@ -1387,10 +1497,10 @@ }, { "c": ")", - "t": "source.coffee string.regexp.coffee meta.group.regexp punctuation.definition.group.regexp", + "t": "source.coffee string.regexp.multiline.coffee meta.group.regexp punctuation.definition.group.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.definition.group.regexp: #CE9178", + "light_plus": "punctuation.definition.group.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -1398,7 +1508,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1409,7 +1519,7 @@ }, { "c": "#", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1420,7 +1530,7 @@ }, { "c": " letters", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1431,7 +1541,7 @@ }, { "c": "\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1442,10 +1552,10 @@ }, { "c": "$", - "t": "source.coffee string.regexp.coffee keyword.control.anchor.regexp", + "t": "source.coffee string.regexp.multiline.coffee keyword.control.anchor.regexp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "keyword.control.anchor.regexp: #DCDCAA", + "light_plus": "keyword.control.anchor.regexp: #FF0000", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -1453,7 +1563,7 @@ }, { "c": "\t\t", - "t": "source.coffee string.regexp.coffee", + "t": "source.coffee string.regexp.multiline.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -1464,7 +1574,7 @@ }, { "c": "#", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee punctuation.definition.comment.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1475,7 +1585,7 @@ }, { "c": " the end", - "t": "source.coffee string.regexp.coffee comment.line.number-sign.coffee", + "t": "source.coffee string.regexp.multiline.coffee comment.line.number-sign.coffee", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1486,7 +1596,7 @@ }, { "c": "///", - "t": "source.coffee string.regexp.coffee punctuation.definition.string.end.coffee", + "t": "source.coffee string.regexp.multiline.coffee punctuation.definition.string.end.coffee", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index 1fd34c23234..67c6c899c16 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -33,19 +33,11 @@ }, { "fileMatch": "vscode://defaultsettings/settings.json", - "url": "vscode://schemas/settings" - }, - { - "fileMatch": "vscode://defaultsettings/resourceSettings.json", - "url": "vscode://schemas/settings/resource" - }, - { - "fileMatch": "vscode://settings/workspaceSettings.json", - "url": "vscode://schemas/settings" + "url": "vscode://schemas/settings/default" }, { "fileMatch": "%APP_SETTINGS_HOME%/settings.json", - "url": "vscode://schemas/settings" + "url": "vscode://schemas/settings/user" }, { "fileMatch": "%APP_WORKSPACES_HOME%/*/workspace.json", @@ -61,7 +53,7 @@ }, { "fileMatch": "/.vscode/settings.json", - "url": "vscode://schemas/settings" + "url": "vscode://schemas/settings/folder" }, { "fileMatch": "/.vscode/launch.json", @@ -82,6 +74,6 @@ ] }, "devDependencies": { - "@types/node": "^7.0.4" + "@types/node": "7.0.4" } -} \ No newline at end of file +} diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts index f18c3fe7c25..75e41fbd0d0 100644 --- a/extensions/configuration-editing/src/extension.ts +++ b/extensions/configuration-editing/src/extension.ts @@ -19,7 +19,7 @@ const decoration = vscode.window.createTextEditorDecorationType({ let pendingLaunchJsonDecoration: NodeJS.Timer; -export function activate(context): void { +export function activate(context: vscode.ExtensionContext): void { //keybindings.json command-suggestions context.subscriptions.push(registerKeybindingsCompletions()); @@ -27,8 +27,8 @@ export function activate(context): void { //settings.json suggestions context.subscriptions.push(registerSettingsCompletions()); - //extensions.json suggestions - context.subscriptions.push(registerExtensionsCompletions()); + //extensions suggestions + context.subscriptions.push(...registerExtensionsCompletions()); // launch.json decorations context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(editor => updateLaunchJsonDecorations(editor), null, context.subscriptions)); @@ -67,43 +67,69 @@ function registerSettingsCompletions(): vscode.Disposable { }); } -function registerExtensionsCompletions(): vscode.Disposable { +interface IExtensionsContent { + recommendations: string[]; +} + +function registerExtensionsCompletions(): vscode.Disposable[] { + return [registerExtensionsCompletionsInExtensionsDocument(), registerExtensionsCompletionsInWorkspaceConfigurationDocument()]; +} + +function registerExtensionsCompletionsInExtensionsDocument(): vscode.Disposable { return vscode.languages.registerCompletionItemProvider({ pattern: '**/extensions.json' }, { provideCompletionItems(document, position, token) { const location = getLocation(document.getText(), document.offsetAt(position)); const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position); if (location.path[0] === 'recommendations') { - const config = parse(document.getText()); - const alreadyEnteredExtensions = config && config.recommendations || []; - if (Array.isArray(alreadyEnteredExtensions)) { - const knownExtensionProposals = vscode.extensions.all.filter(e => - !(e.id.startsWith('vscode.') - || e.id === 'Microsoft.vscode-markdown' - || alreadyEnteredExtensions.indexOf(e.id) > -1)); - if (knownExtensionProposals.length) { - return knownExtensionProposals.map(e => { - const item = new vscode.CompletionItem(e.id); - const insertText = `"${e.id}"`; - item.kind = vscode.CompletionItemKind.Value; - item.insertText = insertText; - item.range = range; - item.filterText = insertText; - return item; - }); - } else { - const example = new vscode.CompletionItem(localize('exampleExtension', "Example")); - example.insertText = '"vscode.csharp"'; - example.kind = vscode.CompletionItemKind.Value; - example.range = range; - return [example]; - } - } + const extensionsContent = parse(document.getText()); + return provideInstalledExtensionProposals(extensionsContent, range); } return []; } }); } +function registerExtensionsCompletionsInWorkspaceConfigurationDocument(): vscode.Disposable { + return vscode.languages.registerCompletionItemProvider({ pattern: '**/*.code-workspace' }, { + provideCompletionItems(document, position, token) { + const location = getLocation(document.getText(), document.offsetAt(position)); + const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position); + if (location.path[0] === 'extensions' && location.path[1] === 'recommendations') { + const extensionsContent = parse(document.getText())['extensions']; + return provideInstalledExtensionProposals(extensionsContent, range); + } + return []; + } + }); +} + +function provideInstalledExtensionProposals(extensionsContent: IExtensionsContent, range: vscode.Range): vscode.ProviderResult { + const alreadyEnteredExtensions = extensionsContent && extensionsContent.recommendations || []; + if (Array.isArray(alreadyEnteredExtensions)) { + const knownExtensionProposals = vscode.extensions.all.filter(e => + !(e.id.startsWith('vscode.') + || e.id === 'Microsoft.vscode-markdown' + || alreadyEnteredExtensions.indexOf(e.id) > -1)); + if (knownExtensionProposals.length) { + return knownExtensionProposals.map(e => { + const item = new vscode.CompletionItem(e.id); + const insertText = `"${e.id}"`; + item.kind = vscode.CompletionItemKind.Value; + item.insertText = insertText; + item.range = range; + item.filterText = insertText; + return item; + }); + } else { + const example = new vscode.CompletionItem(localize('exampleExtension', "Example")); + example.insertText = '"vscode.csharp"'; + example.kind = vscode.CompletionItemKind.Value; + example.range = range; + return [example]; + } + } +} + function newSimpleCompletionItem(label: string, range: vscode.Range, description?: string, insertText?: string): vscode.CompletionItem { const item = new vscode.CompletionItem(label); item.kind = vscode.CompletionItemKind.Value; diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index dc4c47ac129..9bdfe486b35 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -43,13 +43,13 @@ export class SettingsDocument { private provideWindowTitleCompletionItems(location: Location, range: vscode.Range): vscode.ProviderResult { const completions: vscode.CompletionItem[] = []; - completions.push(this.newSimpleCompletionItem('${activeEditorShort}', range, localize('activeEditorShort', "e.g. myFile.txt"))); - completions.push(this.newSimpleCompletionItem('${activeEditorMedium}', range, localize('activeEditorMedium', "e.g. myFolder/myFile.txt"))); - completions.push(this.newSimpleCompletionItem('${activeEditorLong}', range, localize('activeEditorLong', "e.g. /Users/Development/myProject/myFolder/myFile.txt"))); - completions.push(this.newSimpleCompletionItem('${rootName}', range, localize('rootName', "e.g. myFolder1, myFolder2, myFolder3"))); - completions.push(this.newSimpleCompletionItem('${rootPath}', range, localize('rootPath', "e.g. /Users/Development/myProject"))); - completions.push(this.newSimpleCompletionItem('${folderName}', range, localize('folderName', "e.g. myFolder"))); - completions.push(this.newSimpleCompletionItem('${folderPath}', range, localize('folderPath', "e.g. /Users/Development/myFolder"))); + completions.push(this.newSimpleCompletionItem('${activeEditorShort}', range, localize('activeEditorShort', "the file name (e.g. myFile.txt)"))); + completions.push(this.newSimpleCompletionItem('${activeEditorMedium}', range, localize('activeEditorMedium', "the path of the file relative to the workspace folder (e.g. myFolder/myFile.txt)"))); + completions.push(this.newSimpleCompletionItem('${activeEditorLong}', range, localize('activeEditorLong', "the full path of the file (e.g. /Users/Development/myProject/myFolder/myFile.txt)"))); + completions.push(this.newSimpleCompletionItem('${rootName}', range, localize('rootName', "name of the workspace (e.g. myFolder or myWorkspace)"))); + completions.push(this.newSimpleCompletionItem('${rootPath}', range, localize('rootPath', "file path of the workspace (e.g. /Users/Development/myWorkspace)"))); + completions.push(this.newSimpleCompletionItem('${folderName}', range, localize('folderName', "name of the workspace folder the file is contained in (e.g. myFolder)"))); + completions.push(this.newSimpleCompletionItem('${folderPath}', range, localize('folderPath', "file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)"))); completions.push(this.newSimpleCompletionItem('${appName}', range, localize('appName', "e.g. VS Code"))); completions.push(this.newSimpleCompletionItem('${dirty}', range, localize('dirty', "a dirty indicator if the active editor is dirty"))); completions.push(this.newSimpleCompletionItem('${separator}', range, localize('separator', "a conditional separator (' - ') that only shows when surrounded by variables with values"))); @@ -149,7 +149,7 @@ export class SettingsDocument { return Promise.resolve(completions); } - private provideLanguageCompletionItems(location: Location, range: vscode.Range, formatFunc: (string) => string = (l) => JSON.stringify(l)): vscode.ProviderResult { + private provideLanguageCompletionItems(location: Location, range: vscode.Range, formatFunc: (string: string) => string = (l) => JSON.stringify(l)): vscode.ProviderResult { return vscode.languages.getLanguages().then(languages => { return languages.map(l => { return this.newSimpleCompletionItem(formatFunc(l), range); diff --git a/extensions/configuration-editing/tsconfig.json b/extensions/configuration-editing/tsconfig.json index 6971f531b11..23392904dee 100644 --- a/extensions/configuration-editing/tsconfig.json +++ b/extensions/configuration-editing/tsconfig.json @@ -6,7 +6,7 @@ "lib": [ "es2015" ], - "strictNullChecks": true + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index a8782a61e3c..a4f6c85aeab 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -25,5 +25,11 @@ "indentationRules": { "increaseIndentPattern": "^.*\\{[^}\"\\']*$|^.*\\([^\\)\"\\']*$|^\\s*(public|private|protected):\\s*$|^\\s*@(public|private|protected)\\s*$|^\\s*\\{\\}$", "decreaseIndentPattern": "^\\s*(\\s*/[*].*[*]/\\s*)*\\}|^\\s*(\\s*/[*].*[*]/\\s*)*\\)|^\\s*(public|private|protected):\\s*$|^\\s*@(public|private|protected)\\s*$" + }, + "folding": { + "markers": { + "start": "^\\s*#pragma\\s+region\\b", + "end": "^\\s*#pragma\\s+endregion\\b" + } } } \ No newline at end of file diff --git a/extensions/cpp/package.json b/extensions/cpp/package.json index ce8f3d711a6..169cabff934 100644 --- a/extensions/cpp/package.json +++ b/extensions/cpp/package.json @@ -32,6 +32,14 @@ { "scopeName": "source.c.platform", "path": "./syntaxes/Platform.tmLanguage" + }], + "snippets": [{ + "language": "c", + "path": "./snippets/c.json" + }, + { + "language": "cpp", + "path": "./snippets/cpp.json" }] } } \ No newline at end of file diff --git a/extensions/cpp/snippets/c.json b/extensions/cpp/snippets/c.json new file mode 100644 index 00000000000..d9628dfe42c --- /dev/null +++ b/extensions/cpp/snippets/c.json @@ -0,0 +1,16 @@ +{ + "Region Start": { + "prefix": "#region", + "body": [ + "#pragma region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#endregion", + "body": [ + "#pragma endregion" + ], + "description": "Folding Region End" + } +} diff --git a/extensions/cpp/snippets/cpp.json b/extensions/cpp/snippets/cpp.json new file mode 100644 index 00000000000..d9628dfe42c --- /dev/null +++ b/extensions/cpp/snippets/cpp.json @@ -0,0 +1,16 @@ +{ + "Region Start": { + "prefix": "#region", + "body": [ + "#pragma region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#endregion", + "body": [ + "#pragma endregion" + ], + "description": "Folding Region End" + } +} diff --git a/extensions/cpp/syntaxes/c.json b/extensions/cpp/syntaxes/c.json index c81bd51eadc..d5143bd4901 100644 --- a/extensions/cpp/syntaxes/c.json +++ b/extensions/cpp/syntaxes/c.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/atom/language-c/commit/0a57fd7ee32bd14e3ee8291434263d744a8ecf1e", + "version": "https://github.com/atom/language-c/commit/9c0c5f202741a5647025db8d5df5fefba47b036c", "scopeName": "source.c", "fileTypes": [ "c", @@ -780,7 +780,7 @@ }, "patterns": [ { - "begin": "\\G", + "begin": "\\G(?=.)(?!//|/\\*(?!.*\\\\\\s*\\n))", "end": "(?=//)|(?=/\\*(?!.*\\\\\\s*\\n))|(?"], ["'", "'"], ["\"", "\""] - ] + ], + "folding": { + "markers": { + "start": "^\\s*#region\\b", + "end": "^\\s*#endregion\\b" + } + } } \ No newline at end of file diff --git a/extensions/csharp/package.json b/extensions/csharp/package.json index 8bdbb161080..137ce2656d6 100644 --- a/extensions/csharp/package.json +++ b/extensions/csharp/package.json @@ -31,6 +31,10 @@ "scopeName": "source.cs", "path": "./syntaxes/csharp.tmLanguage.json" } - ] + ], + "snippets": [{ + "language": "csharp", + "path": "./snippets/csharp.json" + }] } } \ No newline at end of file diff --git a/extensions/csharp/snippets/csharp.json b/extensions/csharp/snippets/csharp.json new file mode 100644 index 00000000000..5ad4bfca6c1 --- /dev/null +++ b/extensions/csharp/snippets/csharp.json @@ -0,0 +1,16 @@ +{ + "Region Start": { + "prefix": "#region", + "body": [ + "#region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#endregion", + "body": [ + "#endregion" + ], + "description": "Folding Region End" + } +} diff --git a/extensions/csharp/syntaxes/csharp.tmLanguage.json b/extensions/csharp/syntaxes/csharp.tmLanguage.json index 11d402b5e4c..9a96c9bbbee 100644 --- a/extensions/csharp/syntaxes/csharp.tmLanguage.json +++ b/extensions/csharp/syntaxes/csharp.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/dotnet/csharp-tmLanguage/commit/2f2152632650d427e99e261f093d52b807abc72d", + "version": "https://github.com/dotnet/csharp-tmLanguage/commit/436456ee5ce44e29cb1752c3b29f493b1de08c42", "name": "C#", "scopeName": "source.cs", "fileTypes": [ @@ -229,6 +229,9 @@ { "include": "#yield-statement" }, + { + "include": "#await-statement" + }, { "include": "#try-statement" }, @@ -1606,6 +1609,20 @@ } } }, + "await-statement": { + "begin": "(? { // register color provider context.subscriptions.push(languages.registerColorProvider(documentSelector, { - provideDocumentColors(document: TextDocument): Thenable { - let params = client.code2ProtocolConverter.asDocumentSymbolParams(document); + provideDocumentColors(document: TextDocument): Thenable { + let params: DocumentColorParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) + }; return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); - let color = new Color(symbol.color.red * 255, symbol.color.green * 255, symbol.color.blue * 255, symbol.color.alpha); - return new ColorRange(range, color, [CSSColorFormats.Hex, CSSColorFormats.RGB, CSSColorFormats.HSL]); + let color = new Color(symbol.color.red, symbol.color.green, symbol.color.blue, symbol.color.alpha); + return new ColorInformation(range, color); + }); + }); + }, + provideColorPresentations(color: Color, context): ColorPresentation[] | Thenable { + let params: ColorPresentationParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(context.document), + color, + range: client.code2ProtocolConverter.asRange(context.range) + }; + return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { + return presentations.map(p => { + let presentation = new ColorPresentation(p.label); + presentation.textEdit = p.textEdit && client.protocol2CodeConverter.asTextEdit(p.textEdit); + presentation.additionalTextEdits = p.additionalTextEdits && client.protocol2CodeConverter.asTextEdits(p.additionalTextEdits); + return presentation; }); }); } diff --git a/extensions/css/client/src/typings/color-convert.d.ts b/extensions/css/client/src/typings/color-convert.d.ts new file mode 100644 index 00000000000..a88de674d2d --- /dev/null +++ b/extensions/css/client/src/typings/color-convert.d.ts @@ -0,0 +1,11 @@ +declare module "color-convert" { + module convert { + module rgb { + function hex(r: number, g: number, b: number); + function hsl(r: number, g: number, b: number); + function hvs(r: number, g: number, b: number); + } + } + + export = convert; +} \ No newline at end of file diff --git a/extensions/css/client/tsconfig.json b/extensions/css/client/tsconfig.json index e87d1a805a1..dc12dad6cf0 100644 --- a/extensions/css/client/tsconfig.json +++ b/extensions/css/client/tsconfig.json @@ -3,6 +3,7 @@ "target": "es5", "module": "commonjs", "outDir": "./out", + "noUnusedLocals": true, "lib": [ "es5", "es2015.promise" ] diff --git a/extensions/css/language-configuration.json b/extensions/css/language-configuration.json index ae86befcd2a..bd3151ea17e 100644 --- a/extensions/css/language-configuration.json +++ b/extensions/css/language-configuration.json @@ -20,5 +20,11 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] -} \ No newline at end of file + ], + "folding": { + "markers": { + "start": "^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/", + "end": "^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/" + } + } +} diff --git a/extensions/css/npm-shrinkwrap.json b/extensions/css/npm-shrinkwrap.json index d645e03b53f..05ef43dfbe8 100644 --- a/extensions/css/npm-shrinkwrap.json +++ b/extensions/css/npm-shrinkwrap.json @@ -3,24 +3,24 @@ "version": "0.1.0", "dependencies": { "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.5.0-next.2", + "from": "vscode-jsonrpc@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz" }, "vscode-languageclient": { - "version": "3.4.0-next.17", - "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.0-next.17.tgz" + "version": "3.5.0-next.4", + "from": "vscode-languageclient@3.5.0-next.4", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0-next.4.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.5.0-next.5", + "from": "vscode-languageserver-protocol@3.5.0-next.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.5.0-next.2", + "from": "vscode-languageserver-types@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/css/package.json b/extensions/css/package.json index 686dd900e0b..ccd73a979dd 100644 --- a/extensions/css/package.json +++ b/extensions/css/package.json @@ -50,698 +50,680 @@ "path": "./snippets/css.json" } ], - "configuration": { - "order": 20, - "allOf": [ - { - "id": "css", - "title": "CSS", - "allOf": [ - { - "title": "%css.validate.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 (Sass)", - "allOf": [ - { - "title": "%scss.validate.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": 22, - "type": "object", - "title": "LESS", - "allOf": [ - { - "title": "%less.validate.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%" - } - } - } - ] + "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": "3.4.0-next.17", - "vscode-languageserver-protocol": "^3.1.1", + "vscode-languageclient": "3.5.0-next.4", "vscode-nls": "^2.0.2" }, "devDependencies": { - "@types/node": "^6.0.51" + "@types/node": "7.0.43" } } diff --git a/extensions/css/package.nls.json b/extensions/css/package.nls.json index b2a7126c30d..33fbf6d5c28 100644 --- a/extensions/css/package.nls.json +++ b/extensions/css/package.nls.json @@ -1,4 +1,5 @@ { + "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", @@ -20,6 +21,7 @@ "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", @@ -40,6 +42,7 @@ "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", diff --git a/extensions/css/server/.vscode/launch.json b/extensions/css/server/.vscode/launch.json index a09436fd912..764c1456f17 100644 --- a/extensions/css/server/.vscode/launch.json +++ b/extensions/css/server/.vscode/launch.json @@ -8,25 +8,25 @@ "request": "attach", "port": 6004, "sourceMaps": true, - "outDir": "${workspaceRoot}/out" + "outDir": "${workspaceFolder}/out" }, { "name": "Unit Tests", "type": "node", "request": "launch", - "program": "${workspaceRoot}/../../../node_modules/mocha/bin/_mocha", + "program": "${workspaceFolder}/../../../node_modules/mocha/bin/_mocha", "stopOnEntry": false, "args": [ "--timeout", "999999", "--colors" ], - "cwd": "${workspaceRoot}", + "cwd": "${workspaceFolder}", "runtimeExecutable": null, "runtimeArgs": [], "env": {}, "sourceMaps": true, - "outDir": "${workspaceRoot}/out" + "outDir": "${workspaceFolder}/out" } ] } \ No newline at end of file diff --git a/extensions/css/server/npm-shrinkwrap.json b/extensions/css/server/npm-shrinkwrap.json index eeafae21433..9c575943a3e 100644 --- a/extensions/css/server/npm-shrinkwrap.json +++ b/extensions/css/server/npm-shrinkwrap.json @@ -3,29 +3,29 @@ "version": "1.0.0", "dependencies": { "vscode-css-languageservice": { - "version": "2.1.4", - "from": "vscode-css-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.4.tgz" + "version": "3.0.0", + "from": "vscode-css-languageservice@3.0.0", + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-3.0.0.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.5.0-next.2", + "from": "vscode-jsonrpc@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz" }, "vscode-languageserver": { - "version": "3.4.0-next.6", - "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.0-next.6.tgz" + "version": "3.5.0-next.6", + "from": "vscode-languageserver@3.5.0-next.6", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.6.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.5.0-next.5", + "from": "vscode-languageserver-protocol@3.5.0-next.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.5.0-next.2", + "from": "vscode-languageserver-types@3.5.0-next.2d", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/css/server/package.json b/extensions/css/server/package.json index ad6c972e571..f937b8a10fd 100644 --- a/extensions/css/server/package.json +++ b/extensions/css/server/package.json @@ -8,12 +8,11 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^2.1.4", - "vscode-languageserver": "3.4.0-next.6", - "vscode-languageserver-protocol": "^3.1.1" + "vscode-css-languageservice": "3.0.0", + "vscode-languageserver": "3.5.0-next.6" }, "devDependencies": { - "@types/node": "^6.0.51" + "@types/node": "7.0.43" }, "scripts": { "compile": "gulp compile-extension:css-server", diff --git a/extensions/css/server/src/cssServerMain.ts b/extensions/css/server/src/cssServerMain.ts index 0f4e8873e98..28837487764 100644 --- a/extensions/css/server/src/cssServerMain.ts +++ b/extensions/css/server/src/cssServerMain.ts @@ -5,11 +5,13 @@ 'use strict'; import { - createConnection, IConnection, TextDocuments, TextDocument, InitializeParams, InitializeResult, ServerCapabilities + createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities } from 'vscode-languageserver'; -import { GetConfigurationRequest } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; -import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { TextDocument } from 'vscode-languageserver-types'; + +import { ConfigurationRequest } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; +import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet } from 'vscode-css-languageservice'; import { getLanguageModelCache } from './languageModelCache'; @@ -96,7 +98,7 @@ function getDocumentSettings(textDocument: TextDocument): Thenable s[0]); + promise = connection.sendRequest(ConfigurationRequest.type, configRequestParam).then(s => s[0]); documentSettings[textDocument.uri] = promise; } return promise; @@ -211,6 +213,15 @@ connection.onRequest(DocumentColorRequest.type, params => { return []; }); +connection.onRequest(ColorPresentationRequest.type, params => { + let document = documents.get(params.textDocument.uri); + if (document) { + let stylesheet = stylesheets.get(document); + return getLanguageService(document).getColorPresentations(document, stylesheet, params.color, params.range); + } + return []; +}); + connection.onRenameRequest(renameParameters => { let document = documents.get(renameParameters.textDocument.uri); let stylesheet = stylesheets.get(document); diff --git a/extensions/css/server/tsconfig.json b/extensions/css/server/tsconfig.json index 8e862f02646..6092871c85b 100644 --- a/extensions/css/server/tsconfig.json +++ b/extensions/css/server/tsconfig.json @@ -3,6 +3,7 @@ "target": "es5", "module": "commonjs", "outDir": "./out", + "noUnusedLocals": true, "lib": [ "es5" ] diff --git a/extensions/css/syntaxes/css.tmLanguage.json b/extensions/css/syntaxes/css.tmLanguage.json index 52c5eec1308..95caf371210 100644 --- a/extensions/css/syntaxes/css.tmLanguage.json +++ b/extensions/css/syntaxes/css.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/atom/language-css/commit/02c1eb4e0d45f021694cf1825f6e2040872f3599", + "version": "https://github.com/atom/language-css/commit/ec289867164a34fce48a69776b7f8dc380e3dc37", "scopeName": "source.css", "name": "CSS", "fileTypes": [ @@ -670,7 +670,8 @@ "name": "constant.character.escape.codepoint.css" }, { - "match": "\\\\$\\n?", + "begin": "\\\\$\\s*", + "end": "^(?=1.0.17 <2.0.0", - "resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.1.7.tgz" + "version": "1.1.17", + "from": "vscode-emmet-helper@>=1.1.17 <2.0.0", + "resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.1.17.tgz" }, "vscode-languageserver-types": { "version": "3.3.0", @@ -53,4 +53,4 @@ "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz" } } -} +} \ No newline at end of file diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 31de43eb8bf..8dd6947b175 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -15,7 +15,12 @@ "url": "https://github.com/Microsoft/vscode-emmet" }, "activationEvents": [ - "*" + "*", + "onCommand:emmet.expandAbbreviation", + "onLanguage:html", + "onLanguage:css", + "onLanguage:scss", + "onLanguage:less" ], "main": "./out/extension", "contributes": { @@ -126,6 +131,34 @@ "type": "string", "default": " ", "description": "%emmetPreferencesStylusBetween%" + }, + "bem.elementSeparator": { + "type": "string", + "default": "__", + "description": "%emmetPreferencesBemElementSeparator%" + }, + "bem.modifierSeparator": { + "type": "string", + "default": "_", + "description": "%emmetPreferencesBemModifierSeparator%" + }, + "filter.commentBefore": { + "type": "string", + "default": "", + "description": "%emmetPreferencesFilterCommentBefore%" + }, + "filter.commentAfter": { + "type": "string", + "default": "\n", + "description": "%emmetPreferencesFilterCommentAfter%" + }, + "filter.commentTrigger": { + "type": "array", + "default": [ + "id", + "class" + ], + "description": "%emmetPreferencesFilterCommentTrigger%" } } }, @@ -258,16 +291,16 @@ "compile": "gulp compile-extension:emmet" }, "devDependencies": { - "@types/node": "^7.0.4", + "@types/node": "7.0.43", "vscode": "1.0.1" }, "dependencies": { "@emmetio/html-matcher": "^0.3.1", "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", "@emmetio/math-expression": "^0.1.1", - "vscode-emmet-helper": "^1.1.7", + "vscode-emmet-helper": "^1.1.17", "vscode-languageserver-types": "^3.0.3", "image-size": "^0.5.2", "vscode-nls": "2.0.2" } -} \ No newline at end of file +} diff --git a/extensions/emmet/package.nls.json b/extensions/emmet/package.nls.json index 4d63301d0ac..07ffacf4b44 100644 --- a/extensions/emmet/package.nls.json +++ b/extensions/emmet/package.nls.json @@ -23,13 +23,13 @@ "command.incrementNumberByTen": "Increment by 10", "command.decrementNumberByTen": "Decrement by 10", "emmetSyntaxProfiles": "Define profile for specified syntax or use your own profile with specific rules.", - "emmetExclude": "An array of languages where emmet abbreviations should not be expanded.", - "emmetExtensionsPath": "Path to a folder containing emmet profiles and snippets.'", - "emmetShowExpandedAbbreviation": "Shows expanded emmet abbreviations as suggestions.\nThe option \"inMarkupAndStylesheetFilesOnly\" applies to html, haml, jade, slim, xml, xsl, css, scss, sass, less and stylus.\nThe option \"always\" applies to all parts of the file regardless of markup/css.", - "emmetShowAbbreviationSuggestions": "Shows possible emmet abbreviations as suggestions. Not applicable in stylesheets or when emmet.showExpandedAbbreviation is set to \"never\".", - "emmetIncludeLanguages": "Enable emmet abbreviations in languages that are not supported by default. Add a mapping here between the language and emmet supported language.\n Eg: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", - "emmetVariables": "Variables to be used in emmet snippets", - "emmetTriggerExpansionOnTab": "When enabled, emmet abbreviations are expanded when pressing TAB.", + "emmetExclude": "An array of languages where Emmet abbreviations should not be expanded.", + "emmetExtensionsPath": "Path to a folder containing Emmet profiles and snippets.'", + "emmetShowExpandedAbbreviation": "Shows expanded Emmet abbreviations as suggestions.\nThe option \"inMarkupAndStylesheetFilesOnly\" applies to html, haml, jade, slim, xml, xsl, css, scss, sass, less and stylus.\nThe option \"always\" applies to all parts of the file regardless of markup/css.", + "emmetShowAbbreviationSuggestions": "Shows possible Emmet abbreviations as suggestions. Not applicable in stylesheets or when emmet.showExpandedAbbreviation is set to \"never\".", + "emmetIncludeLanguages": "Enable Emmet abbreviations in languages that are not supported by default. Add a mapping here between the language and emmet supported language.\n Eg: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "Variables to be used in Emmet snippets", + "emmetTriggerExpansionOnTab": "When enabled, Emmet abbreviations are expanded when pressing TAB.", "emmetPreferences": "Preferences used to modify behavior of some actions and resolvers of Emmet.", "emmetPreferencesIntUnit": "Default unit for integer values", "emmetPreferencesFloatUnit": "Default unit for float values", @@ -39,5 +39,10 @@ "emmetPreferencesCssBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations", "emmetPreferencesSassBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations in Sass files", "emmetPreferencesStylusBetween": "Symbol to be placed at the between CSS property and value when expanding CSS abbreviations in Stylus files", - "emmetShowSuggestionsAsSnippets": "If true, then emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting." -} \ No newline at end of file + "emmetShowSuggestionsAsSnippets": "If true, then Emmet suggestions will show up as snippets allowing you to order them as per editor.snippetSuggestions setting.", + "emmetPreferencesBemElementSeparator": "Element separator used for classes when using the BEM filter", + "emmetPreferencesBemModifierSeparator": "Modifier separator used for classes when using the BEM filter", + "emmetPreferencesFilterCommentBefore": "A definition of comment that should be placed before matched element when comment filter is applied.", + "emmetPreferencesFilterCommentAfter": "A definition of comment that should be placed after matched element when comment filter is applied.", + "emmetPreferencesFilterCommentTrigger": "A comma-separated list of attribute names that should exist in abbreviation for the comment filter to be applied" +} diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 5d341c2c636..0224594a33e 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -5,8 +5,7 @@ import * as vscode from 'vscode'; import { Node, HtmlNode, Rule } from 'EmmetNode'; -import { getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, validate, getEmmetConfiguration } from './util'; -import { getExpandOptions, extractAbbreviation, extractAbbreviationFromText, isStyleSheet, isAbbreviationValid, getEmmetMode, expandAbbreviation } from 'vscode-emmet-helper'; +import { getEmmetHelper, getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, validate, getEmmetConfiguration, isStyleSheet, getEmmetMode } from './util'; const trimRegex = /[\u00a0]*[\d|#|\-|\*|\u2022]+\.?/; @@ -18,17 +17,18 @@ interface ExpandAbbreviationInput { filter?: string; } -export function wrapWithAbbreviation(args) { - if (!validate(false)) { +export function wrapWithAbbreviation(args: any) { + if (!validate(false) || !vscode.window.activeTextEditor) { return; } const editor = vscode.window.activeTextEditor; const abbreviationPromise = (args && args['abbreviation']) ? Promise.resolve(args['abbreviation']) : vscode.window.showInputBox({ prompt: 'Enter Abbreviation' }); const syntax = getSyntaxFromArgs({ language: editor.document.languageId }); + const helper = getEmmetHelper(); return abbreviationPromise.then(abbreviation => { - if (!abbreviation || !abbreviation.trim() || !isAbbreviationValid(syntax, abbreviation)) { return; } + if (!abbreviation || !abbreviation.trim() || !helper.isAbbreviationValid(syntax, abbreviation)) { return; } let expandAbbrList: ExpandAbbreviationInput[] = []; @@ -50,8 +50,8 @@ export function wrapWithAbbreviation(args) { }); } -export function wrapIndividualLinesWithAbbreviation(args) { - if (!validate(false)) { +export function wrapIndividualLinesWithAbbreviation(args: any) { + if (!validate(false) || !vscode.window.activeTextEditor) { return; } @@ -64,11 +64,12 @@ export function wrapIndividualLinesWithAbbreviation(args) { const abbreviationPromise = (args && args['abbreviation']) ? Promise.resolve(args['abbreviation']) : vscode.window.showInputBox({ prompt: 'Enter Abbreviation' }); const syntax = getSyntaxFromArgs({ language: editor.document.languageId }); const lines = editor.document.getText(editor.selection).split('\n').map(x => x.trim()); + const helper = getEmmetHelper(); return abbreviationPromise.then(inputAbbreviation => { - if (!inputAbbreviation || !inputAbbreviation.trim() || !isAbbreviationValid(syntax, inputAbbreviation)) { return; } + if (!inputAbbreviation || !inputAbbreviation.trim() || !helper.isAbbreviationValid(syntax, inputAbbreviation)) { return; } - let extractedResults = extractAbbreviationFromText(inputAbbreviation); + let extractedResults = helper.extractAbbreviationFromText(inputAbbreviation); if (!extractedResults) { return; } @@ -87,7 +88,7 @@ export function wrapIndividualLinesWithAbbreviation(args) { } -export function expandEmmetAbbreviation(args): Thenable { +export function expandEmmetAbbreviation(args: any): Thenable { const syntax = getSyntaxFromArgs(args); if (!syntax || !validate()) { return fallbackTab(); @@ -105,12 +106,13 @@ export function expandEmmetAbbreviation(args): Thenable { let abbreviationList: ExpandAbbreviationInput[] = []; let firstAbbreviation: string; let allAbbreviationsSame: boolean = true; + const helper = getEmmetHelper(); let getAbbreviation = (document: vscode.TextDocument, selection: vscode.Selection, position: vscode.Position, syntax: string): [vscode.Range, string, string] => { let rangeToReplace: vscode.Range = selection; let abbr = document.getText(rangeToReplace); if (!rangeToReplace.isEmpty) { - let extractedResults = extractAbbreviationFromText(abbr); + let extractedResults = helper.extractAbbreviationFromText(abbr); if (extractedResults) { return [rangeToReplace, extractedResults.abbreviation, extractedResults.filter]; } @@ -130,7 +132,7 @@ export function expandEmmetAbbreviation(args): Thenable { return [rangeToReplace, abbr, '']; } } - let extractedResults = extractAbbreviation(editor.document, position, false); + let extractedResults = helper.extractAbbreviation(editor.document, position, false); if (!extractedResults) { return [null, '', '']; } @@ -139,17 +141,24 @@ export function expandEmmetAbbreviation(args): Thenable { return [new vscode.Range(abbreviationRange.start.line, abbreviationRange.start.character, abbreviationRange.end.line, abbreviationRange.end.character), abbreviation, filter]; }; - editor.selections.forEach(selection => { + let selectionsInReverseOrder = editor.selections.slice(0); + selectionsInReverseOrder.sort((a, b) => { + var posA = a.isReversed ? a.anchor : a.active; + var posB = b.isReversed ? b.anchor : b.active; + return posA.compareTo(posB) * -1; + }); + + selectionsInReverseOrder.forEach(selection => { let position = selection.isReversed ? selection.anchor : selection.active; let [rangeToReplace, abbreviation, filter] = getAbbreviation(editor.document, selection, position, syntax); if (!rangeToReplace) { return; } - if (!isAbbreviationValid(syntax, abbreviation)) { + if (!helper.isAbbreviationValid(syntax, abbreviation)) { return; } - let currentNode = getNode(rootNode, position); + let currentNode = getNode(rootNode, position, true); if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position)) { return; } @@ -170,7 +179,7 @@ export function expandEmmetAbbreviation(args): Thenable { }); } -function fallbackTab(): Thenable { +function fallbackTab(): Thenable | undefined { if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true) { return vscode.commands.executeCommand('tab'); } @@ -189,7 +198,6 @@ export function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: s } if (isStyleSheet(syntax)) { - // If current node is a rule or at-rule, then perform additional checks to ensure // emmet suggestions are not provided in the rule selector if (currentNode.type !== 'rule' && currentNode.type !== 'at-rule') { @@ -218,7 +226,8 @@ export function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: s const currentHtmlNode = currentNode; if (currentHtmlNode.close) { - return getInnerRange(currentHtmlNode).contains(position); + const innerRange = getInnerRange(currentHtmlNode); + return !!innerRange && innerRange.contains(position); } return false; @@ -239,7 +248,7 @@ function expandAbbreviationInRange(editor: vscode.TextEditor, expandAbbrList: Ex // Snippet to replace at multiple cursors are not the same // `editor.insertSnippet` will have to be called for each instance separately // We will not be able to maintain multiple cursors after snippet insertion - let insertPromises = []; + let insertPromises: Thenable[] = []; if (!insertSameSnippet) { expandAbbrList.forEach((expandAbbrInput: ExpandAbbreviationInput) => { let expandedText = expandAbbr(expandAbbrInput); @@ -270,8 +279,9 @@ function expandAbbreviationInRange(editor: vscode.TextEditor, expandAbbrList: Ex /** * Expands abbreviation as detailed in given input. */ -function expandAbbr(input: ExpandAbbreviationInput): string { - const expandOptions = getExpandOptions(input.syntax, getEmmetConfiguration(input.syntax), input.filter); +function expandAbbr(input: ExpandAbbreviationInput): string | undefined { + const helper = getEmmetHelper(); + const expandOptions = helper.getExpandOptions(input.syntax, getEmmetConfiguration(input.syntax), input.filter); if (input.textToWrap) { if (input.filter && input.filter.indexOf('t') > -1) { @@ -291,7 +301,7 @@ function expandAbbr(input: ExpandAbbreviationInput): string { try { // Expand the abbreviation - let expandedText = expandAbbreviation(input.abbreviation, expandOptions); + let expandedText = helper.expandAbbreviation(input.abbreviation, expandOptions); if (input.textToWrap) { // All $anyword would have been escaped by the emmet helper. @@ -313,7 +323,7 @@ function expandAbbr(input: ExpandAbbreviationInput): string { } -function getSyntaxFromArgs(args: any): string { +function getSyntaxFromArgs(args: any): string | undefined { let editor = vscode.window.activeTextEditor; if (!editor) { vscode.window.showInformationMessage('No editor is active.'); diff --git a/extensions/emmet/src/balance.ts b/extensions/emmet/src/balance.ts index 22474be22dd..2d4917994ae 100644 --- a/extensions/emmet/src/balance.ts +++ b/extensions/emmet/src/balance.ts @@ -16,11 +16,10 @@ export function balanceIn() { } function balance(out: boolean) { - let editor = vscode.window.activeTextEditor; - if (!validate(false)) { + if (!validate(false) || !vscode.window.activeTextEditor) { return; } - + const editor = vscode.window.activeTextEditor; let rootNode = parseDocument(editor.document); if (!rootNode) { return; @@ -30,7 +29,7 @@ function balance(out: boolean) { let newSelections: vscode.Selection[] = []; editor.selections.forEach(selection => { let range = getRangeFunction(editor.document, selection, rootNode); - newSelections.push(range ? range : selection); + newSelections.push(range); }); editor.selection = newSelections[0]; @@ -40,7 +39,7 @@ function balance(out: boolean) { function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection { let nodeToBalance = getNode(rootNode, selection.start); if (!nodeToBalance) { - return; + return selection; } if (!nodeToBalance.close) { return new vscode.Selection(nodeToBalance.start, nodeToBalance.end); @@ -55,13 +54,13 @@ function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.S if (outerSelection.contains(selection) && !outerSelection.isEqual(selection)) { return outerSelection; } - return; + return selection; } function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection { let nodeToBalance = getNode(rootNode, selection.start, true); if (!nodeToBalance) { - return; + return selection; } if (selection.start.isEqual(nodeToBalance.start) @@ -71,7 +70,7 @@ function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Se } if (!nodeToBalance.firstChild) { - return; + return selection; } if (selection.start.isEqual(nodeToBalance.firstChild.start) diff --git a/extensions/emmet/src/bufferStream.ts b/extensions/emmet/src/bufferStream.ts index a7a6cd5a0d2..3ab9d9c2eab 100644 --- a/extensions/emmet/src/bufferStream.ts +++ b/extensions/emmet/src/bufferStream.ts @@ -43,20 +43,16 @@ export class DocumentStreamReader { /** * Creates a new stream instance which is limited to given range for given document - * @param {Position} start - * @param {Position} end - * @return {DocumentStreamReader} */ - limit(start, end) { + limit(start: Position, end: Position): DocumentStreamReader { return new DocumentStreamReader(this.document, start, new Range(start, end)); } /** * Returns the next character code in the stream without advancing it. * Will return NaN at the end of the file. - * @returns {Number} */ - peek() { + peek(): number { if (this.eof()) { return NaN; } @@ -67,9 +63,8 @@ export class DocumentStreamReader { /** * Returns the next character in the stream and advances it. * Also returns NaN when no more characters are available. - * @returns {Number} */ - next() { + next(): number { if (this.eof()) { return NaN; } @@ -95,9 +90,8 @@ export class DocumentStreamReader { /** * Backs up the stream n characters. Backing it up further than the * start of the current token will cause things to break, so be careful. - * @param {Number} n */ - backUp(n) { + backUp(n: number) { let row = this.pos.line; let column = this.pos.character; column -= (n || 1); @@ -117,28 +111,22 @@ export class DocumentStreamReader { /** * Get the string between the start of the current token and the * current stream position. - * @returns {String} */ - current() { + current(): string { return this.substring(this.start, this.pos); } /** * Returns contents for given range - * @param {Position} from - * @param {Position} to - * @return {String} */ - substring(from, to) { + substring(from: Position, to: Position): string { return this.document.getText(new Range(from, to)); } /** * Creates error object with current stream state - * @param {String} message - * @return {Error} */ - error(message) { + error(message: string): Error { const err = new Error(`${message} at row ${this.pos.line}, column ${this.pos.character}`); return err; @@ -146,10 +134,8 @@ export class DocumentStreamReader { /** * Returns line length of given row, including line ending - * @param {Number} row - * @return {Number} */ - _lineLength(row) { + _lineLength(row: number): number { if (row === this.document.lineCount - 1) { return this.document.lineAt(row).text.length; } @@ -161,10 +147,8 @@ export class DocumentStreamReader { * and returns a boolean. If the next character in the stream 'matches' * the given argument, it is consumed and returned. * Otherwise, `false` is returned. - * @param {Number|Function} match - * @returns {Boolean} */ - eat(match) { + eat(match: number | Function): boolean { const ch = this.peek(); const ok = typeof match === 'function' ? match(ch) : ch === match; @@ -178,10 +162,8 @@ export class DocumentStreamReader { /** * Repeatedly calls eat with the given argument, until it * fails. Returns true if any characters were eaten. - * @param {Object} match - * @returns {Boolean} */ - eatWhile(match) { + eatWhile(match: number | Function): boolean { const start = this.pos; while (!this.eof() && this.eat(match)) { } return !this.pos.isEqual(start); diff --git a/extensions/emmet/src/defaultCompletionProvider.ts b/extensions/emmet/src/defaultCompletionProvider.ts index 5c78aea06a0..ad6f548bd9f 100644 --- a/extensions/emmet/src/defaultCompletionProvider.ts +++ b/extensions/emmet/src/defaultCompletionProvider.ts @@ -5,13 +5,14 @@ import * as vscode from 'vscode'; import { HtmlNode } from 'EmmetNode'; -import { doComplete, isStyleSheet, getEmmetMode, extractAbbreviation } from 'vscode-emmet-helper'; import { isValidLocationForEmmetAbbreviation } from './abbreviationActions'; -import { getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, getEmmetConfiguration } from './util'; +import { getEmmetHelper, getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, getEmmetConfiguration, getEmmetMode, isStyleSheet } from './util'; + +const allowedMimeTypesInScriptTag = ['text/html', 'text/plain', 'text/x-template', 'text/template']; export class DefaultCompletionItemProvider implements vscode.CompletionItemProvider { - public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable { + public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable | undefined { const mappedLanguages = getMappingForIncludedLanguages(); const emmetConfig = vscode.workspace.getConfiguration('emmet'); @@ -31,20 +32,21 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi return; } + const helper = getEmmetHelper(); let noiseCheckPromise: Thenable = Promise.resolve(); // Fix for https://github.com/Microsoft/vscode/issues/32647 // Check for document symbols in js/ts/jsx/tsx and avoid triggering emmet for abbreviations of the form symbolName.sometext // Presence of > or * or + in the abbreviation denotes valid abbreviation that should trigger emmet if (!isStyleSheet(syntax) && (document.languageId === 'javascript' || document.languageId === 'javascriptreact' || document.languageId === 'typescript' || document.languageId === 'typescriptreact')) { - let extractAbbreviationResults = extractAbbreviation(document, position); + let extractAbbreviationResults = helper.extractAbbreviation(document, position); if (extractAbbreviationResults) { let abbreviation: string = extractAbbreviationResults.abbreviation; if (abbreviation.startsWith('this.')) { noiseCheckPromise = Promise.resolve(true); } else { - noiseCheckPromise = vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', document.uri).then((symbols: vscode.SymbolInformation[]) => { - return symbols.find(x => abbreviation === x.name || (abbreviation.startsWith(x.name + '.') && !/>|\*|\+/.test(abbreviation))); + noiseCheckPromise = vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', document.uri).then((symbols: vscode.SymbolInformation[] | undefined) => { + return symbols && symbols.find(x => abbreviation === x.name || (abbreviation.startsWith(x.name + '.') && !/>|\*|\+/.test(abbreviation))); }); } } @@ -55,7 +57,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi return; } - let result: vscode.CompletionList = doComplete(document, position, syntax, getEmmetConfiguration(syntax)); + let result = helper.doComplete(document, position, syntax, getEmmetConfiguration(syntax)); let newItems: vscode.CompletionItem[] = []; if (result && result.items) { result.items.forEach(item => { @@ -86,7 +88,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi * @param document vscode.Textdocument * @param position vscode.Position position of the abbreviation that needs to be expanded */ - private syntaxHelper(syntax: string, document: vscode.TextDocument, position: vscode.Position): string { + private syntaxHelper(syntax: string | undefined, document: vscode.TextDocument, position: vscode.Position): string | undefined { if (!syntax) { return syntax; } @@ -95,7 +97,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi return; } - let currentNode = getNode(rootNode, position); + let currentNode = getNode(rootNode, position, true); if (!isStyleSheet(syntax)) { const currentHtmlNode = currentNode; @@ -106,6 +108,10 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi return 'css'; } if (currentHtmlNode.name === 'script') { + if (currentHtmlNode.attributes + && currentHtmlNode.attributes.some(x => x.name.toString() === 'type' && allowedMimeTypesInScriptTag.indexOf(x.value.toString()) > -1)) { + return syntax; + } return; } } diff --git a/extensions/emmet/src/editPoint.ts b/extensions/emmet/src/editPoint.ts index 2028d3295b3..afd73a4ddcb 100644 --- a/extensions/emmet/src/editPoint.ts +++ b/extensions/emmet/src/editPoint.ts @@ -7,40 +7,42 @@ import * as vscode from 'vscode'; import { validate } from './util'; export function fetchEditPoint(direction: string): void { - let editor = vscode.window.activeTextEditor; - if (!validate()) { + if (!validate() || !vscode.window.activeTextEditor) { return; } + const editor = vscode.window.activeTextEditor; let newSelections: vscode.Selection[] = []; editor.selections.forEach(selection => { - let updatedSelection = direction === 'next' ? nextEditPoint(selection.anchor, editor) : prevEditPoint(selection.anchor, editor); - newSelections.push(updatedSelection ? updatedSelection : selection); + let updatedSelection = direction === 'next' ? nextEditPoint(selection, editor) : prevEditPoint(selection, editor); + newSelections.push(updatedSelection); }); editor.selections = newSelections; editor.revealRange(editor.selections[editor.selections.length - 1]); } -function nextEditPoint(position: vscode.Position, editor: vscode.TextEditor): vscode.Selection { - for (let lineNum = position.line; lineNum < editor.document.lineCount; lineNum++) { - let updatedSelection = findEditPoint(lineNum, editor, position, 'next'); +function nextEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): vscode.Selection { + for (let lineNum = selection.anchor.line; lineNum < editor.document.lineCount; lineNum++) { + let updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'next'); if (updatedSelection) { return updatedSelection; } } + return selection; } -function prevEditPoint(position: vscode.Position, editor: vscode.TextEditor): vscode.Selection { - for (let lineNum = position.line; lineNum >= 0; lineNum--) { - let updatedSelection = findEditPoint(lineNum, editor, position, 'prev'); +function prevEditPoint(selection: vscode.Selection, editor: vscode.TextEditor): vscode.Selection { + for (let lineNum = selection.anchor.line; lineNum >= 0; lineNum--) { + let updatedSelection = findEditPoint(lineNum, editor, selection.anchor, 'prev'); if (updatedSelection) { return updatedSelection; } } + return selection; } -function findEditPoint(lineNum: number, editor: vscode.TextEditor, position: vscode.Position, direction: string): vscode.Selection { +function findEditPoint(lineNum: number, editor: vscode.TextEditor, position: vscode.Position, direction: string): vscode.Selection | undefined { let line = editor.document.lineAt(lineNum); let lineContent = line.text; diff --git a/extensions/emmet/src/evaluateMathExpression.ts b/extensions/emmet/src/evaluateMathExpression.ts index cf7b84d41cc..8a7de6ca423 100644 --- a/extensions/emmet/src/evaluateMathExpression.ts +++ b/extensions/emmet/src/evaluateMathExpression.ts @@ -10,11 +10,11 @@ import evaluate from '@emmetio/math-expression'; import { DocumentStreamReader } from './bufferStream'; export function evaluateMathExpression() { - let editor = vscode.window.activeTextEditor; - if (!editor) { + if (!vscode.window.activeTextEditor) { vscode.window.showInformationMessage('No editor is active'); return; } + const editor = vscode.window.activeTextEditor; const stream = new DocumentStreamReader(editor.document); editor.edit(editBuilder => { editor.selections.forEach(selection => { diff --git a/extensions/emmet/src/extension.ts b/extensions/emmet/src/extension.ts index 060654c5fa6..4acbf5dfa7b 100644 --- a/extensions/emmet/src/extension.ts +++ b/extensions/emmet/src/extension.ts @@ -17,13 +17,10 @@ import { fetchEditPoint } from './editPoint'; import { fetchSelectItem } from './selectItem'; import { evaluateMathExpression } from './evaluateMathExpression'; import { incrementDecrement } from './incrementDecrement'; -import { LANGUAGE_MODES, getMappingForIncludedLanguages } from './util'; -import { updateExtensionsPath } from 'vscode-emmet-helper'; +import { LANGUAGE_MODES, getMappingForIncludedLanguages, resolveUpdateExtensionsPath } from './util'; import { updateImageSize } from './updateImageSize'; import { reflectCssValue } from './reflectCssValue'; -import * as path from 'path'; - export function activate(context: vscode.ExtensionContext) { registerCompletionProviders(context); @@ -128,18 +125,6 @@ export function activate(context: vscode.ExtensionContext) { return reflectCssValue(); })); - let currentExtensionsPath = undefined; - let resolveUpdateExtensionsPath = () => { - let extensionsPath = vscode.workspace.getConfiguration('emmet')['extensionsPath']; - if (extensionsPath && !path.isAbsolute(extensionsPath)) { - extensionsPath = path.join(vscode.workspace.rootPath, extensionsPath); - } - if (currentExtensionsPath !== extensionsPath) { - currentExtensionsPath = extensionsPath; - updateExtensionsPath(currentExtensionsPath).then(null, err => vscode.window.showErrorMessage(err)); - } - }; - resolveUpdateExtensionsPath(); context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => { diff --git a/extensions/emmet/src/imageSizeHelper.ts b/extensions/emmet/src/imageSizeHelper.ts index 2c8f1de5945..1a88f35c110 100644 --- a/extensions/emmet/src/imageSizeHelper.ts +++ b/extensions/emmet/src/imageSizeHelper.ts @@ -19,20 +19,16 @@ const reUrl = /^https?:/; /** * Get size of given image file. Supports files from local filesystem, * as well as URLs - * @param {String} file Path to local file or URL - * @return {Promise} */ -export function getImageSize(file) { +export function getImageSize(file: string) { file = file.replace(/^file:\/\//, ''); return reUrl.test(file) ? getImageSizeFromURL(file) : getImageSizeFromFile(file); } /** * Get image size from file on local file system - * @param {String} file - * @return {Promise} */ -function getImageSizeFromFile(file) { +function getImageSizeFromFile(file: string) { return new Promise((resolve, reject) => { const isDataUrl = file.match(/^data:.+?;base64,/); @@ -46,7 +42,7 @@ function getImageSizeFromFile(file) { } } - sizeOf(file, (err, size) => { + sizeOf(file, (err: any, size: any) => { if (err) { reject(err); } else { @@ -58,15 +54,13 @@ function getImageSizeFromFile(file) { /** * Get image size from given remove URL - * @param {String} url - * @return {Promise} */ -function getImageSizeFromURL(url) { +function getImageSizeFromURL(urlStr: string) { return new Promise((resolve, reject) => { - url = parseUrl(url); + const url = parseUrl(urlStr); const getTransport = url.protocol === 'https:' ? https.get : http.get; - getTransport(url, resp => { + getTransport(url as any, resp => { const chunks = []; let bufSize = 0; @@ -102,11 +96,8 @@ function getImageSizeFromURL(url) { /** * Returns size object for given file name. If file name contains `@Nx` token, * the final dimentions will be downscaled by N - * @param {String} fileName - * @param {Object} size - * @return {Object} */ -function sizeForFileName(fileName, size) { +function sizeForFileName(fileName: string, size: any) { const m = fileName.match(/@(\d+)x\./); const scale = m ? +m[1] : 1; diff --git a/extensions/emmet/src/selectItem.ts b/extensions/emmet/src/selectItem.ts index 25b918231bd..bd82d2d1bed 100644 --- a/extensions/emmet/src/selectItem.ts +++ b/extensions/emmet/src/selectItem.ts @@ -4,11 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { validate, parseDocument } from './util'; +import { validate, parseDocument, isStyleSheet } from './util'; import { nextItemHTML, prevItemHTML } from './selectItemHTML'; import { nextItemStylesheet, prevItemStylesheet } from './selectItemStylesheet'; -import { isStyleSheet } from 'vscode-emmet-helper'; - export function fetchSelectItem(direction: string): void { let editor = vscode.window.activeTextEditor; diff --git a/extensions/emmet/src/selectItemHTML.ts b/extensions/emmet/src/selectItemHTML.ts index 1b234e2f349..23647722bcc 100644 --- a/extensions/emmet/src/selectItemHTML.ts +++ b/extensions/emmet/src/selectItemHTML.ts @@ -7,9 +7,9 @@ import * as vscode from 'vscode'; import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util'; import { HtmlNode } from 'EmmetNode'; -export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection { +export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined { let currentNode = getNode(rootNode, selectionEnd); - let nextNode: HtmlNode; + let nextNode: HtmlNode | undefined = undefined; if (!currentNode) { return; @@ -50,12 +50,12 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco } } - return getSelectionFromNode(nextNode, editor.document); + return nextNode && getSelectionFromNode(nextNode, editor.document); } -export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection { +export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined { let currentNode = getNode(rootNode, selectionStart); - let prevNode: HtmlNode; + let prevNode: HtmlNode | undefined = undefined; if (!currentNode) { return; @@ -68,7 +68,7 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco } else { // Select the child that appears just before the cursor and is not a comment prevNode = currentNode.firstChild; - let oldOption: HtmlNode; + let oldOption: HtmlNode | undefined = undefined; while (prevNode.nextSibling && selectionStart.isAfterOrEqual(prevNode.nextSibling.end)) { if (prevNode && prevNode.type !== 'comment') { oldOption = prevNode; @@ -94,20 +94,25 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco } + if (!prevNode) { + return undefined; + } + let attrSelection = getPrevAttribute(selectionStart, selectionEnd, editor.document, prevNode); return attrSelection ? attrSelection : getSelectionFromNode(prevNode, editor.document); } -function getSelectionFromNode(node: HtmlNode, document: vscode.TextDocument): vscode.Selection { +function getSelectionFromNode(node: HtmlNode, document: vscode.TextDocument): vscode.Selection | undefined { if (node && node.open) { let selectionStart = (node.open.start).translate(0, 1); let selectionEnd = selectionStart.translate(0, node.name.length); return new vscode.Selection(selectionStart, selectionEnd); } + return undefined; } -function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection { +function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection | undefined { if (!node.attributes || node.attributes.length === 0 || node.type === 'comment') { return; @@ -158,7 +163,7 @@ function getNextAttribute(selectionStart: vscode.Position, selectionEnd: vscode. } } -function getPrevAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection { +function getPrevAttribute(selectionStart: vscode.Position, selectionEnd: vscode.Position, document: vscode.TextDocument, node: HtmlNode): vscode.Selection | undefined { if (!node.attributes || node.attributes.length === 0 || node.type === 'comment') { return; diff --git a/extensions/emmet/src/selectItemStylesheet.ts b/extensions/emmet/src/selectItemStylesheet.ts index 09f0d6103a9..367e0320837 100644 --- a/extensions/emmet/src/selectItemStylesheet.ts +++ b/extensions/emmet/src/selectItemStylesheet.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util'; import { Node, CssNode, Rule, Property } from 'EmmetNode'; -export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection { +export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: Node): vscode.Selection | undefined { let currentNode = getNode(rootNode, endOffset, true); if (!currentNode) { currentNode = rootNode; @@ -50,7 +50,7 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco } -export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: CssNode): vscode.Selection { +export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: CssNode): vscode.Selection | undefined { let currentNode = getNode(rootNode, startOffset); if (!currentNode) { currentNode = rootNode; @@ -88,7 +88,7 @@ export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vsco } -function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode.Selection { +function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode.Selection | undefined { if (!node) { return; } @@ -98,7 +98,7 @@ function getSelectionFromNode(node: Node, document: vscode.TextDocument): vscode } -function getSelectionFromProperty(node: Node, document: vscode.TextDocument, selectionStart: vscode.Position, selectionEnd: vscode.Position, selectFullValue: boolean, direction: string): vscode.Selection { +function getSelectionFromProperty(node: Node, document: vscode.TextDocument, selectionStart: vscode.Position, selectionEnd: vscode.Position, selectFullValue: boolean, direction: string): vscode.Selection | undefined { if (!node || node.type !== 'property') { return; } diff --git a/extensions/emmet/src/splitJoinTag.ts b/extensions/emmet/src/splitJoinTag.ts index 382bd1841b0..67a403bce29 100644 --- a/extensions/emmet/src/splitJoinTag.ts +++ b/extensions/emmet/src/splitJoinTag.ts @@ -8,11 +8,11 @@ import { HtmlNode } from 'EmmetNode'; import { getNode, parseDocument, validate } from './util'; export function splitJoinTag() { - let editor = vscode.window.activeTextEditor; - if (!validate(false)) { + if (!validate(false) || !vscode.window.activeTextEditor) { return; } + const editor = vscode.window.activeTextEditor; let rootNode = parseDocument(editor.document); if (!rootNode) { return; @@ -20,23 +20,19 @@ export function splitJoinTag() { return editor.edit(editBuilder => { editor.selections.reverse().forEach(selection => { - let textEdit = getRangesToReplace(editor.document, selection, rootNode); - if (textEdit) { + let nodeToUpdate = getNode(rootNode, selection.start); + if (nodeToUpdate) { + let textEdit = getRangesToReplace(editor.document, nodeToUpdate); editBuilder.replace(textEdit.range, textEdit.newText); } }); }); } -function getRangesToReplace(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.TextEdit { - let nodeToUpdate = getNode(rootNode, selection.start); +function getRangesToReplace(document: vscode.TextDocument, nodeToUpdate: HtmlNode): vscode.TextEdit { let rangeToReplace: vscode.Range; let textToReplaceWith: string; - if (!nodeToUpdate) { - return; - } - if (!nodeToUpdate.close) { // Split Tag let nodeText = document.getText(new vscode.Range(nodeToUpdate.start, nodeToUpdate.end)); diff --git a/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts index 4dd97f7a7e1..0f599e37b86 100644 --- a/extensions/emmet/src/test/abbreviationAction.test.ts +++ b/extensions/emmet/src/test/abbreviationAction.test.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; import { Selection, workspace } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; @@ -11,6 +12,7 @@ import { expandEmmetAbbreviation, wrapWithAbbreviation, wrapIndividualLinesWithA const cssContents = ` .boo { margin: 20px 10px; + m10 background-image: url('tryme.png'); m10 } @@ -189,9 +191,9 @@ suite('Tests for Expand Abbreviations (CSS)', () => { test('Expand abbreviation (CSS)', () => { return withRandomFileEditor(cssContents, 'css', (editor, doc) => { - editor.selection = new Selection(4, 1, 4, 4); + editor.selections = [new Selection(3, 1, 3, 4), new Selection(5, 1, 5, 4)]; return expandEmmetAbbreviation(null).then(() => { - assert.equal(editor.document.getText(), cssContents.replace('m10', 'margin: 10px;')); + assert.equal(editor.document.getText(), cssContents.replace(/m10/g, 'margin: 10px;')); return Promise.resolve(); }); }); @@ -211,6 +213,29 @@ suite('Tests for Expand Abbreviations (CSS)', () => { }); }); }); + + test('Invalid locations for abbreviations in css', () => { + const scssContentsNoExpand = ` +m10 + .boo { + margin: 10px; + .hoo { + background: + } + } + ` + + return withRandomFileEditor(scssContentsNoExpand, 'scss', (editor, doc) => { + editor.selections = [ + new Selection(1, 3, 1, 3), // outside rule + new Selection(5, 15, 5, 15) // in the value part of property value + ]; + return expandEmmetAbbreviation(null).then(() => { + assert.equal(editor.document.getText(), scssContentsNoExpand); + return Promise.resolve(); + }); + }); + }); }); suite('Tests for Wrap with Abbreviations', () => { @@ -320,7 +345,7 @@ suite('Tests for Wrap with Abbreviations', () => { suite('Tests for jsx, xml and xsl', () => { teardown(closeAllEditors); - + test('Expand abbreviation with className instead of class in jsx', () => { return withRandomFileEditor('ul.nav', 'javascriptreact', (editor, doc) => { editor.selection = new Selection(0, 6, 0, 6); diff --git a/extensions/emmet/src/test/editPointSelectItemBalance.test.ts b/extensions/emmet/src/test/editPointSelectItemBalance.test.ts index 427ee166f95..3393fdddc24 100644 --- a/extensions/emmet/src/test/editPointSelectItemBalance.test.ts +++ b/extensions/emmet/src/test/editPointSelectItemBalance.test.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; import { Selection } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; diff --git a/extensions/emmet/src/test/incrementDecrement.test.ts b/extensions/emmet/src/test/incrementDecrement.test.ts index a846bc6b782..e1c039dffca 100644 --- a/extensions/emmet/src/test/incrementDecrement.test.ts +++ b/extensions/emmet/src/test/incrementDecrement.test.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; import { Selection } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; diff --git a/extensions/emmet/src/test/reflectCssValue.test.ts b/extensions/emmet/src/test/reflectCssValue.test.ts index 228c62ed960..3967503b676 100644 --- a/extensions/emmet/src/test/reflectCssValue.test.ts +++ b/extensions/emmet/src/test/reflectCssValue.test.ts @@ -3,8 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; -import { Selection, commands } from 'vscode'; +import { Selection } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { reflectCssValue } from '../reflectCssValue'; diff --git a/extensions/emmet/src/test/tagActions.test.ts b/extensions/emmet/src/test/tagActions.test.ts index 7d13c98fd84..c95bf8064bc 100644 --- a/extensions/emmet/src/test/tagActions.test.ts +++ b/extensions/emmet/src/test/tagActions.test.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; import { Selection } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; diff --git a/extensions/emmet/src/test/toggleComment.test.ts b/extensions/emmet/src/test/toggleComment.test.ts index 225fbeb8074..7423a028d4b 100644 --- a/extensions/emmet/src/test/toggleComment.test.ts +++ b/extensions/emmet/src/test/toggleComment.test.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; import { Selection } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; diff --git a/extensions/emmet/src/test/updateImageSize.test.ts b/extensions/emmet/src/test/updateImageSize.test.ts index 2fadbe94d58..cc23e3f6651 100644 --- a/extensions/emmet/src/test/updateImageSize.test.ts +++ b/extensions/emmet/src/test/updateImageSize.test.ts @@ -3,15 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; import { Selection } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { updateImageSize } from '../updateImageSize'; -import * as path from 'path'; suite('Tests for Emmet actions on html tags', () => { teardown(closeAllEditors); - const filePath = path.join(__dirname, '../../../../resources/linux/code.png'); test('update image css with multiple cursors in css file', () => { const cssContents = ` diff --git a/extensions/emmet/src/toggleComment.ts b/extensions/emmet/src/toggleComment.ts index 4de5b7e007b..e15dbd0c984 100644 --- a/extensions/emmet/src/toggleComment.ts +++ b/extensions/emmet/src/toggleComment.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { getNodesInBetween, getNode, parseDocument, sameNodes } from './util'; +import { getNodesInBetween, getNode, parseDocument, sameNodes, isStyleSheet, validate } from './util'; import { Node, Stylesheet, Rule, HtmlNode } from 'EmmetNode'; -import { isStyleSheet } from 'vscode-emmet-helper'; import parseStylesheet from '@emmetio/css-parser'; import { DocumentStreamReader } from './bufferStream'; @@ -15,14 +14,12 @@ const endCommentStylesheet = '*/'; const startCommentHTML = ''; -export function toggleComment(): Thenable { - let editor = vscode.window.activeTextEditor; - if (!editor) { - vscode.window.showInformationMessage('No editor is active'); +export function toggleComment(): Thenable | undefined { + if (!validate() || !vscode.window.activeTextEditor) { return; } - - let toggleCommentInternal; + const editor = vscode.window.activeTextEditor; + let toggleCommentInternal: (document: vscode.TextDocument, selection: vscode.Selection, rootNode: Node) => vscode.TextEdit[]; if (isStyleSheet(editor.document.languageId)) { toggleCommentInternal = toggleCommentStylesheet; diff --git a/extensions/emmet/src/typings/EmmetNode.d.ts b/extensions/emmet/src/typings/EmmetNode.d.ts index bf27b63ca91..476af0ed931 100644 --- a/extensions/emmet/src/typings/EmmetNode.d.ts +++ b/extensions/emmet/src/typings/EmmetNode.d.ts @@ -35,7 +35,7 @@ declare module 'EmmetNode' { } export interface Attribute extends Token { - name: string + name: Token value: Token } diff --git a/extensions/emmet/src/typings/refs.d.ts b/extensions/emmet/src/typings/refs.d.ts index 0188b6f9ffc..bc057c55878 100644 --- a/extensions/emmet/src/typings/refs.d.ts +++ b/extensions/emmet/src/typings/refs.d.ts @@ -5,4 +5,3 @@ /// /// -/// diff --git a/extensions/emmet/src/updateImageSize.ts b/extensions/emmet/src/updateImageSize.ts index 352cdd2e046..06fbd45a15b 100644 --- a/extensions/emmet/src/updateImageSize.ts +++ b/extensions/emmet/src/updateImageSize.ts @@ -10,8 +10,7 @@ import { TextEditor, Range, Position, window, TextEdit } from 'vscode'; import * as path from 'path'; import { getImageSize } from './imageSizeHelper'; -import { isStyleSheet } from 'vscode-emmet-helper'; -import { parseDocument, getNode, iterateCSSToken, getCssPropertyFromRule } from './util'; +import { parseDocument, getNode, iterateCSSToken, getCssPropertyFromRule, isStyleSheet, validate } from './util'; import { HtmlNode, CssToken, HtmlToken, Attribute, Property } from 'EmmetNode'; import { locateFile } from './locateFile'; import parseStylesheet from '@emmetio/css-parser'; @@ -21,11 +20,10 @@ import { DocumentStreamReader } from './bufferStream'; * Updates size of context image in given editor */ export function updateImageSize() { - let editor = window.activeTextEditor; - if (!editor) { - window.showInformationMessage('No editor is active.'); + if (!validate() || !window.activeTextEditor) { return; } + const editor = window.activeTextEditor; let allUpdatesPromise = editor.selections.reverse().map(selection => { let position = selection.isReversed ? selection.active : selection.anchor; @@ -50,7 +48,7 @@ export function updateImageSize() { /** * Updates image size of context tag of HTML model */ -function updateImageSizeHTML(editor: TextEditor, position: Position): Promise { +function updateImageSizeHTML(editor: TextEditor, position: Position): Promise { const src = getImageSrcHTML(getImageHTMLNode(editor, position)); if (!src) { @@ -71,7 +69,7 @@ function updateImageSizeHTML(editor: TextEditor, position: Position): Promise { - let getPropertyInsiderStyleTag = (editor) => { + const getPropertyInsiderStyleTag = (editor: TextEditor): Property | undefined => { const rootNode = parseDocument(editor.document); const currentNode = getNode(rootNode, position); if (currentNode && currentNode.name === 'style' @@ -80,7 +78,7 @@ function updateImageSizeStyleTag(editor: TextEditor, position: Position): Promis let buffer = new DocumentStreamReader(editor.document, currentNode.open.end, new Range(currentNode.open.end, currentNode.close.start)); let rootNode = parseStylesheet(buffer); const node = getNode(rootNode, position); - return (node && node.type === 'property') ? node : null; + return (node && node.type === 'property') ? node : undefined; } }; @@ -94,7 +92,7 @@ function updateImageSizeCSSFile(editor: TextEditor, position: Position): Promise /** * Updates image size of context rule of stylesheet model */ -function updateImageSizeCSS(editor: TextEditor, position: Position, fetchNode: (editor, position) => Property): Promise { +function updateImageSizeCSS(editor: TextEditor, position: Position, fetchNode: (editor: TextEditor, position: Position) => Property | undefined): Promise { const src = getImageSrcCSS(fetchNode(editor, position), position); @@ -142,10 +140,8 @@ function getImageCSSNode(editor: TextEditor, position: Position): Property { /** * Returns image source from given node - * @param {HtmlNode} node - * @return {string} */ -function getImageSrcHTML(node: HtmlNode): string { +function getImageSrcHTML(node: HtmlNode): string | undefined { const srcAttr = getAttribute(node, 'src'); if (!srcAttr) { return; @@ -156,11 +152,8 @@ function getImageSrcHTML(node: HtmlNode): string { /** * Returns image source from given `url()` token - * @param {Property} node - * @param {Position} - * @return {string} */ -function getImageSrcCSS(node: Property, position: Position): string { +function getImageSrcCSS(node: Property | undefined, position: Position): string | undefined { if (!node) { return; } @@ -214,10 +207,6 @@ function updateHTMLTag(editor: TextEditor, node: HtmlNode, width: number, height /** * Updates size of given CSS rule - * @param {TextEditor} editor - * @param {Property} srcProp - * @param {number} width - * @param {number} height */ function updateCSSNode(editor: TextEditor, srcProp: Property, width: number, height: number): TextEdit[] { const rule = srcProp.parent; @@ -253,36 +242,28 @@ function updateCSSNode(editor: TextEditor, srcProp: Property, width: number, hei /** * Returns attribute object with `attrName` name from given HTML node - * @param {Node} node - * @param {String} attrName - * @return {Object} */ -function getAttribute(node, attrName): Attribute { +function getAttribute(node: HtmlNode, attrName: string): Attribute { attrName = attrName.toLowerCase(); - return node && node.open.attributes.find(attr => attr.name.value.toLowerCase() === attrName); + return node && (node.open as any).attributes.find(attr => attr.name.value.toLowerCase() === attrName); } /** * Returns quote character, used for value of given attribute. May return empty * string if attribute wasn’t quoted - * @param {TextEditor} editor - * @param {Object} attr - * @return {String} + */ -function getAttributeQuote(editor, attr) { +function getAttributeQuote(editor: TextEditor, attr: any): string { const range = new Range(attr.value ? attr.value.end : attr.end, attr.end); return range.isEmpty ? '' : editor.document.getText(range); } /** * Finds 'url' token for given `pos` point in given CSS property `node` - * @param {Node} node - * @param {Position} pos - * @return {Token} */ -function findUrlToken(node, pos: Position) { - for (let i = 0, il = node.parsedValue.length, url; i < il; i++) { - iterateCSSToken(node.parsedValue[i], (token: CssToken) => { +function findUrlToken(node: Property, pos: Position): CssToken | undefined { + for (let i = 0, il = (node as any).parsedValue.length, url; i < il; i++) { + iterateCSSToken((node as any).parsedValue[i], (token: CssToken) => { if (token.type === 'url' && token.start.isBeforeOrEqual(pos) && token.end.isAfterOrEqual(pos)) { url = token; return false; @@ -297,11 +278,8 @@ function findUrlToken(node, pos: Position) { /** * Returns a string that is used to delimit properties in current node’s rule - * @param {TextEditor} editor - * @param {Property} node - * @return {String} */ -function getPropertyDelimitor(editor: TextEditor, node: Property) { +function getPropertyDelimitor(editor: TextEditor, node: Property): string { let anchor; if (anchor = (node.previousSibling || node.parent.contentStartToken)) { return editor.document.getText(new Range(anchor.end, node.start)); diff --git a/extensions/emmet/src/updateTag.ts b/extensions/emmet/src/updateTag.ts index 66a23e074b6..b62f167d70a 100644 --- a/extensions/emmet/src/updateTag.ts +++ b/extensions/emmet/src/updateTag.ts @@ -7,17 +7,17 @@ import * as vscode from 'vscode'; import { HtmlNode } from 'EmmetNode'; import { getNode, parseDocument, validate } from './util'; -export function updateTag(tagName: string): Thenable { - let editor = vscode.window.activeTextEditor; - if (!validate(false)) { +export function updateTag(tagName: string): Thenable | undefined { + if (!validate(false) || !vscode.window.activeTextEditor) { return; } + let editor = vscode.window.activeTextEditor; let rootNode = parseDocument(editor.document); if (!rootNode) { return; } - let rangesToUpdate = []; + let rangesToUpdate: vscode.Range[] = []; editor.selections.reverse().forEach(selection => { rangesToUpdate = rangesToUpdate.concat(getRangesToUpdate(editor, selection, rootNode)); }); diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index 66f8ba03fc8..450aa136143 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -6,26 +6,53 @@ import * as vscode from 'vscode'; import parse from '@emmetio/html-matcher'; import parseStylesheet from '@emmetio/css-parser'; -import { Node, HtmlNode, CssToken, Property } from 'EmmetNode'; +import { Node, HtmlNode, CssToken, Property, Rule } from 'EmmetNode'; import { DocumentStreamReader } from './bufferStream'; -import { isStyleSheet } from 'vscode-emmet-helper'; +import * as path from 'path'; -export const LANGUAGE_MODES: Object = { +let _emmetHelper: any; +let _currentExtensionsPath: string | undefined = undefined; + +export function getEmmetHelper() { + if (!_emmetHelper) { + _emmetHelper = require('vscode-emmet-helper'); + } + resolveUpdateExtensionsPath(); + return _emmetHelper; +} + +export function resolveUpdateExtensionsPath() { + if (!_emmetHelper) { + return; + } + let extensionsPath = vscode.workspace.getConfiguration('emmet')['extensionsPath']; + if (extensionsPath && !path.isAbsolute(extensionsPath)) { + extensionsPath = path.join(vscode.workspace.rootPath || '', extensionsPath); + } + if (_currentExtensionsPath !== extensionsPath) { + _currentExtensionsPath = extensionsPath; + _emmetHelper.updateExtensionsPath(_currentExtensionsPath).then(null, (err: string) => vscode.window.showErrorMessage(err)); + } +} + +export const LANGUAGE_MODES: any = { 'html': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'jade': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'slim': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'haml': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'xml': ['.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'xsl': ['!', '.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'css': [':', ';'], - 'scss': [':', ';'], - 'sass': [':'], - 'less': [':', ';'], - 'stylus': [':'], + 'css': [':', ';', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'scss': [':', ';', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'sass': [':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'less': [':', ';', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'stylus': [':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'javascriptreact': ['.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'typescriptreact': ['.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] }; +const emmetModes = ['html', 'pug', 'slim', 'haml', 'xml', 'xsl', 'jsx', 'css', 'scss', 'sass', 'less', 'stylus']; + // Explicitly map languages that have built-in grammar in VS Code to their parent language // to get emmet completion support // For other languages, users will have to use `emmet.includeLanguages` or @@ -35,6 +62,11 @@ export const MAPPED_MODES: Object = { 'php': 'html' }; +export function isStyleSheet(syntax: string): boolean { + let stylesheetSyntaxes = ['css', 'scss', 'sass', 'less', 'stylus']; + return (stylesheetSyntaxes.indexOf(syntax) > -1); +} + export function validate(allowStylesheet: boolean = true): boolean { let editor = vscode.window.activeTextEditor; if (!editor) { @@ -48,7 +80,7 @@ export function validate(allowStylesheet: boolean = true): boolean { } export function getMappingForIncludedLanguages(): any { - let finalMappedModes = {}; + const finalMappedModes = Object.create(null); let includeLanguagesConfig = vscode.workspace.getConfiguration('emmet')['includeLanguages']; let includeLanguages = Object.assign({}, MAPPED_MODES, includeLanguagesConfig ? includeLanguagesConfig : {}); Object.keys(includeLanguages).forEach(syntax => { @@ -59,36 +91,58 @@ export function getMappingForIncludedLanguages(): any { return finalMappedModes; } +/** +* Get the corresponding emmet mode for given vscode language mode +* Eg: jsx for typescriptreact/javascriptreact or pug for jade +* If the language is not supported by emmet or has been exlcuded via `exlcudeLanguages` setting, +* then nothing is returned +* +* @param language +* @param exlcudedLanguages Array of language ids that user has chosen to exlcude for emmet +*/ +export function getEmmetMode(language: string, excludedLanguages: string[]): string | undefined { + if (!language || excludedLanguages.indexOf(language) > -1) { + return; + } + if (/\b(typescriptreact|javascriptreact|jsx-tags)\b/.test(language)) { // treat tsx like jsx + return 'jsx'; + } + if (language === 'sass-indented') { // map sass-indented to sass + return 'sass'; + } + if (language === 'jade') { + return 'pug'; + } + if (emmetModes.indexOf(language) > -1) { + return language; + } +} + /** * Parses the given document using emmet parsing modules - * @param document */ -export function parseDocument(document: vscode.TextDocument, showError: boolean = true): Node { +export function parseDocument(document: vscode.TextDocument, showError: boolean = true): Node | undefined { let parseContent = isStyleSheet(document.languageId) ? parseStylesheet : parse; - let rootNode: Node; try { - rootNode = parseContent(new DocumentStreamReader(document)); + return parseContent(new DocumentStreamReader(document)); } catch (e) { if (showError) { vscode.window.showErrorMessage('Emmet: Failed to parse the file'); } } - return rootNode; + return undefined; } /** * Returns node corresponding to given position in the given root node - * @param root - * @param position - * @param includeNodeBoundary */ -export function getNode(root: Node, position: vscode.Position, includeNodeBoundary: boolean = false) { +export function getNode(root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean = false) { if (!root) { return null; } let currentNode = root.firstChild; - let foundNode: Node = null; + let foundNode: Node | null = null; while (currentNode) { const nodeStart: vscode.Position = currentNode.start; @@ -111,14 +165,14 @@ export function getNode(root: Node, position: vscode.Position, includeNodeBounda * Returns inner range of an html node. * @param currentNode */ -export function getInnerRange(currentNode: HtmlNode): vscode.Range { +export function getInnerRange(currentNode: HtmlNode): vscode.Range | undefined { if (!currentNode.close) { - return; + return undefined; } return new vscode.Range(currentNode.open.end, currentNode.close.start); } -export function getDeepestNode(node: Node): Node { +export function getDeepestNode(node: Node | undefined): Node | undefined { if (!node || !node.children || node.children.length === 0 || !node.children.find(x => x.type !== 'comment')) { return node; } @@ -127,6 +181,7 @@ export function getDeepestNode(node: Node): Node { return getDeepestNode(node.children[i]); } } + return undefined; } export function findNextWord(propertyValue: string, pos: number): [number, number] { @@ -283,10 +338,8 @@ export function getEmmetConfiguration(syntax: string) { /** * Itereates by each child, as well as nested child’ children, in their order * and invokes `fn` for each. If `fn` function returns `false`, iteration stops - * @param {Token} token - * @param {Function} fn */ -export function iterateCSSToken(token: CssToken, fn) { +export function iterateCSSToken(token: CssToken, fn: (x: any) => any) { for (let i = 0, il = token.size; i < il; i++) { if (fn(token.item(i)) === false || iterateCSSToken(token.item(i), fn) === false) { return false; @@ -296,21 +349,16 @@ export function iterateCSSToken(token: CssToken, fn) { /** * Returns `name` CSS property from given `rule` - * @param {Node} rule - * @param {String} name - * @return {Property} */ -export function getCssPropertyFromRule(rule, name): Property { - return rule.children.find(node => node.type === 'property' && node.name === name); +export function getCssPropertyFromRule(rule: Rule, name: string): Property | undefined { + return rule.children.find(node => node.type === 'property' && node.name === name) as Property; } /** * Returns css property under caret in given editor or `null` if such node cannot * be found - * @param {TextEditor} editor - * @return {Property} */ -export function getCssPropertyFromDocument(editor: vscode.TextEditor, position: vscode.Position): Property { +export function getCssPropertyFromDocument(editor: vscode.TextEditor, position: vscode.Position): Property | undefined { const rootNode = parseDocument(editor.document); const node = getNode(rootNode, position); diff --git a/extensions/emmet/tsconfig.json b/extensions/emmet/tsconfig.json index 06d04868a70..3ac3cd9c298 100644 --- a/extensions/emmet/tsconfig.json +++ b/extensions/emmet/tsconfig.json @@ -5,8 +5,8 @@ "es2016" ], "module": "commonjs", - "outDir": "./out" - + "outDir": "./out", + "noUnusedLocals": true }, "exclude": [ "node_modules", diff --git a/extensions/extension-editing/npm-shrinkwrap.json b/extensions/extension-editing/npm-shrinkwrap.json index c546fa26f89..2cfa863b624 100644 --- a/extensions/extension-editing/npm-shrinkwrap.json +++ b/extensions/extension-editing/npm-shrinkwrap.json @@ -5,7 +5,8 @@ "@types/node": { "version": "6.0.78", "from": "@types/node@>=6.0.46 <7.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.78.tgz" + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.78.tgz", + "dev": true }, "argparse": { "version": "1.0.9", diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index 36f1ae658ab..8a4c4520f18 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -47,6 +47,6 @@ }, "devDependencies": { "@types/markdown-it": "0.0.2", - "@types/node": "^7.0.4" + "@types/node": "7.0.43" } } diff --git a/extensions/extension-editing/src/extension.ts b/extensions/extension-editing/src/extension.ts index e0ab03f256e..474ea4c8a35 100644 --- a/extensions/extension-editing/src/extension.ts +++ b/extensions/extension-editing/src/extension.ts @@ -46,7 +46,7 @@ const _linkProvider = new class implements vscode.DocumentLinkProvider { const offset = lookUp(match[1]); if (offset === -1) { - console.warn(match[1]); + console.warn(`Could not find symbol for link ${match[1]}`); continue; } diff --git a/extensions/extension-editing/src/extensionLinter.ts b/extensions/extension-editing/src/extensionLinter.ts index d06332e8221..5d6ec0c4591 100644 --- a/extensions/extension-editing/src/extensionLinter.ts +++ b/extensions/extension-editing/src/extensionLinter.ts @@ -8,8 +8,7 @@ import * as path from 'path'; import { parseTree, findNodeAtLocation, Node as JsonNode } from 'jsonc-parser'; import * as nls from 'vscode-nls'; -import * as MarkdownIt from 'markdown-it'; -import * as parse5 from 'parse5'; +import * as MarkdownItType from 'markdown-it'; import { languages, workspace, Disposable, ExtensionContext, TextDocument, Uri, Diagnostic, Range, DiagnosticSeverity, Position } from 'vscode'; @@ -33,7 +32,7 @@ enum Context { } interface TokenAndPosition { - token: MarkdownIt.Token; + token: MarkdownItType.Token; begin: number; end: number; } @@ -53,8 +52,9 @@ export class ExtensionLinter { private packageJsonQ = new Set(); private readmeQ = new Set(); private timer: NodeJS.Timer; - private markdownIt = new MarkdownIt(); + private markdownIt: MarkdownItType.MarkdownIt; + // @ts-ignore unused property constructor(private context: ExtensionContext) { this.disposables.push( workspace.onDidOpenTextDocument(document => this.queue(document)), @@ -148,8 +148,11 @@ export class ExtensionLinter { } const text = document.getText(); + if (!this.markdownIt) { + this.markdownIt = new (await import('markdown-it')); + } const tokens = this.markdownIt.parse(text, {}); - const tokensAndPositions = (function toTokensAndPositions(this: ExtensionLinter, tokens: MarkdownIt.Token[], begin = 0, end = text.length): TokenAndPosition[] { + const tokensAndPositions = (function toTokensAndPositions(this: ExtensionLinter, tokens: MarkdownItType.Token[], begin = 0, end = text.length): TokenAndPosition[] { const tokensAndPositions = tokens.map(token => { if (token.map) { const tokenBegin = document.offsetAt(new Position(token.map[0], 0)); @@ -192,8 +195,9 @@ export class ExtensionLinter { }); let svgStart: Diagnostic; - tokensAndPositions.filter(tnp => tnp.token.type === 'text' && tnp.token.content) - .map(tnp => { + for (const tnp of tokensAndPositions) { + if (tnp.token.type === 'text' && tnp.token.content) { + const parse5 = await import('parse5'); const parser = new parse5.SAXParser({ locationInfo: true }); parser.on('startTag', (name, attrs, selfClosing, location) => { if (name === 'img') { @@ -220,13 +224,14 @@ export class ExtensionLinter { }); parser.write(tnp.token.content); parser.end(); - }); + } + } this.diagnosticsCollection.set(document.uri, diagnostics); - }; + } } - private locateToken(text: string, begin: number, end: number, token: MarkdownIt.Token, content: string) { + private locateToken(text: string, begin: number, end: number, token: MarkdownItType.Token, content: string) { if (content) { const tokenBegin = text.indexOf(content, begin); if (tokenBegin !== -1) { diff --git a/extensions/extension-editing/tsconfig.json b/extensions/extension-editing/tsconfig.json index a2b5bcdfddf..6fbf4543c23 100644 --- a/extensions/extension-editing/tsconfig.json +++ b/extensions/extension-editing/tsconfig.json @@ -5,6 +5,7 @@ "es2015" ], "module": "commonjs", + "noUnusedLocals": true, "outDir": "./out" }, "include": [ diff --git a/extensions/fsharp/language-configuration.json b/extensions/fsharp/language-configuration.json index 89dc2adb5a8..e4affc8deaa 100644 --- a/extensions/fsharp/language-configuration.json +++ b/extensions/fsharp/language-configuration.json @@ -20,5 +20,12 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "offSide": true, + "markers": { + "start": "^\\s*//\\s*#region\\b|^\\s*\\(\\*\\s*#region(.*)\\*\\)", + "end": "^\\s*//\\s*#endregion\\b|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)" + } + } } diff --git a/extensions/fsharp/package.json b/extensions/fsharp/package.json index 4426dcbde61..b97779edbf6 100644 --- a/extensions/fsharp/package.json +++ b/extensions/fsharp/package.json @@ -17,6 +17,10 @@ "language": "fsharp", "scopeName": "source.fsharp", "path": "./syntaxes/fsharp.json" + }], + "snippets": [{ + "language": "fsharp", + "path": "./snippets/fsharp.json" }] } } diff --git a/extensions/fsharp/snippets/fsharp.json b/extensions/fsharp/snippets/fsharp.json new file mode 100644 index 00000000000..f2640f764f4 --- /dev/null +++ b/extensions/fsharp/snippets/fsharp.json @@ -0,0 +1,16 @@ +{ + "Region Start": { + "prefix": "#region", + "body": [ + "//#region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#endregion", + "body": [ + "//#endregion" + ], + "description": "Folding Region End" + } +} diff --git a/extensions/fsharp/syntaxes/fsharp.json b/extensions/fsharp/syntaxes/fsharp.json index d48f35550e4..ca1fdacfab5 100644 --- a/extensions/fsharp/syntaxes/fsharp.json +++ b/extensions/fsharp/syntaxes/fsharp.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/ionide/ionide-fsgrammar/commit/f2e3c30f0ebfcc89fb78ad908701159f20516812", + "version": "https://github.com/ionide/ionide-fsgrammar/commit/7a24912ecdc886e4d973d6d3ab8df20a0feeda76", "name": "fsharp", "scopeName": "source.fsharp", "fileTypes": [ @@ -145,7 +145,7 @@ "patterns": [ { "name": "binding.fsharp", - "begin": "\\b(val mutable|val|let mutable|let inline|let|member|static member|override|let!)(\\s+rec|mutable)?(\\s+\\[\\<.*\\>\\])?\\s*(private|internal|public)?\\s+(\\([^\\s-]*\\)|[_[:alpha:]]([_[:alpha:]0-9,\\._]|(?<=,)\\s)*)", + "begin": "\\b(val mutable|val|let mutable|let inline|let|member|static member|override|let!)(\\s+rec|mutable)?(\\s+\\[\\<.*\\>\\])?\\s*(private|internal|public)?\\s+(\\([^-]*\\)|\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9,\\._]|(?<=,)\\s)*|``[_[:alpha:]]([_[:alpha:]0-9,\\._`\\s]|(?<=,)\\s)*)", "end": "((``.*``)|(with)|=|$)", "beginCaptures": { "1": { @@ -330,7 +330,12 @@ "1": { "name": "punctuation.definition.string.end.fsharp" } - } + }, + "patterns": [ + { + "include": "#string_formatter" + } + ] }, { "name": "string.quoted.double.fsharp", @@ -358,11 +363,27 @@ { "name": "invalid.illeagal.character.string.fsharp", "match": "\\\\(?![\\\\''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})." + }, + { + "include": "#string_formatter" } ] } ] }, + "string_formatter": { + "patterns": [ + { + "name": "entity.name.type.format.specifier.fsharp", + "match": "(%0?-?(\\d+)?((a|t)|(\\.\\d+)?(f|F|e|E|g|G|M)|(b|c|s|d|i|x|X|o)|(s|b|O)|(\\+?A)))", + "captures": { + "1": { + "name": "keyword.other.format.specifier.fsharp" + } + } + } + ] + }, "variables": { "patterns": [ { diff --git a/extensions/fsharp/test/colorize-results/test_fs.json b/extensions/fsharp/test/colorize-results/test_fs.json index 2f161a6fccc..ee0ae2ca9c1 100644 --- a/extensions/fsharp/test/colorize-results/test_fs.json +++ b/extensions/fsharp/test/colorize-results/test_fs.json @@ -1026,11 +1026,11 @@ "c": "\\n", "t": "source.fsharp string.quoted.double.fsharp constant.character.string.escape.fsharp", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character: #569CD6", + "light_plus": "constant.character: #0000FF", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { diff --git a/extensions/git/npm-shrinkwrap.json b/extensions/git/npm-shrinkwrap.json index d757c142e96..9e5bed8584a 100644 --- a/extensions/git/npm-shrinkwrap.json +++ b/extensions/git/npm-shrinkwrap.json @@ -7,13 +7,18 @@ "from": "applicationinsights@0.18.0", "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz" }, + "byline": { + "version": "5.0.0", + "from": "byline@latest", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz" + }, "iconv-lite": { - "version": "0.4.15", - "from": "iconv-lite@0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz" + "version": "0.4.19", + "from": "iconv-lite@0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz" }, "vscode-extension-telemetry": { - "version": "0.0.7", + "version": "0.0.8", "from": "vscode-extension-telemetry@>=0.0.8 <0.0.9", "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz" }, diff --git a/extensions/git/package.json b/extensions/git/package.json index bd646d7f8a6..cf90adfa2b6 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -36,6 +36,11 @@ "dark": "resources/icons/dark/git.svg" } }, + { + "command": "git.close", + "title": "%command.close%", + "category": "Git" + }, { "command": "git.refresh", "title": "%command.refresh%", @@ -96,6 +101,24 @@ "title": "%command.revertSelectedRanges%", "category": "Git" }, + { + "command": "git.stageChange", + "title": "%command.stageChange%", + "category": "Git", + "icon": { + "light": "resources/icons/light/stage.svg", + "dark": "resources/icons/dark/stage.svg" + } + }, + { + "command": "git.revertChange", + "title": "%command.revertChange%", + "category": "Git", + "icon": { + "light": "resources/icons/light/clean.svg", + "dark": "resources/icons/dark/clean.svg" + } + }, { "command": "git.unstage", "title": "%command.unstage%", @@ -241,6 +264,11 @@ "title": "%command.sync%", "category": "Git" }, + { + "command": "git.syncRebase", + "title": "%command.syncRebase%", + "category": "Git" + }, { "command": "git.publish", "title": "%command.publish%", @@ -310,10 +338,18 @@ "command": "git.stageSelectedRanges", "when": "config.git.enabled && gitOpenRepositoryCount != 0" }, + { + "command": "git.stageChange", + "when": "false" + }, { "command": "git.revertSelectedRanges", "when": "config.git.enabled && gitOpenRepositoryCount != 0" }, + { + "command": "git.revertChange", + "when": "false" + }, { "command": "git.unstage", "when": "config.git.enabled && gitOpenRepositoryCount != 0" @@ -418,6 +454,10 @@ "command": "git.sync", "when": "config.git.enabled && gitOpenRepositoryCount != 0" }, + { + "command": "git.syncRebase", + "when": "config.git.enabled && gitOpenRepositoryCount != 0" + }, { "command": "git.publish", "when": "config.git.enabled && gitOpenRepositoryCount != 0" @@ -464,6 +504,11 @@ "group": "1_sync", "when": "config.git.enabled && scmProvider == git" }, + { + "command": "git.syncRebase", + "group": "1_sync", + "when": "config.git.enabled && scmProvider == git && gitState == idle" + }, { "command": "git.pull", "group": "1_sync", @@ -529,6 +574,11 @@ "group": "3_commit", "when": "config.git.enabled && scmProvider == git" }, + { + "command": "git.stageAll", + "group": "4_stage", + "when": "config.git.enabled && scmProvider == git" + }, { "command": "git.unstageAll", "group": "4_stage", @@ -560,6 +610,13 @@ "when": "config.git.enabled && scmProvider == git" } ], + "scm/sourceControl": [ + { + "command": "git.close", + "group": "navigation", + "when": "config.git.enabled && scmProvider == git" + } + ], "scm/resourceGroup/context": [ { "command": "git.stageAll", @@ -688,7 +745,7 @@ { "command": "git.openChange", "group": "navigation", - "when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme != extension" + "when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme == file" }, { "command": "git.stageSelectedRanges", @@ -705,6 +762,16 @@ "group": "2_git@3", "when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff" } + ], + "scm/change/title": [ + { + "command": "git.stageChange", + "when": "config.git.enabled && originalResourceScheme == git" + }, + { + "command": "git.revertChange", + "when": "config.git.enabled && originalResourceScheme == git" + } ] }, "configuration": { @@ -784,18 +851,72 @@ "type": "boolean", "description": "%config.enableCommitSigning%", "default": false + }, + "git.decorations.enabled": { + "type": "boolean", + "default": true, + "description": "%config.decorations.enabled%" } } - } + }, + "colors": [ + { + "id": "gitDecoration.modifiedResourceForeground", + "description": "%colors.modified%", + "defaults": { + "light": "#a76e12", + "dark": "#E2C08D", + "highContrast": "#E2C08D" + } + }, + { + "id": "gitDecoration.deletedResourceForeground", + "description": "%colors.deleted%", + "defaults": { + "light": "#ad0707", + "dark": "#c74e39", + "highContrast": "#c74e39" + } + }, + { + "id": "gitDecoration.untrackedResourceForeground", + "description": "%colors.untracked%", + "defaults": { + "light": "#019001", + "dark": "#73C991", + "highContrast": "#73C991" + } + }, + { + "id": "gitDecoration.ignoredResourceForeground", + "description": "%colors.ignored%", + "defaults": { + "light": "#8E8E90", + "dark": "#A7A8A9", + "highContrast": "#A7A8A9" + } + }, + { + "id": "gitDecoration.conflictingResourceForeground", + "description": "%colors.conflict%", + "defaults": { + "light": "#6c6cc4", + "dark": "#6c6cc4", + "highContrast": "#6c6cc4" + } + } + ] }, "dependencies": { - "iconv-lite": "0.4.15", + "byline": "^5.0.0", + "iconv-lite": "0.4.19", "vscode-extension-telemetry": "0.0.8", "vscode-nls": "2.0.2" }, "devDependencies": { - "@types/mocha": "^2.2.41", - "@types/node": "^7.0.4", + "@types/mocha": "2.2.43", + "@types/node": "7.0.43", + "@types/byline": "4.2.31", "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 da2c9210fd1..e001bbcbb20 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -10,6 +10,8 @@ "command.stageAll": "Stage All Changes", "command.stageSelectedRanges": "Stage Selected Ranges", "command.revertSelectedRanges": "Revert Selected Ranges", + "command.stageChange": "Stage Change", + "command.revertChange": "Revert Change", "command.unstage": "Unstage Changes", "command.unstageAll": "Unstage All Changes", "command.unstageSelectedRanges": "Unstage Selected Ranges", @@ -35,6 +37,7 @@ "command.pushTo": "Push to...", "command.pushWithTags": "Push With Tags", "command.sync": "Sync", + "command.syncRebase": "Sync (Rebase)", "command.publish": "Publish Branch", "command.showOutput": "Show Git Output", "command.ignore": "Add File to .gitignore", @@ -54,5 +57,11 @@ "config.defaultCloneDirectory": "The default location where to clone a git repository", "config.enableSmartCommit": "Commit all changes when there are no staged changes.", "config.enableCommitSigning": "Enables commit signing with GPG.", - "config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run." -} \ No newline at end of file + "config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run.", + "config.decorations.enabled": "Controls if Git contributes colors and badges to the explorer and the open editors view.", + "colors.modified": "Color for modified resources.", + "colors.deleted": "Color for deleted resources.", + "colors.untracked": "Color for untracked resources.", + "colors.ignored": "Color for ignored resources.", + "colors.conflict": "Color for resources with conflicts." +} diff --git a/extensions/git/src/askpass-main.ts b/extensions/git/src/askpass-main.ts index db1bdeac366..3f2588d1939 100644 --- a/extensions/git/src/askpass-main.ts +++ b/extensions/git/src/askpass-main.ts @@ -34,8 +34,8 @@ function main(argv: string[]): void { return fatal('Skip fetch commands'); } - const output = process.env['VSCODE_GIT_ASKPASS_PIPE']; - const socketPath = process.env['VSCODE_GIT_ASKPASS_HANDLE']; + const output = process.env['VSCODE_GIT_ASKPASS_PIPE'] as string; + const socketPath = process.env['VSCODE_GIT_ASKPASS_HANDLE'] as string; const request = argv[2]; const host = argv[4].substring(1, argv[4].length - 2); const opts: http.RequestOptions = { diff --git a/extensions/git/src/askpass.ts b/extensions/git/src/askpass.ts index 597cc043d4e..8c6815b8d1d 100644 --- a/extensions/git/src/askpass.ts +++ b/extensions/git/src/askpass.ts @@ -28,7 +28,7 @@ function getIPCHandlePath(nonce: string): string { } if (process.env['XDG_RUNTIME_DIR']) { - return path.join(process.env['XDG_RUNTIME_DIR'], `vscode-git-askpass-${nonce}.sock`); + return path.join(process.env['XDG_RUNTIME_DIR'] as string, `vscode-git-askpass-${nonce}.sock`); } return path.join(os.tmpdir(), `vscode-git-askpass-${nonce}.sock`); diff --git a/extensions/git/src/autofetch.ts b/extensions/git/src/autofetch.ts index 930fc2f05f3..a984a20c6b6 100644 --- a/extensions/git/src/autofetch.ts +++ b/extensions/git/src/autofetch.ts @@ -5,16 +5,23 @@ 'use strict'; -import { workspace, Disposable } from 'vscode'; +import { workspace, Disposable, EventEmitter } from 'vscode'; import { GitErrorCodes } from './git'; import { Repository } from './repository'; -import { throttle } from './decorators'; +import { eventToPromise, filterEvent } from './util'; export class AutoFetcher { private static Period = 3 * 60 * 1000 /* three minutes */; + + private _onDidChange = new EventEmitter(); + private onDidChange = this._onDidChange.event; + + private _enabled: boolean = false; + get enabled(): boolean { return this._enabled; } + set enabled(enabled: boolean) { this._enabled = enabled; this._onDidChange.fire(enabled); } + private disposables: Disposable[] = []; - private timer: NodeJS.Timer; constructor(private repository: Repository) { workspace.onDidChangeConfiguration(this.onConfiguration, this, this.disposables); @@ -32,26 +39,41 @@ export class AutoFetcher { } enable(): void { - if (this.timer) { + if (this.enabled) { return; } - this.fetch(); - this.timer = setInterval(() => this.fetch(), AutoFetcher.Period); + this.enabled = true; + this.run(); } disable(): void { - clearInterval(this.timer); + this.enabled = false; } - @throttle - private async fetch(): Promise { - try { - await this.repository.fetch(); - } catch (err) { - if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - this.disable(); + private async run(): Promise { + while (this.enabled) { + await this.repository.whenIdleAndFocused(); + + if (!this.enabled) { + return; } + + try { + await this.repository.fetch(); + } catch (err) { + if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { + this.disable(); + } + } + + if (!this.enabled) { + return; + } + + const timeout = new Promise(c => setTimeout(c, AutoFetcher.Period)); + const whenDisabled = eventToPromise(filterEvent(this.onDidChange, enabled => !enabled)); + await Promise.race([timeout, whenDisabled]); } } diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index abc58d41aae..a78041e69bd 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -5,11 +5,12 @@ 'use strict'; -import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation } from 'vscode'; +import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor } from 'vscode'; import { Ref, RefType, Git, GitErrorCodes, Branch } from './git'; import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository'; import { Model } from './model'; import { toGitUri, fromGitUri } from './uri'; +import { grep } from './util'; import { applyLineChanges, intersectDiffWithRange, toLineRanges, invertLineChange } from './staging'; import * as path from 'path'; import * as os from 'os'; @@ -92,11 +93,13 @@ class MergeItem implements QuickPickItem { class CreateBranchItem implements QuickPickItem { + constructor(private cc: CommandCenter) { } + get label(): string { return localize('create branch', '$(plus) Create new branch'); } get description(): string { return ''; } async run(repository: Repository): Promise { - await commands.executeCommand('git.branch'); + await this.cc.branch(repository); } } @@ -169,12 +172,14 @@ export class CommandCenter { const opts: TextDocumentShowOptions = { preserveFocus, preview, - viewColumn: window.activeTextEditor && window.activeTextEditor.viewColumn || ViewColumn.One + viewColumn: ViewColumn.Active }; const activeTextEditor = window.activeTextEditor; - if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.fsPath === right.fsPath) { + // Check if active text editor has same path as other editor. we cannot compare via + // URI.toString() here because the schemas can be different. Instead we just go by path. + if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.path === right.path) { opts.selection = activeTextEditor.selection; } @@ -256,13 +261,20 @@ export class CommandCenter { } @command('git.clone') - async clone(): Promise { - const url = await window.showInputBox({ - prompt: localize('repourl', "Repository URL"), - ignoreFocusOut: true - }); + async clone(url?: string): Promise { + if (!url) { + url = await window.showInputBox({ + prompt: localize('repourl', "Repository URL"), + ignoreFocusOut: true + }); + } if (!url) { + /* __GDPR__ + "clone" : { + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'no_URL' }); return; } @@ -277,6 +289,11 @@ export class CommandCenter { }); if (!parentPath) { + /* __GDPR__ + "clone" : { + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'no_directory' }); return; } @@ -294,14 +311,30 @@ export class CommandCenter { const result = await window.showInformationMessage(localize('proposeopen', "Would you like to open the cloned repository?"), open); const openFolder = result === open; + /* __GDPR__ + "clone" : { + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "openFolder": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } + } + */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'success' }, { openFolder: openFolder ? 1 : 0 }); if (openFolder) { commands.executeCommand('vscode.openFolder', Uri.file(repositoryPath)); } } catch (err) { if (/already exists and is not an empty directory/.test(err && err.stderr || '')) { + /* __GDPR__ + "clone" : { + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'directory_not_empty' }); } else { + /* __GDPR__ + "clone" : { + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'error' }); } throw err; @@ -310,25 +343,44 @@ export class CommandCenter { @command('git.init') async init(): Promise { - const value = workspace.workspaceFolders && workspace.workspaceFolders.length > 0 - ? workspace.workspaceFolders[0].uri.fsPath - : os.homedir(); + const homeUri = Uri.file(os.homedir()); + const defaultUri = workspace.workspaceFolders && workspace.workspaceFolders.length > 0 + ? Uri.file(workspace.workspaceFolders[0].uri.fsPath) + : homeUri; - const path = await window.showInputBox({ - placeHolder: localize('path to init', "Folder path"), - prompt: localize('provide path', "Please provide a folder path to initialize a Git repository"), - value, - ignoreFocusOut: true + const result = await window.showOpenDialog({ + canSelectFiles: false, + canSelectFolders: true, + canSelectMany: false, + defaultUri, + openLabel: localize('init repo', "Initialize Repository") }); - if (!path) { + if (!result || result.length === 0) { return; } + const uri = result[0]; + + if (homeUri.toString().startsWith(uri.toString())) { + const yes = localize('create repo', "Initialize Repository"); + const answer = await window.showWarningMessage(localize('are you sure', "This will create a Git repository in '{0}'. Are you sure you want to continue?", uri.fsPath), yes); + + if (answer !== yes) { + return; + } + } + + const path = uri.fsPath; await this.git.init(path); await this.model.tryOpenRepository(path); } + @command('git.close', { repository: true }) + async close(repository: Repository): Promise { + this.model.close(repository); + } + @command('git.openFile') async openFile(arg?: Resource | Uri, ...resourceStates: SourceControlResourceState[]): Promise { const preserveFocus = arg instanceof Resource; @@ -363,11 +415,13 @@ export class CommandCenter { for (const uri of uris) { const opts: TextDocumentShowOptions = { preserveFocus, - preview: preview, - viewColumn: activeTextEditor && activeTextEditor.viewColumn || ViewColumn.One + preview, + viewColumn: ViewColumn.Active }; - if (activeTextEditor && activeTextEditor.document.uri.fsPath === uri.fsPath) { + // Check if active text editor has same path as other editor. we cannot compare via + // URI.toString() here because the schemas can be different. Instead we just go by path. + if (activeTextEditor && activeTextEditor.document.uri.path === uri.path) { opts.selection = activeTextEditor.selection; } @@ -449,12 +503,20 @@ export class CommandCenter { } const selection = resourceStates.filter(s => s instanceof Resource) as Resource[]; - const mergeConflicts = selection.filter(s => s.resourceGroupType === ResourceGroupType.Merge); + const merge = selection.filter(s => s.resourceGroupType === ResourceGroupType.Merge); + const bothModified = merge.filter(s => s.type === Status.BOTH_MODIFIED); + const promises = bothModified.map(s => grep(s.resourceUri.fsPath, /^<{7}|^={7}|^>{7}/)); + const unresolvedBothModified = await Promise.all(promises); + const resolvedConflicts = bothModified.filter((s, i) => !unresolvedBothModified[i]); + const unresolvedConflicts = [ + ...merge.filter(s => s.type !== Status.BOTH_MODIFIED), + ...bothModified.filter((s, i) => unresolvedBothModified[i]) + ]; - if (mergeConflicts.length > 0) { - const message = mergeConflicts.length > 1 - ? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", mergeConflicts.length) - : localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(mergeConflicts[0].resourceUri.fsPath)); + if (unresolvedConflicts.length > 0) { + const message = unresolvedConflicts.length > 1 + ? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", unresolvedConflicts.length) + : localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(unresolvedConflicts[0].resourceUri.fsPath)); const yes = localize('yes', "Yes"); const pick = await window.showWarningMessage(message, { modal: true }, yes); @@ -464,10 +526,8 @@ export class CommandCenter { } } - const workingTree = selection - .filter(s => s.resourceGroupType === ResourceGroupType.WorkingTree); - - const scmResources = [...workingTree, ...mergeConflicts]; + const workingTree = selection.filter(s => s.resourceGroupType === ResourceGroupType.WorkingTree); + const scmResources = [...workingTree, ...resolvedConflicts, ...unresolvedConflicts]; if (!scmResources.length) { return; @@ -498,14 +558,39 @@ export class CommandCenter { await repository.add([]); } + @command('git.stageChange') + async stageChange(uri: Uri, changes: LineChange[], index: number): Promise { + const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0]; + + if (!textEditor) { + return; + } + + await this._stageChanges(textEditor, [changes[index]]); + } + @command('git.stageSelectedRanges', { diff: true }) - async stageSelectedRanges(diffs: LineChange[]): Promise { + async stageSelectedChanges(changes: LineChange[]): Promise { const textEditor = window.activeTextEditor; if (!textEditor) { return; } + const modifiedDocument = textEditor.document; + const selectedLines = toLineRanges(textEditor.selections, modifiedDocument); + const selectedChanges = changes + .map(diff => selectedLines.reduce((result, range) => result || intersectDiffWithRange(modifiedDocument, diff, range), null)) + .filter(d => !!d) as LineChange[]; + + if (!selectedChanges.length) { + return; + } + + await this._stageChanges(textEditor, selectedChanges); + } + + private async _stageChanges(textEditor: TextEditor, changes: LineChange[]): Promise { const modifiedDocument = textEditor.document; const modifiedUri = modifiedDocument.uri; @@ -515,28 +600,48 @@ export class CommandCenter { const originalUri = toGitUri(modifiedUri, '~'); const originalDocument = await workspace.openTextDocument(originalUri); - const selectedLines = toLineRanges(textEditor.selections, modifiedDocument); - const selectedDiffs = diffs - .map(diff => selectedLines.reduce((result, range) => result || intersectDiffWithRange(modifiedDocument, diff, range), null)) - .filter(d => !!d) as LineChange[]; - - if (!selectedDiffs.length) { - return; - } - - const result = applyLineChanges(originalDocument, modifiedDocument, selectedDiffs); + const result = applyLineChanges(originalDocument, modifiedDocument, changes); await this.runByRepository(modifiedUri, async (repository, resource) => await repository.stage(resource, result)); } + @command('git.revertChange') + async revertChange(uri: Uri, changes: LineChange[], index: number): Promise { + const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0]; + + if (!textEditor) { + return; + } + + await this._revertChanges(textEditor, [...changes.slice(0, index), ...changes.slice(index + 1)]); + } + @command('git.revertSelectedRanges', { diff: true }) - async revertSelectedRanges(diffs: LineChange[]): Promise { + async revertSelectedRanges(changes: LineChange[]): Promise { const textEditor = window.activeTextEditor; if (!textEditor) { return; } + const modifiedDocument = textEditor.document; + const selections = textEditor.selections; + const selectedChanges = changes.filter(change => { + const modifiedRange = change.modifiedEndLineNumber === 0 + ? new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(change.modifiedStartLineNumber).range.start) + : new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(change.modifiedEndLineNumber - 1).range.end); + + return selections.every(selection => !selection.intersection(modifiedRange)); + }); + + if (selectedChanges.length === changes.length) { + return; + } + + await this._revertChanges(textEditor, selectedChanges); + } + + private async _revertChanges(textEditor: TextEditor, changes: LineChange[]): Promise { const modifiedDocument = textEditor.document; const modifiedUri = modifiedDocument.uri; @@ -546,19 +651,6 @@ export class CommandCenter { const originalUri = toGitUri(modifiedUri, '~'); const originalDocument = await workspace.openTextDocument(originalUri); - const selections = textEditor.selections; - const selectedDiffs = diffs.filter(diff => { - const modifiedRange = diff.modifiedEndLineNumber === 0 - ? new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(diff.modifiedStartLineNumber).range.start) - : new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end); - - return selections.every(selection => !selection.intersection(modifiedRange)); - }); - - if (selectedDiffs.length === diffs.length) { - return; - } - const basename = path.basename(modifiedUri.fsPath); const message = localize('confirm revert', "Are you sure you want to revert the selected changes in {0}?", basename); const yes = localize('revert', "Revert Changes"); @@ -568,10 +660,11 @@ export class CommandCenter { return; } - const result = applyLineChanges(originalDocument, modifiedDocument, selectedDiffs); + const result = applyLineChanges(originalDocument, modifiedDocument, changes); const edit = new WorkspaceEdit(); edit.replace(modifiedUri, new Range(new Position(0, 0), modifiedDocument.lineAt(modifiedDocument.lineCount - 1).range.end), result); workspace.applyEdit(edit); + await modifiedDocument.save(); } @command('git.unstage') @@ -907,7 +1000,7 @@ export class CommandCenter { const includeTags = checkoutType === 'all' || checkoutType === 'tags'; const includeRemotes = checkoutType === 'all' || checkoutType === 'remote'; - const createBranch = new CreateBranchItem(); + const createBranch = new CreateBranchItem(this); const heads = repository.refs.filter(ref => ref.type === RefType.Head) .map(ref => new CheckoutItem(ref)); @@ -1145,8 +1238,7 @@ export class CommandCenter { repository.pushTo(pick.label, branchName); } - @command('git.sync', { repository: true }) - async sync(repository: Repository): Promise { + private async _sync(repository: Repository, rebase: boolean): Promise { const HEAD = repository.HEAD; if (!HEAD || !HEAD.upstream) { @@ -1169,7 +1261,34 @@ export class CommandCenter { } } - await repository.sync(); + if (rebase) { + await repository.syncRebase(); + } else { + await repository.sync(); + } + } + + @command('git.sync', { repository: true }) + sync(repository: Repository): Promise { + return this._sync(repository, false); + } + + @command('git._syncAll') + async syncAll(): Promise { + await Promise.all(this.model.repositories.map(async repository => { + const HEAD = repository.HEAD; + + if (!HEAD || !HEAD.upstream) { + return; + } + + await repository.sync(); + })); + } + + @command('git.syncRebase', { repository: true }) + syncRebase(repository: Repository): Promise { + return this._sync(repository, true); } @command('git.publish', { repository: true }) @@ -1182,9 +1301,12 @@ export class CommandCenter { } const branchName = repository.HEAD && repository.HEAD.name || ''; - const picks = repository.remotes.map(r => r.name); - const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName); - const choice = await window.showQuickPick(picks, { placeHolder }); + const selectRemote = async () => { + const picks = repository.remotes.map(r => r.name); + const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName); + return await window.showQuickPick(picks, { placeHolder }); + }; + const choice = remotes.length === 1 ? remotes[0].name : await selectRemote(); if (!choice) { return; @@ -1198,27 +1320,27 @@ export class CommandCenter { this.outputChannel.show(); } - @command('git.ignore', { repository: true }) - async ignore(repository: Repository, ...resourceStates: SourceControlResourceState[]): Promise { + @command('git.ignore') + async ignore(...resourceStates: SourceControlResourceState[]): Promise { if (resourceStates.length === 0 || !(resourceStates[0].resourceUri instanceof Uri)) { - const uri = window.activeTextEditor && window.activeTextEditor.document.uri; + const resource = this.getSCMResource(); - if (!uri) { + if (!resource) { return; } - return await repository.ignore([uri]); + resourceStates = [resource]; } - const uris = resourceStates + const resources = resourceStates .filter(s => s instanceof Resource) .map(r => r.resourceUri); - if (!uris.length) { + if (!resources.length) { return; } - await repository.ignore(uris); + await this.runByRepository(resources, async (repository, resources) => repository.ignore(resources)); } @command('git.stash', { repository: true }) @@ -1273,7 +1395,7 @@ export class CommandCenter { } private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any { - const result = (...args) => { + const result = (...args: any[]) => { let result: Promise; if (!options.repository) { @@ -1300,6 +1422,11 @@ export class CommandCenter { }); } + /* __GDPR__ + "git.command" : { + "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryReporter.sendTelemetryEvent('git.command', { command: id }); return result.catch(async err => { @@ -1317,7 +1444,7 @@ export class CommandCenter { .replace(/^error: /mi, '') .replace(/^> husky.*$/mi, '') .split(/[\r\n]/) - .filter(line => !!line) + .filter((line: string) => !!line) [0]; message = hint @@ -1343,7 +1470,7 @@ export class CommandCenter { }; // patch this object, so people can call methods directly - this[key] = result; + (this as any)[key] = result; return result; } @@ -1387,7 +1514,7 @@ export class CommandCenter { return result; } - const tuple = result.filter(p => p[0] === repository)[0]; + const tuple = result.filter(p => p.repository === repository)[0]; if (tuple) { tuple.resources.push(resource); @@ -1407,4 +1534,4 @@ export class CommandCenter { dispose(): void { this.disposables.forEach(d => d.dispose()); } -} \ No newline at end of file +} diff --git a/extensions/git/src/contentProvider.ts b/extensions/git/src/contentProvider.ts index f47765c484e..4363c80af8e 100644 --- a/extensions/git/src/contentProvider.ts +++ b/extensions/git/src/contentProvider.ts @@ -6,9 +6,10 @@ 'use strict'; import { workspace, Uri, Disposable, Event, EventEmitter, window } from 'vscode'; -import { debounce } from './decorators'; -import { fromGitUri } from './uri'; -import { Model, ModelChangeEvent } from './model'; +import { debounce, throttle } from './decorators'; +import { fromGitUri, toGitUri } from './uri'; +import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model'; +import { filterEvent, eventToPromise } from './util'; interface CacheRow { uri: Uri; @@ -24,8 +25,8 @@ const FIVE_MINUTES = 1000 * 60 * 5; export class GitContentProvider { - private onDidChangeEmitter = new EventEmitter(); - get onDidChange(): Event { return this.onDidChangeEmitter.event; } + private _onDidChange = new EventEmitter(); + get onDidChange(): Event { return this._onDidChange.event; } private changedRepositoryRoots = new Set(); private cache: Cache = Object.create(null); @@ -34,6 +35,7 @@ export class GitContentProvider { constructor(private model: Model) { this.disposables.push( model.onDidChangeRepository(this.onDidChangeRepository, this), + model.onDidChangeOriginalResource(this.onDidChangeOriginalResource, this), workspace.registerTextDocumentContentProvider('git', this) ); @@ -45,19 +47,33 @@ export class GitContentProvider { this.eventuallyFireChangeEvents(); } + private onDidChangeOriginalResource({ uri }: OriginalResourceChangeEvent): void { + if (uri.scheme !== 'file') { + return; + } + + this._onDidChange.fire(toGitUri(uri, '', true)); + } + @debounce(1100) private eventuallyFireChangeEvents(): void { this.fireChangeEvents(); } - private fireChangeEvents(): void { + @throttle + private async fireChangeEvents(): Promise { + if (!window.state.focused) { + const onDidFocusWindow = filterEvent(window.onDidChangeWindowState, e => e.focused); + await eventToPromise(onDidFocusWindow); + } + Object.keys(this.cache).forEach(key => { const uri = this.cache[key].uri; const fsPath = uri.fsPath; for (const root of this.changedRepositoryRoots) { if (fsPath.startsWith(root)) { - this.onDidChangeEmitter.fire(uri); + this._onDidChange.fire(uri); return; } } @@ -75,7 +91,7 @@ export class GitContentProvider { const cacheKey = uri.toString(); const timestamp = new Date().getTime(); - const cacheValue = { uri, timestamp }; + const cacheValue: CacheRow = { uri, timestamp }; this.cache[cacheKey] = cacheValue; @@ -101,7 +117,10 @@ export class GitContentProvider { Object.keys(this.cache).forEach(key => { const row = this.cache[key]; - const isOpen = window.visibleTextEditors.some(e => e.document.uri.fsPath === row.uri.fsPath); + const { path } = fromGitUri(row.uri); + const isOpen = workspace.textDocuments + .filter(d => d.uri.scheme === 'file') + .some(d => d.uri.fsPath === path); if (isOpen || now - row.timestamp < THREE_MINUTES) { cache[row.uri.toString()] = row; diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts new file mode 100644 index 00000000000..dcd1077819e --- /dev/null +++ b/extensions/git/src/decorationProvider.ts @@ -0,0 +1,173 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { window, workspace, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode'; +import { Repository, GitResourceGroup } from './repository'; +import { Model } from './model'; +import { debounce } from './decorators'; +import { filterEvent } from './util'; + +class GitIgnoreDecorationProvider implements DecorationProvider { + + private readonly _onDidChangeDecorations = new EventEmitter(); + readonly onDidChangeDecorations: Event = this._onDidChangeDecorations.event; + + private checkIgnoreQueue = new Map void, reject: (err: any) => void }>(); + private disposables: Disposable[] = []; + + constructor(private repository: Repository) { + this.disposables.push( + window.registerDecorationProvider(this), + filterEvent(workspace.onDidSaveTextDocument, e => e.fileName.endsWith('.gitignore'))(_ => this._onDidChangeDecorations.fire()) + //todo@joh -> events when the ignore status actually changes, not only when the file changes + ); + } + + dispose(): void { + this.disposables.forEach(d => d.dispose()); + this.checkIgnoreQueue.clear(); + } + + provideDecoration(uri: Uri): Promise { + return new Promise((resolve, reject) => { + this.checkIgnoreQueue.set(uri.fsPath, { resolve, reject }); + this.checkIgnoreSoon(); + }).then(ignored => { + if (ignored) { + return { + priority: 3, + color: new ThemeColor('gitDecoration.ignoredResourceForeground') + }; + } + }); + } + + @debounce(500) + private checkIgnoreSoon(): void { + const queue = new Map(this.checkIgnoreQueue.entries()); + this.checkIgnoreQueue.clear(); + this.repository.checkIgnore([...queue.keys()]).then(ignoreSet => { + for (const [key, value] of queue.entries()) { + value.resolve(ignoreSet.has(key)); + } + }, err => { + console.error(err); + for (const [, value] of queue.entries()) { + value.reject(err); + } + }); + } +} + +class GitDecorationProvider implements DecorationProvider { + + private readonly _onDidChangeDecorations = new EventEmitter(); + readonly onDidChangeDecorations: Event = this._onDidChangeDecorations.event; + + private disposables: Disposable[] = []; + private decorations = new Map(); + + constructor(private repository: Repository) { + this.disposables.push( + window.registerDecorationProvider(this), + repository.onDidRunOperation(this.onDidRunOperation, this) + ); + } + + private onDidRunOperation(): void { + let newDecorations = new Map(); + this.collectDecorationData(this.repository.indexGroup, newDecorations); + this.collectDecorationData(this.repository.workingTreeGroup, newDecorations); + this.collectDecorationData(this.repository.mergeGroup, newDecorations); + + let uris: Uri[] = []; + newDecorations.forEach((value, uriString) => { + if (this.decorations.has(uriString)) { + this.decorations.delete(uriString); + } else { + uris.push(Uri.parse(uriString)); + } + }); + this.decorations.forEach((value, uriString) => { + uris.push(Uri.parse(uriString)); + }); + this.decorations = newDecorations; + this._onDidChangeDecorations.fire(uris); + } + + private collectDecorationData(group: GitResourceGroup, bucket: Map): void { + group.resourceStates.forEach(r => { + if (r.resourceDecoration) { + bucket.set(r.original.toString(), r.resourceDecoration); + } + }); + } + + provideDecoration(uri: Uri): DecorationData | undefined { + return this.decorations.get(uri.toString()); + } + + dispose(): void { + this.disposables.forEach(d => d.dispose()); + } +} + + +export class GitDecorations { + + private configListener: Disposable; + private modelListener: Disposable[] = []; + private providers = new Map(); + + constructor(private model: Model) { + this.configListener = workspace.onDidChangeConfiguration(e => e.affectsConfiguration('git.decorations.enabled') && this.update()); + this.update(); + } + + private update(): void { + const enabled = workspace.getConfiguration('git').get('decorations.enabled'); + if (enabled) { + this.enable(); + } else { + this.disable(); + } + } + + private enable(): void { + this.modelListener = []; + this.model.onDidOpenRepository(this.onDidOpenRepository, this, this.modelListener); + this.model.onDidCloseRepository(this.onDidCloseRepository, this, this.modelListener); + this.model.repositories.forEach(this.onDidOpenRepository, this); + } + + private disable(): void { + this.modelListener.forEach(d => d.dispose()); + this.providers.forEach(value => value.dispose()); + this.providers.clear(); + } + + private onDidOpenRepository(repository: Repository): void { + const provider = new GitDecorationProvider(repository); + const ignoreProvider = new GitIgnoreDecorationProvider(repository); + this.providers.set(repository, Disposable.from(provider, ignoreProvider)); + } + + private onDidCloseRepository(repository: Repository): void { + const provider = this.providers.get(repository); + if (provider) { + provider.dispose(); + this.providers.delete(repository); + } + } + + dispose(): void { + this.configListener.dispose(); + this.modelListener.forEach(d => d.dispose()); + this.providers.forEach(value => value.dispose); + this.providers.clear(); + } +} diff --git a/extensions/git/src/decorators.ts b/extensions/git/src/decorators.ts index 905d9e8501b..83ee04b17ad 100644 --- a/extensions/git/src/decorators.ts +++ b/extensions/git/src/decorators.ts @@ -31,7 +31,7 @@ function decorate(decorator: (fn: Function, key: string) => Function): Function function _memoize(fn: Function, key: string): Function { const memoizeKey = `$memoize$${key}`; - return function (...args: any[]) { + return function (this: any, ...args: any[]) { if (!this.hasOwnProperty(memoizeKey)) { Object.defineProperty(this, memoizeKey, { configurable: false, @@ -51,7 +51,7 @@ function _throttle(fn: Function, key: string): Function { const currentKey = `$throttle$current$${key}`; const nextKey = `$throttle$next$${key}`; - const trigger = function (...args: any[]) { + const trigger = function (this: any, ...args: any[]) { if (this[nextKey]) { return this[nextKey]; } @@ -81,7 +81,7 @@ export const throttle = decorate(_throttle); function _sequentialize(fn: Function, key: string): Function { const currentKey = `__$sequence$${key}`; - return function (...args: any[]) { + return function (this: any, ...args: any[]) { const currentPromise = this[currentKey] as Promise || Promise.resolve(null); const run = async () => await fn.apply(this, args); this[currentKey] = currentPromise.then(run, run); @@ -95,7 +95,7 @@ export function debounce(delay: number): Function { return decorate((fn, key) => { const timerKey = `$debounce$${key}`; - return function (...args: any[]) { + return function (this: any, ...args: any[]) { clearTimeout(this[timerKey]); this[timerKey] = setTimeout(() => fn.apply(this, args), delay); }; diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 10de8149121..f758d845d2c 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -13,7 +13,6 @@ import { EventEmitter } from 'events'; import iconv = require('iconv-lite'); import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp } from './util'; -const readdir = denodeify(fs.readdir); const readfile = denodeify(fs.readFile); export interface IGit { @@ -66,7 +65,7 @@ function findSpecificGit(path: string): Promise { const buffers: Buffer[] = []; const child = cp.spawn(path, ['--version']); child.stdout.on('data', (b: Buffer) => buffers.push(b)); - child.on('error', e); + child.on('error', cpErrorHandler(e)); child.on('exit', code => code ? e(new Error('Not found')) : c({ path, version: parseVersion(Buffer.concat(buffers).toString('utf8').trim()) })); }); } @@ -118,48 +117,54 @@ function findSystemGitWin32(base: string): Promise { return findSpecificGit(path.join(base, 'Git', 'cmd', 'git.exe')); } -function findGitHubGitWin32(): Promise { - const github = path.join(process.env['LOCALAPPDATA'], 'GitHub'); - - return readdir(github).then(children => { - const git = children.filter(child => /^PortableGit/.test(child))[0]; - - if (!git) { - return Promise.reject('Not found'); - } - - return findSpecificGit(path.join(github, git, 'cmd', 'git.exe')); - }); -} - function findGitWin32(): Promise { - return findSystemGitWin32(process.env['ProgramW6432']) - .then(void 0, () => findSystemGitWin32(process.env['ProgramFiles(x86)'])) - .then(void 0, () => findSystemGitWin32(process.env['ProgramFiles'])) - .then(void 0, () => findSpecificGit('git')) - .then(void 0, () => findGitHubGitWin32()); + return findSystemGitWin32(process.env['ProgramW6432'] as string) + .then(void 0, () => findSystemGitWin32(process.env['ProgramFiles(x86)'] as string)) + .then(void 0, () => findSystemGitWin32(process.env['ProgramFiles'] as string)) + .then(void 0, () => findSpecificGit('git')); } export function findGit(hint: string | undefined): Promise { var first = hint ? findSpecificGit(hint) : Promise.reject(null); - return first.then(void 0, () => { - switch (process.platform) { - case 'darwin': return findGitDarwin(); - case 'win32': return findGitWin32(); - default: return findSpecificGit('git'); - } - }); + return first + .then(void 0, () => { + switch (process.platform) { + case 'darwin': return findGitDarwin(); + case 'win32': return findGitWin32(); + default: return findSpecificGit('git'); + } + }) + .then(null, () => Promise.reject(new Error('Git installation not found.'))); } - export interface IExecutionResult { exitCode: number; stdout: string; stderr: string; } -async function exec(child: cp.ChildProcess, options: any = {}): Promise { +function cpErrorHandler(cb: (reason?: any) => void): (reason?: any) => void { + return err => { + if (/ENOENT/.test(err.message)) { + err = new GitError({ + error: err, + message: 'Failed to execute git (ENOENT)', + gitErrorCode: GitErrorCodes.NotAGitRepository + }); + } + + cb(err); + }; +} + +export interface SpawnOptions extends cp.SpawnOptions { + input?: string; + encoding?: string; + log?: boolean; +} + +async function exec(child: cp.ChildProcess, options: SpawnOptions = {}): Promise { if (!child.stdout || !child.stderr) { throw new GitError({ message: 'Failed to get stdout or stderr from git process.' @@ -168,12 +173,12 @@ async function exec(child: cp.ChildProcess, options: any = {}): Promise { + const once = (ee: NodeJS.EventEmitter, name: string, fn: (...args: any[]) => void) => { ee.once(name, fn); disposables.push(toDisposable(() => ee.removeListener(name, fn))); }; - const on = (ee: NodeJS.EventEmitter, name: string, fn: Function) => { + const on = (ee: NodeJS.EventEmitter, name: string, fn: (...args: any[]) => void) => { ee.on(name, fn); disposables.push(toDisposable(() => ee.removeListener(name, fn))); }; @@ -183,17 +188,17 @@ async function exec(child: cp.ChildProcess, options: any = {}): Promise([ new Promise((c, e) => { - once(child, 'error', e); + once(child, 'error', cpErrorHandler(e)); once(child, 'exit', c); }), new Promise(c => { const buffers: Buffer[] = []; - on(child.stdout, 'data', b => buffers.push(b)); + on(child.stdout, 'data', (b: Buffer) => buffers.push(b)); once(child.stdout, 'close', () => c(iconv.decode(Buffer.concat(buffers), encoding))); }), new Promise(c => { const buffers: Buffer[] = []; - on(child.stderr, 'data', b => buffers.push(b)); + on(child.stderr, 'data', (b: Buffer) => buffers.push(b)); once(child.stderr, 'close', () => c(Buffer.concat(buffers).toString('utf8'))); }) ]); @@ -246,7 +251,7 @@ export class GitError { gitCommand: this.gitCommand, stdout: this.stdout, stderr: this.stderr - }, [], 2); + }, null, 2); if (this.error) { result += (this.error).stack; @@ -345,22 +350,22 @@ export class Git { return folderPath; } - async getRepositoryRoot(path: string): Promise { - const result = await this.exec(path, ['rev-parse', '--show-toplevel']); - return result.stdout.trim(); + async getRepositoryRoot(repositoryPath: string): Promise { + const result = await this.exec(repositoryPath, ['rev-parse', '--show-toplevel']); + return path.normalize(result.stdout.trim()); } - async exec(cwd: string, args: string[], options: any = {}): Promise { + async exec(cwd: string, args: string[], options: SpawnOptions = {}): Promise { options = assign({ cwd }, options || {}); return await this._exec(args, options); } - stream(cwd: string, args: string[], options: any = {}): cp.ChildProcess { + stream(cwd: string, args: string[], options: SpawnOptions = {}): cp.ChildProcess { options = assign({ cwd }, options || {}); return this.spawn(args, options); } - private async _exec(args: string[], options: any = {}): Promise { + private async _exec(args: string[], options: SpawnOptions = {}): Promise { const child = this.spawn(args, options); if (options.input) { @@ -387,7 +392,7 @@ export class Git { return result; } - spawn(args: string[], options: any = {}): cp.ChildProcess { + spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess { if (!this.gitPath) { throw new Error('git could not be found in the system.'); } @@ -505,19 +510,19 @@ export class Repository { } // TODO@Joao: rename to exec - async run(args: string[], options: any = {}): Promise { + async run(args: string[], options: SpawnOptions = {}): Promise { return await this.git.exec(this.repositoryRoot, args, options); } - stream(args: string[], options: any = {}): cp.ChildProcess { + stream(args: string[], options: SpawnOptions = {}): cp.ChildProcess { return this.git.stream(this.repositoryRoot, args, options); } - spawn(args: string[], options: any = {}): cp.ChildProcess { + spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess { return this.git.spawn(args, options); } - async config(scope: string, key: string, value: any, options: any): Promise { + async config(scope: string, key: string, value: any, options: SpawnOptions): Promise { const args = ['config']; if (scope) { @@ -883,9 +888,10 @@ export class Repository { getStatus(limit = 5000): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> { return new Promise<{ status: IFileStatus[]; didHitLimit: boolean; }>((c, e) => { const parser = new GitStatusParser(); - const child = this.stream(['status', '-z', '-u']); + const env = { GIT_OPTIONAL_LOCKS: '0' }; + const child = this.stream(['status', '-z', '-u'], { env }); - const onExit = exitCode => { + const onExit = (exitCode: number) => { if (exitCode !== 0) { const stderr = stderrData.join(''); return e(new GitError({ @@ -919,7 +925,7 @@ export class Repository { child.stderr.setEncoding('utf8'); child.stderr.on('data', raw => stderrData.push(raw as string)); - child.on('error', e); + child.on('error', cpErrorHandler(e)); child.on('exit', onExit); }); } @@ -947,7 +953,7 @@ export class Repository { async getRefs(): Promise { const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)']); - const fn = (line): Ref | null => { + const fn = (line: string): Ref | null => { let match: RegExpExecArray | null; if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) { @@ -972,7 +978,7 @@ export class Repository { const regex = /^stash@{(\d+)}:(.+)$/; const rawStashes = result.stdout.trim().split('\n') .filter(b => !!b) - .map(line => regex.exec(line)) + .map(line => regex.exec(line) as RegExpExecArray) .filter(g => !!g) .map(([, index, description]: RegExpExecArray) => ({ index: parseInt(index), description })); @@ -984,7 +990,7 @@ export class Repository { const regex = /^([^\s]+)\s+([^\s]+)\s/; const rawRemotes = result.stdout.trim().split('\n') .filter(b => !!b) - .map(line => regex.exec(line)) + .map(line => regex.exec(line) as RegExpExecArray) .filter(g => !!g) .map((groups: RegExpExecArray) => ({ name: groups[1], url: groups[2] })); diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index acc30eeb81d..bd9393ca52a 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -12,6 +12,7 @@ import { findGit, Git, IGit } from './git'; import { Model } from './model'; import { CommandCenter } from './commands'; import { GitContentProvider } from './contentProvider'; +import { GitDecorations } from './decorationProvider'; import { Askpass } from './askpass'; import { toDisposable } from './util'; import TelemetryReporter from 'vscode-extension-telemetry'; @@ -47,13 +48,14 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path)); - const onOutput = str => outputChannel.append(str); + const onOutput = (str: string) => outputChannel.append(str); git.onOutput.addListener('log', onOutput); disposables.push(toDisposable(() => git.onOutput.removeListener('log', onOutput))); disposables.push( new CommandCenter(git, model, outputChannel, telemetryReporter), new GitContentProvider(model), + new GitDecorations(model) ); await checkGitVersion(info); @@ -93,4 +95,4 @@ async function checkGitVersion(info: IGit): Promise { } else if (choice === neverShowAgain) { await config.update('ignoreLegacyWarning', true, true); } -} \ No newline at end of file +} diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index bfd746a427d..be87561ae9a 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -17,8 +17,16 @@ import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); class RepositoryPick implements QuickPickItem { - @memoize get label(): string { return path.basename(this.repository.root); } - @memoize get description(): string { return path.dirname(this.repository.root); } + @memoize get label(): string { + return path.basename(this.repository.root); + } + + @memoize get description(): string { + return [this.repository.headLabel, this.repository.syncLabel] + .filter(l => !!l) + .join(' '); + } + constructor(public readonly repository: Repository) { } } @@ -27,10 +35,19 @@ export interface ModelChangeEvent { uri: Uri; } +export interface OriginalResourceChangeEvent { + repository: Repository; + uri: Uri; +} + interface OpenRepository extends Disposable { repository: Repository; } +function isParent(parent: string, child: string): boolean { + return child.startsWith(parent); +} + export class Model { private _onDidOpenRepository = new EventEmitter(); @@ -42,6 +59,9 @@ export class Model { private _onDidChangeRepository = new EventEmitter(); readonly onDidChangeRepository: Event = this._onDidChangeRepository.event; + private _onDidChangeOriginalResource = new EventEmitter(); + readonly onDidChangeOriginalResource: Event = this._onDidChangeOriginalResource.event; + private openRepositories: OpenRepository[] = []; get repositories(): Repository[] { return this.openRepositories.map(r => r.repository); } @@ -147,7 +167,9 @@ export class Model { const activeRepositories = new Set(activeRepositoriesList); const openRepositoriesToDispose = removed .map(folder => this.getOpenRepository(folder.uri)) - .filter(r => !!r && !activeRepositories.has(r.repository)) as OpenRepository[]; + .filter(r => !!r) + .filter(r => !activeRepositories.has(r!.repository)) + .filter(r => !(workspace.workspaceFolders || []).some(f => isParent(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath)); openRepositoriesToDispose.forEach(r => r.dispose()); @@ -203,10 +225,14 @@ export class Model { const onDidDisappearRepository = filterEvent(repository.onDidChangeState, state => state === RepositoryState.Disposed); const disappearListener = onDidDisappearRepository(() => dispose()); const changeListener = repository.onDidChangeRepository(uri => this._onDidChangeRepository.fire({ repository, uri })); + const originalResourceChangeListener = repository.onDidChangeOriginalResource(uri => this._onDidChangeOriginalResource.fire({ repository, uri })); + const dispose = () => { disappearListener.dispose(); changeListener.dispose(); + originalResourceChangeListener.dispose(); repository.dispose(); + this.openRepositories = this.openRepositories.filter(e => e !== openRepository); this._onDidCloseRepository.fire(repository); }; @@ -216,6 +242,16 @@ export class Model { this._onDidOpenRepository.fire(repository); } + close(repository: Repository): void { + const openRepository = this.getOpenRepository(repository); + + if (!openRepository) { + return; + } + + openRepository.dispose(); + } + async pickRepository(): Promise { if (this.openRepositories.length === 0) { throw new Error(localize('no repositories', "There are no available repositories")); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index af4361dfa7d..58fd4a540fb 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -5,8 +5,8 @@ 'use strict'; -import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit } from 'vscode'; -import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash } from './git'; +import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData } from 'vscode'; +import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git'; import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util'; import { memoize, throttle, debounce } from './decorators'; import { toGitUri } from './uri'; @@ -82,7 +82,7 @@ export class Resource implements SourceControlResourceState { get original(): Uri { return this._resourceUri; } get renameResourceUri(): Uri | undefined { return this._renameResourceUri; } - private static Icons = { + private static Icons: any = { light: { Modified: getIconUri('status-modified', 'light'), Added: getIconUri('status-added', 'light'), @@ -171,13 +171,104 @@ export class Resource implements SourceControlResourceState { } get decorations(): SourceControlResourceDecorations { - const light = { iconPath: this.getIconPath('light') }; - const dark = { iconPath: this.getIconPath('dark') }; + // TODO@joh, still requires restart/redraw in the SCM viewlet + const decorations = workspace.getConfiguration().get('git.decorations.enabled'); + const light = !decorations ? { iconPath: this.getIconPath('light') } : undefined; + const dark = !decorations ? { iconPath: this.getIconPath('dark') } : undefined; const tooltip = this.tooltip; const strikeThrough = this.strikeThrough; const faded = this.faded; + const letter = this.letter; + const color = this.color; - return { strikeThrough, faded, tooltip, light, dark }; + return { strikeThrough, faded, tooltip, light, dark, letter, color, source: 'git.resource' /*todo@joh*/ }; + } + + get letter(): string | undefined { + switch (this.type) { + case Status.INDEX_MODIFIED: + case Status.MODIFIED: + return 'M'; + case Status.INDEX_ADDED: + return 'A'; + case Status.INDEX_DELETED: + case Status.DELETED: + return 'D'; + case Status.INDEX_RENAMED: + return 'R'; + case Status.UNTRACKED: + return 'U'; + case Status.IGNORED: + return 'I'; + case Status.INDEX_COPIED: + case Status.BOTH_DELETED: + case Status.ADDED_BY_US: + case Status.DELETED_BY_THEM: + case Status.ADDED_BY_THEM: + case Status.DELETED_BY_US: + case Status.BOTH_ADDED: + case Status.BOTH_MODIFIED: + return 'C'; + default: + return undefined; + } + } + + get color(): ThemeColor | undefined { + switch (this.type) { + case Status.INDEX_MODIFIED: + case Status.MODIFIED: + return new ThemeColor('gitDecoration.modifiedResourceForeground'); + case Status.INDEX_DELETED: + case Status.DELETED: + return new ThemeColor('gitDecoration.deletedResourceForeground'); + case Status.INDEX_ADDED: // todo@joh - special color? + case Status.INDEX_RENAMED: // todo@joh - special color? + case Status.UNTRACKED: + return new ThemeColor('gitDecoration.untrackedResourceForeground'); + case Status.IGNORED: + return new ThemeColor('gitDecoration.ignoredResourceForeground'); + case Status.INDEX_COPIED: + case Status.BOTH_DELETED: + case Status.ADDED_BY_US: + case Status.DELETED_BY_THEM: + case Status.ADDED_BY_THEM: + case Status.DELETED_BY_US: + case Status.BOTH_ADDED: + case Status.BOTH_MODIFIED: + return new ThemeColor('gitDecoration.conflictingResourceForeground'); + default: + return undefined; + } + } + + get priority(): number { + switch (this.type) { + case Status.INDEX_MODIFIED: + case Status.MODIFIED: + return 2; + case Status.IGNORED: + return 3; + case Status.INDEX_COPIED: + case Status.BOTH_DELETED: + case Status.ADDED_BY_US: + case Status.DELETED_BY_THEM: + case Status.ADDED_BY_THEM: + case Status.DELETED_BY_US: + case Status.BOTH_ADDED: + case Status.BOTH_MODIFIED: + return 4; + default: + return 1; + } + } + + get resourceDecoration(): DecorationData | undefined { + const title = this.tooltip; + const abbreviation = this.letter; + const color = this.color; + const priority = this.priority; + return { bubble: true, source: 'git.resource', title, abbreviation, color, priority }; } constructor( @@ -189,54 +280,34 @@ export class Resource implements SourceControlResourceState { } export enum Operation { - Status = 1 << 0, - Add = 1 << 1, - RevertFiles = 1 << 2, - Commit = 1 << 3, - Clean = 1 << 4, - Branch = 1 << 5, - Checkout = 1 << 6, - Reset = 1 << 7, - Fetch = 1 << 8, - Pull = 1 << 9, - Push = 1 << 10, - Sync = 1 << 11, - Show = 1 << 12, - Stage = 1 << 13, - GetCommitTemplate = 1 << 14, - DeleteBranch = 1 << 15, - Merge = 1 << 16, - Ignore = 1 << 17, - Tag = 1 << 18, - Stash = 1 << 19 + Status = 'Status', + Add = 'Add', + RevertFiles = 'RevertFiles', + Commit = 'Commit', + Clean = 'Clean', + Branch = 'Branch', + Checkout = 'Checkout', + Reset = 'Reset', + Fetch = 'Fetch', + Pull = 'Pull', + Push = 'Push', + Sync = 'Sync', + Show = 'Show', + Stage = 'Stage', + GetCommitTemplate = 'GetCommitTemplate', + DeleteBranch = 'DeleteBranch', + Merge = 'Merge', + Ignore = 'Ignore', + Tag = 'Tag', + Stash = 'Stash', + CheckIgnore = 'CheckIgnore' } -// function getOperationName(operation: Operation): string { -// switch (operation) { -// case Operation.Status: return 'Status'; -// case Operation.Add: return 'Add'; -// case Operation.RevertFiles: return 'RevertFiles'; -// case Operation.Commit: return 'Commit'; -// case Operation.Clean: return 'Clean'; -// case Operation.Branch: return 'Branch'; -// case Operation.Checkout: return 'Checkout'; -// case Operation.Reset: return 'Reset'; -// case Operation.Fetch: return 'Fetch'; -// case Operation.Pull: return 'Pull'; -// case Operation.Push: return 'Push'; -// case Operation.Sync: return 'Sync'; -// case Operation.Init: return 'Init'; -// case Operation.Show: return 'Show'; -// case Operation.Stage: return 'Stage'; -// case Operation.GetCommitTemplate: return 'GetCommitTemplate'; -// default: return 'unknown'; -// } -// } - function isReadOnly(operation: Operation): boolean { switch (operation) { case Operation.Show: case Operation.GetCommitTemplate: + case Operation.CheckIgnore: return true; default: return false; @@ -246,6 +317,7 @@ function isReadOnly(operation: Operation): boolean { function shouldShowProgress(operation: Operation): boolean { switch (operation) { case Operation.Fetch: + case Operation.CheckIgnore: return false; default: return true; @@ -259,24 +331,36 @@ export interface Operations { class OperationsImpl implements Operations { - constructor(private readonly operations: number = 0) { - // noop + private operations = new Map(); + + start(operation: Operation): void { + this.operations.set(operation, (this.operations.get(operation) || 0) + 1); } - start(operation: Operation): OperationsImpl { - return new OperationsImpl(this.operations | operation); - } + end(operation: Operation): void { + const count = (this.operations.get(operation) || 0) - 1; - end(operation: Operation): OperationsImpl { - return new OperationsImpl(this.operations & ~operation); + if (count <= 0) { + this.operations.delete(operation); + } else { + this.operations.set(operation, count); + } } isRunning(operation: Operation): boolean { - return (this.operations & operation) !== 0; + return this.operations.has(operation); } isIdle(): boolean { - return this.operations === 0; + const operations = this.operations.keys(); + + for (const operation of operations) { + if (!isReadOnly(operation)) { + return false; + } + } + + return true; } } @@ -302,6 +386,9 @@ export class Repository implements Disposable { private _onDidChangeStatus = new EventEmitter(); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + private _onDidChangeOriginalResource = new EventEmitter(); + readonly onDidChangeOriginalResource: Event = this._onDidChangeOriginalResource.event; + private _onRunOperation = new EventEmitter(); readonly onRunOperation: Event = this._onRunOperation.event; @@ -382,9 +469,8 @@ export class Repository implements Disposable { const onRelevantGitChange = filterEvent(onRelevantRepositoryChange, uri => /\/\.git\//.test(uri.path)); onRelevantGitChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); - const label = `${path.basename(repository.root)} (Git)`; - - this._sourceControl = scm.createSourceControl('git', label); + this._sourceControl = scm.createSourceControl('git', 'Git', Uri.file(repository.root)); + this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message (press {0} to commit)"); this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] }; this._sourceControl.quickDiffProvider = this; this.disposables.push(this._sourceControl); @@ -449,6 +535,7 @@ export class Repository implements Disposable { async stage(resource: Uri, contents: string): Promise { const relativePath = path.relative(this.repository.root, resource.fsPath).replace(/\\/g, '/'); await this.run(Operation.Stage, () => this.repository.stage(relativePath, contents)); + this._onDidChangeOriginalResource.fire(resource); } async revert(resources: Uri[]): Promise { @@ -534,11 +621,7 @@ export class Repository implements Disposable { @throttle async fetch(): Promise { - try { - await this.run(Operation.Fetch, () => this.repository.fetch()); - } catch (err) { - // noop - } + await this.run(Operation.Fetch, () => this.repository.fetch()); } @throttle @@ -568,10 +651,9 @@ export class Repository implements Disposable { await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true)); } - @throttle - async sync(): Promise { + private async _sync(rebase: boolean): Promise { await this.run(Operation.Sync, async () => { - await this.repository.pull(); + await this.repository.pull(rebase); const shouldPush = this.HEAD && typeof this.HEAD.ahead === 'number' ? this.HEAD.ahead > 0 : true; @@ -581,10 +663,20 @@ export class Repository implements Disposable { }); } + @throttle + sync(): Promise { + return this._sync(false); + } + + @throttle + async syncRebase(): Promise { + return this._sync(true); + } + async show(ref: string, filePath: string): Promise { return await this.run(Operation.Show, async () => { const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/'); - const configFiles = workspace.getConfiguration('files'); + const configFiles = workspace.getConfiguration('files', Uri.file(filePath)); const encoding = configFiles.get('encoding'); return await this.repository.buffer(`${ref}:${relativePath}`, encoding); @@ -629,13 +721,56 @@ export class Repository implements Disposable { }); } + checkIgnore(filePaths: string[]): Promise> { + return this.run(Operation.CheckIgnore, () => { + return new Promise>((resolve, reject) => { + + filePaths = filePaths.filter(filePath => !path.relative(this.root, filePath).startsWith('..')); + + if (filePaths.length === 0) { + // nothing left + return Promise.resolve(new Set()); + } + + const child = this.repository.stream(['check-ignore', ...filePaths]); + + const onExit = (exitCode: number) => { + if (exitCode === 1) { + // nothing ignored + resolve(new Set()); + } else if (exitCode === 0) { + // each line is something ignored + resolve(new Set(data.split('\n'))); + } else { + reject(new GitError({ stdout: data, stderr, exitCode })); + } + }; + + let data = ''; + const onStdoutData = (raw: string) => { + data += raw; + }; + + child.stdout.setEncoding('utf8'); + child.stdout.on('data', onStdoutData); + + let stderr: string = ''; + child.stderr.setEncoding('utf8'); + child.stderr.on('data', raw => stderr += raw); + + child.on('error', reject); + child.on('exit', onExit); + }); + }); + } + private async run(operation: Operation, runOperation: () => Promise = () => Promise.resolve(null)): Promise { if (this.state !== RepositoryState.Idle) { throw new Error('Repository not initialized'); } const run = async () => { - this._operations = this._operations.start(operation); + this._operations.start(operation); this._onRunOperation.fire(operation); try { @@ -653,7 +788,7 @@ export class Repository implements Disposable { throw err; } finally { - this._operations = this._operations.end(operation); + this._operations.end(operation); this._onDidRunOperation.fire(operation); } }; @@ -818,7 +953,7 @@ export class Repository implements Disposable { await timeout(5000); } - private async whenIdleAndFocused(): Promise { + async whenIdleAndFocused(): Promise { while (true) { if (!this.operations.isIdle()) { await eventToPromise(this.onDidRunOperation); @@ -835,6 +970,36 @@ export class Repository implements Disposable { } } + get headLabel(): string { + const HEAD = this.HEAD; + + if (!HEAD) { + return ''; + } + + const tag = this.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0]; + const tagName = tag && tag.name; + const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8); + + return head + + (this.workingTreeGroup.resourceStates.length > 0 ? '*' : '') + + (this.indexGroup.resourceStates.length > 0 ? '+' : '') + + (this.mergeGroup.resourceStates.length > 0 ? '!' : ''); + } + + get syncLabel(): string { + if (!this.HEAD + || !this.HEAD.name + || !this.HEAD.commit + || !this.HEAD.upstream + || !(this.HEAD.ahead || this.HEAD.behind) + ) { + return ''; + } + + return `${this.HEAD.behind}↓ ${this.HEAD.ahead}↑`; + } + dispose(): void { this.disposables = dispose(this.disposables); } diff --git a/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts index f82fda91881..4233abec580 100644 --- a/extensions/git/src/statusbar.ts +++ b/extensions/git/src/statusbar.ts @@ -6,7 +6,7 @@ 'use strict'; import { Disposable, Command, EventEmitter, Event } from 'vscode'; -import { RefType, Branch } from './git'; +import { Branch } from './git'; import { Repository, Operation } from './repository'; import { anyEvent, dispose } from './util'; import * as nls from 'vscode-nls'; @@ -24,20 +24,7 @@ class CheckoutStatusBar { } get command(): Command | undefined { - const HEAD = this.repository.HEAD; - - if (!HEAD) { - return undefined; - } - - const tag = this.repository.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0]; - const tagName = tag && tag.name; - const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8); - const title = '$(git-branch) ' - + head - + (this.repository.workingTreeGroup.resourceStates.length > 0 ? '*' : '') - + (this.repository.indexGroup.resourceStates.length > 0 ? '+' : '') - + (this.repository.mergeGroup.resourceStates.length > 0 ? '!' : ''); + const title = `$(git-branch) ${this.repository.headLabel}`; return { command: 'git.checkout', @@ -112,7 +99,7 @@ class SyncStatusBar { if (HEAD && HEAD.name && HEAD.commit) { if (HEAD.upstream) { if (HEAD.ahead || HEAD.behind) { - text += `${HEAD.behind}↓ ${HEAD.ahead}↑`; + text += this.repository.syncLabel; } command = 'git.sync'; tooltip = localize('sync changes', "Synchronize Changes"); diff --git a/extensions/git/src/test/git.test.ts b/extensions/git/src/test/git.test.ts index b42041ce80d..d8c1eb405ad 100644 --- a/extensions/git/src/test/git.test.ts +++ b/extensions/git/src/test/git.test.ts @@ -5,6 +5,7 @@ 'use strict'; +import 'mocha'; import { GitStatusParser } from '../git'; import * as assert from 'assert'; diff --git a/extensions/git/src/typings/refs.d.ts b/extensions/git/src/typings/refs.d.ts index eebe504c7ee..12e1d618942 100644 --- a/extensions/git/src/typings/refs.d.ts +++ b/extensions/git/src/typings/refs.d.ts @@ -4,6 +4,4 @@ *--------------------------------------------------------------------------------------------*/ /// -/// -/// -/// +/// \ No newline at end of file diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index 632fd5a0a86..7004ccc18e0 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -8,6 +8,7 @@ import { Event } from 'vscode'; import { dirname } from 'path'; import * as fs from 'fs'; +import * as byline from 'byline'; export function log(...args: any[]): void { console.log.apply(console, ['git:', ...args]); @@ -85,7 +86,7 @@ export function once(fn: (...args: any[]) => any): (...args: any[]) => any { export function assign(destination: T, ...sources: any[]): T { for (const source of sources) { - Object.keys(source).forEach(key => destination[key] = source[key]); + Object.keys(source).forEach(key => (destination as any)[key] = source[key]); } return destination; @@ -114,12 +115,12 @@ export function groupBy(arr: T[], fn: (el: T) => string): { [key: string]: T[ }, Object.create(null)); } -export function denodeify(fn: Function): (...args) => Promise { - return (...args) => new Promise((c, e) => fn(...args, (err, r) => err ? e(err) : c(r))); +export function denodeify(fn: Function): (...args: any[]) => Promise { + return (...args) => new Promise((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r))); } -export function nfcall(fn: Function, ...args): Promise { - return new Promise((c, e) => fn(...args, (err, r) => err ? e(err) : c(r))); +export function nfcall(fn: Function, ...args: any[]): Promise { + return new Promise((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r))); } export async function mkdirp(path: string, mode?: number): Promise { @@ -188,4 +189,20 @@ export function find(array: T[], fn: (t: T) => boolean): T | undefined { }); return result; +} + +export async function grep(filename: string, pattern: RegExp): Promise { + return new Promise((c, e) => { + const fileStream = fs.createReadStream(filename, { encoding: 'utf8' }); + const stream = byline(fileStream); + stream.on('data', (line: string) => { + if (pattern.test(line)) { + fileStream.close(); + c(true); + } + }); + + stream.on('error', e); + stream.on('end', () => c(false)); + }); } \ No newline at end of file diff --git a/extensions/git/tsconfig.json b/extensions/git/tsconfig.json index 254c9e67459..ea7679c9ac0 100644 --- a/extensions/git/tsconfig.json +++ b/extensions/git/tsconfig.json @@ -6,7 +6,10 @@ ], "module": "commonjs", "outDir": "./out", - "strictNullChecks": true, + "typeRoots": [ + "./node_modules/@types" + ], + "strict": true, "experimentalDecorators": true }, "include": [ diff --git a/extensions/gitsyntax/package.json b/extensions/gitsyntax/package.json index bc1a1810f91..0040fe55473 100644 --- a/extensions/gitsyntax/package.json +++ b/extensions/gitsyntax/package.json @@ -50,6 +50,11 @@ "scopeName": "text.git-rebase", "path": "./syntaxes/git-rebase.tmLanguage.json" } - ] + ], + "configurationDefaults": { + "[git-commit]": { + "editor.rulers": [72] + } + } } } \ No newline at end of file diff --git a/extensions/go/syntaxes/go.json b/extensions/go/syntaxes/go.json index 5adc522e0a4..4a62b05ef8c 100644 --- a/extensions/go/syntaxes/go.json +++ b/extensions/go/syntaxes/go.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/atom/language-go/commit/c413bc93966c03031cd114c53c54bc7927eea25b", + "version": "https://github.com/atom/language-go/commit/f7c6ca60bfd9d11252560b21e9378e5f82438ce3", "scopeName": "source.go", "name": "Go", "comment": "Go language", @@ -233,7 +233,7 @@ ] }, { - "match": "(?,\\s*\\w+(?:\\.\\w+)*)*)(?=\\s*=(?!=))", "captures": { "1": { "patterns": [ @@ -242,7 +242,7 @@ "name": "invalid.illegal.identifier.go" }, { - "match": "\\w+(?:\\.\\w+)?", + "match": "\\w+(?:\\.\\w+)*", "name": "variable.other.assignment.go", "captures": { "0": { @@ -627,7 +627,7 @@ } }, { - "match": "(\\w+(?:,\\s*\\w+)*)(\\s+(\\[(\\d*|\\.\\.\\.)\\])*\\*?\\w+(?:\\.\\w+)?\\s*[^=].*)", + "match": "(\\w+(?:,\\s*\\w+)*)(\\s+(\\[(\\d*|\\.\\.\\.)\\])*\\*?(<-)?\\w+(?:\\.\\w+)?\\s*[^=].*)", "captures": { "1": { "patterns": [ diff --git a/extensions/groovy/test/colorize-results/test_groovy.json b/extensions/groovy/test/colorize-results/test_groovy.json index ee78a65becc..8d1191aa367 100644 --- a/extensions/groovy/test/colorize-results/test_groovy.json +++ b/extensions/groovy/test/colorize-results/test_groovy.json @@ -9232,33 +9232,33 @@ "c": "${", "t": "source.groovy meta.definition.method.groovy meta.method.body.java string.quoted.double.groovy source.groovy.embedded.source punctuation.section.embedded.groovy", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "System.currentTimeMillis() - start", "t": "source.groovy meta.definition.method.groovy meta.method.body.java string.quoted.double.groovy source.groovy.embedded.source", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "dark_plus": "source.groovy.embedded: #D4D4D4", + "light_plus": "source.groovy.embedded: #000000", + "dark_vs": "source.groovy.embedded: #D4D4D4", + "light_vs": "source.groovy.embedded: #000000", + "hc_black": "source.groovy.embedded: #FFFFFF" } }, { "c": "}", "t": "source.groovy meta.definition.method.groovy meta.method.body.java string.quoted.double.groovy source.groovy.embedded.source punctuation.section.embedded.groovy", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index 0758d440b08..b330d18326c 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -18,7 +18,7 @@ "vscode-nls": "^2.0.2" }, "devDependencies": { - "@types/node": "^7.0.12" + "@types/node": "7.0.43" }, "main": "./out/main", "activationEvents": [ @@ -31,6 +31,7 @@ "title": "Grunt", "properties": { "grunt.autoDetect": { + "scope": "resource", "type": "string", "enum": [ "off", diff --git a/extensions/grunt/src/main.ts b/extensions/grunt/src/main.ts index 554bb4963e6..d08e845c1ba 100644 --- a/extensions/grunt/src/main.ts +++ b/extensions/grunt/src/main.ts @@ -13,49 +13,6 @@ import * as nls from 'vscode-nls'; const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); type AutoDetect = 'on' | 'off'; -let taskProvider: vscode.Disposable | undefined; - -export function activate(_context: vscode.ExtensionContext): void { - let workspaceRoot = vscode.workspace.rootPath; - if (!workspaceRoot) { - return; - } - let pattern = path.join(workspaceRoot, '[Gg]runtfile.js'); - let detectorPromise: Thenable | undefined = undefined; - let fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); - fileWatcher.onDidChange(() => detectorPromise = undefined); - fileWatcher.onDidCreate(() => detectorPromise = undefined); - fileWatcher.onDidDelete(() => detectorPromise = undefined); - - function onConfigurationChanged() { - let autoDetect = vscode.workspace.getConfiguration('grunt').get('autoDetect'); - if (taskProvider && autoDetect === 'off') { - detectorPromise = undefined; - taskProvider.dispose(); - taskProvider = undefined; - } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider('grunt', { - provideTasks: () => { - if (!detectorPromise) { - detectorPromise = getGruntTasks(); - } - return detectorPromise; - }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; - } - }); - } - } - vscode.workspace.onDidChangeConfiguration(onConfigurationChanged); - onConfigurationChanged(); -} - -export function deactivate(): void { - if (taskProvider) { - taskProvider.dispose(); - } -} function exists(file: string): Promise { return new Promise((resolve, _reject) => { @@ -76,19 +33,6 @@ function exec(command: string, options: cp.ExecOptions): Promise<{ stdout: strin }); } -let _channel: vscode.OutputChannel; -function getOutputChannel(): vscode.OutputChannel { - if (!_channel) { - _channel = vscode.window.createOutputChannel('Grunt Auto Detection'); - } - return _channel; -} - -interface GruntTaskDefinition extends vscode.TaskDefinition { - task: string; - file?: string; -} - const buildNames: string[] = ['build', 'compile', 'watch']; function isBuildTask(name: string): boolean { for (let buildName of buildNames) { @@ -109,97 +53,269 @@ function isTestTask(name: string): boolean { return false; } -async function getGruntTasks(): Promise { - let workspaceRoot = vscode.workspace.rootPath; - let emptyTasks: vscode.Task[] = []; - if (!workspaceRoot) { - return emptyTasks; +let _channel: vscode.OutputChannel; +function getOutputChannel(): vscode.OutputChannel { + if (!_channel) { + _channel = vscode.window.createOutputChannel('Gulp Auto Detection'); } - if (!await exists(path.join(workspaceRoot, 'gruntfile.js')) && !await exists(path.join(workspaceRoot, 'Gruntfile.js'))) { - return emptyTasks; + return _channel; +} + +interface GruntTaskDefinition extends vscode.TaskDefinition { + task: string; + file?: string; +} + +class FolderDetector { + + private fileWatcher: vscode.FileSystemWatcher; + private promise: Thenable | undefined; + + constructor(private _workspaceFolder: vscode.WorkspaceFolder) { } - let command: string; - let platform = process.platform; - if (platform === 'win32' && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'grunt.cmd'))) { - command = path.join('.', 'node_modules', '.bin', 'grunt.cmd'); - } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'grunt'))) { - command = path.join('.', 'node_modules', '.bin', 'grunt'); - } else { - command = 'grunt'; + public get workspaceFolder(): vscode.WorkspaceFolder { + return this._workspaceFolder; } - let commandLine = `${command} --help --no-color`; - try { - let { stdout, stderr } = await exec(commandLine, { cwd: workspaceRoot }); - if (stderr) { - getOutputChannel().appendLine(stderr); - getOutputChannel().show(true); + public isEnabled(): boolean { + return vscode.workspace.getConfiguration('grunt', this._workspaceFolder.uri).get('autoDetect') === 'on'; + } + + public start(): void { + let pattern = path.join(this._workspaceFolder.uri.fsPath, '[Gg]runtfile.js'); + this.fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); + this.fileWatcher.onDidChange(() => this.promise = undefined); + this.fileWatcher.onDidCreate(() => this.promise = undefined); + this.fileWatcher.onDidDelete(() => this.promise = undefined); + } + + public async getTasks(): Promise { + if (!this.promise) { + this.promise = this.computeTasks(); } - let result: vscode.Task[] = []; - if (stdout) { - // grunt lists tasks as follows (description is wrapped into a new line if too long): - // ... - // Available tasks - // uglify Minify files with UglifyJS. * - // jshint Validate files with JSHint. * - // test Alias for "jshint", "qunit" tasks. - // default Alias for "jshint", "qunit", "concat", "uglify" tasks. - // long Alias for "eslint", "qunit", "browserify", "sass", - // "autoprefixer", "uglify", tasks. - // - // Tasks run in the order specified + return this.promise; + } - let lines = stdout.split(/\r{0,1}\n/); - let tasksStart = false; - let tasksEnd = false; - for (let line of lines) { - if (line.length === 0) { - continue; - } - if (!tasksStart && !tasksEnd) { - if (line.indexOf('Available tasks') === 0) { - tasksStart = true; + private async computeTasks(): Promise { + let rootPath = this._workspaceFolder.uri.scheme === 'file' ? this._workspaceFolder.uri.fsPath : undefined; + let emptyTasks: vscode.Task[] = []; + if (!rootPath) { + return emptyTasks; + } + if (!await exists(path.join(rootPath, 'gruntfile.js')) && !await exists(path.join(rootPath, 'Gruntfile.js'))) { + return emptyTasks; + } + + let command: string; + let platform = process.platform; + if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'grunt.cmd'))) { + command = path.join('.', 'node_modules', '.bin', 'grunt.cmd'); + } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(rootPath!, 'node_modules', '.bin', 'grunt'))) { + command = path.join('.', 'node_modules', '.bin', 'grunt'); + } else { + command = 'grunt'; + } + + let commandLine = `${command} --help --no-color`; + try { + let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); + if (stderr) { + getOutputChannel().appendLine(stderr); + getOutputChannel().show(true); + } + let result: vscode.Task[] = []; + if (stdout) { + // grunt lists tasks as follows (description is wrapped into a new line if too long): + // ... + // Available tasks + // uglify Minify files with UglifyJS. * + // jshint Validate files with JSHint. * + // test Alias for "jshint", "qunit" tasks. + // default Alias for "jshint", "qunit", "concat", "uglify" tasks. + // long Alias for "eslint", "qunit", "browserify", "sass", + // "autoprefixer", "uglify", tasks. + // + // Tasks run in the order specified + + let lines = stdout.split(/\r{0,1}\n/); + let tasksStart = false; + let tasksEnd = false; + for (let line of lines) { + if (line.length === 0) { + continue; } - } else if (tasksStart && !tasksEnd) { - if (line.indexOf('Tasks run in the order specified') === 0) { - tasksEnd = true; - } else { - let regExp = /^\s*(\S.*\S) \S/g; - let matches = regExp.exec(line); - if (matches && matches.length === 2) { - let name = matches[1]; - let kind: GruntTaskDefinition = { - type: 'grunt', - task: name - }; - let source = 'grunt'; - let task = name.indexOf(' ') === -1 - ? new vscode.Task(kind, name, source, new vscode.ShellExecution(`${command} ${name}`)) - : new vscode.Task(kind, name, source, new vscode.ShellExecution(`${command} "${name}"`)); - result.push(task); - let lowerCaseTaskName = name.toLowerCase(); - if (isBuildTask(lowerCaseTaskName)) { - task.group = vscode.TaskGroup.Build; - } else if (isTestTask(lowerCaseTaskName)) { - task.group = vscode.TaskGroup.Test; + if (!tasksStart && !tasksEnd) { + if (line.indexOf('Available tasks') === 0) { + tasksStart = true; + } + } else if (tasksStart && !tasksEnd) { + if (line.indexOf('Tasks run in the order specified') === 0) { + tasksEnd = true; + } else { + let regExp = /^\s*(\S.*\S) \S/g; + let matches = regExp.exec(line); + if (matches && matches.length === 2) { + let name = matches[1]; + let kind: GruntTaskDefinition = { + type: 'grunt', + task: name + }; + let source = 'grunt'; + let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath }; + let task = name.indexOf(' ') === -1 + ? new vscode.Task(kind, this.workspaceFolder, name, source, new vscode.ShellExecution(`${command} ${name}`, options)) + : new vscode.Task(kind, this.workspaceFolder, name, source, new vscode.ShellExecution(`${command} "${name}"`, options)); + result.push(task); + let lowerCaseTaskName = name.toLowerCase(); + if (isBuildTask(lowerCaseTaskName)) { + task.group = vscode.TaskGroup.Build; + } else if (isTestTask(lowerCaseTaskName)) { + task.group = vscode.TaskGroup.Test; + } } } } } } + return result; + } catch (err) { + let channel = getOutputChannel(); + if (err.stderr) { + channel.appendLine(err.stderr); + } + if (err.stdout) { + channel.appendLine(err.stdout); + } + channel.appendLine(localize('execFailed', 'Auto detecting Grunt for folder {0} failed with error: {1}', this.workspaceFolder.name, err.error ? err.error.toString() : 'unknown')); + channel.show(true); + return emptyTasks; } - return result; - } catch (err) { - let channel = getOutputChannel(); - if (err.stderr) { - channel.appendLine(err.stderr); - } - if (err.stdout) { - channel.appendLine(err.stdout); - } - channel.appendLine(localize('execFailed', 'Auto detecting Grunt failed with error: {0}', err.error ? err.error.toString() : 'unknown')); - channel.show(true); - return emptyTasks; } + + public dispose() { + this.promise = undefined; + if (this.fileWatcher) { + this.fileWatcher.dispose(); + } + } +} + +class TaskDetector { + + private taskProvider: vscode.Disposable | undefined; + private detectors: Map = new Map(); + + constructor() { + } + + public start(): void { + let folders = vscode.workspace.workspaceFolders; + if (folders) { + this.updateWorkspaceFolders(folders, []); + } + vscode.workspace.onDidChangeWorkspaceFolders((event) => this.updateWorkspaceFolders(event.added, event.removed)); + vscode.workspace.onDidChangeConfiguration(this.updateConfiguration, this); + } + + public dispose(): void { + if (this.taskProvider) { + this.taskProvider.dispose(); + this.taskProvider = undefined; + } + this.detectors.clear(); + } + + private updateWorkspaceFolders(added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[]): void { + for (let remove of removed) { + let detector = this.detectors.get(remove.uri.toString()); + if (detector) { + detector.dispose(); + this.detectors.delete(remove.uri.toString()); + } + } + for (let add of added) { + let detector = new FolderDetector(add); + if (detector.isEnabled()) { + this.detectors.set(add.uri.toString(), detector); + detector.start(); + } + } + this.updateProvider(); + } + + private updateConfiguration(): void { + for (let detector of this.detectors.values()) { + if (!detector.isEnabled()) { + detector.dispose(); + this.detectors.delete(detector.workspaceFolder.uri.toString()); + } + } + let folders = vscode.workspace.workspaceFolders; + if (folders) { + for (let folder of folders) { + if (!this.detectors.has(folder.uri.toString())) { + let detector = new FolderDetector(folder); + if (detector.isEnabled()) { + this.detectors.set(folder.uri.toString(), detector); + detector.start(); + } + } + } + } + this.updateProvider(); + } + + private updateProvider(): void { + if (!this.taskProvider && this.detectors.size > 0) { + this.taskProvider = vscode.workspace.registerTaskProvider('gulp', { + provideTasks: () => { + return this.getTasks(); + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; + } + }); + } + else if (this.taskProvider && this.detectors.size === 0) { + this.taskProvider.dispose(); + this.taskProvider = undefined; + } + } + + public getTasks(): Promise { + return this.computeTasks(); + } + + private computeTasks(): Promise { + if (this.detectors.size === 0) { + return Promise.resolve([]); + } else if (this.detectors.size === 1) { + return this.detectors.values().next().value.getTasks(); + } else { + let promises: Promise[] = []; + for (let detector of this.detectors.values()) { + promises.push(detector.getTasks().then((value) => value, () => [])); + } + return Promise.all(promises).then((values) => { + let result: vscode.Task[] = []; + for (let tasks of values) { + if (tasks && tasks.length > 0) { + result.push(...tasks); + } + } + return result; + }); + } + } +} + +let detector: TaskDetector; +export function activate(_context: vscode.ExtensionContext): void { + detector = new TaskDetector(); + detector.start(); +} + +export function deactivate(): void { + detector.dispose(); } \ No newline at end of file diff --git a/extensions/grunt/tsconfig.json b/extensions/grunt/tsconfig.json index e804fa3acd7..51007d3cc84 100644 --- a/extensions/grunt/tsconfig.json +++ b/extensions/grunt/tsconfig.json @@ -6,11 +6,11 @@ "es2016" ], "outDir": "./out", - "strictNullChecks": true, "noImplicitAny": true, "noImplicitReturns": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index 235f3e2d138..00e098d9b20 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -18,7 +18,7 @@ "vscode-nls": "^2.0.2" }, "devDependencies": { - "@types/node": "^7.0.4" + "@types/node": "7.0.43" }, "main": "./out/main", "activationEvents": [ @@ -31,6 +31,7 @@ "title": "Gulp", "properties": { "gulp.autoDetect": { + "scope": "resource", "type": "string", "enum": [ "off", diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index 24d7370cf13..cde1116d3ef 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -13,49 +13,6 @@ import * as nls from 'vscode-nls'; const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); type AutoDetect = 'on' | 'off'; -let taskProvider: vscode.Disposable | undefined; - -export function activate(_context: vscode.ExtensionContext): void { - let workspaceRoot = vscode.workspace.rootPath; - if (!workspaceRoot) { - return; - } - let pattern = path.join(workspaceRoot, 'gulpfile{.babel.js,.js}'); - let gulpPromise: Thenable | undefined = undefined; - let fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); - fileWatcher.onDidChange(() => gulpPromise = undefined); - fileWatcher.onDidCreate(() => gulpPromise = undefined); - fileWatcher.onDidDelete(() => gulpPromise = undefined); - - function onConfigurationChanged() { - let autoDetect = vscode.workspace.getConfiguration('gulp').get('autoDetect'); - if (taskProvider && autoDetect === 'off') { - gulpPromise = undefined; - taskProvider.dispose(); - taskProvider = undefined; - } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider('gulp', { - provideTasks: () => { - if (!gulpPromise) { - gulpPromise = getGulpTasks(); - } - return gulpPromise; - }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; - } - }); - } - } - vscode.workspace.onDidChangeConfiguration(onConfigurationChanged); - onConfigurationChanged(); -} - -export function deactivate(): void { - if (taskProvider) { - taskProvider.dispose(); - } -} function exists(file: string): Promise { return new Promise((resolve, _reject) => { @@ -76,19 +33,6 @@ function exec(command: string, options: cp.ExecOptions): Promise<{ stdout: strin }); } -let _channel: vscode.OutputChannel; -function getOutputChannel(): vscode.OutputChannel { - if (!_channel) { - _channel = vscode.window.createOutputChannel('Gulp Auto Detection'); - } - return _channel; -} - -interface GulpTaskDefinition extends vscode.TaskDefinition { - task: string; - file?: string; -} - const buildNames: string[] = ['build', 'compile', 'watch']; function isBuildTask(name: string): boolean { for (let buildName of buildNames) { @@ -109,69 +53,241 @@ function isTestTask(name: string): boolean { return false; } -async function getGulpTasks(): Promise { - let workspaceRoot = vscode.workspace.rootPath; - let emptyTasks: vscode.Task[] = []; - if (!workspaceRoot) { - return emptyTasks; +let _channel: vscode.OutputChannel; +function getOutputChannel(): vscode.OutputChannel { + if (!_channel) { + _channel = vscode.window.createOutputChannel('Gulp Auto Detection'); } - let gulpfile = path.join(workspaceRoot, 'gulpfile.js'); - if (!await exists(gulpfile)) { - gulpfile = path.join(workspaceRoot, 'gulpfile.babel.js'); - if (! await exists(gulpfile)) { + return _channel; +} + +interface GulpTaskDefinition extends vscode.TaskDefinition { + task: string; + file?: string; +} + +class FolderDetector { + + private fileWatcher: vscode.FileSystemWatcher; + private promise: Thenable | undefined; + + constructor(private _workspaceFolder: vscode.WorkspaceFolder) { + } + + public get workspaceFolder(): vscode.WorkspaceFolder { + return this._workspaceFolder; + } + + public isEnabled(): boolean { + return vscode.workspace.getConfiguration('gulp', this._workspaceFolder.uri).get('autoDetect') === 'on'; + } + + public start(): void { + let pattern = path.join(this._workspaceFolder.uri.fsPath, 'gulpfile{.babel.js,.js}'); + this.fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); + this.fileWatcher.onDidChange(() => this.promise = undefined); + this.fileWatcher.onDidCreate(() => this.promise = undefined); + this.fileWatcher.onDidDelete(() => this.promise = undefined); + } + + public async getTasks(): Promise { + if (!this.promise) { + this.promise = this.computeTasks(); + } + return this.promise; + } + + private async computeTasks(): Promise { + let rootPath = this._workspaceFolder.uri.scheme === 'file' ? this._workspaceFolder.uri.fsPath : undefined; + let emptyTasks: vscode.Task[] = []; + if (!rootPath) { + return emptyTasks; + } + let gulpfile = path.join(rootPath, 'gulpfile.js'); + if (!await exists(gulpfile)) { + gulpfile = path.join(rootPath, 'gulpfile.babel.js'); + if (! await exists(gulpfile)) { + return emptyTasks; + } + } + + let gulpCommand: string; + let platform = process.platform; + if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp.cmd'))) { + gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp.cmd'); + } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp'))) { + gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp'); + } else { + gulpCommand = 'gulp'; + } + + let commandLine = `${gulpCommand} --tasks-simple --no-color`; + try { + let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); + if (stderr && stderr.length > 0) { + getOutputChannel().appendLine(stderr); + getOutputChannel().show(true); + } + let result: vscode.Task[] = []; + if (stdout) { + let lines = stdout.split(/\r{0,1}\n/); + for (let line of lines) { + if (line.length === 0) { + continue; + } + let kind: GulpTaskDefinition = { + type: 'gulp', + task: line + }; + let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath }; + let task = new vscode.Task(kind, this.workspaceFolder, line, 'gulp', new vscode.ShellExecution(`${gulpCommand} ${line}`, options)); + result.push(task); + let lowerCaseLine = line.toLowerCase(); + if (isBuildTask(lowerCaseLine)) { + task.group = vscode.TaskGroup.Build; + } else if (isTestTask(lowerCaseLine)) { + task.group = vscode.TaskGroup.Test; + } + } + } + return result; + } catch (err) { + let channel = getOutputChannel(); + if (err.stderr) { + channel.appendLine(err.stderr); + } + if (err.stdout) { + channel.appendLine(err.stdout); + } + channel.appendLine(localize('execFailed', 'Auto detecting gulp for folder {0} failed with error: {1}', this.workspaceFolder.name, err.error ? err.error.toString() : 'unknown')); + channel.show(true); return emptyTasks; } } - let gulpCommand: string; - let platform = process.platform; - if (platform === 'win32' && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'gulp.cmd'))) { - gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp.cmd'); - } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'gulp'))) { - gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp'); - } else { - gulpCommand = 'gulp'; + public dispose() { + this.promise = undefined; + if (this.fileWatcher) { + this.fileWatcher.dispose(); + } + } +} + +class TaskDetector { + + private taskProvider: vscode.Disposable | undefined; + private detectors: Map = new Map(); + + constructor() { } - let commandLine = `${gulpCommand} --tasks-simple --no-color`; - try { - let { stdout, stderr } = await exec(commandLine, { cwd: workspaceRoot }); - if (stderr && stderr.length > 0) { - getOutputChannel().appendLine(stderr); - getOutputChannel().show(true); + public start(): void { + let folders = vscode.workspace.workspaceFolders; + if (folders) { + this.updateWorkspaceFolders(folders, []); } - let result: vscode.Task[] = []; - if (stdout) { - let lines = stdout.split(/\r{0,1}\n/); - for (let line of lines) { - if (line.length === 0) { - continue; - } - let kind: GulpTaskDefinition = { - type: 'gulp', - task: line - }; - let task = new vscode.Task(kind, line, 'gulp', new vscode.ShellExecution(`${gulpCommand} ${line}`)); - result.push(task); - let lowerCaseLine = line.toLowerCase(); - if (isBuildTask(lowerCaseLine)) { - task.group = vscode.TaskGroup.Build; - } else if (isTestTask(lowerCaseLine)) { - task.group = vscode.TaskGroup.Test; + vscode.workspace.onDidChangeWorkspaceFolders((event) => this.updateWorkspaceFolders(event.added, event.removed)); + vscode.workspace.onDidChangeConfiguration(this.updateConfiguration, this); + } + + public dispose(): void { + if (this.taskProvider) { + this.taskProvider.dispose(); + this.taskProvider = undefined; + } + this.detectors.clear(); + } + + private updateWorkspaceFolders(added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[]): void { + for (let remove of removed) { + let detector = this.detectors.get(remove.uri.toString()); + if (detector) { + detector.dispose(); + this.detectors.delete(remove.uri.toString()); + } + } + for (let add of added) { + let detector = new FolderDetector(add); + if (detector.isEnabled()) { + this.detectors.set(add.uri.toString(), detector); + detector.start(); + } + } + this.updateProvider(); + } + + private updateConfiguration(): void { + for (let detector of this.detectors.values()) { + if (!detector.isEnabled()) { + detector.dispose(); + this.detectors.delete(detector.workspaceFolder.uri.toString()); + } + } + let folders = vscode.workspace.workspaceFolders; + if (folders) { + for (let folder of folders) { + if (!this.detectors.has(folder.uri.toString())) { + let detector = new FolderDetector(folder); + if (detector.isEnabled()) { + this.detectors.set(folder.uri.toString(), detector); + detector.start(); + } } } } - return result; - } catch (err) { - let channel = getOutputChannel(); - if (err.stderr) { - channel.appendLine(err.stderr); - } - if (err.stdout) { - channel.appendLine(err.stdout); - } - channel.appendLine(localize('execFailed', 'Auto detecting gulp failed with error: {0}', err.error ? err.error.toString() : 'unknown')); - channel.show(true); - return emptyTasks; + this.updateProvider(); } + + private updateProvider(): void { + if (!this.taskProvider && this.detectors.size > 0) { + this.taskProvider = vscode.workspace.registerTaskProvider('gulp', { + provideTasks: () => { + return this.getTasks(); + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; + } + }); + } + else if (this.taskProvider && this.detectors.size === 0) { + this.taskProvider.dispose(); + this.taskProvider = undefined; + } + } + + public getTasks(): Promise { + return this.computeTasks(); + } + + private computeTasks(): Promise { + if (this.detectors.size === 0) { + return Promise.resolve([]); + } else if (this.detectors.size === 1) { + return this.detectors.values().next().value.getTasks(); + } else { + let promises: Promise[] = []; + for (let detector of this.detectors.values()) { + promises.push(detector.getTasks().then((value) => value, () => [])); + } + return Promise.all(promises).then((values) => { + let result: vscode.Task[] = []; + for (let tasks of values) { + if (tasks && tasks.length > 0) { + result.push(...tasks); + } + } + return result; + }); + } + } +} + +let detector: TaskDetector; +export function activate(_context: vscode.ExtensionContext): void { + detector = new TaskDetector(); + detector.start(); +} + +export function deactivate(): void { + detector.dispose(); } \ No newline at end of file diff --git a/extensions/gulp/tsconfig.json b/extensions/gulp/tsconfig.json index e804fa3acd7..51007d3cc84 100644 --- a/extensions/gulp/tsconfig.json +++ b/extensions/gulp/tsconfig.json @@ -6,11 +6,11 @@ "es2016" ], "outDir": "./out", - "strictNullChecks": true, "noImplicitAny": true, "noImplicitReturns": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/html/.vscode/launch.json b/extensions/html/.vscode/launch.json index c794c543acd..753220eccdf 100644 --- a/extensions/html/.vscode/launch.json +++ b/extensions/html/.vscode/launch.json @@ -7,11 +7,11 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" + "--extensionDevelopmentPath=${workspaceFolder}" ], "stopOnEntry": false, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/client/out/**/*.js"], + "outFiles": ["${workspaceFolder}/client/out/**/*.js"], "preLaunchTask": "npm" }, { @@ -19,10 +19,10 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/client/out/test" ], + "args": ["--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/client/out/test" ], "stopOnEntry": false, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/client/out/test/**/*.js"], + "outFiles": ["${workspaceFolder}/client/out/test/**/*.js"], "preLaunchTask": "npm" }, { @@ -32,7 +32,7 @@ "port": 6004, "protocol": "legacy", "sourceMaps": true, - "outFiles": ["${workspaceRoot}/server/out/**/*.js"] + "outFiles": ["${workspaceFolder}/server/out/**/*.js"] } ] } \ No newline at end of file diff --git a/extensions/html/.vscode/tasks.json b/extensions/html/.vscode/tasks.json index a132a04214d..9e5593ade83 100644 --- a/extensions/html/.vscode/tasks.json +++ b/extensions/html/.vscode/tasks.json @@ -1,5 +1,5 @@ // Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team +// ${workspaceFolder}: the root folder of the team // ${file}: the current opened file // ${fileBasename}: the current opened file's basename // ${fileDirname}: the current opened file's dirname diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index 44138ce758a..db3d12b2f3a 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -6,14 +6,14 @@ import * as path from 'path'; -import { languages, ExtensionContext, IndentAction, Position, TextDocument, Color, ColorRange } from 'vscode'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Color, ColorInformation, ColorPresentation } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed'; -import { DocumentColorRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; +import { DocumentColorRequest, DocumentColorParams, ColorPresentationRequest, ColorPresentationParams } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -28,18 +28,6 @@ interface IPackageInfo { aiKey: string; } -const CSSColorFormats = { - Hex: '#{red:X}{green:X}{blue:X}', - RGB: { - opaque: 'rgb({red:d[0-255]}, {green:d[0-255]}, {blue:d[0-255]})', - transparent: 'rgba({red:d[0-255]}, {green:d[0-255]}, {blue:d[0-255]}, {alpha})' - }, - HSL: { - opaque: 'hsl({hue:d[0-360]}, {saturation:d[0-100]}%, {luminance:d[0-100]}%)', - transparent: 'hsla({hue:d[0-360]}, {saturation:d[0-100]}%, {luminance:d[0-100]}%, {alpha})' - } -}; - export function activate(context: ExtensionContext) { let toDispose = context.subscriptions; @@ -83,13 +71,30 @@ export function activate(context: ExtensionContext) { toDispose.push(disposable); client.onReady().then(() => { disposable = languages.registerColorProvider(documentSelector, { - provideDocumentColors(document: TextDocument): Thenable { - let params = client.code2ProtocolConverter.asDocumentSymbolParams(document); + provideDocumentColors(document: TextDocument): Thenable { + let params: DocumentColorParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) + }; return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); - let color = new Color(symbol.color.red * 255, symbol.color.green * 255, symbol.color.blue * 255, symbol.color.alpha); - return new ColorRange(range, color, [CSSColorFormats.Hex, CSSColorFormats.RGB, CSSColorFormats.HSL]); + let color = new Color(symbol.color.red, symbol.color.green, symbol.color.blue, symbol.color.alpha); + return new ColorInformation(range, color); + }); + }); + }, + provideColorPresentations(color, context): Thenable { + let params: ColorPresentationParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(context.document), + color, + range: client.code2ProtocolConverter.asRange(context.range) + }; + return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { + return presentations.map(p => { + let presentation = new ColorPresentation(p.label); + presentation.textEdit = p.textEdit && client.protocol2CodeConverter.asTextEdit(p.textEdit); + presentation.additionalTextEdits = p.additionalTextEdits && client.protocol2CodeConverter.asTextEdits(p.additionalTextEdits); + return presentation; }); }); } @@ -171,4 +176,4 @@ function getPackageInfo(context: ExtensionContext): IPackageInfo { }; } return null; -} \ No newline at end of file +} diff --git a/extensions/html/client/src/typings/color-convert.d.ts b/extensions/html/client/src/typings/color-convert.d.ts new file mode 100644 index 00000000000..a88de674d2d --- /dev/null +++ b/extensions/html/client/src/typings/color-convert.d.ts @@ -0,0 +1,11 @@ +declare module "color-convert" { + module convert { + module rgb { + function hex(r: number, g: number, b: number); + function hsl(r: number, g: number, b: number); + function hvs(r: number, g: number, b: number); + } + } + + export = convert; +} \ No newline at end of file diff --git a/extensions/html/client/tsconfig.json b/extensions/html/client/tsconfig.json index 31c07df105b..d2f8f6376fe 100644 --- a/extensions/html/client/tsconfig.json +++ b/extensions/html/client/tsconfig.json @@ -3,6 +3,7 @@ "target": "es5", "module": "commonjs", "outDir": "./out", + "noUnusedLocals": true, "lib": [ "es5", "es2015.promise" ] diff --git a/extensions/html/npm-shrinkwrap.json b/extensions/html/npm-shrinkwrap.json index f8f32b0eef7..358372962ed 100644 --- a/extensions/html/npm-shrinkwrap.json +++ b/extensions/html/npm-shrinkwrap.json @@ -13,24 +13,24 @@ "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.5.0-next.2", + "from": "vscode-jsonrpc@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz" }, "vscode-languageclient": { - "version": "3.4.0-next.17", - "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.0-next.17.tgz" + "version": "3.5.0-next.4", + "from": "vscode-languageclient@3.5.0-next.4", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0-next.4.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.5.0-next.5", + "from": "vscode-languageserver-protocol@3.5.0-next.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.5.0-next.2", + "from": "vscode-languageserver-types@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/html/package.json b/extensions/html/package.json index 3f4871ce158..da8612b9852 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -17,8 +17,8 @@ "compile": "gulp compile-extension:html-client && gulp compile-extension:html-server", "postinstall": "cd server && npm install", "update-grammar": "node ../../build/npm/update-grammar.js textmate/html.tmbundle Syntaxes/HTML.plist ./syntaxes/html.json", - "install-client-next": "npm install vscode-languageserver-types -f -S && npm install vscode-languageclient@next -f -S", - "install-client-local": "npm install ../../../vscode-languageserver-node/types -f -S && npm install ../../../vscode-languageserver-node/client -f -S" + "install-client-next": "npm install vscode-languageclient@next -f -S", + "install-client-local": "npm install ../../../vscode-languageserver-node/client -f -S" }, "contributes": { "languages": [ @@ -92,7 +92,7 @@ "null" ], "scope": "resource", - "default": "a, abbr, acronym, b, bdo, big, br, button, cite, code, dfn, em, i, img, input, kbd, label, map, object, q, samp, select, small, span, strong, sub, sup, textarea, tt, var", + "default": "wbr", "description": "%html.format.unformatted.desc%" }, "html.format.contentUnformatted": { @@ -101,7 +101,7 @@ "null" ], "scope": "resource", - "default": "pre", + "default": "pre,code,textarea", "description": "%html.format.contentUnformatted.desc%" }, "html.format.indentInnerHtml": { @@ -216,13 +216,10 @@ }, "dependencies": { "vscode-extension-telemetry": "0.0.8", - "vscode-languageclient": "3.4.0-next.17", - "vscode-languageserver-protocol": "^3.1.1", - "vscode-languageserver-types": "^3.3.0", + "vscode-languageclient": "3.5.0-next.4", "vscode-nls": "2.0.2" }, "devDependencies": { - "@types/node": "^6.0.51", - "@types/mocha": "^2.2.33" + "@types/node": "7.0.43" } } diff --git a/extensions/html/server/.vscode/launch.json b/extensions/html/server/.vscode/launch.json index a09436fd912..764c1456f17 100644 --- a/extensions/html/server/.vscode/launch.json +++ b/extensions/html/server/.vscode/launch.json @@ -8,25 +8,25 @@ "request": "attach", "port": 6004, "sourceMaps": true, - "outDir": "${workspaceRoot}/out" + "outDir": "${workspaceFolder}/out" }, { "name": "Unit Tests", "type": "node", "request": "launch", - "program": "${workspaceRoot}/../../../node_modules/mocha/bin/_mocha", + "program": "${workspaceFolder}/../../../node_modules/mocha/bin/_mocha", "stopOnEntry": false, "args": [ "--timeout", "999999", "--colors" ], - "cwd": "${workspaceRoot}", + "cwd": "${workspaceFolder}", "runtimeExecutable": null, "runtimeArgs": [], "env": {}, "sourceMaps": true, - "outDir": "${workspaceRoot}/out" + "outDir": "${workspaceFolder}/out" } ] } \ No newline at end of file diff --git a/extensions/html/server/npm-shrinkwrap.json b/extensions/html/server/npm-shrinkwrap.json index 62a5bf9b691..28596433531 100644 --- a/extensions/html/server/npm-shrinkwrap.json +++ b/extensions/html/server/npm-shrinkwrap.json @@ -3,34 +3,34 @@ "version": "1.0.0", "dependencies": { "vscode-css-languageservice": { - "version": "2.1.4", - "from": "vscode-css-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.4.tgz" + "version": "3.0.0", + "from": "vscode-css-languageservice@3.0.0", + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-3.0.0.tgz" }, "vscode-html-languageservice": { - "version": "2.0.7", - "from": "vscode-html-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.7.tgz" + "version": "2.0.10", + "from": "vscode-html-languageservice@2.0.10", + "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.10.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.5.0-next.2", + "from": "vscode-jsonrpc@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz" }, "vscode-languageserver": { - "version": "3.4.0-next.6", - "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.0-next.6.tgz" + "version": "3.5.0-next.6", + "from": "vscode-languageserver@3.5.0-next.6", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.6.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.5.0-next.5", + "from": "vscode-languageserver-protocol@3.5.0-next.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.5.0-next.2", + "from": "vscode-languageserver-types@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/html/server/package.json b/extensions/html/server/package.json index 3cac05b7da9..9c54bcba388 100644 --- a/extensions/html/server/package.json +++ b/extensions/html/server/package.json @@ -8,17 +8,15 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^2.1.4", - "vscode-html-languageservice": "^2.0.7", - "vscode-languageserver": "3.4.0-next.6", - "vscode-languageserver-protocol": "^3.1.1", - "vscode-languageserver-types": "^3.3.0", + "vscode-css-languageservice": "3.0.0", + "vscode-html-languageservice": "2.0.10", + "vscode-languageserver": "3.5.0-next.6", "vscode-nls": "^2.0.2", "vscode-uri": "^1.0.1" }, "devDependencies": { - "@types/node": "^6.0.51", - "@types/mocha": "^2.2.33" + "@types/node": "7.0.43", + "@types/mocha": "2.2.33" }, "scripts": { "compile": "gulp compile-extension:html-server", diff --git a/extensions/html/server/src/htmlServerMain.ts b/extensions/html/server/src/htmlServerMain.ts index 9b53da722a2..ff5df2a8ebd 100644 --- a/extensions/html/server/src/htmlServerMain.ts +++ b/extensions/html/server/src/htmlServerMain.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType, DocumentRangeFormattingRequest, Disposable, DocumentSelector, GetConfigurationParams, TextDocumentPositionParams, ServerCapabilities, Position } from 'vscode-languageserver'; +import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType, DocumentRangeFormattingRequest, Disposable, DocumentSelector, TextDocumentPositionParams, ServerCapabilities, Position } from 'vscode-languageserver'; import { DocumentContext } from 'vscode-html-languageservice'; import { TextDocument, Diagnostic, DocumentLink, SymbolInformation } from 'vscode-languageserver-types'; import { getLanguageModes, LanguageModes, Settings } from './modes/languageModes'; -import { GetConfigurationRequest } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; -import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorInformation } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { ConfigurationRequest, ConfigurationParams } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; +import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorInformation, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import { format } from './modes/formatting'; import { pushAll } from './utils/arrays'; @@ -54,13 +54,12 @@ documents.onDidClose(e => { }); function getDocumentSettings(textDocument: TextDocument, needsDocumentSettings: () => boolean): Thenable { - console.log('scopedSettingsSupport ' + scopedSettingsSupport + 'needsSettings ' + needsDocumentSettings()); if (scopedSettingsSupport && needsDocumentSettings()) { let promise = documentSettings[textDocument.uri]; if (!promise) { let scopeUri = textDocument.uri; - let configRequestParam: GetConfigurationParams = { items: [{ scopeUri, section: 'css' }, { scopeUri, section: 'html' }, { scopeUri, section: 'javascript' }] }; - promise = connection.sendRequest(GetConfigurationRequest.type, configRequestParam).then(s => ({ css: s[0], html: s[1], javascript: s[2] })); + let configRequestParam: ConfigurationParams = { items: [{ scopeUri, section: 'css' }, { scopeUri, section: 'html' }, { scopeUri, section: 'javascript' }] }; + promise = connection.sendRequest(ConfigurationRequest.type, configRequestParam).then(s => ({ css: s[0], html: s[1], javascript: s[2] })); documentSettings[textDocument.uri] = promise; } return promise; @@ -324,6 +323,17 @@ connection.onRequest(DocumentColorRequest.type, params => { return infos; }); +connection.onRequest(ColorPresentationRequest.type, params => { + let document = documents.get(params.textDocument.uri); + if (document) { + let mode = languageModes.getModeAtPosition(document, params.range.start); + if (mode && mode.getColorPresentations) { + return mode.getColorPresentations(document, params.color, params.range); + } + } + return []; +}); + connection.onRequest(TagCloseRequest.type, params => { let document = documents.get(params.textDocument.uri); if (document) { diff --git a/extensions/html/server/src/modes/cssMode.ts b/extensions/html/server/src/modes/cssMode.ts index dcb221e83d5..f787b9c2742 100644 --- a/extensions/html/server/src/modes/cssMode.ts +++ b/extensions/html/server/src/modes/cssMode.ts @@ -5,10 +5,11 @@ 'use strict'; import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; -import { TextDocument, Position } from 'vscode-languageserver-types'; +import { TextDocument, Position, Range } from 'vscode-languageserver-types'; import { getCSSLanguageService, Stylesheet } from 'vscode-css-languageservice'; import { LanguageMode, Settings } from './languageModes'; import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport'; +import { Color } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; export function getCSSMode(documentRegions: LanguageModelCache): LanguageMode { let cssLanguageService = getCSSLanguageService(); @@ -54,6 +55,10 @@ export function getCSSMode(documentRegions: LanguageModelCache(entry.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Text) }; }); - }; + } return null; }, findDocumentSymbols(document: TextDocument): SymbolInformation[] { @@ -286,7 +286,7 @@ export function getJavascriptMode(documentRegions: LanguageModelCache Location[]; format?: (document: TextDocument, range: Range, options: FormattingOptions, settings: Settings) => TextEdit[]; findDocumentColors?: (document: TextDocument) => ColorInformation[]; + getColorPresentations?: (document: TextDocument, color: Color, range: Range) => ColorPresentation[]; doAutoClose?: (document: TextDocument, position: Position) => string; onDocumentRemoved(document: TextDocument): void; dispose(): void; diff --git a/extensions/html/server/src/test/embedded.test.ts b/extensions/html/server/src/test/embedded.test.ts index 95050a135e5..acc3b4be0d8 100644 --- a/extensions/html/server/src/test/embedded.test.ts +++ b/extensions/html/server/src/test/embedded.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import 'mocha'; import * as assert from 'assert'; import * as embeddedSupport from '../modes/embeddedSupport'; import { TextDocument } from 'vscode-languageserver-types'; diff --git a/extensions/html/server/src/test/fixtures/expected/19813-4spaces.html b/extensions/html/server/src/test/fixtures/expected/19813-4spaces.html index d6bf8136562..0a5a4431a1a 100644 --- a/extensions/html/server/src/test/fixtures/expected/19813-4spaces.html +++ b/extensions/html/server/src/test/fixtures/expected/19813-4spaces.html @@ -13,7 +13,6 @@ } }, }); - diff --git a/extensions/html/server/src/test/fixtures/expected/19813-tab.html b/extensions/html/server/src/test/fixtures/expected/19813-tab.html index 5f0bf9e0003..6292fe9cd4e 100644 --- a/extensions/html/server/src/test/fixtures/expected/19813-tab.html +++ b/extensions/html/server/src/test/fixtures/expected/19813-tab.html @@ -13,7 +13,6 @@ } }, }); - diff --git a/extensions/html/server/src/test/fixtures/expected/19813.html b/extensions/html/server/src/test/fixtures/expected/19813.html index 296e4ba3e96..aac7580ac1e 100644 --- a/extensions/html/server/src/test/fixtures/expected/19813.html +++ b/extensions/html/server/src/test/fixtures/expected/19813.html @@ -13,7 +13,6 @@ } }, }); - diff --git a/extensions/html/server/src/test/fixtures/expected/21634.html b/extensions/html/server/src/test/fixtures/expected/21634.html index 189aab98163..8398821a6ae 100644 --- a/extensions/html/server/src/test/fixtures/expected/21634.html +++ b/extensions/html/server/src/test/fixtures/expected/21634.html @@ -3,5 +3,4 @@ \ No newline at end of file diff --git a/extensions/html/server/src/test/formatting.test.ts b/extensions/html/server/src/test/formatting.test.ts index 713d2943ed4..ad8918274b6 100644 --- a/extensions/html/server/src/test/formatting.test.ts +++ b/extensions/html/server/src/test/formatting.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import 'mocha'; import * as path from 'path'; import * as fs from 'fs'; @@ -58,12 +59,11 @@ suite('HTML Embedded Formatting', () => { test('HTML & Scripts', function (): any { assertFormat('', '\n\n\n \n\n\n'); - assertFormat('', '\n\n\n \n\n\n'); - assertFormat('', '\n\n\n \n\n\n'); - assertFormat('\n ', '\n\n\n \n\n\n'); - assertFormat('\n ', '\n\n\n \n\n\n'); - - assertFormat('\n ||', '\n '); + assertFormat('', '\n\n\n \n\n\n'); + assertFormat('', '\n\n\n \n\n\n'); + assertFormat('\n ', '\n\n\n \n\n\n'); + assertFormat('\n ', '\n\n\n \n\n\n'); + assertFormat('\n ||', '\n '); }); test('HTLM & Scripts - Fixtures', function () { @@ -74,11 +74,11 @@ suite('HTML Embedded Formatting', () => { }); test('Script end tag', function (): any { - assertFormat('\n\n ', '\n\n\n \n\n\n'); + assertFormat('\n\n ', '\n\n\n \n\n\n'); }); test('HTML & Multiple Scripts', function (): any { - assertFormat('\n', '\n\n\n \n \n\n\n'); + assertFormat('\n', '\n\n\n \n \n\n\n'); }); test('HTML & Styles', function (): any { @@ -95,7 +95,7 @@ suite('HTML Embedded Formatting', () => { }; assertFormat('

Hello

', '\n\n\n

Hello

\n\n\n\n', options); assertFormat('|

Hello

|', '\n

Hello

\n', options); - assertFormat('', '\n\n\n \n\n\n\n', options); + assertFormat('', '\n\n\n \n\n\n\n', options); }); test('Inside script', function (): any { @@ -104,7 +104,7 @@ suite('HTML Embedded Formatting', () => { }); test('Range after new line', function (): any { - assertFormat('\n |\n|', '\n \n'); + assertFormat('\n |\n|', '\n \n'); }); }); diff --git a/extensions/html/server/src/test/javascriptMode.test.ts b/extensions/html/server/src/test/javascriptMode.test.ts index c5d44e88cae..c775c19b0b9 100644 --- a/extensions/html/server/src/test/javascriptMode.test.ts +++ b/extensions/html/server/src/test/javascriptMode.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import 'mocha'; import * as assert from 'assert'; import { getJavascriptMode } from '../modes/javascriptMode'; import { TextDocument } from 'vscode-languageserver-types'; diff --git a/extensions/html/server/src/test/ref.d.ts b/extensions/html/server/src/test/ref.d.ts deleted file mode 100644 index 4e54d6a8a24..00000000000 --- a/extensions/html/server/src/test/ref.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// \ No newline at end of file diff --git a/extensions/html/server/src/utils/edits.ts b/extensions/html/server/src/utils/edits.ts index 5983d9014fb..f29dd174f67 100644 --- a/extensions/html/server/src/utils/edits.ts +++ b/extensions/html/server/src/utils/edits.ts @@ -15,6 +15,7 @@ export function applyEdits(document: TextDocument, edits: TextEdit[]): string { } return startDiff; }); + // @ts-ignore unused local let lastOffset = text.length; sortedEdits.forEach(e => { let startOffset = document.offsetAt(e.range.start); diff --git a/extensions/html/server/tsconfig.json b/extensions/html/server/tsconfig.json index 31c07df105b..d2f8f6376fe 100644 --- a/extensions/html/server/tsconfig.json +++ b/extensions/html/server/tsconfig.json @@ -3,6 +3,7 @@ "target": "es5", "module": "commonjs", "outDir": "./out", + "noUnusedLocals": true, "lib": [ "es5", "es2015.promise" ] diff --git a/extensions/html/snippet/html.json b/extensions/html/snippet/html.json index a7f9c9cb1ab..f999d151752 100644 --- a/extensions/html/snippet/html.json +++ b/extensions/html/snippet/html.json @@ -5,15 +5,15 @@ "", "", "", - " ", - " ", - " {{Page Title}}", - " ", - " ", - " ", + "\t", + "\t", + "\t{{Page Title}}", + "\t", + "\t", + "\t", "", "", - " {{}}", + "\t{{}}", "", "" ], diff --git a/extensions/html/test/colorize-results/12750_html.json b/extensions/html/test/colorize-results/12750_html.json index 88c372b5581..a89b03aa84f 100644 --- a/extensions/html/test/colorize-results/12750_html.json +++ b/extensions/html/test/colorize-results/12750_html.json @@ -25,11 +25,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -47,11 +47,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -102,11 +102,11 @@ "c": "\t", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -115,8 +115,8 @@ "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.variable: #9CDCFE" } }, @@ -124,11 +124,11 @@ "c": ".", "t": "text.html.basic meta.embedded.block.html source.js meta.function-call.js punctuation.accessor.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -137,8 +137,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -146,11 +146,11 @@ "c": "(", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -190,22 +190,22 @@ "c": ")", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.basic meta.embedded.block.html source.js punctuation.terminator.statement.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -289,11 +289,11 @@ "c": "\t", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -302,8 +302,8 @@ "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.variable: #9CDCFE" } }, @@ -311,11 +311,11 @@ "c": ".", "t": "text.html.basic meta.embedded.block.html source.js meta.function-call.js punctuation.accessor.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -324,8 +324,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -333,11 +333,11 @@ "c": "(", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -377,22 +377,22 @@ "c": ")", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.basic meta.embedded.block.html source.js punctuation.terminator.statement.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { diff --git a/extensions/html/test/colorize-results/25920_html.json b/extensions/html/test/colorize-results/25920_html.json index 697937acdbd..16b71acbe88 100644 --- a/extensions/html/test/colorize-results/25920_html.json +++ b/extensions/html/test/colorize-results/25920_html.json @@ -58,11 +58,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -80,11 +80,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -135,11 +135,11 @@ "c": "\t", "t": "text.html.basic meta.embedded.block.html text.html.basic", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -168,11 +168,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html text.html.basic meta.tag.any.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -190,11 +190,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html text.html.basic meta.tag.any.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -355,11 +355,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -377,11 +377,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -432,11 +432,11 @@ "c": "\t", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -454,11 +454,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.var.expr.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -467,8 +467,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -476,11 +476,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.var.expr.js meta.var-single-variable.expr.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -498,11 +498,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.var.expr.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -520,11 +520,11 @@ "c": ";", "t": "text.html.basic meta.embedded.block.html source.js punctuation.terminator.statement.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -597,11 +597,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -619,11 +619,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -674,11 +674,11 @@ "c": "\t", "t": "text.html.basic meta.embedded.block.html text.html.basic", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -707,11 +707,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html text.html.basic meta.tag.any.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -729,11 +729,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html text.html.basic meta.tag.any.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { diff --git a/extensions/html/test/colorize-results/test_html.json b/extensions/html/test/colorize-results/test_html.json index 987bfae286c..a1da5d2c393 100644 --- a/extensions/html/test/colorize-results/test_html.json +++ b/extensions/html/test/colorize-results/test_html.json @@ -476,11 +476,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.style.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -498,11 +498,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.style.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -553,11 +553,11 @@ "c": "\t\t", "t": "text.html.basic meta.embedded.block.html source.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -575,33 +575,33 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -619,22 +619,22 @@ "c": ":", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css punctuation.separator.key-value.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -643,7 +643,7 @@ "r": { "dark_plus": "support.constant.color: #CE9178", "light_plus": "support.constant.color: #0451A5", - "dark_vs": "default: #D4D4D4", + "dark_vs": "meta.embedded: #D4D4D4", "light_vs": "support.constant.color: #0451A5", "hc_black": "support.constant.color: #CE9178" } @@ -652,22 +652,22 @@ "c": ";", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css punctuation.terminator.rule.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -685,22 +685,22 @@ "c": ":", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css punctuation.separator.key-value.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -709,7 +709,7 @@ "r": { "dark_plus": "constant.other.color.rgb-value: #CE9178", "light_plus": "constant.other.color.rgb-value: #0451A5", - "dark_vs": "default: #D4D4D4", + "dark_vs": "meta.embedded: #D4D4D4", "light_vs": "constant.other.color.rgb-value: #0451A5", "hc_black": "constant.other.color.rgb-value: #CE9178" } @@ -720,7 +720,7 @@ "r": { "dark_plus": "constant.other.color.rgb-value: #CE9178", "light_plus": "constant.other.color.rgb-value: #0451A5", - "dark_vs": "default: #D4D4D4", + "dark_vs": "meta.embedded: #D4D4D4", "light_vs": "constant.other.color.rgb-value: #0451A5", "hc_black": "constant.other.color.rgb-value: #CE9178" } @@ -729,44 +729,44 @@ "c": ";", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css punctuation.terminator.rule.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.basic meta.embedded.block.html source.css meta.property-list.css punctuation.section.property-list.end.bracket.curly.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.basic meta.embedded.block.html source.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1125,11 +1125,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1147,11 +1147,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1279,11 +1279,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1301,11 +1301,11 @@ "c": "=", "t": "text.html.basic meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1444,11 +1444,11 @@ "c": "\t\t", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1457,8 +1457,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1466,11 +1466,11 @@ "c": ".", "t": "text.html.basic meta.embedded.block.html source.js meta.function-call.js punctuation.accessor.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1479,8 +1479,8 @@ "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "entity.name.function: #DCDCAA" } }, @@ -1488,11 +1488,11 @@ "c": "(", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1532,33 +1532,33 @@ "c": ")", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.basic meta.embedded.block.html source.js punctuation.terminator.statement.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1567,8 +1567,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1576,11 +1576,11 @@ "c": ".", "t": "text.html.basic meta.embedded.block.html source.js meta.function-call.js punctuation.accessor.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1589,8 +1589,8 @@ "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "entity.name.function: #DCDCAA" } }, @@ -1598,33 +1598,33 @@ "c": "(", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1633,8 +1633,8 @@ "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "meta.object-literal.key: #9CDCFE" } }, @@ -1644,8 +1644,8 @@ "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "meta.object-literal.key: #9CDCFE" } }, @@ -1653,11 +1653,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1697,22 +1697,22 @@ "c": ",", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js punctuation.separator.comma.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1721,8 +1721,8 @@ "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "meta.object-literal.key: #9CDCFE" } }, @@ -1732,8 +1732,8 @@ "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "meta.object-literal.key: #9CDCFE" } }, @@ -1741,33 +1741,33 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js meta.objectliteral.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t\t", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js meta.objectliteral.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1776,8 +1776,8 @@ "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "meta.object-literal.key: #9CDCFE" } }, @@ -1787,8 +1787,8 @@ "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "meta.object-literal.key: #9CDCFE" } }, @@ -1796,11 +1796,11 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js meta.objectliteral.js meta.object.member.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1840,77 +1840,77 @@ "c": "\t\t\t", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js meta.objectliteral.js meta.object.member.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js meta.objectliteral.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.basic meta.embedded.block.html source.js punctuation.terminator.statement.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1919,8 +1919,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -1928,33 +1928,33 @@ "c": "(", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{ ", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1963,8 +1963,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1972,55 +1972,55 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js meta.object.member.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.basic meta.embedded.block.html source.js meta.objectliteral.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ",", "t": "text.html.basic meta.embedded.block.html source.js punctuation.separator.comma.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2038,66 +2038,66 @@ "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "(", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.end.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.block.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2106,8 +2106,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2115,11 +2115,11 @@ "c": ".", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.block.js meta.function-call.js punctuation.accessor.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2128,8 +2128,8 @@ "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "entity.name.function: #DCDCAA" } }, @@ -2137,77 +2137,77 @@ "c": "()", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.block.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.block.js punctuation.terminator.statement.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.basic meta.embedded.block.html source.js meta.function.expression.js meta.block.js punctuation.definition.block.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.basic meta.embedded.block.html source.js meta.brace.round.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.basic meta.embedded.block.html source.js punctuation.terminator.statement.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.basic meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { diff --git a/extensions/jake/package.json b/extensions/jake/package.json index 9e48dd07c43..58ba0168e4a 100644 --- a/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -18,7 +18,7 @@ "vscode-nls": "^2.0.2" }, "devDependencies": { - "@types/node": "^7.0.18" + "@types/node": "7.0.43" }, "main": "./out/main", "activationEvents": [ @@ -31,6 +31,7 @@ "title": "Jake", "properties": { "jake.autoDetect": { + "scope": "resource", "type": "string", "enum": [ "off", diff --git a/extensions/jake/src/main.ts b/extensions/jake/src/main.ts index b0b4b137ab9..0a2032c970c 100644 --- a/extensions/jake/src/main.ts +++ b/extensions/jake/src/main.ts @@ -13,49 +13,6 @@ import * as nls from 'vscode-nls'; const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); type AutoDetect = 'on' | 'off'; -let taskProvider: vscode.Disposable | undefined; - -export function activate(_context: vscode.ExtensionContext): void { - let workspaceRoot = vscode.workspace.rootPath; - if (!workspaceRoot) { - return; - } - let pattern = path.join(workspaceRoot, '{Jakefile,Jakefile.js}'); - let jakePromise: Thenable | undefined = undefined; - let fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); - fileWatcher.onDidChange(() => jakePromise = undefined); - fileWatcher.onDidCreate(() => jakePromise = undefined); - fileWatcher.onDidDelete(() => jakePromise = undefined); - - function onConfigurationChanged() { - let autoDetect = vscode.workspace.getConfiguration('jake').get('autoDetect'); - if (taskProvider && autoDetect === 'off') { - jakePromise = undefined; - taskProvider.dispose(); - taskProvider = undefined; - } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider('jake', { - provideTasks: () => { - if (!jakePromise) { - jakePromise = getJakeTasks(); - } - return jakePromise; - }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; - } - }); - } - } - vscode.workspace.onDidChangeConfiguration(onConfigurationChanged); - onConfigurationChanged(); -} - -export function deactivate(): void { - if (taskProvider) { - taskProvider.dispose(); - } -} function exists(file: string): Promise { return new Promise((resolve, _reject) => { @@ -76,19 +33,6 @@ function exec(command: string, options: cp.ExecOptions): Promise<{ stdout: strin }); } -let _channel: vscode.OutputChannel; -function getOutputChannel(): vscode.OutputChannel { - if (!_channel) { - _channel = vscode.window.createOutputChannel('Jake Auto Detection'); - } - return _channel; -} - -interface JakeTaskDefinition extends vscode.TaskDefinition { - task: string; - file?: string; -} - const buildNames: string[] = ['build', 'compile', 'watch']; function isBuildTask(name: string): boolean { for (let buildName of buildNames) { @@ -109,74 +53,246 @@ function isTestTask(name: string): boolean { return false; } -async function getJakeTasks(): Promise { - let workspaceRoot = vscode.workspace.rootPath; - let emptyTasks: vscode.Task[] = []; - if (!workspaceRoot) { - return emptyTasks; +let _channel: vscode.OutputChannel; +function getOutputChannel(): vscode.OutputChannel { + if (!_channel) { + _channel = vscode.window.createOutputChannel('Jake Auto Detection'); } - let jakefile = path.join(workspaceRoot, 'Jakefile'); - if (!await exists(jakefile)) { - jakefile = path.join(workspaceRoot, 'Jakefile.js'); - if (! await exists(jakefile)) { + return _channel; +} + +interface JakeTaskDefinition extends vscode.TaskDefinition { + task: string; + file?: string; +} + +class FolderDetector { + + private fileWatcher: vscode.FileSystemWatcher; + private promise: Thenable | undefined; + + constructor(private _workspaceFolder: vscode.WorkspaceFolder) { + } + + public get workspaceFolder(): vscode.WorkspaceFolder { + return this._workspaceFolder; + } + + public isEnabled(): boolean { + return vscode.workspace.getConfiguration('jake', this._workspaceFolder.uri).get('autoDetect') === 'on'; + } + + public start(): void { + let pattern = path.join(this._workspaceFolder.uri.fsPath, '{Jakefile,Jakefile.js}'); + this.fileWatcher = vscode.workspace.createFileSystemWatcher(pattern); + this.fileWatcher.onDidChange(() => this.promise = undefined); + this.fileWatcher.onDidCreate(() => this.promise = undefined); + this.fileWatcher.onDidDelete(() => this.promise = undefined); + } + + public async getTasks(): Promise { + if (!this.promise) { + this.promise = this.computeTasks(); + } + return this.promise; + } + + private async computeTasks(): Promise { + let rootPath = this._workspaceFolder.uri.scheme === 'file' ? this._workspaceFolder.uri.fsPath : undefined; + let emptyTasks: vscode.Task[] = []; + if (!rootPath) { + return emptyTasks; + } + let jakefile = path.join(rootPath, 'Jakefile'); + if (!await exists(jakefile)) { + jakefile = path.join(rootPath, 'Jakefile.js'); + if (! await exists(jakefile)) { + return emptyTasks; + } + } + + let jakeCommand: string; + let platform = process.platform; + if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'jake.cmd'))) { + jakeCommand = path.join('.', 'node_modules', '.bin', 'jake.cmd'); + } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(rootPath!, 'node_modules', '.bin', 'jake'))) { + jakeCommand = path.join('.', 'node_modules', '.bin', 'jake'); + } else { + jakeCommand = 'jake'; + } + + let commandLine = `${jakeCommand} --tasks`; + try { + let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); + if (stderr) { + getOutputChannel().appendLine(stderr); + getOutputChannel().show(true); + } + let result: vscode.Task[] = []; + if (stdout) { + let lines = stdout.split(/\r{0,1}\n/); + for (let line of lines) { + if (line.length === 0) { + continue; + } + let regExp = /^jake\s+([^\s]+)\s/g; + let matches = regExp.exec(line); + if (matches && matches.length === 2) { + let taskName = matches[1]; + let kind: JakeTaskDefinition = { + type: 'jake', + task: taskName + }; + let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath }; + let task = new vscode.Task(kind, taskName, 'jake', new vscode.ShellExecution(`${jakeCommand} ${taskName}`, options)); + result.push(task); + let lowerCaseLine = line.toLowerCase(); + if (isBuildTask(lowerCaseLine)) { + task.group = vscode.TaskGroup.Build; + } else if (isTestTask(lowerCaseLine)) { + task.group = vscode.TaskGroup.Test; + } + } + } + } + return result; + } catch (err) { + let channel = getOutputChannel(); + if (err.stderr) { + channel.appendLine(err.stderr); + } + if (err.stdout) { + channel.appendLine(err.stdout); + } + channel.appendLine(localize('execFailed', 'Auto detecting Jake for folder {0} failed with error: {1}', this.workspaceFolder.name, err.error ? err.error.toString() : 'unknown')); + channel.show(true); return emptyTasks; } } - let jakeCommand: string; - let platform = process.platform; - if (platform === 'win32' && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'jake.cmd'))) { - jakeCommand = path.join('.', 'node_modules', '.bin', 'jake.cmd'); - } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'jake'))) { - jakeCommand = path.join('.', 'node_modules', '.bin', 'jake'); - } else { - jakeCommand = 'jake'; + public dispose() { + this.promise = undefined; + if (this.fileWatcher) { + this.fileWatcher.dispose(); + } + } +} + +class TaskDetector { + + private taskProvider: vscode.Disposable | undefined; + private detectors: Map = new Map(); + + constructor() { } - let commandLine = `${jakeCommand} --tasks`; - try { - let { stdout, stderr } = await exec(commandLine, { cwd: workspaceRoot }); - if (stderr) { - getOutputChannel().appendLine(stderr); - getOutputChannel().show(true); + public start(): void { + let folders = vscode.workspace.workspaceFolders; + if (folders) { + this.updateWorkspaceFolders(folders, []); } - let result: vscode.Task[] = []; - if (stdout) { - let lines = stdout.split(/\r{0,1}\n/); - for (let line of lines) { - if (line.length === 0) { - continue; - } - let regExp = /^jake\s+([^\s]+)\s/g; - let matches = regExp.exec(line); - if (matches && matches.length === 2) { - let taskName = matches[1]; - let kind: JakeTaskDefinition = { - type: 'jake', - task: taskName - }; - let task = new vscode.Task(kind, taskName, 'jake', new vscode.ShellExecution(`${jakeCommand} ${taskName}`)); - result.push(task); - let lowerCaseLine = line.toLowerCase(); - if (isBuildTask(lowerCaseLine)) { - task.group = vscode.TaskGroup.Build; - } else if (isTestTask(lowerCaseLine)) { - task.group = vscode.TaskGroup.Test; + vscode.workspace.onDidChangeWorkspaceFolders((event) => this.updateWorkspaceFolders(event.added, event.removed)); + vscode.workspace.onDidChangeConfiguration(this.updateConfiguration, this); + } + + public dispose(): void { + if (this.taskProvider) { + this.taskProvider.dispose(); + this.taskProvider = undefined; + } + this.detectors.clear(); + } + + private updateWorkspaceFolders(added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[]): void { + for (let remove of removed) { + let detector = this.detectors.get(remove.uri.toString()); + if (detector) { + detector.dispose(); + this.detectors.delete(remove.uri.toString()); + } + } + for (let add of added) { + let detector = new FolderDetector(add); + if (detector.isEnabled()) { + this.detectors.set(add.uri.toString(), detector); + detector.start(); + } + } + this.updateProvider(); + } + + private updateConfiguration(): void { + for (let detector of this.detectors.values()) { + if (!detector.isEnabled()) { + detector.dispose(); + this.detectors.delete(detector.workspaceFolder.uri.toString()); + } + } + let folders = vscode.workspace.workspaceFolders; + if (folders) { + for (let folder of folders) { + if (!this.detectors.has(folder.uri.toString())) { + let detector = new FolderDetector(folder); + if (detector.isEnabled()) { + this.detectors.set(folder.uri.toString(), detector); + detector.start(); } } } } - return result; - } catch (err) { - let channel = getOutputChannel(); - if (err.stderr) { - channel.appendLine(err.stderr); - } - if (err.stdout) { - channel.appendLine(err.stdout); - } - channel.appendLine(localize('execFailed', 'Auto detecting Jake failed with error: {0}', err.error ? err.error.toString() : 'unknown')); - channel.show(true); - return emptyTasks; + this.updateProvider(); } + + private updateProvider(): void { + if (!this.taskProvider && this.detectors.size > 0) { + this.taskProvider = vscode.workspace.registerTaskProvider('gulp', { + provideTasks: () => { + return this.getTasks(); + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; + } + }); + } + else if (this.taskProvider && this.detectors.size === 0) { + this.taskProvider.dispose(); + this.taskProvider = undefined; + } + } + + public getTasks(): Promise { + return this.computeTasks(); + } + + private computeTasks(): Promise { + if (this.detectors.size === 0) { + return Promise.resolve([]); + } else if (this.detectors.size === 1) { + return this.detectors.values().next().value.getTasks(); + } else { + let promises: Promise[] = []; + for (let detector of this.detectors.values()) { + promises.push(detector.getTasks().then((value) => value, () => [])); + } + return Promise.all(promises).then((values) => { + let result: vscode.Task[] = []; + for (let tasks of values) { + if (tasks && tasks.length > 0) { + result.push(...tasks); + } + } + return result; + }); + } + } +} + +let detector: TaskDetector; +export function activate(_context: vscode.ExtensionContext): void { + detector = new TaskDetector(); + detector.start(); +} + +export function deactivate(): void { + detector.dispose(); } \ No newline at end of file diff --git a/extensions/jake/tsconfig.json b/extensions/jake/tsconfig.json index e804fa3acd7..51007d3cc84 100644 --- a/extensions/jake/tsconfig.json +++ b/extensions/jake/tsconfig.json @@ -6,11 +6,11 @@ "es2016" ], "outDir": "./out", - "strictNullChecks": true, "noImplicitAny": true, "noImplicitReturns": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/java/language-configuration.json b/extensions/java/language-configuration.json index 5ae0cec3192..cc45a8a0139 100644 --- a/extensions/java/language-configuration.json +++ b/extensions/java/language-configuration.json @@ -23,5 +23,11 @@ ["\"", "\""], ["'", "'"], ["<", ">"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*//\\s*(#?region\\b)|()" + } + } } diff --git a/extensions/java/syntaxes/java.tmLanguage.json b/extensions/java/syntaxes/java.tmLanguage.json index 28495a497cc..abc5ee65bb1 100644 --- a/extensions/java/syntaxes/java.tmLanguage.json +++ b/extensions/java/syntaxes/java.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/atom/language-java/commit/4eb3d906f572ef1999b7ebf0708c841d36b32f0b", + "version": "https://github.com/atom/language-java/commit/26b83893bf071f291481c924051462e17d2f77cd", "scopeName": "source.java", "name": "Java", "fileTypes": [ @@ -121,18 +121,21 @@ "annotations": { "patterns": [ { - "begin": "(@[^ (]+)(\\()", + "begin": "((@)[^\\s(]+)(\\()", "beginCaptures": { "1": { "name": "storage.type.annotation.java" }, "2": { + "name": "punctuation.definition.annotation.java" + }, + "3": { "name": "punctuation.definition.annotation-arguments.begin.bracket.round.java" } }, - "end": "(\\))", + "end": "\\)", "endCaptures": { - "1": { + "0": { "name": "punctuation.definition.annotation-arguments.end.bracket.round.java" } }, @@ -155,8 +158,25 @@ ] }, { - "match": "@\\w*", - "name": "storage.type.annotation.java" + "match": "(@)(interface)\\s+(\\w*)|((@)\\w*)", + "name": "meta.declaration.annotation.java", + "captures": { + "1": { + "name": "punctuation.definition.annotation.java" + }, + "2": { + "name": "storage.modifier.java" + }, + "3": { + "name": "storage.type.annotation.java" + }, + "4": { + "name": "storage.type.annotation.java" + }, + "5": { + "name": "punctuation.definition.annotation.java" + } + } } ] }, @@ -224,7 +244,7 @@ ] }, "class": { - "begin": "(?=\\w?[\\w\\s]*(?:class|(?:@)?interface|enum)\\s+\\w+)", + "begin": "(?=\\w?[\\w\\s]*(?:class|(?(\\w+\\.)*[A-Z]+\\w*) # e.g. `javax.ws.rs.Response`, or `String`\n )\n (\n <[\\w<>,?\\s]*> # HashMap\n |\n (\\[\\])* # int[][]\n )?\n \\s+\n [A-Za-z_$][\\w$]* # At least one identifier after space\n ([\\w\\[\\],$][\\w\\[\\],\\s]*)? # possibly primitive array or additional identifiers\n \\s*(=|;)\n)", + "begin": "(?x)\n(?=\n (\n (void|boolean|byte|char|short|int|float|long|double)\n |\n (?>(\\w+\\.)*[A-Z]+\\w*) # e.g. `javax.ws.rs.Response`, or `String`\n )\n (\n <[\\w<>,?\\s]*> # HashMap\n )?\n (\n (\\[\\])* # int[][]\n )?\n \\s+\n [A-Za-z_$][\\w$]* # At least one identifier after space\n ([\\w\\[\\],$][\\w\\[\\],\\s]*)? # possibly primitive array or additional identifiers\n \\s*(=|;)\n)", "end": "(?=;)", "name": "meta.definition.variable.java", "patterns": [ diff --git a/extensions/java/test/colorize-results/basic_java.json b/extensions/java/test/colorize-results/basic_java.json index 0622a9209cc..1ef3a8ff324 100644 --- a/extensions/java/test/colorize-results/basic_java.json +++ b/extensions/java/test/colorize-results/basic_java.json @@ -1056,7 +1056,18 @@ } }, { - "c": "@SuppressWarnings", + "c": "@", + "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java punctuation.definition.annotation.java", + "r": { + "dark_plus": "storage.type.annotation.java: #4EC9B0", + "light_plus": "storage.type.annotation.java: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.annotation.java: #4EC9B0" + } + }, + { + "c": "SuppressWarnings", "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java", "r": { "dark_plus": "storage.type.annotation.java: #4EC9B0", @@ -1848,8 +1859,19 @@ } }, { - "c": "@Test", - "t": "source.java meta.class.java meta.class.body.java storage.type.annotation.java", + "c": "@", + "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java punctuation.definition.annotation.java", + "r": { + "dark_plus": "storage.type.annotation.java: #4EC9B0", + "light_plus": "storage.type.annotation.java: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.annotation.java: #4EC9B0" + } + }, + { + "c": "Test", + "t": "source.java meta.class.java meta.class.body.java meta.declaration.annotation.java storage.type.annotation.java", "r": { "dark_plus": "storage.type.annotation.java: #4EC9B0", "light_plus": "storage.type.annotation.java: #267F99", diff --git a/extensions/javascript/.vscode/launch.json b/extensions/javascript/.vscode/launch.json index 2bfe2a16420..da4bc0f01e1 100644 --- a/extensions/javascript/.vscode/launch.json +++ b/extensions/javascript/.vscode/launch.json @@ -7,11 +7,11 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" + "--extensionDevelopmentPath=${workspaceFolder}" ], "stopOnEntry": false, "sourceMaps": true, - "outDir": "${workspaceRoot}/out", + "outDir": "${workspaceFolder}/out", "preLaunchTask": "npm" }, { @@ -19,10 +19,10 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], + "args": ["--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out/test" ], "stopOnEntry": false, "sourceMaps": true, - "outDir": "${workspaceRoot}/out/test", + "outDir": "${workspaceFolder}/out/test", "preLaunchTask": "npm" } ] diff --git a/extensions/javascript/.vscode/tasks.json b/extensions/javascript/.vscode/tasks.json index a132a04214d..9e5593ade83 100644 --- a/extensions/javascript/.vscode/tasks.json +++ b/extensions/javascript/.vscode/tasks.json @@ -1,5 +1,5 @@ // Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team +// ${workspaceFolder}: the root folder of the team // ${file}: the current opened file // ${fileBasename}: the current opened file's basename // ${fileDirname}: the current opened file's dirname diff --git a/extensions/javascript/OSSREADME.json b/extensions/javascript/OSSREADME.json index 89a7912b239..ad083ab8743 100644 --- a/extensions/javascript/OSSREADME.json +++ b/extensions/javascript/OSSREADME.json @@ -3,190 +3,9 @@ [{ "name": "Microsoft/TypeScript-TmLanguage", "version": "0.0.1", - "license": "Apache2", + "license": "MIT", "repositoryURL": "https://github.com/Microsoft/TypeScript-TmLanguage", - "description": "The file syntaxes/JavaScript.tmLanguage.json was derived from TypeScriptReact.tmLanguage in https://github.com/Microsoft/TypeScript-TmLanguage.", - "licenseDetail": [ - // Reason: LICENSE file does not include Copyright statement - "Copyright (c) Microsoft Corporation. All rights reserved.", - "", - " Apache License", - " Version 2.0, January 2004", - " http://www.apache.org/licenses/", - "", - " TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION", - "", - " 1. Definitions.", - "", - " \"License\" shall mean the terms and conditions for use, reproduction,", - " and distribution as defined by Sections 1 through 9 of this document.", - "", - " \"Licensor\" shall mean the copyright owner or entity authorized by", - " the copyright owner that is granting the License.", - "", - " \"Legal Entity\" shall mean the union of the acting entity and all", - " other entities that control, are controlled by, or are under common", - " control with that entity. For the purposes of this definition,", - " \"control\" means (i) the power, direct or indirect, to cause the", - " direction or management of such entity, whether by contract or", - " otherwise, or (ii) ownership of fifty percent (50%) or more of the", - " outstanding shares, or (iii) beneficial ownership of such entity.", - "", - " \"You\" (or \"Your\") shall mean an individual or Legal Entity", - " exercising permissions granted by this License.", - "", - " \"Source\" form shall mean the preferred form for making modifications,", - " including but not limited to software source code, documentation", - " source, and configuration files.", - "", - " \"Object\" form shall mean any form resulting from mechanical", - " transformation or translation of a Source form, including but", - " not limited to compiled object code, generated documentation,", - " and conversions to other media types.", - "", - " \"Work\" shall mean the work of authorship, whether in Source or", - " Object form, made available under the License, as indicated by a", - " copyright notice that is included in or attached to the work", - " (an example is provided in the Appendix below).", - "", - " \"Derivative Works\" shall mean any work, whether in Source or Object", - " form, that is based on (or derived from) the Work and for which the", - " editorial revisions, annotations, elaborations, or other modifications", - " represent, as a whole, an original work of authorship. For the purposes", - " of this License, Derivative Works shall not include works that remain", - " separable from, or merely link (or bind by name) to the interfaces of,", - " the Work and Derivative Works thereof.", - "", - " \"Contribution\" shall mean any work of authorship, including", - " the original version of the Work and any modifications or additions", - " to that Work or Derivative Works thereof, that is intentionally", - " submitted to Licensor for inclusion in the Work by the copyright owner", - " or by an individual or Legal Entity authorized to submit on behalf of", - " the copyright owner. For the purposes of this definition, \"submitted\"", - " means any form of electronic, verbal, or written communication sent", - " to the Licensor or its representatives, including but not limited to", - " communication on electronic mailing lists, source code control systems,", - " and issue tracking systems that are managed by, or on behalf of, the", - " Licensor for the purpose of discussing and improving the Work, but", - " excluding communication that is conspicuously marked or otherwise", - " designated in writing by the copyright owner as \"Not a Contribution.\"", - "", - " \"Contributor\" shall mean Licensor and any individual or Legal Entity", - " on behalf of whom a Contribution has been received by Licensor and", - " subsequently incorporated within the Work.", - "", - " 2. Grant of Copyright License. Subject to the terms and conditions of", - " this License, each Contributor hereby grants to You a perpetual,", - " worldwide, non-exclusive, no-charge, royalty-free, irrevocable", - " copyright license to reproduce, prepare Derivative Works of,", - " publicly display, publicly perform, sublicense, and distribute the", - " Work and such Derivative Works in Source or Object form.", - "", - " 3. Grant of Patent License. Subject to the terms and conditions of", - " this License, each Contributor hereby grants to You a perpetual,", - " worldwide, non-exclusive, no-charge, royalty-free, irrevocable", - " (except as stated in this section) patent license to make, have made,", - " use, offer to sell, sell, import, and otherwise transfer the Work,", - " where such license applies only to those patent claims licensable", - " by such Contributor that are necessarily infringed by their", - " Contribution(s) alone or by combination of their Contribution(s)", - " with the Work to which such Contribution(s) was submitted. If You", - " institute patent litigation against any entity (including a", - " cross-claim or counterclaim in a lawsuit) alleging that the Work", - " or a Contribution incorporated within the Work constitutes direct", - " or contributory patent infringement, then any patent licenses", - " granted to You under this License for that Work shall terminate", - " as of the date such litigation is filed.", - "", - " 4. Redistribution. You may reproduce and distribute copies of the", - " Work or Derivative Works thereof in any medium, with or without", - " modifications, and in Source or Object form, provided that You", - " meet the following conditions:", - "", - " (a) You must give any other recipients of the Work or", - " Derivative Works a copy of this License; and", - "", - " (b) You must cause any modified files to carry prominent notices", - " stating that You changed the files; and", - "", - " (c) You must retain, in the Source form of any Derivative Works", - " that You distribute, all copyright, patent, trademark, and", - " attribution notices from the Source form of the Work,", - " excluding those notices that do not pertain to any part of", - " the Derivative Works; and", - "", - " (d) If the Work includes a \"NOTICE\" text file as part of its", - " distribution, then any Derivative Works that You distribute must", - " include a readable copy of the attribution notices contained", - " within such NOTICE file, excluding those notices that do not", - " pertain to any part of the Derivative Works, in at least one", - " of the following places: within a NOTICE text file distributed", - " as part of the Derivative Works; within the Source form or", - " documentation, if provided along with the Derivative Works; or,", - " within a display generated by the Derivative Works, if and", - " wherever such third-party notices normally appear. The contents", - " of the NOTICE file are for informational purposes only and", - " do not modify the License. You may add Your own attribution", - " notices within Derivative Works that You distribute, alongside", - " or as an addendum to the NOTICE text from the Work, provided", - " that such additional attribution notices cannot be construed", - " as modifying the License.", - "", - " You may add Your own copyright statement to Your modifications and", - " may provide additional or different license terms and conditions", - " for use, reproduction, or distribution of Your modifications, or", - " for any such Derivative Works as a whole, provided Your use,", - " reproduction, and distribution of the Work otherwise complies with", - " the conditions stated in this License.", - "", - " 5. Submission of Contributions. Unless You explicitly state otherwise,", - " any Contribution intentionally submitted for inclusion in the Work", - " by You to the Licensor shall be under the terms and conditions of", - " this License, without any additional terms or conditions.", - " Notwithstanding the above, nothing herein shall supersede or modify", - " the terms of any separate license agreement you may have executed", - " with Licensor regarding such Contributions.", - "", - " 6. Trademarks. This License does not grant permission to use the trade", - " names, trademarks, service marks, or product names of the Licensor,", - " except as required for reasonable and customary use in describing the", - " origin of the Work and reproducing the content of the NOTICE file.", - "", - " 7. Disclaimer of Warranty. Unless required by applicable law or", - " agreed to in writing, Licensor provides the Work (and each", - " Contributor provides its Contributions) on an \"AS IS\" BASIS,", - " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or", - " implied, including, without limitation, any warranties or conditions", - " of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A", - " PARTICULAR PURPOSE. You are solely responsible for determining the", - " appropriateness of using or redistributing the Work and assume any", - " risks associated with Your exercise of permissions under this License.", - "", - " 8. Limitation of Liability. In no event and under no legal theory,", - " whether in tort (including negligence), contract, or otherwise,", - " unless required by applicable law (such as deliberate and grossly", - " negligent acts) or agreed to in writing, shall any Contributor be", - " liable to You for damages, including any direct, indirect, special,", - " incidental, or consequential damages of any character arising as a", - " result of this License or out of the use or inability to use the", - " Work (including but not limited to damages for loss of goodwill,", - " work stoppage, computer failure or malfunction, or any and all", - " other commercial damages or losses), even if such Contributor", - " has been advised of the possibility of such damages.", - "", - " 9. Accepting Warranty or Additional Liability. While redistributing", - " the Work or Derivative Works thereof, You may choose to offer,", - " and charge a fee for, acceptance of support, warranty, indemnity,", - " or other liability obligations and/or rights consistent with this", - " License. However, in accepting such obligations, You may act only", - " on Your own behalf and on Your sole responsibility, not on behalf", - " of any other Contributor, and only if You agree to indemnify,", - " defend, and hold each Contributor harmless for any liability", - " incurred by, or claims asserted against, such Contributor by reason", - " of your accepting any such warranty or additional liability.", - "", - " END OF TERMS AND CONDITIONS" - ] + "description": "The file syntaxes/JavaScript.tmLanguage.json was derived from TypeScriptReact.tmLanguage in https://github.com/Microsoft/TypeScript-TmLanguage." }, { "name": "textmate/javascript.tmbundle", diff --git a/extensions/javascript/javascript-language-configuration.json b/extensions/javascript/javascript-language-configuration.json index f25940db455..1e8f440a420 100644 --- a/extensions/javascript/javascript-language-configuration.json +++ b/extensions/javascript/javascript-language-configuration.json @@ -24,5 +24,11 @@ ["'", "'"], ["\"", "\""], ["`", "`"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*//\\s*#?region\\b", + "end": "^\\s*//\\s*#?endregion\\b" + } + } } \ No newline at end of file diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index b22f781c5f9..b3b68dedd5f 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -63,11 +63,13 @@ "grammars": [ { "language": "javascriptreact", - "scopeName": "source.js", - "path": "./syntaxes/JavaScript.tmLanguage.json", + "scopeName": "source.js.jsx", + "path": "./syntaxes/JavaScriptReact.tmLanguage.json", "embeddedLanguages": { "meta.tag.js": "jsx-tags", - "meta.tag.without-attributes.js": "jsx-tags" + "meta.tag.without-attributes.js": "jsx-tags", + "meta.tag.attributes.js.jsx": "javascriptreact", + "meta.embedded.expression.js": "javascriptreact" } }, { @@ -76,7 +78,9 @@ "path": "./syntaxes/JavaScript.tmLanguage.json", "embeddedLanguages": { "meta.tag.js": "jsx-tags", - "meta.tag.without-attributes.js": "jsx-tags" + "meta.tag.without-attributes.js": "jsx-tags", + "meta.tag.attributes.js": "javascript", + "meta.embedded.expression.js": "javascript" } }, { @@ -91,7 +95,7 @@ }, { "language": "javascriptreact", - "path": "./snippets/javascriptreact.json" + "path": "./snippets/javascript.json" } ], "jsonValidation": [ @@ -130,6 +134,6 @@ ] }, "devDependencies": { - "@types/node": "^7.0.4" + "@types/node": "8.0.33" } -} \ No newline at end of file +} diff --git a/extensions/javascript/snippets/javascript.json b/extensions/javascript/snippets/javascript.json index bdae6179418..5cbc2a0418d 100644 --- a/extensions/javascript/snippets/javascript.json +++ b/extensions/javascript/snippets/javascript.json @@ -15,8 +15,8 @@ "For Loop": { "prefix": "for", "body": [ - "for (var ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", - "\tvar ${3:element} = ${2:array}[${1:index}];", + "for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", + "\tconst ${3:element} = ${2:array}[${1:index}];", "\t$0", "}" ], @@ -25,24 +25,33 @@ "For-Each Loop": { "prefix": "foreach", "body": [ - "${1:array}.forEach(function(${2:element}) {", + "${1:array}.forEach(${2:element} => {", "\t$0", - "}, this);" + "});" ], "description": "For-Each Loop" }, "For-In Loop": { "prefix": "forin", "body": [ - "for (var ${1:key} in ${2:object}) {", + "for (const ${1:key} in ${2:object}) {", "\tif (${2:object}.hasOwnProperty(${1:key})) {", - "\t\tvar ${3:element} = ${2:object}[${1:key}];", + "\t\tconst ${3:element} = ${2:object}[${1:key}];", "\t\t$0", "\t}", "}" ], "description": "For-In Loop" }, + "For-Of Loop": { + "prefix": "forof", + "body": [ + "for (const ${1:iterator} of ${2:object}) {", + "\t$0", + "}" + ], + "description": "For-Of Loop" + }, "Function Statement": { "prefix": "function", "body": [ @@ -75,7 +84,7 @@ "New Statement": { "prefix": "new", "body": [ - "var ${1:name} = new ${2:type}(${3:arguments});$0" + "const ${1:name} = new ${2:type}(${3:arguments});$0" ], "description": "New Statement" }, @@ -125,17 +134,31 @@ "Set Timeout Function": { "prefix": "settimeout", "body": [ - "setTimeout(function() {", + "setTimeout(() => {", "\t$0", "}, ${1:timeout});" ], "description": "Set Timeout Function" }, - "Relative Reference to another File": { - "prefix": "reference", + "Import external module.": { + "prefix": "import statement", "body": [ - "/// $0" + "import { $0 } from \"${1:module}\";" ], - "description": "Relative Reference to another File" + "description": "Import external module." + }, + "Region Start": { + "prefix": "#region", + "body": [ + "//#region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#endregion", + "body": [ + "//#endregion" + ], + "description": "Folding Region End" } } diff --git a/extensions/javascript/snippets/javascriptreact.json b/extensions/javascript/snippets/javascriptreact.json deleted file mode 100644 index 0566af20e7b..00000000000 --- a/extensions/javascript/snippets/javascriptreact.json +++ /dev/null @@ -1,141 +0,0 @@ -{ - "define module": { - "prefix": "define", - "body": [ - "define([", - "\t'require',", - "\t'${1:dependency}'", - "], function(require, ${2:factory}) {", - "\t'use strict';", - "\t$0", - "});" - ], - "description": "define module" - }, - "For Loop": { - "prefix": "for", - "body": [ - "for (var ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", - "\tvar ${3:element} = ${2:array}[${1:index}];", - "\t$0", - "}" - ], - "description": "For Loop" - }, - "For-Each Loop": { - "prefix": "foreach", - "body": [ - "${1:array}.forEach(function(${2:element}) {", - "\t$0", - "}, this);" - ], - "description": "For-Each Loop" - }, - "For-In Loop": { - "prefix": "forin", - "body": [ - "for (var ${1:key} in ${2:object}) {", - "\tif (${2:object}.hasOwnProperty(${1:key})) {", - "\t\tvar ${3:element} = ${2:object}[${1:key}];", - "\t\t$0", - "\t}", - "}" - ], - "description": "For-In Loop" - }, - "Function Statement": { - "prefix": "function", - "body": [ - "function ${1:name}(${2:params}) {", - "\t$0", - "}" - ], - "description": "Function Statement" - }, - "If Statement": { - "prefix": "if", - "body": [ - "if (${1:condition}) {", - "\t$0", - "}" - ], - "description": "If Statement" - }, - "If-Else Statement": { - "prefix": "ifelse", - "body": [ - "if (${1:condition}) {", - "\t$0", - "} else {", - "\t", - "}" - ], - "description": "If-Else Statement" - }, - "New Statement": { - "prefix": "new", - "body": [ - "var ${1:name} = new ${2:type}(${3:arguments});$0" - ], - "description": "New Statement" - }, - "Switch Statement": { - "prefix": "switch", - "body": [ - "switch (${1:key}) {", - "\tcase ${2:value}:", - "\t\t$0", - "\t\tbreak;", - "", - "\tdefault:", - "\t\tbreak;", - "}" - ], - "description": "Switch Statement" - }, - "While Statement": { - "prefix": "while", - "body": [ - "while (${1:condition}) {", - "\t$0", - "}" - ], - "description": "While Statement" - }, - "Do-While Statement": { - "prefix": "dowhile", - "body": [ - "do {", - "\t$0", - "} while (${1:condition});" - ], - "description": "Do-While Statement" - }, - "Try-Catch Statement": { - "prefix": "trycatch", - "body": [ - "try {", - "\t$0", - "} catch (${2:error}) {", - "\t", - "}" - ], - "description": "Try-Catch Statement" - }, - "Set Timeout Function": { - "prefix": "settimeout", - "body": [ - "setTimeout(function() {", - "\t$0", - "}, ${1:timeout});" - ], - "description": "Set Timeout Function" - }, - "Relative Reference to another File": { - "prefix": "reference", - "body": [ - "/// $0" - ], - "description": "Relative Reference to another File" - } -} diff --git a/extensions/javascript/src/features/bowerJSONContribution.ts b/extensions/javascript/src/features/bowerJSONContribution.ts index c8ecb91aeb3..a3c7b17e46d 100644 --- a/extensions/javascript/src/features/bowerJSONContribution.ts +++ b/extensions/javascript/src/features/bowerJSONContribution.ts @@ -30,8 +30,8 @@ export class BowerJSONContribution implements IJSONContribution { return [{ language: 'json', pattern: '**/bower.json' }, { language: 'json', pattern: '**/.bower.json' }]; } - public collectDefaultSuggestions(resource: string, collector: ISuggestionsCollector): Thenable { - let defaultValue = { + public collectDefaultSuggestions(_resource: string, collector: ISuggestionsCollector): Thenable { + const defaultValue = { 'name': '${1:name}', 'description': '${2:description}', 'authors': ['${3:author}'], @@ -39,37 +39,37 @@ export class BowerJSONContribution implements IJSONContribution { 'main': '${5:pathToMain}', 'dependencies': {} }; - let proposal = new CompletionItem(localize('json.bower.default', 'Default bower.json')); + const proposal = new CompletionItem(localize('json.bower.default', 'Default bower.json')); proposal.kind = CompletionItemKind.Class; proposal.insertText = new SnippetString(JSON.stringify(defaultValue, null, '\t')); collector.add(proposal); return Promise.resolve(null); } - public collectPropertySuggestions(resource: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector): Thenable { + public collectPropertySuggestions(_resource: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector): Thenable | null { if ((location.matches(['dependencies']) || location.matches(['devDependencies']))) { if (currentWord.length > 0) { - let queryUrl = 'https://bower.herokuapp.com/packages/search/' + encodeURIComponent(currentWord); + const queryUrl = 'https://bower.herokuapp.com/packages/search/' + encodeURIComponent(currentWord); return this.xhr({ url: queryUrl }).then((success) => { if (success.status === 200) { try { - let obj = JSON.parse(success.responseText); + const obj = JSON.parse(success.responseText); if (Array.isArray(obj)) { - let results = <{ name: string; description: string; }[]>obj; + const results = <{ name: string; description: string; }[]>obj; for (let i = 0; i < results.length; i++) { - let name = results[i].name; - let description = results[i].description || ''; - let insertText = new SnippetString().appendText(JSON.stringify(name)); + const name = results[i].name; + const description = results[i].description || ''; + const insertText = new SnippetString().appendText(JSON.stringify(name)); if (addValue) { insertText.appendText(': ').appendPlaceholder('latest'); if (!isLast) { insertText.appendText(','); } } - let proposal = new CompletionItem(name); + const proposal = new CompletionItem(name); proposal.kind = CompletionItemKind.Property; proposal.insertText = insertText; proposal.filterText = JSON.stringify(name); @@ -85,13 +85,14 @@ export class BowerJSONContribution implements IJSONContribution { collector.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', success.responseText)); return 0; } + return undefined; }, (error) => { collector.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', error.responseText)); return 0; }); } else { this.topRanked.forEach((name) => { - let insertText = new SnippetString().appendText(JSON.stringify(name)); + const insertText = new SnippetString().appendText(JSON.stringify(name)); if (addValue) { insertText.appendText(': ').appendPlaceholder('latest'); if (!isLast) { @@ -99,7 +100,7 @@ export class BowerJSONContribution implements IJSONContribution { } } - let proposal = new CompletionItem(name); + const proposal = new CompletionItem(name); proposal.kind = CompletionItemKind.Property; proposal.insertText = insertText; proposal.filterText = JSON.stringify(name); @@ -113,10 +114,10 @@ export class BowerJSONContribution implements IJSONContribution { return null; } - public collectValueSuggestions(resource: string, location: Location, collector: ISuggestionsCollector): Thenable { + public collectValueSuggestions(_resource: string, location: Location, collector: ISuggestionsCollector): Thenable { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) { // not implemented. Could be do done calling the bower command. Waiting for web API: https://github.com/bower/registry/issues/26 - let proposal = new CompletionItem(localize('json.bower.latest.version', 'latest')); + const proposal = new CompletionItem(localize('json.bower.latest.version', 'latest')); proposal.insertText = new SnippetString('"${1:latest}"'); proposal.filterText = '""'; proposal.kind = CompletionItemKind.Value; @@ -126,7 +127,7 @@ export class BowerJSONContribution implements IJSONContribution { return Promise.resolve(null); } - public resolveSuggestion(item: CompletionItem): Thenable { + public resolveSuggestion(item: CompletionItem): Thenable | null { if (item.kind === CompletionItemKind.Property && item.documentation === '') { return this.getInfo(item.label).then(documentation => { if (documentation) { @@ -135,18 +136,18 @@ export class BowerJSONContribution implements IJSONContribution { } return null; }); - }; + } return null; } - private getInfo(pack: string): Thenable { - let queryUrl = 'https://bower.herokuapp.com/packages/' + encodeURIComponent(pack); + private getInfo(pack: string): Thenable { + const queryUrl = 'https://bower.herokuapp.com/packages/' + encodeURIComponent(pack); return this.xhr({ url: queryUrl }).then((success) => { try { - let obj = JSON.parse(success.responseText); + const obj = JSON.parse(success.responseText); if (obj && obj.url) { let url: string = obj.url; if (url.indexOf('git://') === 0) { @@ -161,14 +162,14 @@ export class BowerJSONContribution implements IJSONContribution { // ignore } return void 0; - }, (error) => { + }, () => { return void 0; }); } - public getInfoContribution(resource: string, location: Location): Thenable { + public getInfoContribution(_resource: string, location: Location): Thenable | null { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) { - let pack = location.path[location.path.length - 1]; + const pack = location.path[location.path.length - 1]; if (typeof pack === 'string') { return this.getInfo(pack).then(documentation => { if (documentation) { diff --git a/extensions/javascript/src/features/jsonContributions.ts b/extensions/javascript/src/features/jsonContributions.ts index 6aca3ebd416..81f8a66f2c2 100644 --- a/extensions/javascript/src/features/jsonContributions.ts +++ b/extensions/javascript/src/features/jsonContributions.ts @@ -24,18 +24,18 @@ export interface ISuggestionsCollector { export interface IJSONContribution { getDocumentSelector(): DocumentSelector; - getInfoContribution(fileName: string, location: Location): Thenable; - collectPropertySuggestions(fileName: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, result: ISuggestionsCollector): Thenable; - collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable; + getInfoContribution(fileName: string, location: Location): Thenable | null; + collectPropertySuggestions(fileName: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, result: ISuggestionsCollector): Thenable | null; + collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable | null; collectDefaultSuggestions(fileName: string, result: ISuggestionsCollector): Thenable; - resolveSuggestion?(item: CompletionItem): Thenable; + resolveSuggestion?(item: CompletionItem): Thenable | null; } export function addJSONProviders(xhr: XHRRequest): Disposable { - let contributions = [new PackageJSONContribution(xhr), new BowerJSONContribution(xhr)]; - let subscriptions: Disposable[] = []; + const contributions = [new PackageJSONContribution(xhr), new BowerJSONContribution(xhr)]; + const subscriptions: Disposable[] = []; contributions.forEach(contribution => { - let selector = contribution.getDocumentSelector(); + const selector = contribution.getDocumentSelector(); subscriptions.push(languages.registerCompletionItemProvider(selector, new JSONCompletionItemProvider(contribution), '"', ':')); subscriptions.push(languages.registerHoverProvider(selector, new JSONHoverProvider(contribution))); }); @@ -47,18 +47,21 @@ export class JSONHoverProvider implements HoverProvider { constructor(private jsonContribution: IJSONContribution) { } - public provideHover(document: TextDocument, position: Position, token: CancellationToken): Thenable { - let fileName = basename(document.fileName); - let offset = document.offsetAt(position); - let location = getLocation(document.getText(), offset); - let node = location.previousNode; + public provideHover(document: TextDocument, position: Position, _token: CancellationToken): Thenable | null { + const fileName = basename(document.fileName); + const offset = document.offsetAt(position); + const location = getLocation(document.getText(), offset); + if (!location.previousNode) { + return null; + } + const node = location.previousNode; if (node && node.offset <= offset && offset <= node.offset + node.length) { - let promise = this.jsonContribution.getInfoContribution(fileName, location); + const promise = this.jsonContribution.getInfoContribution(fileName, location); if (promise) { return promise.then(htmlContent => { - let range = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length)); - let result: Hover = { - contents: htmlContent, + const range = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length)); + const result: Hover = { + contents: htmlContent || [], range: range }; return result; @@ -74,9 +77,9 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { constructor(private jsonContribution: IJSONContribution) { } - public resolveCompletionItem(item: CompletionItem, token: CancellationToken): Thenable { + public resolveCompletionItem(item: CompletionItem, _token: CancellationToken): Thenable { if (this.jsonContribution.resolveSuggestion) { - let resolver = this.jsonContribution.resolveSuggestion(item); + const resolver = this.jsonContribution.resolveSuggestion(item); if (resolver) { return resolver; } @@ -84,28 +87,28 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { return Promise.resolve(item); } - public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Thenable { + public provideCompletionItems(document: TextDocument, position: Position, _token: CancellationToken): Thenable | null { - let fileName = basename(document.fileName); + const fileName = basename(document.fileName); - let currentWord = this.getCurrentWord(document, position); + const currentWord = this.getCurrentWord(document, position); let overwriteRange: Range; - let items: CompletionItem[] = []; + const items: CompletionItem[] = []; let isIncomplete = false; - let offset = document.offsetAt(position); - let location = getLocation(document.getText(), offset); + const offset = document.offsetAt(position); + const location = getLocation(document.getText(), offset); - let node = location.previousNode; + const node = location.previousNode; if (node && node.offset <= offset && offset <= node.offset + node.length && (node.type === 'property' || node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) { overwriteRange = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length)); } else { overwriteRange = new Range(document.positionAt(offset - currentWord.length), position); } - let proposed: { [key: string]: boolean } = {}; - let collector: ISuggestionsCollector = { + const proposed: { [key: string]: boolean } = {}; + const collector: ISuggestionsCollector = { add: (suggestion: CompletionItem) => { if (!proposed[suggestion.label]) { proposed[suggestion.label] = true; @@ -118,11 +121,11 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { log: (message: string) => console.log(message) }; - let collectPromise: Thenable = null; + let collectPromise: Thenable | null = null; if (location.isAtPropertyKey) { - let addValue = !location.previousNode || !location.previousNode.columnOffset; - let isLast = this.isLast(document, position); + const addValue = !location.previousNode || !location.previousNode.columnOffset; + const isLast = this.isLast(document, position); collectPromise = this.jsonContribution.collectPropertySuggestions(fileName, location, currentWord, addValue, isLast, collector); } else { if (location.path.length === 0) { @@ -143,8 +146,8 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { } private getCurrentWord(document: TextDocument, position: Position) { - var i = position.character - 1; - var text = document.lineAt(position.line).text; + let i = position.character - 1; + const text = document.lineAt(position.line).text; while (i >= 0 && ' \t\n\r\v":{[,'.indexOf(text.charAt(i)) === -1) { i--; } @@ -152,7 +155,7 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { } private isLast(document: TextDocument, position: Position): boolean { - let scanner = createScanner(document.getText(), true); + const scanner = createScanner(document.getText(), true); scanner.setPosition(document.offsetAt(position)); let nextToken = scanner.scan(); if (nextToken === SyntaxKind.StringLiteral && scanner.getTokenError() === ScanError.UnexpectedEndOfString) { diff --git a/extensions/javascript/src/features/packageJSONContribution.ts b/extensions/javascript/src/features/packageJSONContribution.ts index 82bb37ac0d8..5b09fb0c9d1 100644 --- a/extensions/javascript/src/features/packageJSONContribution.ts +++ b/extensions/javascript/src/features/packageJSONContribution.ts @@ -13,7 +13,7 @@ import { textToMarkedString } from './markedTextUtil'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -let LIMIT = 40; +const LIMIT = 40; export class PackageJSONContribution implements IJSONContribution { @@ -31,8 +31,8 @@ export class PackageJSONContribution implements IJSONContribution { public constructor(private xhr: XHRRequest) { } - public collectDefaultSuggestions(fileName: string, result: ISuggestionsCollector): Thenable { - let defaultValue = { + public collectDefaultSuggestions(_fileName: string, result: ISuggestionsCollector): Thenable { + const defaultValue = { 'name': '${1:name}', 'description': '${2:description}', 'authors': '${3:author}', @@ -40,14 +40,21 @@ export class PackageJSONContribution implements IJSONContribution { 'main': '${5:pathToMain}', 'dependencies': {} }; - let proposal = new CompletionItem(localize('json.package.default', 'Default package.json')); + const proposal = new CompletionItem(localize('json.package.default', 'Default package.json')); proposal.kind = CompletionItemKind.Module; proposal.insertText = new SnippetString(JSON.stringify(defaultValue, null, '\t')); result.add(proposal); return Promise.resolve(null); } - public collectPropertySuggestions(resource: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector): Thenable { + public collectPropertySuggestions( + _resource: string, + location: Location, + currentWord: string, + addValue: boolean, + isLast: boolean, + collector: ISuggestionsCollector + ): Thenable | null { if ((location.matches(['dependencies']) || location.matches(['devDependencies']) || location.matches(['optionalDependencies']) || location.matches(['peerDependencies']))) { let queryUrl: string; if (currentWord.length > 0) { @@ -58,21 +65,21 @@ export class PackageJSONContribution implements IJSONContribution { }).then((success) => { if (success.status === 200) { try { - let obj = JSON.parse(success.responseText); + const obj = JSON.parse(success.responseText); if (obj && Array.isArray(obj.rows)) { - let results = <{ key: string[]; }[]>obj.rows; + const results = <{ key: string[]; }[]>obj.rows; for (let i = 0; i < results.length; i++) { - let keys = results[i].key; + const keys = results[i].key; if (Array.isArray(keys) && keys.length > 0) { - let name = keys[0]; - let insertText = new SnippetString().appendText(JSON.stringify(name)); + const name = keys[0]; + const insertText = new SnippetString().appendText(JSON.stringify(name)); if (addValue) { insertText.appendText(': "').appendTabstop().appendText('"'); if (!isLast) { insertText.appendText(','); } } - let proposal = new CompletionItem(name); + const proposal = new CompletionItem(name); proposal.kind = CompletionItemKind.Property; proposal.insertText = insertText; proposal.filterText = JSON.stringify(name); @@ -91,20 +98,21 @@ export class PackageJSONContribution implements IJSONContribution { collector.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', success.responseText)); return 0; } + return undefined; }, (error) => { collector.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', error.responseText)); return 0; }); } else { this.mostDependedOn.forEach((name) => { - let insertText = new SnippetString().appendText(JSON.stringify(name)); + const insertText = new SnippetString().appendText(JSON.stringify(name)); if (addValue) { insertText.appendText(': "').appendTabstop().appendText('"'); if (!isLast) { insertText.appendText(','); } } - let proposal = new CompletionItem(name); + const proposal = new CompletionItem(name); proposal.kind = CompletionItemKind.Property; proposal.insertText = insertText; proposal.filterText = JSON.stringify(name); @@ -118,17 +126,21 @@ export class PackageJSONContribution implements IJSONContribution { return null; } - public collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable { + public collectValueSuggestions( + _fileName: string, + location: Location, + result: ISuggestionsCollector + ): Thenable | null { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) { - let currentKey = location.path[location.path.length - 1]; + const currentKey = location.path[location.path.length - 1]; if (typeof currentKey === 'string') { - let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(currentKey).replace('%40', '@'); + const queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(currentKey).replace('%40', '@'); return this.xhr({ url: queryUrl }).then((success) => { try { - let obj = JSON.parse(success.responseText); - let latest = obj && obj['dist-tags'] && obj['dist-tags']['latest']; + const obj = JSON.parse(success.responseText); + const latest = obj && obj['dist-tags'] && obj['dist-tags']['latest']; if (latest) { let name = JSON.stringify(latest); let proposal = new CompletionItem(name); @@ -155,7 +167,7 @@ export class PackageJSONContribution implements IJSONContribution { // ignore } return 0; - }, (error) => { + }, () => { return 0; }); } @@ -163,7 +175,7 @@ export class PackageJSONContribution implements IJSONContribution { return null; } - public resolveSuggestion(item: CompletionItem): Thenable { + public resolveSuggestion(item: CompletionItem): Thenable | null { if (item.kind === CompletionItemKind.Property && item.documentation === '') { return this.getInfo(item.label).then(infos => { if (infos.length > 0) { @@ -175,24 +187,24 @@ export class PackageJSONContribution implements IJSONContribution { } return null; }); - }; + } return null; } private getInfo(pack: string): Thenable { - let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(pack).replace('%40', '@'); + const queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(pack).replace('%40', '@'); return this.xhr({ url: queryUrl }).then((success) => { try { - let obj = JSON.parse(success.responseText); + const obj = JSON.parse(success.responseText); if (obj) { - let result: string[] = []; + const result: string[] = []; if (obj.description) { result.push(obj.description); } - let latest = obj && obj['dist-tags'] && obj['dist-tags']['latest']; + const latest = obj && obj['dist-tags'] && obj['dist-tags']['latest']; if (latest) { result.push(localize('json.npm.version.hover', 'Latest version: {0}', latest)); } @@ -202,14 +214,14 @@ export class PackageJSONContribution implements IJSONContribution { // ignore } return []; - }, (error) => { + }, () => { return []; }); } - public getInfoContribution(fileName: string, location: Location): Thenable { + public getInfoContribution(_fileName: string, location: Location): Thenable | null { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) { - let pack = location.path[location.path.length - 1]; + const pack = location.path[location.path.length - 1]; if (typeof pack === 'string') { return this.getInfo(pack).then(infos => { if (infos.length) { diff --git a/extensions/javascript/src/javascriptMain.ts b/extensions/javascript/src/javascriptMain.ts index 92dc3e82b70..ed2552b87f0 100644 --- a/extensions/javascript/src/javascriptMain.ts +++ b/extensions/javascript/src/javascriptMain.ts @@ -16,12 +16,12 @@ export function activate(context: ExtensionContext): any { nls.config({ locale: env.language }); configureHttpRequest(); - workspace.onDidChangeConfiguration(e => configureHttpRequest()); + workspace.onDidChangeConfiguration(() => configureHttpRequest()); context.subscriptions.push(addJSONProviders(httpRequest.xhr)); } function configureHttpRequest() { - let httpSettings = workspace.getConfiguration('http'); - httpRequest.configure(httpSettings.get('proxy'), httpSettings.get('proxyStrictSSL')); + const httpSettings = workspace.getConfiguration('http'); + httpRequest.configure(httpSettings.get('proxy', ''), httpSettings.get('proxyStrictSSL', true)); } diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 6a9a32ac03c..7b1ec3d76c5 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/648a036db2bad78ee93463269ec49ed91ee5aa91", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/824f47ea6e98590ac2e75db5bebdf6eff71421ad", "name": "JavaScript (with React support)", "scopeName": "source.js", "fileTypes": [ @@ -47,20 +47,14 @@ "include": "#declaration" }, { - "include": "#switch-statement" + "include": "#control-statement" }, { - "include": "#for-loop" - }, - { - "include": "#after-operator-block" + "include": "#after-operator-block-as-object-literal" }, { "include": "#decl-block" }, - { - "include": "#control-statement" - }, { "include": "#expression" }, @@ -69,6 +63,164 @@ } ] }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.js", + "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js entity.name.function.js" @@ -326,1241 +501,6 @@ } ] }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.js" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.js" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "expression": { - "patterns": [ - { - "include": "#jsx" - }, - { - "include": "#string" - }, - { - "include": "#regex" - }, - { - "include": "#template" - }, - { - "include": "#comment" - }, - { - "include": "#function-expression" - }, - { - "include": "#class-expression" - }, - { - "include": "#arrow-function" - }, - { - "include": "#cast" - }, - { - "include": "#ternary-expression" - }, - { - "include": "#new-expr" - }, - { - "include": "#object-literal" - }, - { - "include": "#expression-operators" - }, - { - "include": "#function-call" - }, - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#identifiers" - }, - { - "include": "#paren-expression" - }, - { - "include": "#punctuation-comma" - }, - { - "include": "#punctuation-accessor" - } - ] - }, - "control-statement": { - "patterns": [ - { - "name": "keyword.control.trycatch.js", - "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)" - }, - { - "name": "meta.definition.property.js variable.object.property.js", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.js", - "match": "\\?" - } - ] - } - ] - }, - "method-declaration": { - "patterns": [ - { - "name": "meta.method.declaration.js", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js" @@ -1768,140 +708,400 @@ } ] }, - "return-type": { + "field-declaration": { + "name": "meta.field.declaration.js", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.js variable.object.property.js", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js", + "match": "\\?" } ] } ] }, - "return-type-core": { + "variable-initializer": { + "patterns": [ + { + "begin": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.js", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, { "include": "#type-parameters" }, { - "include": "#type-tuple" + "include": "#function-parameters" }, { - "include": "#type-object" + "include": "#return-type" }, { - "include": "#type-operators" + "include": "#decl-block" + } + ] + }, + "method-declaration": { + "patterns": [ + { + "name": "meta.method.declaration.js", + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js" + }, + "2": { + "name": "variable.parameter.js" + } + } + }, + { + "name": "meta.arrow.js", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js", + "begin": "(?:(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.js", - "match": "(?)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.js" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.js", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { + "class-declaration-or-expression-patterns": { "patterns": [ { "include": "#comment" }, { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" + "include": "#class-or-interface-heritage" + }, + { + "match": "[_$[:alpha:]][_$[:alnum:]]*", + "captures": { + "0": { + "name": "entity.name.type.class.js" } - ] + } }, { - "include": "#type-predicate-operator" + "include": "#type-parameters" }, { - "include": "#type" + "include": "#class-or-interface-body" } ] }, - "type-tuple": { - "name": "meta.type.tuple.js", - "begin": "\\[", + "interface-declaration": { + "name": "meta.interface.js", + "begin": "(?)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.js" + "name": "keyword.control.export.js" + }, + "2": { + "name": "storage.modifier.js" + }, + "3": { + "name": "storage.type.enum.js" + }, + "4": { + "name": "entity.name.type.enum.js" } }, + "end": "(?<=\\})", "patterns": [ { "include": "#comment" }, { - "name": "storage.modifier.js", - "match": "(?)" + "include": "#string" + }, + { + "name": "entity.name.type.module.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + }, + { + "include": "#punctuation-accessor" + }, + { + "include": "#decl-block" + } + ] + }, + "type-alias-declaration": { + "name": "meta.type.declaration.js", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.js" + }, + "1": { + "name": "entity.name.function.js" + } + } + }, + { + "name": "meta.object.member.js", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.js" + } + } + }, + { + "name": "meta.object.member.js", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.js" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.js" + } + } + }, + { + "name": "meta.object.member.js", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.js punctuation.separator.key-value.js" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.js" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.js" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.js", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.js", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.js", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.js" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.js" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.js", + "begin": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.js", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.js", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.js", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.js", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.js", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.js", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.js", + "match": "--" + }, + { + "name": "keyword.operator.increment.js", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.js", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.js" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.js", + "match": "(?=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "captures": { "1": { "name": "punctuation.accessor.js" @@ -2466,7 +2548,7 @@ "match": "(?=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "patterns": [ - { - "name": "meta.function-call.js", - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "patterns": [ - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#object-identifiers" - }, - { - "include": "#punctuation-accessor" - }, - { - "name": "keyword.operator.expression.import.js", - "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" - }, - { - "name": "entity.name.function.js", - "match": "([_$[:alpha:]][_$[:alnum:]]*)" - } - ] - }, - { - "include": "#comment" - }, - { - "name": "meta.type.parameters.js", - "begin": "\\<", - "beginCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.begin.js" - } - }, - "end": "\\>", - "endCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.end.js" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - { - "include": "#paren-expression" - } - ] - }, "identifiers": { "patterns": [ { "include": "#object-identifiers" }, { - "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n))", + "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.js" @@ -2627,195 +2647,17 @@ } ] }, - "cast": { + "type-annotation": { "patterns": [ { - "include": "#jsx" - } - ] - }, - "new-expr": { - "name": "new.expr.js", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.js" - }, - "1": { - "name": "entity.name.function.js" - } - } - }, - { - "name": "meta.object.member.js", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.js" - } - }, - "end": "(?=,|\\})" - }, - { - "name": "meta.object.member.js", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.js" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.js", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.js" - } - } - }, - { - "include": "#object-member-body" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "object-member-body": { - "name": "meta.object.member.js", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.js punctuation.separator.key-value.js" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - "expression-operators": { - "patterns": [ - { - "name": "keyword.control.flow.js", - "match": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { "include": "#type" @@ -2823,125 +2665,78 @@ ] }, { - "name": "keyword.operator.spread.js", - "match": "\\.\\.\\." - }, - { - "name": "keyword.operator.assignment.compound.js", - "match": "\\*=|(?>=|>>>=|\\|=" - }, - { - "name": "keyword.operator.bitwise.shift.js", - "match": "<<|>>>|>>" - }, - { - "name": "keyword.operator.comparison.js", - "match": "===|!==|==|!=" - }, - { - "name": "keyword.operator.relational.js", - "match": "<=|>=|<>|<|>" - }, - { - "name": "keyword.operator.logical.js", - "match": "\\!|&&|\\|\\|" - }, - { - "name": "keyword.operator.bitwise.js", - "match": "\\&|~|\\^|\\|" - }, - { - "name": "keyword.operator.assignment.js", - "match": "\\=" - }, - { - "name": "keyword.operator.decrement.js", - "match": "--" - }, - { - "name": "keyword.operator.increment.js", - "match": "\\+\\+" - }, - { - "name": "keyword.operator.arithmetic.js", - "match": "%|\\*|/|-|\\+" - }, - { - "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", - "captures": { + "name": "meta.type.annotation.js", + "begin": "(:)", + "beginCaptures": { "1": { - "name": "keyword.operator.arithmetic.js" + "name": "keyword.operator.type.annotation.js" } - } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] } ] }, - "typeof-operator": { - "name": "keyword.operator.expression.typeof.js", - "match": "(?)", - "captures": { - "1": { - "name": "storage.modifier.async.js" - }, - "2": { - "name": "variable.parameter.js" - } - } - }, - { - "name": "meta.arrow.js", - "begin": "(?x) (?:\n (? is on new line\n (\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n ) |\n (\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends \n ) |\n # arrow function possible to detect only with => on same line\n (\n (<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(([^()]|\\([^()]*\\))*\\) # parameteres\n (\\s*:\\s*(.)*)? # return type\n \\s*=> # arrow operator\n )\n )\n)", + "name": "meta.return.type.js", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", "beginCaptures": { "1": { - "name": "storage.modifier.async.js" + "name": "keyword.operator.type.annotation.js" } }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "end": "(?", + "name": "meta.return.type.js", + "begin": "(?<=\\))\\s*(:)", "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js" + "1": { + "name": "keyword.operator.type.annotation.js" } }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "end": "(?)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] }, - "punctuation-semicolon": { - "name": "punctuation.terminator.statement.js", - "match": ";" + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] }, - "punctuation-accessor": { - "name": "punctuation.accessor.js", - "match": "\\." + "type-primitive": { + "name": "support.type.primitive.js", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?<=[=(:,\\[?+!]|return|case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.js" @@ -3076,7 +3250,7 @@ }, { "name": "string.regexp.js", - "begin": "(?\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", "captures": { "1": { "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" @@ -3788,33 +3755,12 @@ "5": { "name": "invalid.illegal.syntax.jsdoc" } - }, - "begin": "\\[", - "end": "\\]|(?=\\*/)", - "patterns": [ - { - "match": "(=)((?:[^\\]*]|\\*[^/])*)", - "captures": { - "1": { - "name": "keyword.operator.assignment.jsdoc" - }, - "2": { - "name": "source.embedded.js" - } - } - }, - { - "include": "#brackets" - }, - { - "include": "#quotes" - } - ] + } } ] }, { - "begin": "((@)(?:define|enum|exception|implements|modifies|namespace|private|protected|returns?|suppress|throws|type))\\s+(?={)", + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", "beginCaptures": { "1": { "name": "storage.type.class.jsdoc" @@ -3887,7 +3833,7 @@ }, { "name": "storage.type.class.jsdoc", - "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|global|host|ignore|implements|implicitCast|inherit[Dd]oc|inner|instance|interface |internal|kind|lends|license|listens|main|member|memberof!?|method|mixes|mixins?|modifies|module |name|namespace|noalias|nocollapse|nocompile|nosideeffects|override|overview|package|param|preserve |private|prop|property|protected|public|read[Oo]nly|record|require[ds]|returns?|see|since|static |struct|submodule|summary|suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted |uses|var|variation|version|virtual|writeOnce) \\b", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", "captures": { "1": { "name": "punctuation.definition.block.tag.jsdoc" @@ -3982,28 +3928,6 @@ } ] }, - "quotes": { - "patterns": [ - { - "begin": "'", - "end": "'|(?=\\*/)", - "patterns": [ - { - "include": "#quotes" - } - ] - }, - { - "begin": "\"", - "end": "\"|(?=\\*/)", - "patterns": [ - { - "include": "#quotes" - } - ] - } - ] - }, "jsdoctype": { "patterns": [ { @@ -4038,121 +3962,19 @@ } ] }, - "jsx-tag-attributes": { + "jsx": { "patterns": [ { - "include": "#jsx-tag-attribute-name" + "include": "#jsx-tag-without-attributes-in-expression" }, { - "include": "#jsx-tag-attribute-assignment" + "include": "#jsx-tag-in-expression" }, { - "include": "#jsx-string-double-quoted" - }, - { - "include": "#jsx-string-single-quoted" - }, - { - "include": "#jsx-evaluated-code" + "include": "#jsx-tag-invalid" } ] }, - "jsx-tag-attribute-name": { - "match": "(?x)\n \\s*\n ([_$a-zA-Z][-$\\w]*)\n (?=\\s|=|/?>|/\\*|//)", - "captures": { - "1": { - "name": "entity.other.attribute-name.js" - } - } - }, - "jsx-tag-attribute-assignment": { - "name": "keyword.operator.assignment.js", - "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" - }, - "jsx-string-double-quoted": { - "name": "string.quoted.double.js", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-string-single-quoted": { - "name": "string.quoted.single.js", - "begin": "'", - "end": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-entities": { - "patterns": [ - { - "name": "constant.character.entity.js", - "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", - "captures": { - "1": { - "name": "punctuation.definition.entity.js" - }, - "3": { - "name": "punctuation.definition.entity.js" - } - } - }, - { - "name": "invalid.illegal.bad-ampersand.js", - "match": "&" - } - ] - }, - "jsx-evaluated-code": { - "name": "meta.embedded.expression.js", - "begin": "\\{", - "end": "\\}", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.js" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "jsx-tag-attributes-illegal": { - "name": "invalid.illegal.attribute.js", - "match": "\\S+" - }, "jsx-tag-without-attributes-in-expression": { "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", @@ -4194,7 +4016,7 @@ "name": "punctuation.definition.tag.end.js" } }, - "contentName": "meta.jsx.children.tsx", + "contentName": "meta.jsx.children.js", "patterns": [ { "include": "#jsx-children" @@ -4278,6 +4100,7 @@ } }, "end": "(?=[/]?>)", + "contentName": "meta.tag.attributes.js", "patterns": [ { "include": "#comment" @@ -4298,7 +4121,7 @@ } }, "end": "(?=|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.js" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js", + "match": "\\S+" } } } \ No newline at end of file diff --git a/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json new file mode 100644 index 00000000000..f0ad9fc5c29 --- /dev/null +++ b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json @@ -0,0 +1,4272 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/TypeScript-TmLanguage/blob/master/TypeScriptReact.tmLanguage", + "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/824f47ea6e98590ac2e75db5bebdf6eff71421ad", + "name": "JavaScript (with React support)", + "scopeName": "source.js.jsx", + "fileTypes": [ + ".js", + ".jsx", + ".es6", + ".mjs" + ], + "uuid": "805375ec-d614-41f5-8993-5843fe63ea82", + "patterns": [ + { + "include": "#directives" + }, + { + "include": "#statements" + }, + { + "name": "comment.line.shebang.ts", + "match": "\\A(#!).*(?=$)", + "captures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + } + } + ], + "repository": { + "statements": { + "patterns": [ + { + "include": "#string" + }, + { + "include": "#template" + }, + { + "include": "#comment" + }, + { + "include": "#declaration" + }, + { + "include": "#control-statement" + }, + { + "include": "#after-operator-block-as-object-literal" + }, + { + "include": "#decl-block" + }, + { + "include": "#expression" + }, + { + "include": "#punctuation-semicolon" + } + ] + }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.js.jsx", + "match": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js.jsx", + "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx variable.other.constant.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.js.jsx", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.js.jsx variable.other.readwrite.js.jsx" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + } + ] + }, + "var-single-variable-type-annotation": { + "patterns": [ + { + "include": "#type-annotation" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "destructuring-variable": { + "patterns": [ + { + "name": "meta.object-binding-pattern-variable.js.jsx", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js.jsx" + }, + "2": { + "name": "keyword.operator.rest.js.jsx" + }, + "3": { + "name": "entity.name.function.js.jsx variable.language.this.js.jsx" + }, + "4": { + "name": "entity.name.function.js.jsx" + }, + "5": { + "name": "keyword.operator.optional.js.jsx" + } + } + }, + { + "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.js.jsx variable.object.property.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js.jsx", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js.jsx" + }, + "2": { + "name": "variable.parameter.js.jsx" + } + } + }, + { + "name": "meta.arrow.js.jsx", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js.jsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js.jsx", + "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + }, + "1": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.js.jsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.js.jsx" + } + } + }, + { + "name": "meta.object.member.js.jsx", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.js.jsx", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.js.jsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.js.jsx", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.js.jsx", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.js.jsx", + "begin": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.js.jsx", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.js.jsx", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.js.jsx", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.js.jsx", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.js.jsx", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.js.jsx", + "match": "--" + }, + { + "name": "keyword.operator.increment.js.jsx", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.js.jsx", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.js.jsx" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.js.jsx", + "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "support.constant.dom.js.jsx" + }, + "3": { + "name": "support.variable.property.dom.js.jsx" + } + } + }, + { + "name": "support.class.node.js.jsx", + "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "entity.name.function.js.jsx" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.constant.property.js.jsx" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.property.js.jsx" + } + } + }, + { + "name": "variable.other.constant.js.jsx", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.js.jsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.js.jsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js.jsx" + }, + "2": { + "name": "variable.other.constant.object.property.js.jsx" + }, + "3": { + "name": "variable.other.object.property.js.jsx" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.js.jsx" + }, + "2": { + "name": "variable.other.object.js.jsx" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.js.jsx", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.js.jsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js.jsx" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.js.jsx", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.js.jsx" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js.jsx", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] + }, + "type-primitive": { + "name": "support.type.primitive.js.jsx", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js.jsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js.jsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js.jsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js.jsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js.jsx", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "end": "(/)([gimuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.js.jsx" + }, + "2": { + "name": "keyword.other.js.jsx" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.js.jsx", + "begin": "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.js.jsx" + } + }, + "end": "(?=^)", + "patterns": [ + { + "name": "meta.tag.js.jsx", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.js.jsx" + }, + "2": { + "name": "entity.name.tag.directive.js.jsx" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.js.jsx" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.js.jsx", + "match": "path|types|no-default-lib|name" + }, + { + "name": "keyword.operator.assignment.js.jsx", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.js.jsx" + } + } + } + ] + }, + { + "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.js.jsx" + }, + "4": { + "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "name": "invalid.illegal.type.jsdoc", + "match": "\\G{(?:[^}*]|\\*[^/}])+$" + }, + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "jsx": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes-in-expression" + }, + { + "include": "#jsx-tag-in-expression" + }, + { + "include": "#jsx-tag-invalid" + } + ] + }, + "jsx-tag-without-attributes-in-expression": { + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + } + ] + }, + "jsx-tag-without-attributes": { + "name": "meta.tag.without-attributes.js.jsx", + "begin": "(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "end": "()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + }, + "4": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "endCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + }, + "4": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "contentName": "meta.jsx.children.js.jsx", + "patterns": [ + { + "include": "#jsx-children" + } + ] + }, + "jsx-tag-in-expression": { + "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js.jsx" + }, + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "3": { + "name": "entity.name.tag.js.jsx" + }, + "4": { + "name": "support.class.component.js.jsx" + }, + "5": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-child-tag": { + "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(/>)|(?:())", + "endCaptures": { + "0": { + "name": "meta.tag.js.jsx" + }, + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + }, + "2": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "3": { + "name": "entity.name.tag.js.jsx" + }, + "4": { + "name": "support.class.component.js.jsx" + }, + "5": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-tag" + } + ] + }, + "jsx-tag": { + "name": "meta.tag.js.jsx", + "begin": "(?x)\n (?=(<)\\s*\n ([_$a-zA-Z][-$\\w.]*(?))", + "end": "(?=(/>)|(?:()))", + "patterns": [ + { + "begin": "(?x)\n (<)\\s*\n ((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.begin.js.jsx" + }, + "2": { + "name": "entity.name.tag.js.jsx" + }, + "3": { + "name": "support.class.component.js.jsx" + } + }, + "end": "(?=[/]?>)", + "contentName": "meta.tag.attributes.js.jsx", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#jsx-tag-attributes" + }, + { + "include": "#jsx-tag-attributes-illegal" + } + ] + }, + { + "begin": "(>)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.end.js.jsx" + } + }, + "end": "(?=" + }, + "jsx-children": { + "patterns": [ + { + "include": "#jsx-tag-without-attributes" + }, + { + "include": "#jsx-child-tag" + }, + { + "include": "#jsx-tag-invalid" + }, + { + "include": "#jsx-evaluated-code" + }, + { + "include": "#jsx-entities" + } + ] + }, + "jsx-evaluated-code": { + "name": "meta.embedded.expression.js.jsx", + "begin": "\\{", + "end": "\\}", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "jsx-entities": { + "patterns": [ + { + "name": "constant.character.entity.js.jsx", + "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", + "captures": { + "1": { + "name": "punctuation.definition.entity.js.jsx" + }, + "3": { + "name": "punctuation.definition.entity.js.jsx" + } + } + }, + { + "name": "invalid.illegal.bad-ampersand.js.jsx", + "match": "&" + } + ] + }, + "jsx-tag-attributes": { + "patterns": [ + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n ([_$a-zA-Z][-$\\w]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.js.jsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js.jsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js.jsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js.jsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js.jsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js.jsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js.jsx", + "match": "\\S+" + } + } +} \ No newline at end of file diff --git a/extensions/javascript/test/colorize-results/test_jsx.json b/extensions/javascript/test/colorize-results/test_jsx.json index 55e2c440d3b..7824e567af2 100644 --- a/extensions/javascript/test/colorize-results/test_jsx.json +++ b/extensions/javascript/test/colorize-results/test_jsx.json @@ -1,7 +1,7 @@ [ { "c": "var", - "t": "source.js meta.var.expr.js storage.type.js", + "t": "source.js.jsx meta.var.expr.js.jsx storage.type.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -12,7 +12,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -23,7 +23,7 @@ }, { "c": "ToggleText", - "t": "source.js meta.var.expr.js meta.var-single-variable.expr.js meta.definition.variable.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx meta.definition.variable.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -34,7 +34,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.var-single-variable.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -45,7 +45,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -56,7 +56,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -67,7 +67,7 @@ }, { "c": "React", - "t": "source.js meta.var.expr.js meta.function-call.js variable.other.object.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.function-call.js.jsx variable.other.object.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -78,7 +78,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -89,7 +89,7 @@ }, { "c": "createClass", - "t": "source.js meta.var.expr.js meta.function-call.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.function-call.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -100,7 +100,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -111,7 +111,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -122,7 +122,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -133,7 +133,7 @@ }, { "c": "getInitialState", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "meta.object-literal.key entity.name.function: #9CDCFE", "light_plus": "meta.object-literal.key entity.name.function: #001080", @@ -144,7 +144,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -155,7 +155,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -166,7 +166,7 @@ }, { "c": "function", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js storage.type.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx storage.type.function.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -177,7 +177,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -188,7 +188,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.begin.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -199,7 +199,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.end.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -210,7 +210,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -221,7 +221,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -232,7 +232,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -243,7 +243,7 @@ }, { "c": "return", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.control.flow.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.control.flow.js.jsx", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -254,7 +254,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -265,7 +265,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -276,7 +276,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -287,7 +287,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -298,7 +298,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -309,7 +309,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -320,7 +320,7 @@ }, { "c": "true", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js constant.language.boolean.true.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx constant.language.boolean.true.js.jsx", "r": { "dark_plus": "constant.language: #569CD6", "light_plus": "constant.language: #0000FF", @@ -331,7 +331,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -342,7 +342,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -353,7 +353,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -364,7 +364,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -375,7 +375,7 @@ }, { "c": ",", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.separator.comma.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.separator.comma.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -386,7 +386,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -397,7 +397,7 @@ }, { "c": "toggle", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "meta.object-literal.key entity.name.function: #9CDCFE", "light_plus": "meta.object-literal.key entity.name.function: #001080", @@ -408,7 +408,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -419,7 +419,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -430,7 +430,7 @@ }, { "c": "function", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js storage.type.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx storage.type.function.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -441,7 +441,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -452,7 +452,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.begin.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -463,7 +463,7 @@ }, { "c": "e", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js variable.parameter.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx variable.parameter.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -474,7 +474,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.end.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -485,7 +485,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -496,7 +496,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -507,7 +507,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -518,7 +518,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -529,7 +529,7 @@ }, { "c": " Prevent following the link.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -540,7 +540,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -551,7 +551,7 @@ }, { "c": "e", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js variable.other.object.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx variable.other.object.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -562,7 +562,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -573,7 +573,7 @@ }, { "c": "preventDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js support.function.dom.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx support.function.dom.js.jsx", "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", @@ -584,7 +584,7 @@ }, { "c": "()", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -595,7 +595,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -606,7 +606,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -617,7 +617,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -628,7 +628,7 @@ }, { "c": " Invert the chosen default.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -639,7 +639,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -650,7 +650,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -661,7 +661,7 @@ }, { "c": " This will trigger an intelligent re-render of the component.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -672,7 +672,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -683,7 +683,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -694,7 +694,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -705,7 +705,7 @@ }, { "c": "setState", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.function-call.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.function-call.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -716,7 +716,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -727,7 +727,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -738,7 +738,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -749,7 +749,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -760,7 +760,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -771,7 +771,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -782,7 +782,7 @@ }, { "c": "!", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js keyword.operator.logical.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx keyword.operator.logical.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -793,7 +793,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -804,7 +804,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -815,7 +815,7 @@ }, { "c": "state", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -826,7 +826,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -837,7 +837,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -848,7 +848,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -859,7 +859,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -870,7 +870,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -881,7 +881,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -892,7 +892,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -903,7 +903,7 @@ }, { "c": ",", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.separator.comma.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.separator.comma.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -914,7 +914,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -925,7 +925,7 @@ }, { "c": "render", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js entity.name.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "meta.object-literal.key entity.name.function: #9CDCFE", "light_plus": "meta.object-literal.key entity.name.function: #001080", @@ -936,7 +936,7 @@ }, { "c": ":", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.object-literal.key.js punctuation.separator.key-value.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.object-literal.key.js.jsx punctuation.separator.key-value.js.jsx", "r": { "dark_plus": "meta.object-literal.key: #9CDCFE", "light_plus": "meta.object-literal.key: #001080", @@ -947,7 +947,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -958,7 +958,7 @@ }, { "c": "function", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js storage.type.function.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx storage.type.function.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -969,7 +969,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -980,7 +980,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.begin.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -991,7 +991,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.parameters.js punctuation.definition.parameters.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.parameters.js.jsx punctuation.definition.parameters.end.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1002,7 +1002,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1013,7 +1013,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1024,7 +1024,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1035,7 +1035,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1046,7 +1046,7 @@ }, { "c": " Default to the default message.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1057,7 +1057,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1068,7 +1068,7 @@ }, { "c": "var", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js storage.type.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx storage.type.js.jsx", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -1079,7 +1079,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1090,7 +1090,7 @@ }, { "c": "message", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js meta.var-single-variable.expr.js meta.definition.variable.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx meta.definition.variable.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1101,7 +1101,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js meta.var-single-variable.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx meta.var-single-variable.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1112,7 +1112,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1123,7 +1123,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1134,7 +1134,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1145,7 +1145,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1156,7 +1156,7 @@ }, { "c": "props", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1167,7 +1167,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1178,7 +1178,7 @@ }, { "c": "default", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.var.expr.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.var.expr.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1189,7 +1189,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1200,7 +1200,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.whitespace.comment.leading.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.whitespace.comment.leading.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1211,7 +1211,7 @@ }, { "c": "//", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.js punctuation.definition.comment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx punctuation.definition.comment.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1222,7 +1222,7 @@ }, { "c": " If toggled, show the alternate message.", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js comment.line.double-slash.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx comment.line.double-slash.js.jsx", "r": { "dark_plus": "comment: #608B4E", "light_plus": "comment: #008000", @@ -1233,7 +1233,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1244,7 +1244,7 @@ }, { "c": "if", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.control.conditional.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.control.conditional.js.jsx", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1255,7 +1255,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1266,7 +1266,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1277,7 +1277,7 @@ }, { "c": "!", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.operator.logical.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.operator.logical.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1288,7 +1288,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1299,7 +1299,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1310,7 +1310,7 @@ }, { "c": "state", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1321,7 +1321,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1332,7 +1332,7 @@ }, { "c": "showDefault", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1343,7 +1343,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1354,7 +1354,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1365,7 +1365,7 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1376,7 +1376,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1387,7 +1387,7 @@ }, { "c": "message", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1398,7 +1398,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1409,7 +1409,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1420,7 +1420,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1431,7 +1431,7 @@ }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1442,7 +1442,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1453,7 +1453,7 @@ }, { "c": "props", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js variable.other.object.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx variable.other.object.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1464,7 +1464,7 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1475,7 +1475,7 @@ }, { "c": "alt", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js support.variable.property.dom.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx support.variable.property.dom.js.jsx", "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", @@ -1486,7 +1486,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1497,7 +1497,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1508,7 +1508,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1519,7 +1519,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1530,7 +1530,7 @@ }, { "c": "return", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js keyword.control.flow.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx keyword.control.flow.js.jsx", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1541,7 +1541,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1552,7 +1552,7 @@ }, { "c": "(", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1563,7 +1563,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1574,7 +1574,7 @@ }, { "c": "<", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1585,7 +1585,7 @@ }, { "c": "div", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js entity.name.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx entity.name.tag.js.jsx", "r": { "dark_plus": "entity.name.tag: #569CD6", "light_plus": "entity.name.tag: #800000", @@ -1596,7 +1596,7 @@ }, { "c": ">", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1607,7 +1607,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1618,7 +1618,7 @@ }, { "c": "<", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1629,7 +1629,7 @@ }, { "c": "h1", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js entity.name.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx entity.name.tag.js.jsx", "r": { "dark_plus": "entity.name.tag: #569CD6", "light_plus": "entity.name.tag: #800000", @@ -1640,7 +1640,7 @@ }, { "c": ">", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1651,7 +1651,7 @@ }, { "c": "Hello ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1662,40 +1662,40 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx meta.embedded.expression.js punctuation.section.embedded.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "message", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx meta.embedded.expression.js variable.other.readwrite.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.embedded.expression.js.jsx variable.other.readwrite.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx meta.embedded.expression.js punctuation.section.embedded.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "!", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1706,7 +1706,7 @@ }, { "c": "", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1739,7 +1739,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1750,7 +1750,7 @@ }, { "c": "<", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1761,7 +1761,7 @@ }, { "c": "a", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js entity.name.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx entity.name.tag.js.jsx", "r": { "dark_plus": "entity.name.tag: #569CD6", "light_plus": "entity.name.tag: #800000", @@ -1772,7 +1772,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1783,7 +1783,7 @@ }, { "c": "href", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1794,7 +1794,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1805,7 +1805,7 @@ }, { "c": "\"", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js string.quoted.double.js punctuation.definition.string.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1816,7 +1816,7 @@ }, { "c": "\"", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js string.quoted.double.js punctuation.definition.string.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1827,7 +1827,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1838,7 +1838,7 @@ }, { "c": "onClick", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -1849,7 +1849,7 @@ }, { "c": "=", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1860,18 +1860,18 @@ }, { "c": "{", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js punctuation.section.embedded.begin.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.begin.js.jsx", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "this", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js variable.language.this.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx variable.language.this.js.jsx", "r": { "dark_plus": "variable.language: #569CD6", "light_plus": "variable.language: #0000FF", @@ -1882,40 +1882,40 @@ }, { "c": ".", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js punctuation.accessor.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx punctuation.accessor.js.jsx", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "toggle", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js variable.other.property.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx variable.other.property.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.embedded.expression.js punctuation.section.embedded.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx meta.embedded.expression.js.jsx punctuation.section.embedded.end.js.jsx", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "punctuation.section.embedded: #569CD6", + "light_plus": "punctuation.section.embedded: #0000FF", + "dark_vs": "punctuation.section.embedded: #569CD6", + "light_vs": "punctuation.section.embedded: #0000FF", + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": ">", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1926,7 +1926,7 @@ }, { "c": "Toggle", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1937,7 +1937,7 @@ }, { "c": "", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx meta.tag.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -1970,7 +1970,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js meta.jsx.children.tsx", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx meta.jsx.children.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1981,7 +1981,7 @@ }, { "c": "", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.tag.without-attributes.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.tag.without-attributes.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -2014,7 +2014,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2025,7 +2025,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2036,7 +2036,7 @@ }, { "c": ";", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.terminator.statement.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2047,7 +2047,7 @@ }, { "c": " ", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2058,7 +2058,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js meta.object.member.js meta.function.expression.js meta.block.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx meta.object.member.js.jsx meta.function.expression.js.jsx meta.block.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2069,7 +2069,7 @@ }, { "c": "}", - "t": "source.js meta.var.expr.js meta.objectliteral.js punctuation.definition.block.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.objectliteral.js.jsx punctuation.definition.block.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2080,7 +2080,7 @@ }, { "c": ")", - "t": "source.js meta.var.expr.js meta.brace.round.js", + "t": "source.js.jsx meta.var.expr.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2091,7 +2091,7 @@ }, { "c": ";", - "t": "source.js punctuation.terminator.statement.js", + "t": "source.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2102,7 +2102,7 @@ }, { "c": "React", - "t": "source.js meta.function-call.js variable.other.object.js", + "t": "source.js.jsx meta.function-call.js.jsx variable.other.object.js.jsx", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -2113,7 +2113,7 @@ }, { "c": ".", - "t": "source.js meta.function-call.js punctuation.accessor.js", + "t": "source.js.jsx meta.function-call.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2124,7 +2124,7 @@ }, { "c": "render", - "t": "source.js meta.function-call.js entity.name.function.js", + "t": "source.js.jsx meta.function-call.js.jsx entity.name.function.js.jsx", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -2135,7 +2135,7 @@ }, { "c": "(", - "t": "source.js meta.brace.round.js", + "t": "source.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2146,7 +2146,7 @@ }, { "c": "<", - "t": "source.js meta.tag.js punctuation.definition.tag.begin.js", + "t": "source.js.jsx meta.tag.js.jsx punctuation.definition.tag.begin.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -2157,7 +2157,7 @@ }, { "c": "ToggleText", - "t": "source.js meta.tag.js entity.name.tag.js support.class.component.js", + "t": "source.js.jsx meta.tag.js.jsx entity.name.tag.js.jsx support.class.component.js.jsx", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -2168,7 +2168,7 @@ }, { "c": " ", - "t": "source.js meta.tag.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2179,7 +2179,7 @@ }, { "c": "default", - "t": "source.js meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -2190,7 +2190,7 @@ }, { "c": "=", - "t": "source.js meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2201,7 +2201,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.begin.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2212,7 +2212,7 @@ }, { "c": "World", - "t": "source.js meta.tag.js string.quoted.double.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2223,7 +2223,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.end.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2234,7 +2234,7 @@ }, { "c": " ", - "t": "source.js meta.tag.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2245,7 +2245,7 @@ }, { "c": "alt", - "t": "source.js meta.tag.js entity.other.attribute-name.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx entity.other.attribute-name.js.jsx", "r": { "dark_plus": "entity.other.attribute-name: #9CDCFE", "light_plus": "entity.other.attribute-name: #FF0000", @@ -2256,7 +2256,7 @@ }, { "c": "=", - "t": "source.js meta.tag.js keyword.operator.assignment.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx keyword.operator.assignment.js.jsx", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2267,7 +2267,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.begin.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.begin.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2278,7 +2278,7 @@ }, { "c": "Mars", - "t": "source.js meta.tag.js string.quoted.double.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2289,7 +2289,7 @@ }, { "c": "\"", - "t": "source.js meta.tag.js string.quoted.double.js punctuation.definition.string.end.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx string.quoted.double.js.jsx punctuation.definition.string.end.js.jsx", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -2300,7 +2300,7 @@ }, { "c": " ", - "t": "source.js meta.tag.js", + "t": "source.js.jsx meta.tag.js.jsx meta.tag.attributes.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2311,7 +2311,7 @@ }, { "c": "/>", - "t": "source.js meta.tag.js punctuation.definition.tag.end.js", + "t": "source.js.jsx meta.tag.js.jsx punctuation.definition.tag.end.js.jsx", "r": { "dark_plus": "punctuation.definition.tag: #808080", "light_plus": "punctuation.definition.tag: #800000", @@ -2322,7 +2322,7 @@ }, { "c": ",", - "t": "source.js punctuation.separator.comma.js", + "t": "source.js.jsx punctuation.separator.comma.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2333,7 +2333,7 @@ }, { "c": " ", - "t": "source.js", + "t": "source.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2344,7 +2344,7 @@ }, { "c": "document", - "t": "source.js support.variable.dom.js", + "t": "source.js.jsx support.variable.dom.js.jsx", "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", @@ -2355,7 +2355,7 @@ }, { "c": ".", - "t": "source.js punctuation.accessor.js", + "t": "source.js.jsx punctuation.accessor.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2366,7 +2366,7 @@ }, { "c": "body", - "t": "source.js support.variable.property.dom.js", + "t": "source.js.jsx support.variable.property.dom.js.jsx", "r": { "dark_plus": "support.variable: #9CDCFE", "light_plus": "support.variable: #001080", @@ -2377,7 +2377,7 @@ }, { "c": ")", - "t": "source.js meta.brace.round.js", + "t": "source.js.jsx meta.brace.round.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2388,7 +2388,7 @@ }, { "c": ";", - "t": "source.js punctuation.terminator.statement.js", + "t": "source.js.jsx punctuation.terminator.statement.js.jsx", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/javascript/tsconfig.json b/extensions/javascript/tsconfig.json index 4445bb27fd7..32325af1b23 100644 --- a/extensions/javascript/tsconfig.json +++ b/extensions/javascript/tsconfig.json @@ -5,7 +5,12 @@ "outDir": "./out", "lib": [ "es2015" - ] + ], + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/json/.vscode/launch.json b/extensions/json/.vscode/launch.json index ac84c7bdf26..b2d26ad6c35 100644 --- a/extensions/json/.vscode/launch.json +++ b/extensions/json/.vscode/launch.json @@ -7,11 +7,11 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" + "--extensionDevelopmentPath=${workspaceFolder}" ], "stopOnEntry": false, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/client/out"], + "outFiles": ["${workspaceFolder}/client/out"], "preLaunchTask": "npm" }, { @@ -19,10 +19,10 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/client/out/test" ], + "args": ["--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/client/out/test" ], "stopOnEntry": false, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/client/out/test"], + "outFiles": ["${workspaceFolder}/client/out/test"], "preLaunchTask": "npm" }, { @@ -31,7 +31,7 @@ "request": "attach", "port": 6004, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/server/out"] + "outFiles": ["${workspaceFolder}/server/out"] } ] diff --git a/extensions/json/.vscode/tasks.json b/extensions/json/.vscode/tasks.json index a132a04214d..9e5593ade83 100644 --- a/extensions/json/.vscode/tasks.json +++ b/extensions/json/.vscode/tasks.json @@ -1,5 +1,5 @@ // Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team +// ${workspaceFolder}: the root folder of the team // ${file}: the current opened file // ${fileBasename}: the current opened file's basename // ${fileDirname}: the current opened file's dirname diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index afbf9c71d64..3c9218017c9 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -6,21 +6,25 @@ import * as path from 'path'; -import { workspace, languages, ExtensionContext, extensions, Uri, TextDocument, ColorRange, Color } from 'vscode'; +import { workspace, languages, ExtensionContext, extensions, Uri, TextDocument, ColorInformation, Color, ColorPresentation } from 'vscode'; import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed'; - -import { DocumentColorRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; +import { DocumentColorRequest, DocumentColorParams, ColorPresentationParams, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import * as nls from 'vscode-nls'; +import { hash } from './utils/hash'; let localize = nls.loadMessageBundle(); namespace VSCodeContentRequest { export const type: RequestType = new RequestType('vscode/content'); } +namespace SchemaContentChangeNotification { + export const type: NotificationType = new NotificationType('json/schemaContent'); +} + export interface ISchemaAssociations { [pattern: string]: string[]; } @@ -46,6 +50,7 @@ interface Settings { }; } +// @ts-ignore unused type interface JSONSettings { schemas: JSONSchemaSettings[]; } @@ -56,16 +61,13 @@ interface JSONSchemaSettings { schema?: any; } -const ColorFormat_HEX = { - opaque: '"#{red:X}{green:X}{blue:X}"', - transparent: '"#{red:X}{green:X}{blue:X}{alpha:X}"' -}; - export function activate(context: ExtensionContext) { + let toDispose = context.subscriptions; + let packageInfo = getPackageInfo(context); let telemetryReporter: TelemetryReporter = packageInfo && new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey); - context.subscriptions.push(telemetryReporter); + toDispose.push(telemetryReporter); // The server is implemented in node let serverModule = context.asAbsolutePath(path.join('server', 'out', 'jsonServerMain.js')); @@ -102,6 +104,7 @@ export function activate(context: ExtensionContext) { client.registerFeature(new ConfigurationFeature(client)); let disposable = client.start(); + toDispose.push(disposable); client.onReady().then(() => { client.onTelemetry(e => { if (telemetryReporter) { @@ -119,27 +122,48 @@ export function activate(context: ExtensionContext) { }); }); + let handleContentChange = (uri: Uri) => { + if (uri.scheme === 'vscode' && uri.authority === 'schemas') { + client.sendNotification(SchemaContentChangeNotification.type, uri.toString()); + } + }; + toDispose.push(workspace.onDidChangeTextDocument(e => handleContentChange(e.document.uri))); + toDispose.push(workspace.onDidCloseTextDocument(d => handleContentChange(d.uri))); + client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); // register color provider - context.subscriptions.push(languages.registerColorProvider(documentSelector, { - provideDocumentColors(document: TextDocument): Thenable { - let params = client.code2ProtocolConverter.asDocumentSymbolParams(document); + toDispose.push(languages.registerColorProvider(documentSelector, { + provideDocumentColors(document: TextDocument): Thenable { + let params: DocumentColorParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) + }; return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); - let color = new Color(symbol.color.red * 255, symbol.color.green * 255, symbol.color.blue * 255, symbol.color.alpha); - return new ColorRange(range, color, [ColorFormat_HEX]); + let color = new Color(symbol.color.red, symbol.color.green, symbol.color.blue, symbol.color.alpha); + return new ColorInformation(range, color); + }); + }); + }, + provideColorPresentations(color: Color, context): Thenable { + let params: ColorPresentationParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(context.document), + color: color, + range: client.code2ProtocolConverter.asRange(context.range) + }; + return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { + return presentations.map(p => { + let presentation = new ColorPresentation(p.label); + presentation.textEdit = p.textEdit && client.protocol2CodeConverter.asTextEdit(p.textEdit); + presentation.additionalTextEdits = p.additionalTextEdits && client.protocol2CodeConverter.asTextEdits(p.additionalTextEdits); + return presentation; }); }); } })); }); - // Push the disposable to the context's subscriptions so that the - // client can be deactivated on extension deactivation - context.subscriptions.push(disposable); - languages.setLanguageConfiguration('json', { wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/, indentationRules: { @@ -184,9 +208,6 @@ function getSchemaAssociation(context: ExtensionContext): ISchemaAssociations { function getSettings(): Settings { let httpSettings = workspace.getConfiguration('http'); - let jsonSettings = workspace.getConfiguration('json'); - - let schemas = []; let settings: Settings = { http: { @@ -194,42 +215,70 @@ function getSettings(): Settings { proxyStrictSSL: httpSettings.get('proxyStrictSSL') }, json: { - format: jsonSettings.get('format'), - schemas: schemas, + format: workspace.getConfiguration('json').get('format'), + schemas: [], + } + }; + let schemaSettingsById: { [schemaId: string]: JSONSchemaSettings } = Object.create(null); + let collectSchemaSettings = (schemaSettings: JSONSchemaSettings[], rootPath?: string, fileMatchPrefix?: string) => { + for (let setting of schemaSettings) { + let url = getSchemaId(setting, rootPath); + if (!url) { + continue; + } + let schemaSetting = schemaSettingsById[url]; + if (!schemaSetting) { + schemaSetting = schemaSettingsById[url] = { url, fileMatch: [] }; + settings.json.schemas.push(schemaSetting); + } + let fileMatches = setting.fileMatch; + if (Array.isArray(fileMatches)) { + if (fileMatchPrefix) { + fileMatches = fileMatches.map(m => fileMatchPrefix + m); + } + schemaSetting.fileMatch.push(...fileMatches); + } + if (setting.schema) { + schemaSetting.schema = setting.schema; + } } }; - let settingsSchemas = jsonSettings.get('schemas'); - if (Array.isArray(settingsSchemas)) { - schemas.push(...settingsSchemas); - } + // merge global and folder settings. Qualify all file matches with the folder path. + let globalSettings = workspace.getConfiguration('json', null).get('schemas'); + if (Array.isArray(globalSettings)) { + collectSchemaSettings(globalSettings, workspace.rootPath); + } let folders = workspace.workspaceFolders; if (folders) { - folders.forEach(folder => { - let jsonConfig = workspace.getConfiguration('json', folder.uri); - let schemaConfigInfo = jsonConfig.inspect('schemas'); + for (let folder of folders) { + let folderUri = folder.uri; + let schemaConfigInfo = workspace.getConfiguration('json', folderUri).inspect('schemas'); let folderSchemas = schemaConfigInfo.workspaceFolderValue; if (Array.isArray(folderSchemas)) { - folderSchemas.forEach(schema => { - let url = schema.url; - if (!url && schema.schema) { - url = schema.schema.id; - } - if (url && url[0] === '.') { - url = Uri.file(path.normalize(path.join(folder.uri.fsPath, url))).toString(); - } - let fileMatch = schema.fileMatch; - if (fileMatch) { - fileMatch = fileMatch.map(m => folder.uri.toString() + '*' + m); - } - schemas.push({ url, fileMatch, schema: schema.schema }); - }); - }; - }); + let folderPath = folderUri.toString(); + if (folderPath[folderPath.length - 1] !== '/') { + folderPath = folderPath + '/'; + } + collectSchemaSettings(folderSchemas, folderUri.fsPath, folderPath + '*'); + } + } } return settings; } +function getSchemaId(schema: JSONSchemaSettings, rootPath?: string) { + let url = schema.url; + if (!url) { + if (schema.schema) { + url = schema.schema.id || `vscode://schemas/custom/${encodeURIComponent(hash(schema.schema).toString(16))}`; + } + } else if (rootPath && (url[0] === '.' || url[0] === '/')) { + url = Uri.file(path.normalize(path.join(rootPath, url))).toString(); + } + return url; +} + function getPackageInfo(context: ExtensionContext): IPackageInfo { let extensionPackage = require(context.asAbsolutePath('./package.json')); if (extensionPackage) { @@ -240,4 +289,4 @@ function getPackageInfo(context: ExtensionContext): IPackageInfo { }; } return null; -} \ No newline at end of file +} diff --git a/extensions/json/client/src/utils/hash.ts b/extensions/json/client/src/utils/hash.ts new file mode 100644 index 00000000000..e7149e43cd7 --- /dev/null +++ b/extensions/json/client/src/utils/hash.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +/** + * Return a hash value for an object. + */ +export function hash(obj: any, hashVal = 0): number { + switch (typeof obj) { + case 'object': + if (obj === null) { + return numberHash(349, hashVal); + } else if (Array.isArray(obj)) { + return arrayHash(obj, hashVal); + } + return objectHash(obj, hashVal); + case 'string': + return stringHash(obj, hashVal); + case 'boolean': + return booleanHash(obj, hashVal); + case 'number': + return numberHash(obj, hashVal); + case 'undefined': + return numberHash(obj, 937); + default: + return numberHash(obj, 617); + } +} + +function numberHash(val: number, initialHashVal: number): number { + return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32 +} + +function booleanHash(b: boolean, initialHashVal: number): number { + return numberHash(b ? 433 : 863, initialHashVal); +} + +function stringHash(s: string, hashVal: number) { + hashVal = numberHash(149417, hashVal); + for (let i = 0, length = s.length; i < length; i++) { + hashVal = numberHash(s.charCodeAt(i), hashVal); + } + return hashVal; +} + +function arrayHash(arr: any[], initialHashVal: number): number { + initialHashVal = numberHash(104579, initialHashVal); + return arr.reduce((hashVal, item) => hash(item, hashVal), initialHashVal); +} + +function objectHash(obj: any, initialHashVal: number): number { + initialHashVal = numberHash(181387, initialHashVal); + return Object.keys(obj).sort().reduce((hashVal, key) => { + hashVal = stringHash(key, hashVal); + return hash(obj[key], hashVal); + }, initialHashVal); +} diff --git a/extensions/json/client/tsconfig.json b/extensions/json/client/tsconfig.json index 31c07df105b..d2f8f6376fe 100644 --- a/extensions/json/client/tsconfig.json +++ b/extensions/json/client/tsconfig.json @@ -3,6 +3,7 @@ "target": "es5", "module": "commonjs", "outDir": "./out", + "noUnusedLocals": true, "lib": [ "es5", "es2015.promise" ] diff --git a/extensions/json/npm-shrinkwrap.json b/extensions/json/npm-shrinkwrap.json index 4caf64d28b7..a9e20b252be 100644 --- a/extensions/json/npm-shrinkwrap.json +++ b/extensions/json/npm-shrinkwrap.json @@ -13,24 +13,24 @@ "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.5.0-next.2", + "from": "vscode-jsonrpc@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz" }, "vscode-languageclient": { - "version": "3.4.0-next.17", - "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.0-next.17.tgz" + "version": "3.5.0-next.4", + "from": "vscode-languageclient@3.5.0-next.4", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0-next.4.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.5.0-next.5", + "from": "vscode-languageserver-protocol@3.5.0-next.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.5.0-next.2", + "from": "vscode-languageserver-types@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/json/package.json b/extensions/json/package.json index ba30bb1045d..3ba10afe8c6 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -133,11 +133,10 @@ }, "dependencies": { "vscode-extension-telemetry": "0.0.8", - "vscode-languageclient": "3.4.0-next.17", - "vscode-languageserver-protocol": "^3.1.1", + "vscode-languageclient": "3.5.0-next.4", "vscode-nls": "2.0.2" }, "devDependencies": { - "@types/node": "^6.0.51" + "@types/node": "7.0.43" } } diff --git a/extensions/json/server/.vscode/launch.json b/extensions/json/server/.vscode/launch.json index a09436fd912..764c1456f17 100644 --- a/extensions/json/server/.vscode/launch.json +++ b/extensions/json/server/.vscode/launch.json @@ -8,25 +8,25 @@ "request": "attach", "port": 6004, "sourceMaps": true, - "outDir": "${workspaceRoot}/out" + "outDir": "${workspaceFolder}/out" }, { "name": "Unit Tests", "type": "node", "request": "launch", - "program": "${workspaceRoot}/../../../node_modules/mocha/bin/_mocha", + "program": "${workspaceFolder}/../../../node_modules/mocha/bin/_mocha", "stopOnEntry": false, "args": [ "--timeout", "999999", "--colors" ], - "cwd": "${workspaceRoot}", + "cwd": "${workspaceFolder}", "runtimeExecutable": null, "runtimeArgs": [], "env": {}, "sourceMaps": true, - "outDir": "${workspaceRoot}/out" + "outDir": "${workspaceFolder}/out" } ] } \ No newline at end of file diff --git a/extensions/json/server/npm-shrinkwrap.json b/extensions/json/server/npm-shrinkwrap.json index 517efec26a3..daef1ef2fd8 100644 --- a/extensions/json/server/npm-shrinkwrap.json +++ b/extensions/json/server/npm-shrinkwrap.json @@ -43,29 +43,29 @@ "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.1.tgz" }, "vscode-json-languageservice": { - "version": "2.0.16", + "version": "3.0.0", "from": "vscode-json-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.16.tgz" + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-3.0.0.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.5.0-next.2", + "from": "vscode-jsonrpc@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz" }, "vscode-languageserver": { - "version": "3.4.0-next.6", - "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.0-next.6.tgz" + "version": "3.5.0-next.6", + "from": "vscode-languageserver@3.5.0-next.6", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.6.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.5.0-next.5", + "from": "vscode-languageserver-protocol@3.5.0-next.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.0.3 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.5.0-next.2", + "from": "vscode-languageserver-types@3.5.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index 3b6e892cc42..8a9d8db8e0b 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -10,13 +10,13 @@ "dependencies": { "jsonc-parser": "^1.0.0", "request-light": "^0.2.1", - "vscode-json-languageservice": "^2.0.16", - "vscode-languageserver": "3.4.0-next.6", - "vscode-languageserver-protocol": "^3.1.1", - "vscode-nls": "^2.0.2" + "vscode-json-languageservice": "3.0.0", + "vscode-languageserver": "3.5.0-next.6", + "vscode-nls": "^2.0.2", + "vscode-uri": "^1.0.1" }, "devDependencies": { - "@types/node": "^6.0.51" + "@types/node": "7.0.43" }, "scripts": { "compile": "gulp compile-extension:json-server", diff --git a/extensions/json/server/src/jsonServerMain.ts b/extensions/json/server/src/jsonServerMain.ts index 2fe428f717f..1706466ab61 100644 --- a/extensions/json/server/src/jsonServerMain.ts +++ b/extensions/json/server/src/jsonServerMain.ts @@ -10,12 +10,11 @@ import { DocumentRangeFormattingRequest, Disposable, ServerCapabilities } from 'vscode-languageserver'; -import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDescription } from 'request-light'; -import path = require('path'); import fs = require('fs'); -import URI from './utils/uri'; +import URI from 'vscode-uri'; import * as URL from 'url'; import Strings = require('./utils/strings'); import { JSONDocument, JSONSchema, LanguageSettings, getLanguageService } from 'vscode-json-languageservice'; @@ -36,6 +35,10 @@ namespace VSCodeContentRequest { export const type: RequestType = new RequestType('vscode/content'); } +namespace SchemaContentChangeNotification { + export const type: NotificationType = new NotificationType('json/schemaContent'); +} + // Create a connection for the server let connection: IConnection = createConnection(); @@ -54,9 +57,7 @@ let clientDynamicRegisterSupport = false; // After the server has started the client sends an initilize request. The server receives // in the passed params the rootPath of the workspace plus the client capabilities. -let workspaceRoot: URI; connection.onInitialize((params: InitializeParams): InitializeResult => { - workspaceRoot = URI.parse(params.rootPath); function hasClientCapability(...keys: string[]) { let c = params.capabilities; @@ -175,6 +176,11 @@ connection.onNotification(SchemaAssociationNotification.type, associations => { updateConfiguration(); }); +// A schema has changed +connection.onNotification(SchemaContentChangeNotification.type, uri => { + languageService.resetSchema(uri); +}); + function updateConfiguration() { let languageSettings: LanguageSettings = { validate: true, @@ -192,19 +198,12 @@ function updateConfiguration() { } } if (jsonConfigurationSettings) { - jsonConfigurationSettings.forEach(schema => { + jsonConfigurationSettings.forEach((schema, index) => { let uri = schema.url; if (!uri && schema.schema) { - uri = schema.schema.id; - } - if (!uri && schema.fileMatch) { - uri = 'vscode://schemas/custom/' + encodeURIComponent(schema.fileMatch.join('&')); + uri = schema.schema.id || `vscode://schemas/custom/${index}`; } if (uri) { - if (uri[0] === '.' && workspaceRoot) { - // workspace relative path - uri = URI.file(path.normalize(path.join(workspaceRoot.fsPath, uri))).toString(); - } languageSettings.schemas.push({ uri, fileMatch: schema.fileMatch, schema: schema.schema }); } }); @@ -321,5 +320,14 @@ connection.onRequest(DocumentColorRequest.type, params => { return []; }); +connection.onRequest(ColorPresentationRequest.type, params => { + let document = documents.get(params.textDocument.uri); + if (document) { + let jsonDocument = getJSONDocument(document); + return languageService.getColorPresentations(document, jsonDocument, params.color, params.range); + } + return []; +}); + // Listen on the connection connection.listen(); \ No newline at end of file diff --git a/extensions/json/server/src/utils/uri.ts b/extensions/json/server/src/utils/uri.ts deleted file mode 100644 index 5cce7590977..00000000000 --- a/extensions/json/server/src/utils/uri.ts +++ /dev/null @@ -1,351 +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'; - -function _encode(ch: string): string { - return '%' + ch.charCodeAt(0).toString(16).toUpperCase(); -} - -// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent -function encodeURIComponent2(str: string): string { - return encodeURIComponent(str).replace(/[!'()*]/g, _encode); -} - -function encodeNoop(str: string): string { - return str; -} - - -/** - * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. - * This class is a simple parser which creates the basic component paths - * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation - * and encoding. - * - * foo://example.com:8042/over/there?name=ferret#nose - * \_/ \______________/\_________/ \_________/ \__/ - * | | | | | - * scheme authority path query fragment - * | _____________________|__ - * / \ / \ - * urn:example:animal:ferret:nose - * - * - */ -export default class URI { - - private static _empty = ''; - private static _slash = '/'; - private static _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; - private static _driveLetterPath = /^\/[a-zA-z]:/; - private static _upperCaseDrive = /^(\/)?([A-Z]:)/; - - private _scheme: string; - private _authority: string; - private _path: string; - private _query: string; - private _fragment: string; - private _formatted: string; - private _fsPath: string; - - constructor() { - this._scheme = URI._empty; - this._authority = URI._empty; - this._path = URI._empty; - this._query = URI._empty; - this._fragment = URI._empty; - - this._formatted = null; - this._fsPath = null; - } - - /** - * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'. - * The part before the first colon. - */ - get scheme() { - return this._scheme; - } - - /** - * authority is the 'www.msft.com' part of 'http://www.msft.com/some/path?query#fragment'. - * The part between the first double slashes and the next slash. - */ - get authority() { - return this._authority; - } - - /** - * path is the '/some/path' part of 'http://www.msft.com/some/path?query#fragment'. - */ - get path() { - return this._path; - } - - /** - * query is the 'query' part of 'http://www.msft.com/some/path?query#fragment'. - */ - get query() { - return this._query; - } - - /** - * fragment is the 'fragment' part of 'http://www.msft.com/some/path?query#fragment'. - */ - get fragment() { - return this._fragment; - } - - // ---- filesystem path ----------------------- - - /** - * Returns a string representing the corresponding file system path of this URI. - * Will handle UNC paths and normalize windows drive letters to lower-case. Also - * uses the platform specific path separator. Will *not* validate the path for - * invalid characters and semantics. Will *not* look at the scheme of this URI. - */ - get fsPath() { - if (!this._fsPath) { - var value: string; - if (this._authority && this.scheme === 'file') { - // unc path: file://shares/c$/far/boo - value = `//${this._authority}${this._path}`; - } else if (URI._driveLetterPath.test(this._path)) { - // windows drive letter: file:///c:/far/boo - value = this._path[1].toLowerCase() + this._path.substr(2); - } else { - // other path - value = this._path; - } - if (process.platform === 'win32') { - value = value.replace(/\//g, '\\'); - } - this._fsPath = value; - } - return this._fsPath; - } - - // ---- modify to new ------------------------- - - public with(scheme: string, authority: string, path: string, query: string, fragment: string): URI { - var ret = new URI(); - ret._scheme = scheme || this.scheme; - ret._authority = authority || this.authority; - ret._path = path || this.path; - ret._query = query || this.query; - ret._fragment = fragment || this.fragment; - URI._validate(ret); - return ret; - } - - public withScheme(value: string): URI { - return this.with(value, undefined, undefined, undefined, undefined); - } - - public withAuthority(value: string): URI { - return this.with(undefined, value, undefined, undefined, undefined); - } - - public withPath(value: string): URI { - return this.with(undefined, undefined, value, undefined, undefined); - } - - public withQuery(value: string): URI { - return this.with(undefined, undefined, undefined, value, undefined); - } - - public withFragment(value: string): URI { - return this.with(undefined, undefined, undefined, undefined, value); - } - - // ---- parse & validate ------------------------ - - public static parse(value: string): URI { - const ret = new URI(); - const data = URI._parseComponents(value); - ret._scheme = data.scheme; - ret._authority = decodeURIComponent(data.authority); - ret._path = decodeURIComponent(data.path); - ret._query = decodeURIComponent(data.query); - ret._fragment = decodeURIComponent(data.fragment); - URI._validate(ret); - return ret; - } - - public static file(path: string): URI { - - const ret = new URI(); - ret._scheme = 'file'; - - // normalize to fwd-slashes - path = path.replace(/\\/g, URI._slash); - - // check for authority as used in UNC shares - // or use the path as given - if (path[0] === URI._slash && path[0] === path[1]) { - let idx = path.indexOf(URI._slash, 2); - if (idx === -1) { - ret._authority = path.substring(2); - } else { - ret._authority = path.substring(2, idx); - ret._path = path.substring(idx); - } - } else { - ret._path = path; - } - - // Ensure that path starts with a slash - // or that it is at least a slash - if (ret._path[0] !== URI._slash) { - ret._path = URI._slash + ret._path; - } - - URI._validate(ret); - - return ret; - } - - private static _parseComponents(value: string): UriComponents { - - const ret: UriComponents = { - scheme: URI._empty, - authority: URI._empty, - path: URI._empty, - query: URI._empty, - fragment: URI._empty, - }; - - const match = URI._regexp.exec(value); - if (match) { - ret.scheme = match[2] || ret.scheme; - ret.authority = match[4] || ret.authority; - ret.path = match[5] || ret.path; - ret.query = match[7] || ret.query; - ret.fragment = match[9] || ret.fragment; - } - return ret; - } - - public static create(scheme?: string, authority?: string, path?: string, query?: string, fragment?: string): URI { - return new URI().with(scheme, authority, path, query, fragment); - } - - private static _validate(ret: URI): void { - - // validation - // path, http://tools.ietf.org/html/rfc3986#section-3.3 - // If a URI contains an authority component, then the path component - // must either be empty or begin with a slash ("/") character. If a URI - // does not contain an authority component, then the path cannot begin - // with two slash characters ("//"). - if (ret.authority && ret.path && ret.path[0] !== '/') { - throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); - } - if (!ret.authority && ret.path.indexOf('//') === 0) { - throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); - } - } - - // ---- printing/externalize --------------------------- - - /** - * - * @param skipEncoding Do not encode the result, default is `false` - */ - public toString(skipEncoding: boolean = false): string { - if (!skipEncoding) { - if (!this._formatted) { - this._formatted = URI._asFormatted(this, false); - } - return this._formatted; - } else { - // we don't cache that - return URI._asFormatted(this, true); - } - } - - private static _asFormatted(uri: URI, skipEncoding: boolean): string { - - const encoder = !skipEncoding - ? encodeURIComponent2 - : encodeNoop; - - const parts: string[] = []; - - let { scheme, authority, path, query, fragment } = uri; - if (scheme) { - parts.push(scheme, ':'); - } - if (authority || scheme === 'file') { - parts.push('//'); - } - if (authority) { - authority = authority.toLowerCase(); - let idx = authority.indexOf(':'); - if (idx === -1) { - parts.push(encoder(authority)); - } else { - parts.push(encoder(authority.substr(0, idx)), authority.substr(idx)); - } - } - if (path) { - // lower-case windown drive letters in /C:/fff - const m = URI._upperCaseDrive.exec(path); - if (m) { - path = m[1] + m[2].toLowerCase() + path.substr(m[1].length + m[2].length); - } - - // encode every segement but not slashes - // make sure that # and ? are always encoded - // when occurring in paths - otherwise the result - // cannot be parsed back again - let lastIdx = 0; - while (true) { - let idx = path.indexOf(URI._slash, lastIdx); - if (idx === -1) { - parts.push(encoder(path.substring(lastIdx)).replace(/[#?]/, _encode)); - break; - } - parts.push(encoder(path.substring(lastIdx, idx)).replace(/[#?]/, _encode), URI._slash); - lastIdx = idx + 1; - }; - } - if (query) { - parts.push('?', encoder(query)); - } - if (fragment) { - parts.push('#', encoder(fragment)); - } - - return parts.join(URI._empty); - } - - public toJSON(): any { - return { - scheme: this.scheme, - authority: this.authority, - path: this.path, - fsPath: this.fsPath, - query: this.query, - fragment: this.fragment, - external: this.toString(), - $mid: 1 - }; - } -} - -interface UriComponents { - scheme: string; - authority: string; - path: string; - query: string; - fragment: string; -} - -interface UriState extends UriComponents { - $mid: number; - fsPath: string; - external: string; -} diff --git a/extensions/json/server/tsconfig.json b/extensions/json/server/tsconfig.json index deecf69b8b4..e085b24514b 100644 --- a/extensions/json/server/tsconfig.json +++ b/extensions/json/server/tsconfig.json @@ -5,6 +5,7 @@ "sourceMap": true, "sourceRoot": "../src", "outDir": "./out", + "noUnusedLocals": true, "lib": [ "es5", "es2015.promise" ] diff --git a/extensions/json/test/colorize-results/test_json.json b/extensions/json/test/colorize-results/test_json.json index 5f9b48b1ea0..f5295bcf70a 100644 --- a/extensions/json/test/colorize-results/test_json.json +++ b/extensions/json/test/colorize-results/test_json.json @@ -388,11 +388,11 @@ "c": "\\u0056", "t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json constant.character.escape.json", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { diff --git a/extensions/lua/language-configuration.json b/extensions/lua/language-configuration.json index 5a26730ed02..73618cfe630 100644 --- a/extensions/lua/language-configuration.json +++ b/extensions/lua/language-configuration.json @@ -21,5 +21,9 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] -} \ No newline at end of file + ], + "indentationRules": { + "increaseIndentPattern": "((\\b(else|function|then|do|repeat)\\b((?!\\b(end|until)\\b).)*)|(\\{\\s*))$", + "decreaseIndentPattern": "^\\s*((\\b(elseif|else|end|until)\\b)|(\\})|(\\)))" + } +} diff --git a/extensions/make/syntaxes/Makefile.json b/extensions/make/syntaxes/Makefile.json index 1574eed0229..b149c2c17b8 100644 --- a/extensions/make/syntaxes/Makefile.json +++ b/extensions/make/syntaxes/Makefile.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/fadeevab/make.tmbundle/commit/3c1e978bb465ffbf53a36639a69bae99ed047f08", + "version": "https://github.com/fadeevab/make.tmbundle/commit/43e1a67476dea3ddefbb4f0ee7901834b31b8bee", "fileTypes": [ "Makefile", "makefile", @@ -102,7 +102,7 @@ ] }, { - "begin": "^(?:(override)\\s*)?(define)\\s*([^\\s]+)\\s*(=|\\?=|:=|\\+=)?(?=\\s)", + "begin": "^\\s*(?:(override)\\s*)?(define)\\s*([^\\s]+)\\s*(=|\\?=|:=|\\+=)?(?=\\s)", "captures": { "1": { "name": "keyword.control.override.makefile" @@ -117,7 +117,7 @@ "name": "punctuation.separator.key-value.makefile" } }, - "end": "^(endef)\\b", + "end": "^\\s*(endef)\\b", "name": "meta.scope.conditional.makefile", "patterns": [ { @@ -194,7 +194,7 @@ ] }, { - "begin": "^(ifdef|ifndef)\\s*([^\\s]+)(?=\\s)", + "begin": "^\\s*(ifdef|ifndef)\\s*([^\\s]+)(?=\\s)", "captures": { "1": { "name": "keyword.control.$1.makefile" @@ -206,7 +206,7 @@ "name": "punctuation.separator.key-value.makefile" } }, - "end": "^(endif)\\b", + "end": "^\\s*(endif)\\b", "name": "meta.scope.conditional.makefile", "patterns": [ { @@ -224,13 +224,13 @@ ] }, { - "begin": "^(ifeq|ifneq)(?=\\s)", + "begin": "^\\s*(ifeq|ifneq)(?=\\s)", "captures": { "1": { "name": "keyword.control.$1.makefile" } }, - "end": "^(endif)\\b", + "end": "^\\s*(endif)\\b", "name": "meta.scope.conditional.makefile", "patterns": [ { @@ -247,7 +247,7 @@ ] }, { - "begin": "^else(?=\\s)", + "begin": "^\\s*else(?=\\s)", "beginCaptures": { "0": { "name": "keyword.control.else.makefile" @@ -293,6 +293,18 @@ } ] }, + "braces-interpolation": { + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "include": "#variables" + }, + { + "include": "#braces-interpolation" + } + ] + }, "recipe": { "begin": "^(?!\\t)([^:]*)(:)(?!\\=)", "beginCaptures": { @@ -408,22 +420,17 @@ "variables": { "patterns": [ { - "captures": { - "1": { - "name": "punctuation.definition.variable.makefile" - } - }, - "match": "(\\$?\\$)[@% { export default class LinkProvider implements vscode.DocumentLinkProvider { private linkPattern = /(\[[^\]]*\]\(\s*?)(((((?=.*\)\)+)|(?=.*\)\]+))[^\s\)]+?)|([^\s]+)))\)/g; - private referenceLinkPattern = /(\[([^\]]+)\]\[\s*?)(\w*)\]/g; - private definitionPattern = /^([\t ]*\[(\w+)\]:\s*)(\S+)/gm; + private referenceLinkPattern = /(\[([^\]]+)\]\[\s*?)([^\s\]]*?)\]/g; + private definitionPattern = /^([\t ]*\[([^\]]+)\]:\s*)(\S+)/gm; public provideDocumentLinks( document: vscode.TextDocument, @@ -52,11 +52,11 @@ export default class LinkProvider implements vscode.DocumentLinkProvider { const base = path.dirname(document.uri.fsPath); const text = document.getText(); - return this.privateInlineLinks(text, document, base) + return this.providerInlineLinks(text, document, base) .concat(this.provideReferenceLinks(text, document, base)); } - private privateInlineLinks( + private providerInlineLinks( text: string, document: vscode.TextDocument, base: string @@ -91,16 +91,19 @@ export default class LinkProvider implements vscode.DocumentLinkProvider { for (const match of matchAll(this.referenceLinkPattern, text)) { let linkStart: vscode.Position; let linkEnd: vscode.Position; - const reference = match[3]; + let reference = match[3]; if (reference) { // [text][ref] const pre = match[1]; const offset = (match.index || 0) + pre.length; linkStart = document.positionAt(offset); linkEnd = document.positionAt(offset + reference.length); - } else { // [ref][] + } else if (match[2]) { // [ref][] + reference = match[2]; const offset = (match.index || 0) + 1; - linkStart = document.positionAt(offset + 1); + linkStart = document.positionAt(offset); linkEnd = document.positionAt(offset + match[2].length); + } else { + continue; } try { @@ -108,7 +111,7 @@ export default class LinkProvider implements vscode.DocumentLinkProvider { if (link) { results.push(new vscode.DocumentLink( new vscode.Range(linkStart, linkEnd), - normalizeLink(document, link.link, base))); + vscode.Uri.parse(`command:_markdown.moveCursorToPosition?${encodeURIComponent(JSON.stringify([link.linkRange.start.line, link.linkRange.start.character]))}`))); } } catch (e) { // noop diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index d6dc45c7227..c34f12e44b8 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -102,12 +102,22 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.commands.registerCommand('markdown.showPreviewToSide', uri => showPreview(cspArbiter, uri, true))); context.subscriptions.push(vscode.commands.registerCommand('markdown.showSource', showSource)); + context.subscriptions.push(vscode.commands.registerCommand('_markdown.moveCursorToPosition', (line: number, character: number) => { + if (!vscode.window.activeTextEditor) { + return; + } + const position = new vscode.Position(line, character); + const selection = new vscode.Selection(position, position); + vscode.window.activeTextEditor.revealRange(selection); + vscode.window.activeTextEditor.selection = selection; + })); + context.subscriptions.push(vscode.commands.registerCommand('_markdown.revealLine', (uri, line) => { const sourceUri = vscode.Uri.parse(decodeURIComponent(uri)); logger.log('revealLine', { uri, sourceUri: sourceUri.toString(), line }); vscode.window.visibleTextEditors - .filter(editor => isMarkdownFile(editor.document) && editor.document.uri.fsPath === sourceUri.fsPath) + .filter(editor => isMarkdownFile(editor.document) && editor.document.uri.toString() === sourceUri.toString()) .forEach(editor => { const sourceLine = Math.floor(line); const fraction = line - sourceLine; @@ -243,13 +253,19 @@ function showPreview(cspArbiter: ExtensionContentSecurityPolicyArbiter, uri?: vs const thenable = vscode.commands.executeCommand('vscode.previewHtml', getMarkdownUri(resource), getViewColumn(sideBySide), - `Preview '${path.basename(resource.fsPath)}'`, + localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath)), { allowScripts: true, allowSvgs: cspArbiter.shouldAllowSvgsForResource(resource) }); if (telemetryReporter) { + /* __GDPR__ + "openPreview" : { + "where" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "how": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ telemetryReporter.sendTelemetryEvent('openPreview', { where: sideBySide ? 'sideBySide' : 'inPlace', how: (uri instanceof vscode.Uri) ? 'action' : 'pallete' @@ -286,7 +302,7 @@ function showSource(mdUri: vscode.Uri) { const docUri = vscode.Uri.parse(mdUri.query); for (const editor of vscode.window.visibleTextEditors) { - if (editor.document.uri.scheme === docUri.scheme && editor.document.uri.fsPath === docUri.fsPath) { + if (editor.document.uri.scheme === docUri.scheme && editor.document.uri.toString() === docUri.toString()) { return vscode.window.showTextDocument(editor.document, editor.viewColumn); } } diff --git a/extensions/markdown/src/markdownEngine.ts b/extensions/markdown/src/markdownEngine.ts index d41ced769e7..b2e41133330 100644 --- a/extensions/markdown/src/markdownEngine.ts +++ b/extensions/markdown/src/markdownEngine.ts @@ -35,7 +35,7 @@ export class MarkdownEngine { } } - private async getEngine(): Promise { + private async getEngine(resource: vscode.Uri): Promise { if (!this.md) { const hljs = await import('highlight.js'); const mdnh = await import('markdown-it-named-headers'); @@ -66,10 +66,10 @@ export class MarkdownEngine { this.addLinkValidator(this.md); } - const config = vscode.workspace.getConfiguration('markdown'); + const config = vscode.workspace.getConfiguration('markdown', resource); this.md.set({ - breaks: config.get('preview.breaks', false), - linkify: config.get('preview.linkify', true) + breaks: config.get('preview.breaks', false), + linkify: config.get('preview.linkify', true) }); return this.md; } @@ -94,14 +94,14 @@ export class MarkdownEngine { } this.currentDocument = document; this.firstLine = offset; - const engine = await this.getEngine(); + const engine = await this.getEngine(document); return engine.render(text); } public async parse(document: vscode.Uri, source: string): Promise { const { text, offset } = this.stripFrontmatter(source); this.currentDocument = document; - const engine = await this.getEngine(); + const engine = await this.getEngine(document); return engine.parse(text, {}).map(token => { if (token.map) { diff --git a/extensions/markdown/src/previewContentProvider.ts b/extensions/markdown/src/previewContentProvider.ts index a7eef2330a3..0a1c1702994 100644 --- a/extensions/markdown/src/previewContentProvider.ts +++ b/extensions/markdown/src/previewContentProvider.ts @@ -38,8 +38,8 @@ export function getMarkdownUri(uri: vscode.Uri) { } class MarkdownPreviewConfig { - public static getCurrentConfig() { - return new MarkdownPreviewConfig(); + public static getConfigForResource(resource: vscode.Uri) { + return new MarkdownPreviewConfig(resource); } public readonly scrollBeyondLastLine: boolean; @@ -56,9 +56,9 @@ class MarkdownPreviewConfig { public readonly fontFamily: string | undefined; public readonly styles: string[]; - private constructor() { - const editorConfig = vscode.workspace.getConfiguration('editor'); - const markdownConfig = vscode.workspace.getConfiguration('markdown'); + private constructor(resource: vscode.Uri) { + const editorConfig = vscode.workspace.getConfiguration('editor', resource); + const markdownConfig = vscode.workspace.getConfiguration('markdown', resource); const markdownEditorConfig = vscode.workspace.getConfiguration('[markdown]'); this.scrollBeyondLastLine = editorConfig.get('scrollBeyondLastLine', false); @@ -107,11 +107,41 @@ class MarkdownPreviewConfig { [key: string]: any; } +class PreviewConfigManager { + private previewConfigurationsForWorkspaces = new Map(); + + public loadAndCacheConfiguration( + resource: vscode.Uri + ) { + const config = MarkdownPreviewConfig.getConfigForResource(resource); + this.previewConfigurationsForWorkspaces.set(this.getKey(resource), config); + return config; + } + + public shouldUpdateConfiguration( + resource: vscode.Uri + ): boolean { + const key = this.getKey(resource); + const currentConfig = this.previewConfigurationsForWorkspaces.get(key); + const newConfig = MarkdownPreviewConfig.getConfigForResource(resource); + return (!currentConfig || !currentConfig.isEqualTo(newConfig)); + } + + private getKey( + resource: vscode.Uri + ): string { + const folder = vscode.workspace.getWorkspaceFolder(resource); + if (!folder) { + return ''; + } + return folder.uri.toString(); + } +} + export class MDDocumentContentProvider implements vscode.TextDocumentContentProvider { private _onDidChange = new vscode.EventEmitter(); private _waiting: boolean = false; - - private config: MarkdownPreviewConfig; + private previewConfigurations = new PreviewConfigManager(); private extraStyles: Array = []; private extraScripts: Array = []; @@ -121,9 +151,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv private context: vscode.ExtensionContext, private cspArbiter: ContentSecurityPolicyArbiter, private logger: Logger - ) { - this.config = MarkdownPreviewConfig.getCurrentConfig(); - } + ) { } public addScript(resource: vscode.Uri): void { this.extraScripts.push(resource); @@ -163,34 +191,34 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href)).toString(); } - private computeCustomStyleSheetIncludes(uri: vscode.Uri): string { - if (this.config.styles && Array.isArray(this.config.styles)) { - return this.config.styles.map((style) => { - return ``; + private computeCustomStyleSheetIncludes(resource: vscode.Uri, config: MarkdownPreviewConfig): string { + if (config.styles && Array.isArray(config.styles)) { + return config.styles.map(style => { + return ``; }).join('\n'); } return ''; } - private getSettingsOverrideStyles(nonce: string): string { + private getSettingsOverrideStyles(nonce: string, config: MarkdownPreviewConfig): string { return ``; } - private getStyles(resource: vscode.Uri, nonce: string): string { + private getStyles(resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfig): string { const baseStyles = [ this.getMediaPath('markdown.css'), this.getMediaPath('tomorrow.css') ].concat(this.extraStyles.map(resource => resource.toString())); return `${baseStyles.map(href => ``).join('\n')} - ${this.getSettingsOverrideStyles(nonce)} - ${this.computeCustomStyleSheetIncludes(resource)}`; + ${this.getSettingsOverrideStyles(nonce, config)} + ${this.computeCustomStyleSheetIncludes(resource, config)}`; } private getScripts(nonce: string): string { @@ -205,20 +233,20 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv let initialLine: number | undefined = undefined; const editor = vscode.window.activeTextEditor; - if (editor && editor.document.uri.fsPath === sourceUri.fsPath) { + if (editor && editor.document.uri.toString() === sourceUri.toString()) { initialLine = editor.selection.active.line; } const document = await vscode.workspace.openTextDocument(sourceUri); - this.config = MarkdownPreviewConfig.getCurrentConfig(); + const config = this.previewConfigurations.loadAndCacheConfiguration(sourceUri); const initialData = { previewUri: uri.toString(), source: sourceUri.toString(), line: initialLine, - scrollPreviewWithEditorSelection: this.config.scrollPreviewWithEditorSelection, - scrollEditorWithPreview: this.config.scrollEditorWithPreview, - doubleClickToSwitchToEditor: this.config.doubleClickToSwitchToEditor + scrollPreviewWithEditorSelection: config.scrollPreviewWithEditorSelection, + scrollEditorWithPreview: config.scrollEditorWithPreview, + doubleClickToSwitchToEditor: config.doubleClickToSwitchToEditor }; this.logger.log('provideTextDocumentContent', initialData); @@ -227,7 +255,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv const nonce = new Date().getTime() + '' + new Date().getMilliseconds(); const csp = this.getCspForResource(sourceUri, nonce); - const body = await this.engine.render(sourceUri, this.config.previewFrontMatter === 'hide', document.getText()); + const body = await this.engine.render(sourceUri, config.previewFrontMatter === 'hide', document.getText()); return ` @@ -236,10 +264,10 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv - ${this.getStyles(sourceUri, nonce)} + ${this.getStyles(sourceUri, nonce, config)} - + ${body}
${this.getScripts(nonce)} @@ -248,12 +276,11 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv } public updateConfiguration() { - const newConfig = MarkdownPreviewConfig.getCurrentConfig(); - if (!this.config.isEqualTo(newConfig)) { - this.config = newConfig; - // update all generated md documents - for (const document of vscode.workspace.textDocuments) { - if (document.uri.scheme === 'markdown') { + // update all generated md documents + for (const document of vscode.workspace.textDocuments) { + if (document.uri.scheme === 'markdown') { + const sourceUri = vscode.Uri.parse(document.uri.query); + if (this.previewConfigurations.shouldUpdateConfiguration(sourceUri)) { this.update(document.uri); } } diff --git a/extensions/markdown/src/tableOfContentsProvider.ts b/extensions/markdown/src/tableOfContentsProvider.ts index 26e64e4d837..c93dd25f6e7 100644 --- a/extensions/markdown/src/tableOfContentsProvider.ts +++ b/extensions/markdown/src/tableOfContentsProvider.ts @@ -79,7 +79,7 @@ export class TableOfContentsProvider { } private static getHeaderText(header: string): string { - return header.replace(/^\s*#+\s*(.*?)\s*\1*$/, (_, word) => `${word.trim()}`); + return header.replace(/^\s*#+\s*(.*?)\s*#*$/, (_, word) => word.trim()); } public static slugify(header: string): string { diff --git a/extensions/markdown/syntaxes/gulpfile.js b/extensions/markdown/syntaxes/gulpfile.js index e04c73fe1d1..9371f0ddc18 100644 --- a/extensions/markdown/syntaxes/gulpfile.js +++ b/extensions/markdown/syntaxes/gulpfile.js @@ -1,64 +1,69 @@ +// @ts-check + var gulp = require('gulp'); +var util = require("gulp-util"); var replace = require('gulp-replace'); var rename = require('gulp-rename'); const languages = [ - { name: 'css', identifiers: ['css', 'css.erb'], source: 'source.css' }, - { name: 'basic', identifiers: ['html', 'htm', 'shtml', 'xhtml', 'inc', 'tmpl', 'tpl'], source: 'text.html.basic' }, - { name: 'ini', identifiers: ['ini', 'conf'], source: 'source.ini' }, - { name: 'java', identifiers: ['java', 'bsh'], source: 'source.java' }, - { name: 'lua', identifiers: ['lua'], source: 'source.lua' }, - { name: 'makefile', identifiers: ['Makefile', 'makefile', 'GNUmakefile', 'OCamlMakefile'], source: 'source.makefile' }, - { name: 'perl', identifiers: ['perl', 'pl', 'pm', 'pod', 't', 'PL', 'psgi', 'vcl'], source: 'source.perl' }, - { name: 'r', identifiers: ['R', 'r', 's', 'S', 'Rprofile'], source: 'source.r' }, - { name: 'ruby', identifiers: ['ruby', 'rb', 'rbx', 'rjs', 'Rakefile', 'rake', 'cgi', 'fcgi', 'gemspec', 'irbrc', 'Capfile', 'ru', 'prawn', 'Cheffile', 'Gemfile', 'Guardfile', 'Hobofile', 'Vagrantfile', 'Appraisals', 'Rantfile', 'Berksfile', 'Berksfile.lock', 'Thorfile', 'Puppetfile'], source: 'source.ruby' }, + { name: 'css', language: 'css', identifiers: ['css', 'css.erb'], source: 'source.css' }, + { name: 'basic', language: 'html', identifiers: ['html', 'htm', 'shtml', 'xhtml', 'inc', 'tmpl', 'tpl'], source: 'text.html.basic' }, + { name: 'ini', language: 'ini', identifiers: ['ini', 'conf'], source: 'source.ini' }, + { name: 'java', language: 'java', identifiers: ['java', 'bsh'], source: 'source.java' }, + { name: 'lua', language: 'lua', identifiers: ['lua'], source: 'source.lua' }, + { name: 'makefile', language: 'makefile', identifiers: ['Makefile', 'makefile', 'GNUmakefile', 'OCamlMakefile'], source: 'source.makefile' }, + { name: 'perl', language: 'perl', identifiers: ['perl', 'pl', 'pm', 'pod', 't', 'PL', 'psgi', 'vcl'], source: 'source.perl' }, + { name: 'r', language: 'r', identifiers: ['R', 'r', 's', 'S', 'Rprofile'], source: 'source.r' }, + { name: 'ruby', language: 'ruby', identifiers: ['ruby', 'rb', 'rbx', 'rjs', 'Rakefile', 'rake', 'cgi', 'fcgi', 'gemspec', 'irbrc', 'Capfile', 'ru', 'prawn', 'Cheffile', 'Gemfile', 'Guardfile', 'Hobofile', 'Vagrantfile', 'Appraisals', 'Rantfile', 'Berksfile', 'Berksfile.lock', 'Thorfile', 'Puppetfile'], source: 'source.ruby' }, // Left to its own devices, the PHP grammar will match HTML as a combination of operators // and constants. Therefore, HTML must take precedence over PHP in order to get proper // syntax highlighting. - { name: 'php', identifiers: ['php', 'php3', 'php4', 'php5', 'phpt', 'phtml', 'aw', 'ctp'], source: ['text.html.basic', 'text.html.php#language'] }, - { name: 'sql', identifiers: ['sql', 'ddl', 'dml'], source: 'source.sql' }, - { name: 'vs_net', identifiers: ['vb'], source: 'source.asp.vb.net' }, - { name: 'xml', identifiers: ['xml', 'xsd', 'tld', 'jsp', 'pt', 'cpt', 'dtml', 'rss', 'opml'], source: 'text.xml' }, - { name: 'xsl', identifiers: ['xsl', 'xslt'], source: 'text.xml.xsl' }, - { name: 'yaml', identifiers: ['yaml', 'yml'], source: 'source.yaml' }, - { name: 'dosbatch', identifiers: ['bat', 'batch'], source: 'source.dosbatch' }, - { name: 'clojure', identifiers: ['clj', 'cljs', 'clojure'], source: 'source.clojure' }, - { name: 'coffee', identifiers: ['coffee', 'Cakefile', 'coffee.erb'], source: 'source.coffee' }, - { name: 'c', identifiers: ['c', 'h'], source: 'source.c' }, - { name: 'cpp', identifiers: ['cpp', 'c\\+\\+', 'cxx'], source: 'source.cpp' }, - { name: 'diff', identifiers: ['patch', 'diff', 'rej'], source: 'source.diff' }, - { name: 'dockerfile', identifiers: ['dockerfile', 'Dockerfile'], source: 'source.dockerfile' }, + { name: 'php', language: 'php', identifiers: ['php', 'php3', 'php4', 'php5', 'phpt', 'phtml', 'aw', 'ctp'], source: ['text.html.basic', 'text.html.php#language'] }, + { name: 'sql', language: 'sql', identifiers: ['sql', 'ddl', 'dml'], source: 'source.sql' }, + { name: 'vs_net', language: 'vs_net', identifiers: ['vb'], source: 'source.asp.vb.net' }, + { name: 'xml', language: 'xml', identifiers: ['xml', 'xsd', 'tld', 'jsp', 'pt', 'cpt', 'dtml', 'rss', 'opml'], source: 'text.xml' }, + { name: 'xsl', language: 'xsl', identifiers: ['xsl', 'xslt'], source: 'text.xml.xsl' }, + { name: 'yaml', language: 'yaml', identifiers: ['yaml', 'yml'], source: 'source.yaml' }, + { name: 'dosbatch', language: 'dosbatch', identifiers: ['bat', 'batch'], source: 'source.dosbatch' }, + { name: 'clojure', language: 'clojure', identifiers: ['clj', 'cljs', 'clojure'], source: 'source.clojure' }, + { name: 'coffee', language: 'coffee', identifiers: ['coffee', 'Cakefile', 'coffee.erb'], source: 'source.coffee' }, + { name: 'c', language: 'c', identifiers: ['c', 'h'], source: 'source.c' }, + { name: 'cpp', language: 'cpp', identifiers: ['cpp', 'c\\+\\+', 'cxx'], source: 'source.cpp' }, + { name: 'diff', language: 'diff', identifiers: ['patch', 'diff', 'rej'], source: 'source.diff' }, + { name: 'dockerfile', language: 'dockerfile', identifiers: ['dockerfile', 'Dockerfile'], source: 'source.dockerfile' }, { name: 'git_commit', identifiers: ['COMMIT_EDITMSG', 'MERGE_MSG'], source: 'text.git-commit' }, { name: 'git_rebase', identifiers: ['git-rebase-todo'], source: 'text.git-rebase' }, - { name: 'go', identifiers: ['go', 'golang'], source: 'source.go' }, - { name: 'groovy', identifiers: ['groovy', 'gvy'], source: 'source.groovy' }, - { name: 'jade', identifiers: ['jade', 'pug'], source: 'text.jade' }, + { name: 'go', language: 'go', identifiers: ['go', 'golang'], source: 'source.go' }, + { name: 'groovy', language: 'groovy', identifiers: ['groovy', 'gvy'], source: 'source.groovy' }, + { name: 'jade', language: 'jade', identifiers: ['jade', 'pug'], source: 'text.jade' }, - { name: 'js', identifiers: ['js', 'jsx', 'javascript', 'es6', 'mjs'], source: 'source.js' }, + { name: 'js', language: 'javascript', identifiers: ['js', 'jsx', 'javascript', 'es6', 'mjs'], source: 'source.js' }, { name: 'js_regexp', identifiers: ['regexp'], source: 'source.js.regexp' }, - { name: 'json', identifiers: ['json', 'sublime-settings', 'sublime-menu', 'sublime-keymap', 'sublime-mousemap', 'sublime-theme', 'sublime-build', 'sublime-project', 'sublime-completions'], source: 'source.json' }, - { name: 'less', identifiers: ['less'], source: 'source.css.less' }, - { name: 'objc', identifiers: ['objectivec', 'objective-c', 'mm', 'objc', 'obj-c', 'm', 'h'], source: 'source.objc' }, - { name: 'scss', identifiers: ['scss'], source: 'source.css.scss' }, + { name: 'json', language: 'json', identifiers: ['json', 'sublime-settings', 'sublime-menu', 'sublime-keymap', 'sublime-mousemap', 'sublime-theme', 'sublime-build', 'sublime-project', 'sublime-completions'], source: 'source.json' }, + { name: 'less', language: 'less', identifiers: ['less'], source: 'source.css.less' }, + { name: 'objc', language: 'objc', identifiers: ['objectivec', 'objective-c', 'mm', 'objc', 'obj-c', 'm', 'h'], source: 'source.objc' }, + { name: 'scss', language: 'scss', identifiers: ['scss'], source: 'source.css.scss' }, - { name: 'perl6', identifiers: ['perl6', 'p6', 'pl6', 'pm6', 'nqp'], source: 'source.perl.6' }, - { name: 'powershell', identifiers: ['powershell', 'ps1', 'psm1', 'psd1'], source: 'source.powershell' }, - { name: 'python', identifiers: ['python', 'py', 'py3', 'rpy', 'pyw', 'cpy', 'SConstruct', 'Sconstruct', 'sconstruct', 'SConscript', 'gyp', 'gypi'], source: 'source.python' }, + { name: 'perl6', language: 'perl6', identifiers: ['perl6', 'p6', 'pl6', 'pm6', 'nqp'], source: 'source.perl.6' }, + { name: 'powershell', language: 'powershell', identifiers: ['powershell', 'ps1', 'psm1', 'psd1'], source: 'source.powershell' }, + { name: 'python', language: 'python', identifiers: ['python', 'py', 'py3', 'rpy', 'pyw', 'cpy', 'SConstruct', 'Sconstruct', 'sconstruct', 'SConscript', 'gyp', 'gypi'], source: 'source.python' }, { name: 'regexp_python', identifiers: ['re'], source: 'source.regexp.python' }, - { name: 'rust', identifiers: ['rust', 'rs'], source: 'source.rust' }, - { name: 'scala', identifiers: ['scala', 'sbt'], source: 'source.scala' }, - { name: 'shell', identifiers: ['shell', 'sh', 'bash', 'zsh', 'bashrc', 'bash_profile', 'bash_login', 'profile', 'bash_logout', '.textmate_init'], source: 'source.shell' }, - { name: 'ts', identifiers: ['typescript', 'ts'], source: 'source.ts' }, - { name: 'tsx', identifiers: ['tsx'], source: 'source.tsx' }, - { name: 'csharp', identifiers: ['cs', 'csharp', 'c#'], source: 'source.cs' }, - { name: 'fsharp', identifiers: ['fs', 'fsharp', 'f#'], source: 'source.fsharp' }, + { name: 'rust', language: 'rust', identifiers: ['rust', 'rs'], source: 'source.rust' }, + { name: 'scala', language: 'scala', identifiers: ['scala', 'sbt'], source: 'source.scala' }, + { name: 'shell', language: 'shellscript', identifiers: ['shell', 'sh', 'bash', 'zsh', 'bashrc', 'bash_profile', 'bash_login', 'profile', 'bash_logout', '.textmate_init'], source: 'source.shell' }, + { name: 'ts', language: 'typescript', identifiers: ['typescript', 'ts'], source: 'source.ts' }, + { name: 'tsx', language: 'typescriptreact', identifiers: ['tsx'], source: 'source.tsx' }, + { name: 'csharp', language: 'csharp', identifiers: ['cs', 'csharp', 'c#'], source: 'source.cs' }, + { name: 'fsharp', language: 'fsharp', identifiers: ['fs', 'fsharp', 'f#'], source: 'source.fsharp' }, ]; -const fencedCodeBlockDefinition = (name, identifiers, sourceScope) => { +const fencedCodeBlockDefinition = (name, identifiers, sourceScope, language) => { if (!Array.isArray(sourceScope)) { sourceScope = [sourceScope]; } + language = language || name + const scopes = sourceScope.map(scope => ` include @@ -106,6 +111,8 @@ const fencedCodeBlockDefinition = (name, identifiers, sourceScope) => { (^|\\G)(\\s*)(.*) while (^|\\G)(?!\\s*([\`~]{3,})\\s*$) + contentName + meta.embedded.block.${language} patterns ${indent(4, scopes)} @@ -129,7 +136,7 @@ const fencedCodeBlockInclude = (name) => const fencedCodeBlockDefinitions = () => languages - .map(language => fencedCodeBlockDefinition(language.name, language.identifiers, language.source)) + .map(language => fencedCodeBlockDefinition(language.name, language.identifiers, language.source, language.language)) .join('\n'); @@ -147,3 +154,11 @@ gulp.task('default', function () { .pipe(rename('markdown.tmLanguage')) .pipe(gulp.dest('.')); }); + +gulp.task('embedded', function () { + const out = {} + for (const lang of languages.filter(x => x.language)) { + out['meta.embedded.block.' +lang.language] = lang.language; + } + util.log(JSON.stringify(out, undefined, 4)); +}); diff --git a/extensions/markdown/syntaxes/markdown.tmLanguage b/extensions/markdown/syntaxes/markdown.tmLanguage index d9429dcf6a0..5e7d26dea2b 100644 --- a/extensions/markdown/syntaxes/markdown.tmLanguage +++ b/extensions/markdown/syntaxes/markdown.tmLanguage @@ -354,11 +354,11 @@ while - ^\s*(?!</(script|style|pre)>) + ^(?!.*</(script|style|pre)>) end - (?=</(script|style|pre)>) + (?=.*</(script|style|pre)>) begin @@ -626,6 +626,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.css patterns @@ -677,6 +679,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.html patterns @@ -728,6 +732,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.ini patterns @@ -779,6 +785,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.java patterns @@ -830,6 +838,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.lua patterns @@ -881,6 +891,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.makefile patterns @@ -932,6 +944,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.perl patterns @@ -983,6 +997,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.r patterns @@ -1034,6 +1050,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.ruby patterns @@ -1085,6 +1103,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.php patterns @@ -1140,6 +1160,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.sql patterns @@ -1191,6 +1213,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.vs_net patterns @@ -1242,6 +1266,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.xml patterns @@ -1293,6 +1319,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.xsl patterns @@ -1344,6 +1372,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.yaml patterns @@ -1395,6 +1425,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.dosbatch patterns @@ -1446,6 +1478,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.clojure patterns @@ -1497,6 +1531,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.coffee patterns @@ -1548,6 +1584,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.c patterns @@ -1599,6 +1637,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.cpp patterns @@ -1650,6 +1690,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.diff patterns @@ -1701,6 +1743,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.dockerfile patterns @@ -1752,6 +1796,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.git_commit patterns @@ -1803,6 +1849,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.git_rebase patterns @@ -1854,6 +1902,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.go patterns @@ -1905,6 +1955,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.groovy patterns @@ -1956,6 +2008,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.jade patterns @@ -2007,6 +2061,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.javascript patterns @@ -2058,6 +2114,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.js_regexp patterns @@ -2109,6 +2167,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.json patterns @@ -2160,6 +2220,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.less patterns @@ -2211,6 +2273,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.objc patterns @@ -2262,6 +2326,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.scss patterns @@ -2313,6 +2379,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.perl6 patterns @@ -2364,6 +2432,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.powershell patterns @@ -2415,6 +2485,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.python patterns @@ -2466,6 +2538,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.regexp_python patterns @@ -2517,6 +2591,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.rust patterns @@ -2568,6 +2644,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.scala patterns @@ -2619,6 +2697,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.shellscript patterns @@ -2670,6 +2750,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.typescript patterns @@ -2721,6 +2803,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.typescriptreact patterns @@ -2772,6 +2856,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.csharp patterns @@ -2823,6 +2909,8 @@ (^|\G)(\s*)(.*) while (^|\G)(?!\s*([`~]{3,})\s*$) + contentName + meta.embedded.block.fsharp patterns @@ -3603,6 +3691,8 @@ frontMatter + contentName + meta.embedded.block.frontmatter begin \A-{3}\s*$ while diff --git a/extensions/markdown/syntaxes/markdown.tmLanguage.base b/extensions/markdown/syntaxes/markdown.tmLanguage.base index 4783abf8b0f..d501f50a86f 100644 --- a/extensions/markdown/syntaxes/markdown.tmLanguage.base +++ b/extensions/markdown/syntaxes/markdown.tmLanguage.base @@ -179,11 +179,11 @@ while - ^\s*(?!</(script|style|pre)>) + ^(?!.*</(script|style|pre)>) end - (?=</(script|style|pre)>) + (?=.*</(script|style|pre)>) begin @@ -1181,6 +1181,8 @@ frontMatter + contentName + meta.embedded.block.frontmatter begin \A-{3}\s*$ while diff --git a/extensions/markdown/test/colorize-fixtures/test-33886.md b/extensions/markdown/test/colorize-fixtures/test-33886.md new file mode 100644 index 00000000000..472c4a76498 --- /dev/null +++ b/extensions/markdown/test/colorize-fixtures/test-33886.md @@ -0,0 +1,13 @@ +# h + +

+# a
+
+ +# h + +
+# a
+a
+ +# h \ No newline at end of file diff --git a/extensions/markdown/test/colorize-results/test-33886_md.json b/extensions/markdown/test/colorize-results/test-33886_md.json new file mode 100644 index 00000000000..ed8d6a43aaa --- /dev/null +++ b/extensions/markdown/test/colorize-results/test-33886_md.json @@ -0,0 +1,332 @@ +[ + { + "c": "#", + "t": "text.html.markdown markup.heading.markdown punctuation.definition.heading.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": " ", + "t": "text.html.markdown markup.heading.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": "h", + "t": "text.html.markdown markup.heading.markdown entity.name.section.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": "<", + "t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.begin.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "pre", + "t": "text.html.markdown meta.tag.block.any.html entity.name.tag.block.any.html", + "r": { + "dark_plus": "entity.name.tag: #569CD6", + "light_plus": "entity.name.tag: #800000", + "dark_vs": "entity.name.tag: #569CD6", + "light_vs": "entity.name.tag: #800000", + "hc_black": "entity.name.tag: #569CD6" + } + }, + { + "c": ">", + "t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "<", + "t": "text.html.markdown meta.tag.inline.any.html punctuation.definition.tag.begin.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "code", + "t": "text.html.markdown meta.tag.inline.any.html entity.name.tag.inline.any.html", + "r": { + "dark_plus": "entity.name.tag: #569CD6", + "light_plus": "entity.name.tag: #800000", + "dark_vs": "entity.name.tag: #569CD6", + "light_vs": "entity.name.tag: #800000", + "hc_black": "entity.name.tag: #569CD6" + } + }, + { + "c": ">", + "t": "text.html.markdown meta.tag.inline.any.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "# a", + "t": "text.html.markdown", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "", + "t": "text.html.markdown meta.paragraph.markdown meta.tag.inline.any.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "", + "t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "#", + "t": "text.html.markdown markup.heading.markdown punctuation.definition.heading.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": " ", + "t": "text.html.markdown markup.heading.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": "h", + "t": "text.html.markdown markup.heading.markdown entity.name.section.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": "<", + "t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.begin.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "pre", + "t": "text.html.markdown meta.tag.block.any.html entity.name.tag.block.any.html", + "r": { + "dark_plus": "entity.name.tag: #569CD6", + "light_plus": "entity.name.tag: #800000", + "dark_vs": "entity.name.tag: #569CD6", + "light_vs": "entity.name.tag: #800000", + "hc_black": "entity.name.tag: #569CD6" + } + }, + { + "c": ">", + "t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "# a", + "t": "text.html.markdown", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "a", + "t": "text.html.markdown meta.paragraph.markdown", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "", + "t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "#", + "t": "text.html.markdown markup.heading.markdown punctuation.definition.heading.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": " ", + "t": "text.html.markdown markup.heading.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + }, + { + "c": "h", + "t": "text.html.markdown markup.heading.markdown entity.name.section.markdown", + "r": { + "dark_plus": "markup.heading: #569CD6", + "light_plus": "markup.heading: #800000", + "dark_vs": "markup.heading: #569CD6", + "light_vs": "markup.heading: #800000", + "hc_black": "markup.heading: #6796E6" + } + } +] \ No newline at end of file diff --git a/extensions/markdown/test/colorize-results/test_md.json b/extensions/markdown/test/colorize-results/test_md.json index c40d5536256..c07d8316525 100644 --- a/extensions/markdown/test/colorize-results/test_md.json +++ b/extensions/markdown/test/colorize-results/test_md.json @@ -652,11 +652,11 @@ "c": " ", "t": "text.html.markdown meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -674,11 +674,11 @@ "c": "=", "t": "text.html.markdown meta.embedded.block.html meta.tag.metadata.script.html", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -729,22 +729,22 @@ "c": " function( x: int ) { return x*x; }", "t": "text.html.markdown meta.embedded.block.html source.unknown", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.markdown meta.embedded.block.html source.unknown", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1026,11 +1026,11 @@ "c": " ", "t": "text.html.markdown meta.embedded.block.html source.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1048,33 +1048,33 @@ "c": " ", "t": "text.html.markdown meta.embedded.block.html source.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1092,22 +1092,22 @@ "c": ":", "t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css punctuation.separator.key-value.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1147,33 +1147,33 @@ "c": " ", "t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css punctuation.section.property-list.end.bracket.curly.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.markdown meta.embedded.block.html source.css", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1541,7 +1541,7 @@ }, { "c": "`", - "t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.markdown punctuation.definition.raw.markdown", + "t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.string.markdown punctuation.definition.raw.markdown", "r": { "dark_plus": "markup.inline.raw: #CE9178", "light_plus": "markup.inline.raw: #800000", @@ -1552,7 +1552,7 @@ }, { "c": "code()", - "t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.markdown", + "t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.string.markdown", "r": { "dark_plus": "markup.inline.raw: #CE9178", "light_plus": "markup.inline.raw: #800000", @@ -1563,7 +1563,7 @@ }, { "c": "`", - "t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.markdown punctuation.definition.raw.markdown", + "t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.string.markdown punctuation.definition.raw.markdown", "r": { "dark_plus": "markup.inline.raw: #CE9178", "light_plus": "markup.inline.raw: #800000", diff --git a/extensions/markdown/tsconfig.json b/extensions/markdown/tsconfig.json index d4e37635588..c85599b62fe 100644 --- a/extensions/markdown/tsconfig.json +++ b/extensions/markdown/tsconfig.json @@ -9,11 +9,11 @@ ], "outDir": "./out", "sourceMap": true, - "strictNullChecks": true, "noImplicitAny": true, "noImplicitReturns": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 4ecece640ea..38a33087345 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -88,6 +88,6 @@ "vscode-nls": "^2.0.2" }, "devDependencies": { - "@types/node": "^7.0.4" + "@types/node": "8.0.33" } } \ No newline at end of file diff --git a/extensions/merge-conflict/src/codelensProvider.ts b/extensions/merge-conflict/src/codelensProvider.ts index ca54a189a7a..32b1cb9e381 100644 --- a/extensions/merge-conflict/src/codelensProvider.ts +++ b/extensions/merge-conflict/src/codelensProvider.ts @@ -13,7 +13,7 @@ export default class MergeConflictCodeLensProvider implements vscode.CodeLensPro private config: interfaces.IExtensionConfiguration; private tracker: interfaces.IDocumentMergeConflictTracker; - constructor(private context: vscode.ExtensionContext, trackerService: interfaces.IDocumentMergeConflictTrackerService) { + constructor(trackerService: interfaces.IDocumentMergeConflictTrackerService) { this.tracker = trackerService.createTracker('codelens'); } @@ -46,7 +46,7 @@ export default class MergeConflictCodeLensProvider implements vscode.CodeLensPro } } - async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { + async provideCodeLenses(document: vscode.TextDocument, _token: vscode.CancellationToken): Promise { if (!this.config || !this.config.enableCodeLens) { return null; diff --git a/extensions/merge-conflict/src/commandHandler.ts b/extensions/merge-conflict/src/commandHandler.ts index 23fca8d15f5..1a737cfaf3f 100644 --- a/extensions/merge-conflict/src/commandHandler.ts +++ b/extensions/merge-conflict/src/commandHandler.ts @@ -24,7 +24,7 @@ export default class CommandHandler implements vscode.Disposable { private disposables: vscode.Disposable[] = []; private tracker: interfaces.IDocumentMergeConflictTracker; - constructor(private context: vscode.ExtensionContext, trackerService: interfaces.IDocumentMergeConflictTrackerService) { + constructor(trackerService: interfaces.IDocumentMergeConflictTrackerService) { this.tracker = trackerService.createTracker('commands'); } @@ -43,38 +43,38 @@ export default class CommandHandler implements vscode.Disposable { ); } - private registerTextEditorCommand(command: string, cb: (editor: vscode.TextEditor, ...args) => Promise) { + private registerTextEditorCommand(command: string, cb: (editor: vscode.TextEditor, ...args: any[]) => Promise) { return vscode.commands.registerCommand(command, (...args) => { const editor = vscode.window.activeTextEditor; return editor && cb.call(this, editor, ...args); }); } - acceptCurrent(editor: vscode.TextEditor, ...args): Promise { + acceptCurrent(editor: vscode.TextEditor, ...args: any[]): Promise { return this.accept(interfaces.CommitType.Current, editor, ...args); } - acceptIncoming(editor: vscode.TextEditor, ...args): Promise { + acceptIncoming(editor: vscode.TextEditor, ...args: any[]): Promise { return this.accept(interfaces.CommitType.Incoming, editor, ...args); } - acceptBoth(editor: vscode.TextEditor, ...args): Promise { + acceptBoth(editor: vscode.TextEditor, ...args: any[]): Promise { return this.accept(interfaces.CommitType.Both, editor, ...args); } - acceptAllCurrent(editor: vscode.TextEditor, ...args): Promise { + acceptAllCurrent(editor: vscode.TextEditor): Promise { return this.acceptAll(interfaces.CommitType.Current, editor); } - acceptAllIncoming(editor: vscode.TextEditor, ...args): Promise { + acceptAllIncoming(editor: vscode.TextEditor): Promise { return this.acceptAll(interfaces.CommitType.Incoming, editor); } - acceptAllBoth(editor: vscode.TextEditor, ...args): Promise { + acceptAllBoth(editor: vscode.TextEditor): Promise { return this.acceptAll(interfaces.CommitType.Both, editor); } - async compare(editor: vscode.TextEditor, conflict: interfaces.IDocumentMergeConflict | null, ...args) { + async compare(editor: vscode.TextEditor, conflict: interfaces.IDocumentMergeConflict | null) { const fileName = path.basename(editor.document.uri.fsPath); // No conflict, command executed from command palette @@ -102,15 +102,15 @@ export default class CommandHandler implements vscode.Disposable { vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title); } - navigateNext(editor: vscode.TextEditor, ...args): Promise { + navigateNext(editor: vscode.TextEditor): Promise { return this.navigate(editor, NavigationDirection.Forwards); } - navigatePrevious(editor: vscode.TextEditor, ...args): Promise { + navigatePrevious(editor: vscode.TextEditor): Promise { return this.navigate(editor, NavigationDirection.Backwards); } - async acceptSelection(editor: vscode.TextEditor, ...args): Promise { + async acceptSelection(editor: vscode.TextEditor): Promise { let conflict = await this.findConflictContainingSelection(editor); if (!conflict) { @@ -175,7 +175,7 @@ export default class CommandHandler implements vscode.Disposable { editor.revealRange(navigationResult.conflict.range, vscode.TextEditorRevealType.Default); } - private async accept(type: interfaces.CommitType, editor: vscode.TextEditor, ...args): Promise { + private async accept(type: interfaces.CommitType, editor: vscode.TextEditor, ...args: any[]): Promise { let conflict: interfaces.IDocumentMergeConflict | null; @@ -257,7 +257,7 @@ export default class CommandHandler implements vscode.Disposable { }; } - let predicate: (conflict) => boolean; + let predicate: (_conflict: any) => boolean; let fallback: () => interfaces.IDocumentMergeConflict; if (direction === NavigationDirection.Forwards) { diff --git a/extensions/merge-conflict/src/contentProvider.ts b/extensions/merge-conflict/src/contentProvider.ts index 446ab052f22..37e5923e135 100644 --- a/extensions/merge-conflict/src/contentProvider.ts +++ b/extensions/merge-conflict/src/contentProvider.ts @@ -4,21 +4,11 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; import * as vscode from 'vscode'; -import * as interfaces from './interfaces'; export default class MergeConflictContentProvider implements vscode.TextDocumentContentProvider, vscode.Disposable { static scheme = 'merge-conflict.conflict-diff'; - constructor(private context: vscode.ExtensionContext) { - } - - begin(config: interfaces.IExtensionConfiguration) { - this.context.subscriptions.push( - vscode.workspace.registerTextDocumentContentProvider(MergeConflictContentProvider.scheme, this) - ); - } - dispose() { } diff --git a/extensions/merge-conflict/src/delayer.ts b/extensions/merge-conflict/src/delayer.ts index 59ec77ed503..de74b6033ee 100644 --- a/extensions/merge-conflict/src/delayer.ts +++ b/extensions/merge-conflict/src/delayer.ts @@ -13,7 +13,7 @@ export class Delayer { public defaultDelay: number; private timeout: any; // Timer private completionPromise: Promise | null; - private onSuccess: ((value?: T | Thenable | null) => void) | null; + private onSuccess: ((value?: T | Thenable | undefined) => void) | null; private task: ITask | null; constructor(defaultDelay: number) { @@ -45,7 +45,7 @@ export class Delayer { if (delay >= 0 || this.timeout === null) { this.timeout = setTimeout(() => { this.timeout = null; - this.onSuccess!(null); + this.onSuccess!(undefined); }, delay >= 0 ? delay : this.defaultDelay); } @@ -58,7 +58,7 @@ export class Delayer { } this.cancelTimeout(); let result = this.completionPromise; - this.onSuccess!(null); + this.onSuccess!(undefined); return result; } diff --git a/extensions/merge-conflict/src/documentMergeConflict.ts b/extensions/merge-conflict/src/documentMergeConflict.ts index f1714c98163..3bf94a16ea7 100644 --- a/extensions/merge-conflict/src/documentMergeConflict.ts +++ b/extensions/merge-conflict/src/documentMergeConflict.ts @@ -13,7 +13,7 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict public commonAncestors: interfaces.IMergeRegion[]; public splitter: vscode.Range; - constructor(document: vscode.TextDocument, descriptor: interfaces.IDocumentMergeConflictDescriptor) { + constructor(descriptor: interfaces.IDocumentMergeConflictDescriptor) { this.range = descriptor.range; this.current = descriptor.current; this.incoming = descriptor.incoming; @@ -27,7 +27,7 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict this.applyEdit(type, editor, edit); return Promise.resolve(true); - }; + } return editor.edit((edit) => this.applyEdit(type, editor, edit)); } diff --git a/extensions/merge-conflict/src/documentTracker.ts b/extensions/merge-conflict/src/documentTracker.ts index 83c578122fc..f70cd91f185 100644 --- a/extensions/merge-conflict/src/documentTracker.ts +++ b/extensions/merge-conflict/src/documentTracker.ts @@ -116,7 +116,7 @@ export default class DocumentMergeConflictTracker implements vscode.Disposable, this.cache.clear(); } - private getConflictsOrEmpty(document: vscode.TextDocument, origins: string[]): interfaces.IDocumentMergeConflict[] { + private getConflictsOrEmpty(document: vscode.TextDocument, _origins: string[]): interfaces.IDocumentMergeConflict[] { const containsConflict = MergeConflictParser.containsConflict(document); if (!containsConflict) { diff --git a/extensions/merge-conflict/src/interfaces.ts b/extensions/merge-conflict/src/interfaces.ts index 70519b72b1f..b45cd252c9d 100644 --- a/extensions/merge-conflict/src/interfaces.ts +++ b/extensions/merge-conflict/src/interfaces.ts @@ -24,8 +24,8 @@ export interface IExtensionConfiguration { } export interface IDocumentMergeConflict extends IDocumentMergeConflictDescriptor { - commitEdit(type: CommitType, editor: vscode.TextEditor, edit?: vscode.TextEditorEdit); - applyEdit(type: CommitType, editor: vscode.TextEditor, edit: vscode.TextEditorEdit); + commitEdit(type: CommitType, editor: vscode.TextEditor, edit?: vscode.TextEditorEdit): Thenable; + applyEdit(type: CommitType, editor: vscode.TextEditor, edit: vscode.TextEditorEdit): void; } export interface IDocumentMergeConflictDescriptor { @@ -39,10 +39,10 @@ export interface IDocumentMergeConflictDescriptor { export interface IDocumentMergeConflictTracker { getConflicts(document: vscode.TextDocument): PromiseLike; isPending(document: vscode.TextDocument): boolean; - forget(document: vscode.TextDocument); + forget(document: vscode.TextDocument): void; } export interface IDocumentMergeConflictTrackerService { createTracker(origin: string): IDocumentMergeConflictTracker; - forget(document: vscode.TextDocument); + forget(document: vscode.TextDocument): void; } diff --git a/extensions/merge-conflict/src/mergeConflictParser.ts b/extensions/merge-conflict/src/mergeConflictParser.ts index 4ff9a58e07c..84a4607ac14 100644 --- a/extensions/merge-conflict/src/mergeConflictParser.ts +++ b/extensions/merge-conflict/src/mergeConflictParser.ts @@ -81,7 +81,7 @@ export class MergeConflictParser { return conflictDescriptors .filter(Boolean) - .map(descriptor => new DocumentMergeConflict(document, descriptor)); + .map(descriptor => new DocumentMergeConflict(descriptor)); } private static scanItemTolMergeConflictDescriptor(document: vscode.TextDocument, scanned: IScanMergedConflict): interfaces.IDocumentMergeConflictDescriptor | null { diff --git a/extensions/merge-conflict/src/services.ts b/extensions/merge-conflict/src/services.ts index 320adb3e53e..f3eb0e0630e 100644 --- a/extensions/merge-conflict/src/services.ts +++ b/extensions/merge-conflict/src/services.ts @@ -26,9 +26,9 @@ export default class ServiceWrapper implements vscode.Disposable { this.services.push( documentTracker, - new CommandHandler(this.context, documentTracker), - new CodeLensProvider(this.context, documentTracker), - new ContentProvider(this.context), + new CommandHandler(documentTracker), + new CodeLensProvider(documentTracker), + new ContentProvider(), new Decorator(this.context, documentTracker), ); diff --git a/extensions/merge-conflict/tsconfig.json b/extensions/merge-conflict/tsconfig.json index ce3e55fff2d..545f2260b61 100644 --- a/extensions/merge-conflict/tsconfig.json +++ b/extensions/merge-conflict/tsconfig.json @@ -6,7 +6,11 @@ ], "module": "commonjs", "outDir": "./out", - "strictNullChecks": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true, "experimentalDecorators": true }, "include": [ diff --git a/extensions/npm-shrinkwrap.json b/extensions/npm-shrinkwrap.json index 5933662026d..4349563cff1 100644 --- a/extensions/npm-shrinkwrap.json +++ b/extensions/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "0.0.1", "dependencies": { "typescript": { - "version": "2.5.2", - "from": "typescript@2.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz" + "version": "2.6.1", + "from": "typescript@2.6.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.1.tgz" } } } diff --git a/extensions/npm/.vscode/launch.json b/extensions/npm/.vscode/launch.json index da043ff85d9..017c8762415 100644 --- a/extensions/npm/.vscode/launch.json +++ b/extensions/npm/.vscode/launch.json @@ -7,11 +7,11 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" + "--extensionDevelopmentPath=${workspaceFolder}" ], "stopOnEntry": false, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/client/out/**/*.js"], + "outFiles": ["${workspaceFolder}/client/out/**/*.js"], "preLaunchTask": "npm" } ] diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 07387994960..5810b4ee483 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -18,7 +18,7 @@ "vscode-nls": "^2.0.2" }, "devDependencies": { - "@types/node": "^7.0.12" + "@types/node": "7.0.43" }, "main": "./out/main", "activationEvents": [ @@ -37,19 +37,33 @@ "on" ], "default": "on", + "scope": "resource", "description": "%config.npm.autoDetect%" }, "npm.runSilent": { - "type": "boolean", - "default": false, - "description": "%config.npm.runSilent%" + "type": "boolean", + "default": false, + "scope": "resource", + "description": "%config.npm.runSilent%" + }, + "npm.packageManager": { + "scope": "resource", + "type": "string", + "enum": [ + "npm", + "yarn" + ], + "default": "npm", + "description": "%config.npm.packageManager%" } } }, "taskDefinitions": [ { "type": "npm", - "required": ["script"], + "required": [ + "script" + ], "properties": { "script": { "type": "string", diff --git a/extensions/npm/package.nls.json b/extensions/npm/package.nls.json index 78227cb0df1..3f537686a6c 100644 --- a/extensions/npm/package.nls.json +++ b/extensions/npm/package.nls.json @@ -1,4 +1,6 @@ { "config.npm.autoDetect": "Controls whether auto detection of npm scripts is on or off. Default is on.", - "config.npm.runSilent": "Run npm commands with the `--silent` option" -} \ No newline at end of file + "config.npm.runSilent": "Run npm commands with the `--silent` option.", + "config.npm.packageManager": "The package manager used to run scripts.", + "npm.parseError": "Npm task detection: failed to parse the file {0}" +} diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 6c22119b342..e18287872db 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -8,6 +8,8 @@ import * as path from 'path'; import * as fs from 'fs'; import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; +let localize = nls.loadMessageBundle(); type AutoDetect = 'on' | 'off'; let taskProvider: vscode.Disposable | undefined; @@ -17,24 +19,14 @@ export function activate(_context: vscode.ExtensionContext): void { return; } - function onConfigurationChanged() { - let autoDetect = vscode.workspace.getConfiguration('npm').get('autoDetect'); - if (taskProvider && autoDetect === 'off') { - taskProvider.dispose(); - taskProvider = undefined; - } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider('npm', { - provideTasks: () => { - return provideNpmScripts(); - }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; - } - }); + taskProvider = vscode.workspace.registerTaskProvider('npm', { + provideTasks: () => { + return provideNpmScripts(); + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; } - } - vscode.workspace.onDidChangeConfiguration(onConfigurationChanged); - onConfigurationChanged(); + }); } export function deactivate(): void { @@ -99,20 +91,31 @@ async function provideNpmScripts(): Promise { if (!folders) { return emptyTasks; } - - const isSingleRoot = folders.length === 1; - - for (let i = 0; i < folders.length; i++) { - let tasks = await provideNpmScriptsForFolder(folders[i], isSingleRoot); - allTasks.push(...tasks); + try { + for (let i = 0; i < folders.length; i++) { + if (isEnabled(folders[i])) { + let tasks = await provideNpmScriptsForFolder(folders[i]); + allTasks.push(...tasks); + } + } + return allTasks; + } catch (error) { + return Promise.reject(error); } - return allTasks; } -async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder, singleRoot: boolean): Promise { - let rootPath = folder.uri.fsPath; +function isEnabled(folder: vscode.WorkspaceFolder): boolean { + return vscode.workspace.getConfiguration('npm', folder.uri).get('autoDetect') === 'on'; +} + +async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder): Promise { let emptyTasks: vscode.Task[] = []; + if (folder.uri.scheme !== 'file') { + return emptyTasks; + } + let rootPath = folder.uri.fsPath; + let packageJson = path.join(rootPath, 'package.json'); if (!await exists(packageJson)) { return emptyTasks; @@ -127,7 +130,7 @@ async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder, single const result: vscode.Task[] = []; Object.keys(json.scripts).filter(isNotPreOrPostScript).forEach(each => { - const task = createTask(each, `run ${each}`, rootPath, folder.name, singleRoot); + const task = createTask(each, `run ${each}`, rootPath, folder); const lowerCaseTaskName = each.toLowerCase(); if (isBuildTask(lowerCaseTaskName)) { task.group = vscode.TaskGroup.Build; @@ -137,34 +140,32 @@ async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder, single result.push(task); }); // always add npm install (without a problem matcher) - result.push(createTask('install', 'install', rootPath, folder.name, singleRoot, [])); + // result.push(createTask('install', 'install', rootPath, folder, [])); return result; } catch (e) { - return emptyTasks; + let localizedParseError = localize('npm.parseError', 'Npm task detection: failed to parse the file {0}', packageJson); + throw new Error(localizedParseError); } } -function createTask(script: string, cmd: string, rootPath: string, shortPath: string, singleRoot: boolean, matcher?: any): vscode.Task { +function createTask(script: string, cmd: string, rootPath: string, folder: vscode.WorkspaceFolder, matcher?: any): vscode.Task { - function getTaskName(script: string, shortPath: string, singleRoot: boolean) { - if (singleRoot) { - return script; - } - return `${script} - ${shortPath}`; + function getTaskName(script: string) { + return script; } - function getNpmCommandLine(cmd: string): string { - if (vscode.workspace.getConfiguration('npm').get('runSilent')) { - return `npm --silent ${cmd}`; + function getCommandLine(folder: vscode.WorkspaceFolder, cmd: string): string { + let packageManager = vscode.workspace.getConfiguration('npm', folder.uri).get('packageManager', 'npm'); + if (vscode.workspace.getConfiguration('npm', folder.uri).get('runSilent')) { + return `${packageManager} --silent ${cmd}`; } - return `npm ${cmd}`; + return `${packageManager} ${cmd}`; } let kind: NpmTaskDefinition = { type: 'npm', script: script }; - let taskName = getTaskName(script, shortPath, singleRoot); - - return new vscode.Task(kind, taskName, 'npm', new vscode.ShellExecution(getNpmCommandLine(cmd), { cwd: rootPath }), matcher); -} \ No newline at end of file + let taskName = getTaskName(script); + return new vscode.Task(kind, folder, taskName, 'npm', new vscode.ShellExecution(getCommandLine(folder, cmd), { cwd: rootPath }), matcher); +} diff --git a/extensions/npm/tsconfig.json b/extensions/npm/tsconfig.json index e804fa3acd7..51007d3cc84 100644 --- a/extensions/npm/tsconfig.json +++ b/extensions/npm/tsconfig.json @@ -6,11 +6,11 @@ "es2016" ], "outDir": "./out", - "strictNullChecks": true, "noImplicitAny": true, "noImplicitReturns": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/objective-c/package.json b/extensions/objective-c/package.json index 94795240f5c..0a5125c3273 100644 --- a/extensions/objective-c/package.json +++ b/extensions/objective-c/package.json @@ -6,7 +6,7 @@ "vscode": "*" }, "scripts": { - "update-grammar": "node ../../build/npm/update-grammar.js atom/language-objective-c grammars/objective-c.cson ./syntaxes/objective-c.tmLanguage.json && node ../../build/npm/update-grammar.js atom/language-objective-c grammars/objective-c++.cson ./syntaxes/objective-c++.tmLanguage.json" + "update-grammar": "node ../../build/npm/update-grammar.js atom/language-objective-c grammars/objective-c.cson ./syntaxes/objective-c.tmLanguage.json && node ../../build/npm/update-grammar.js atom/language-objective-c grammars/objective-c%2B%2B.cson ./syntaxes/objective-c++.tmLanguage.json" }, "contributes": { "languages": [ diff --git a/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json index 2b46507a2fb..82ee0f572d3 100644 --- a/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json +++ b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json @@ -1,9 +1,10 @@ { "information_for_contributors": [ - "This file has been converted from https://github.com/atom/language-objective-c/blob/master/grammars/objective-c++.cson", + "This file has been converted from https://github.com/atom/language-objective-c/blob/master/grammars/objective-c%2B%2B.cson", "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/atom/language-objective-c/commit/7fdf0c40ec1d592a902ed6a7cf5565bdf12e2ae8", "scopeName": "source.objcpp", "fileTypes": [ "mm", diff --git a/extensions/package.json b/extensions/package.json index 89341a27ebb..0e886571165 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.5.2" + "typescript": "2.6.1" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/perl/test/colorize-results/test2_pl.json b/extensions/perl/test/colorize-results/test2_pl.json index ef4bcabf439..bf690458af4 100644 --- a/extensions/perl/test/colorize-results/test2_pl.json +++ b/extensions/perl/test/colorize-results/test2_pl.json @@ -1301,11 +1301,11 @@ "c": "\\d\\d\\d", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -1323,11 +1323,11 @@ "c": "\\d\\d", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -1345,11 +1345,11 @@ "c": "\\d\\d", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -1774,11 +1774,11 @@ "c": "\\d", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { diff --git a/extensions/perl/test/colorize-results/test_pl.json b/extensions/perl/test/colorize-results/test_pl.json index dd6dc702ac1..e6551c2c639 100644 --- a/extensions/perl/test/colorize-results/test_pl.json +++ b/extensions/perl/test/colorize-results/test_pl.json @@ -388,11 +388,11 @@ "c": "\\s", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -410,11 +410,11 @@ "c": "\\s", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -432,11 +432,11 @@ "c": "\\(", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -454,11 +454,11 @@ "c": "\\)", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -476,11 +476,11 @@ "c": "\\)", "t": "source.perl string.regexp.find.perl constant.character.escape.perl", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { @@ -674,11 +674,11 @@ "c": "\\n", "t": "source.perl string.quoted.double.perl constant.character.escape.perl", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { @@ -949,11 +949,11 @@ "c": "\\n", "t": "source.perl string.quoted.double.perl constant.character.escape.perl", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { @@ -1444,11 +1444,11 @@ "c": "\\n", "t": "source.perl string.quoted.double.perl constant.character.escape.perl", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { @@ -2280,11 +2280,11 @@ "c": "\\n", "t": "source.perl string.quoted.double.perl constant.character.escape.perl", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { diff --git a/extensions/php/.vscode/launch.json b/extensions/php/.vscode/launch.json index 476551bebae..5e5696dce52 100644 --- a/extensions/php/.vscode/launch.json +++ b/extensions/php/.vscode/launch.json @@ -7,12 +7,12 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" + "--extensionDevelopmentPath=${workspaceFolder}" ], "stopOnEntry": false, "sourceMaps": true, - "outDir": "${workspaceRoot}/out", + "outDir": "${workspaceFolder}/out", "preLaunchTask": "npm" - } + } ] } \ No newline at end of file diff --git a/extensions/php/.vscode/tasks.json b/extensions/php/.vscode/tasks.json index a132a04214d..9e5593ade83 100644 --- a/extensions/php/.vscode/tasks.json +++ b/extensions/php/.vscode/tasks.json @@ -1,5 +1,5 @@ // Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team +// ${workspaceFolder}: the root folder of the team // ${file}: the current opened file // ${fileBasename}: the current opened file's basename // ${fileDirname}: the current opened file's dirname diff --git a/extensions/php/language-configuration.json b/extensions/php/language-configuration.json index 0b35ccae67d..8172fcd09e5 100644 --- a/extensions/php/language-configuration.json +++ b/extensions/php/language-configuration.json @@ -26,5 +26,11 @@ "indentationRules": { "increaseIndentPattern": "({(?!.+}).*|\\(|\\[|((else(\\s)?)?if|else|for(each)?|while|switch).*:)\\s*(/[/*].*)?$", "decreaseIndentPattern": "^(.*\\*\\/)?\\s*((\\})|(\\)+[;,])|(\\][;,])|\\b(else:)|\\b((end(if|for(each)?|while|switch));))" + }, + "folding": { + "markers": { + "start": "^\\s*(#|\/\/)region\\b", + "end": "^\\s*(#|\/\/)endregion\\b" + } } } \ No newline at end of file diff --git a/extensions/php/package.json b/extensions/php/package.json index e3b313bb321..7d4eb5204e3 100644 --- a/extensions/php/package.json +++ b/extensions/php/package.json @@ -27,7 +27,7 @@ "PHP", "php" ], - "firstLine": "^#!/.*\\bphp\\b", + "firstLine": "^#!/.*\\bphp\\b", "mimetypes": [ "application/x-php" ], @@ -118,6 +118,6 @@ "update-grammar": "node ./build/update-grammar.js" }, "devDependencies": { - "@types/node": "^7.0.4" + "@types/node": "7.0.43" } } diff --git a/extensions/php/src/features/completionItemProvider.ts b/extensions/php/src/features/completionItemProvider.ts index a430aa3f154..05a0f9f29bc 100644 --- a/extensions/php/src/features/completionItemProvider.ts +++ b/extensions/php/src/features/completionItemProvider.ts @@ -12,7 +12,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider public triggerCharacters = ['.', ':', '$']; - public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise { + public provideCompletionItems(document: TextDocument, position: Position, _token: CancellationToken): Promise { let result: CompletionItem[] = []; let shouldProvideCompletionItems = workspace.getConfiguration('php').get('suggest.basic', true); @@ -27,7 +27,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider } var added: any = {}; - var createNewProposal = function (kind: CompletionItemKind, name: string, entry: phpGlobals.IEntry): CompletionItem { + var createNewProposal = function (kind: CompletionItemKind, name: string, entry: phpGlobals.IEntry | null): CompletionItem { var proposal: CompletionItem = new CompletionItem(name); proposal.kind = kind; if (entry) { @@ -85,7 +85,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider var text = document.getText(); if (prefix[0] === '$') { var variableMatch = /\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/g; - var match: RegExpExecArray = null; + var match: RegExpExecArray | null = null; while (match = variableMatch.exec(text)) { var word = match[0]; if (!added[word]) { @@ -95,7 +95,7 @@ export default class PHPCompletionItemProvider implements CompletionItemProvider } } var functionMatch = /function\s+([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\(/g; - var match: RegExpExecArray = null; + var match: RegExpExecArray | null = null; while (match = functionMatch.exec(text)) { var word = match[1]; if (!added[word]) { diff --git a/extensions/php/src/features/hoverProvider.ts b/extensions/php/src/features/hoverProvider.ts index 1e300e2fccd..f40d210b133 100644 --- a/extensions/php/src/features/hoverProvider.ts +++ b/extensions/php/src/features/hoverProvider.ts @@ -11,15 +11,15 @@ import { textToMarkedString } from './utils/markedTextUtil'; export default class PHPHoverProvider implements HoverProvider { - public provideHover(document: TextDocument, position: Position, token: CancellationToken): Hover { + public provideHover(document: TextDocument, position: Position, _token: CancellationToken): Hover | undefined { let enable = workspace.getConfiguration('php').get('suggest.basic', true); if (!enable) { - return null; + return undefined; } let wordRange = document.getWordRangeAtPosition(position); if (!wordRange) { - return; + return undefined; } let name = document.getText(wordRange); @@ -30,5 +30,7 @@ export default class PHPHoverProvider implements HoverProvider { let contents: MarkedString[] = [textToMarkedString(entry.description), { language: 'php', value: signature }]; return new Hover(contents, wordRange); } + + return undefined; } } diff --git a/extensions/php/src/features/signatureHelpProvider.ts b/extensions/php/src/features/signatureHelpProvider.ts index b52392cfca4..b3f6c12a306 100644 --- a/extensions/php/src/features/signatureHelpProvider.ts +++ b/extensions/php/src/features/signatureHelpProvider.ts @@ -69,7 +69,7 @@ class BackwardIterator { export default class PHPSignatureHelpProvider implements SignatureHelpProvider { - public provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise { + public provideSignatureHelp(document: TextDocument, position: Position, _token: CancellationToken): Promise | null { let enable = workspace.getConfiguration('php').get('suggest.basic', true); if (!enable) { return null; @@ -95,7 +95,7 @@ export default class PHPSignatureHelpProvider implements SignatureHelpProvider { let signatureInfo = new SignatureInformation(ident + paramsString, entry.description); var re = /\w*\s+\&?\$[\w_\.]+|void/g; - var match: RegExpExecArray = null; + var match: RegExpExecArray | null = null; while ((match = re.exec(paramsString)) !== null) { signatureInfo.parameters.push({ label: match[0], documentation: '' }); } diff --git a/extensions/php/src/features/utils/async.ts b/extensions/php/src/features/utils/async.ts index f9c86930453..78ba0aa582a 100644 --- a/extensions/php/src/features/utils/async.ts +++ b/extensions/php/src/features/utils/async.ts @@ -29,9 +29,9 @@ export interface ITask { */ export class Throttler { - private activePromise: Promise; - private queuedPromise: Promise; - private queuedPromiseFactory: ITask>; + private activePromise: Promise | null; + private queuedPromise: Promise | null; + private queuedPromiseFactory: ITask> | null; constructor() { this.activePromise = null; @@ -47,26 +47,26 @@ export class Throttler { var onComplete = () => { this.queuedPromise = null; - var result = this.queue(this.queuedPromiseFactory); + var result = this.queue(this.queuedPromiseFactory!); this.queuedPromiseFactory = null; return result; }; - this.queuedPromise = new Promise((resolve, reject) => { - this.activePromise.then(onComplete, onComplete).then(resolve); + this.queuedPromise = new Promise((resolve) => { + this.activePromise!.then(onComplete, onComplete).then(resolve); }); } return new Promise((resolve, reject) => { - this.queuedPromise.then(resolve, reject); + this.queuedPromise!.then(resolve, reject); }); } this.activePromise = promiseFactory(); return new Promise((resolve, reject) => { - this.activePromise.then((result: T) => { + this.activePromise!.then((result: T) => { this.activePromise = null; resolve(result); }, (err: any) => { @@ -103,10 +103,10 @@ export class Throttler { export class Delayer { public defaultDelay: number; - private timeout: NodeJS.Timer; - private completionPromise: Promise; - private onResolve: (value: T | Thenable) => void; - private task: ITask; + private timeout: NodeJS.Timer | null; + private completionPromise: Promise | null; + private onResolve: ((value: T | Thenable | undefined) => void) | null; + private task: ITask | null; constructor(defaultDelay: number) { this.defaultDelay = defaultDelay; @@ -121,13 +121,13 @@ export class Delayer { this.cancelTimeout(); if (!this.completionPromise) { - this.completionPromise = new Promise((resolve, reject) => { + this.completionPromise = new Promise((resolve) => { this.onResolve = resolve; }).then(() => { this.completionPromise = null; this.onResolve = null; - var result = this.task(); + var result = this.task!(); this.task = null; return result; @@ -136,7 +136,7 @@ export class Delayer { this.timeout = setTimeout(() => { this.timeout = null; - this.onResolve(null); + this.onResolve!(undefined); }, delay); return this.completionPromise; diff --git a/extensions/php/src/features/validationProvider.ts b/extensions/php/src/features/validationProvider.ts index 712164af0f9..4f7f8cadbb7 100644 --- a/extensions/php/src/features/validationProvider.ts +++ b/extensions/php/src/features/validationProvider.ts @@ -16,7 +16,7 @@ let localize = nls.loadMessageBundle(); export class LineDecoder { private stringDecoder: NodeStringDecoder; - private remaining: string; + private remaining: string | null; constructor(encoding: string = 'utf8') { this.stringDecoder = new StringDecoder(encoding); @@ -55,7 +55,7 @@ export class LineDecoder { return result; } - public end(): string { + public end(): string | null { return this.remaining; } } @@ -88,17 +88,17 @@ export default class PHPValidationProvider { private static FileArgs: string[] = ['-l', '-n', '-d', 'display_errors=On', '-d', 'log_errors=Off', '-f']; private validationEnabled: boolean; - private executableIsUserDefined: boolean; - private executable: string; + private executableIsUserDefined: boolean | undefined; + private executable: string | undefined; private trigger: RunTrigger; private pauseValidation: boolean; - private documentListener: vscode.Disposable; + private documentListener: vscode.Disposable | null; private diagnosticCollection: vscode.DiagnosticCollection; private delayers: { [key: string]: ThrottledDelayer }; constructor(private workspaceStore: vscode.Memento) { - this.executable = null; + this.executable = undefined; this.validationEnabled = true; this.trigger = RunTrigger.onSave; this.pauseValidation = false; @@ -145,7 +145,7 @@ export default class PHPValidationProvider { } this.trigger = RunTrigger.from(section.get('validate.run', RunTrigger.strings.onSave)); } - if (this.executableIsUserDefined !== true && this.workspaceStore.get(CheckedExecutablePath, undefined) !== void 0) { + if (this.executableIsUserDefined !== true && this.workspaceStore.get(CheckedExecutablePath, undefined) !== void 0) { vscode.commands.executeCommand('setContext', 'php.untrustValidationExecutableContext', true); } this.delayers = Object.create(null); @@ -195,7 +195,7 @@ export default class PHPValidationProvider { }; if (this.executableIsUserDefined !== void 0 && !this.executableIsUserDefined) { - let checkedExecutablePath = this.workspaceStore.get(CheckedExecutablePath, undefined); + let checkedExecutablePath = this.workspaceStore.get(CheckedExecutablePath, undefined); if (!checkedExecutablePath || checkedExecutablePath !== this.executable) { vscode.window.showInformationMessage( localize('php.useExecutablePath', 'Do you allow {0} (defined as a workspace setting) to be executed to lint PHP files?', this.executable), @@ -224,7 +224,7 @@ export default class PHPValidationProvider { } private doValidate(textDocument: vscode.TextDocument): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { let executable = this.executable || 'php'; let decoder = new LineDecoder(); let diagnostics: vscode.Diagnostic[] = []; @@ -286,7 +286,7 @@ export default class PHPValidationProvider { } private showError(error: any, executable: string): void { - let message: string = null; + let message: string | null = null; if (error.code === 'ENOENT') { if (this.executable) { message = localize('wrongExecutable', 'Cannot validate since {0} is not a valid php executable. Use the setting \'php.validate.executablePath\' to configure the PHP executable.', executable); @@ -296,6 +296,8 @@ export default class PHPValidationProvider { } else { message = error.message ? error.message : localize('unknownReason', 'Failed to run php using path: {0}. Reason is unknown.', executable); } - vscode.window.showInformationMessage(message); + if (message) { + vscode.window.showInformationMessage(message); + } } } diff --git a/extensions/php/src/phpMain.ts b/extensions/php/src/phpMain.ts index 6c62574e851..320f9da2c52 100644 --- a/extensions/php/src/phpMain.ts +++ b/extensions/php/src/phpMain.ts @@ -19,7 +19,7 @@ export function activate(context: vscode.ExtensionContext): any { validator.activate(context.subscriptions); // add providers - context.subscriptions.push(vscode.languages.registerCompletionItemProvider('php', new PHPCompletionItemProvider(), '.', '$')); + context.subscriptions.push(vscode.languages.registerCompletionItemProvider('php', new PHPCompletionItemProvider(), '>', '$')); context.subscriptions.push(vscode.languages.registerHoverProvider('php', new PHPHoverProvider())); context.subscriptions.push(vscode.languages.registerSignatureHelpProvider('php', new PHPSignatureHelpProvider(), '(', ',')); diff --git a/extensions/php/syntaxes/php.tmLanguage.json b/extensions/php/syntaxes/php.tmLanguage.json index 8d571c01747..aa0446b8af1 100644 --- a/extensions/php/syntaxes/php.tmLanguage.json +++ b/extensions/php/syntaxes/php.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/atom/language-php/commit/f53f2fc2c3f52468b6d205b8c2bbf79aca95f5b2", + "version": "https://github.com/atom/language-php/commit/71231bfb975ac56d9c13c5b4cda21c081ebbc6ee", "scopeName": "text.html.php", "name": "PHP", "fileTypes": [ @@ -20,7 +20,8 @@ "php5", "phpt", "phtml", - "profile" + "profile", + "theme" ], "firstLineMatch": "(?x)\n# Hashbang\n^\\#!.*(?:\\s|\\/)\n php\\d?\n(?:$|\\s)\n|\n# Modeline\n(?i:\n # Emacs\n -\\*-(?:\\s*(?=[^:;\\s]+\\s*-\\*-)|(?:.*?[;\\s]|(?<=-\\*-))mode\\s*:\\s*)\n php\n (?=[\\s;]|(?]?\\d+|m)?|\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s*set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=\n (?:php|phtml)\n (?=\\s|:|$)\n)", "foldingStartMarker": "(/\\*|\\{\\s*$|<<))", - "beginCaptures": { - "0": { - "name": "punctuation.whitespace.embedded.leading.php" - } - }, - "end": "(?!\\G)(\\s*$\\n)?", - "endCaptures": { - "0": { - "name": "punctuation.whitespace.embedded.trailing.php" - } - }, - "patterns": [ - { - "begin": "<\\?(?i:php|=)?", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.php" - } - }, - "contentName": "source.php", - "end": "(\\?)>", - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.php" - }, - "1": { - "name": "source.php" - } - }, - "name": "meta.embedded.block.php", - "patterns": [ - { - "include": "#language" - } - ] - } - ] - }, { "begin": "<\\?(?i:php|=)?(?![^?]*\\?>)", "beginCaptures": { @@ -151,99 +112,6 @@ } ], "repository": { - "class-body": { - "patterns": [ - { - "begin": "(?i)\\buse\\b", - "beginCaptures": { - "0": { - "name": "keyword.other.use.php" - } - }, - "end": "(?=;)", - "name": "meta.use.php", - "patterns": [ - { - "match": "(?i)[a-z_\\x{7f}-\\x{ff}\\\\][a-z0-9_\\x{7f}-\\x{ff}\\\\]*", - "captures": { - "0": { - "patterns": [ - { - "include": "#class-name" - } - ] - } - } - }, - { - "match": ",", - "name": "punctuation.separator.delimiter.php" - }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.definition.use.begin.bracket.curly.php" - } - }, - "end": "}", - "endCaptures": { - "0": { - "name": "punctuation.definition.use.end.bracket.curly.php" - } - }, - "contentName": "meta.use.body.php", - "patterns": [ - { - "include": "#scope-resolution" - }, - { - "match": "(?xi)\n\\b(as)\\s+\n([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)\\b # Visibility modifier OR alias\n(?:\\s+([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*))? # alias", - "captures": { - "1": { - "name": "keyword.other.use-as.php" - }, - "2": { - "patterns": [ - { - "match": "\\b(final|abstract|public|private|protected|static)\\b", - "name": "storage.modifier.php" - }, - { - "match": "[a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*", - "name": "entity.other.alias.php" - } - ] - }, - "3": { - "name": "entity.other.alias.php" - } - } - }, - { - "match": "(?i)\\b(insteadof)\\s+([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)", - "captures": { - "1": { - "name": "keyword.other.use-insteadof.php" - }, - "2": { - "name": "support.class.php" - } - } - }, - { - "match": ";", - "name": "punctuation.terminator.expression.php" - } - ] - } - ] - }, - { - "include": "#language" - } - ] - }, "class-builtin": { "patterns": [ { @@ -261,7 +129,7 @@ "patterns": [ { "begin": "(?i)(?=\\\\?[a-z_0-9]+\\\\)", - "end": "(?i)([a-z_][a-z_0-9]*)?(?=[^a-z0-9_\\\\])", + "end": "(?i)([a-z_][a-z_0-9]*)?(?![a-z0-9_\\\\])", "endCaptures": { "1": { "name": "support.class.php" @@ -278,7 +146,7 @@ }, { "begin": "(?=[\\\\a-zA-Z_])", - "end": "(?i)([a-z_][a-z_0-9]*)?(?=[^a-z0-9_\\\\])", + "end": "(?i)([a-z_][a-z_0-9]*)?(?![a-z0-9_\\\\])", "endCaptures": { "1": { "name": "support.class.php" @@ -641,7 +509,7 @@ "name": "punctuation.definition.arguments.begin.bracket.round.php" } }, - "end": "\\)", + "end": "\\)|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.arguments.end.bracket.round.php" @@ -679,7 +547,7 @@ "name": "punctuation.definition.arguments.begin.bracket.round.php" } }, - "end": "\\)", + "end": "\\)|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.arguments.end.bracket.round.php" @@ -741,7 +609,7 @@ } }, "contentName": "text.html", - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -777,7 +645,7 @@ } }, "contentName": "text.xml", - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -813,7 +681,7 @@ } }, "contentName": "source.sql", - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -849,7 +717,7 @@ } }, "contentName": "source.js", - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -885,7 +753,7 @@ } }, "contentName": "source.json", - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -921,7 +789,7 @@ } }, "contentName": "source.css", - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -957,7 +825,7 @@ } }, "contentName": "string.regexp.heredoc.php", - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1036,7 +904,7 @@ "name": "invalid.illegal.trailing-whitespace.php" } }, - "end": "^(\\3)\\b", + "end": "^(\\3)(?=;?$)", "endCaptures": { "1": { "name": "keyword.operator.heredoc.php" @@ -1069,7 +937,7 @@ } }, "contentName": "text.html", - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1102,7 +970,7 @@ } }, "contentName": "text.xml", - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1135,7 +1003,7 @@ } }, "contentName": "source.sql", - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1168,7 +1036,7 @@ } }, "contentName": "source.js", - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1201,7 +1069,7 @@ } }, "contentName": "source.json", - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1234,7 +1102,7 @@ } }, "contentName": "source.css", - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1267,7 +1135,7 @@ } }, "contentName": "string.regexp.nowdoc.php", - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "0": { "name": "punctuation.section.embedded.end.php" @@ -1343,7 +1211,7 @@ "name": "invalid.illegal.trailing-whitespace.php" } }, - "end": "^(\\2)\\b", + "end": "^(\\2)(?=;?$)", "endCaptures": { "1": { "name": "keyword.operator.nowdoc.php" @@ -1377,14 +1245,18 @@ "patterns": [ { "match": "\\\\[0-7]{1,3}", - "name": "constant.numeric.octal.php" + "name": "constant.character.escape.octal.php" }, { "match": "\\\\x[0-9A-Fa-f]{1,2}", - "name": "constant.numeric.hex.php" + "name": "constant.character.escape.hex.php" }, { - "match": "\\\\[enrt\\\\\\$\\\"]", + "match": "\\\\u{[0-9A-Fa-f]+}", + "name": "constant.character.escape.unicode.php" + }, + { + "match": "\\\\[nrtvef$\"\\\\]", "name": "constant.character.escape.php" }, { @@ -1509,7 +1381,7 @@ "name": "keyword.other.namespace.php" } }, - "end": "(?<=})", + "end": "(?<=})|(?=\\?>)", "name": "meta.namespace.php", "patterns": [ { @@ -1536,7 +1408,7 @@ "name": "punctuation.definition.namespace.begin.bracket.curly.php" } }, - "end": "}", + "end": "}|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.namespace.end.bracket.curly.php" @@ -1555,32 +1427,88 @@ ] }, { - "begin": "(?i)\\b(use)\\s+(?:(const|function)\\s+)?", + "match": "\\s+(?=use\\b)" + }, + { + "begin": "(?i)\\buse\\b", "beginCaptures": { - "1": { + "0": { "name": "keyword.other.use.php" - }, - "2": { - "name": "storage.type.${2:/downcase}.php" } }, - "end": "(?=;)", + "end": "(?<=})|(?=;)", "name": "meta.use.php", "patterns": [ + { + "match": "\\b(const|function)\\b", + "name": "storage.type.${1:/downcase}.php" + }, { "begin": "{", "beginCaptures": { "0": { - "name": "punctuation.definition.use.group.begin.bracket.curly.php" + "name": "punctuation.definition.use.begin.bracket.curly.php" } }, "end": "}", "endCaptures": { "0": { - "name": "punctuation.definition.use.group.end.bracket.curly.php" + "name": "punctuation.definition.use.end.bracket.curly.php" } }, "patterns": [ + { + "include": "#scope-resolution" + }, + { + "match": "(?xi)\n\\b(as)\n\\s+(final|abstract|public|private|protected|static)\n\\s+([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)\n\\b", + "captures": { + "1": { + "name": "keyword.other.use-as.php" + }, + "2": { + "name": "storage.modifier.php" + }, + "3": { + "name": "entity.other.alias.php" + } + } + }, + { + "match": "(?xi)\n\\b(as)\n\\s+([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)\n\\b", + "captures": { + "1": { + "name": "keyword.other.use-as.php" + }, + "2": { + "patterns": [ + { + "match": "^(?:final|abstract|public|private|protected|static)$", + "name": "storage.modifier.php" + }, + { + "match": ".+", + "name": "entity.other.alias.php" + } + ] + } + } + }, + { + "match": "(?i)\\b(insteadof)\\s+([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)", + "captures": { + "1": { + "name": "keyword.other.use-insteadof.php" + }, + "2": { + "name": "support.class.php" + } + } + }, + { + "match": ";", + "name": "punctuation.terminator.expression.php" + }, { "include": "#use-inner" } @@ -1604,7 +1532,7 @@ "name": "entity.name.type.class.php" } }, - "end": "}", + "end": "}|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.class.end.bracket.curly.php" @@ -1703,11 +1631,11 @@ "name": "punctuation.definition.class.begin.bracket.curly.php" } }, - "end": "(?=})", + "end": "(?=}|\\?>)", "contentName": "meta.class.body.php", "patterns": [ { - "include": "#class-body" + "include": "#language" } ] } @@ -1717,8 +1645,12 @@ "include": "#switch_statement" }, { - "match": "(?x)\n\\b(\n break|case|continue|declare|default|die|do|\n else(if)?|end(declare|for(each)?|if|switch|while)|exit|\n for(each)?|if|return|switch|use|while|yield\n)\\b", - "name": "keyword.control.php" + "match": "(?x)\n\\s*\n\\b(\n break|case|continue|declare|default|die|do|\n else(if)?|end(declare|for(each)?|if|switch|while)|exit|\n for(each)?|if|return|switch|use|while|yield\n)\\b", + "captures": { + "1": { + "name": "keyword.control.${1:/downcase}.php" + } + } }, { "begin": "(?i)\\b((?:require|include)(?:_once)?)\\s+", @@ -1855,7 +1787,7 @@ ] }, { - "begin": "(?x)\n((?:(?:final|abstract|public|private|protected|static)\\s+)*)\n(function)\\s+\n(?i:\n (__(?:call|construct|debugInfo|destruct|get|set|isset|unset|tostring|\n clone|set_state|sleep|wakeup|autoload|invoke|callStatic))\n |([a-zA-Z_\\x{7f}-\\x{ff}][a-zA-Z0-9_\\x{7f}-\\x{ff}]*)\n)\n\\s*(\\()", + "begin": "(?x)\n((?:(?:final|abstract|public|private|protected|static)\\s+)*)\n(function)\\s+\n(?i:\n (__(?:call|construct|debugInfo|destruct|get|set|isset|unset|toString|\n clone|set_state|sleep|wakeup|autoload|invoke|callStatic))\n |([a-zA-Z_\\x{7f}-\\x{ff}][a-zA-Z0-9_\\x{7f}-\\x{ff}]*)\n)\n\\s*(\\()", "beginCaptures": { "1": { "patterns": [ @@ -1935,7 +1867,7 @@ "name": "punctuation.definition.array.begin.bracket.round.php" } }, - "end": "\\)", + "end": "\\)|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.array.end.bracket.round.php" @@ -1977,9 +1909,16 @@ "match": ";", "name": "punctuation.terminator.expression.php" }, + { + "match": ":", + "name": "punctuation.terminator.statement.php" + }, { "include": "#heredoc" }, + { + "include": "#numbers" + }, { "match": "(?i)\\bclone\\b", "name": "keyword.other.clone.php" @@ -2058,9 +1997,6 @@ } ] }, - { - "include": "#numbers" - }, { "include": "#instantiation" }, @@ -2093,7 +2029,7 @@ "name": "punctuation.definition.begin.bracket.curly.php" } }, - "end": "}", + "end": "}|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.end.bracket.curly.php" @@ -2112,7 +2048,7 @@ "name": "punctuation.section.array.begin.php" } }, - "end": "\\]", + "end": "\\]|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.section.array.end.php" @@ -2131,7 +2067,7 @@ "name": "punctuation.definition.begin.bracket.round.php" } }, - "end": "\\)", + "end": "\\)|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.end.bracket.round.php" @@ -2153,7 +2089,7 @@ ] }, "namespace": { - "begin": "(?i)(?:(namespace)|[a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)?(\\\\)(?=.*?[^a-z0-9_\\x{7f}-\\x{ff}\\\\])", + "begin": "(?i)(?:(namespace)|[a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)?(\\\\)", "beginCaptures": { "1": { "name": "variable.language.namespace.php" @@ -2162,7 +2098,7 @@ "name": "punctuation.separator.inheritance.php" } }, - "end": "(?i)(?=[a-z0-9_\\x{7f}-\\x{ff}]*[^a-z0-9_\\x{7f}-\\x{ff}\\\\])", + "end": "(?i)(?![a-z0-9_\\x{7f}-\\x{ff}]*\\\\)", "name": "support.other.namespace.php", "patterns": [ { @@ -2172,8 +2108,36 @@ ] }, "numbers": { - "match": "(?i)\\b((0x[0-9a-f]*)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))(e(\\+|-)?[0-9]+)?)\\b", - "name": "constant.numeric.php" + "patterns": [ + { + "match": "0[xX][0-9a-fA-F]+", + "name": "constant.numeric.hex.php" + }, + { + "match": "0[bB][01]+", + "name": "constant.numeric.binary.php" + }, + { + "match": "0[0-7]+", + "name": "constant.numeric.octal.php" + }, + { + "match": "(?x)\n(?:\n [0-9]*(\\.)[0-9]+(?:[eE][+-]?[0-9]+)?|\n [0-9]+(\\.)[0-9]*(?:[eE][+-]?[0-9]+)?|\n [0-9]+[eE][+-]?[0-9]+\n)", + "name": "constant.numeric.decimal.php", + "captures": { + "1": { + "name": "punctuation.separator.decimal.period.php" + }, + "2": { + "name": "punctuation.separator.decimal.period.php" + } + } + }, + { + "match": "0|[1-9][0-9]*", + "name": "constant.numeric.decimal.php" + } + ] }, "object": { "patterns": [ @@ -2212,7 +2176,7 @@ "name": "punctuation.definition.arguments.begin.bracket.round.php" } }, - "end": "\\)", + "end": "\\)|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.arguments.end.bracket.round.php" @@ -2553,7 +2517,7 @@ "scope-resolution": { "patterns": [ { - "match": "(?i)\\b([a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*)(?=\\s*::)", + "match": "(?i)([a-z_\\x{7f}-\\x{ff}\\\\][a-z0-9_\\x{7f}-\\x{ff}\\\\]*)(?=\\s*::)", "captures": { "1": { "patterns": [ @@ -2584,7 +2548,7 @@ "name": "punctuation.definition.arguments.begin.bracket.round.php" } }, - "end": "\\)", + "end": "\\)|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.arguments.end.bracket.round.php" @@ -3273,6 +3237,9 @@ }, "switch_statement": { "patterns": [ + { + "match": "\\s+(?=switch\\b)" + }, { "begin": "\\bswitch\\b(?!\\s*\\(.*\\)\\s*:)", "beginCaptures": { @@ -3280,7 +3247,7 @@ "name": "keyword.control.switch.php" } }, - "end": "}", + "end": "}|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.section.switch-block.end.bracket.curly.php" @@ -3295,7 +3262,7 @@ "name": "punctuation.definition.switch-expression.begin.bracket.round.php" } }, - "end": "\\)", + "end": "\\)|(?=\\?>)", "endCaptures": { "0": { "name": "punctuation.definition.switch-expression.end.bracket.round.php" @@ -3314,38 +3281,8 @@ "name": "punctuation.definition.section.switch-block.begin.bracket.curly.php" } }, - "end": "(?=})", + "end": "(?=}|\\?>)", "patterns": [ - { - "begin": "\\bcase\\b", - "beginCaptures": { - "0": { - "name": "keyword.control.case.php" - } - }, - "end": ":", - "endCaptures": { - "0": { - "name": "punctuation.terminator.statement.php" - } - }, - "patterns": [ - { - "include": "#language" - } - ] - }, - { - "match": "(?:^\\s*)?\\b(default)\\s*(:)", - "captures": { - "1": { - "name": "keyword.control.default.php" - }, - "2": { - "name": "punctuation.terminator.statement.php" - } - } - }, { "include": "#language" } @@ -3370,7 +3307,7 @@ "end": "(?i)[a-z_\\x{7f}-\\x{ff}][a-z0-9_\\x{7f}-\\x{ff}]*", "endCaptures": { "0": { - "name": "support.other.namespace.use-as.php" + "name": "entity.other.alias.php" } } }, diff --git a/extensions/php/test/colorize-results/issue-28354_php.json b/extensions/php/test/colorize-results/issue-28354_php.json index 94d5419c05b..ec02263f54e 100644 --- a/extensions/php/test/colorize-results/issue-28354_php.json +++ b/extensions/php/test/colorize-results/issue-28354_php.json @@ -36,11 +36,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -56,13 +56,13 @@ }, { "c": " ", - "t": "text.html.php meta.embedded.block.html source.js punctuation.whitespace.embedded.leading.php", + "t": "text.html.php meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -73,23 +73,23 @@ "light_plus": "punctuation.section.embedded.begin.php: #800000", "dark_vs": "punctuation.section.embedded.begin.php: #569CD6", "light_vs": "punctuation.section.embedded.begin.php: #800000", - "hc_black": "default: #FFFFFF" + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "foreach", - "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php keyword.control.php", + "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php keyword.control.foreach.php", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -102,11 +102,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php punctuation.definition.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -115,8 +115,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -126,8 +126,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -135,11 +135,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -157,11 +157,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -170,8 +170,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -181,8 +181,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -190,44 +190,44 @@ "c": ")", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php punctuation.definition.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -236,8 +236,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -245,11 +245,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -278,11 +278,11 @@ "c": "\\'", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php string.quoted.single.php constant.character.escape.php", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { @@ -324,8 +324,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -335,8 +335,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -377,11 +377,11 @@ "c": "\\'", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php string.quoted.single.php constant.character.escape.php", "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #A31515", "dark_vs": "string: #CE9178", "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" + "hc_black": "constant.character: #569CD6" } }, { @@ -410,44 +410,44 @@ "c": ";", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.html source.js meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -458,7 +458,7 @@ "light_plus": "punctuation.section.embedded.end.php: #800000", "dark_vs": "punctuation.section.embedded.end.php: #569CD6", "light_vs": "punctuation.section.embedded.end.php: #800000", - "hc_black": "default: #FFFFFF" + "hc_black": "punctuation.section.embedded: #569CD6" } }, { @@ -469,18 +469,18 @@ "light_plus": "punctuation.section.embedded.end.php: #800000", "dark_vs": "punctuation.section.embedded.end.php: #569CD6", "light_vs": "punctuation.section.embedded.end.php: #800000", - "hc_black": "default: #FFFFFF" + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": " ", "t": "text.html.php meta.embedded.block.html source.js", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { diff --git a/extensions/php/test/colorize-results/test_php.json b/extensions/php/test/colorize-results/test_php.json index d821838bb5f..4cb58182b1a 100644 --- a/extensions/php/test/colorize-results/test_php.json +++ b/extensions/php/test/colorize-results/test_php.json @@ -227,18 +227,18 @@ "light_plus": "punctuation.section.embedded.begin.php: #800000", "dark_vs": "punctuation.section.embedded.begin.php: #569CD6", "light_vs": "punctuation.section.embedded.begin.php: #800000", - "hc_black": "default: #FFFFFF" + "hc_black": "punctuation.section.embedded: #569CD6" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -256,11 +256,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.function.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -269,8 +269,8 @@ "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "entity.name.function: #DCDCAA" } }, @@ -278,44 +278,44 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function.php punctuation.definition.parameters.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function.php punctuation.definition.parameters.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php punctuation.whitespace.comment.leading.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -344,33 +344,33 @@ "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -432,11 +432,11 @@ "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -445,8 +445,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -456,8 +456,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -465,11 +465,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -487,11 +487,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -500,8 +500,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -509,11 +509,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.definition.array.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -553,22 +553,22 @@ "c": ",", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.separator.delimiter.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.array.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -608,22 +608,22 @@ "c": ",", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.separator.delimiter.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.array.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -663,22 +663,22 @@ "c": ",", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.separator.delimiter.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.array.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -718,22 +718,22 @@ "c": ",", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.separator.delimiter.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php meta.array.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -773,22 +773,22 @@ "c": ",", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.separator.delimiter.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.array.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -828,22 +828,22 @@ "c": ",", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.separator.delimiter.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.array.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -883,22 +883,22 @@ "c": ",", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.separator.delimiter.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.array.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -938,33 +938,33 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.array.php punctuation.definition.array.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -973,8 +973,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -982,11 +982,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -995,8 +995,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -1004,60 +1004,60 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "for", - "t": "text.html.php meta.embedded.block.php source.php keyword.control.php", + "t": "text.html.php meta.embedded.block.php source.php keyword.control.for.php", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1070,11 +1070,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1083,8 +1083,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1094,8 +1094,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1103,11 +1103,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1125,16 +1125,16 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "0", - "t": "text.html.php meta.embedded.block.php source.php constant.numeric.php", + "t": "text.html.php meta.embedded.block.php source.php constant.numeric.decimal.php", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1147,22 +1147,22 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1171,8 +1171,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1182,8 +1182,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1191,11 +1191,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1213,16 +1213,16 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "52", - "t": "text.html.php meta.embedded.block.php source.php constant.numeric.php", + "t": "text.html.php meta.embedded.block.php source.php constant.numeric.decimal.php", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1235,22 +1235,22 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1259,8 +1259,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1270,8 +1270,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1290,44 +1290,44 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1336,8 +1336,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1347,8 +1347,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1356,11 +1356,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1378,11 +1378,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1391,8 +1391,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -1400,11 +1400,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1413,8 +1413,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1424,8 +1424,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1433,33 +1433,33 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1468,8 +1468,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1479,8 +1479,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1488,11 +1488,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1510,22 +1510,22 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "(", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1534,8 +1534,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -1543,22 +1543,22 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1578,8 +1578,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1589,8 +1589,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1598,38 +1598,38 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "if", - "t": "text.html.php meta.embedded.block.php source.php keyword.control.php", + "t": "text.html.php meta.embedded.block.php source.php keyword.control.if.php", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1642,11 +1642,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1655,8 +1655,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1666,8 +1666,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1675,11 +1675,11 @@ "c": "[", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.begin.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1688,8 +1688,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1699,8 +1699,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1708,22 +1708,22 @@ "c": "]", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.end.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1741,11 +1741,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1774,44 +1774,44 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1820,8 +1820,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1831,8 +1831,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1851,49 +1851,49 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "else", - "t": "text.html.php meta.embedded.block.php source.php keyword.control.php", + "t": "text.html.php meta.embedded.block.php source.php keyword.control.else.php", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1906,33 +1906,33 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -1941,8 +1941,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1952,8 +1952,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -1961,33 +1961,33 @@ "c": "[", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.begin.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "]", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.end.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2005,11 +2005,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2018,8 +2018,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2029,8 +2029,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2038,11 +2038,11 @@ "c": "[", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.begin.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2051,8 +2051,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2062,8 +2062,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2071,33 +2071,33 @@ "c": "]", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.end.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2106,8 +2106,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2117,8 +2117,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2126,11 +2126,11 @@ "c": "[", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.begin.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2139,8 +2139,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2150,8 +2150,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2159,22 +2159,22 @@ "c": "]", "t": "text.html.php meta.embedded.block.php source.php punctuation.section.array.end.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2192,11 +2192,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2225,66 +2225,66 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2293,8 +2293,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -2302,11 +2302,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2315,8 +2315,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -2324,55 +2324,55 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2381,8 +2381,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2392,8 +2392,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2401,11 +2401,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2423,22 +2423,22 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "(", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2447,8 +2447,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -2456,22 +2456,22 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2487,7 +2487,7 @@ }, { "c": "51", - "t": "text.html.php meta.embedded.block.php source.php constant.numeric.php", + "t": "text.html.php meta.embedded.block.php source.php constant.numeric.decimal.php", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -2500,33 +2500,33 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2535,8 +2535,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -2544,11 +2544,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2621,33 +2621,33 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php punctuation.whitespace.comment.leading.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2676,16 +2676,16 @@ "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "for", - "t": "text.html.php meta.embedded.block.php source.php keyword.control.php", + "t": "text.html.php meta.embedded.block.php source.php keyword.control.for.php", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -2698,22 +2698,22 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "(", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2722,8 +2722,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2733,8 +2733,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2742,11 +2742,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2764,16 +2764,16 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "0", - "t": "text.html.php meta.embedded.block.php source.php constant.numeric.php", + "t": "text.html.php meta.embedded.block.php source.php constant.numeric.decimal.php", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -2786,22 +2786,22 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2810,8 +2810,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2821,8 +2821,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2830,11 +2830,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2852,16 +2852,16 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "52", - "t": "text.html.php meta.embedded.block.php source.php constant.numeric.php", + "t": "text.html.php meta.embedded.block.php source.php constant.numeric.decimal.php", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -2874,22 +2874,22 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -2898,8 +2898,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2909,8 +2909,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -2929,49 +2929,49 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "if", - "t": "text.html.php meta.embedded.block.php source.php keyword.control.php", + "t": "text.html.php meta.embedded.block.php source.php keyword.control.if.php", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -2984,22 +2984,22 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "(", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3008,8 +3008,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -3019,8 +3019,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -3028,11 +3028,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3050,16 +3050,16 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "52", - "t": "text.html.php meta.embedded.block.php source.php constant.numeric.php", + "t": "text.html.php meta.embedded.block.php source.php constant.numeric.decimal.php", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -3072,44 +3072,44 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3118,8 +3118,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -3129,8 +3129,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -3138,11 +3138,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3160,16 +3160,16 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "0", - "t": "text.html.php meta.embedded.block.php source.php constant.numeric.php", + "t": "text.html.php meta.embedded.block.php source.php constant.numeric.decimal.php", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -3182,44 +3182,44 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": " ", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3228,8 +3228,8 @@ "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "support.function: #DCDCAA" } }, @@ -3237,11 +3237,11 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3358,33 +3358,33 @@ "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function-call.php punctuation.definition.arguments.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3393,8 +3393,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -3404,8 +3404,8 @@ "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -3424,44 +3424,44 @@ "c": ";", "t": "text.html.php meta.embedded.block.php source.php punctuation.terminator.expression.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "\t", "t": "text.html.php meta.embedded.block.php source.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3479,11 +3479,11 @@ "c": " ", "t": "text.html.php meta.embedded.block.php source.php meta.function.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3492,8 +3492,8 @@ "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "entity.name.function: #DCDCAA" } }, @@ -3501,44 +3501,44 @@ "c": "(", "t": "text.html.php meta.embedded.block.php source.php meta.function.php punctuation.definition.parameters.begin.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": ")", "t": "text.html.php meta.embedded.block.php source.php meta.function.php punctuation.definition.parameters.end.bracket.round.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "{", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.begin.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "}", "t": "text.html.php meta.embedded.block.php source.php punctuation.definition.end.bracket.curly.php", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -3549,7 +3549,7 @@ "light_plus": "punctuation.section.embedded.end.php: #800000", "dark_vs": "punctuation.section.embedded.end.php: #569CD6", "light_vs": "punctuation.section.embedded.end.php: #800000", - "hc_black": "default: #FFFFFF" + "hc_black": "punctuation.section.embedded: #569CD6" } }, { @@ -3560,7 +3560,7 @@ "light_plus": "punctuation.section.embedded.end.php: #800000", "dark_vs": "punctuation.section.embedded.end.php: #569CD6", "light_vs": "punctuation.section.embedded.end.php: #800000", - "hc_black": "default: #FFFFFF" + "hc_black": "punctuation.section.embedded: #569CD6" } }, { diff --git a/extensions/php/tsconfig.json b/extensions/php/tsconfig.json index a2b5bcdfddf..7e9b0d127b4 100644 --- a/extensions/php/tsconfig.json +++ b/extensions/php/tsconfig.json @@ -5,7 +5,12 @@ "es2015" ], "module": "commonjs", - "outDir": "./out" + "outDir": "./out", + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/powershell/language-configuration.json b/extensions/powershell/language-configuration.json index b409b3ce4c0..b03aa5cd42e 100644 --- a/extensions/powershell/language-configuration.json +++ b/extensions/powershell/language-configuration.json @@ -22,5 +22,11 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*#region\\b", + "end": "^\\s*#endregion\\b" + } + } } \ No newline at end of file diff --git a/extensions/powershell/package.json b/extensions/powershell/package.json index 7448dd048a8..83d51ea3137 100644 --- a/extensions/powershell/package.json +++ b/extensions/powershell/package.json @@ -14,6 +14,10 @@ "language": "powershell", "scopeName": "source.powershell", "path": "./syntaxes/PowershellSyntax.tmLanguage" + }], + "snippets": [{ + "language": "powershell", + "path": "./snippets/powershell.json" }] }, "scripts": { diff --git a/extensions/powershell/snippets/powershell.json b/extensions/powershell/snippets/powershell.json new file mode 100644 index 00000000000..5ad4bfca6c1 --- /dev/null +++ b/extensions/powershell/snippets/powershell.json @@ -0,0 +1,16 @@ +{ + "Region Start": { + "prefix": "#region", + "body": [ + "#region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#endregion", + "body": [ + "#endregion" + ], + "description": "Folding Region End" + } +} diff --git a/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage b/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage index f54cf896b52..1ad8b5e38b5 100644 --- a/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage +++ b/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage @@ -45,7 +45,7 @@
begin - (?<![\\-])# + (?<![`\\-])# end $ name @@ -246,7 +246,7 @@ match - (?<!\w)((?i:begin|break|catch|continue|data|define|do|dynamicparam|else|elseif|end|exit|finally|for|foreach(?!-object)|from|if|in|inlinescript|parallel|param|process|return|switch|throw|trap|try|until|using|var|where(?!=-object)|while)|%|\?)(?!\w) + (?<!\w)((?i:begin|break|catch|continue|data|define|do|dynamicparam|else|elseif|end|exit|finally|for|foreach(?!-object)|from|if|in|inlinescript|parallel|param|process|return|switch|throw|trap|try|until|using|var|where(?!-object)|while)|%|\?)(?!\w) name keyword.control.powershell @@ -426,6 +426,14 @@ name support.function.powershell
+ + comment + Builtin cmdlets with reserved verbs + match + (?<!\w)(?i:where-object)(?!\w) + name + support.function.powershell +
commentEmbeddedDocs diff --git a/extensions/pug/language-configuration.json b/extensions/pug/language-configuration.json index e22b6120252..00f4885d46e 100644 --- a/extensions/pug/language-configuration.json +++ b/extensions/pug/language-configuration.json @@ -20,5 +20,8 @@ ["(", ")"], ["'", "'"], ["\"", "\""] - ] + ], + "folding": { + "offSide": true + } } \ No newline at end of file diff --git a/extensions/python/.vscode/launch.json b/extensions/python/.vscode/launch.json index 476551bebae..5e5696dce52 100644 --- a/extensions/python/.vscode/launch.json +++ b/extensions/python/.vscode/launch.json @@ -7,12 +7,12 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" + "--extensionDevelopmentPath=${workspaceFolder}" ], "stopOnEntry": false, "sourceMaps": true, - "outDir": "${workspaceRoot}/out", + "outDir": "${workspaceFolder}/out", "preLaunchTask": "npm" - } + } ] } \ No newline at end of file diff --git a/extensions/python/.vscode/tasks.json b/extensions/python/.vscode/tasks.json index a132a04214d..9e5593ade83 100644 --- a/extensions/python/.vscode/tasks.json +++ b/extensions/python/.vscode/tasks.json @@ -1,5 +1,5 @@ // Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team +// ${workspaceFolder}: the root folder of the team // ${file}: the current opened file // ${fileBasename}: the current opened file's basename // ${fileDirname}: the current opened file's dirname diff --git a/extensions/python/language-configuration.json b/extensions/python/language-configuration.json index c995ea91f3d..14ad98220b4 100644 --- a/extensions/python/language-configuration.json +++ b/extensions/python/language-configuration.json @@ -21,6 +21,12 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] - // enhancedBrackets: [ { open: /.*:\s*$/, closeComplete: 'else:' } ], -} \ No newline at end of file + ], + "folding": { + "offSide": true, + "markers": { + "start": "^\\s*#region\\b", + "end": "^\\s*#endregion\\b" + } + } +} diff --git a/extensions/python/test/colorize-results/test_py.json b/extensions/python/test/colorize-results/test_py.json index b456114b1ed..235958f078f 100644 --- a/extensions/python/test/colorize-results/test_py.json +++ b/extensions/python/test/colorize-results/test_py.json @@ -5294,8 +5294,8 @@ "c": "(", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "support.other.parenthesis.regexp: #CE9178", + "light_plus": "support.other.parenthesis.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5305,8 +5305,8 @@ "c": "[", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.character.set.begin.regexp: #CE9178", + "light_plus": "punctuation.character.set.begin.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5316,19 +5316,19 @@ "c": "0-9-", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.set.regexp: #D16969", + "light_plus": "constant.character.set.regexp: #811F3F", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { "c": "]", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.character.set.end.regexp: #CE9178", + "light_plus": "punctuation.character.set.end.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5338,8 +5338,8 @@ "c": "*", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", + "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", + "light_plus": "keyword.operator.quantifier.regexp: #000000", "dark_vs": "keyword.operator: #D4D4D4", "light_vs": "keyword.operator: #000000", "hc_black": "keyword.operator: #D4D4D4" @@ -5349,8 +5349,8 @@ "c": ")", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "support.other.parenthesis.regexp: #CE9178", + "light_plus": "support.other.parenthesis.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5371,8 +5371,8 @@ "c": "*", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", + "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", + "light_plus": "keyword.operator.quantifier.regexp: #000000", "dark_vs": "keyword.operator: #D4D4D4", "light_vs": "keyword.operator: #000000", "hc_black": "keyword.operator: #D4D4D4" @@ -5382,8 +5382,8 @@ "c": "(", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "support.other.parenthesis.regexp: #CE9178", + "light_plus": "support.other.parenthesis.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5393,8 +5393,8 @@ "c": "[", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.character.set.begin.regexp: #CE9178", + "light_plus": "punctuation.character.set.begin.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5404,19 +5404,19 @@ "c": "A-Za-z", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.set.regexp: #D16969", + "light_plus": "constant.character.set.regexp: #811F3F", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { "c": "]", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.character.set.end.regexp: #CE9178", + "light_plus": "punctuation.character.set.end.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5426,8 +5426,8 @@ "c": "+", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", + "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", + "light_plus": "keyword.operator.quantifier.regexp: #000000", "dark_vs": "keyword.operator: #D4D4D4", "light_vs": "keyword.operator: #000000", "hc_black": "keyword.operator: #D4D4D4" @@ -5437,8 +5437,8 @@ "c": ")", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "support.other.parenthesis.regexp: #CE9178", + "light_plus": "support.other.parenthesis.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5470,8 +5470,8 @@ "c": "+", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", + "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", + "light_plus": "keyword.operator.quantifier.regexp: #000000", "dark_vs": "keyword.operator: #D4D4D4", "light_vs": "keyword.operator: #000000", "hc_black": "keyword.operator: #D4D4D4" @@ -5481,8 +5481,8 @@ "c": "(", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "support.other.parenthesis.regexp: #CE9178", + "light_plus": "support.other.parenthesis.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -5503,8 +5503,8 @@ "c": "*", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", + "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", + "light_plus": "keyword.operator.quantifier.regexp: #000000", "dark_vs": "keyword.operator: #D4D4D4", "light_vs": "keyword.operator: #000000", "hc_black": "keyword.operator: #D4D4D4" @@ -5514,8 +5514,8 @@ "c": ")", "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "support.other.parenthesis.regexp: #CE9178", + "light_plus": "support.other.parenthesis.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -6504,8 +6504,8 @@ "c": "[", "t": "source.python string.regexp.quoted.multi.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "punctuation.character.set.begin.regexp: #CE9178", + "light_plus": "punctuation.character.set.begin.regexp: #D16969", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", "hc_black": "string.regexp: #D16969" @@ -6515,11 +6515,11 @@ "c": "1,2)`` leads to", "t": "source.python string.regexp.quoted.multi.python meta.character.set.regexp constant.character.set.regexp", "r": { - "dark_plus": "string.regexp: #D16969", - "light_plus": "string.regexp: #811F3F", + "dark_plus": "constant.character.set.regexp: #D16969", + "light_plus": "constant.character.set.regexp: #811F3F", "dark_vs": "string.regexp: #D16969", "light_vs": "string.regexp: #811F3F", - "hc_black": "string.regexp: #D16969" + "hc_black": "constant.character: #569CD6" } }, { diff --git a/extensions/python/tsconfig.json b/extensions/python/tsconfig.json index a2b5bcdfddf..b16347a7524 100644 --- a/extensions/python/tsconfig.json +++ b/extensions/python/tsconfig.json @@ -5,7 +5,8 @@ "es2015" ], "module": "commonjs", - "outDir": "./out" + "outDir": "./out", + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/r/OSSREADME.json b/extensions/r/OSSREADME.json index 9cf3b6c42fe..bd7a0cab273 100644 --- a/extensions/r/OSSREADME.json +++ b/extensions/r/OSSREADME.json @@ -1,17 +1,7 @@ // ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: [{ - "name": "textmate/r.tmbundle", + "name": "Ikuyadeu/vscode-R", "version": "0.0.0", - "license": "TextMate Bundle License", - "repositoryURL": "https://github.com/textmate/r.tmbundle", - "licenseDetail": [ - "Copyright (c) textmate-r.tmbundle project authors", - "", - "If not otherwise specified (see below), files in this folder fall under the following license: ", - "", - "Permission to copy, use, modify, sell and distribute this", - "software is granted. This software is provided \"as is\" without", - "express or implied warranty, and with no claim as to its", - "suitability for any purpose." - ] + "license": "MIT", + "repositoryURL": "https://github.com/Ikuyadeu/vscode-R" }] diff --git a/extensions/r/package.json b/extensions/r/package.json index e1104e23440..96f89e8c67b 100644 --- a/extensions/r/package.json +++ b/extensions/r/package.json @@ -4,7 +4,7 @@ "publisher": "vscode", "engines": { "vscode": "*" }, "scripts": { - "update-grammar": "node ../../build/npm/update-grammar.js textmate/r.tmbundle Syntaxes/R.plist ./syntaxes/r.tmLanguage.json" + "update-grammar": "node ../../build/npm/update-grammar.js Ikuyadeu/vscode-R syntax/r.json ./syntaxes/r.tmLanguage.json" }, "contributes": { "languages": [{ diff --git a/extensions/r/syntaxes/r.tmLanguage.json b/extensions/r/syntaxes/r.tmLanguage.json index 0ba828e6eb2..38ce48074cb 100644 --- a/extensions/r/syntaxes/r.tmLanguage.json +++ b/extensions/r/syntaxes/r.tmLanguage.json @@ -1,209 +1,555 @@ { "information_for_contributors": [ - "This file has been converted from https://github.com/textmate/r.tmbundle/blob/master/Syntaxes/R.plist", + "This file has been converted from https://github.com/Ikuyadeu/vscode-R/blob/master/syntax/r.json", "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/textmate/r.tmbundle/commit/6b04ff3424f3f1cdfe64a9cfb71d8765959be250", + "version": "https://github.com/Ikuyadeu/vscode-R/commit/b3ef459a3999160d97ea28f4754fda810417f99f", "fileTypes": [ "R", "r", - "s", "S", + "s", "Rprofile" ], + "foldingStartMarker": "(\\(\\s*$|\\{\\s*$)", + "foldingStopMarker": "(^\\s*\\)|^\\s*\\})", "keyEquivalent": "^~R", "name": "R", "patterns": [ { - "captures": { - "1": { - "name": "comment.line.pragma.r" - }, - "2": { - "name": "entity.name.pragma.name.r" - } - }, - "match": "^(#pragma[ \\t]+mark)[ \\t](.*)", - "name": "comment.line.pragma-mark.r" + "include": "#roxygen" }, { - "begin": "(^[ \\t]+)?(?=#)", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.r" - } - }, - "end": "(?!\\G)", + "include": "#comments" + }, + { + "include": "#constants" + }, + { + "include": "#keywords" + }, + { + "include": "#storage-type" + }, + { + "include": "#strings" + }, + { + "include": "#brackets" + }, + { + "include": "#function-declarations" + }, + { + "include": "#lambda-functions" + }, + { + "include": "#builtin-functions" + }, + { + "include": "#function-calls" + }, + { + "include": "#general-variables" + } + ], + "repository": { + "comments": { "patterns": [ { - "begin": "#", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.r" + "captures": { + "1": { + "name": "comment.line.pragma.r" + }, + "2": { + "name": "entity.name.pragma.name.r" } }, - "end": "\\n", - "name": "comment.line.number-sign.r" - } - ] - }, - { - "match": "\\b(logical|numeric|character|complex|matrix|array|data\\.frame|list|factor)(?=\\s*\\()", - "name": "storage.type.r" - }, - { - "match": "\\b(function|if|break|next|repeat|else|for|return|switch|while|in|invisible)\\b", - "name": "keyword.control.r" - }, - { - "match": "\\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?)(i|L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b", - "name": "constant.numeric.r" - }, - { - "match": "\\b(T|F|TRUE|FALSE|NULL|NA|Inf|NaN)\\b", - "name": "constant.language.r" - }, - { - "match": "\\b(pi|letters|LETTERS|month\\.abb|month\\.name)\\b", - "name": "support.constant.misc.r" - }, - { - "match": "(\\-|\\+|\\*|\\/|%\\/%|%%|%\\*%|%in%|%o%|%x%|\\^)", - "name": "keyword.operator.arithmetic.r" - }, - { - "match": "(=|<-|<<-|->|->>)", - "name": "keyword.operator.assignment.r" - }, - { - "match": "(==|!=|<>|<|>|<=|>=)", - "name": "keyword.operator.comparison.r" - }, - { - "match": "(!|&{1,2}|[|]{1,2})", - "name": "keyword.operator.logical.r" - }, - { - "match": "(\\.\\.\\.|\\$|@|:|\\~)", - "name": "keyword.other.r" - }, - { - "begin": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.r" - } - }, - "end": "\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.r" - } - }, - "name": "string.quoted.double.r", - "patterns": [ - { - "match": "\\\\.", - "name": "constant.character.escape.r" - } - ] - }, - { - "begin": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.r" - } - }, - "end": "'", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.r" - } - }, - "name": "string.quoted.single.r", - "patterns": [ - { - "match": "\\\\.", - "name": "constant.character.escape.r" - } - ] - }, - { - "captures": { - "1": { - "name": "entity.name.function.r" + "match": "^(#pragma[ \\t]+mark)[ \\t](.*)", + "name": "comment.line.pragma-mark.r" }, - "2": { + { + "begin": "(^[ \\t]+)?(?=#)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.r" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "#", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.r" + } + }, + "end": "\\n", + "name": "comment.line.number-sign.r" + } + ] + } + ] + }, + "constants": { + "patterns": [ + { + "match": "\\b(pi|letters|LETTERS|month\\.abb|month\\.name)\\b", + "name": "support.constant.misc.r" + }, + { + "match": "\\b(TRUE|FALSE|NULL|NA|NA_integer_|NA_real_|NA_complex_|NA_character_|Inf|NaN)\\b", + "name": "constant.language.r" + }, + { + "match": "\\b0(x|X)[0-9a-fA-F]+i\\b", + "name": "constant.numeric.imaginary.hexadecimal.r" + }, + { + "match": "\\b[0-9]+\\.?[0-9]*(?:(e|E)(\\+|-)?[0-9]+)?i\\b", + "name": "constant.numeric.imaginary.decimal.r" + }, + { + "match": "\\.[0-9]+(?:(e|E)(\\+|-)?[0-9]+)?i\\b", + "name": "constant.numeric.imaginary.decimal.r" + }, + { + "match": "\\b0(x|X)[0-9a-fA-F]+L\\b", + "name": "constant.numeric.integer.hexadecimal.r" + }, + { + "match": "\\b(?:[0-9]+\\.?[0-9]*)L\\b", + "name": "constant.numeric.integer.decimal.r" + }, + { + "match": "\\b0(x|X)[0-9a-fA-F]+\\b", + "name": "constant.numeric.float.hexadecimal.r" + }, + { + "match": "\\b[0-9]+\\.?[0-9]*(?:(e|E)(\\+|-)?[0-9]+)?\\b", + "name": "constant.numeric.float.decimal.r" + }, + { + "match": "\\.[0-9]+(?:(e|E)(\\+|-)?[0-9]+)?\\b", + "name": "constant.numeric.float.decimal.r" + } + ] + }, + "general-variables": { + "patterns": [ + { + "captures": { + "1": { + "name": "variable.parameter.r" + }, + "2": { + "name": "keyword.operator.assignment.r" + } + }, + "match": "([[:alpha:].][[:alnum:]._]*)\\s*(=)(?=[^=])" + }, + { + "match": "\\b([\\d_][[:alnum:]._]+)\\b", + "name": "invalid.illegal.variable.other.r" + }, + { + "match": "\\b([[:alnum:]_]+)(?=::)", + "name": "entity.namespace.r" + }, + { + "match": "\\b([[:alnum:]._]+)\\b", + "name": "variable.other.r" + } + ] + }, + "keywords": { + "patterns": [ + { + "match": "\\b(break|next|repeat|else|in)\\b", + "name": "keyword.control.r" + }, + { + "match": "\\b(ifelse|if|for|return|switch|while|invisible)\\b(?=\\s*\\()", + "name": "keyword.control.r" + }, + { + "match": "(\\-|\\+|\\*|\\/|%\\/%|%%|%\\*%|%o%|%x%|\\^)", + "name": "keyword.operator.arithmetic.r" + }, + { + "match": "==", + "name": "keyword.operator.comarison.r" + }, + { + "match": "(:=|<-|<<-|->|->>)", "name": "keyword.operator.assignment.r" }, - "3": { - "name": "keyword.control.r" - } - }, - "match": "([[:alpha:].][[:alnum:]._]*)\\s*(<-)\\s*(function)", - "name": "meta.function.r" - }, - { - "captures": { - "1": { - "name": "entity.name.tag.r" + { + "match": "(!=|<>|<|>|<=|>=|%in%)", + "name": "keyword.operator.comparison.r" }, - "4": { - "name": "entity.name.type.r" + { + "match": "(!|&{1,2}|[|]{1,2})", + "name": "keyword.operator.logical.r" + }, + { + "match": "(%between%|%chin%|%like%|%\\+%|%\\+replace%|%:%|%do%|%dopar%|%>%|%<>%|%T>%|%\\$%)", + "name": "keyword.operator.other.r" + }, + { + "match": "(\\.\\.\\.|\\$|:|\\~|@)", + "name": "keyword.other.r" + } + ] + }, + "storage-type": { + "patterns": [ + { + "match": "\\b(character|complex|double|expression|integer|list|logical|numeric|single|raw)\\b(?=\\s*\\()", + "name": "storage.type.r" + } + ] + }, + "strings": { + "patterns": [ + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.r" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.r" + } + }, + "name": "string.quoted.double.r", + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.r" + } + ] + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.r" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.r" + } + }, + "name": "string.quoted.single.r", + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.r" + } + ] + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.r" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.r" + } + }, + "patterns": [ + { + "include": "source.r" + } + ] + }, + { + "begin": "\\[(?!\\[)", + "beginCaptures": { + "0": { + "name": "punctuation.section.brackets.single.begin.r" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.single.end.r" + } + }, + "patterns": [ + { + "include": "source.r" + } + ] + }, + { + "begin": "\\[\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.brackets.double.begin.r" + } + }, + "end": "\\]\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.double.end.r" + } + }, + "contentName": "meta.item-access.arguments.r", + "patterns": [ + { + "include": "source.r" + } + ] + }, + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.braces.begin.r" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.braces.end.r" + } + }, + "patterns": [ + { + "include": "source.r" + } + ] + } + ] + }, + "function-declarations": { + "patterns": [ + { + "begin": "^\\s*([a-zA-Z._][\\w.:]*)\\s*(<", + "end": "(?", "patterns": [ { "include": "#block_comment" diff --git a/extensions/scss/syntaxes/scss.json b/extensions/scss/syntaxes/scss.json index 58990917ec5..520c09e515d 100644 --- a/extensions/scss/syntaxes/scss.json +++ b/extensions/scss/syntaxes/scss.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/atom/language-sass/commit/20fdaf75c1b91a6896df3f63c78506009ae860f4", + "version": "https://github.com/atom/language-sass/commit/d47701c2d389c5e657b8c51a34d90691e4bac3ea", "scopeName": "source.css.scss", "name": "SCSS", "fileTypes": [ @@ -33,6 +33,9 @@ { "include": "#rules" }, + { + "include": "#selectors" + }, { "include": "#property_list" }, @@ -492,6 +495,9 @@ }, { "include": "#rules" + }, + { + "include": "#selectors" } ] } @@ -1155,7 +1161,7 @@ "properties": { "patterns": [ { - "begin": "(? - - - - fileTypes - - sql - ddl - dml - dsql - psql - - keyEquivalent - ^~S - name - SQL - patterns - - - include - #comments - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.sql - - 5 - - name - entity.name.function.sql - - - match - (?i:^\s*(create(?:\s+or\s+replace)?)\s+(aggregate|conversion|database|domain|function|group|(unique\s+)?index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\s+)(['"`]?)(\w+)\4 - name - meta.create.sql - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.sql - - - match - (?i:^\s*(drop)\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)) - name - meta.drop.sql - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.table.sql - - 3 - - name - entity.name.function.sql - - 4 - - name - keyword.other.cascade.sql - - - match - (?i:\s*(drop)\s+(table)\s+(\w+)(\s+cascade)?\b) - name - meta.drop.sql - - - captures - - 1 - - name - keyword.other.create.sql - - 2 - - name - keyword.other.table.sql - - - match - (?i:^\s*(alter)\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\s+) - name - meta.alter.sql - - - captures - - 1 - - name - storage.type.sql - - 10 - - name - constant.numeric.sql - - 11 - - name - storage.type.sql - - 12 - - name - storage.type.sql - - 13 - - name - storage.type.sql - - 14 - - name - constant.numeric.sql - - 15 - - name - storage.type.sql - - 2 - - name - storage.type.sql - - 3 - - name - constant.numeric.sql - - 4 - - name - storage.type.sql - - 5 - - name - constant.numeric.sql - - 6 - - name - storage.type.sql - - 7 - - name - constant.numeric.sql - - 8 - - name - constant.numeric.sql - - 9 - - name - storage.type.sql - - - match - (?xi) - - # normal stuff, capture 1 - \b(bigint|bigserial|bit|boolean|box|bytea|cidr|circle|date|double\sprecision|inet|int|integer|line|lseg|macaddr|money|oid|path|point|polygon|real|serial|smallint|sysdate|text)\b - - # numeric suffix, capture 2 + 3i - |\b(bit\svarying|character\s(?:varying)?|tinyint|var\schar|float|interval)\((\d+)\) - - # optional numeric suffix, capture 4 + 5i - |\b(char|number|varchar\d?)\b(?:\((\d+)\))? - - # special case, capture 6 + 7i + 8i - |\b(numeric|decimal)\b(?:\((\d+),(\d+)\))? - - # special case, captures 9, 10i, 11 - |\b(times?)\b(?:\((\d+)\))?(\swith(?:out)?\stime\szone\b)? - - # special case, captures 12, 13, 14i, 15 - |\b(timestamp)(?:(s|tz))?\b(?:\((\d+)\))?(\s(with|without)\stime\szone\b)? - - - - - match - (?i:\b((?:primary|foreign)\s+key|references|on\sdelete(\s+cascade)?|check|constraint)\b) - name - storage.modifier.sql - - - match - \b\d+\b - name - constant.numeric.sql - - - match - (?i:\b(select(\s+distinct)?|insert\s+(ignore\s+)?into|update|delete|from|declare|set|where|group\sby|or|like|and|union(\s+all)?|having|order\sby|limit|(inner|cross)\s+join|join|straight_join|(left|right)(\s+outer)?\s+join|natural(\s+(left|right)(\s+outer)?)?\s+join)\b) - name - keyword.other.DML.sql - - - match - (?i:\b(on|((is\s+)?not\s+)?null)\b) - name - keyword.other.DDL.create.II.sql - - - match - (?i:\b(values|go|use|into|exec|execute|openquery)\b) - name - keyword.other.DML.II.sql - - - match - (?i:\b(begin(\s+work)?|start\s+transaction|commit(\s+work)?|rollback(\s+work)?)\b) - name - keyword.other.LUW.sql - - - match - (?i:\b(grant(\swith\sgrant\soption)?|revoke)\b) - name - keyword.other.authorization.sql - - - match - (?i:\bin\b) - name - keyword.other.data-integrity.sql - - - match - (?i:^\s*(comment\s+on\s+(table|column|aggregate|constraint|database|domain|function|index|operator|rule|schema|sequence|trigger|type|view))\s+.*?\s+(is)\s+) - name - keyword.other.object-comments.sql - - - match - (?i)\bAS\b - name - keyword.other.alias.sql - - - match - (?i)\b(DESC|ASC)\b - name - keyword.other.order.sql - - - match - \* - name - keyword.operator.star.sql - - - match - [!<>]?=|<>|<|> - name - keyword.operator.comparison.sql - - - match - -|\+|/ - name - keyword.operator.math.sql - - - match - \|\| - name - keyword.operator.concatenator.sql - - - comment - List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html - match - (?i)\b(CURRENT_(DATE|TIME(STAMP)?|USER)|(SESSION|SYSTEM)_USER)\b - name - support.function.scalar.sql - - - comment - List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html - match - (?i)\b(AVG|COUNT|MIN|MAX|SUM)(?=\s*\() - name - support.function.aggregate.sql - - - match - (?i)\b(CONCATENATE|CONVERT|LOWER|SUBSTRING|TRANSLATE|TRIM|UPPER)\b - name - support.function.string.sql - - - captures - - 1 - - name - constant.other.database-name.sql - - 2 - - name - constant.other.table-name.sql - - - match - (\w+?)\.(\w+) - - - include - #strings - - - include - #regexps - - - captures - - 1 - - name - punctuation.section.scope.begin.sql - - 2 - - name - punctuation.section.scope.end.sql - - - comment - Allow for special ↩ behavior - match - (\()(\)) - name - meta.block.sql - - - repository - - comments - - patterns - - - begin - (^[ \t]+)?(?=--) - beginCaptures - - 1 - - name - punctuation.whitespace.comment.leading.sql - - - end - (?!\G) - patterns - - - begin - -- - beginCaptures - - 0 - - name - punctuation.definition.comment.sql - - - end - \n - name - comment.line.double-dash.sql - - - - - begin - (^[ \t]+)?(?=#) - beginCaptures - - 1 - - name - punctuation.whitespace.comment.leading.sql - - - end - (?!\G) - patterns - - - begin - # - beginCaptures - - 0 - - name - punctuation.definition.comment.sql - - - end - \n - name - comment.line.number-sign.sql - - - - - begin - /\* - captures - - 0 - - name - punctuation.definition.comment.sql - - - end - \*/ - name - comment.block.c - - - - regexps - - patterns - - - begin - /(?=\S.*/) - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - / - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.regexp.sql - patterns - - - include - #string_interpolation - - - match - \\/ - name - constant.character.escape.slash.sql - - - - - begin - %r\{ - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - comment - We should probably handle nested bracket pairs!?! -- Allan - end - \} - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.regexp.modr.sql - patterns - - - include - #string_interpolation - - - - - - string_escape - - match - \\. - name - constant.character.escape.sql - - string_interpolation - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 3 - - name - punctuation.definition.string.end.sql - - - match - (#\{)([^\}]*)(\}) - name - string.interpolated.sql - - strings - - patterns - - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 2 - - name - punctuation.definition.string.end.sql - - - comment - this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines. - match - (')[^'\\]*(') - name - string.quoted.single.sql - - - begin - ' - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - ' - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.quoted.single.sql - patterns - - - include - #string_escape - - - - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 2 - - name - punctuation.definition.string.end.sql - - - comment - this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines. - match - (`)[^`\\]*(`) - name - string.quoted.other.backtick.sql - - - begin - ` - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - ` - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.quoted.other.backtick.sql - patterns - - - include - #string_escape - - - - - captures - - 1 - - name - punctuation.definition.string.begin.sql - - 2 - - name - punctuation.definition.string.end.sql - - - comment - this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines. - match - (")[^"#]*(") - name - string.quoted.double.sql - - - begin - " - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - " - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.quoted.double.sql - patterns - - - include - #string_interpolation - - - - - begin - %\{ - beginCaptures - - 0 - - name - punctuation.definition.string.begin.sql - - - end - \} - endCaptures - - 0 - - name - punctuation.definition.string.end.sql - - - name - string.other.quoted.brackets.sql - patterns - - - include - #string_interpolation - - - - - - - scopeName - source.sql - uuid - C49120AC-6ECC-11D9-ACC8-000D93589AF6 - - diff --git a/extensions/sql/syntaxes/sql.tmLanguage.json b/extensions/sql/syntaxes/sql.tmLanguage.json new file mode 100644 index 00000000000..033fc63c97f --- /dev/null +++ b/extensions/sql/syntaxes/sql.tmLanguage.json @@ -0,0 +1,472 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/Microsoft/vscode-mssql/blob/master/syntaxes/SQL.plist", + "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/vscode-mssql/commit/cfc8b65ed6daf8252b0cbfd5611aadbd49353bca", + "fileTypes": [ + "sql", + "ddl", + "dml" + ], + "keyEquivalent": "^~S", + "name": "SQL", + "patterns": [ + { + "match": "\\b(?i)(abort|abort_after_wait|absent|absolute|accent_sensitivity|acceptable_cursopt|acp|action|activation|address|admin|aes_128|aes_192|aes_256|affinity|after|aggregate|algorithm|all_constraints|all_errormsgs|all_indexes|all_levels|all_results|allow_connections|allow_dup_row|allow_encrypted_value_modifications|allow_page_locks|allow_row_locks|allow_snapshot_isolation|altercolumn|always|anonymous|ansi_defaults|ansi_null_default|ansi_null_dflt_off|ansi_null_dflt_on|ansi_nulls|ansi_padding|ansi_warnings|appdomain|append|application|apply|arithabort|arithignore|assembly|asymmetric|asynchronous_commit|at|atan2|atomic|attach|attach_force_rebuild_log|attach_rebuild_log|audit|auth_realm|authentication|auto|auto_cleanup|auto_close|auto_create_statistics|auto_shrink|auto_update_statistics|auto_update_statistics_async|automated_backup_preference |automatic|autopilot|availability|availability_mode|backup_priority|base64|basic|batches|batchsize|before|bigint|binary|binding|bit|block|blocksize|bmk|broker|broker_instance|bucket_count|buffer|buffercount|bulk_logged|by|call|caller|card|case|cast|catalog|catch|cert|certificate|change_retention|change_tracking|change_tracking_context|changes|char|character|character_set|check_expiration|check_policy|checkconstraints|checkindex|checkpoint|cleanup_policy|clear|clear_port|codepage|collection|column_encryption_key|column_master_key|columnstore|columnstore_archive|colv_80_to_100|colv_100_to_80|commit_differential_base|committed|compatibility_level|compress_all_row_groups|compression|compression_delay|concat_null_yields_null|concatenate|configuration|connect|continue_after_error|contract|contract_name|control|conversation|conversation_group_id|conversation_handle|copy|copy_only|count_rows|counter|create|credential|cross|cryptographic|cryptographic_provider|cube|cursor_close_on_commit|cursor_default|data|data_compression|data_flush_interval_seconds|data_mirroring|data_purity|data_source|database|database_name|database_snapshot|datafiletype|date_correlation_optimization|date|datefirst|dateformat|date_format|datetime|datetime2|datetimeoffset|days|db_chaining|dbid|dbidexec|dbo_only|deadlock_priority|dec|decimal|declare|decrypt|decrypt_a|decryption|default_database|default_language|default_logon_domain|default_schema|definition|delay|delayed_durability|delimitedtext|density_vector|dependent|des|description|desired_state|desx|differential|digest|disable|disable_broker|disable_def_cnst_chk|disabled|disk|distribution|drop|drop_existing|dts_buffers|dump|durability|dynamic|edition|elements|emergency|empty|enable|enable_broker|enabled|encoding|encrypted|encrypted_value|encryption|encryption_type|end|endpoint|endpoint_url|enhancedintegrity|entry|error_broker_conversations|errorfile|estimateonly|event|exec|executable|exists|expand|expiredate|expiry_date|explicit|external_access|failover|failover_mode|failure_condition_level|fast|fast_forward|fastfirstrow|federated_service_account|field_terminator|fieldterminator|file|filelistonly|filegroup|filename|filestream|filestream_log|filestream_on|filetable|file_format|filter|fips_flagger|fire_triggers|first|firstrow|float|flush_interval_seconds|fmtonly|following|force|force_failover_allow_data_loss|force_service_allow_data_loss|forced|forceplan|formatfile|format_options|format_type|formsof|forward_only|free_cursors|free_exec_context|fullscan|fulltext|fulltextall|fulltextkey|function|generated|get|geography|geometry|global|go|governor|guid|hadoop|hardening|hash|hashed|header_limit|headeronly|health_check_timeout|hidden|hierarchyid|histogram|histogram_steps|hits_cursors|hits_exec_context|hours|http|identity_value|if|ifnull|ignore_constraints|ignore_dup_key|ignore_dup_row|ignore_triggers|image|immediate|implicit_transactions|include|include_null_values|inflectional|init|initiator|insensitive|insert|instead|int|integer|integrated|intermediate|interval_length_minutes|into|inuse_cursors|inuse_exec_context|io|is|isabout|iso_week|isolation|job_tracker_location|json|keep|keep_nulls|keep_replication|keepdefaults|keepfixed|keepidentity|keepnulls|kerberos|key|key_path|key_source|key_store_provider_name|keyset|kilobytes_per_batch|labelonly|langid|language|last|lastrow|legacy_cardinality_estimation|length|level|lifetime|lineage_80_to_100|lineage_100_to_80|listener_ip|listener_port|load|loadhistory|lob_compaction|local|local_service_name|locate|location|lock_escalation|lock_timeout|lockres|login|login_type|loop|manual|mark_in_use_for_removal|masked|master|max_queue_readers|max_duration|max_outstanding_io_per_volume|maxdop|maxerrors|maxlength|maxtransfersize|max_plans_per_query|max_storage_size_mb|mediadescription|medianame|mediapassword|memogroup|memory_optimized|merge|message|message_forward_size|message_forwarding|microsecond|millisecond|minutes|mirror_address|misses_cursors|misses_exec_context|mixed|modify|money|move|multi_user|must_change|name|namespace|nanosecond|native|native_compilation|nchar|ncharacter|never|new_account|new_broker|newname|next|no|no_browsetable|no_checksum|no_compression|no_infomsgs|no_triggers|no_truncate|nocount|noexec|noexpand|noformat|noinit|nolock|nonatomic|nondurable|none|norecompute|norecovery|noreset|norewind|noskip|not|notification|nounload|now|nowait|ntext|ntlm|numeric|numeric_roundabort|nvarchar|object|objid|oem|offline|old_account|online|operation_mode|openjson|optimistic|option|orc|out|outer|output|over|override|owner|ownership|pad_index|page|page_checksum|page_verify|pagecount|paglock|param|parameter_sniffing|parameter_type_expansion|parameterization|parquet|parseonly|partial|partition|partner|password|path|pause|percentage|permission_set|persisted|period|physical_only|plan_forcing_mode|policy|pool|population|ports|preceding|precision|predicate|presume_abort|primary|primary_role|print|prior|priority |priority_level|private|procedure_name|profile|provider|query_capture_mode|query_governor_cost_limit|query_optimizer_hotfixes|query_store|queue|quoted_identifier|range|raw|rcfile|rc2|rc4|rc4_128|rdbms|read_committed_snapshot|read|read_only|read_write|readcommitted|readcommittedlock|readonly|readpast|readuncommitted|readwrite|real|rebuild|receive|recmodel_70backcomp|recompile|recovery|recursive|recursive_triggers|redo_queue|reject_sample_value|reject_type|reject_value|relative|remote|remote_data_archive|remote_proc_transactions|remote_service_name|remove|removed_cursors|removed_exec_context|reorganize|repeat|repeatable|repeatableread|replica|replicated|replnick_100_to_80|replnickarray_80_to_100|replnickarray_100_to_80|required|required_cursopt|resample|reset|resource|resource_manager_location|restart|restore|restricted_user|resume|retaindays|retention|return|rewind|rewindonly|returns|robust|role|rollup|root|round_robin|route|row|rowdump|rowlock|row_terminator|rows|rows_per_batch|rowsets_only|rowterminator|rowversion|rsa_1024|rsa_2048|rsa_3072|rsa_4096|rsa_512|safe|safety|sample|schemabinding|scoped|scroll|scroll_locks|sddl|secexpr|secondary|secondary_only|secondary_role|secret|security|securityaudit|selective|self|send|sent|sequence|serde_method|serializable|server|service|service_broker|service_name|service_objective|session_timeout|session|sessions|seterror|setopts|sets|shard_map_manager|shard_map_name|sharded|shared_memory|show_statistics|showplan_all|showplan_text|showplan_xml|showplan_xml_with_recompile|shrinkdb|sid|signature|simple|single_blob|single_clob|single_nclob|single_user|singleton|site|size_based_cleanup_mode|skip|smalldatetime|smallint|smallmoney|snapshot|snapshot_import|snapshotrestorephase|soap|softnuma|sort_in_tempdb|sorted_data|sorted_data_reorg|spatial|sql|sql_bigint|sql_binary|sql_bit|sql_char|sql_date|sql_decimal|sql_double|sql_float|sql_guid|sql_handle|sql_longvarbinary|sql_longvarchar|sql_numeric|sql_real|sql_smallint|sql_time|sql_timestamp|sql_tinyint|sql_tsi_day|sql_tsi_frac_second|sql_tsi_hour|sql_tsi_minute|sql_tsi_month|sql_tsi_quarter|sql_tsi_second|sql_tsi_week|sql_tsi_year|sql_type_date|sql_type_time|sql_type_timestamp|sql_varbinary|sql_varchar|sql_variant|sql_wchar|sql_wlongvarchar|ssl|ssl_port|standard|standby|start|start_date|started|stat_header|state|statement|static|statistics|statistics_incremental|statistics_norecompute|statistics_only|statman|stats_stream|status|stop|stop_on_error|stopat|stopatmark|stopbeforemark|stoplist|stopped|string_delimiter|subject|supplemental_logging|supported|suspend|symmetric|synchronous_commit|synonym|sysname|system|system_time|system_versioning|table|tableresults|tablock|tablockx|take|tape|target|target_index|target_partition|tcp|temporal_history_retention|text|textimage_on|then|thesaurus|throw|time|timeout|timestamp|tinyint|to|top|torn_page_detection|track_columns_updated|tran|transaction|transfer|triple_des|triple_des_3key|trustworthy|try|tsql|type|type_desc|type_warning|tzoffset|uid|unbounded|uncommitted|uniqueidentifier|unlimited|unload|unlock|unsafe|updlock|url|use|useplan|useroptions|use_type_default|using|utcdatetime|valid_xml|validation|value|values|varbinary|varchar|verbose|verifyonly|version|view_metadata|virtual_device|visiblity|webmethod|weekday|weight|well_formed_xml|when|widechar|widechar_ansi|widenative|windows|with|within|witness|without|without_array_wrapper|workload|wsdl|xact_abort|xlock|xml|xmlschema|xquery|xsinil|zone)\\b", + "name": "keyword.other.sql" + }, + { + "include": "#comments" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.sql" + }, + "5": { + "name": "entity.name.function.sql" + } + }, + "match": "(?i:^\\s*(create(?:\\s+or\\s+replace)?)\\s+(aggregate|conversion|database|domain|function|group|(unique\\s+)?index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\\s+)(['\"`]?)(\\w+)\\4", + "name": "meta.create.sql" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.sql" + } + }, + "match": "(?i:^\\s*(drop)\\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view))", + "name": "meta.drop.sql" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.table.sql" + }, + "3": { + "name": "entity.name.function.sql" + }, + "4": { + "name": "keyword.other.cascade.sql" + } + }, + "match": "(?i:\\s*(drop)\\s+(table)\\s+(\\w+)(\\s+cascade)?\\b)", + "name": "meta.drop.sql" + }, + { + "captures": { + "1": { + "name": "keyword.other.create.sql" + }, + "2": { + "name": "keyword.other.table.sql" + } + }, + "match": "(?i:^\\s*(alter)\\s+(aggregate|conversion|database|domain|function|group|index|language|operator class|operator|rule|schema|sequence|table|tablespace|trigger|type|user|view)\\s+)", + "name": "meta.alter.sql" + }, + { + "captures": { + "1": { + "name": "storage.type.sql" + }, + "2": { + "name": "storage.type.sql" + }, + "3": { + "name": "constant.numeric.sql" + }, + "4": { + "name": "storage.type.sql" + }, + "5": { + "name": "constant.numeric.sql" + }, + "6": { + "name": "storage.type.sql" + }, + "7": { + "name": "constant.numeric.sql" + }, + "8": { + "name": "constant.numeric.sql" + }, + "9": { + "name": "storage.type.sql" + }, + "10": { + "name": "constant.numeric.sql" + }, + "11": { + "name": "storage.type.sql" + }, + "12": { + "name": "storage.type.sql" + }, + "13": { + "name": "storage.type.sql" + }, + "14": { + "name": "constant.numeric.sql" + }, + "15": { + "name": "storage.type.sql" + } + }, + "match": "(?xi)\n\n\t\t\t\t# normal stuff, capture 1\n\t\t\t\t \\b(bigint|bigserial|bit|boolean|box|bytea|cidr|circle|date|double\\sprecision|inet|int|integer|line|lseg|macaddr|money|oid|path|point|polygon|real|serial|smallint|sysdate|text)\\b\n\n\t\t\t\t# numeric suffix, capture 2 + 3i\n\t\t\t\t|\\b(bit\\svarying|character\\s(?:varying)?|tinyint|var\\schar|float|interval)\\((\\d+)\\)\n\n\t\t\t\t# optional numeric suffix, capture 4 + 5i\n\t\t\t\t|\\b(char|number|varchar\\d?)\\b(?:\\((\\d+)\\))?\n\n\t\t\t\t# special case, capture 6 + 7i + 8i\n\t\t\t\t|\\b(numeric|decimal)\\b(?:\\((\\d+),(\\d+)\\))?\n\n\t\t\t\t# special case, captures 9, 10i, 11\n\t\t\t\t|\\b(times?)\\b(?:\\((\\d+)\\))?(\\swith(?:out)?\\stime\\szone\\b)?\n\n\t\t\t\t# special case, captures 12, 13, 14i, 15\n\t\t\t\t|\\b(timestamp)(?:(s|tz))?\\b(?:\\((\\d+)\\))?(\\s(with|without)\\stime\\szone\\b)?\n\n\t\t\t" + }, + { + "match": "(?i:\\b((?:primary|foreign)\\s+key|references|on\\sdelete(\\s+cascade)?|check|constraint)\\b)", + "name": "storage.modifier.sql" + }, + { + "match": "\\b\\d+\\b", + "name": "constant.numeric.sql" + }, + { + "match": "(?i:\\b(select(\\s+distinct)?|insert\\s+(ignore\\s+)?into|update|delete|from|set|where|group\\sby|or|like|and|union(\\s+all)?|having|order\\sby|limit|(inner|cross)\\s+join|join|straight_join|(left|right)(\\s+outer)?\\s+join|natural(\\s+(left|right)(\\s+outer)?)?\\s+join)\\b)", + "name": "keyword.other.DML.sql" + }, + { + "match": "(?i:\\b(on|off|((is\\s+)?not\\s+)?null)\\b)", + "name": "keyword.other.DDL.create.II.sql" + }, + { + "match": "(?i:\\bvalues\\b)", + "name": "keyword.other.DML.II.sql" + }, + { + "match": "(?i:\\b(begin(\\s+work)?|start\\s+transaction|commit(\\s+work)?|rollback(\\s+work)?)\\b)", + "name": "keyword.other.LUW.sql" + }, + { + "match": "(?i:\\b(grant(\\swith\\sgrant\\soption)?|revoke)\\b)", + "name": "keyword.other.authorization.sql" + }, + { + "match": "(?i:\\bin\\b)", + "name": "keyword.other.data-integrity.sql" + }, + { + "match": "(?i:^\\s*(comment\\s+on\\s+(table|column|aggregate|constraint|database|domain|function|index|operator|rule|schema|sequence|trigger|type|view))\\s+.*?\\s+(is)\\s+)", + "name": "keyword.other.object-comments.sql" + }, + { + "match": "(?i)\\bAS\\b", + "name": "keyword.other.alias.sql" + }, + { + "match": "(?i)\\b(DESC|ASC)\\b", + "name": "keyword.other.order.sql" + }, + { + "match": "\\*", + "name": "keyword.operator.star.sql" + }, + { + "match": "[!<>]?=|<>|<|>", + "name": "keyword.operator.comparison.sql" + }, + { + "match": "-|\\+|/", + "name": "keyword.operator.math.sql" + }, + { + "match": "\\|\\|", + "name": "keyword.operator.concatenator.sql" + }, + { + "comment": "List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html", + "match": "(?i)\\b(CURRENT_(DATE|TIME(STAMP)?|USER)|(SESSION|SYSTEM)_USER)\\b", + "name": "support.function.scalar.sql" + }, + { + "comment": "List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html", + "match": "(?i)\\b(AVG|COUNT|MIN|MAX|SUM)(?=\\s*\\()", + "name": "support.function.aggregate.sql" + }, + { + "match": "(?i)\\b(CONCATENATE|CONVERT|LOWER|SUBSTRING|TRANSLATE|TRIM|UPPER)\\b", + "name": "support.function.string.sql" + }, + { + "captures": { + "1": { + "name": "constant.other.database-name.sql" + }, + "2": { + "name": "constant.other.table-name.sql" + } + }, + "match": "(\\w+?)\\.(\\w+)" + }, + { + "include": "#strings" + }, + { + "include": "#regexps" + }, + { + "captures": { + "1": { + "name": "punctuation.section.scope.begin.sql" + }, + "2": { + "name": "punctuation.section.scope.end.sql" + } + }, + "comment": "Allow for special ↩ behavior", + "match": "(\\()(\\))", + "name": "meta.block.sql" + } + ], + "repository": { + "comments": { + "patterns": [ + { + "begin": "(^[ \\t]+)?(?=--)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.sql" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "--", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.sql" + } + }, + "end": "\\n", + "name": "comment.line.double-dash.sql" + } + ] + }, + { + "begin": "(^[ \\t]+)?(?=#)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.sql" + } + }, + "end": "(?!\\G)", + "patterns": [] + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.sql" + } + }, + "end": "\\*/", + "name": "comment.block.c" + } + ] + }, + "regexps": { + "patterns": [ + { + "begin": "/(?=\\S.*/)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "/", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.regexp.sql", + "patterns": [ + { + "include": "#string_interpolation" + }, + { + "match": "\\\\/", + "name": "constant.character.escape.slash.sql" + } + ] + }, + { + "begin": "%r\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "comment": "We should probably handle nested bracket pairs!?! -- Allan", + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.regexp.modr.sql", + "patterns": [ + { + "include": "#string_interpolation" + } + ] + } + ] + }, + "string_escape": { + "match": "\\\\.", + "name": "constant.character.escape.sql" + }, + "string_interpolation": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "3": { + "name": "punctuation.definition.string.end.sql" + } + }, + "match": "(#\\{)([^\\}]*)(\\})", + "name": "string.interpolated.sql" + }, + "strings": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "2": { + "name": "punctuation.definition.string.end.sql" + } + }, + "comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.", + "match": "(')[^']*(')", + "name": "string.quoted.single.sql" + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.quoted.single.sql", + "patterns": [ + { + "include": "#string_escape" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "2": { + "name": "punctuation.definition.string.end.sql" + } + }, + "comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.", + "match": "(`)[^`\\\\]*(`)", + "name": "string.quoted.other.backtick.sql" + }, + { + "begin": "`", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "`", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.quoted.other.backtick.sql", + "patterns": [ + { + "include": "#string_escape" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.sql" + }, + "2": { + "name": "punctuation.definition.string.end.sql" + } + }, + "comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.", + "match": "(\")[^\"#]*(\")", + "name": "string.quoted.double.sql" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.quoted.double.sql", + "patterns": [ + { + "include": "#string_interpolation" + } + ] + }, + { + "begin": "%\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.sql" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.sql" + } + }, + "name": "string.other.quoted.brackets.sql", + "patterns": [ + { + "include": "#string_interpolation" + } + ] + } + ] + } + }, + "scopeName": "source.sql", + "uuid": "C49120AC-6ECC-11D9-ACC8-000D93589AF6" +} \ No newline at end of file diff --git a/extensions/sql/test/colorize-results/test_sql.json b/extensions/sql/test/colorize-results/test_sql.json index 7b133d4de64..a44b31e2461 100644 --- a/extensions/sql/test/colorize-results/test_sql.json +++ b/extensions/sql/test/colorize-results/test_sql.json @@ -1,7 +1,7 @@ [ { "c": "CREATE", - "t": "source.sql meta.create.sql keyword.other.create.sql", + "t": "source.sql keyword.other.sql", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -11,51 +11,7 @@ } }, { - "c": " ", - "t": "source.sql meta.create.sql", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "VIEW", - "t": "source.sql meta.create.sql keyword.other.sql", - "r": { - "dark_plus": "keyword: #569CD6", - "light_plus": "keyword: #0000FF", - "dark_vs": "keyword: #569CD6", - "light_vs": "keyword: #0000FF", - "hc_black": "keyword: #569CD6" - } - }, - { - "c": " ", - "t": "source.sql meta.create.sql", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "METRIC_STATS", - "t": "source.sql meta.create.sql entity.name.function.sql", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": " (ID, MONTH, TEMP_C, RAIN_C) ", + "c": " VIEW METRIC_STATS (ID, MONTH, TEMP_C, RAIN_C) ", "t": "source.sql", "r": { "dark_plus": "default: #D4D4D4", diff --git a/extensions/swift/snippets/swift.json b/extensions/swift/snippets/swift.json index ef4deac0206..43591d13a7b 100644 --- a/extensions/swift/snippets/swift.json +++ b/extensions/swift/snippets/swift.json @@ -11,7 +11,7 @@ "prefix": "repeat", "body": [ "repeat {", - " $0", + "\t$0", "} while ${1:true}" ], "description": "repeat...while loop" @@ -20,7 +20,7 @@ "prefix": "while", "body": [ "while ${1:true} {", - " $0", + "\t$0", "}" ], "description": "While loop" @@ -29,7 +29,7 @@ "prefix": "forin", "body": [ "for ${1:item} in ${2:collection} {", - " $0", + "\t$0", "}" ], "description": "For-In statement" @@ -38,7 +38,7 @@ "prefix": "forr", "body": [ "for var ${1:i} = ${2:length} - 1; ${1:i} >= 0; ${1:i}-- {", - " $0", + "\t$0", "}" ], "description": "Reverse for loop" @@ -47,7 +47,7 @@ "prefix": "for", "body": [ "for var ${1:i} = 0; ${1:i} < ${2:length}; ${1:i}++ {", - " $0", + "\t$0", "}" ], "description": "for loop" @@ -56,7 +56,7 @@ "prefix": "if", "body": [ "if ${1:true} {", - " $0", + "\t$0", "}" ], "description": "if statement" @@ -65,7 +65,7 @@ "prefix": "elif", "body": [ "else if ${1:true} {", - " $0", + "\t$0", "}" ], "description": "if statement" @@ -74,7 +74,7 @@ "prefix": "else", "body": [ "else {", - " $0", + "\t$0", "}" ], "description": "Else statement" @@ -83,7 +83,7 @@ "prefix": "guard", "body": [ "guard let ${1:a} = ${2:optional} else {", - " $0", + "\t$0", "}" ], "description": "Guard statement" @@ -92,7 +92,7 @@ "prefix": "ifnil", "body": [ "if let ${1:a} = ${2:optional} {", - " $0", + "\t$0", "}" ], "description": "Optional Binding statement" @@ -102,9 +102,9 @@ "body": [ "switch ${1:switch_on} {", "case ${2:a}:", - " $0", + "\t$0", "default:", - " $1", + "\t$1", "}" ], "description": "Switch statement" @@ -113,9 +113,9 @@ "prefix": "docatch", "body": [ "do {", - " try ${1:function that throws}", + "\ttry ${1:function that throws}", "} catch ${2:pattern} {", - " $0", + "\t$0", "}" ], "description": "Try catch" @@ -124,7 +124,7 @@ "prefix": "enum", "body": [ "enum ${1:Name} {", - " case $0", + "\tcase $0", "}" ], "description": "Enum" diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 9901ee0d6b8..bae5fd48804 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -7,6 +7,13 @@ "foreground": "#6688cc" } }, + { + "scope": ["meta.embedded", "source.groovy.embedded"], + "settings": { + "background": "#000c18", + "foreground": "#6688cc" + } + }, { "name": "Comment", "scope": "comment", diff --git a/extensions/theme-defaults/fileicons/vs_minimal_icons.json b/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json similarity index 100% rename from extensions/theme-defaults/fileicons/vs_minimal_icons.json rename to extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json diff --git a/extensions/theme-defaults/package.json b/extensions/theme-defaults/package.json index a73e2654255..7a48ad6ece2 100644 --- a/extensions/theme-defaults/package.json +++ b/extensions/theme-defaults/package.json @@ -43,7 +43,7 @@ { "id": "vs-minimal", "label": "Minimal (Visual Studio Code)", - "path": "./fileicons/vs_minimal_icons.json" + "path": "./fileicons/vs_minimal-icon-theme.json" } ] } diff --git a/extensions/theme-defaults/themes/dark_plus.json b/extensions/theme-defaults/themes/dark_plus.json index 972481b7e22..6fdfb2263ce 100644 --- a/extensions/theme-defaults/themes/dark_plus.json +++ b/extensions/theme-defaults/themes/dark_plus.json @@ -101,6 +101,59 @@ "settings": { "foreground": "#CE9178" } + }, + { + "name": "Regular expression groups", + "scope": [ + "punctuation.definition.group.regexp", + "punctuation.definition.group.assertion.regexp", + "punctuation.definition.character-class.regexp", + "punctuation.character.set.begin.regexp", + "punctuation.character.set.end.regexp", + "keyword.operator.negation.regexp", + "support.other.parenthesis.regexp" + ], + "settings": { + "foreground": "#CE9178" + } + }, + { + "scope": [ + "constant.character.character-class.regexp", + "constant.other.character-class.set.regexp", + "constant.other.character-class.regexp", + "constant.character.set.regexp" + ], + "settings": { + "foreground": "#d16969" + } + }, + { + "scope": [ + "keyword.operator.or.regexp", + "keyword.control.anchor.regexp" + ], + "settings": { + "foreground": "#DCDCAA" + } + }, + { + "scope": "keyword.operator.quantifier.regexp", + "settings": { + "foreground": "#d7ba7d" + } + }, + { + "scope": "constant.character", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "constant.character.escape", + "settings": { + "foreground": "#d7ba7d" + } } ] } \ No newline at end of file diff --git a/extensions/theme-defaults/themes/dark_vs.json b/extensions/theme-defaults/themes/dark_vs.json index 4dd90c71801..084720561d0 100644 --- a/extensions/theme-defaults/themes/dark_vs.json +++ b/extensions/theme-defaults/themes/dark_vs.json @@ -9,6 +9,16 @@ "background": "#1E1E1E" } }, + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "foreground": "#D4D4D4", + "background": "#1E1E1E" + } + }, { "scope": "emphasis", "settings": { @@ -241,11 +251,11 @@ } }, { - "name": "JavaScript string interpolation ${}", + "name": "String interpolation", "scope": [ "punctuation.definition.template-expression.begin", "punctuation.definition.template-expression.end", - "punctuation.section.embedded.coffee" + "punctuation.section.embedded" ], "settings": { "foreground": "#569cd6" diff --git a/extensions/theme-defaults/themes/hc_black_defaults.json b/extensions/theme-defaults/themes/hc_black_defaults.json index 986fa7cf615..8833ff32c1f 100644 --- a/extensions/theme-defaults/themes/hc_black_defaults.json +++ b/extensions/theme-defaults/themes/hc_black_defaults.json @@ -14,6 +14,16 @@ "background": "#000000" } }, + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "foreground": "#FFFFFF", + "background": "#000000" + } + }, { "scope": "emphasis", "settings": { @@ -61,6 +71,12 @@ "foreground": "#b46695" } }, + { + "scope": "constant.character", + "settings": { + "foreground": "#569cd6" + } + }, { "scope": "entity.name.tag", "settings": { @@ -227,11 +243,11 @@ } }, { - "name": "JavaScript string interpolation ${}", + "name": "String interpolation", "scope": [ "punctuation.definition.template-expression.begin", "punctuation.definition.template-expression.end", - "punctuation.section.embedded.coffee" + "punctuation.section.embedded" ], "settings": { "foreground": "#569cd6" diff --git a/extensions/theme-defaults/themes/light_plus.json b/extensions/theme-defaults/themes/light_plus.json index c087a8f6ca1..3d5775ecec5 100644 --- a/extensions/theme-defaults/themes/light_plus.json +++ b/extensions/theme-defaults/themes/light_plus.json @@ -101,6 +101,60 @@ "settings": { "foreground": "#0451a5" } + }, + { + "name": "Regular expression groups", + "scope": [ + "punctuation.definition.group.regexp", + "punctuation.definition.group.assertion.regexp", + "punctuation.definition.character-class.regexp", + "punctuation.character.set.begin.regexp", + "punctuation.character.set.end.regexp", + "keyword.operator.negation.regexp", + "support.other.parenthesis.regexp" + ], + "settings": { + "foreground": "#d16969" + } + }, + { + "scope": [ + "constant.character.character-class.regexp", + "constant.other.character-class.set.regexp", + "constant.other.character-class.regexp", + "constant.character.set.regexp" + ], + "settings": { + "foreground": "#811f3f" + } + }, + { + "scope": "keyword.operator.quantifier.regexp", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "keyword.operator.or.regexp", + "keyword.control.anchor.regexp" + ], + "settings": { + "foreground": "#ff0000" + } + }, + { + "scope": "constant.character", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "constant.character.escape", + "settings": { + "foreground": "#a31515" + } } + ] } \ No newline at end of file diff --git a/extensions/theme-defaults/themes/light_vs.json b/extensions/theme-defaults/themes/light_vs.json index 162c32f6218..883d88347dc 100644 --- a/extensions/theme-defaults/themes/light_vs.json +++ b/extensions/theme-defaults/themes/light_vs.json @@ -3,6 +3,13 @@ "name": "Light (Visual Studio)", "include": "./light_defaults.json", "tokenColors": [ + { + "scope": ["meta.embedded", "source.groovy.embedded"], + "settings": { + "foreground": "#000000ff", + "background":"#ffffffff" + } + }, { "scope": "emphasis", "settings": { @@ -237,11 +244,11 @@ } }, { - "name": "JavaScript string interpolation ${}", + "name": "String interpolation", "scope": [ "punctuation.definition.template-expression.begin", "punctuation.definition.template-expression.end", - "punctuation.section.embedded.coffee" + "punctuation.section.embedded" ], "settings": { "foreground": "#0000ff" 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 f9a84a5c5ee..bad21aface9 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -54,6 +54,13 @@ "foreground": "#d3af86" } }, + { + "scope": ["meta.embedded", "source.groovy.embedded"], + "settings": { + "background": "#221a0f", + "foreground": "#d3af86" + } + }, { "name": "Text", "scope": "variable.parameter.function", 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 60277bbbf06..e090cc5f213 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -51,11 +51,21 @@ "foreground": "#c5c8c6ff" } }, + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "background": "#1e1e1e", + "foreground": "#C5C8C6" + } + }, { "name": "Comment", "scope": "comment", "settings": { - "fontStyle": "\n ", + "fontStyle": "", "foreground": "#9A9B99" } }, @@ -63,7 +73,7 @@ "name": "String", "scope": "string", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -71,7 +81,7 @@ "name": "String Embedded Source", "scope": "string source", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D08442" } }, @@ -79,7 +89,7 @@ "name": "Number", "scope": "constant.numeric", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -87,7 +97,7 @@ "name": "Built-in constant", "scope": "constant.language", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#408080" } }, @@ -95,7 +105,7 @@ "name": "User-defined constant", "scope": "constant.character, constant.other", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#8080FF", "background": "#1e1e1e" } @@ -104,7 +114,7 @@ "name": "Keyword", "scope": "keyword", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -112,7 +122,7 @@ "name": "Support", "scope": "support", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#C7444A" } }, @@ -120,7 +130,7 @@ "name": "Storage", "scope": "storage", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -128,7 +138,7 @@ "name": "Class name", "scope": "entity.name.class, entity.name.type", "settings": { - "fontStyle": "\n \t\t\t \t", + "fontStyle": "", "foreground": "#9B0000", "background": "#1E1E1E" } @@ -137,7 +147,7 @@ "name": "Inherited class", "scope": "entity.other.inherited-class", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#C7444A" } }, @@ -145,7 +155,7 @@ "name": "Function name", "scope": "entity.name.function", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#CE6700" } }, @@ -153,7 +163,7 @@ "name": "Function argument", "scope": "variable.parameter", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -161,7 +171,7 @@ "name": "Tag name", "scope": "entity.name.tag", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -169,7 +179,7 @@ "name": "Tag attribute", "scope": "entity.other.attribute-name", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -177,7 +187,7 @@ "name": "Library function", "scope": "support.function", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -185,7 +195,7 @@ "name": "Keyword", "scope": "keyword", "settings": { - "fontStyle": "\n \t\t\t\t", + "fontStyle": "", "foreground": "#676867" } }, @@ -193,7 +203,7 @@ "name": "Class Variable", "scope": "variable.other, variable.js, punctuation.separator.variable", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -201,7 +211,7 @@ "name": "Language Constant", "scope": "constant.language", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#FF0080" } }, @@ -209,7 +219,7 @@ "name": "Meta Brace", "scope": "punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#008200" } }, @@ -217,7 +227,7 @@ "name": "Invalid", "scope": "invalid", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#FF0B00" } }, @@ -225,7 +235,7 @@ "name": "Normal Variable", "scope": "variable.other.php, variable.other.normal", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -233,7 +243,7 @@ "name": "Function Object", "scope": "meta.function-call.object", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -241,7 +251,7 @@ "name": "Function Call Variable", "scope": "variable.other.property", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -249,7 +259,7 @@ "name": "Keyword Control", "scope": "keyword.control", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -257,7 +267,7 @@ "name": "Tag", "scope": "meta.tag", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -265,7 +275,7 @@ "name": "Tag Name", "scope": "entity.name.tag", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -273,7 +283,7 @@ "name": "Doctype", "scope": "meta.doctype, meta.tag.sgml-declaration.doctype, meta.tag.sgml.doctype", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -281,7 +291,7 @@ "name": "Tag Inline Source", "scope": "meta.tag.inline source, text.html.php.source", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -289,7 +299,7 @@ "name": "Tag Other", "scope": "meta.tag.other, entity.name.tag.style, entity.name.tag.script, meta.tag.block.script, source.js.embedded punctuation.definition.tag.html, source.css.embedded punctuation.definition.tag.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -297,7 +307,7 @@ "name": "Tag Attribute", "scope": "entity.other.attribute-name, meta.tag punctuation.definition.string", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -305,7 +315,7 @@ "name": "Tag Value", "scope": "meta.tag string -source -punctuation, text source text meta.tag string -punctuation", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -313,7 +323,7 @@ "name": "Meta Brace", "scope": "punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -328,7 +338,7 @@ "name": "HTML String", "scope": "string.quoted.double.html, punctuation.definition.string.begin.html, punctuation.definition.string.end.html", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -336,7 +346,7 @@ "name": "HTML Tags", "scope": "punctuation.definition.tag.html, punctuation.definition.tag.begin, punctuation.definition.tag.end", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#6089B4" } }, @@ -344,7 +354,7 @@ "name": "CSS ID", "scope": "meta.selector.css entity.other.attribute-name.id", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9872A2" } }, @@ -352,7 +362,7 @@ "name": "CSS Property Name", "scope": "support.type.property-name.css", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#676867" } }, @@ -360,7 +370,7 @@ "name": "CSS Property Value", "scope": "meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#C7444A" } }, @@ -394,7 +404,7 @@ "name": "PHP Function Call", "scope": "meta.function-call.object.php", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -416,7 +426,7 @@ "name": "PHP Punctuation Embedded", "scope": "punctuation.section.embedded.begin.php, punctuation.section.embedded.end.php", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D08442" } }, @@ -424,7 +434,7 @@ "name": "Ruby Symbol", "scope": "constant.other.symbol.ruby", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#9AA83A" } }, @@ -432,7 +442,7 @@ "name": "Ruby Variable", "scope": "variable.language.ruby", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, @@ -440,13 +450,16 @@ "name": "Ruby Special Method", "scope": "keyword.other.special-method.ruby", "settings": { - "fontStyle": "\n \t\t\t", + "fontStyle": "", "foreground": "#D9B700" } }, { "name": "Ruby Embedded Source", - "scope": "source.ruby.embedded.source", + "scope": [ + "punctuation.section.embedded.begin.ruby", + "punctuation.section.embedded.end.ruby" + ], "settings": { "foreground": "#D08442" } @@ -455,7 +468,7 @@ "name": "SQL", "scope": "keyword.other.DML.sql", "settings": { - "fontStyle": "\n \t\t\t\t", + "fontStyle": "", "foreground": "#D0B344" } }, diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index fa42db4a3c3..a1324d9ee01 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -18,7 +18,8 @@ "editor.background": "#272822", "editor.foreground": "#f8f8f2", "selection.background": "#ccccc7", - "editor.selectionBackground": "#49483e", + "editor.selectionHighlightBackground": "#665044cc", + "editor.selectionBackground": "#334444cc", "editor.lineHighlightBackground": "#3e3d32", "editorCursor.foreground": "#f8f8f0", "editorWhitespace.foreground": "#464741", @@ -72,22 +73,22 @@ "peekViewResult.selectionBackground": "#414339", "peekViewResult.matchHighlightBackground": "#75715E", "peekViewEditor.matchHighlightBackground": "#75715E", - "terminal.ansiBlack": "#333333", - "terminal.ansiRed": "#C4265E", // the bright color with ~75% transparent on the background - "terminal.ansiGreen": "#86B42B", - "terminal.ansiYellow": "#B3B42B", - "terminal.ansiBlue": "#6A7EC8", - "terminal.ansiMagenta": "#8C6BC8", - "terminal.ansiCyan": "#56ADBC", - "terminal.ansiWhite": "#e3e3dd", - "terminal.ansiBrightBlack": "#666666", - "terminal.ansiBrightRed": "#f92672", - "terminal.ansiBrightGreen": "#A6E22E", - "terminal.ansiBrightYellow": "#e2e22e", // hue shifted #A6E22E - "terminal.ansiBrightBlue": "#819aff", // hue shifted #AE81FF - "terminal.ansiBrightMagenta": "#AE81FF", - "terminal.ansiBrightCyan": "#66D9EF", - "terminal.ansiBrightWhite": "#f8f8f2" + "terminal.ansiBlack": "#333333", + "terminal.ansiRed": "#C4265E", // the bright color with ~75% transparent on the background + "terminal.ansiGreen": "#86B42B", + "terminal.ansiYellow": "#B3B42B", + "terminal.ansiBlue": "#6A7EC8", + "terminal.ansiMagenta": "#8C6BC8", + "terminal.ansiCyan": "#56ADBC", + "terminal.ansiWhite": "#e3e3dd", + "terminal.ansiBrightBlack": "#666666", + "terminal.ansiBrightRed": "#f92672", + "terminal.ansiBrightGreen": "#A6E22E", + "terminal.ansiBrightYellow": "#e2e22e", // hue shifted #A6E22E + "terminal.ansiBrightBlue": "#819aff", // hue shifted #AE81FF + "terminal.ansiBrightMagenta": "#AE81FF", + "terminal.ansiBrightCyan": "#66D9EF", + "terminal.ansiBrightWhite": "#f8f8f2" }, "tokenColors": [ { @@ -96,6 +97,16 @@ "foreground": "#F8F8F2" } }, + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "background": "#272822", + "foreground": "#F8F8F2" + } + }, { "name": "Comment", "scope": "comment", @@ -114,7 +125,7 @@ "name": "Template Definition", "scope": [ "punctuation.definition.template-expression", - "punctuation.section.embedded.coffee" + "punctuation.section.embedded" ], "settings": { "foreground": "#F92672" @@ -400,4 +411,4 @@ } } ] -} +} \ No newline at end of file diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 4ffeda5516a..fc9e8f7db2c 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -7,6 +7,16 @@ "foreground": "#333333" } }, + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "background": "#F5F5F5", + "foreground": "#333333" + } + }, { "name": "Comments", "scope": [ @@ -484,8 +494,8 @@ "statusBar.background": "#705697", "statusBar.noFolderBackground": "#705697", "statusBar.debuggingBackground": "#705697", - "activityBar.background": "#EDEDF5", - "activityBar.foreground": "#705697", + "activityBar.background": "#EDEDF5", + "activityBar.foreground": "#705697", "activityBarBadge.background": "#705697", "titleBar.activeBackground": "#c4b7d7", "button.background": "#705697", diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index 94d2c20ae2b..6c964e506d5 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -1,5 +1,5 @@ { - "tokenColors": "./red.tmTheme", + "name": "Red", "colors": { // window "activityBar.background": "#580000", @@ -57,5 +57,357 @@ "extensionButton.prominentBackground": "#cc3333", "extensionButton.prominentHoverBackground": "#cc333388" }, - "name": "Red" + "tokenColors": [ + { + "settings": { + "background": "#390000", + "caret": "#970000", + "foreground": "#F8F8F8", + "invisibles": "#c10000", + "lineHighlight": "#0000004A", + "selection": "#750000" + } + }, + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "background": "#390000", + "foreground": "#F8F8F8" + } + }, + { + "name": "Comment", + "scope": "comment", + "settings": { + "fontStyle": "italic", + "foreground": "#e7c0c0ff" + } + }, + { + "name": "Constant", + "scope": "constant", + "settings": { + "fontStyle": "", + "foreground": "#994646ff" + } + }, + { + "name": "Keyword", + "scope": "keyword", + "settings": { + "fontStyle": "", + "foreground": "#f12727ff" + } + }, + { + "name": "Entity", + "scope": "entity", + "settings": { + "fontStyle": "", + "foreground": "#fec758ff" + } + }, + { + "name": "Storage", + "scope": "storage", + "settings": { + "fontStyle": "bold", + "foreground": "#ff6262ff" + } + }, + { + "name": "String", + "scope": "string", + "settings": { + "fontStyle": "", + "foreground": "#cd8d8dff" + } + }, + { + "name": "Support", + "scope": "support", + "settings": { + "fontStyle": "", + "foreground": "#9df39fff" + } + }, + { + "name": "Variable", + "scope": "variable", + "settings": { + "fontStyle": "italic", + "foreground": "#fb9a4bff" + } + }, + { + "name": "Invalid", + "scope": "invalid", + "settings": { + "background": "#fd6209ff", + "foreground": "#ffffffff" + } + }, + { + "name": "Embedded Source", + "scope": "text source", + "settings": { + "background": "#b0b3ba14" + } + }, + { + "name": "Embedded Source (Bright)", + "scope": "text.html.ruby source", + "settings": { + "background": "#b1b3ba21" + } + }, + { + "name": "Entity inherited-class", + "scope": "entity.other.inherited-class", + "settings": { + "fontStyle": "underline", + "foreground": "#aa5507ff" + } + }, + { + "scope": "constant.character", + "settings": { + "foreground": "#ec0d1e" + } + }, + { + "scope": [ + "string constant", + "constant.character.escape" + ], + "settings": { + "fontStyle": "", + "foreground": "#ffe862ff" + } + }, + { + "name": "String.regexp", + "scope": "string.regexp", + "settings": { + "foreground": "#ffb454ff" + } + }, + { + "name": "String variable", + "scope": "string variable", + "settings": { + "foreground": "#edef7dff" + } + }, + { + "name": "Support.function", + "scope": "support.function", + "settings": { + "fontStyle": "", + "foreground": "#ffb454ff" + } + }, + { + "name": "Support.constant", + "scope": "support.constant", + "settings": { + "fontStyle": "", + "foreground": "#eb939aff" + } + }, + { + "name": "Doctype/XML Processing", + "scope": [ + "declaration.sgml.html declaration.doctype", + "declaration.sgml.html declaration.doctype entity", + "declaration.sgml.html declaration.doctype string", + "declaration.xml-processing", + "declaration.xml-processing entity", + "declaration.xml-processing string" + ], + "settings": { + "fontStyle": "", + "foreground": "#73817dff" + } + }, + { + "name": "Meta.tag.A", + "scope": [ + "declaration.tag", + "declaration.tag entity", + "meta.tag", + "meta.tag entity" + ], + "settings": { + "fontStyle": "", + "foreground": "#ec0d1eff" + } + }, + { + "name": "css tag-name", + "scope": "meta.selector.css entity.name.tag", + "settings": { + "fontStyle": "", + "foreground": "#aa5507ff" + } + }, + { + "name": "css#id", + "scope": "meta.selector.css entity.other.attribute-name.id", + "settings": { + "foreground": "#fec758ff" + } + }, + { + "name": "css.class", + "scope": "meta.selector.css entity.other.attribute-name.class", + "settings": { + "fontStyle": "", + "foreground": "#41a83eff" + } + }, + { + "name": "css property-name:", + "scope": "support.type.property-name.css", + "settings": { + "fontStyle": "", + "foreground": "#96dd3bff" + } + }, + { + "name": "css property-value;", + "scope": [ + "meta.property-group support.constant.property-value.css", + "meta.property-value support.constant.property-value.css" + ], + "settings": { + "fontStyle": "italic", + "foreground": "#ffe862ff" + } + }, + { + "name": "css additional-constants", + "scope": [ + "meta.property-value support.constant.named-color.css", + "meta.property-value constant" + ], + "settings": { + "fontStyle": "", + "foreground": "#ffe862ff" + } + }, + { + "name": "css @at-rule", + "scope": "meta.preprocessor.at-rule keyword.control.at-rule", + "settings": { + "foreground": "#fd6209ff" + } + }, + { + "name": "css constructor.argument", + "scope": "meta.constructor.argument.css", + "settings": { + "fontStyle": "", + "foreground": "#ec9799ff" + } + }, + { + "name": "diff.header", + "scope": [ + "meta.diff", + "meta.diff.header" + ], + "settings": { + "background": "#0b2f20ff", + "fontStyle": "italic", + "foreground": "#f8f8f8ff" + } + }, + { + "name": "diff.deleted", + "scope": "markup.deleted", + "settings": { + "background": "#fedcddff", + "foreground": "#ec9799ff" + } + }, + { + "name": "diff.changed", + "scope": "markup.changed", + "settings": { + "background": "#c4b14aff", + "foreground": "#f8f8f8ff" + } + }, + { + "name": "diff.inserted", + "scope": "markup.inserted", + "settings": { + "background": "#9bf199ff", + "foreground": "#41a83eff" + } + }, + { + "name": "Markup Quote", + "scope": "markup.quote", + "settings": { + "foreground": "#f12727ff" + } + }, + { + "name": "Markup Lists", + "scope": "markup.list", + "settings": { + "foreground": "#ff6262ff" + } + }, + { + "name": "Markup Styling", + "scope": [ + "markup.bold", + "markup.italic" + ], + "settings": { + "foreground": "#fb9a4bff" + } + }, + { + "name": "Markup Inline", + "scope": "markup.inline.raw", + "settings": { + "fontStyle": "", + "foreground": "#cd8d8dff" + } + }, + { + "name": "Markup Headings", + "scope": "markup.heading", + "settings": { + "foreground": "#fec758ff" + } + }, + { + "name": "Markup Setext Header", + "scope": "markup.heading.setext", + "settings": { + "fontStyle": "", + "foreground": "#fec758ff" + } + }, + { + "name": "String interpolation", + "scope": [ + "punctuation.definition.template-expression.begin", + "punctuation.definition.template-expression.end", + "punctuation.section.embedded", + ".format.placeholder" + ], + "settings": { + "foreground": "#ec0d1e" + } + } + ] } \ No newline at end of file diff --git a/extensions/theme-red/themes/red.tmTheme b/extensions/theme-red/themes/red.tmTheme deleted file mode 100644 index 2e7039551f4..00000000000 --- a/extensions/theme-red/themes/red.tmTheme +++ /dev/null @@ -1,514 +0,0 @@ - - - - - name - Red - settings - - - settings - - background - #390000 - caret - #970000 - foreground - #F8F8F8 - invisibles - #c10000 - lineHighlight - #0000004A - selection - #750000 - - - - name - Comment - scope - comment - settings - - fontStyle - italic - foreground - #e7c0c0ff - - - - name - Constant - scope - constant - settings - - fontStyle - - foreground - #994646ff - - - - name - Keyword - scope - keyword - settings - - fontStyle - - foreground - #f12727ff - - - - name - Entity - scope - entity - settings - - fontStyle - - foreground - #fec758ff - - - - name - Storage - scope - storage - settings - - fontStyle - bold - foreground - #ff6262ff - - - - name - String - scope - string - settings - - fontStyle - - foreground - #cd8d8dff - - - - name - Support - scope - support - settings - - fontStyle - - foreground - #9df39fff - - - - name - Variable - scope - variable - settings - - fontStyle - italic - foreground - #fb9a4bff - - - - name - Invalid - scope - invalid - settings - - background - #fd6209ff - foreground - #ffffffff - - - - name - Embedded Source - scope - text source - settings - - background - #b0b3ba14 - - - - name - Embedded Source (Bright) - scope - text.html.ruby source - settings - - background - #b1b3ba21 - - - - name - Entity inherited-class - scope - entity.other.inherited-class - settings - - fontStyle - underline - foreground - #aa5507ff - - - - name - String embedded-source - scope - string.quoted source - settings - - fontStyle - - foreground - #9df39fff - - - - name - String constant - scope - string constant - settings - - fontStyle - - foreground - #ffe862ff - - - - name - String.regexp - scope - string.regexp - settings - - foreground - #ffb454ff - - - - name - String variable - scope - string variable - settings - - foreground - #edef7dff - - - - name - Support.function - scope - support.function - settings - - fontStyle - - foreground - #ffb454ff - - - - name - Support.constant - scope - support.constant - settings - - fontStyle - - foreground - #eb939aff - - - - name - Doctype/XML Processing - scope - declaration.sgml.html declaration.doctype, declaration.sgml.html declaration.doctype entity, declaration.sgml.html declaration.doctype string, declaration.xml-processing, declaration.xml-processing entity, declaration.xml-processing string - settings - - fontStyle - - foreground - #73817dff - - - - name - Meta.tag.A - scope - declaration.tag, declaration.tag entity, meta.tag, meta.tag entity - settings - - fontStyle - - foreground - #ec0d1eff - - - - name - css tag-name - scope - meta.selector.css entity.name.tag - settings - - fontStyle - - foreground - #aa5507ff - - - - name - css#id - scope - meta.selector.css entity.other.attribute-name.id - settings - - foreground - #fec758ff - - - - name - css.class - scope - meta.selector.css entity.other.attribute-name.class - settings - - fontStyle - - foreground - #41a83eff - - - - name - css property-name: - scope - support.type.property-name.css - settings - - fontStyle - - foreground - #96dd3bff - - - - name - css property-value; - scope - meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css - settings - - fontStyle - italic - foreground - #ffe862ff - - - - name - css additional-constants - scope - meta.property-value support.constant.named-color.css, meta.property-value constant - settings - - fontStyle - - foreground - #ffe862ff - - - - name - css @at-rule - scope - meta.preprocessor.at-rule keyword.control.at-rule - settings - - foreground - #fd6209ff - - - - name - css constructor.argument - scope - meta.constructor.argument.css - settings - - fontStyle - - foreground - #ec9799ff - - - - name - diff.header - scope - meta.diff, meta.diff.header - settings - - background - #0b2f20ff - fontStyle - italic - foreground - #f8f8f8ff - - - - name - diff.deleted - scope - markup.deleted - settings - - background - #fedcddff - foreground - #ec9799ff - - - - name - diff.changed - scope - markup.changed - settings - - background - #c4b14aff - foreground - #f8f8f8ff - - - - name - diff.inserted - scope - markup.inserted - settings - - background - #9bf199ff - foreground - #41a83eff - - - - - name - Markup Quote - scope - markup.quote - settings - - foreground - #f12727ff - - - - name - Markup Lists - scope - markup.list - settings - - foreground - #ff6262ff - - - - name - Markup Styling - scope - markup.bold, markup.italic - settings - - foreground - #fb9a4bff - - - - name - Markup Inline - scope - markup.inline.raw - settings - - fontStyle - - foreground - #cd8d8dff - - - - name - Markup Headings - scope - markup.heading - settings - - foreground - #fec758ff - - - - name - Markup Setext Header - scope - markup.heading.setext - settings - - fontStyle - - foreground - #fec758ff - - - - - - - uuid - AC0A28C5-65E6-42A6-AD05-4D01735652EE - colorSpaceName - sRGB - semanticClass - theme.dark.django - - \ No newline at end of file diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js index 20520f6b536..955a9327e76 100644 --- a/extensions/theme-seti/build/update-icon-theme.js +++ b/extensions/theme-seti/build/update-icon-theme.js @@ -117,17 +117,21 @@ function copyFile(fileName, dest) { }); } -function invertColor(color) { +function darkenColor(color) { var res = '#'; for (var i = 1; i < 7; i+=2) { - var newVal = 255 - parseInt('0x' + color.substr(i, 2), 16); - res += newVal.toString(16); + var newVal = Math.round(parseInt('0x' + color.substr(i, 2), 16) * 0.9); + var hex = newVal.toString(16); + if (hex.length == 1) { + res += '0'; + } + res += hex; } return res; } function getLanguageMappings() { - let langMappings = {} + let langMappings = {}; var allExtensions = fs.readdirSync('..'); for (var i= 0; i < allExtensions.length; i++) { let dirPath = path.join('..', allExtensions[i], 'package.json'); @@ -193,7 +197,7 @@ exports.update = function () { if (colorValue) { entry.fontColor = colorValue; - var entryInverse = { fontCharacter: entry.fontCharacter, fontColor: invertColor(colorValue) }; + var entryInverse = { fontCharacter: entry.fontCharacter, fontColor: darkenColor(colorValue) }; iconDefinitions[def + '_light'] = entryInverse; } } @@ -213,10 +217,10 @@ exports.update = function () { var res = { information_for_contributors: [ - 'This file has been generated from data in https://github.com/jesseweed/seti-ui:', - '- icon definitions: styles/_fonts/seti.less', - '- icon colors: styles/ui-variables.less', - '- file associations: styles/icons/mapping.less', + 'This file has been generated from data in https://github.com/jesseweed/seti-ui', + '- icon definitions: https://github.com/jesseweed/seti-ui/blob/master/styles/_fonts/seti.less', + '- icon colors: https://github.com/jesseweed/seti-ui/blob/master/styles/ui-variables.less', + '- file associations: https://github.com/jesseweed/seti-ui/blob/master/styles/components/icons/mapping.less', 'If you want to provide a fix or improvement, please create a pull request against the jesseweed/seti-ui repository.', 'Once accepted there, we are happy to receive an update request.', ], diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index b6bc2671ce9..72b34229231 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -1,9 +1,9 @@ { "information_for_contributors": [ - "This file has been generated from data in https://github.com/jesseweed/seti-ui:", - "- icon definitions: styles/_fonts/seti.less", - "- icon colors: styles/ui-variables.less", - "- file associations: styles/components/icons/mapping.lesst", + "This file has been generated from data in https://github.com/jesseweed/seti-ui", + "- icon definitions: https://github.com/jesseweed/seti-ui/blob/master/styles/_fonts/seti.less", + "- icon colors: https://github.com/jesseweed/seti-ui/blob/master/styles/ui-variables.less", + "- file associations: https://github.com/jesseweed/seti-ui/blob/master/styles/components/icons/mapping.less", "If you want to provide a fix or improvement, please create a pull request against the jesseweed/seti-ui repository.", "Once accepted there, we are happy to receive an update request." ], @@ -30,7 +30,7 @@ }, "_asm_light": { "fontCharacter": "\\E003", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_asm": { "fontCharacter": "\\E003", @@ -38,7 +38,7 @@ }, "_audio_light": { "fontCharacter": "\\E004", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_audio": { "fontCharacter": "\\E004", @@ -46,7 +46,7 @@ }, "_babel_light": { "fontCharacter": "\\E005", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_babel": { "fontCharacter": "\\E005", @@ -54,7 +54,7 @@ }, "_bower_light": { "fontCharacter": "\\E006", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_bower": { "fontCharacter": "\\E006", @@ -62,7 +62,7 @@ }, "_bsl_light": { "fontCharacter": "\\E007", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_bsl": { "fontCharacter": "\\E007", @@ -70,7 +70,7 @@ }, "_c-sharp_light": { "fontCharacter": "\\E008", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_c-sharp": { "fontCharacter": "\\E008", @@ -78,7 +78,7 @@ }, "_c_light": { "fontCharacter": "\\E009", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_c": { "fontCharacter": "\\E009", @@ -86,7 +86,7 @@ }, "_cake_light": { "fontCharacter": "\\E00A", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_cake": { "fontCharacter": "\\E00A", @@ -94,7 +94,7 @@ }, "_cake_php_light": { "fontCharacter": "\\E00B", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_cake_php": { "fontCharacter": "\\E00B", @@ -111,7 +111,7 @@ }, "_clock_light": { "fontCharacter": "\\E00F", - "fontColor": "#927f79" + "fontColor": "#627379" }, "_clock": { "fontCharacter": "\\E00F", @@ -119,7 +119,7 @@ }, "_code-climate_light": { "fontCharacter": "\\E010", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_code-climate": { "fontCharacter": "\\E010", @@ -127,7 +127,7 @@ }, "_coffee_light": { "fontCharacter": "\\E011", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_coffee": { "fontCharacter": "\\E011", @@ -138,7 +138,7 @@ }, "_coldfusion_light": { "fontCharacter": "\\E013", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_coldfusion": { "fontCharacter": "\\E013", @@ -146,7 +146,7 @@ }, "_config_light": { "fontCharacter": "\\E014", - "fontColor": "#927f79" + "fontColor": "#627379" }, "_config": { "fontCharacter": "\\E014", @@ -154,7 +154,7 @@ }, "_cpp_light": { "fontCharacter": "\\E015", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_cpp": { "fontCharacter": "\\E015", @@ -162,7 +162,7 @@ }, "_css_light": { "fontCharacter": "\\E016", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_css": { "fontCharacter": "\\E016", @@ -170,7 +170,7 @@ }, "_csv_light": { "fontCharacter": "\\E017", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_csv": { "fontCharacter": "\\E017", @@ -178,7 +178,7 @@ }, "_d_light": { "fontCharacter": "\\E018", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_d": { "fontCharacter": "\\E018", @@ -186,7 +186,7 @@ }, "_db_light": { "fontCharacter": "\\E019", - "fontColor": "#aac7a" + "fontColor": "#dd4b78" }, "_db": { "fontCharacter": "\\E019", @@ -194,7 +194,7 @@ }, "_default_light": { "fontCharacter": "\\E01A", - "fontColor": "#2b2829" + "fontColor": "#bfc2c1" }, "_default": { "fontCharacter": "\\E01A", @@ -205,7 +205,7 @@ }, "_docker_light": { "fontCharacter": "\\E01C", - "fontColor": "#aac7a" + "fontColor": "#dd4b78" }, "_docker": { "fontCharacter": "\\E01C", @@ -216,7 +216,7 @@ }, "_ejs_light": { "fontCharacter": "\\E01E", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_ejs": { "fontCharacter": "\\E01E", @@ -224,7 +224,7 @@ }, "_elixir_light": { "fontCharacter": "\\E01F", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_elixir": { "fontCharacter": "\\E01F", @@ -232,7 +232,7 @@ }, "_elixir_script_light": { "fontCharacter": "\\E020", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_elixir_script": { "fontCharacter": "\\E020", @@ -240,7 +240,7 @@ }, "_elm_light": { "fontCharacter": "\\E021", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_elm": { "fontCharacter": "\\E021", @@ -251,7 +251,7 @@ }, "_eslint_light": { "fontCharacter": "\\E023", - "fontColor": "#b2a5a1" + "fontColor": "#455155" }, "_eslint": { "fontCharacter": "\\E023", @@ -259,7 +259,7 @@ }, "_f-sharp_light": { "fontCharacter": "\\E024", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_f-sharp": { "fontCharacter": "\\E024", @@ -267,7 +267,7 @@ }, "_favicon_light": { "fontCharacter": "\\E025", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_favicon": { "fontCharacter": "\\E025", @@ -275,7 +275,7 @@ }, "_firebase_light": { "fontCharacter": "\\E026", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_firebase": { "fontCharacter": "\\E026", @@ -283,7 +283,7 @@ }, "_firefox_light": { "fontCharacter": "\\E027", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_firefox": { "fontCharacter": "\\E027", @@ -294,7 +294,7 @@ }, "_font_light": { "fontCharacter": "\\E029", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_font": { "fontCharacter": "\\E029", @@ -302,7 +302,7 @@ }, "_git_light": { "fontCharacter": "\\E02A", - "fontColor": "#beaca4" + "fontColor": "#3b4b52" }, "_git": { "fontCharacter": "\\E02A", @@ -319,7 +319,7 @@ }, "_go_light": { "fontCharacter": "\\E02E", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_go": { "fontCharacter": "\\E02E", @@ -327,7 +327,7 @@ }, "_go2_light": { "fontCharacter": "\\E02F", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_go2": { "fontCharacter": "\\E02F", @@ -335,7 +335,7 @@ }, "_gradle_light": { "fontCharacter": "\\E030", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_gradle": { "fontCharacter": "\\E030", @@ -343,7 +343,7 @@ }, "_grails_light": { "fontCharacter": "\\E031", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_grails": { "fontCharacter": "\\E031", @@ -351,7 +351,7 @@ }, "_grunt_light": { "fontCharacter": "\\E032", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_grunt": { "fontCharacter": "\\E032", @@ -359,7 +359,7 @@ }, "_gulp_light": { "fontCharacter": "\\E033", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_gulp": { "fontCharacter": "\\E033", @@ -370,7 +370,7 @@ }, "_haml_light": { "fontCharacter": "\\E035", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_haml": { "fontCharacter": "\\E035", @@ -378,7 +378,7 @@ }, "_haskell_light": { "fontCharacter": "\\E036", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_haskell": { "fontCharacter": "\\E036", @@ -386,7 +386,7 @@ }, "_heroku_light": { "fontCharacter": "\\E037", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_heroku": { "fontCharacter": "\\E037", @@ -394,7 +394,7 @@ }, "_hex_light": { "fontCharacter": "\\E038", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_hex": { "fontCharacter": "\\E038", @@ -402,7 +402,7 @@ }, "_html_light": { "fontCharacter": "\\E039", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_html": { "fontCharacter": "\\E039", @@ -413,7 +413,7 @@ }, "_ignored_light": { "fontCharacter": "\\E03B", - "fontColor": "#beaca4" + "fontColor": "#3b4b52" }, "_ignored": { "fontCharacter": "\\E03B", @@ -421,7 +421,7 @@ }, "_illustrator_light": { "fontCharacter": "\\E03C", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_illustrator": { "fontCharacter": "\\E03C", @@ -429,7 +429,7 @@ }, "_image_light": { "fontCharacter": "\\E03D", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_image": { "fontCharacter": "\\E03D", @@ -437,7 +437,7 @@ }, "_info_light": { "fontCharacter": "\\E03E", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_info": { "fontCharacter": "\\E03E", @@ -445,7 +445,7 @@ }, "_ionic_light": { "fontCharacter": "\\E03F", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_ionic": { "fontCharacter": "\\E03F", @@ -453,7 +453,7 @@ }, "_jade_light": { "fontCharacter": "\\E040", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_jade": { "fontCharacter": "\\E040", @@ -461,7 +461,7 @@ }, "_java_light": { "fontCharacter": "\\E041", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_java": { "fontCharacter": "\\E041", @@ -469,7 +469,7 @@ }, "_javascript_light": { "fontCharacter": "\\E042", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_javascript": { "fontCharacter": "\\E042", @@ -477,7 +477,7 @@ }, "_jenkins_light": { "fontCharacter": "\\E043", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_jenkins": { "fontCharacter": "\\E043", @@ -485,7 +485,7 @@ }, "_jinja_light": { "fontCharacter": "\\E044", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_jinja": { "fontCharacter": "\\E044", @@ -496,7 +496,7 @@ }, "_json_light": { "fontCharacter": "\\E046", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_json": { "fontCharacter": "\\E046", @@ -504,7 +504,7 @@ }, "_julia_light": { "fontCharacter": "\\E047", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_julia": { "fontCharacter": "\\E047", @@ -512,7 +512,7 @@ }, "_karma_light": { "fontCharacter": "\\E048", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_karma": { "fontCharacter": "\\E048", @@ -520,7 +520,7 @@ }, "_less_light": { "fontCharacter": "\\E049", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_less": { "fontCharacter": "\\E049", @@ -528,7 +528,7 @@ }, "_license_light": { "fontCharacter": "\\E04A", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_license": { "fontCharacter": "\\E04A", @@ -536,7 +536,7 @@ }, "_liquid_light": { "fontCharacter": "\\E04B", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_liquid": { "fontCharacter": "\\E04B", @@ -544,7 +544,7 @@ }, "_livescript_light": { "fontCharacter": "\\E04C", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_livescript": { "fontCharacter": "\\E04C", @@ -552,7 +552,7 @@ }, "_lock_light": { "fontCharacter": "\\E04D", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_lock": { "fontCharacter": "\\E04D", @@ -560,7 +560,7 @@ }, "_lua_light": { "fontCharacter": "\\E04E", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_lua": { "fontCharacter": "\\E04E", @@ -568,7 +568,7 @@ }, "_makefile_light": { "fontCharacter": "\\E04F", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_makefile": { "fontCharacter": "\\E04F", @@ -576,7 +576,7 @@ }, "_markdown_light": { "fontCharacter": "\\E050", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_markdown": { "fontCharacter": "\\E050", @@ -584,7 +584,7 @@ }, "_maven_light": { "fontCharacter": "\\E051", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_maven": { "fontCharacter": "\\E051", @@ -592,7 +592,7 @@ }, "_mdo_light": { "fontCharacter": "\\E052", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_mdo": { "fontCharacter": "\\E052", @@ -600,7 +600,7 @@ }, "_mustache_light": { "fontCharacter": "\\E053", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_mustache": { "fontCharacter": "\\E053", @@ -611,7 +611,7 @@ }, "_npm_light": { "fontCharacter": "\\E055", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_npm": { "fontCharacter": "\\E055", @@ -619,7 +619,7 @@ }, "_npm_ignored_light": { "fontCharacter": "\\E056", - "fontColor": "#beaca4" + "fontColor": "#3b4b52" }, "_npm_ignored": { "fontCharacter": "\\E056", @@ -627,7 +627,7 @@ }, "_nunjucks_light": { "fontCharacter": "\\E057", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_nunjucks": { "fontCharacter": "\\E057", @@ -635,7 +635,7 @@ }, "_ocaml_light": { "fontCharacter": "\\E058", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_ocaml": { "fontCharacter": "\\E058", @@ -643,7 +643,7 @@ }, "_pdf_light": { "fontCharacter": "\\E059", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_pdf": { "fontCharacter": "\\E059", @@ -651,7 +651,7 @@ }, "_perl_light": { "fontCharacter": "\\E05A", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_perl": { "fontCharacter": "\\E05A", @@ -659,7 +659,7 @@ }, "_photoshop_light": { "fontCharacter": "\\E05B", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_photoshop": { "fontCharacter": "\\E05B", @@ -667,7 +667,7 @@ }, "_php_light": { "fontCharacter": "\\E05C", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_php": { "fontCharacter": "\\E05C", @@ -675,7 +675,7 @@ }, "_powershell_light": { "fontCharacter": "\\E05D", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_powershell": { "fontCharacter": "\\E05D", @@ -686,7 +686,7 @@ }, "_pug_light": { "fontCharacter": "\\E05F", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_pug": { "fontCharacter": "\\E05F", @@ -694,7 +694,7 @@ }, "_puppet_light": { "fontCharacter": "\\E060", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_puppet": { "fontCharacter": "\\E060", @@ -702,7 +702,7 @@ }, "_python_light": { "fontCharacter": "\\E061", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_python": { "fontCharacter": "\\E061", @@ -713,7 +713,7 @@ }, "_react_light": { "fontCharacter": "\\E063", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_react": { "fontCharacter": "\\E063", @@ -721,7 +721,7 @@ }, "_rollup_light": { "fontCharacter": "\\E064", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_rollup": { "fontCharacter": "\\E064", @@ -729,7 +729,7 @@ }, "_ruby_light": { "fontCharacter": "\\E065", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_ruby": { "fontCharacter": "\\E065", @@ -737,7 +737,7 @@ }, "_rust_light": { "fontCharacter": "\\E066", - "fontColor": "#927f79" + "fontColor": "#627379" }, "_rust": { "fontCharacter": "\\E066", @@ -745,7 +745,7 @@ }, "_salesforce_light": { "fontCharacter": "\\E067", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_salesforce": { "fontCharacter": "\\E067", @@ -753,7 +753,7 @@ }, "_sass_light": { "fontCharacter": "\\E068", - "fontColor": "#aac7a" + "fontColor": "#dd4b78" }, "_sass": { "fontCharacter": "\\E068", @@ -761,7 +761,7 @@ }, "_sbt_light": { "fontCharacter": "\\E069", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_sbt": { "fontCharacter": "\\E069", @@ -769,7 +769,7 @@ }, "_scala_light": { "fontCharacter": "\\E06A", - "fontColor": "#33c1bb" + "fontColor": "#b8383d" }, "_scala": { "fontCharacter": "\\E06A", @@ -783,7 +783,7 @@ }, "_shell_light": { "fontCharacter": "\\E06D", - "fontColor": "#b2a5a1" + "fontColor": "#455155" }, "_shell": { "fontCharacter": "\\E06D", @@ -791,7 +791,7 @@ }, "_slim_light": { "fontCharacter": "\\E06E", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_slim": { "fontCharacter": "\\E06E", @@ -799,7 +799,7 @@ }, "_smarty_light": { "fontCharacter": "\\E06F", - "fontColor": "#3434be" + "fontColor": "#b7b73b" }, "_smarty": { "fontCharacter": "\\E06F", @@ -807,7 +807,7 @@ }, "_spring_light": { "fontCharacter": "\\E070", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_spring": { "fontCharacter": "\\E070", @@ -815,7 +815,7 @@ }, "_stylus_light": { "fontCharacter": "\\E071", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_stylus": { "fontCharacter": "\\E071", @@ -823,7 +823,7 @@ }, "_sublime_light": { "fontCharacter": "\\E072", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_sublime": { "fontCharacter": "\\E072", @@ -831,7 +831,7 @@ }, "_svg_light": { "fontCharacter": "\\E073", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_svg": { "fontCharacter": "\\E073", @@ -839,7 +839,7 @@ }, "_swift_light": { "fontCharacter": "\\E074", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_swift": { "fontCharacter": "\\E074", @@ -847,7 +847,7 @@ }, "_terraform_light": { "fontCharacter": "\\E075", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_terraform": { "fontCharacter": "\\E075", @@ -855,7 +855,7 @@ }, "_tex_light": { "fontCharacter": "\\E076", - "fontColor": "#2b2829" + "fontColor": "#bfc2c1" }, "_tex": { "fontCharacter": "\\E076", @@ -869,7 +869,7 @@ }, "_twig_light": { "fontCharacter": "\\E079", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_twig": { "fontCharacter": "\\E079", @@ -877,7 +877,7 @@ }, "_typescript_light": { "fontCharacter": "\\E07A", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_typescript": { "fontCharacter": "\\E07A", @@ -885,7 +885,7 @@ }, "_vala_light": { "fontCharacter": "\\E07B", - "fontColor": "#927f79" + "fontColor": "#627379" }, "_vala": { "fontCharacter": "\\E07B", @@ -893,7 +893,7 @@ }, "_video_light": { "fontCharacter": "\\E07C", - "fontColor": "#aac7a" + "fontColor": "#dd4b78" }, "_video": { "fontCharacter": "\\E07C", @@ -901,7 +901,7 @@ }, "_vue_light": { "fontCharacter": "\\E07D", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_vue": { "fontCharacter": "\\E07D", @@ -909,7 +909,7 @@ }, "_windows_light": { "fontCharacter": "\\E07E", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_windows": { "fontCharacter": "\\E07E", @@ -917,7 +917,7 @@ }, "_word_light": { "fontCharacter": "\\E07F", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_word": { "fontCharacter": "\\E07F", @@ -925,7 +925,7 @@ }, "_xls_light": { "fontCharacter": "\\E080", - "fontColor": "#723eb6" + "fontColor": "#7fae42" }, "_xls": { "fontCharacter": "\\E080", @@ -933,7 +933,7 @@ }, "_xml_light": { "fontCharacter": "\\E081", - "fontColor": "#1c86cc" + "fontColor": "#cc6d2e" }, "_xml": { "fontCharacter": "\\E081", @@ -941,7 +941,7 @@ }, "_yarn_light": { "fontCharacter": "\\E082", - "fontColor": "#ae6545" + "fontColor": "#498ba7" }, "_yarn": { "fontCharacter": "\\E082", @@ -949,7 +949,7 @@ }, "_yml_light": { "fontCharacter": "\\E083", - "fontColor": "#5f8b3b" + "fontColor": "#9068b0" }, "_yml": { "fontCharacter": "\\E083", @@ -957,7 +957,7 @@ }, "_zip_light": { "fontCharacter": "\\E084", - "fontColor": "#927f79" + "fontColor": "#627379" }, "_zip": { "fontCharacter": "\\E084", @@ -1074,6 +1074,7 @@ "pxm": "_image", "svg": "_svg", "svgx": "_image", + "webp": "_image", "sublime-project": "_sublime", "sublime-workspace": "_sublime", "component": "_salesforce", 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 5309eb6fd1a..bfd823e9658 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -7,6 +7,13 @@ "foreground": "#93A1A1" } }, + { + "scope": ["meta.embedded", "source.groovy.embedded"], + "settings": { + "background": "#002B36", + "foreground": "#93A1A1" + } + }, { "name": "Comment", "scope": "comment", @@ -364,9 +371,9 @@ // "editor.inactiveSelectionBackground": "", // "editor.lineHighlightBorder": "", // "editor.rangeHighlightBackground": "", - // "editor.selectionHighlightBackground": "", - // "editor.wordHighlightBackground": "", - // "editor.wordHighlightStrongBackground": "", + "editor.selectionHighlightBackground": "#005A6FAA", + "editor.wordHighlightBackground": "#004454AA", + "editor.wordHighlightStrongBackground": "#005A6FAA", // Editor: Suggest // "editorSuggestWidget.background": "", @@ -476,4 +483,4 @@ "terminal.ansiBrightCyan": "#93a1a1", "terminal.ansiBrightWhite": "#fdf6e3" } -} \ No newline at end of file +} 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 3abeb7e7493..6d2b7146583 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -7,6 +7,13 @@ "foreground": "#657B83" } }, + { + "scope": ["meta.embedded", "source.groovy.embedded"], + "settings": { + "background": "#FDF6E3", + "foreground": "#657B83" + } + }, { "name": "Comment", "scope": "comment", 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 830caf27cb6..7163c4d671a 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 @@ -60,6 +60,13 @@ "foreground": "#FFFFFF" } }, + { + "scope": ["meta.embedded", "source.groovy.embedded"], + "settings": { + "background": "#002451", + "foreground": "#FFFFFF" + } + }, { "name": "Comment", "scope": "comment", diff --git a/extensions/typescript/OSSREADME.json b/extensions/typescript/OSSREADME.json index ec0394b3adf..d9220b9f35b 100644 --- a/extensions/typescript/OSSREADME.json +++ b/extensions/typescript/OSSREADME.json @@ -1,204 +1,16 @@ -// August 2015 -// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: -// THEY ARE CLEARED ONLY FOR LIMITED USE BY MONACO FOR THE MONACO PRODUCT. -// DO NOT USE OR SHARE THIS CODE WITHOUT APPROVAL PURSUANT TO THE MICROSOFT OPEN SOURCE SOFTWARE APPROVAL POLICY. - [{ "name": "TypeScript-TmLanguage", "version": "0.1.8", - "license": "Apache2", + "license": "MIT", "repositoryURL": "https://github.com/Microsoft/TypeScript-TmLanguage", - "description": "The files syntaxes/TypeScript.tmLanguage.json and syntaxes/TypeScriptReact.tmLanguage.json were derived from TypeScript.tmLanguage and TypeScriptReact.tmLanguage in https://github.com/Microsoft/TypeScript-TmLanguage.", - "licenseDetail": [ - // Reason: LICENSE file does not include Copyright statement - "Copyright (c) Microsoft Corporation. All rights reserved.", - "", - " Apache License", - " Version 2.0, January 2004", - " http://www.apache.org/licenses/", - "", - " TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION", - "", - " 1. Definitions.", - "", - " \"License\" shall mean the terms and conditions for use, reproduction,", - " and distribution as defined by Sections 1 through 9 of this document.", - "", - " \"Licensor\" shall mean the copyright owner or entity authorized by", - " the copyright owner that is granting the License.", - "", - " \"Legal Entity\" shall mean the union of the acting entity and all", - " other entities that control, are controlled by, or are under common", - " control with that entity. For the purposes of this definition,", - " \"control\" means (i) the power, direct or indirect, to cause the", - " direction or management of such entity, whether by contract or", - " otherwise, or (ii) ownership of fifty percent (50%) or more of the", - " outstanding shares, or (iii) beneficial ownership of such entity.", - "", - " \"You\" (or \"Your\") shall mean an individual or Legal Entity", - " exercising permissions granted by this License.", - "", - " \"Source\" form shall mean the preferred form for making modifications,", - " including but not limited to software source code, documentation", - " source, and configuration files.", - "", - " \"Object\" form shall mean any form resulting from mechanical", - " transformation or translation of a Source form, including but", - " not limited to compiled object code, generated documentation,", - " and conversions to other media types.", - "", - " \"Work\" shall mean the work of authorship, whether in Source or", - " Object form, made available under the License, as indicated by a", - " copyright notice that is included in or attached to the work", - " (an example is provided in the Appendix below).", - "", - " \"Derivative Works\" shall mean any work, whether in Source or Object", - " form, that is based on (or derived from) the Work and for which the", - " editorial revisions, annotations, elaborations, or other modifications", - " represent, as a whole, an original work of authorship. For the purposes", - " of this License, Derivative Works shall not include works that remain", - " separable from, or merely link (or bind by name) to the interfaces of,", - " the Work and Derivative Works thereof.", - "", - " \"Contribution\" shall mean any work of authorship, including", - " the original version of the Work and any modifications or additions", - " to that Work or Derivative Works thereof, that is intentionally", - " submitted to Licensor for inclusion in the Work by the copyright owner", - " or by an individual or Legal Entity authorized to submit on behalf of", - " the copyright owner. For the purposes of this definition, \"submitted\"", - " means any form of electronic, verbal, or written communication sent", - " to the Licensor or its representatives, including but not limited to", - " communication on electronic mailing lists, source code control systems,", - " and issue tracking systems that are managed by, or on behalf of, the", - " Licensor for the purpose of discussing and improving the Work, but", - " excluding communication that is conspicuously marked or otherwise", - " designated in writing by the copyright owner as \"Not a Contribution.\"", - "", - " \"Contributor\" shall mean Licensor and any individual or Legal Entity", - " on behalf of whom a Contribution has been received by Licensor and", - " subsequently incorporated within the Work.", - "", - " 2. Grant of Copyright License. Subject to the terms and conditions of", - " this License, each Contributor hereby grants to You a perpetual,", - " worldwide, non-exclusive, no-charge, royalty-free, irrevocable", - " copyright license to reproduce, prepare Derivative Works of,", - " publicly display, publicly perform, sublicense, and distribute the", - " Work and such Derivative Works in Source or Object form.", - "", - " 3. Grant of Patent License. Subject to the terms and conditions of", - " this License, each Contributor hereby grants to You a perpetual,", - " worldwide, non-exclusive, no-charge, royalty-free, irrevocable", - " (except as stated in this section) patent license to make, have made,", - " use, offer to sell, sell, import, and otherwise transfer the Work,", - " where such license applies only to those patent claims licensable", - " by such Contributor that are necessarily infringed by their", - " Contribution(s) alone or by combination of their Contribution(s)", - " with the Work to which such Contribution(s) was submitted. If You", - " institute patent litigation against any entity (including a", - " cross-claim or counterclaim in a lawsuit) alleging that the Work", - " or a Contribution incorporated within the Work constitutes direct", - " or contributory patent infringement, then any patent licenses", - " granted to You under this License for that Work shall terminate", - " as of the date such litigation is filed.", - "", - " 4. Redistribution. You may reproduce and distribute copies of the", - " Work or Derivative Works thereof in any medium, with or without", - " modifications, and in Source or Object form, provided that You", - " meet the following conditions:", - "", - " (a) You must give any other recipients of the Work or", - " Derivative Works a copy of this License; and", - "", - " (b) You must cause any modified files to carry prominent notices", - " stating that You changed the files; and", - "", - " (c) You must retain, in the Source form of any Derivative Works", - " that You distribute, all copyright, patent, trademark, and", - " attribution notices from the Source form of the Work,", - " excluding those notices that do not pertain to any part of", - " the Derivative Works; and", - "", - " (d) If the Work includes a \"NOTICE\" text file as part of its", - " distribution, then any Derivative Works that You distribute must", - " include a readable copy of the attribution notices contained", - " within such NOTICE file, excluding those notices that do not", - " pertain to any part of the Derivative Works, in at least one", - " of the following places: within a NOTICE text file distributed", - " as part of the Derivative Works; within the Source form or", - " documentation, if provided along with the Derivative Works; or,", - " within a display generated by the Derivative Works, if and", - " wherever such third-party notices normally appear. The contents", - " of the NOTICE file are for informational purposes only and", - " do not modify the License. You may add Your own attribution", - " notices within Derivative Works that You distribute, alongside", - " or as an addendum to the NOTICE text from the Work, provided", - " that such additional attribution notices cannot be construed", - " as modifying the License.", - "", - " You may add Your own copyright statement to Your modifications and", - " may provide additional or different license terms and conditions", - " for use, reproduction, or distribution of Your modifications, or", - " for any such Derivative Works as a whole, provided Your use,", - " reproduction, and distribution of the Work otherwise complies with", - " the conditions stated in this License.", - "", - " 5. Submission of Contributions. Unless You explicitly state otherwise,", - " any Contribution intentionally submitted for inclusion in the Work", - " by You to the Licensor shall be under the terms and conditions of", - " this License, without any additional terms or conditions.", - " Notwithstanding the above, nothing herein shall supersede or modify", - " the terms of any separate license agreement you may have executed", - " with Licensor regarding such Contributions.", - "", - " 6. Trademarks. This License does not grant permission to use the trade", - " names, trademarks, service marks, or product names of the Licensor,", - " except as required for reasonable and customary use in describing the", - " origin of the Work and reproducing the content of the NOTICE file.", - "", - " 7. Disclaimer of Warranty. Unless required by applicable law or", - " agreed to in writing, Licensor provides the Work (and each", - " Contributor provides its Contributions) on an \"AS IS\" BASIS,", - " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or", - " implied, including, without limitation, any warranties or conditions", - " of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A", - " PARTICULAR PURPOSE. You are solely responsible for determining the", - " appropriateness of using or redistributing the Work and assume any", - " risks associated with Your exercise of permissions under this License.", - "", - " 8. Limitation of Liability. In no event and under no legal theory,", - " whether in tort (including negligence), contract, or otherwise,", - " unless required by applicable law (such as deliberate and grossly", - " negligent acts) or agreed to in writing, shall any Contributor be", - " liable to You for damages, including any direct, indirect, special,", - " incidental, or consequential damages of any character arising as a", - " result of this License or out of the use or inability to use the", - " Work (including but not limited to damages for loss of goodwill,", - " work stoppage, computer failure or malfunction, or any and all", - " other commercial damages or losses), even if such Contributor", - " has been advised of the possibility of such damages.", - "", - " 9. Accepting Warranty or Additional Liability. While redistributing", - " the Work or Derivative Works thereof, You may choose to offer,", - " and charge a fee for, acceptance of support, warranty, indemnity,", - " or other liability obligations and/or rights consistent with this", - " License. However, in accepting such obligations, You may act only", - " on Your own behalf and on Your sole responsibility, not on behalf", - " of any other Contributor, and only if You agree to indemnify,", - " defend, and hold each Contributor harmless for any liability", - " incurred by, or claims asserted against, such Contributor by reason", - " of your accepting any such warranty or additional liability.", - "", - " END OF TERMS AND CONDITIONS" - ] + "description": "The files syntaxes/TypeScript.tmLanguage.json and syntaxes/TypeScriptReact.tmLanguage.json were derived from TypeScript.tmLanguage and TypeScriptReact.tmLanguage in https://github.com/Microsoft/TypeScript-TmLanguage." }, { - "isLicense": true, // We override the license since we need a coorect Copyright + // We override the license that gets discovered at + // https://github.com/Microsoft/TypeScript/blob/master/LICENSE.txt + // because it does not contain a Copyright statement + "isLicense": true, "name": "typescript", - "version": "2.0.6", - "license": "Apache2", - "repositoryURL": "https://github.com/Microsoft/TypeScript", - "description": "The contents of the folder lib is from the TypeScript project https://github.com/Microsoft/TypeScript.", - // Reason: LICENSE file does not include Copyright statement "licenseDetail": [ "Copyright (c) Microsoft Corporation. All rights reserved.", "", @@ -258,4 +70,4 @@ "", "END OF TERMS AND CONDITIONS" ] -}] \ No newline at end of file +}] diff --git a/extensions/typescript/build/update-grammars.js b/extensions/typescript/build/update-grammars.js index c38d6f10510..bae3329d9b1 100644 --- a/extensions/typescript/build/update-grammars.js +++ b/extensions/typescript/build/update-grammars.js @@ -6,14 +6,17 @@ var updateGrammar = require('../../../build/npm/update-grammar'); -function adaptToJavaScript(grammar) { +function adaptToJavaScript(grammar, replacementScope) { grammar.name = 'JavaScript (with React support)'; grammar.fileTypes = ['.js', '.jsx', '.es6', '.mjs' ]; - grammar.scopeName = 'source.js'; + grammar.scopeName = `source${replacementScope}`; var fixScopeNames = function(rule) { if (typeof rule.name === 'string') { - rule.name = rule.name.replace(/\.tsx/g, '.js'); + rule.name = rule.name.replace(/\.tsx/g, replacementScope); + } + if (typeof rule.contentName === 'string') { + rule.contentName = rule.contentName.replace(/\.tsx/g, replacementScope); } for (var property in rule) { var value = rule[property]; @@ -32,7 +35,9 @@ function adaptToJavaScript(grammar) { var tsGrammarRepo = 'Microsoft/TypeScript-TmLanguage'; updateGrammar.update(tsGrammarRepo, 'TypeScript.tmLanguage', './syntaxes/TypeScript.tmLanguage.json'); updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', './syntaxes/TypeScriptReact.tmLanguage.json'); -updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScript.tmLanguage.json', adaptToJavaScript); +updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScript.tmLanguage.json', grammar => adaptToJavaScript(grammar, '.js')); +updateGrammar.update(tsGrammarRepo, 'TypeScriptReact.tmLanguage', '../javascript/syntaxes/JavaScriptReact.tmLanguage.json', grammar => adaptToJavaScript(grammar, '.js.jsx')); + diff --git a/extensions/typescript/language-configuration.json b/extensions/typescript/language-configuration.json index f25940db455..1e8f440a420 100644 --- a/extensions/typescript/language-configuration.json +++ b/extensions/typescript/language-configuration.json @@ -24,5 +24,11 @@ ["'", "'"], ["\"", "\""], ["`", "`"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*//\\s*#?region\\b", + "end": "^\\s*//\\s*#?endregion\\b" + } + } } \ No newline at end of file diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 7f24be0df8b..6d2e4f19230 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -17,8 +17,8 @@ "vscode-nls": "2.0.1" }, "devDependencies": { - "@types/node": "^7.0.4", - "@types/semver": "^5.3.30" + "@types/node": "8.0.33", + "@types/semver": "5.4.0" }, "scripts": { "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:typescript ./tsconfig.json", @@ -77,7 +77,9 @@ "path": "./syntaxes/TypeScriptReact.tmLanguage.json", "embeddedLanguages": { "meta.tag.tsx": "jsx-tags", - "meta.tag.without-attributes.tsx": "jsx-tags" + "meta.tag.without-attributes.tsx": "jsx-tags", + "meta.tag.attributes.tsx": "typescriptreact", + "meta.embedded.expression.tsx": "typescriptreact" } } ], @@ -164,17 +166,23 @@ "description": "%typescript.useCodeSnippetsOnMethodSuggest.dec%", "scope": "resource" }, + "typescript.reportStyleChecksAsWarnings": { + "type": "boolean", + "default": true, + "description": "%typescript.reportStyleChecksAsWarnings%", + "scope": "window" + }, "typescript.validate.enable": { "type": "boolean", "default": true, "description": "%typescript.validate.enable%", - "scope": "resource" + "scope": "window" }, "typescript.format.enable": { "type": "boolean", "default": true, "description": "%typescript.format.enable%", - "scope": "resource" + "scope": "window" }, "typescript.format.insertSpaceAfterCommaDelimiter": { "type": "boolean", @@ -270,13 +278,13 @@ "type": "boolean", "default": true, "description": "%javascript.validate.enable%", - "scope": "resource" + "scope": "window" }, "javascript.format.enable": { "type": "boolean", "default": true, "description": "%javascript.format.enable%", - "scope": "resource" + "scope": "window" }, "javascript.format.insertSpaceAfterCommaDelimiter": { "type": "boolean", @@ -374,6 +382,12 @@ "description": "%javascript.implicitProjectConfig.checkJs%", "scope": "window" }, + "javascript.implicitProjectConfig.experimentalDecorators": { + "type": "boolean", + "default": false, + "description": "%javascript.implicitProjectConfig.experimentalDecorators%", + "scope": "window" + }, "javascript.nameSuggestions": { "type": "boolean", "default": true, @@ -385,10 +399,46 @@ "default": "on", "enum": [ "on", - "off" + "off", + "build", + "watch" ], "description": "%typescript.tsc.autoDetect%", + "scope": "window" + }, + "typescript.quickSuggestionsForPaths": { + "type": "boolean", + "default": true, + "description": "%typescript.quickSuggestionsForPaths%", "scope": "resource" + }, + "typescript.autoImportSuggestions.enabled": { + "type": "boolean", + "default": true, + "description": "%typescript.autoImportSuggestions.enabled%", + "scope": "resource" + }, + "typescript.locale": { + "type": [ + "string", + "null" + ], + "enum": [ + "de", + "es", + "en", + "fr", + "it", + "ja", + "ko", + "ru", + "zh-CN", + "zh-TW", + null + ], + "default": null, + "description": "%typescript.locale%", + "scope": "window" } } }, @@ -480,7 +530,7 @@ }, { "language": "typescriptreact", - "path": "./snippets/typescriptreact.json" + "path": "./snippets/typescript.json" } ], "jsonValidation": [ @@ -515,6 +565,9 @@ "tsconfig": { "type": "string", "description": "The tsconfig file that defines the TS build" + }, + "option": { + "type": "string" } } } diff --git a/extensions/typescript/package.nls.json b/extensions/typescript/package.nls.json index b25953666f6..2aa7a9e59e6 100644 --- a/extensions/typescript/package.nls.json +++ b/extensions/typescript/package.nls.json @@ -34,12 +34,17 @@ "typescript.openTsServerLog.title": "Open TS Server log", "typescript.restartTsServer": "Restart TS server", "typescript.selectTypeScriptVersion.title": "Select TypeScript Version", + "typescript.reportStyleChecksAsWarnings": "Report style checks as warnings", "jsDocCompletion.enabled": "Enable/disable auto JSDoc comments", "javascript.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing jsconfig.json or tsconfig.json files override this setting. Requires TypeScript >=2.3.1.", "typescript.npm": "Specifies the path to the NPM executable used for Automatic Type Acquisition. Requires TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "Check if NPM is installed for Automatic Type Acquisition.", "javascript.nameSuggestions": "Enable/disable including unique names from the file in JavaScript suggestion lists.", - "typescript.tsc.autoDetect": "Controls whether auto detection of tsc tasks is on or off.", + "typescript.tsc.autoDetect": "Controls auto detection of tsc tasks. 'off' disables this feature. 'build' only creates single run compile tasks. 'watch' only creates compile and watch tasks. 'on' creates both build and watch tasks. Default is 'on'.", "typescript.problemMatchers.tsc.label": "TypeScript problems", - "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)" -} + "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)", + "typescript.quickSuggestionsForPaths": "Enable/disable quick suggestions when typing out an import path.", + "typescript.locale": "Sets the locale used to report TypeScript errors. Requires TypeScript >= 2.6.0. Default of 'null' uses VS Code's locale for TypeScript errors.", + "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" +} \ No newline at end of file diff --git a/extensions/typescript/snippets/typescript.json b/extensions/typescript/snippets/typescript.json index f76afcb02c4..b5627443402 100644 --- a/extensions/typescript/snippets/typescript.json +++ b/extensions/typescript/snippets/typescript.json @@ -56,7 +56,7 @@ "body": [ "", "public get ${1:value}() : ${2:string} {", - " ${3:return $0}", + "\t${3:return $0}", "}", "" ], @@ -76,10 +76,10 @@ "", "private _${1:value} : ${2:string};", "public get ${1:value}() : ${2:string} {", - " return this._${1:value};", + "\treturn this._${1:value};", "}", "public set ${1:value}(v : ${2:string}) {", - " this._${1:value} = v;", + "\tthis._${1:value} = v;", "}", "" ], @@ -119,7 +119,7 @@ "body": [ "", "public set ${1:value}(v : ${2:string}) {", - " this.$3 = v;", + "\tthis.$3 = v;", "}", "" ], @@ -136,8 +136,8 @@ "For Loop": { "prefix": "for", "body": [ - "for (var ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", - "\tvar ${3:element} = ${2:array}[${1:index}];", + "for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", + "\tconst ${3:element} = ${2:array}[${1:index}];", "\t$0", "}" ], @@ -155,15 +155,24 @@ "For-In Loop": { "prefix": "forin", "body": [ - "for (var ${1:key} in ${2:object}) {", + "for (const ${1:key} in ${2:object}) {", "\tif (${2:object}.hasOwnProperty(${1:key})) {", - "\t\tvar ${3:element} = ${2:object}[${1:key}];", + "\t\tconst ${3:element} = ${2:object}[${1:key}];", "\t\t$0", "\t}", "}" ], "description": "For-In Loop" }, + "For-Of Loop": { + "prefix": "forof", + "body": [ + "for (const ${1:iterator} of ${2:object}) {", + "\t$0", + "}" + ], + "description": "For-Of Loop" + }, "Function Statement": { "prefix": "function", "body": [ @@ -196,7 +205,7 @@ "New Statement": { "prefix": "new", "body": [ - "var ${1:name} = new ${2:type}(${3:arguments});$0" + "const ${1:name} = new ${2:type}(${3:arguments});$0" ], "description": "New Statement" }, @@ -246,10 +255,24 @@ "Set Timeout Function": { "prefix": "settimeout", "body": [ - "setTimeout(function() {", + "setTimeout(() => {", "\t$0", "}, ${1:timeout});" ], "description": "Set Timeout Function" + }, + "Region Start": { + "prefix": "#region", + "body": [ + "//#region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#endregion", + "body": [ + "//#endregion" + ], + "description": "Folding Region End" } } diff --git a/extensions/typescript/snippets/typescriptreact.json b/extensions/typescript/snippets/typescriptreact.json deleted file mode 100644 index c0d38f23c18..00000000000 --- a/extensions/typescript/snippets/typescriptreact.json +++ /dev/null @@ -1,258 +0,0 @@ -{ - "Constructor": { - "prefix": "ctor", - "body": [ - "/**", - " *", - " */", - "constructor() {", - "\tsuper();", - "\t$0", - "}" - ], - "description": "Constructor" - }, - "Class Definition": { - "prefix": "class", - "body": [ - "/**", - " * ${1:name}", - " */", - "class ${1:name} {", - "\tconstructor(${2:parameters}) {", - "\t\t$0", - "\t}", - "}" - ], - "description": "Class Definition" - }, - "Public Method Definition": { - "prefix": "public method", - "body": [ - "/**", - " * ${1:name}", - " */", - "public ${1:name}() {", - "\t$0", - "}" - ], - "description": "Public Method Definition" - }, - "Private Method Definition": { - "prefix": "private method", - "body": [ - "private ${1:name}() {", - "\t$0", - "}" - ], - "description": "Private Method Definition" - }, - "Import external module.": { - "prefix": "import statement", - "body": [ - "import ${1:name} = require('$0');" - ], - "description": "Import external module." - }, - "Property getter": { - "prefix": "get", - "body": [ - "", - "public get ${1:value}() : ${2:string} {", - " ${3:return $0}", - "}", - "" - ], - "description": "Property getter" - }, - "Log to the console": { - "prefix": "log", - "body": [ - "console.log($1);", - "$0" - ], - "description": "Log to the console" - }, - "Define a full property": { - "prefix": "prop", - "body": [ - "", - "private _${1:value} : ${2:string};", - "public get ${1:value}() : ${2:string} {", - " return this._${1:value};", - "}", - "public set ${1:value}(v : ${2:string}) {", - " this._${1:value} = v;", - "}", - "" - ], - "description": "Define a full property" - }, - "Triple-slash reference": { - "prefix": "ref", - "body": [ - "/// ", - "$0" - ], - "description": "Triple-slash reference" - }, - "Return false": { - "prefix": "ret0", - "body": [ - "return false;$0" - ], - "description": "Return false" - }, - "Return true": { - "prefix": "ret1", - "body": [ - "return true;$0" - ], - "description": "Return true" - }, - "Return statement": { - "prefix": "ret", - "body": [ - "return $1;$0" - ], - "description": "Return statement" - }, - "Property setter": { - "prefix": "set", - "body": [ - "", - "public set ${1:value}(v : ${2:string}) {", - " this.$3 = v;", - "}", - "" - ], - "description": "Property setter" - }, - "Throw Exception": { - "prefix": "throw", - "body": [ - "throw \"$1\";", - "$0" - ], - "description": "Throw Exception" - }, - "For Loop": { - "prefix": "for", - "body": [ - "for (var ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", - "\tvar ${3:element} = ${2:array}[${1:index}];", - "\t$0", - "}" - ], - "description": "For Loop" - }, - "For-Each Loop using =>": { - "prefix": "foreach =>", - "body": [ - "${1:array}.forEach(${2:element} => {", - "\t$0", - "});" - ], - "description": "For-Each Loop using =>" - }, - "For-In Loop": { - "prefix": "forin", - "body": [ - "for (var ${1:key} in ${2:object}) {", - "\tif (${2:object}.hasOwnProperty(${1:key})) {", - "\t\tvar ${3:element} = ${2:object}[${1:key}];", - "\t\t$0", - "\t}", - "}" - ], - "description": "For-In Loop" - }, - "Function Statement": { - "prefix": "function", - "body": [ - "function ${1:name}(${2:params}:${3:type}) {", - "\t$0", - "}" - ], - "description": "Function Statement" - }, - "If Statement": { - "prefix": "if", - "body": [ - "if (${1:condition}) {", - "\t$0", - "}" - ], - "description": "If Statement" - }, - "If-Else Statement": { - "prefix": "ifelse", - "body": [ - "if (${1:condition}) {", - "\t$0", - "} else {", - "\t", - "}" - ], - "description": "If-Else Statement" - }, - "New Statement": { - "prefix": "new", - "body": [ - "var ${1:name} = new ${2:type}(${2:arguments});$0" - ], - "description": "New Statement" - }, - "Switch Statement": { - "prefix": "switch", - "body": [ - "switch (${1:key}) {", - "\tcase ${2:value}:", - "\t\t$0", - "\t\tbreak;", - "", - "\tdefault:", - "\t\tbreak;", - "}" - ], - "description": "Switch Statement" - }, - "While Statement": { - "prefix": "while", - "body": [ - "while (${1:condition}) {", - "\t$0", - "}" - ], - "description": "While Statement" - }, - "Do-While Statement": { - "prefix": "dowhile", - "body": [ - "do {", - "\t$0", - "} while (${1:condition});" - ], - "description": "Do-While Statement" - }, - "Try-Catch Statement": { - "prefix": "trycatch", - "body": [ - "try {", - "\t$0", - "} catch (${1:error}) {", - "\t", - "}" - ], - "description": "Try-Catch Statement" - }, - "Set Timeout Function": { - "prefix": "settimeout", - "body": [ - "setTimeout(function() {", - "\t$0", - "}, ${1:timeout});" - ], - "description": "Set Timeout Function" - } -} diff --git a/extensions/typescript/src/features/baseCodeLensProvider.ts b/extensions/typescript/src/features/baseCodeLensProvider.ts index 84ba69a0a96..46db4127e71 100644 --- a/extensions/typescript/src/features/baseCodeLensProvider.ts +++ b/extensions/typescript/src/features/baseCodeLensProvider.ts @@ -6,7 +6,8 @@ import { CodeLensProvider, CodeLens, CancellationToken, TextDocument, Range, Uri, Position, Event, EventEmitter, ProviderResult, } from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange } from '../utils/convert'; export class ReferencesCodeLens extends CodeLens { constructor( @@ -23,7 +24,7 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider private onDidChangeCodeLensesEmitter = new EventEmitter(); public constructor( - protected client: ITypescriptServiceClient + protected client: ITypeScriptServiceClient ) { } public get onDidChangeCodeLenses(): Event { @@ -99,10 +100,7 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider return null; } - const range = new Range( - span.start.line - 1, span.start.offset - 1, - span.end.line - 1, span.end.offset - 1); - + const range = tsTextSpanToVsRange(span); const text = document.getText(range); const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${(item.text || '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}(\\b|\\W)`, 'gm'); diff --git a/extensions/typescript/src/features/bufferSyncSupport.ts b/extensions/typescript/src/features/bufferSyncSupport.ts index 975d4e9f529..63f0bdfbc86 100644 --- a/extensions/typescript/src/features/bufferSyncSupport.ts +++ b/extensions/typescript/src/features/bufferSyncSupport.ts @@ -7,8 +7,9 @@ import * as fs from 'fs'; import { workspace, TextDocument, TextDocumentChangeEvent, TextDocumentContentChangeEvent, Disposable } from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; import { Delayer } from '../utils/async'; +import * as languageModeIds from '../utils/languageModeIds'; interface IDiagnosticRequestor { requestDiagnostic(filepath: string): void; @@ -16,10 +17,10 @@ interface IDiagnosticRequestor { function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined { switch (mode) { - case 'typescript': return 'TS'; - case 'typescriptreact': return 'TSX'; - case 'javascript': return 'JS'; - case 'javascriptreact': return 'JSX'; + case languageModeIds.typescript: return 'TS'; + case languageModeIds.typescriptreact: return 'TSX'; + case languageModeIds.javascript: return 'JS'; + case languageModeIds.javascriptreact: return 'JSX'; } return undefined; } @@ -30,7 +31,7 @@ class SyncedBuffer { private readonly document: TextDocument, private readonly filepath: string, private readonly diagnosticRequestor: IDiagnosticRequestor, - private readonly client: ITypescriptServiceClient + private readonly client: ITypeScriptServiceClient ) { } public open(): void { @@ -105,7 +106,7 @@ export interface Diagnostics { export default class BufferSyncSupport { - private readonly client: ITypescriptServiceClient; + private readonly client: ITypeScriptServiceClient; private _validate: boolean; private readonly modeIds: Set; @@ -117,7 +118,7 @@ export default class BufferSyncSupport { private readonly diagnosticDelayer: Delayer; constructor( - client: ITypescriptServiceClient, + client: ITypeScriptServiceClient, modeIds: string[], diagnostics: Diagnostics, validate: boolean diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index c48caaf79e4..644ad445616 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -3,41 +3,50 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, Uri, workspace, WorkspaceEdit, TextEdit, FormattingOptions, window } from 'vscode'; +import * as vscode from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { vsRangeToTsFileRange } from '../utils/convert'; +import FormattingConfigurationManager from './formattingConfigurationManager'; +import { applyCodeAction } from '../utils/codeAction'; +import { CommandManager, Command } from '../utils/commandManager'; interface NumberSet { [key: number]: boolean; } -interface Source { - uri: Uri; - version: number; - range: Range; - formattingOptions: FormattingOptions | undefined; +class ApplyCodeActionCommand implements Command { + + public static readonly ID: string = '_typescript.applyCodeAction'; + public readonly id: string = ApplyCodeActionCommand.ID; + + constructor( + private readonly client: ITypeScriptServiceClient + ) { } + + execute(action: Proto.CodeAction, file: string): void { + applyCodeAction(this.client, action, file); + } } -export default class TypeScriptCodeActionProvider implements CodeActionProvider { - private commandId: string; - +export default class TypeScriptCodeActionProvider implements vscode.CodeActionProvider { private _supportedCodeActions?: Thenable; constructor( - private readonly client: ITypescriptServiceClient, - mode: string + private readonly client: ITypeScriptServiceClient, + private readonly formattingConfigurationManager: FormattingConfigurationManager, + commandManager: CommandManager ) { - this.commandId = `_typescript.applyCodeAction.${mode}`; - commands.registerCommand(this.commandId, this.onCodeAction, this); + commandManager.register(new ApplyCodeActionCommand(this.client)); } public async provideCodeActions( - document: TextDocument, - range: Range, - context: CodeActionContext, - token: CancellationToken - ): Promise { + document: vscode.TextDocument, + range: vscode.Range, + context: vscode.CodeActionContext, + token: vscode.CancellationToken + ): Promise { if (!this.client.apiVersion.has213Features()) { return []; } @@ -52,30 +61,14 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider return []; } - let formattingOptions: FormattingOptions | undefined = undefined; - for (const editor of window.visibleTextEditors) { - if (editor.document.fileName === document.fileName) { - formattingOptions = { tabSize: editor.options.tabSize, insertSpaces: editor.options.insertSpaces } as FormattingOptions; - break; - } - } + await this.formattingConfigurationManager.ensureFormatOptionsForDocument(document, token); - const source: Source = { - uri: document.uri, - version: document.version, - range: range, - formattingOptions: formattingOptions - }; const args: Proto.CodeFixRequestArgs = { - file: file, - startLine: range.start.line + 1, - endLine: range.end.line + 1, - startOffset: range.start.character + 1, - endOffset: range.end.character + 1, + ...vsRangeToTsFileRange(file, range), errorCodes: Array.from(supportedActions) }; const response = await this.client.execute('getCodeFixes', args, token); - return (response.body || []).map(action => this.getCommandForAction(source, action)); + return (response.body || []).map(action => this.getCommandForAction(action, file)); } private get supportedCodeActions(): Thenable { @@ -92,62 +85,18 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider return this._supportedCodeActions; } - private getSupportedActionsForContext(context: CodeActionContext): Thenable> { - return this.supportedCodeActions.then(supportedActions => - new Set(context.diagnostics - .map(diagnostic => +diagnostic.code) - .filter(code => supportedActions[code]))); + private async getSupportedActionsForContext(context: vscode.CodeActionContext): Promise> { + const supportedActions = await this.supportedCodeActions; + return new Set(context.diagnostics + .map(diagnostic => +diagnostic.code) + .filter(code => supportedActions[code])); } - private getCommandForAction(source: Source, action: Proto.CodeAction): Command { + private getCommandForAction(action: Proto.CodeAction, file: string): vscode.Command { return { title: action.description, - command: this.commandId, - arguments: [source, action] + command: ApplyCodeActionCommand.ID, + arguments: [action, file] }; } - - private async onCodeAction(source: Source, action: Proto.CodeAction): Promise { - const workspaceEdit = new WorkspaceEdit(); - for (const change of action.changes) { - for (const textChange of change.textChanges) { - workspaceEdit.replace(this.client.asUrl(change.fileName), - new Range( - textChange.start.line - 1, textChange.start.offset - 1, - textChange.end.line - 1, textChange.end.offset - 1), - textChange.newText); - } - } - - const success = workspace.applyEdit(workspaceEdit); - if (!success) { - return false; - } - - let firstEdit: TextEdit | undefined = undefined; - for (const [uri, edits] of workspaceEdit.entries()) { - if (uri.fsPath === source.uri.fsPath) { - firstEdit = edits[0]; - break; - } - } - - if (!firstEdit) { - return true; - } - - const newLines = firstEdit.newText.match(/\n/g); - const editedRange = new Range( - firstEdit.range.start.line, 0, - firstEdit.range.end.line + 1 + (newLines ? newLines.length : 0), 0); - // TODO: Workaround for https://github.com/Microsoft/TypeScript/issues/12249 - // apply formatting to the source range until TS returns formatted results - const edits = (await commands.executeCommand('vscode.executeFormatRangeProvider', source.uri, editedRange, source.formattingOptions || {})) as TextEdit[]; - if (!edits || !edits.length) { - return false; - } - const formattingEdit = new WorkspaceEdit(); - formattingEdit.set(source.uri, edits); - return workspace.applyEdit(formattingEdit); - } } \ No newline at end of file diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index db06b46cbc2..29e40633eea 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -3,36 +3,44 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult } from 'vscode'; +import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext, Uri, MarkdownString } from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; import TypingsStatus from '../utils/typingsStatus'; import * as PConst from '../protocol.const'; -import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails, FileLocationRequestArgs } from '../protocol'; +import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails, CodeAction } from '../protocol'; import * as Previewer from './previewer'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; +import { applyCodeAction } from '../utils/codeAction'; +import * as languageModeIds from '../utils/languageModeIds'; +import { CommandManager, Command } from '../utils/commandManager'; + let localize = nls.loadMessageBundle(); class MyCompletionItem extends CompletionItem { + public readonly source: string | undefined; constructor( - public position: Position, - public document: TextDocument, + public readonly position: Position, + public readonly document: TextDocument, entry: CompletionEntry, enableDotCompletions: boolean, - enableCallCompletions: boolean + public readonly useCodeSnippetsOnMethodSuggest: boolean ) { super(entry.name); + this.source = entry.source; this.sortText = entry.sortText; this.kind = MyCompletionItem.convertKind(entry.kind); this.position = position; - this.commitCharacters = MyCompletionItem.getCommitCharacters(enableDotCompletions, enableCallCompletions, entry.kind); + this.commitCharacters = MyCompletionItem.getCommitCharacters(enableDotCompletions, !useCodeSnippetsOnMethodSuggest, entry.kind); + if (entry.replacementSpan) { let span: protocol.TextSpan = entry.replacementSpan; // The indexing for the range returned by the server uses 1-based indexing. // We convert to 0-based indexing. - this.textEdit = TextEdit.replace(new Range(span.start.line - 1, span.start.offset - 1, span.end.line - 1, span.end.offset - 1), entry.name); + this.textEdit = TextEdit.replace(tsTextSpanToVsRange(span), entry.name); } else { // Try getting longer, prefix based range for completions that span words const wordRange = document.getWordRangeAtPosition(position); @@ -92,13 +100,6 @@ class MyCompletionItem extends CompletionItem { private static getCommitCharacters(enableDotCompletions: boolean, enableCallCompletions: boolean, kind: string): string[] | undefined { switch (kind) { - case PConst.Kind.externalModuleName: - return ['"', '\'']; - - case PConst.Kind.file: - case PConst.Kind.directory: - return ['"', '\'']; - case PConst.Kind.memberGetAccessor: case PConst.Kind.memberSetAccessor: case PConst.Kind.constructSignature: @@ -125,40 +126,54 @@ class MyCompletionItem extends CompletionItem { } } +class ApplyCompletionCodeActionCommand implements Command { + public static readonly ID = '_typescript.applyCompletionCodeAction'; + public readonly id = ApplyCompletionCodeActionCommand.ID; + + public constructor( + private readonly client: ITypeScriptServiceClient + ) { } + + public async execute(file: string, codeActions: CodeAction[]): Promise { + for (const action of codeActions) { + if (!(await applyCodeAction(this.client, action, file))) { + return false; + } + } + return true; + } +} + interface Configuration { useCodeSnippetsOnMethodSuggest: boolean; nameSuggestions: boolean; + quickSuggestionsForPaths: boolean; + autoImportSuggestions: boolean; } namespace Configuration { export const useCodeSnippetsOnMethodSuggest = 'useCodeSnippetsOnMethodSuggest'; export const nameSuggestions = 'nameSuggestions'; + export const quickSuggestionsForPaths = 'quickSuggestionsForPaths'; + export const autoImportSuggestions = 'autoImportSuggestions.enabled'; + } export default class TypeScriptCompletionItemProvider implements CompletionItemProvider { - - private config: Configuration; - constructor( - private client: ITypescriptServiceClient, - private typingsStatus: TypingsStatus + private client: ITypeScriptServiceClient, + private readonly typingsStatus: TypingsStatus, + commandManager: CommandManager ) { - this.config = { - useCodeSnippetsOnMethodSuggest: false, - nameSuggestions: true - }; + commandManager.register(new ApplyCompletionCodeActionCommand(this.client)); } - public updateConfiguration(): void { - // Use shared setting for js and ts - const typeScriptConfig = workspace.getConfiguration('typescript'); - this.config.useCodeSnippetsOnMethodSuggest = typeScriptConfig.get(Configuration.useCodeSnippetsOnMethodSuggest, false); - - const jsConfig = workspace.getConfiguration('javascript'); - this.config.nameSuggestions = jsConfig.get(Configuration.nameSuggestions, true); - } - - public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise { + public async provideCompletionItems( + document: TextDocument, + position: Position, + token: CancellationToken, + context: CompletionContext + ): Promise { if (this.typingsStatus.isAcquiringTypings) { return Promise.reject({ label: localize( @@ -172,15 +187,49 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP const file = this.client.normalizePath(document.uri); if (!file) { - return Promise.resolve([]); + return []; } - const args: CompletionsRequestArgs = { - file: file, - line: position.line + 1, - offset: position.character + 1 - }; - return this.client.execute('completions', args, token).then((msg) => { + const config = this.getConfiguration(document.uri); + + if (context.triggerCharacter === '"' || context.triggerCharacter === '\'') { + if (!config.quickSuggestionsForPaths) { + return []; + } + + // make sure we are in something that looks like the start of an import + const line = document.lineAt(position.line).text.slice(0, position.character); + if (!line.match(/\b(from|import)\s*["']$/) && !line.match(/\b(import|require)\(['"]$/)) { + return []; + } + } + + if (context.triggerCharacter === '/') { + if (!config.quickSuggestionsForPaths) { + return []; + } + + // make sure we are in something that looks like an import path + const line = document.lineAt(position.line).text.slice(0, position.character); + if (!line.match(/\b(from|import)\s*["'][^'"]*$/) && !line.match(/\b(import|require)\(['"][^'"]*$/)) { + return []; + } + } + + if (context.triggerCharacter === '@') { + // make sure we are in something that looks like the start of a jsdoc comment + const line = document.lineAt(position.line).text.slice(0, position.character); + if (!line.match(/^\s*\*[ ]?@/) && !line.match(/\/\*\*+[ ]?@/)) { + return []; + } + } + + try { + const args = { + ...vsPositionToTsFileLocation(file, position), + includeExternalModuleExports: config.autoImportSuggestions + } as CompletionsRequestArgs; + const msg = await this.client.execute('completions', args, token); // This info has to come from the tsserver. See https://github.com/Microsoft/TypeScript/issues/2831 // let isMemberCompletion = false; // let requestColumn = position.character; @@ -201,12 +250,12 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP const body = msg.body; if (body) { // Only enable dot completions in TS files for now - let enableDotCompletions = document && (document.languageId === 'typescript' || document.languageId === 'typescriptreact'); + let enableDotCompletions = document && (document.languageId === languageModeIds.typescript || document.languageId === languageModeIds.typescriptreact); // 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. - if (position.character > 0) { + if (position.character > 1) { const preText = document.getText(new Range( position.line, 0, position.line, position.character - 1)); @@ -214,18 +263,21 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } for (const element of body) { - if (element.kind === PConst.Kind.warning && !this.config.nameSuggestions) { + if (element.kind === PConst.Kind.warning && !config.nameSuggestions) { continue; } - const item = new MyCompletionItem(position, document, element, enableDotCompletions, !this.config.useCodeSnippetsOnMethodSuggest); + if (!config.autoImportSuggestions && element.hasAction) { + continue; + } + const item = new MyCompletionItem(position, document, element, enableDotCompletions, config.useCodeSnippetsOnMethodSuggest); completionItems.push(item); } } return completionItems; - }, () => { + } catch { return []; - }); + } } public resolveCompletionItem(item: CompletionItem, token: CancellationToken): ProviderResult { @@ -238,10 +290,10 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP return null; } const args: CompletionDetailsRequestArgs = { - file: filepath, - line: item.position.line + 1, - offset: item.position.character + 1, - entryNames: [item.label] + ...vsPositionToTsFileLocation(filepath, item.position), + entryNames: [ + item.source ? { name: item.label, source: item.source } : item.label + ] }; return this.client.execute('completionEntryDetails', args, token).then((response) => { const details = response.body; @@ -250,10 +302,37 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } const detail = details[0]; item.detail = Previewer.plain(detail.displayParts); + const documentation = new MarkdownString(); + if (item.source) { + let importPath = `'${item.source}'`; + // Try to resolve the real import name that will be added + if (detail.codeActions && detail.codeActions[0]) { + const action = detail.codeActions[0]; + if (action.changes[0] && action.changes[0].textChanges[0]) { + const textChange = action.changes[0].textChanges[0]; + const matchedImport = textChange.newText.match(/(['"])(.+?)\1/); + if (matchedImport) { + importPath = matchedImport[0]; + item.detail += ` — from ${matchedImport[0]}`; + } + } + } + documentation.appendMarkdown(localize('autoImportLabel', 'Auto import from {0}', importPath)); + documentation.appendMarkdown('\n\n'); + } - item.documentation = Previewer.plainDocumentation(detail.documentation, detail.tags); + Previewer.addmarkdownDocumentation(documentation, detail.documentation, detail.tags); + item.documentation = documentation; - if (detail && this.config.useCodeSnippetsOnMethodSuggest && (item.kind === CompletionItemKind.Function || item.kind === CompletionItemKind.Method)) { + if (detail.codeActions && detail.codeActions.length) { + item.command = { + title: '', + command: ApplyCompletionCodeActionCommand.ID, + arguments: [filepath, detail.codeActions] + }; + } + + if (detail && item.useCodeSnippetsOnMethodSuggest && (item.kind === CompletionItemKind.Function || item.kind === CompletionItemKind.Method)) { return this.isValidFunctionCompletionContext(filepath, item.position).then(shouldCompleteFunction => { if (shouldCompleteFunction) { item.insertText = this.snippetForFunctionCall(detail); @@ -269,11 +348,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } private isValidFunctionCompletionContext(filepath: string, position: Position): Promise { - const args: FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args = vsPositionToTsFileLocation(filepath, position); // Workaround for https://github.com/Microsoft/TypeScript/issues/12677 // Don't complete function calls inside of destructive assigments or imports return this.client.execute('quickinfo', args).then(infoResponse => { @@ -318,4 +393,15 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP return new SnippetString(codeSnippet); } + + private getConfiguration(resource: Uri): Configuration { + // Use shared setting for js and ts + const typeScriptConfig = workspace.getConfiguration('typescript', resource); + return { + useCodeSnippetsOnMethodSuggest: typeScriptConfig.get(Configuration.useCodeSnippetsOnMethodSuggest, false), + quickSuggestionsForPaths: typeScriptConfig.get(Configuration.quickSuggestionsForPaths, true), + autoImportSuggestions: typeScriptConfig.get(Configuration.autoImportSuggestions, true), + nameSuggestions: workspace.getConfiguration('javascript', resource).get(Configuration.nameSuggestions, true) + }; + } } diff --git a/extensions/typescript/src/features/definitionProvider.ts b/extensions/typescript/src/features/definitionProvider.ts index 2713fc603db..25f9218c4e1 100644 --- a/extensions/typescript/src/features/definitionProvider.ts +++ b/extensions/typescript/src/features/definitionProvider.ts @@ -5,16 +5,10 @@ import { DefinitionProvider, TextDocument, Position, CancellationToken, Definition } from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; import DefinitionProviderBase from './definitionProviderBase'; export default class TypeScriptDefinitionProvider extends DefinitionProviderBase implements DefinitionProvider { - - constructor(client: ITypescriptServiceClient) { - super(client); - } - - public provideDefinition(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { + public provideDefinition(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { return this.getSymbolLocations('definition', document, position, token); } } \ No newline at end of file diff --git a/extensions/typescript/src/features/definitionProviderBase.ts b/extensions/typescript/src/features/definitionProviderBase.ts index 78768df2fee..47be5791b6b 100644 --- a/extensions/typescript/src/features/definitionProviderBase.ts +++ b/extensions/typescript/src/features/definitionProviderBase.ts @@ -3,45 +3,42 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TextDocument, Position, Range, CancellationToken, Location } from 'vscode'; +import { TextDocument, Position, CancellationToken, Location } from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptDefinitionProviderBase { constructor( - private client: ITypescriptServiceClient) { } + private client: ITypeScriptServiceClient) { } - protected getSymbolLocations( + protected async getSymbolLocations( definitionType: 'definition' | 'implementation' | 'typeDefinition', document: TextDocument, position: Position, token: CancellationToken | boolean - ): Promise { + ): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { - return Promise.resolve(null); + return undefined; } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; - return this.client.execute(definitionType, args, token).then(response => { + + const args = vsPositionToTsFileLocation(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); - if (resource === null) { - return null; - } else { - return new Location(resource, new Range(location.start.line - 1, location.start.offset - 1, location.end.line - 1, location.end.offset - 1)); - } - }).filter(x => x !== null) as Location[]; - }, () => { + return resource + ? new Location(resource, tsTextSpanToVsRange(location)) + : undefined; + }).filter(x => x) as Location[]; + } catch { return []; - }); + } } } \ No newline at end of file diff --git a/extensions/typescript/src/features/directiveCommentCompletionProvider.ts b/extensions/typescript/src/features/directiveCommentCompletionProvider.ts index b52012d833c..2253a2acb27 100644 --- a/extensions/typescript/src/features/directiveCommentCompletionProvider.ts +++ b/extensions/typescript/src/features/directiveCommentCompletionProvider.ts @@ -5,7 +5,7 @@ import { Position, CompletionItemProvider, CompletionItemKind, TextDocument, CancellationToken, CompletionItem, ProviderResult, Range } from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -36,7 +36,7 @@ const directives: Directive[] = [ export default class DirectiveCommentCompletionProvider implements CompletionItemProvider { constructor( - private client: ITypescriptServiceClient, + private client: ITypeScriptServiceClient, ) { } public provideCompletionItems(document: TextDocument, position: Position, _token: CancellationToken): ProviderResult { diff --git a/extensions/typescript/src/features/documentHighlightProvider.ts b/extensions/typescript/src/features/documentHighlightProvider.ts index 15224ca2c2e..7c62fcd1fc8 100644 --- a/extensions/typescript/src/features/documentHighlightProvider.ts +++ b/extensions/typescript/src/features/documentHighlightProvider.ts @@ -5,26 +5,28 @@ import { DocumentHighlightProvider, DocumentHighlight, DocumentHighlightKind, TextDocument, Position, Range, CancellationToken } from 'vscode'; -import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptDocumentHighlightProvider implements DocumentHighlightProvider { public constructor( - private client: ITypescriptServiceClient) { } + private client: ITypeScriptServiceClient) { } - public provideDocumentHighlights(resource: TextDocument, position: Position, token: CancellationToken): Promise { + public async provideDocumentHighlights( + resource: TextDocument, + position: Position, + token: CancellationToken + ): Promise { const filepath = this.client.normalizePath(resource.uri); if (!filepath) { - return Promise.resolve([]); + return []; } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; - return this.client.execute('occurrences', args, token).then((response): DocumentHighlight[] => { - let data = response.body; + + 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 @@ -37,14 +39,14 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh return []; } } - return data.map((item) => { - return new DocumentHighlight(new Range(item.start.line - 1, item.start.offset - 1, item.end.line - 1, item.end.offset - 1), - item.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read); - }); + 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/features/documentSymbolProvider.ts b/extensions/typescript/src/features/documentSymbolProvider.ts index 456776cf3a6..bb052549a5c 100644 --- a/extensions/typescript/src/features/documentSymbolProvider.ts +++ b/extensions/typescript/src/features/documentSymbolProvider.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DocumentSymbolProvider, SymbolInformation, SymbolKind, TextDocument, Range, Location, CancellationToken, Uri } from 'vscode'; +import { DocumentSymbolProvider, SymbolInformation, SymbolKind, TextDocument, Location, CancellationToken, Uri } from 'vscode'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange } from '../utils/convert'; const outlineTypeTable: { [kind: string]: SymbolKind } = Object.create(null); outlineTypeTable[PConst.Kind.module] = SymbolKind.Module; @@ -25,13 +26,10 @@ outlineTypeTable[PConst.Kind.variable] = SymbolKind.Variable; outlineTypeTable[PConst.Kind.function] = SymbolKind.Function; outlineTypeTable[PConst.Kind.localFunction] = SymbolKind.Function; -function textSpan2Range(value: Proto.TextSpan): Range { - return new Range(value.start.line - 1, value.start.offset - 1, value.end.line - 1, value.end.offset - 1); -} export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolProvider { public constructor( - private client: ITypescriptServiceClient) { } + private client: ITypeScriptServiceClient) { } public async provideDocumentSymbols(resource: TextDocument, token: CancellationToken): Promise { const filepath = this.client.normalizePath(resource.uri); @@ -73,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, textSpan2Range(item.spans[0]))); + new Location(resource, tsTextSpanToVsRange(item.spans[0]))); foldingMap[key] = result; bucket.push(result); } @@ -88,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, textSpan2Range(item.spans[0])) + new Location(resource, tsTextSpanToVsRange(item.spans[0])) ); if (item.childItems && item.childItems.length > 0) { for (const child of item.childItems) { diff --git a/extensions/typescript/src/features/formattingConfigurationManager.ts b/extensions/typescript/src/features/formattingConfigurationManager.ts new file mode 100644 index 00000000000..09d4a5bdc82 --- /dev/null +++ b/extensions/typescript/src/features/formattingConfigurationManager.ts @@ -0,0 +1,125 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { workspace as Workspace, FormattingOptions, TextDocument, CancellationToken, window, Disposable, workspace } from 'vscode'; + +import * as Proto from '../protocol'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import * as languageIds from '../utils/languageModeIds'; + +namespace FormattingConfiguration { + export function equals(a: Proto.FormatCodeSettings, b: Proto.FormatCodeSettings): boolean { + let keys = Object.keys(a); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + if ((a as any)[key] !== (b as any)[key]) { + return false; + } + } + return true; + } +} + +export default class FormattingConfigurationManager { + private onDidCloseTextDocumentSub: Disposable | undefined; + private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; } = Object.create(null); + + public constructor( + private client: ITypeScriptServiceClient + ) { + this.onDidCloseTextDocumentSub = Workspace.onDidCloseTextDocument((textDocument) => { + const key = textDocument.uri.toString(); + // When a document gets closed delete the cached formatting options. + // This is necessary since the tsserver now closed a project when its + // last file in it closes which drops the stored formatting options + // as well. + delete this.formatOptions[key]; + }); + } + + public dispose() { + if (this.onDidCloseTextDocumentSub) { + this.onDidCloseTextDocumentSub.dispose(); + this.onDidCloseTextDocumentSub = undefined; + } + } + + public async ensureFormatOptionsForDocument( + document: TextDocument, + token: CancellationToken | undefined + ): Promise { + const editor = window.visibleTextEditors.find(editor => editor.document.fileName === document.fileName); + if (editor) { + const formattingOptions = { + tabSize: editor.options.tabSize, + insertSpaces: editor.options.insertSpaces + } as FormattingOptions; + return this.ensureFormatOptions(document, formattingOptions, token); + } + } + + public async ensureFormatOptions( + document: TextDocument, + options: FormattingOptions, + token: CancellationToken | undefined + ): Promise { + const file = this.client.normalizePath(document.uri); + if (!file) { + return; + } + + const key = document.uri.toString(); + const cachedOptions = this.formatOptions[key]; + const formatOptions = this.getFormatOptions(document, options); + + if (cachedOptions && FormattingConfiguration.equals(cachedOptions, formatOptions)) { + return; + } + + const args: Proto.ConfigureRequestArguments = { + file: file, + formatOptions: formatOptions + }; + await this.client.execute('configure', args, token); + this.formatOptions[key] = formatOptions; + } + + public reset() { + this.formatOptions = Object.create(null); + } + + private getFormatOptions( + document: TextDocument, + options: FormattingOptions + ): Proto.FormatCodeSettings { + const config = workspace.getConfiguration( + document.languageId === languageIds.typescript || document.languageId === languageIds.typescriptreact + ? 'typescript.format' + : 'javascript.format', + document.uri); + return { + tabSize: options.tabSize, + indentSize: options.tabSize, + convertTabsToSpaces: options.insertSpaces, + // We can use \n here since the editor normalizes later on to its line endings. + newLineCharacter: '\n', + insertSpaceAfterCommaDelimiter: config.get('insertSpaceAfterCommaDelimiter'), + insertSpaceAfterConstructor: config.get('insertSpaceAfterConstructor'), + insertSpaceAfterSemicolonInForStatements: config.get('insertSpaceAfterSemicolonInForStatements'), + insertSpaceBeforeAndAfterBinaryOperators: config.get('insertSpaceBeforeAndAfterBinaryOperators'), + insertSpaceAfterKeywordsInControlFlowStatements: config.get('insertSpaceAfterKeywordsInControlFlowStatements'), + insertSpaceAfterFunctionKeywordForAnonymousFunctions: config.get('insertSpaceAfterFunctionKeywordForAnonymousFunctions'), + insertSpaceBeforeFunctionParenthesis: config.get('insertSpaceBeforeFunctionParenthesis'), + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: config.get('insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis'), + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: config.get('insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets'), + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: config.get('insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces'), + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: config.get('insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces'), + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: config.get('insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces'), + insertSpaceAfterTypeAssertion: config.get('insertSpaceAfterTypeAssertion'), + placeOpenBraceOnNewLineForFunctions: config.get('placeOpenBraceOnNewLineForFunctions'), + placeOpenBraceOnNewLineForControlBlocks: config.get('placeOpenBraceOnNewLineForControlBlocks'), + }; + } +} diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 1c5e7866b8f..6a149b96f75 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -3,153 +3,56 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { workspace as Workspace, DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, FormattingOptions, TextDocument, Position, Range, CancellationToken, TextEdit, WorkspaceConfiguration, Disposable, languages, workspace } from 'vscode'; +import { DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, FormattingOptions, TextDocument, Position, Range, CancellationToken, TextEdit, WorkspaceConfiguration, Disposable, languages, workspace } from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; - -interface Configuration { - enable: boolean; - insertSpaceAfterCommaDelimiter: boolean; - insertSpaceAfterConstructor: boolean; - insertSpaceAfterSemicolonInForStatements: boolean; - insertSpaceBeforeAndAfterBinaryOperators: boolean; - insertSpaceAfterKeywordsInControlFlowStatements: boolean; - insertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: boolean; - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean; - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: boolean; - insertSpaceAfterTypeAssertion: boolean; - insertSpaceBeforeFunctionParenthesis: boolean; - placeOpenBraceOnNewLineForFunctions: boolean; - placeOpenBraceOnNewLineForControlBlocks: boolean; -} - -namespace Configuration { - export const insertSpaceAfterCommaDelimiter = 'insertSpaceAfterCommaDelimiter'; - export const insertSpaceAfterConstructor = 'insertSpaceAfterConstructor'; - export const insertSpaceAfterSemicolonInForStatements = 'insertSpaceAfterSemicolonInForStatements'; - export const insertSpaceBeforeAndAfterBinaryOperators = 'insertSpaceBeforeAndAfterBinaryOperators'; - export const insertSpaceAfterKeywordsInControlFlowStatements = 'insertSpaceAfterKeywordsInControlFlowStatements'; - export const insertSpaceAfterFunctionKeywordForAnonymousFunctions = 'insertSpaceAfterFunctionKeywordForAnonymousFunctions'; - export const insertSpaceBeforeFunctionParenthesis = 'insertSpaceBeforeFunctionParenthesis'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces'; - export const insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = 'insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces'; - export const insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = 'insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces'; - export const insertSpaceAfterTypeAssertion = 'insertSpaceAfterTypeAssertion'; - export const placeOpenBraceOnNewLineForFunctions = 'placeOpenBraceOnNewLineForFunctions'; - export const placeOpenBraceOnNewLineForControlBlocks = 'placeOpenBraceOnNewLineForControlBlocks'; - - export function equals(a: Configuration, b: Configuration): boolean { - let keys = Object.keys(a); - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - if ((a as any)[key] !== (b as any)[key]) { - return false; - } - } - return true; - } - - export function def(): Configuration { - let result: Configuration = Object.create(null); - result.enable = true; - result.insertSpaceAfterCommaDelimiter = true; - result.insertSpaceAfterConstructor = false; - result.insertSpaceAfterSemicolonInForStatements = true; - result.insertSpaceBeforeAndAfterBinaryOperators = true; - result.insertSpaceAfterKeywordsInControlFlowStatements = true; - result.insertSpaceAfterFunctionKeywordForAnonymousFunctions = false; - result.insertSpaceBeforeFunctionParenthesis = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = true; - result.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = false; - result.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = false; - result.insertSpaceAfterTypeAssertion = false; - result.placeOpenBraceOnNewLineForFunctions = false; - result.placeOpenBraceOnNewLineForControlBlocks = false; - return result; - } -} +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange } from '../utils/convert'; +import FormattingConfigurationManager from './formattingConfigurationManager'; export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { - private config: Configuration; - private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; }; + private enabled: boolean = true; public constructor( - private client: ITypescriptServiceClient - ) { - this.config = Configuration.def(); - this.formatOptions = Object.create(null); - Workspace.onDidCloseTextDocument((textDocument) => { - let key = textDocument.uri.toString(); - // When a document gets closed delete the cached formatting options. - // This is necessary sine the tsserver now closed a project when its - // last file in it closes which drops the stored formatting options - // as well. - delete this.formatOptions[key]; - }); - } + private readonly client: ITypeScriptServiceClient, + private readonly formattingOptionsManager: FormattingConfigurationManager + ) { } public updateConfiguration(config: WorkspaceConfiguration): void { - let newConfig = config.get('format', Configuration.def()); - - if (!Configuration.equals(this.config, newConfig)) { - this.config = newConfig; - this.formatOptions = Object.create(null); - } + this.enabled = config.get('format.enable', true); } public isEnabled(): boolean { - return this.config.enable; + return this.enabled; } - private ensureFormatOptions(document: TextDocument, options: FormattingOptions, token: CancellationToken): Promise { - const key = document.uri.toString(); - const currentOptions = this.formatOptions[key]; - if (currentOptions && currentOptions.tabSize === options.tabSize && currentOptions.indentSize === options.tabSize && currentOptions.convertTabsToSpaces === options.insertSpaces) { - return Promise.resolve(currentOptions); - } else { - const absPath = this.client.normalizePath(document.uri); - if (!absPath) { - return Promise.resolve(Object.create(null)); + private async doFormat( + document: TextDocument, + options: FormattingOptions, + args: Proto.FormatRequestArgs, + token: CancellationToken + ): Promise { + await this.formattingOptionsManager.ensureFormatOptions(document, options, token); + try { + const response = await this.client.execute('format', args, token); + if (response.body) { + return response.body.map(this.codeEdit2SingleEditOperation); } - - const formatOptions = this.getFormatOptions(options); - const args: Proto.ConfigureRequestArguments = { - file: absPath, - formatOptions: formatOptions - }; - return this.client.execute('configure', args, token).then(_ => { - this.formatOptions[key] = formatOptions; - return formatOptions; - }); + } catch { + // noop } + return []; } - private doFormat(document: TextDocument, options: FormattingOptions, args: Proto.FormatRequestArgs, token: CancellationToken): Promise { - return this.ensureFormatOptions(document, options, token).then(() => { - return this.client.execute('format', args, token).then((response): TextEdit[] => { - if (response.body) { - return response.body.map(this.codeEdit2SingleEditOperation); - } else { - return []; - } - }, () => { - return []; - }); - }); - } - - public provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): Promise { + public async provideDocumentRangeFormattingEdits( + document: TextDocument, + range: Range, + options: FormattingOptions, + token: CancellationToken + ): Promise { const absPath = this.client.normalizePath(document.uri); if (!absPath) { - return Promise.resolve([]); + return []; } const args: Proto.FormatRequestArgs = { file: absPath, @@ -161,10 +64,16 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit return this.doFormat(document, options, args, token); } - public provideOnTypeFormattingEdits(document: TextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): Promise { + public async provideOnTypeFormattingEdits( + document: TextDocument, + position: Position, + ch: string, + options: FormattingOptions, + token: CancellationToken + ): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { - return Promise.resolve([]); + return []; } let args: Proto.FormatOnKeyRequestArgs = { file: filepath, @@ -173,66 +82,38 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit key: ch }; - return this.ensureFormatOptions(document, options, token).then(() => { - return this.client.execute('formatonkey', args, token).then((response): TextEdit[] => { - let edits = response.body; - let result: TextEdit[] = []; - if (!edits) { - return result; - } - for (let edit of edits) { - let textEdit = this.codeEdit2SingleEditOperation(edit); - let 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 - // an empty line. Drop those edits - if (range.start.character === 0 && range.start.line === range.end.line && textEdit.newText === '') { - let lText = document.lineAt(range.start.line).text; - // If the edit leaves something on the line keep the edit (note that the end character is exclusive). - // Keep it also if it removes something else than whitespace - if (lText.trim().length > 0 || lText.length > range.end.character) { - result.push(textEdit); - } - } else { + await this.formattingOptionsManager.ensureFormatOptions(document, options, token); + return this.client.execute('formatonkey', args, token).then((response): TextEdit[] => { + let edits = response.body; + let result: TextEdit[] = []; + if (!edits) { + return result; + } + for (let edit of edits) { + let textEdit = this.codeEdit2SingleEditOperation(edit); + let 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 + // an empty line. Drop those edits + if (range.start.character === 0 && range.start.line === range.end.line && textEdit.newText === '') { + let lText = document.lineAt(range.start.line).text; + // If the edit leaves something on the line keep the edit (note that the end character is exclusive). + // Keep it also if it removes something else than whitespace + if (lText.trim().length > 0 || lText.length > range.end.character) { result.push(textEdit); } + } else { + result.push(textEdit); } - return result; - }, () => { - return []; - }); + } + return result; + }, () => { + return []; }); } private codeEdit2SingleEditOperation(edit: Proto.CodeEdit): TextEdit { - return new TextEdit(new Range(edit.start.line - 1, edit.start.offset - 1, edit.end.line - 1, edit.end.offset - 1), - edit.newText); - } - - private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { - return { - tabSize: options.tabSize, - indentSize: options.tabSize, - convertTabsToSpaces: options.insertSpaces, - // We can use \n here since the editor normalizes later on to its line endings. - newLineCharacter: '\n', - insertSpaceAfterCommaDelimiter: this.config.insertSpaceAfterCommaDelimiter, - insertSpaceAfterConstructor: this.config.insertSpaceAfterConstructor, - insertSpaceAfterSemicolonInForStatements: this.config.insertSpaceAfterSemicolonInForStatements, - insertSpaceBeforeAndAfterBinaryOperators: this.config.insertSpaceBeforeAndAfterBinaryOperators, - insertSpaceAfterKeywordsInControlFlowStatements: this.config.insertSpaceAfterKeywordsInControlFlowStatements, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: this.config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, - insertSpaceBeforeFunctionParenthesis: this.config.insertSpaceBeforeFunctionParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, - insertSpaceAfterTypeAssertion: this.config.insertSpaceAfterTypeAssertion, - placeOpenBraceOnNewLineForFunctions: this.config.placeOpenBraceOnNewLineForFunctions, - placeOpenBraceOnNewLineForControlBlocks: this.config.placeOpenBraceOnNewLineForControlBlocks, - - }; + return new TextEdit(tsTextSpanToVsRange(edit), edit.newText); } } diff --git a/extensions/typescript/src/features/hoverProvider.ts b/extensions/typescript/src/features/hoverProvider.ts index 9fd1483b625..12714a6c7e4 100644 --- a/extensions/typescript/src/features/hoverProvider.ts +++ b/extensions/typescript/src/features/hoverProvider.ts @@ -3,35 +3,31 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { HoverProvider, Hover, TextDocument, Position, Range, CancellationToken } from 'vscode'; +import { HoverProvider, Hover, TextDocument, Position, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; import { tagsMarkdownPreview } from './previewer'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptHoverProvider implements HoverProvider { public constructor( - private client: ITypescriptServiceClient) { } + private client: ITypeScriptServiceClient) { } public async provideHover(document: TextDocument, position: Position, token: CancellationToken): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { return undefined; } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; - + const args = vsPositionToTsFileLocation(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), - new Range(data.start.line - 1, data.start.offset - 1, data.end.line - 1, data.end.offset - 1)); + tsTextSpanToVsRange(data)); } } catch (e) { // noop @@ -40,10 +36,14 @@ export default class TypeScriptHoverProvider implements HoverProvider { } private static getContents(data: Proto.QuickInfoResponseBody) { + const parts = []; + + if (data.displayString) { + parts.push({ language: 'typescript', value: data.displayString }); + } + const tags = tagsMarkdownPreview(data.tags); - return [ - { language: 'typescript', value: data.displayString }, - data.documentation + (tags ? '\n\n' + tags : '') - ]; + parts.push(data.documentation + (tags ? '\n\n' + tags : '')); + return parts; } } \ No newline at end of file diff --git a/extensions/typescript/src/features/implementationProvider.ts b/extensions/typescript/src/features/implementationProvider.ts index ab4d5b8c45b..03879ef51ea 100644 --- a/extensions/typescript/src/features/implementationProvider.ts +++ b/extensions/typescript/src/features/implementationProvider.ts @@ -5,16 +5,10 @@ import { ImplementationProvider, TextDocument, Position, CancellationToken, Definition } from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; import DefinitionProviderBase from './definitionProviderBase'; export default class TypeScriptImplementationProvider extends DefinitionProviderBase implements ImplementationProvider { - - constructor(client: ITypescriptServiceClient) { - super(client); - } - - public provideImplementation(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { + public provideImplementation(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { return this.getSymbolLocations('implementation', document, position, token); } } \ No newline at end of file diff --git a/extensions/typescript/src/features/implementationsCodeLensProvider.ts b/extensions/typescript/src/features/implementationsCodeLensProvider.ts index 30daa644a4e..7377913a184 100644 --- a/extensions/typescript/src/features/implementationsCodeLensProvider.ts +++ b/extensions/typescript/src/features/implementationsCodeLensProvider.ts @@ -8,14 +8,15 @@ import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider { public constructor( - client: ITypescriptServiceClient, + client: ITypeScriptServiceClient, private readonly language: string ) { super(client); @@ -35,11 +36,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args: Proto.FileLocationRequestArgs = { - file: codeLens.file, - line: codeLens.range.start.line + 1, - offset: codeLens.range.start.character + 1 - }; + const args = vsPositionToTsFileLocation(codeLens.file, codeLens.range.start); return this.client.execute('implementation', args, token).then(response => { if (!response || !response.body) { throw codeLens; @@ -50,15 +47,13 @@ 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 - ? new Range( - reference.start.line - 1, reference.start.offset - 1, - reference.end.line - 1, reference.end.offset - 1) + ? tsTextSpanToVsRange(reference) : new Range( reference.start.line - 1, reference.start.offset - 1, reference.start.line, 0))) // Exclude original from implementations .filter(location => - !(location.uri.fsPath === codeLens.document.fsPath && + !(location.uri.toString() === codeLens.document.toString() && location.range.start.line === codeLens.range.start.line && location.range.start.character === codeLens.range.start.character)); diff --git a/extensions/typescript/src/features/jsDocCompletionProvider.ts b/extensions/typescript/src/features/jsDocCompletionProvider.ts index 502cf89c42c..267acadb93f 100644 --- a/extensions/typescript/src/features/jsDocCompletionProvider.ts +++ b/extensions/typescript/src/features/jsDocCompletionProvider.ts @@ -5,19 +5,16 @@ import { Position, Range, CompletionItemProvider, CompletionItemKind, TextDocument, CancellationToken, CompletionItem, window, Uri, ProviderResult, TextEditor, SnippetString, workspace } from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; -import { FileLocationRequestArgs, DocCommandTemplateResponse } from '../protocol'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { DocCommandTemplateResponse } from '../protocol'; import * as nls from 'vscode-nls'; +import { vsPositionToTsFileLocation } from '../utils/convert'; +import { Command, CommandManager } from '../utils/commandManager'; const localize = nls.loadMessageBundle(); const configurationNamespace = 'jsDocCompletion'; - -interface Configuration { - enabled: boolean; -} - namespace Configuration { export const enabled = 'enabled'; } @@ -49,21 +46,20 @@ class JsDocCompletionItem extends CompletionItem { } } -export class JsDocCompletionProvider implements CompletionItemProvider { - private config: Configuration; +export default class JsDocCompletionProvider implements CompletionItemProvider { constructor( - private client: ITypescriptServiceClient, + private client: ITypeScriptServiceClient, + commandManager: CommandManager ) { - this.config = { enabled: true }; + commandManager.register(new TryCompleteJsDocCommand(client)); } - public updateConfiguration(): void { - const jsDocCompletionConfig = workspace.getConfiguration(configurationNamespace); - this.config.enabled = jsDocCompletionConfig.get(Configuration.enabled, true); - } - - public provideCompletionItems(document: TextDocument, position: Position, _token: CancellationToken): ProviderResult { + public provideCompletionItems( + document: TextDocument, + position: Position, + _token: CancellationToken + ): ProviderResult { const file = this.client.normalizePath(document.uri); if (!file) { return []; @@ -74,7 +70,8 @@ export class JsDocCompletionProvider implements CompletionItemProvider { const line = document.lineAt(position.line).text; const prefix = line.slice(0, position.character); if (prefix.match(/^\s*$|\/\*\*\s*$|^\s*\/\*\*+\s*$/)) { - return [new JsDocCompletionItem(document, position, this.config.enabled)]; + const enableJsDocCompletions = workspace.getConfiguration(configurationNamespace).get(Configuration.enabled, true); + return [new JsDocCompletionItem(document, position, enableJsDocCompletions)]; } return []; } @@ -84,50 +81,45 @@ export class JsDocCompletionProvider implements CompletionItemProvider { } } -export class TryCompleteJsDocCommand { - static COMMAND_NAME = '_typeScript.tryCompleteJsDoc'; +class TryCompleteJsDocCommand implements Command { + public static readonly COMMAND_NAME = '_typeScript.tryCompleteJsDoc'; + public readonly id = TryCompleteJsDocCommand.COMMAND_NAME; constructor( - private lazyClient: () => ITypescriptServiceClient + private readonly client: ITypeScriptServiceClient ) { } /** * Try to insert a jsdoc comment, using a template provide by typescript * if possible, otherwise falling back to a default comment format. */ - public tryCompleteJsDoc(resource: Uri, start: Position, shouldGetJSDocFromTSServer: boolean): Thenable { - const file = this.lazyClient().normalizePath(resource); + public async execute(resource: Uri, start: Position, shouldGetJSDocFromTSServer: boolean): Promise { + const file = this.client.normalizePath(resource); if (!file) { - return Promise.resolve(false); + return false; } const editor = window.activeTextEditor; if (!editor || editor.document.uri.fsPath !== resource.fsPath) { - return Promise.resolve(false); + return false; } if (!shouldGetJSDocFromTSServer) { return this.tryInsertDefaultDoc(editor, start); } - return this.tryInsertJsDocFromTemplate(editor, file, start) - .then((didInsertFromTemplate: boolean) => { - if (didInsertFromTemplate) { - return true; - } - return this.tryInsertDefaultDoc(editor, start); - }); + const didInsertFromTemplate = await this.tryInsertJsDocFromTemplate(editor, file, start); + if (didInsertFromTemplate) { + return true; + } + return this.tryInsertDefaultDoc(editor, start); } private tryInsertJsDocFromTemplate(editor: TextEditor, file: string, position: Position): Promise { - const args: FileLocationRequestArgs = { - file: file, - line: position.line + 1, - offset: position.character + 1 - }; + const args = vsPositionToTsFileLocation(file, position); return Promise.race([ - this.lazyClient().execute('docCommentTemplate', args), - new Promise((_, reject) => setTimeout(reject, 250)) + this.client.execute('docCommentTemplate', args), + new Promise((_, reject) => setTimeout(reject, 250)) ]).then((res: DocCommandTemplateResponse) => { if (!res || !res.body) { return false; diff --git a/extensions/typescript/src/features/previewer.ts b/extensions/typescript/src/features/previewer.ts index 5865b560d2b..e56e067d17f 100644 --- a/extensions/typescript/src/features/previewer.ts +++ b/extensions/typescript/src/features/previewer.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as Proto from '../protocol'; +import { MarkdownString } from 'vscode'; export function plain(parts: Proto.SymbolDisplayPart[]): string { if (!parts) { @@ -24,20 +25,24 @@ export function tagsMarkdownPreview(tags: Proto.JSDocTagInfo[]): string { .join(' \n\n'); } -function tagsPlainPreview(tags: Proto.JSDocTagInfo[]): string { - return (tags || []) - .map(tag => { - const label = `@${tag.name}`; - if (!tag.text) { - return label; - } - return label + (tag.text.match(/\r\n|\n/g) ? '\n' + tag.text : ` — ${tag.text}`); - }) - .join('\n\ngit'); +export function markdownDocumentation( + documentation: Proto.SymbolDisplayPart[], + tags: Proto.JSDocTagInfo[] +): MarkdownString { + const out = new MarkdownString(); + addmarkdownDocumentation(out, documentation, tags); + return out; } -export function plainDocumentation(documentation: Proto.SymbolDisplayPart[], tags: Proto.JSDocTagInfo[]): string { - const processedDocumentation = plain(documentation).replace(/\n([ \t]*\n)?/gm, (x) => x.length >= 2 ? '\n\n' : ' '); - const parts = [processedDocumentation, tagsPlainPreview(tags)]; - return parts.filter(x => x).join('\n\n'); +export function addmarkdownDocumentation( + out: MarkdownString, + documentation: Proto.SymbolDisplayPart[], + tags: Proto.JSDocTagInfo[] +): MarkdownString { + out.appendMarkdown(plain(documentation)); + const tagsPreview = tagsMarkdownPreview(tags); + if (tagsPreview) { + out.appendMarkdown('\n\n' + tagsPreview); + } + return out; } \ No newline at end of file diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index 1b9062998b5..932b56544fc 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -5,34 +5,113 @@ 'use strict'; -import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit, window, QuickPickItem, Selection, Position } from 'vscode'; +import * as vscode from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange, vsRangeToTsFileRange, tsLocationToVsPosition } from '../utils/convert'; +import FormattingOptionsManager from './formattingConfigurationManager'; +import { CommandManager, Command } from '../utils/commandManager'; - -export default class TypeScriptRefactorProvider implements CodeActionProvider { - private doRefactorCommandId: string; - private selectRefactorCommandId: string; +class ApplyRefactoringCommand implements Command { + public static readonly ID = '_typescript.applyRefactoring'; + public readonly id = ApplyRefactoringCommand.ID; constructor( - private readonly client: ITypescriptServiceClient, - mode: string + private readonly client: ITypeScriptServiceClient, + private formattingOptionsManager: FormattingOptionsManager + ) { } + + public async execute( + document: vscode.TextDocument, + file: string, + refactor: string, + action: string, + range: vscode.Range + ): Promise { + await this.formattingOptionsManager.ensureFormatOptionsForDocument(document, undefined); + + const args: Proto.GetEditsForRefactorRequestArgs = { + ...vsRangeToTsFileRange(file, range), + refactor, + action + }; + + const response = await this.client.execute('getEditsForRefactor', args); + if (!response || !response.body || !response.body.edits.length) { + return false; + } + + const edit = this.toWorkspaceEdit(response.body.edits); + if (!(await vscode.workspace.applyEdit(edit))) { + return false; + } + + const renameLocation = response.body.renameLocation; + if (renameLocation) { + if (vscode.window.activeTextEditor && vscode.window.activeTextEditor.document.uri.fsPath === file) { + const pos = tsLocationToVsPosition(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 { + public static readonly ID = '_typescript.selectRefactoring'; + public readonly id = SelectRefactorCommand.ID; + + constructor( + private readonly doRefactoring: ApplyRefactoringCommand + ) { } + + public async execute( + document: vscode.TextDocument, + file: string, + info: Proto.ApplicableRefactorInfo, + range: vscode.Range + ): Promise { + const selected = await vscode.window.showQuickPick(info.actions.map((action): vscode.QuickPickItem => ({ + label: action.name, + description: action.description + }))); + if (!selected) { + return false; + } + return this.doRefactoring.execute(document, file, info.name, selected.label, range); + } +} + +export default class TypeScriptRefactorProvider implements vscode.CodeActionProvider { + constructor( + private readonly client: ITypeScriptServiceClient, + formattingOptionsManager: FormattingOptionsManager, + commandManager: CommandManager ) { - this.doRefactorCommandId = `_typescript.applyRefactoring.${mode}`; - this.selectRefactorCommandId = `_typescript.selectRefactoring.${mode}`; - - commands.registerCommand(this.doRefactorCommandId, this.doRefactoring, this); - commands.registerCommand(this.selectRefactorCommandId, this.selectRefactoring, this); - + const doRefactoringCommand = commandManager.register(new ApplyRefactoringCommand(this.client, formattingOptionsManager)); + commandManager.register(new SelectRefactorCommand(doRefactoringCommand)); } public async provideCodeActions( - document: TextDocument, - range: Range, - _context: CodeActionContext, - token: CancellationToken - ): Promise { + document: vscode.TextDocument, + range: vscode.Range, + _context: vscode.CodeActionContext, + token: vscode.CancellationToken + ): Promise { if (!this.client.apiVersion.has240Features()) { return []; } @@ -42,34 +121,27 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { return []; } - const args: Proto.GetApplicableRefactorsRequestArgs = { - file: file, - startLine: range.start.line + 1, - startOffset: range.start.character + 1, - endLine: range.end.line + 1, - endOffset: range.end.character + 1 - }; - + const args: Proto.GetApplicableRefactorsRequestArgs = vsRangeToTsFileRange(file, range); try { const response = await this.client.execute('getApplicableRefactors', args, token); if (!response || !response.body) { return []; } - const actions: Command[] = []; + const actions: vscode.Command[] = []; for (const info of response.body) { if (info.inlineable === false) { actions.push({ title: info.description, - command: this.selectRefactorCommandId, - arguments: [file, info, range] + command: SelectRefactorCommand.ID, + arguments: [document, file, info, range] }); } else { for (const action of info.actions) { actions.push({ title: action.description, - command: this.doRefactorCommandId, - arguments: [file, info.name, action.name, range] + command: ApplyRefactoringCommand.ID, + arguments: [document, file, info.name, action.name, range] }); } } @@ -79,62 +151,4 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { return []; } } - - private toWorkspaceEdit(edits: Proto.FileCodeEdits[]): WorkspaceEdit { - const workspaceEdit = new WorkspaceEdit(); - for (const edit of edits) { - for (const textChange of edit.textChanges) { - workspaceEdit.replace(this.client.asUrl(edit.fileName), - new Range( - textChange.start.line - 1, textChange.start.offset - 1, - textChange.end.line - 1, textChange.end.offset - 1), - textChange.newText); - } - } - return workspaceEdit; - } - - private async selectRefactoring(file: string, info: Proto.ApplicableRefactorInfo, range: Range): Promise { - return window.showQuickPick(info.actions.map((action): QuickPickItem => ({ - label: action.name, - description: action.description - }))).then(selected => { - if (!selected) { - return false; - } - return this.doRefactoring(file, info.name, selected.label, range); - }); - } - - private async doRefactoring(file: string, refactor: string, action: string, range: Range): Promise { - const args: Proto.GetEditsForRefactorRequestArgs = { - file, - refactor, - action, - startLine: range.start.line + 1, - startOffset: range.start.character + 1, - endLine: range.end.line + 1, - endOffset: range.end.character + 1 - }; - - const response = await this.client.execute('getEditsForRefactor', args); - if (!response || !response.body || !response.body.edits.length) { - return false; - } - - const edit = this.toWorkspaceEdit(response.body.edits); - if (!(await workspace.applyEdit(edit))) { - return false; - } - - const renameLocation = response.body.renameLocation; - if (renameLocation) { - if (window.activeTextEditor && window.activeTextEditor.document.uri.fsPath === file) { - const pos = new Position(renameLocation.line - 1, renameLocation.offset - 1); - window.activeTextEditor.selection = new Selection(pos, pos); - await commands.executeCommand('editor.action.rename'); - } - } - return true; - } } \ No newline at end of file diff --git a/extensions/typescript/src/features/referenceProvider.ts b/extensions/typescript/src/features/referenceProvider.ts index 9f7ccf9f49a..4d8c7e5c7d5 100644 --- a/extensions/typescript/src/features/referenceProvider.ts +++ b/extensions/typescript/src/features/referenceProvider.ts @@ -3,25 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ReferenceProvider, Location, TextDocument, Position, Range, CancellationToken } from 'vscode'; +import { ReferenceProvider, Location, TextDocument, Position, CancellationToken } from 'vscode'; -import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptReferenceSupport implements ReferenceProvider { public constructor( - private client: ITypescriptServiceClient) { } + private client: ITypeScriptServiceClient) { } public provideReferences(document: TextDocument, position: Position, options: { includeDeclaration: boolean }, token: CancellationToken): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { return Promise.resolve([]); } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args = vsPositionToTsFileLocation(filepath, position); const apiVersion = this.client.apiVersion; return this.client.execute('references', args, token).then((msg) => { const result: Location[] = []; @@ -35,9 +31,7 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider { continue; } const url = this.client.asUrl(ref.file); - const location = new Location( - url, - new Range(ref.start.line - 1, ref.start.offset - 1, ref.end.line - 1, ref.end.offset - 1)); + const location = new Location(url, tsTextSpanToVsRange(ref)); result.push(location); } return result; diff --git a/extensions/typescript/src/features/referencesCodeLensProvider.ts b/extensions/typescript/src/features/referencesCodeLensProvider.ts index 5576bfc4825..016913a3217 100644 --- a/extensions/typescript/src/features/referencesCodeLensProvider.ts +++ b/extensions/typescript/src/features/referencesCodeLensProvider.ts @@ -8,14 +8,15 @@ import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider { public constructor( - client: ITypescriptServiceClient, + client: ITypeScriptServiceClient, private readonly language: string ) { super(client); @@ -35,11 +36,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args: Proto.FileLocationRequestArgs = { - file: codeLens.file, - line: codeLens.range.start.line + 1, - offset: codeLens.range.start.character + 1 - }; + const args = vsPositionToTsFileLocation(codeLens.file, codeLens.range.start); return this.client.execute('references', args, token).then(response => { if (!response || !response.body) { throw codeLens; @@ -47,13 +44,10 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase const locations = response.body.refs .map(reference => - new Location(this.client.asUrl(reference.file), - new Range( - reference.start.line - 1, reference.start.offset - 1, - reference.end.line - 1, reference.end.offset - 1))) + new Location(this.client.asUrl(reference.file), tsTextSpanToVsRange(reference))) .filter(location => // Exclude original definition from references - !(location.uri.fsPath === codeLens.document.fsPath && + !(location.uri.toString() === codeLens.document.toString() && location.range.start.isEqual(codeLens.range.start))); codeLens.command = { diff --git a/extensions/typescript/src/features/renameProvider.ts b/extensions/typescript/src/features/renameProvider.ts index 291be640ca7..15f94368315 100644 --- a/extensions/typescript/src/features/renameProvider.ts +++ b/extensions/typescript/src/features/renameProvider.ts @@ -3,14 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { RenameProvider, WorkspaceEdit, TextDocument, Position, Range, CancellationToken } from 'vscode'; +import { RenameProvider, WorkspaceEdit, TextDocument, Position, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptRenameProvider implements RenameProvider { public constructor( - private client: ITypescriptServiceClient) { } + private client: ITypeScriptServiceClient) { } public async provideRenameEdits( document: TextDocument, @@ -24,9 +25,7 @@ export default class TypeScriptRenameProvider implements RenameProvider { } const args: Proto.RenameRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1, + ...vsPositionToTsFileLocation(filepath, position), findInStrings: false, findInComments: false }; @@ -49,9 +48,7 @@ export default class TypeScriptRenameProvider implements RenameProvider { continue; } for (const textSpan of spanGroup.locs) { - result.replace(resource, - new Range(textSpan.start.line - 1, textSpan.start.offset - 1, textSpan.end.line - 1, textSpan.end.offset - 1), - newName); + result.replace(resource, tsTextSpanToVsRange(textSpan), newName); } } return result; diff --git a/extensions/typescript/src/features/signatureHelpProvider.ts b/extensions/typescript/src/features/signatureHelpProvider.ts index c3f6c86e001..b303d8f46c5 100644 --- a/extensions/typescript/src/features/signatureHelpProvider.ts +++ b/extensions/typescript/src/features/signatureHelpProvider.ts @@ -7,23 +7,20 @@ import { SignatureHelpProvider, SignatureHelp, SignatureInformation, ParameterIn import * as Previewer from './previewer'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptSignatureHelpProvider implements SignatureHelpProvider { public constructor( - private client: ITypescriptServiceClient) { } + private client: ITypeScriptServiceClient) { } public provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { return Promise.resolve(null); } - const args: Proto.SignatureHelpRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args: Proto.SignatureHelpRequestArgs = vsPositionToTsFileLocation(filepath, position); return this.client.execute('signatureHelp', args, token).then((response) => { const info = response.body; if (!info) { @@ -59,7 +56,7 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro } }); signature.label += Previewer.plain(item.suffixDisplayParts); - signature.documentation = Previewer.plainDocumentation(item.documentation, item.tags); + signature.documentation = Previewer.markdownDocumentation(item.documentation, item.tags); result.signatures.push(signature); }); diff --git a/extensions/typescript/src/features/taskProvider.ts b/extensions/typescript/src/features/taskProvider.ts index 7b88988257e..6582ad68e82 100644 --- a/extensions/typescript/src/features/taskProvider.ts +++ b/extensions/typescript/src/features/taskProvider.ts @@ -10,13 +10,15 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as Proto from '../protocol'; -import TypeScriptServiceClient from '../typescriptServiceClient'; +import { ITypeScriptServiceClient } from '../typescriptService'; import TsConfigProvider, { TSConfig } from '../utils/tsconfigProvider'; import { isImplicitProjectConfigFile } from '../utils/tsconfig'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); +type AutoDetect = 'on' | 'off' | 'build' | 'watch'; + const exists = (file: string): Promise => new Promise((resolve, _reject) => { @@ -28,18 +30,28 @@ const exists = (file: string): Promise => interface TypeScriptTaskDefinition extends vscode.TaskDefinition { tsconfig: string; + option?: string; } /** * Provides tasks for building `tsconfig.json` files in a project. */ class TscTaskProvider implements vscode.TaskProvider { + private autoDetect: AutoDetect = 'on'; private readonly tsconfigProvider: TsConfigProvider; + private readonly disposables: vscode.Disposable[] = []; public constructor( - private readonly lazyClient: () => TypeScriptServiceClient + private readonly lazyClient: () => ITypeScriptServiceClient ) { this.tsconfigProvider = new TsConfigProvider(); + + vscode.workspace.onDidChangeConfiguration(this.onConfigurationChanged, this, this.disposables); + this.onConfigurationChanged(); + } + + dispose() { + this.disposables.forEach(x => x.dispose()); } public async provideTasks(token: vscode.CancellationToken): Promise { @@ -53,7 +65,7 @@ class TscTaskProvider implements vscode.TaskProvider { for (const project of await this.getAllTsConfigs(token)) { if (!configPaths.has(project.path)) { configPaths.add(project.path); - tasks.push(await this.getBuildTaskForProject(project)); + tasks.push(...(await this.getTasksForProject(project))); } } return tasks; @@ -135,18 +147,6 @@ class TscTaskProvider implements vscode.TaskProvider { return 'tsc'; } - private shouldUseWatchForBuild(configFile: TSConfig): boolean { - try { - const config = JSON.parse(fs.readFileSync(configFile.path, 'utf-8')); - if (config) { - return !!config.compileOnSave; - } - } catch (e) { - // noop - } - return false; - } - private getActiveTypeScriptFile(): string | null { const editor = vscode.window.activeTextEditor; if (editor) { @@ -158,10 +158,44 @@ class TscTaskProvider implements vscode.TaskProvider { return null; } - private async getBuildTaskForProject(project: TSConfig): Promise { + private async getTasksForProject(project: TSConfig): Promise { const command = await this.getCommand(project); + const label = this.getLabelForTasks(project); - let label: string = project.path; + const tasks: vscode.Task[] = []; + + if (this.autoDetect === 'build' || this.autoDetect === 'on') { + const buildTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; + const buildTask = new vscode.Task( + buildTaskidentifier, + project.workspaceFolder || vscode.TaskScope.Workspace, + localize('buildTscLabel', 'build - {0}', label), + 'tsc', + new vscode.ShellExecution(`${command} -p "${project.path}"`), + '$tsc'); + buildTask.group = vscode.TaskGroup.Build; + buildTask.isBackground = false; + tasks.push(buildTask); + } + + if (this.autoDetect === 'watch' || this.autoDetect === 'on') { + const watchTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label, option: 'watch' }; + const watchTask = new vscode.Task( + watchTaskidentifier, + project.workspaceFolder || vscode.TaskScope.Workspace, + localize('buildAndWatchTscLabel', 'watch - {0}', label), + 'tsc', + new vscode.ShellExecution(`${command} --watch -p "${project.path}"`), + '$tsc-watch'); + watchTask.group = vscode.TaskGroup.Build; + watchTask.isBackground = true; + tasks.push(watchTask); + } + + return tasks; + } + + private getLabelForTasks(project: TSConfig): string { if (project.workspaceFolder) { const projectFolder = project.workspaceFolder; const workspaceFolders = vscode.workspace.workspaceFolders; @@ -169,36 +203,23 @@ class TscTaskProvider implements vscode.TaskProvider { if (workspaceFolders && workspaceFolders.length > 1) { // Use absolute path when we have multiple folders with the same name if (workspaceFolders.filter(x => x.name === projectFolder.name).length > 1) { - label = path.join(project.workspaceFolder.uri.fsPath, relativePath); + return path.join(project.workspaceFolder.uri.fsPath, relativePath); } else { - label = path.join(project.workspaceFolder.name, relativePath); + return path.join(project.workspaceFolder.name, relativePath); } } else { - label = relativePath; + return relativePath; } } + return project.path; + } - const watch = false && this.shouldUseWatchForBuild(project); - const identifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; - const buildTask = new vscode.Task( - identifier, - watch - ? localize('buildAndWatchTscLabel', 'watch - {0}', label) - : localize('buildTscLabel', 'build - {0}', label), - 'tsc', - new vscode.ShellExecution(`${command} ${watch ? '--watch' : ''} -p "${project.path}"`), - watch - ? '$tsc-watch' - : '$tsc' - ); - buildTask.group = vscode.TaskGroup.Build; - buildTask.isBackground = watch; - return buildTask; + private onConfigurationChanged(): void { + const type = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetect'); + this.autoDetect = typeof type === 'undefined' ? 'on' : type; } } -type AutoDetect = 'on' | 'off'; - /** * Manages registrations of TypeScript task provides with VScode. */ @@ -207,7 +228,7 @@ export default class TypeScriptTaskProviderManager { private readonly disposables: vscode.Disposable[] = []; constructor( - private readonly lazyClient: () => TypeScriptServiceClient + private readonly lazyClient: () => ITypeScriptServiceClient ) { vscode.workspace.onDidChangeConfiguration(this.onConfigurationChanged, this, this.disposables); this.onConfigurationChanged(); @@ -222,11 +243,11 @@ export default class TypeScriptTaskProviderManager { } private onConfigurationChanged() { - let autoDetect = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetect'); + const autoDetect = vscode.workspace.getConfiguration('typescript.tsc').get('autoDetect'); if (this.taskProviderSub && autoDetect === 'off') { this.taskProviderSub.dispose(); this.taskProviderSub = undefined; - } else if (!this.taskProviderSub && autoDetect === 'on') { + } else if (!this.taskProviderSub && autoDetect !== 'off') { this.taskProviderSub = vscode.workspace.registerTaskProvider('typescript', new TscTaskProvider(this.lazyClient)); } } diff --git a/extensions/typescript/src/features/typeDefinitionProvider.ts b/extensions/typescript/src/features/typeDefinitionProvider.ts index d107f67580a..7b2eb4239f1 100644 --- a/extensions/typescript/src/features/typeDefinitionProvider.ts +++ b/extensions/typescript/src/features/typeDefinitionProvider.ts @@ -5,15 +5,10 @@ import { TypeDefinitionProvider, TextDocument, Position, CancellationToken, Definition } from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; import DefinitionProviderBase from './definitionProviderBase'; export default class TypeScriptTypeDefinitionProvider extends DefinitionProviderBase implements TypeDefinitionProvider { - constructor(client: ITypescriptServiceClient) { - super(client); - } - - public provideTypeDefinition(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { + public provideTypeDefinition(document: TextDocument, position: Position, token: CancellationToken | boolean): Promise { return this.getSymbolLocations('typeDefinition', document, position, token); } } \ No newline at end of file diff --git a/extensions/typescript/src/features/workspaceSymbolProvider.ts b/extensions/typescript/src/features/workspaceSymbolProvider.ts index ab2329501a3..b344f5498ce 100644 --- a/extensions/typescript/src/features/workspaceSymbolProvider.ts +++ b/extensions/typescript/src/features/workspaceSymbolProvider.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { workspace, window, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, Range, Location, CancellationToken } from 'vscode'; +import { workspace, window, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, Location, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { tsTextSpanToVsRange } from '../utils/convert'; function getSymbolKind(item: Proto.NavtoItem): SymbolKind { switch (item.kind) { @@ -22,8 +23,9 @@ function getSymbolKind(item: Proto.NavtoItem): SymbolKind { export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbolProvider { public constructor( - private client: ITypescriptServiceClient, - private modeId: string) { } + private client: ITypeScriptServiceClient, + private modeIds: string[] + ) { } public async provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { // typescript wants to have a resource even when asking @@ -33,14 +35,14 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo const editor = window.activeTextEditor; if (editor) { const document = editor.document; - if (document && document.languageId === this.modeId) { + if (document && this.modeIds.indexOf(document.languageId) >= 0) { uri = document.uri; } } if (!uri) { const documents = workspace.textDocuments; for (const document of documents) { - if (document.languageId === this.modeId) { + if (this.modeIds.indexOf(document.languageId) >= 0) { uri = document.uri; break; } @@ -67,7 +69,7 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo if (!item.containerName && item.kind === 'alias') { continue; } - const range = new Range(item.start.line - 1, item.start.offset - 1, item.end.line - 1, item.end.offset - 1); + const range = tsTextSpanToVsRange(item); let label = item.name; if (item.kind === 'method' || item.kind === 'function') { label += '()'; diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 77988313104..91f6780b2cd 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -8,7 +8,7 @@ * https://github.com/Microsoft/TypeScript-Sublime-Plugin/blob/master/TypeScript%20Indent.tmPreferences * ------------------------------------------------------------------------------------------ */ -import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, Disposable, Uri, MessageItem, TextEditor, DiagnosticSeverity, TextDocument } from 'vscode'; +import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, Disposable, Uri, MessageItem, DiagnosticSeverity, TextDocument } from 'vscode'; // This must be the first statement otherwise modules might got loaded with // the wrong locale. @@ -22,10 +22,9 @@ import * as Proto from './protocol'; import * as PConst from './protocol.const'; import TypeScriptServiceClient from './typescriptServiceClient'; -import { ITypescriptServiceClientHost } from './typescriptService'; +import { ITypeScriptServiceClientHost } from './typescriptService'; import BufferSyncSupport from './features/bufferSyncSupport'; -import { JsDocCompletionProvider, TryCompleteJsDocCommand } from './features/jsDocCompletionProvider'; import TypeScriptTaskProviderManager from './features/taskProvider'; import * as ProjectStatus from './utils/projectStatus'; @@ -33,6 +32,10 @@ import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import VersionStatus from './utils/versionStatus'; import { getContributedTypeScriptServerPlugins, TypeScriptServerPlugin } from './utils/plugins'; import { openOrCreateConfigFile, isImplicitProjectConfigFile } from './utils/tsconfig'; +import { tsLocationToVsPosition } from './utils/convert'; +import FormattingConfigurationManager from './features/formattingConfigurationManager'; +import * as languageModeIds from './utils/languageModeIds'; +import { CommandManager, Command } from './utils/commandManager'; interface LanguageDescription { id: string; @@ -42,48 +45,126 @@ interface LanguageDescription { isExternal?: boolean; } -enum ProjectConfigAction { - None, - CreateConfig, - LearnMore -} - -interface ProjectConfigMessageItem extends MessageItem { - id: ProjectConfigAction; -} - -const MODE_ID_TS = 'typescript'; -const MODE_ID_TSX = 'typescriptreact'; -const MODE_ID_JS = 'javascript'; -const MODE_ID_JSX = 'javascriptreact'; - const standardLanguageDescriptions: LanguageDescription[] = [ { id: 'typescript', diagnosticSource: 'ts', - modeIds: [MODE_ID_TS, MODE_ID_TSX], + modeIds: [languageModeIds.typescript, languageModeIds.typescriptreact], configFile: 'tsconfig.json' }, { id: 'javascript', diagnosticSource: 'js', - modeIds: [MODE_ID_JS, MODE_ID_JSX], + modeIds: [languageModeIds.javascript, languageModeIds.javascriptreact], configFile: 'jsconfig.json' } ]; +class ReloadTypeScriptProjectsCommand implements Command { + public readonly id = 'typescript.reloadProjects'; + + public constructor( + private readonly lazyClientHost: () => TypeScriptServiceClientHost + ) { } + + public execute() { + this.lazyClientHost().reloadProjects(); + } +} + +class ReloadJavaScriptProjectsCommand implements Command { + public readonly id = 'javascript.reloadProjects'; + + public constructor( + private readonly lazyClientHost: () => TypeScriptServiceClientHost + ) { } + + public execute() { + this.lazyClientHost().reloadProjects(); + } +} + +class SelectTypeScriptVersionCommand implements Command { + public readonly id = 'typescript.selectTypeScriptVersion'; + + public constructor( + private readonly lazyClientHost: () => TypeScriptServiceClientHost + ) { } + + public execute() { + this.lazyClientHost().serviceClient.onVersionStatusClicked(); + } +} + +class OpenTsServerLogCommand implements Command { + public readonly id = 'typescript.openTsServerLog'; + + public constructor( + private readonly lazyClientHost: () => TypeScriptServiceClientHost + ) { } + + public execute() { + this.lazyClientHost().serviceClient.openTsServerLogFile(); + } +} + +class RestartTsServerCommand implements Command { + public readonly id = 'typescript.restartTsServer'; + + public constructor( + private readonly lazyClientHost: () => TypeScriptServiceClientHost + ) { } + + public execute() { + this.lazyClientHost().serviceClient.restartTsServer(); + } +} + +class TypeScriptGoToProjectConfigCommand implements Command { + public readonly id = 'typescript.goToProjectConfig'; + + public constructor( + private readonly lazyClientHost: () => TypeScriptServiceClientHost, + ) { } + + public execute() { + const editor = window.activeTextEditor; + if (editor) { + this.lazyClientHost().goToProjectConfig(true, editor.document.uri); + } + } +} + +class JavaScriptGoToProjectConfigCommand implements Command { + public readonly id = 'javascript.goToProjectConfig'; + + public constructor( + private readonly lazyClientHost: () => TypeScriptServiceClientHost, + ) { } + + public execute() { + const editor = window.activeTextEditor; + if (editor) { + this.lazyClientHost().goToProjectConfig(false, editor.document.uri); + } + } +} + export function activate(context: ExtensionContext): void { const plugins = getContributedTypeScriptServerPlugins(); + const commandManager = new CommandManager(); + context.subscriptions.push(commandManager); + const lazyClientHost = (() => { let clientHost: TypeScriptServiceClientHost | undefined; return () => { if (!clientHost) { - clientHost = new TypeScriptServiceClientHost(standardLanguageDescriptions, context.workspaceState, plugins); + clientHost = new TypeScriptServiceClientHost(standardLanguageDescriptions, context.workspaceState, plugins, commandManager); context.subscriptions.push(clientHost); const host = clientHost; clientHost.serviceClient.onReady().then(() => { - context.subscriptions.push(ProjectStatus.create(host.serviceClient, + context.subscriptions.push(ProjectStatus.create(host.serviceClient, host.serviceClient.telemetryReporter, path => new Promise(resolve => setTimeout(() => resolve(host.handles(path)), 750)), context.workspaceState)); }, () => { @@ -94,42 +175,16 @@ export function activate(context: ExtensionContext): void { }; })(); - - context.subscriptions.push(commands.registerCommand('typescript.reloadProjects', () => { - lazyClientHost().reloadProjects(); - })); - - context.subscriptions.push(commands.registerCommand('javascript.reloadProjects', () => { - lazyClientHost().reloadProjects(); - })); - - context.subscriptions.push(commands.registerCommand('typescript.selectTypeScriptVersion', () => { - lazyClientHost().serviceClient.onVersionStatusClicked(); - })); - - context.subscriptions.push(commands.registerCommand('typescript.openTsServerLog', () => { - lazyClientHost().serviceClient.openTsServerLogFile(); - })); - - context.subscriptions.push(commands.registerCommand('typescript.restartTsServer', () => { - lazyClientHost().serviceClient.restartTsServer(); - })); + commandManager.register(new ReloadTypeScriptProjectsCommand(lazyClientHost)); + commandManager.register(new ReloadJavaScriptProjectsCommand(lazyClientHost)); + commandManager.register(new SelectTypeScriptVersionCommand(lazyClientHost)); + commandManager.register(new OpenTsServerLogCommand(lazyClientHost)); + commandManager.register(new RestartTsServerCommand(lazyClientHost)); + commandManager.register(new TypeScriptGoToProjectConfigCommand(lazyClientHost)); + commandManager.register(new JavaScriptGoToProjectConfigCommand(lazyClientHost)); context.subscriptions.push(new TypeScriptTaskProviderManager(() => lazyClientHost().serviceClient)); - const goToProjectConfig = (isTypeScript: boolean) => { - const editor = window.activeTextEditor; - if (editor) { - lazyClientHost().goToProjectConfig(isTypeScript, editor.document.uri); - } - }; - context.subscriptions.push(commands.registerCommand('typescript.goToProjectConfig', goToProjectConfig.bind(null, true))); - context.subscriptions.push(commands.registerCommand('javascript.goToProjectConfig', goToProjectConfig.bind(null, false))); - - const jsDocCompletionCommand = new TryCompleteJsDocCommand(() => lazyClientHost().serviceClient); - context.subscriptions.push(commands.registerCommand(TryCompleteJsDocCommand.COMMAND_NAME, jsDocCompletionCommand.tryCompleteJsDoc, jsDocCompletionCommand)); - - const EMPTY_ELEMENTS: string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr']; context.subscriptions.push(languages.setLanguageConfiguration('jsx-tags', { @@ -156,7 +211,7 @@ export function activate(context: ExtensionContext): void { return true; } return false; - }; + } const openListener = workspace.onDidOpenTextDocument(didOpenTextDocument); for (let textDocument of workspace.textDocuments) { if (didOpenTextDocument(textDocument)) { @@ -171,10 +226,14 @@ const validateSetting = 'validate.enable'; class LanguageProvider { private syntaxDiagnostics: ObjectMap; + private semanticDiagnostics: ObjectMap; + private readonly currentDiagnostics: DiagnosticCollection; private readonly bufferSyncSupport: BufferSyncSupport; + private readonly formattingOptionsManager: FormattingConfigurationManager; - private typingsStatus: TypingsStatus; + private readonly typingsStatus: TypingsStatus; + private readonly ataProgressReporter: AtaProgressReporter; private toUpdateOnConfigurationChanged: ({ updateConfiguration: () => void })[] = []; private _validate: boolean = true; @@ -185,18 +244,21 @@ class LanguageProvider { constructor( private readonly client: TypeScriptServiceClient, - private readonly description: LanguageDescription + private readonly description: LanguageDescription, + private readonly commandManager: CommandManager ) { + this.formattingOptionsManager = new FormattingConfigurationManager(client); this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds, { delete: (file: string) => { this.currentDiagnostics.delete(client.asUrl(file)); } }, this._validate); this.syntaxDiagnostics = Object.create(null); + this.semanticDiagnostics = Object.create(null); this.currentDiagnostics = languages.createDiagnosticCollection(description.id); this.typingsStatus = new TypingsStatus(client); - new AtaProgressReporter(client); + this.ataProgressReporter = new AtaProgressReporter(client); workspace.onDidChangeConfiguration(this.configurationChanged, this, this.disposables); this.configurationChanged(); @@ -225,6 +287,7 @@ class LanguageProvider { } this.typingsStatus.dispose(); + this.ataProgressReporter.dispose(); this.currentDiagnostics.dispose(); this.bufferSyncSupport.dispose(); } @@ -233,15 +296,14 @@ class LanguageProvider { const selector = this.description.modeIds; const config = workspace.getConfiguration(this.id); - const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.typingsStatus); - completionItemProvider.updateConfiguration(); - this.toUpdateOnConfigurationChanged.push(completionItemProvider); - this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.')); + this.disposables.push(languages.registerCompletionItemProvider(selector, + new (await import('./features/completionItemProvider')).default(client, this.typingsStatus, this.commandManager), + '.', '"', '\'', '/', '@')); this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/directiveCommentCompletionProvider')).default(client), '@')); const { TypeScriptFormattingProvider, FormattingProviderManager } = await import('./features/formattingProvider'); - const formattingProvider = new TypeScriptFormattingProvider(client); + const formattingProvider = new TypeScriptFormattingProvider(client, this.formattingOptionsManager); formattingProvider.updateConfiguration(config); this.disposables.push(languages.registerOnTypeFormattingEditProvider(selector, formattingProvider, ';', '}', '\n')); @@ -250,10 +312,7 @@ class LanguageProvider { this.disposables.push(formattingProviderManager); this.toUpdateOnConfigurationChanged.push(formattingProviderManager); - const jsDocCompletionProvider = new JsDocCompletionProvider(client); - jsDocCompletionProvider.updateConfiguration(); - this.disposables.push(languages.registerCompletionItemProvider(selector, jsDocCompletionProvider, '*')); - + this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/jsDocCompletionProvider')).default(client, this.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))); this.disposables.push(languages.registerDocumentHighlightProvider(selector, new (await import('./features/documentHighlightProvider')).default(client))); @@ -261,24 +320,24 @@ 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/codeActionProvider')).default(client, this.description.id))); - this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.description.id))); + this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/codeActionProvider')).default(client, this.formattingOptionsManager, this.commandManager))); + this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, this.commandManager))); this.registerVersionDependentProviders(); - for (const modeId of this.description.modeIds) { - this.disposables.push(languages.registerWorkspaceSymbolProvider(new (await import('./features/workspaceSymbolProvider')).default(client, modeId))); + const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, this.description.id); + referenceCodeLensProvider.updateConfiguration(); + this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider); + this.disposables.push(languages.registerCodeLensProvider(selector, referenceCodeLensProvider)); - const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, modeId); - referenceCodeLensProvider.updateConfiguration(); - this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider); - this.disposables.push(languages.registerCodeLensProvider(selector, referenceCodeLensProvider)); + const implementationCodeLensProvider = new (await import('./features/implementationsCodeLensProvider')).default(client, this.description.id); + implementationCodeLensProvider.updateConfiguration(); + this.toUpdateOnConfigurationChanged.push(implementationCodeLensProvider); + this.disposables.push(languages.registerCodeLensProvider(selector, implementationCodeLensProvider)); - const implementationCodeLensProvider = new (await import('./features/implementationsCodeLensProvider')).default(client, modeId); - implementationCodeLensProvider.updateConfiguration(); - this.toUpdateOnConfigurationChanged.push(implementationCodeLensProvider); - this.disposables.push(languages.registerCodeLensProvider(selector, implementationCodeLensProvider)); + this.disposables.push(languages.registerWorkspaceSymbolProvider(new (await import('./features/workspaceSymbolProvider')).default(client, this.description.modeIds))); - if (!this.description.isExternal) { + if (!this.description.isExternal) { + for (const modeId of this.description.modeIds) { this.disposables.push(languages.setLanguageConfiguration(modeId, { indentationRules: { // ^(.*\*/)?\s*\}.*$ @@ -357,6 +416,7 @@ class LanguageProvider { this.triggerAllDiagnostics(); } else { this.syntaxDiagnostics = Object.create(null); + this.semanticDiagnostics = Object.create(null); this.currentDiagnostics.clear(); } } @@ -364,8 +424,10 @@ class LanguageProvider { public reInitialize(): void { this.currentDiagnostics.clear(); this.syntaxDiagnostics = Object.create(null); + this.semanticDiagnostics = Object.create(null); this.bufferSyncSupport.reOpenDocuments(); this.bufferSyncSupport.requestAllDiagnostics(); + this.formattingOptionsManager.reset(); this.registerVersionDependentProviders(); } @@ -396,21 +458,22 @@ class LanguageProvider { this.bufferSyncSupport.requestAllDiagnostics(); } - public syntaxDiagnosticsReceived(file: string, diagnostics: Diagnostic[]): void { - if (this._validate) { - this.syntaxDiagnostics[file] = diagnostics; + public syntaxDiagnosticsReceived(file: string, syntaxDiagnostics: Diagnostic[]): void { + if (!this._validate) { + return; } + this.syntaxDiagnostics[file] = syntaxDiagnostics; + const semanticDianostics = this.semanticDiagnostics[file] || []; + this.currentDiagnostics.set(this.client.asUrl(file), semanticDianostics.concat(syntaxDiagnostics)); } - public semanticDiagnosticsReceived(file: string, diagnostics: Diagnostic[]): void { - if (this._validate) { - const syntaxMarkers = this.syntaxDiagnostics[file]; - if (syntaxMarkers) { - delete this.syntaxDiagnostics[file]; - diagnostics = syntaxMarkers.concat(diagnostics); - } - this.currentDiagnostics.set(this.client.asUrl(file), diagnostics); + public semanticDiagnosticsReceived(file: string, semanticDiagnostics: Diagnostic[]): void { + if (!this._validate) { + return; } + this.semanticDiagnostics[file] = semanticDiagnostics; + const syntaxDiagnostics = this.syntaxDiagnostics[file] || []; + this.currentDiagnostics.set(this.client.asUrl(file), semanticDiagnostics.concat(syntaxDiagnostics)); } public configFileDiagnosticsReceived(file: string, diagnostics: Diagnostic[]): void { @@ -418,7 +481,17 @@ class LanguageProvider { } } -class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { +// Style check diagnostics that can be reported as warnings +const styleCheckDiagnostics = [ + 6133, // variable is declared but never used + 6138, // property is declared but its value is never read + 7027, // unreachable code detected + 7028, // unused label + 7029, // fall through case in switch + 7030 // not all code paths return a value +]; + +class TypeScriptServiceClientHost implements ITypeScriptServiceClientHost { private client: TypeScriptServiceClient; private languages: LanguageProvider[] = []; private languagePerId: Map; @@ -428,7 +501,8 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { constructor( descriptions: LanguageDescription[], workspaceState: Memento, - plugins: TypeScriptServerPlugin[] + plugins: TypeScriptServerPlugin[], + private commandManager: CommandManager ) { const handleProjectCreateOrDelete = () => { this.client.execute('reloadProjects', null, false); @@ -453,7 +527,7 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { this.languagePerId = new Map(); for (const description of descriptions) { - const manager = new LanguageProvider(this.client, description); + const manager = new LanguageProvider(this.client, description, this.commandManager); this.languages.push(manager); this.disposables.push(manager); this.languagePerId.set(description.id, manager); @@ -477,7 +551,7 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { diagnosticSource: 'ts-plugins', isExternal: true }; - const manager = new LanguageProvider(this.client, description); + const manager = new LanguageProvider(this.client, description, this.commandManager); this.languages.push(manager); this.disposables.push(manager); this.languagePerId.set(description.id, manager); @@ -511,10 +585,10 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { return !!this.findLanguage(file); } - public goToProjectConfig( + public async goToProjectConfig( isTypeScriptProject: boolean, resource: Uri - ): Thenable | undefined { + ): Promise { const rootPath = this.client.getWorkspaceRootForResource(resource); if (!rootPath) { window.showInformationMessage( @@ -534,49 +608,61 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { return; } - return this.client.execute('projectInfo', { file, needFileNameList: false } as protocol.ProjectInfoRequestArgs).then(res => { - if (!res || !res.body) { - return window.showWarningMessage(localize('typescript.projectConfigCouldNotGetInfo', 'Could not determine TypeScript or JavaScript project')) - .then(() => void 0); - } + let res: protocol.ProjectInfoResponse | undefined = undefined; + try { + res = await this.client.execute('projectInfo', { file, needFileNameList: false } as protocol.ProjectInfoRequestArgs); + } catch { + // noop + } + if (!res || !res.body) { + window.showWarningMessage(localize('typescript.projectConfigCouldNotGetInfo', 'Could not determine TypeScript or JavaScript project')); + return; + } - const { configFileName } = res.body; - if (configFileName && !isImplicitProjectConfigFile(configFileName)) { - return workspace.openTextDocument(configFileName) - .then(doc => - window.showTextDocument(doc, window.activeTextEditor ? window.activeTextEditor.viewColumn : undefined)); - } + const { configFileName } = res.body; + if (configFileName && !isImplicitProjectConfigFile(configFileName)) { + const doc = await workspace.openTextDocument(configFileName); + window.showTextDocument(doc, window.activeTextEditor ? window.activeTextEditor.viewColumn : undefined); + return; + } - return window.showInformationMessage( - (isTypeScriptProject - ? localize('typescript.noTypeScriptProjectConfig', 'File is not part of a TypeScript project') - : localize('typescript.noJavaScriptProjectConfig', 'File is not part of a JavaScript project') - ), { - title: isTypeScriptProject - ? localize('typescript.configureTsconfigQuickPick', 'Configure tsconfig.json') - : localize('typescript.configureJsconfigQuickPick', 'Configure jsconfig.json'), - id: ProjectConfigAction.CreateConfig - }, { - title: localize('typescript.projectConfigLearnMore', 'Learn More'), - id: ProjectConfigAction.LearnMore - }).then(selected => { - switch (selected && selected.id) { - case ProjectConfigAction.CreateConfig: - return openOrCreateConfigFile(isTypeScriptProject, rootPath); + enum ProjectConfigAction { + None, + CreateConfig, + LearnMore + } - case ProjectConfigAction.LearnMore: - if (isTypeScriptProject) { - commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=841896')); - } else { - commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=759670')); - } - return; + interface ProjectConfigMessageItem extends MessageItem { + id: ProjectConfigAction; + } - default: - return Promise.resolve(undefined); - } - }); - }); + const selected = await window.showInformationMessage( + (isTypeScriptProject + ? localize('typescript.noTypeScriptProjectConfig', 'File is not part of a TypeScript project') + : localize('typescript.noJavaScriptProjectConfig', 'File is not part of a JavaScript project') + ), { + title: isTypeScriptProject + ? localize('typescript.configureTsconfigQuickPick', 'Configure tsconfig.json') + : localize('typescript.configureJsconfigQuickPick', 'Configure jsconfig.json'), + id: ProjectConfigAction.CreateConfig + }, { + title: localize('typescript.projectConfigLearnMore', 'Learn More'), + id: ProjectConfigAction.LearnMore + }); + + switch (selected && selected.id) { + case ProjectConfigAction.CreateConfig: + openOrCreateConfigFile(isTypeScriptProject, rootPath, this.client.configuration); + return; + + case ProjectConfigAction.LearnMore: + if (isTypeScriptProject) { + commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=841896')); + } else { + commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=759670')); + } + return; + } } private findLanguage(file: string): Thenable { @@ -634,8 +720,6 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { return; } - // TODO: restore opening trigger file? - // body.triggerFile ? this.findLanguage(body.triggerFile) (this.findLanguage(body.configFile)).then(language => { if (!language) { return; @@ -684,17 +768,24 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { const result: Diagnostic[] = []; for (let diagnostic of diagnostics) { const { start, end, text } = diagnostic; - const range = new Range(start.line - 1, start.offset - 1, end.line - 1, end.offset - 1); + const range = new Range(tsLocationToVsPosition(start), tsLocationToVsPosition(end)); const converted = new Diagnostic(range, text); converted.severity = this.getDiagnosticSeverity(diagnostic); converted.source = diagnostic.source || source; - converted.code = '' + diagnostic.code; + if (diagnostic.code) { + converted.code = diagnostic.code; + } result.push(converted); } return result; } private getDiagnosticSeverity(diagnostic: Proto.Diagnostic): DiagnosticSeverity { + + if (this.reportStyleCheckAsWarnings() && this.isStyleCheckDiagnostic(diagnostic.code)) { + return DiagnosticSeverity.Warning; + } + switch (diagnostic.category) { case PConst.DiagnosticCategory.error: return DiagnosticSeverity.Error; @@ -706,4 +797,13 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { return DiagnosticSeverity.Error; } } -} + + private isStyleCheckDiagnostic(code: number | undefined): boolean { + return code ? styleCheckDiagnostics.indexOf(code) !== -1 : false; + } + + private reportStyleCheckAsWarnings() { + const config = workspace.getConfiguration('typescript'); + return config.get('reportStyleChecksAsWarnings', true); + } +} \ No newline at end of file diff --git a/extensions/typescript/src/typescriptService.ts b/extensions/typescript/src/typescriptService.ts index bf4067894ef..fbcda9c7938 100644 --- a/extensions/typescript/src/typescriptService.ts +++ b/extensions/typescript/src/typescriptService.ts @@ -8,8 +8,10 @@ import { CancellationToken, Uri, Event } from 'vscode'; import * as Proto from './protocol'; import API from './utils/api'; import { TypeScriptServerPlugin } from './utils/plugins'; +import { TypeScriptServiceConfiguration } from './utils/configuration'; +import Logger from './utils/logger'; -export interface ITypescriptServiceClientHost { +export interface ITypeScriptServiceClientHost { syntaxDiagnosticsReceived(event: Proto.DiagnosticEvent): void; semanticDiagnosticsReceived(event: Proto.DiagnosticEvent): void; configFileDiagnosticsReceived(event: Proto.ConfigFileDiagnosticEvent): void; @@ -17,25 +19,21 @@ export interface ITypescriptServiceClientHost { } -export interface ITypescriptServiceClient { +export interface ITypeScriptServiceClient { normalizePath(resource: Uri): string | null; asUrl(filepath: string): Uri; getWorkspaceRootForResource(resource: Uri): string | undefined; - warn(message: string, data?: any): void; - onTsServerStarted: Event; - onProjectLanguageServiceStateChanged: Event; onDidBeginInstallTypings: Event; onDidEndInstallTypings: Event; onTypesInstallerInitializationFailed: Event; - logTelemetry(eventName: string, properties?: { [prop: string]: string }): void; - apiVersion: API; - plugins: TypeScriptServerPlugin[]; + configuration: TypeScriptServiceConfiguration; + logger: Logger; execute(command: 'configure', args: Proto.ConfigureRequestArguments, token?: CancellationToken): Promise; execute(command: 'open', args: Proto.OpenRequestArgs, expectedResult: boolean, token?: CancellationToken): Promise; @@ -66,6 +64,7 @@ export interface ITypescriptServiceClient { execute(command: 'docCommentTemplate', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise; 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: string, args: any, expectedResult: boolean | CancellationToken, token?: CancellationToken): Promise; diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript/src/typescriptServiceClient.ts index 09cb2140286..fb4f732e7ce 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript/src/typescriptServiceClient.ts @@ -11,9 +11,9 @@ import * as os from 'os'; import * as electron from './utils/electron'; import { Reader } from './utils/wireProtocol'; -import { workspace, window, Uri, CancellationToken, Disposable, Memento, MessageItem, EventEmitter, Event, commands } from 'vscode'; +import { workspace, window, Uri, CancellationToken, Disposable, Memento, MessageItem, EventEmitter, Event, commands, env } from 'vscode'; import * as Proto from './protocol'; -import { ITypescriptServiceClient, ITypescriptServiceClientHost } from './typescriptService'; +import { ITypeScriptServiceClient, ITypeScriptServiceClientHost } from './typescriptService'; import { TypeScriptServerPlugin } from './utils/plugins'; import Logger from './utils/logger'; @@ -25,7 +25,7 @@ import API from './utils/api'; import * as nls from 'vscode-nls'; import { TypeScriptServiceConfiguration, TsServerLogLevel } from './utils/configuration'; -import { TypeScriptVersionProvider } from './utils/versionProvider'; +import { TypeScriptVersionProvider, TypeScriptVersion } from './utils/versionProvider'; import { TypeScriptVersionPicker } from './utils/versionPicker'; const localize = nls.loadMessageBundle(); @@ -36,14 +36,14 @@ interface CallbackItem { } class CallbackMap { - private callbacks: Map = new Map(); + private readonly callbacks: Map = new Map(); public pendingResponses: number = 0; public destroy(e: any): void { for (const callback of this.callbacks.values()) { callback.e(e); } - this.callbacks = new Map(); + this.callbacks.clear(); this.pendingResponses = 0; } @@ -71,15 +71,6 @@ interface RequestItem { callbacks: CallbackItem | null; } - -enum MessageAction { - reportIssue -} - -interface MyMessageItem extends MessageItem { - id: MessageAction; -} - class RequestQueue { private queue: RequestItem[] = []; private sequenceNumber: number = 0; @@ -116,25 +107,22 @@ class RequestQueue { } } - -export default class TypeScriptServiceClient implements ITypescriptServiceClient { +export default class TypeScriptServiceClient implements ITypeScriptServiceClient { private static readonly WALK_THROUGH_SNIPPET_SCHEME = 'walkThroughSnippet'; private static readonly WALK_THROUGH_SNIPPET_SCHEME_COLON = `${TypeScriptServiceClient.WALK_THROUGH_SNIPPET_SCHEME}:`; private pathSeparator: string; private _onReady: { promise: Promise; resolve: () => void; reject: () => void; }; - private configuration: TypeScriptServiceConfiguration; + private _configuration: TypeScriptServiceConfiguration; private versionProvider: TypeScriptVersionProvider; private versionPicker: TypeScriptVersionPicker; private tracer: Tracer; - private readonly logger: Logger = new Logger(); + public readonly logger: Logger = new Logger(); private tsServerLogFile: string | null = null; private servicePromise: Thenable | null; private lastError: Error | null; - private reader: Reader; - private firstStart: number; private lastStart: number; private numberRestarts: number; private isRestarting: boolean = false; @@ -150,13 +138,20 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient private readonly _onDidEndInstallTypings = new EventEmitter(); private readonly _onTypesInstallerInitializationFailed = new EventEmitter(); + public readonly telemetryReporter: TelemetryReporter; + /** + * API version obtained from the version picker after checking the corresponding path exists. + */ private _apiVersion: API; - private telemetryReporter: TelemetryReporter; + /** + * Version reported by currently-running tsserver. + */ + private _tsserverVersion: string | undefined; private readonly disposables: Disposable[] = []; constructor( - private readonly host: ITypescriptServiceClientHost, + private readonly host: ITypeScriptServiceClientHost, private readonly workspaceState: Memento, private readonly versionStatus: VersionStatus, public readonly plugins: TypeScriptServerPlugin[] @@ -171,40 +166,46 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this.servicePromise = null; this.lastError = null; - this.firstStart = Date.now(); this.numberRestarts = 0; this.requestQueue = new RequestQueue(); this.callbacks = new CallbackMap(); - this.configuration = TypeScriptServiceConfiguration.loadFromWorkspace(); - this.versionProvider = new TypeScriptVersionProvider(this.configuration); + this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace(); + this.versionProvider = new TypeScriptVersionProvider(this._configuration); this.versionPicker = new TypeScriptVersionPicker(this.versionProvider, this.workspaceState); this._apiVersion = API.defaultVersion; + this._tsserverVersion = undefined; this.tracer = new Tracer(this.logger); workspace.onDidChangeConfiguration(() => { - const oldConfiguration = this.configuration; - this.configuration = TypeScriptServiceConfiguration.loadFromWorkspace(); + const oldConfiguration = this._configuration; + this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace(); - this.versionProvider.updateConfiguration(this.configuration); + this.versionProvider.updateConfiguration(this._configuration); this.tracer.updateConfiguration(); if (this.servicePromise) { - if (this.configuration.checkJs !== oldConfiguration.checkJs) { - this.setCompilerOptionsForInferredProjects(); + if (this._configuration.checkJs !== oldConfiguration.checkJs + || this._configuration.experimentalDecorators !== oldConfiguration.experimentalDecorators + ) { + this.setCompilerOptionsForInferredProjects(this._configuration); } - if (!this.configuration.isEqualTo(oldConfiguration)) { + if (!this._configuration.isEqualTo(oldConfiguration)) { this.restartTsServer(); } } }, this, this.disposables); - this.telemetryReporter = new TelemetryReporter(); + this.telemetryReporter = new TelemetryReporter(() => this._tsserverVersion || this._apiVersion.versionString); this.disposables.push(this.telemetryReporter); this.startService(); } + public get configuration() { + return this._configuration; + } + public dispose() { if (this.servicePromise) { this.servicePromise.then(cp => { @@ -231,8 +232,10 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient if (this.servicePromise) { this.servicePromise = this.servicePromise.then(cp => { if (cp) { + this.info('Killing TS Server'); this.isRestarting = true; cp.kill(); + this.resetClientVersion(); } }).then(start); } else { @@ -311,11 +314,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient } this._apiVersion = this.versionPicker.currentVersion.version || API.defaultVersion; - - const label = this._apiVersion.versionString; - const tooltip = currentVersion.path; - this.versionStatus.showHideStatus(); - this.versionStatus.setInfo(label, tooltip); + this.versionStatus.onDidChangeTypeScriptVersion(currentVersion); this.requestQueue = new RequestQueue(); this.callbacks = new CallbackMap(); @@ -325,85 +324,47 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient const options: electron.IForkOptions = { execArgv: [] // [`--debug-brk=5859`] }; - if (this.mainWorkspaceRootPath) { - options.cwd = this.mainWorkspaceRootPath; - } - const args: string[] = []; - if (this.apiVersion.has206Features()) { - if (this.apiVersion.has250Features()) { - args.push('--useInferredProjectPerProjectRoot'); - } else { - args.push('--useSingleInferredProject'); - } - - if (this.configuration.disableAutomaticTypeAcquisition) { - args.push('--disableAutomaticTypingAcquisition'); - } - } - if (this.apiVersion.has208Features()) { - args.push('--enableTelemetry'); - } - if (this.apiVersion.has222Features()) { - this.cancellationPipeName = electron.getTempFile(`tscancellation-${electron.makeRandomHexString(20)}`); - args.push('--cancellationPipeName', this.cancellationPipeName + '*'); - } - - if (this.apiVersion.has222Features()) { - if (this.configuration.tsServerLogLevel !== TsServerLogLevel.Off) { - try { - const logDir = fs.mkdtempSync(path.join(os.tmpdir(), `vscode-tsserver-log-`)); - this.tsServerLogFile = path.join(logDir, `tsserver.log`); - this.info(`TSServer log file: ${this.tsServerLogFile}`); - } catch (e) { - this.error('Could not create TSServer log directory'); - } - - if (this.tsServerLogFile) { - args.push('--logVerbosity', TsServerLogLevel.toString(this.configuration.tsServerLogLevel)); - args.push('--logFile', this.tsServerLogFile); - } - } - } - - if (this.apiVersion.has230Features()) { - 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(',')); - } - } - } - - if (this.apiVersion.has234Features()) { - if (this.configuration.npmLocation) { - args.push('--npmLocation', `"${this.configuration.npmLocation}"`); - } - } - - electron.fork(currentVersion.tsServerPath, args, options, this.logger, (err: any, childProcess: cp.ChildProcess) => { - if (err) { + electron.fork(currentVersion.tsServerPath, this.getTsServerArgs(currentVersion), options, this.logger, (err: any, childProcess: cp.ChildProcess | null) => { + if (err || !childProcess) { this.lastError = err; this.error('Starting TSServer failed with error.', err); window.showErrorMessage(localize('serverCouldNotBeStarted', 'TypeScript language server couldn\'t be started. Error message is: {0}', err.message || err)); + /* __GDPR__ + "error" : { + "message": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" } + } + */ this.logTelemetry('error', { message: err.message }); + this.resetClientVersion(); return; } + + this.info('Started TSServer'); this.lastStart = Date.now(); + childProcess.on('error', (err: Error) => { this.lastError = err; this.error('TSServer errored with error.', err); if (this.tsServerLogFile) { this.error(`TSServer log file: ${this.tsServerLogFile}`); } + /* __GDPR__ + "tsserver.error" : {} + */ this.logTelemetry('tsserver.error'); this.serviceExited(false); }); childProcess.on('exit', (code: any) => { if (code === null || typeof code === 'undefined') { - this.info(`TSServer exited`); + this.info('TSServer exited'); } else { this.error(`TSServer exited with code: ${code}`); + /* __GDPR__ + "tsserver.exitWithCode" : { + "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ this.logTelemetry('tsserver.exitWithCode', { code: code }); } @@ -414,7 +375,8 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this.isRestarting = false; }); - this.reader = new Reader( + // tslint:disable-next-line:no-unused-expression + new Reader( childProcess.stdout, (msg) => { this.dispatchMessage(msg); }, error => { this.error('ReaderError', error); }); @@ -444,17 +406,17 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient }); } - public openTsServerLogFile(): Thenable { + public async openTsServerLogFile(): Promise { if (!this.apiVersion.has222Features()) { - return window.showErrorMessage( + window.showErrorMessage( localize( 'typescript.openTsServerLog.notSupported', - 'TS Server logging requires TS 2.2.2+')) - .then(() => false); + 'TS Server logging requires TS 2.2.2+')); + return false; } - if (this.configuration.tsServerLogLevel === TsServerLogLevel.Off) { - return window.showErrorMessage( + if (this._configuration.tsServerLogLevel === TsServerLogLevel.Off) { + window.showErrorMessage( localize( 'typescript.openTsServerLog.loggingNotEnabled', 'TS Server logging is off. Please set `typescript.tsserver.log` and restart the TS server to enable logging'), @@ -467,26 +429,29 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient if (selection) { return workspace.getConfiguration().update('typescript.tsserver.log', 'verbose', true).then(() => { this.restartTsServer(); - return false; }); } - return false; + return undefined; }); + return false; } if (!this.tsServerLogFile) { - return window.showWarningMessage(localize( + window.showWarningMessage(localize( 'typescript.openTsServerLog.noLogFile', - 'TS Server has not started logging.')).then(() => false); + 'TS Server has not started logging.')); + return false; } - return commands.executeCommand('_workbench.action.files.revealInOS', Uri.parse(this.tsServerLogFile)) - .then(() => true, () => { - window.showWarningMessage(localize( - 'openTsServerLog.openFileFailedFailed', - 'Could not open TS Server log file')); - return false; - }); + try { + await commands.executeCommand('_workbench.action.files.revealInOS', Uri.parse(this.tsServerLogFile)); + return true; + } catch { + window.showWarningMessage(localize( + 'openTsServerLog.openFileFailedFailed', + 'Could not open TS Server log file')); + return false; + } } private serviceStarted(resendModels: boolean): void { @@ -494,17 +459,24 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient hostInfo: 'vscode' }; this.execute('configure', configureOptions); - this.setCompilerOptionsForInferredProjects(); + this.setCompilerOptionsForInferredProjects(this._configuration); if (resendModels) { this.host.populateService(); } } - private setCompilerOptionsForInferredProjects(): void { + private setCompilerOptionsForInferredProjects(configuration: TypeScriptServiceConfiguration): void { if (!this.apiVersion.has206Features()) { return; } + const args: Proto.SetCompilerOptionsForInferredProjectsArgs = { + options: this.getCompilerOptionsForInferredProjects(configuration) + }; + this.execute('compilerOptionsForInferredProjects', args, true); + } + + private getCompilerOptionsForInferredProjects(configuration: TypeScriptServiceConfiguration): Proto.ExternalProjectCompilerOptions { const compilerOptions: Proto.ExternalProjectCompilerOptions = { module: 'CommonJS' as Proto.ModuleKind, target: 'ES6' as Proto.ScriptTarget, @@ -515,23 +487,29 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient }; if (this.apiVersion.has230Features()) { - compilerOptions.checkJs = workspace.getConfiguration('javascript').get('implicitProjectConfig.checkJs', false); + compilerOptions.checkJs = configuration.checkJs; + compilerOptions.experimentalDecorators = configuration.experimentalDecorators; } - - const args: Proto.SetCompilerOptionsForInferredProjectsArgs = { - options: compilerOptions - }; - this.execute('compilerOptionsForInferredProjects', args, true).catch((err) => { - this.error(`'compilerOptionsForInferredProjects' request failed with error.`, err); - }); + return compilerOptions; } private serviceExited(restart: boolean): void { + enum MessageAction { + reportIssue + } + + interface MyMessageItem extends MessageItem { + id: MessageAction; + } + this.servicePromise = null; this.tsServerLogFile = null; this.callbacks.destroy(new Error('Service died.')); this.callbacks = new CallbackMap(); - if (restart) { + if (!restart) { + this.resetClientVersion(); + } + else { const diff = Date.now() - this.lastStart; this.numberRestarts++; let startService = true; @@ -548,7 +526,11 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient id: MessageAction.reportIssue, isCloseAffordance: true }); + /* __GDPR__ + "serviceExited" : {} + */ this.logTelemetry('serviceExited'); + this.resetClientVersion(); } else if (diff < 60 * 1000 /* 1 Minutes */) { this.lastStart = Date.now(); prompt = window.showWarningMessage( @@ -586,7 +568,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient if (resource.scheme !== 'file') { return null; } - let result = resource.fsPath; + const result = resource.fsPath; if (!result) { return null; } @@ -603,14 +585,6 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient return Uri.file(filepath); } - private get mainWorkspaceRootPath(): string | undefined { - if (workspace.workspaceFolders && workspace.workspaceFolders.length) { - return workspace.workspaceFolders[0].uri.fsPath; - } - - return undefined; - } - public getWorkspaceRootForResource(resource: Uri): string | undefined { const roots = workspace.workspaceFolders; if (!roots || !roots.length) { @@ -656,6 +630,8 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient }).catch((err: any) => { if (!wasCancelled) { this.error(`'${command}' request failed with error.`, err); + const properties = this.parseErrorText(err && err.message, command); + this.logTelemetry('languageServiceErrorResponse', properties); } throw err; }); @@ -667,6 +643,30 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient return result; } + /** + * Given a `errorText` from a tsserver request indicating failure in handling a request, + * prepares a payload for telemetry-logging. + */ + private parseErrorText(errorText: string | undefined, command: string) { + const properties: ObjectMap = Object.create(null); + properties['command'] = command; + if (errorText) { + properties['errorText'] = errorText; + + const errorPrefix = 'Error processing request. '; + if (errorText.startsWith(errorPrefix)) { + const prefixFreeErrorText = errorText.substr(errorPrefix.length); + const newlineIndex = prefixFreeErrorText.indexOf('\n'); + if (newlineIndex >= 0) { + // Newline expected between message and stack. + properties['message'] = prefixFreeErrorText.substring(0, newlineIndex); + properties['stack'] = prefixFreeErrorText.substring(newlineIndex + 1); + } + } + } + return properties; + } + private sendNextRequests(): void { while (this.callbacks.pendingResponses === 0 && this.requestQueue.length > 0) { const item = this.requestQueue.shift(); @@ -705,7 +705,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this.tracer.logTrace(`TypeScript Service: trying to cancel ongoing request with sequence number ${seq}`); try { fs.writeFileSync(this.cancellationPipeName + seq, ''); - } catch (e) { + } catch { // noop } return true; @@ -747,35 +747,47 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient } private dispatchEvent(event: Proto.Event) { - if (event.event === 'syntaxDiag') { - this.host.syntaxDiagnosticsReceived(event as Proto.DiagnosticEvent); - } else if (event.event === 'semanticDiag') { - this.host.semanticDiagnosticsReceived(event as Proto.DiagnosticEvent); - } else if (event.event === 'configFileDiag') { - this.host.configFileDiagnosticsReceived(event as Proto.ConfigFileDiagnosticEvent); - } else if (event.event === 'telemetry') { - const telemetryData = (event as Proto.TelemetryEvent).body; - this.dispatchTelemetryEvent(telemetryData); - } else if (event.event === 'projectLanguageServiceState') { - const data = (event as Proto.ProjectLanguageServiceStateEvent).body; - if (data) { - this._onProjectLanguageServiceStateChanged.fire(data); - } - } else if (event.event === 'beginInstallTypes') { - const data = (event as Proto.BeginInstallTypesEvent).body; - if (data) { - this._onDidBeginInstallTypings.fire(data); - } - } else if (event.event === 'endInstallTypes') { - const data = (event as Proto.EndInstallTypesEvent).body; - if (data) { - this._onDidEndInstallTypings.fire(data); - } - } else if (event.event === 'typesInstallerInitializationFailed') { - const data = (event as Proto.TypesInstallerInitializationFailedEvent).body; - if (data) { - this._onTypesInstallerInitializationFailed.fire(data); - } + switch (event.event) { + case 'syntaxDiag': + this.host.syntaxDiagnosticsReceived(event as Proto.DiagnosticEvent); + break; + + case 'semanticDiag': + this.host.semanticDiagnosticsReceived(event as Proto.DiagnosticEvent); + break; + + case 'configFileDiag': + this.host.configFileDiagnosticsReceived(event as Proto.ConfigFileDiagnosticEvent); + break; + + case 'telemetry': + const telemetryData = (event as Proto.TelemetryEvent).body; + this.dispatchTelemetryEvent(telemetryData); + break; + + case 'projectLanguageServiceState': + if (event.body) { + this._onProjectLanguageServiceStateChanged.fire((event as Proto.ProjectLanguageServiceStateEvent).body); + } + break; + + case 'beginInstallTypes': + if (event.body) { + this._onDidBeginInstallTypings.fire((event as Proto.BeginInstallTypesEvent).body); + } + break; + + case 'endInstallTypes': + if (event.body) { + this._onDidEndInstallTypings.fire((event as Proto.EndInstallTypesEvent).body); + } + break; + + case 'typesInstallerInitializationFailed': + if (event.body) { + this._onTypesInstallerInitializationFailed.fire((event as Proto.TypesInstallerInitializationFailedEvent).body); + } + break; } } @@ -809,6 +821,94 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient } break; } + if (telemetryData.telemetryEventName === 'projectInfo') { + this._tsserverVersion = properties['version']; + } + + /* __GDPR__ + "typingsInstalled" : { + "installedPackages" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "installSuccess": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "typingsInstallerVersion": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ + // __GDPR__COMMENT__: Other events are defined by TypeScript. this.logTelemetry(telemetryData.telemetryEventName, properties); } + + private getTsServerArgs(currentVersion: TypeScriptVersion): string[] { + const args: string[] = []; + + if (this.apiVersion.has206Features()) { + if (this.apiVersion.has250Features()) { + args.push('--useInferredProjectPerProjectRoot'); + } else { + args.push('--useSingleInferredProject'); + } + + if (this._configuration.disableAutomaticTypeAcquisition) { + args.push('--disableAutomaticTypingAcquisition'); + } + } + + if (this.apiVersion.has208Features()) { + args.push('--enableTelemetry'); + } + + if (this.apiVersion.has222Features()) { + this.cancellationPipeName = electron.getTempFile(`tscancellation-${electron.makeRandomHexString(20)}`); + args.push('--cancellationPipeName', this.cancellationPipeName + '*'); + } + + if (this.apiVersion.has222Features()) { + if (this._configuration.tsServerLogLevel !== TsServerLogLevel.Off) { + try { + const logDir = fs.mkdtempSync(path.join(os.tmpdir(), `vscode-tsserver-log-`)); + this.tsServerLogFile = path.join(logDir, `tsserver.log`); + this.info(`TSServer log file: ${this.tsServerLogFile}`); + } catch (e) { + this.error('Could not create TSServer log directory'); + } + + if (this.tsServerLogFile) { + args.push('--logVerbosity', TsServerLogLevel.toString(this._configuration.tsServerLogLevel)); + args.push('--logFile', this.tsServerLogFile); + } + } + } + + if (this.apiVersion.has230Features()) { + 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(',')); + } + } + } + + if (this.apiVersion.has234Features()) { + if (this._configuration.npmLocation) { + args.push('--npmLocation', `"${this._configuration.npmLocation}"`); + } + } + + if (this.apiVersion.has260Features()) { + const tsLocale = getTsLocale(this._configuration); + if (tsLocale) { + args.push('--locale', tsLocale); + } + } + return args; + } + + private resetClientVersion() { + this._apiVersion = API.defaultVersion; + this._tsserverVersion = undefined; + } } + + +const getTsLocale = (configuration: TypeScriptServiceConfiguration): string | undefined => + (configuration.locale + ? configuration.locale + : env.language); \ No newline at end of file diff --git a/extensions/typescript/src/utils/api.ts b/extensions/typescript/src/utils/api.ts index 91888a52f58..51a630b83a0 100644 --- a/extensions/typescript/src/utils/api.ts +++ b/extensions/typescript/src/utils/api.ts @@ -16,7 +16,7 @@ export default class API { return new API(localize('invalidVersion', 'invalid version'), '1.0.0'); } - // Cut of any prerelease tag since we sometimes consume those on purpose. + // Cut off any prerelease tag since we sometimes consume those on purpose. const index = versionString.indexOf('-'); if (index >= 0) { version = version.substr(0, index); @@ -29,7 +29,6 @@ export default class API { private readonly version: string ) { } - public has203Features(): boolean { return semver.gte(this.version, '2.0.3'); } @@ -69,4 +68,8 @@ export default class API { public has250Features(): boolean { return semver.gte(this.version, '2.5.0'); } + + public has260Features(): boolean { + return semver.gte(this.version, '2.6.0'); + } } \ No newline at end of file diff --git a/extensions/typescript/src/utils/async.ts b/extensions/typescript/src/utils/async.ts index f87754e69e8..db4ca99ed8f 100644 --- a/extensions/typescript/src/utils/async.ts +++ b/extensions/typescript/src/utils/async.ts @@ -53,27 +53,6 @@ export class Delayer { return this.completionPromise; } - public forceDelivery(): Promise | null { - if (!this.completionPromise) { - return null; - } - this.cancelTimeout(); - let result = this.completionPromise; - if (this.onSuccess) { - this.onSuccess(undefined); - } - return result; - } - - public isTriggered(): boolean { - return this.timeout !== null; - } - - public cancel(): void { - this.cancelTimeout(); - this.completionPromise = null; - } - private cancelTimeout(): void { if (this.timeout !== null) { clearTimeout(this.timeout); diff --git a/extensions/typescript/src/utils/codeAction.ts b/extensions/typescript/src/utils/codeAction.ts new file mode 100644 index 00000000000..5432a89e509 --- /dev/null +++ b/extensions/typescript/src/utils/codeAction.ts @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { WorkspaceEdit, workspace } from 'vscode'; +import * as Proto from '../protocol'; +import { tsTextSpanToVsRange } from './convert'; +import { ITypeScriptServiceClient } from '../typescriptService'; + + +export async function applyCodeAction( + client: ITypeScriptServiceClient, + action: Proto.CodeAction, + file: string +): Promise { + if (action.changes && action.changes.length) { + const workspaceEdit = new WorkspaceEdit(); + for (const change of action.changes) { + for (const textChange of change.textChanges) { + workspaceEdit.replace(client.asUrl(change.fileName), + tsTextSpanToVsRange(textChange), + textChange.newText); + } + } + + if (!(await workspace.applyEdit(workspaceEdit))) { + return false; + } + } + + if (action.commands && action.commands.length) { + for (const command of action.commands) { + const response = await client.execute('applyCodeActionCommand', { file, command }); + if (!response || !response.body) { + return false; + } + } + } + return true; +} \ No newline at end of file diff --git a/extensions/typescript/src/utils/commandManager.ts b/extensions/typescript/src/utils/commandManager.ts new file mode 100644 index 00000000000..4f3e6a8f3d3 --- /dev/null +++ b/extensions/typescript/src/utils/commandManager.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +export interface Command { + readonly id: string; + + execute(...args: any[]): void; +} + +export class CommandManager { + private readonly commands = new Map(); + + public dispose() { + for (const registration of this.commands.values()) { + registration.dispose(); + } + this.commands.clear(); + } + + private registerCommand(id: string, impl: (...args: any[]) => void, thisArg?: any) { + if (this.commands.has(id)) { + return; + } + + this.commands.set(id, vscode.commands.registerCommand(id, impl, thisArg)); + } + + public register(command: T): T { + this.registerCommand(command.id, command.execute, command); + return command; + } +} \ No newline at end of file diff --git a/extensions/typescript/src/utils/configuration.ts b/extensions/typescript/src/utils/configuration.ts index 4a759024dd5..4976a3ec26a 100644 --- a/extensions/typescript/src/utils/configuration.ts +++ b/extensions/typescript/src/utils/configuration.ts @@ -42,11 +42,13 @@ export namespace TsServerLogLevel { } export class TypeScriptServiceConfiguration { + public readonly locale: string | null; public readonly globalTsdk: string | null; public readonly localTsdk: string | null; public readonly npmLocation: string | null; public readonly tsServerLogLevel: TsServerLogLevel = TsServerLogLevel.Off; public readonly checkJs: boolean; + public readonly experimentalDecorators: boolean; public readonly disableAutomaticTypeAcquisition: boolean; public static loadFromWorkspace(): TypeScriptServiceConfiguration { @@ -56,20 +58,24 @@ export class TypeScriptServiceConfiguration { private constructor() { const configuration = workspace.getConfiguration(); + this.locale = TypeScriptServiceConfiguration.extractLocale(configuration); this.globalTsdk = TypeScriptServiceConfiguration.extractGlobalTsdk(configuration); this.localTsdk = TypeScriptServiceConfiguration.extractLocalTsdk(configuration); this.npmLocation = TypeScriptServiceConfiguration.readNpmLocation(configuration); this.tsServerLogLevel = TypeScriptServiceConfiguration.readTsServerLogLevel(configuration); this.checkJs = TypeScriptServiceConfiguration.readCheckJs(configuration); + this.experimentalDecorators = TypeScriptServiceConfiguration.readExperimentalDecorators(configuration); this.disableAutomaticTypeAcquisition = TypeScriptServiceConfiguration.readDisableAutomaticTypeAcquisition(configuration); } public isEqualTo(other: TypeScriptServiceConfiguration): boolean { - return this.globalTsdk === other.globalTsdk + return this.locale === other.locale + && this.globalTsdk === other.globalTsdk && this.localTsdk === other.localTsdk && this.npmLocation === other.npmLocation && this.tsServerLogLevel === other.tsServerLogLevel && this.checkJs === other.checkJs + && this.experimentalDecorators === other.experimentalDecorators && this.disableAutomaticTypeAcquisition === other.disableAutomaticTypeAcquisition; } @@ -98,6 +104,10 @@ export class TypeScriptServiceConfiguration { return configuration.get('javascript.implicitProjectConfig.checkJs', false); } + private static readExperimentalDecorators(configuration: WorkspaceConfiguration): boolean { + return configuration.get('javascript.implicitProjectConfig.experimentalDecorators', false); + } + private static readNpmLocation(configuration: WorkspaceConfiguration): string | null { return configuration.get('typescript.npm', null); } @@ -105,4 +115,8 @@ export class TypeScriptServiceConfiguration { private static readDisableAutomaticTypeAcquisition(configuration: WorkspaceConfiguration): boolean { return configuration.get('typescript.disableAutomaticTypeAcquisition', false); } + + private static extractLocale(configuration: WorkspaceConfiguration): string | null { + return configuration.get('typescript.locale', null); + } } diff --git a/extensions/typescript/src/utils/convert.ts b/extensions/typescript/src/utils/convert.ts new file mode 100644 index 00000000000..299597f34d5 --- /dev/null +++ b/extensions/typescript/src/utils/convert.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * 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/electron.ts b/extensions/typescript/src/utils/electron.ts index 10961a57b93..527046465aa 100644 --- a/extensions/typescript/src/utils/electron.ts +++ b/extensions/typescript/src/utils/electron.ts @@ -94,6 +94,7 @@ export function fork( const newEnv = generatePatchedEnv(process.env, stdInPipeName, stdOutPipeName, stdErrPipeName); + newEnv['NODE_PATH'] = path.join(modulePath, '..', '..', '..'); let childProcess: cp.ChildProcess; // Begin listening to stderr pipe diff --git a/extensions/typescript/src/utils/languageModeIds.ts b/extensions/typescript/src/utils/languageModeIds.ts new file mode 100644 index 00000000000..f69fd1295df --- /dev/null +++ b/extensions/typescript/src/utils/languageModeIds.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const typescript = 'typescript'; +export const typescriptreact = 'typescriptreact'; +export const javascript = 'javascript'; +export const javascriptreact = 'javascriptreact'; \ No newline at end of file diff --git a/extensions/typescript/src/utils/projectStatus.ts b/extensions/typescript/src/utils/projectStatus.ts index ec6cb67c2b5..bb2da195465 100644 --- a/extensions/typescript/src/utils/projectStatus.ts +++ b/extensions/typescript/src/utils/projectStatus.ts @@ -4,13 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; import { loadMessageBundle } from 'vscode-nls'; import { dirname } from 'path'; import { openOrCreateConfigFile, isImplicitProjectConfigFile } from './tsconfig'; +import * as languageModeIds from '../utils/languageModeIds'; +import TelemetryReporter from './telemetry'; const localize = loadMessageBundle(); -const selector = ['javascript', 'javascriptreact']; +const selector = [languageModeIds.javascript, languageModeIds.javascriptreact]; interface Hint { @@ -26,11 +28,11 @@ const fileLimit = 500; class ExcludeHintItem { public configFileName?: string; private _item: vscode.StatusBarItem; - private _client: ITypescriptServiceClient; private _currentHint: Hint; - constructor(client: ITypescriptServiceClient) { - this._client = client; + constructor( + private readonly telemetryReporter: TelemetryReporter + ) { this._item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, Number.MIN_VALUE); this._item.command = 'js.projectStatus.command'; } @@ -54,11 +56,14 @@ class ExcludeHintItem { this._item.tooltip = localize('hintExclude.tooltip', "To enable project-wide JavaScript/TypeScript language features, exclude large folders with source files that you do not work on."); this._item.color = '#A5DF3B'; this._item.show(); - this._client.logTelemetry('js.hintProjectExcludes'); + /* __GDPR__ + "js.hintProjectExcludes" : {} + */ + this.telemetryReporter.logTelemetry('js.hintProjectExcludes'); } } -function createLargeProjectMonitorForProject(item: ExcludeHintItem, client: ITypescriptServiceClient, isOpen: (path: string) => Promise, memento: vscode.Memento): vscode.Disposable[] { +function createLargeProjectMonitorForProject(item: ExcludeHintItem, client: ITypeScriptServiceClient, isOpen: (path: string) => Promise, memento: vscode.Memento): vscode.Disposable[] { const toDispose: vscode.Disposable[] = []; const projectHinted: ProjectHintedMap = Object.create(null); @@ -107,7 +112,7 @@ function createLargeProjectMonitorForProject(item: ExcludeHintItem, client: ITyp } }); }).catch(err => { - client.warn(err); + client.logger.warn(err); }); } @@ -121,7 +126,7 @@ function createLargeProjectMonitorForProject(item: ExcludeHintItem, client: ITyp return toDispose; } -function createLargeProjectMonitorFromTypeScript(item: ExcludeHintItem, client: ITypescriptServiceClient): vscode.Disposable { +function createLargeProjectMonitorFromTypeScript(item: ExcludeHintItem, client: ITypeScriptServiceClient): vscode.Disposable { interface LargeProjectMessageItem extends vscode.MessageItem { index: number; @@ -149,7 +154,10 @@ function createLargeProjectMonitorFromTypeScript(item: ExcludeHintItem, client: }); } -function onConfigureExcludesSelected(client: ITypescriptServiceClient, configFileName: string) { +function onConfigureExcludesSelected( + client: ITypeScriptServiceClient, + configFileName: string +) { if (!isImplicitProjectConfigFile(configFileName)) { vscode.workspace.openTextDocument(configFileName) .then(vscode.window.showTextDocument); @@ -158,15 +166,21 @@ function onConfigureExcludesSelected(client: ITypescriptServiceClient, configFil if (root) { openOrCreateConfigFile( configFileName.match(/tsconfig\.?.*\.json/) !== null, - root); + root, + client.configuration); } } } -export function create(client: ITypescriptServiceClient, isOpen: (path: string) => Promise, memento: vscode.Memento) { +export function create( + client: ITypeScriptServiceClient, + telemetryReporter: TelemetryReporter, + isOpen: (path: string) => Promise, + memento: vscode.Memento +) { const toDispose: vscode.Disposable[] = []; - const item = new ExcludeHintItem(client); + const item = new ExcludeHintItem(telemetryReporter); toDispose.push(vscode.commands.registerCommand('js.projectStatus.command', () => { if (item.configFileName) { onConfigureExcludesSelected(client, item.configFileName); diff --git a/extensions/typescript/src/utils/telemetry.ts b/extensions/typescript/src/utils/telemetry.ts index b687b11b4ac..b0cba1133a5 100644 --- a/extensions/typescript/src/utils/telemetry.ts +++ b/extensions/typescript/src/utils/telemetry.ts @@ -5,8 +5,6 @@ import * as path from 'path'; import VsCodeTelemetryReporter from 'vscode-extension-telemetry'; -import { Disposable } from 'vscode'; - interface IPackageInfo { name: string; @@ -14,16 +12,10 @@ interface IPackageInfo { aiKey: string; } - -export default class TelemetryReporter extends Disposable { +export default class TelemetryReporter { private _packageInfo: IPackageInfo | null; - private _reporter: VsCodeTelemetryReporter | null; - constructor() { - super(() => this.dispose()); - } - dispose() { if (this._reporter) { this._reporter.dispose(); @@ -31,8 +23,17 @@ export default class TelemetryReporter extends Disposable { } } + constructor( + private readonly clientVersionDelegate: () => string + ) { } + public logTelemetry(eventName: string, properties?: { [prop: string]: string }) { if (this.reporter) { + if (!properties) { + properties = {}; + } + properties['version'] = this.clientVersionDelegate(); + this.reporter.sendTelemetryEvent(eventName, properties); } } @@ -57,8 +58,8 @@ export default class TelemetryReporter extends Disposable { if (this._packageInfo !== undefined) { return this._packageInfo; } - let packagePath = path.join(__dirname, '..', '..', 'package.json'); - let extensionPackage = require(packagePath); + const packagePath = path.join(__dirname, '..', '..', 'package.json'); + const extensionPackage = require(packagePath); if (extensionPackage) { this._packageInfo = { name: extensionPackage.name, diff --git a/extensions/typescript/src/utils/tsconfig.ts b/extensions/typescript/src/utils/tsconfig.ts index 2cdd311ace4..a495afc5590 100644 --- a/extensions/typescript/src/utils/tsconfig.ts +++ b/extensions/typescript/src/utils/tsconfig.ts @@ -5,29 +5,53 @@ import * as vscode from 'vscode'; import * as path from 'path'; +import { TypeScriptServiceConfiguration } from './configuration'; export function isImplicitProjectConfigFile(configFileName: string) { return configFileName.indexOf('/dev/null/') === 0; } -export function openOrCreateConfigFile( +function getEmptyConfig( isTypeScriptProject: boolean, - rootPath: string -): Thenable { + config: TypeScriptServiceConfiguration +) { + const compilerOptions = [ + '"target": "ES6"', + '"module": "commonjs"' + ]; + if (!isTypeScriptProject && config.checkJs) { + compilerOptions.push('"checkJs": true'); + } + if (!isTypeScriptProject && config.experimentalDecorators) { + compilerOptions.push('"experimentalDecorators": true'); + } + return new vscode.SnippetString(`{ + "compilerOptions": { + ${compilerOptions.join(',\n\t\t')}$0 + }, + "exclude": [ + "node_modules", + "**/node_modules/*" + ] +}`); +} + +export async function openOrCreateConfigFile( + isTypeScriptProject: boolean, + rootPath: string, + config: TypeScriptServiceConfiguration +): Promise { const configFile = vscode.Uri.file(path.join(rootPath, isTypeScriptProject ? 'tsconfig.json' : 'jsconfig.json')); const col = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; - return vscode.workspace.openTextDocument(configFile) - .then(doc => { - return vscode.window.showTextDocument(doc, col); - }, _ => { - return vscode.workspace.openTextDocument(configFile.with({ scheme: 'untitled' })) - .then(doc => vscode.window.showTextDocument(doc, col)) - .then(editor => { - if (editor.document.getText().length === 0) { - return editor.insertSnippet(new vscode.SnippetString('{\n\t$0\n}')) - .then(_ => editor); - } - return editor; - }); - }); + try { + const doc = await vscode.workspace.openTextDocument(configFile); + return vscode.window.showTextDocument(doc, col); + } catch { + const doc = await vscode.workspace.openTextDocument(configFile.with({ scheme: 'untitled' })); + const editor = await vscode.window.showTextDocument(doc, col); + if (editor.document.getText().length === 0) { + await editor.insertSnippet(getEmptyConfig(isTypeScriptProject, config)); + } + return editor; + } } \ No newline at end of file diff --git a/extensions/typescript/src/utils/typingsStatus.ts b/extensions/typescript/src/utils/typingsStatus.ts index 33c4a85c7d6..4f014e02287 100644 --- a/extensions/typescript/src/utils/typingsStatus.ts +++ b/extensions/typescript/src/utils/typingsStatus.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { MessageItem, workspace, Disposable, ProgressLocation, window, commands, Uri } from 'vscode'; -import { ITypescriptServiceClient } from '../typescriptService'; +import { ITypeScriptServiceClient } from '../typescriptService'; import { loadMessageBundle } from 'vscode-nls'; const localize = loadMessageBundle(); @@ -13,10 +13,10 @@ const typingsInstallTimeout = 30 * 1000; export default class TypingsStatus extends Disposable { private _acquiringTypings: { [eventId: string]: NodeJS.Timer } = Object.create({}); - private _client: ITypescriptServiceClient; + private _client: ITypeScriptServiceClient; private _subscriptions: Disposable[] = []; - constructor(client: ITypescriptServiceClient) { + constructor(client: ITypeScriptServiceClient) { super(() => this.dispose()); this._client = client; @@ -62,7 +62,7 @@ export class AtaProgressReporter { private _promises = new Map(); private _disposable: Disposable; - constructor(client: ITypescriptServiceClient) { + constructor(client: ITypeScriptServiceClient) { this._disposable = Disposable.from( client.onDidBeginInstallTypings(e => this._onBegin(e.eventId)), client.onDidEndInstallTypings(e => this._onEndOrTimeout(e.eventId)), @@ -110,12 +110,10 @@ export class AtaProgressReporter { ), { title: localize('typesInstallerInitializationFailed.moreInformation', "More Information"), id: 1 - }, - { + }, { title: localize('typesInstallerInitializationFailed.doNotCheckAgain', "Don't Check Again"), id: 2 - }, - { + }, { title: localize('typesInstallerInitializationFailed.close', 'Close'), id: 3, isCloseAffordance: true diff --git a/extensions/typescript/src/utils/versionProvider.ts b/extensions/typescript/src/utils/versionProvider.ts index d1aee828261..4f3d4ed85f4 100644 --- a/extensions/typescript/src/utils/versionProvider.ts +++ b/extensions/typescript/src/utils/versionProvider.ts @@ -58,17 +58,24 @@ export class TypeScriptVersion { return undefined; } - let p = serverPath.split(path.sep); + const p = serverPath.split(path.sep); if (p.length <= 2) { return undefined; } - let p2 = p.slice(0, -2); - let modulePath = p2.join(path.sep); + const p2 = p.slice(0, -2); + const modulePath = p2.join(path.sep); let fileName = path.join(modulePath, 'package.json'); + if (!fs.existsSync(fileName)) { + // Special case for ts dev versions + if (path.basename(modulePath) === 'built') { + fileName = path.join(modulePath, '..', 'package.json'); + } + } if (!fs.existsSync(fileName)) { return undefined; } - let contents = fs.readFileSync(fileName).toString(); + + const contents = fs.readFileSync(fileName).toString(); let desc: any = null; try { desc = JSON.parse(contents); diff --git a/extensions/typescript/src/utils/versionStatus.ts b/extensions/typescript/src/utils/versionStatus.ts index 21f3a1c34f1..78b5d0167c0 100644 --- a/extensions/typescript/src/utils/versionStatus.ts +++ b/extensions/typescript/src/utils/versionStatus.ts @@ -4,17 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import { TypeScriptVersion } from './versionProvider'; +import * as languageModeIds from './languageModeIds'; - -export default class VersionStatus extends vscode.Disposable { - onChangeEditorSub: any; +export default class VersionStatus { + private onChangeEditorSub: vscode.Disposable; private versionBarEntry: vscode.StatusBarItem; constructor() { - super(() => this.dispose()); - this.versionBarEntry = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, Number.MIN_VALUE); - this.onChangeEditorSub = vscode.window.onDidChangeActiveTextEditor(this.showHideStatus, this); } @@ -23,7 +21,14 @@ export default class VersionStatus extends vscode.Disposable { this.onChangeEditorSub.dispose(); } - showHideStatus() { + public onDidChangeTypeScriptVersion(version: TypeScriptVersion) { + this.showHideStatus(); + this.versionBarEntry.text = version.versionString; + this.versionBarEntry.tooltip = version.path; + this.versionBarEntry.command = 'typescript.selectTypeScriptVersion'; + } + + private showHideStatus() { if (!this.versionBarEntry) { return; } @@ -32,8 +37,8 @@ export default class VersionStatus extends vscode.Disposable { return; } - let doc = vscode.window.activeTextEditor.document; - if (vscode.languages.match('typescript', doc) || vscode.languages.match('typescriptreact', doc)) { + const doc = vscode.window.activeTextEditor.document; + if (vscode.languages.match([languageModeIds.typescript, languageModeIds.typescriptreact], doc)) { this.versionBarEntry.show(); return; } @@ -46,10 +51,4 @@ export default class VersionStatus extends vscode.Disposable { this.versionBarEntry.hide(); } - - public setInfo(message: string, tooltip: string) { - this.versionBarEntry.text = message; - this.versionBarEntry.tooltip = tooltip; - this.versionBarEntry.command = 'typescript.selectTypeScriptVersion'; - } } diff --git a/extensions/typescript/syntaxes/Readme.md b/extensions/typescript/syntaxes/Readme.md index d45fc854245..3e1cf32a0e2 100644 --- a/extensions/typescript/syntaxes/Readme.md +++ b/extensions/typescript/syntaxes/Readme.md @@ -7,10 +7,10 @@ To update to the latest version: Migration notes and todos: - differentiate variable and function declarations from references - - I suggest we use a new scope segment 'function-call' to sigmal a function references, and 'definition' to the declaration. Alternative is to use 'support.function' everywhere. + - I suggest we use a new scope segment 'function-call' to signal a function reference, and 'definition' to the declaration. An alternative is to use 'support.function' everywhere. - I suggest we use a new scope segment 'definition' to the variable declarations. Haven't yet found a scope for references that other grammars use. - rename scope to return.type to return-type, which is already used in other grammars - rename entity.name.class to entity.name.type.class which is used in all other grammars I've seen -- do we really want to have the list of all the 'library' types (Math, Dom...). It adds a lot of size to the grammar, lots of special rules and is not really correct as it depends on the JavaScript runtime which types are present. \ No newline at end of file +- do we really want to have the list of all the 'library' types (Math, Dom...). It adds a lot of size to the grammar, lots of special rules and is not really correct as it depends on the JavaScript runtime which types are present. diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json index 96f7d0e6fed..454dc854bdf 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript/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/648a036db2bad78ee93463269ec49ed91ee5aa91", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/f3a2069b99f45c34ac5cc7dc5f1dcb4e81486ab9", "name": "TypeScript", "scopeName": "source.ts", "fileTypes": [ @@ -44,20 +44,14 @@ "include": "#declaration" }, { - "include": "#switch-statement" + "include": "#control-statement" }, { - "include": "#for-loop" - }, - { - "include": "#after-operator-block" + "include": "#after-operator-block-as-object-literal" }, { "include": "#decl-block" }, - { - "include": "#control-statement" - }, { "include": "#expression" }, @@ -66,6 +60,161 @@ } ] }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.ts", + "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts entity.name.function.ts" @@ -323,1238 +495,6 @@ } ] }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.ts" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.ts" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "expression": { - "patterns": [ - { - "include": "#string" - }, - { - "include": "#regex" - }, - { - "include": "#template" - }, - { - "include": "#comment" - }, - { - "include": "#function-expression" - }, - { - "include": "#class-expression" - }, - { - "include": "#arrow-function" - }, - { - "include": "#cast" - }, - { - "include": "#ternary-expression" - }, - { - "include": "#new-expr" - }, - { - "include": "#object-literal" - }, - { - "include": "#expression-operators" - }, - { - "include": "#function-call" - }, - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#identifiers" - }, - { - "include": "#paren-expression" - }, - { - "include": "#punctuation-comma" - }, - { - "include": "#punctuation-accessor" - } - ] - }, - "control-statement": { - "patterns": [ - { - "name": "keyword.control.trycatch.ts", - "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)" - }, - { - "name": "meta.definition.property.ts variable.object.property.ts", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.ts", - "match": "\\?" - } - ] - } - ] - }, - "method-declaration": { - "patterns": [ - { - "name": "meta.method.declaration.ts", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "captures": { "1": { "name": "storage.modifier.ts" @@ -1762,140 +702,400 @@ } ] }, - "return-type": { + "field-declaration": { + "name": "meta.field.declaration.ts", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.ts variable.object.property.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.ts", + "match": "\\?" } ] } ] }, - "return-type-core": { + "variable-initializer": { + "patterns": [ + { + "begin": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.ts", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.ts" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, { "include": "#type-parameters" }, { - "include": "#type-tuple" + "include": "#function-parameters" }, { - "include": "#type-object" + "include": "#return-type" }, { - "include": "#type-operators" + "include": "#decl-block" + } + ] + }, + "method-declaration": { + "patterns": [ + { + "name": "meta.method.declaration.ts", + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "variable.parameter.ts" + } + } + }, + { + "name": "meta.arrow.ts", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.ts", + "begin": "(?:(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.ts" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.ts" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.ts", - "match": "(?)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.ts", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { + "class-declaration-or-expression-patterns": { "patterns": [ { "include": "#comment" }, { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" + "include": "#class-or-interface-heritage" + }, + { + "match": "[_$[:alpha:]][_$[:alnum:]]*", + "captures": { + "0": { + "name": "entity.name.type.class.ts" } - ] + } }, { - "include": "#type-predicate-operator" + "include": "#type-parameters" }, { - "include": "#type" + "include": "#class-or-interface-body" } ] }, - "type-tuple": { - "name": "meta.type.tuple.ts", - "begin": "\\[", + "interface-declaration": { + "name": "meta.interface.ts", + "begin": "(?)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.ts" + "name": "keyword.control.export.ts" + }, + "2": { + "name": "storage.modifier.ts" + }, + "3": { + "name": "storage.type.enum.ts" + }, + "4": { + "name": "entity.name.type.enum.ts" } }, + "end": "(?<=\\})", "patterns": [ { "include": "#comment" }, { - "name": "storage.modifier.ts", - "match": "(?)" + "include": "#string" + }, + { + "name": "entity.name.type.module.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + }, + { + "include": "#punctuation-accessor" + }, + { + "include": "#decl-block" + } + ] + }, + "type-alias-declaration": { + "name": "meta.type.declaration.ts", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + }, + "1": { + "name": "entity.name.function.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.ts" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.ts", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.ts" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.ts" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.ts", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.ts", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.ts", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.ts", + "begin": "(?*?]|[^+]\\+))\\s*(<)(?!)\\s*", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "cast.expr.ts", + "begin": "(?:(?<=^))\\s*(<)(?=[_$[:alpha:]][_$[:alnum:]]*\\s*>)", + "beginCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "end": "(\\>)\\s*", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "expression-operators": { + "patterns": [ + { + "name": "keyword.control.flow.ts", + "match": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.ts", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.ts", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.ts", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.ts", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.ts", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.ts", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.ts", + "match": "--" + }, + { + "name": "keyword.operator.increment.ts", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.ts", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.ts" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.ts", + "match": "(?=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "captures": { "1": { "name": "punctuation.accessor.ts" @@ -2460,7 +2579,7 @@ "match": "(?=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "patterns": [ - { - "name": "meta.function-call.ts", - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "patterns": [ - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#object-identifiers" - }, - { - "include": "#punctuation-accessor" - }, - { - "name": "keyword.operator.expression.import.ts", - "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" - }, - { - "name": "entity.name.function.ts", - "match": "([_$[:alpha:]][_$[:alnum:]]*)" - } - ] - }, - { - "include": "#comment" - }, - { - "name": "meta.type.parameters.ts", - "begin": "\\<", - "beginCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.begin.ts" - } - }, - "end": "\\>", - "endCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.end.ts" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - { - "include": "#paren-expression" - } - ] - }, "identifiers": { "patterns": [ { "include": "#object-identifiers" }, { - "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n))", + "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.ts" @@ -2621,22 +2678,17 @@ } ] }, - "cast": { + "type-annotation": { "patterns": [ { - "name": "cast.expr.ts", - "begin": "(?:(?<=return|throw|yield|await|default|[=(,:>*?]))\\s*(<)(?!)\\s*", - "endCaptures": { - "1": { - "name": "meta.brace.angle.ts" + "name": "keyword.operator.type.annotation.ts" } }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { "include": "#type" @@ -2644,19 +2696,14 @@ ] }, { - "name": "cast.expr.ts", - "begin": "(?:(?<=^))\\s*(<)(?=[_$[:alpha:]][_$[:alnum:]]*\\s*>)", + "name": "meta.type.annotation.ts", + "begin": "(:)", "beginCaptures": { "1": { - "name": "meta.brace.angle.ts" - } - }, - "end": "(\\>)\\s*", - "endCaptures": { - "1": { - "name": "meta.brace.angle.ts" + "name": "keyword.operator.type.annotation.ts" } }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { "include": "#type" @@ -2665,311 +2712,59 @@ } ] }, - "new-expr": { - "name": "new.expr.ts", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.ts" - }, - "1": { - "name": "entity.name.function.ts" - } - } - }, - { - "name": "meta.object.member.ts", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.ts" - } - }, - "end": "(?=,|\\})" - }, - { - "name": "meta.object.member.ts", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.ts" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.ts", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.ts" - } - } - }, - { - "include": "#object-member-body" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "object-member-body": { - "name": "meta.object.member.ts", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - "expression-operators": { - "patterns": [ - { - "name": "keyword.control.flow.ts", - "match": "(?>=|>>>=|\\|=" - }, - { - "name": "keyword.operator.bitwise.shift.ts", - "match": "<<|>>>|>>" - }, - { - "name": "keyword.operator.comparison.ts", - "match": "===|!==|==|!=" - }, - { - "name": "keyword.operator.relational.ts", - "match": "<=|>=|<>|<|>" - }, - { - "name": "keyword.operator.logical.ts", - "match": "\\!|&&|\\|\\|" - }, - { - "name": "keyword.operator.bitwise.ts", - "match": "\\&|~|\\^|\\|" - }, - { - "name": "keyword.operator.assignment.ts", - "match": "\\=" - }, - { - "name": "keyword.operator.decrement.ts", - "match": "--" - }, - { - "name": "keyword.operator.increment.ts", - "match": "\\+\\+" - }, - { - "name": "keyword.operator.arithmetic.ts", - "match": "%|\\*|/|-|\\+" - }, - { - "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", - "captures": { - "1": { - "name": "keyword.operator.arithmetic.ts" - } - } - } - ] - }, - "typeof-operator": { - "name": "keyword.operator.expression.typeof.ts", - "match": "(?)", - "captures": { - "1": { - "name": "storage.modifier.async.ts" - }, - "2": { - "name": "variable.parameter.ts" - } - } - }, - { - "name": "meta.arrow.ts", - "begin": "(?x) (?:\n (? is on new line\n (\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n ) |\n (\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends \n ) |\n # arrow function possible to detect only with => on same line\n (\n (<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(([^()]|\\([^()]*\\))*\\) # parameteres\n (\\s*:\\s*(.)*)? # return type\n \\s*=> # arrow operator\n )\n )\n)", - "beginCaptures": { - "1": { - "name": "storage.modifier.async.ts" - } - }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" - } - ] - }, - { - "name": "meta.arrow.ts", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", - "patterns": [ - { - "include": "#decl-block" - }, - { - "include": "#expression" - } - ] + "include": "#type" } ] }, @@ -3000,19 +2795,174 @@ } ] }, - "punctuation-comma": { - "name": "punctuation.separator.comma.ts", - "match": "," + "type-parameters": { + "name": "meta.type.parameters.ts", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.ts", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] }, - "punctuation-semicolon": { - "name": "punctuation.terminator.statement.ts", - "match": ";" + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] }, - "punctuation-accessor": { - "name": "punctuation.accessor.ts", - "match": "\\." + "type-primitive": { + "name": "support.type.primitive.ts", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.ts", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.ts", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?<=[=(:,\\[?+!]|return|case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.ts" @@ -3107,7 +3281,7 @@ }, { "name": "string.regexp.ts", - "begin": "(?\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", "captures": { "1": { "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" @@ -3819,33 +3786,12 @@ "5": { "name": "invalid.illegal.syntax.jsdoc" } - }, - "begin": "\\[", - "end": "\\]|(?=\\*/)", - "patterns": [ - { - "match": "(=)((?:[^\\]*]|\\*[^/])*)", - "captures": { - "1": { - "name": "keyword.operator.assignment.jsdoc" - }, - "2": { - "name": "source.embedded.ts" - } - } - }, - { - "include": "#brackets" - }, - { - "include": "#quotes" - } - ] + } } ] }, { - "begin": "((@)(?:define|enum|exception|implements|modifies|namespace|private|protected|returns?|suppress|throws|type))\\s+(?={)", + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", "beginCaptures": { "1": { "name": "storage.type.class.jsdoc" @@ -3918,7 +3864,7 @@ }, { "name": "storage.type.class.jsdoc", - "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|global|host|ignore|implements|implicitCast|inherit[Dd]oc|inner|instance|interface |internal|kind|lends|license|listens|main|member|memberof!?|method|mixes|mixins?|modifies|module |name|namespace|noalias|nocollapse|nocompile|nosideeffects|override|overview|package|param|preserve |private|prop|property|protected|public|read[Oo]nly|record|require[ds]|returns?|see|since|static |struct|submodule|summary|suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted |uses|var|variation|version|virtual|writeOnce) \\b", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", "captures": { "1": { "name": "punctuation.definition.block.tag.jsdoc" @@ -4013,28 +3959,6 @@ } ] }, - "quotes": { - "patterns": [ - { - "begin": "'", - "end": "'|(?=\\*/)", - "patterns": [ - { - "include": "#quotes" - } - ] - }, - { - "begin": "\"", - "end": "\"|(?=\\*/)", - "patterns": [ - { - "include": "#quotes" - } - ] - } - ] - }, "jsdoctype": { "patterns": [ { diff --git a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json index 2d161f0667a..3c825612994 100644 --- a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage.json +++ b/extensions/typescript/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/648a036db2bad78ee93463269ec49ed91ee5aa91", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/824f47ea6e98590ac2e75db5bebdf6eff71421ad", "name": "TypeScriptReact", "scopeName": "source.tsx", "fileTypes": [ @@ -44,20 +44,14 @@ "include": "#declaration" }, { - "include": "#switch-statement" + "include": "#control-statement" }, { - "include": "#for-loop" - }, - { - "include": "#after-operator-block" + "include": "#after-operator-block-as-object-literal" }, { "include": "#decl-block" }, - { - "include": "#control-statement" - }, { "include": "#expression" }, @@ -66,6 +60,164 @@ } ] }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.tsx", + "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx entity.name.function.tsx" @@ -323,1241 +498,6 @@ } ] }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.tsx" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.tsx" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "expression": { - "patterns": [ - { - "include": "#jsx" - }, - { - "include": "#string" - }, - { - "include": "#regex" - }, - { - "include": "#template" - }, - { - "include": "#comment" - }, - { - "include": "#function-expression" - }, - { - "include": "#class-expression" - }, - { - "include": "#arrow-function" - }, - { - "include": "#cast" - }, - { - "include": "#ternary-expression" - }, - { - "include": "#new-expr" - }, - { - "include": "#object-literal" - }, - { - "include": "#expression-operators" - }, - { - "include": "#function-call" - }, - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#identifiers" - }, - { - "include": "#paren-expression" - }, - { - "include": "#punctuation-comma" - }, - { - "include": "#punctuation-accessor" - } - ] - }, - "control-statement": { - "patterns": [ - { - "name": "keyword.control.trycatch.tsx", - "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)" - }, - { - "name": "meta.definition.property.tsx variable.object.property.tsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.tsx", - "match": "\\?" - } - ] - } - ] - }, - "method-declaration": { - "patterns": [ - { - "name": "meta.method.declaration.tsx", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -1765,140 +705,400 @@ } ] }, - "return-type": { + "field-declaration": { + "name": "meta.field.declaration.tsx", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.tsx variable.object.property.tsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.tsx", + "match": "\\?" } ] } ] }, - "return-type-core": { + "variable-initializer": { + "patterns": [ + { + "begin": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.tsx", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.tsx" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, { "include": "#type-parameters" }, { - "include": "#type-tuple" + "include": "#function-parameters" }, { - "include": "#type-object" + "include": "#return-type" }, { - "include": "#type-operators" + "include": "#decl-block" + } + ] + }, + "method-declaration": { + "patterns": [ + { + "name": "meta.method.declaration.tsx", + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.tsx" + }, + "2": { + "name": "variable.parameter.tsx" + } + } + }, + { + "name": "meta.arrow.tsx", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.tsx", + "begin": "(?:(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.tsx" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.tsx" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.tsx", - "match": "(?)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.tsx" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.tsx", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.tsx" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { + "class-declaration-or-expression-patterns": { "patterns": [ { "include": "#comment" }, { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" + "include": "#class-or-interface-heritage" + }, + { + "match": "[_$[:alpha:]][_$[:alnum:]]*", + "captures": { + "0": { + "name": "entity.name.type.class.tsx" } - ] + } }, { - "include": "#type-predicate-operator" + "include": "#type-parameters" }, { - "include": "#type" + "include": "#class-or-interface-body" } ] }, - "type-tuple": { - "name": "meta.type.tuple.tsx", - "begin": "\\[", + "interface-declaration": { + "name": "meta.interface.tsx", + "begin": "(?)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.tsx" + "name": "keyword.control.export.tsx" + }, + "2": { + "name": "storage.modifier.tsx" + }, + "3": { + "name": "storage.type.enum.tsx" + }, + "4": { + "name": "entity.name.type.enum.tsx" } }, + "end": "(?<=\\})", "patterns": [ { "include": "#comment" }, { - "name": "storage.modifier.tsx", - "match": "(?)" + "include": "#string" + }, + { + "name": "entity.name.type.module.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + }, + { + "include": "#punctuation-accessor" + }, + { + "include": "#decl-block" + } + ] + }, + "type-alias-declaration": { + "name": "meta.type.declaration.tsx", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.tsx" + }, + "1": { + "name": "entity.name.function.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.tsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.tsx" + } + } + }, + { + "name": "meta.object.member.tsx", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.tsx", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.tsx punctuation.separator.key-value.tsx" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(\\?)", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.tsx" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.tsx" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.tsx", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.tsx", + "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" + }, + { + "name": "entity.name.function.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)" + } + ] + }, + { + "include": "#comment" + }, + { + "name": "meta.type.parameters.tsx", + "begin": "\\<", + "beginCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.begin.tsx" + } + }, + "end": "\\>", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.tsx" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.tsx", + "begin": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.tsx", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.tsx", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.tsx", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.tsx", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.tsx", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.tsx", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.tsx", + "match": "--" + }, + { + "name": "keyword.operator.increment.tsx", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.tsx", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.tsx" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.tsx", + "match": "(?=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "match": "(?x) (\\.) \\s* (?:\n (ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE\n |DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR\n |INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR\n |NOT_SUPPORTED_ERR|NOTATION_NODE|PROCESSING_INSTRUCTION_NODE|TEXT_NODE|WRONG_DOCUMENT_ERR)\n |\n (_content|[xyz]|abbr|above|accept|acceptCharset|accessKey|action|align|[av]Link(?:color)?|all|alt|anchors|appCodeName\n |appCore|applets|appMinorVersion|appName|appVersion|archive|areas|arguments|attributes|availHeight|availLeft|availTop\n |availWidth|axis|background|backgroundColor|backgroundImage|below|bgColor|body|border|borderBottomWidth|borderColor\n |borderLeftWidth|borderRightWidth|borderStyle|borderTopWidth|borderWidth|bottom|bufferDepth|callee|caller|caption\n |cellPadding|cells|cellSpacing|ch|characterSet|charset|checked|childNodes|chOff|cite|classes|className|clear\n |clientInformation|clip|clipBoardData|closed|code|codeBase|codeType|color|colorDepth|cols|colSpan|compact|complete\n |components|content|controllers|cookie|cookieEnabled|cords|cpuClass|crypto|current|data|dateTime|declare|defaultCharset\n |defaultChecked|defaultSelected|defaultStatus|defaultValue|defaultView|defer|description|dialogArguments|dialogHeight\n |dialogLeft|dialogTop|dialogWidth|dir|directories|disabled|display|docmain|doctype|documentElement|elements|embeds\n |enabledPlugin|encoding|enctype|entities|event|expando|external|face|fgColor|filename|firstChild|fontFamily|fontSize\n |fontWeight|form|formName|forms|frame|frameBorder|frameElement|frames|hasFocus|hash|headers|height|history|host\n |hostname|href|hreflang|hspace|htmlFor|httpEquiv|id|ids|ignoreCase|images|implementation|index|innerHeight|innerWidth\n |input|isMap|label|lang|language|lastChild|lastIndex|lastMatch|lastModified|lastParen|layer[sXY]|left|leftContext\n |lineHeight|link|linkColor|links|listStyleType|localName|location|locationbar|longDesc|lowsrc|lowSrc|marginBottom\n |marginHeight|marginLeft|marginRight|marginTop|marginWidth|maxLength|media|menubar|method|mimeTypes|multiline|multiple\n |name|nameProp|namespaces|namespaceURI|next|nextSibling|nodeName|nodeType|nodeValue|noHref|noResize|noShade|notationName\n |notations|noWrap|object|offscreenBuffering|onLine|onreadystatechange|opener|opsProfile|options|oscpu|outerHeight\n |outerWidth|ownerDocument|paddingBottom|paddingLeft|paddingRight|paddingTop|page[XY]|page[XY]Offset|parent|parentLayer\n |parentNode|parentWindow|pathname|personalbar|pixelDepth|pkcs11|platform|plugins|port|prefix|previous|previousDibling\n |product|productSub|profile|profileend|prompt|prompter|protocol|publicId|readOnly|readyState|referrer|rel|responseText\n |responseXML|rev|right|rightContext|rowIndex|rows|rowSpan|rules|scheme|scope|screen[XY]|screenLeft|screenTop|scripts\n |scrollbars|scrolling|sectionRowIndex|security|securityPolicy|selected|selectedIndex|selection|self|shape|siblingAbove\n |siblingBelow|size|source|specified|standby|start|status|statusbar|statusText|style|styleSheets|suffixes|summary\n |systemId|systemLanguage|tagName|tags|target|tBodies|text|textAlign|textDecoration|textIndent|textTransform|tFoot|tHead\n |title|toolbar|top|type|undefined|uniqueID|updateInterval|URL|URLUnencoded|useMap|userAgent|userLanguage|userProfile\n |vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\\b(?!\\$|\\s*(<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", "captures": { "1": { "name": "punctuation.accessor.tsx" @@ -2463,7 +2545,7 @@ "match": "(?=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "patterns": [ - { - "name": "meta.function-call.tsx", - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\.\\s*)*|(\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "patterns": [ - { - "include": "#literal" - }, - { - "include": "#support-objects" - }, - { - "include": "#object-identifiers" - }, - { - "include": "#punctuation-accessor" - }, - { - "name": "keyword.operator.expression.import.tsx", - "match": "(?![\\.\\$])\\bimport(?=\\s*[\\(]\\s*[\\\"\\'\\`])" - }, - { - "name": "entity.name.function.tsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)" - } - ] - }, - { - "include": "#comment" - }, - { - "name": "meta.type.parameters.tsx", - "begin": "\\<", - "beginCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.begin.tsx" - } - }, - "end": "\\>", - "endCaptures": { - "0": { - "name": "punctuation.definition.typeparameters.end.tsx" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - { - "include": "#paren-expression" - } - ] - }, "identifiers": { "patterns": [ { "include": "#object-identifiers" }, { - "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n))", + "match": "(?x)(?:(\\.)\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(\\[]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(\\[]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.tsx" @@ -2624,195 +2644,17 @@ } ] }, - "cast": { + "type-annotation": { "patterns": [ { - "include": "#jsx" - } - ] - }, - "new-expr": { - "name": "new.expr.tsx", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)?\\(([^()]|\\([^()]*\\))*\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.tsx" - }, - "1": { - "name": "entity.name.function.tsx" - } - } - }, - { - "name": "meta.object.member.tsx", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.tsx" - } - }, - "end": "(?=,|\\})" - }, - { - "name": "meta.object.member.tsx", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.tsx" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.tsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.tsx" - } - } - }, - { - "include": "#object-member-body" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "object-member-body": { - "name": "meta.object.member.tsx", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.tsx punctuation.separator.key-value.tsx" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - "expression-operators": { - "patterns": [ - { - "name": "keyword.control.flow.tsx", - "match": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { "include": "#type" @@ -2820,125 +2662,78 @@ ] }, { - "name": "keyword.operator.spread.tsx", - "match": "\\.\\.\\." - }, - { - "name": "keyword.operator.assignment.compound.tsx", - "match": "\\*=|(?>=|>>>=|\\|=" - }, - { - "name": "keyword.operator.bitwise.shift.tsx", - "match": "<<|>>>|>>" - }, - { - "name": "keyword.operator.comparison.tsx", - "match": "===|!==|==|!=" - }, - { - "name": "keyword.operator.relational.tsx", - "match": "<=|>=|<>|<|>" - }, - { - "name": "keyword.operator.logical.tsx", - "match": "\\!|&&|\\|\\|" - }, - { - "name": "keyword.operator.bitwise.tsx", - "match": "\\&|~|\\^|\\|" - }, - { - "name": "keyword.operator.assignment.tsx", - "match": "\\=" - }, - { - "name": "keyword.operator.decrement.tsx", - "match": "--" - }, - { - "name": "keyword.operator.increment.tsx", - "match": "\\+\\+" - }, - { - "name": "keyword.operator.arithmetic.tsx", - "match": "%|\\*|/|-|\\+" - }, - { - "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", - "captures": { + "name": "meta.type.annotation.tsx", + "begin": "(:)", + "beginCaptures": { "1": { - "name": "keyword.operator.arithmetic.tsx" + "name": "keyword.operator.type.annotation.tsx" } - } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] } ] }, - "typeof-operator": { - "name": "keyword.operator.expression.typeof.tsx", - "match": "(?)", - "captures": { - "1": { - "name": "storage.modifier.async.tsx" - }, - "2": { - "name": "variable.parameter.tsx" - } - } - }, - { - "name": "meta.arrow.tsx", - "begin": "(?x) (?:\n (? is on new line\n (\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n ) |\n (\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends \n ) |\n # arrow function possible to detect only with => on same line\n (\n (<([^<>=]|=[^<]|\\<([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\(([^()]|\\([^()]*\\))*\\) # parameteres\n (\\s*:\\s*(.)*)? # return type\n \\s*=> # arrow operator\n )\n )\n)", + "name": "meta.return.type.tsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", "beginCaptures": { "1": { - "name": "storage.modifier.async.tsx" + "name": "keyword.operator.type.annotation.tsx" } }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "end": "(?", + "name": "meta.return.type.tsx", + "begin": "(?<=\\))\\s*(:)", "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.tsx" + "1": { + "name": "keyword.operator.type.annotation.tsx" } }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "end": "(?)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.tsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.tsx", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] }, - "punctuation-semicolon": { - "name": "punctuation.terminator.statement.tsx", - "match": ";" + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] }, - "punctuation-accessor": { - "name": "punctuation.accessor.tsx", - "match": "\\." + "type-primitive": { + "name": "support.type.primitive.tsx", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.tsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.tsx", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimy]*(?!\\s*[a-zA-Z0-9_$]))", + "begin": "(?<=[=(:,\\[?+!]|return|case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", "beginCaptures": { "1": { "name": "punctuation.definition.string.begin.tsx" @@ -3073,7 +3247,7 @@ }, { "name": "string.regexp.tsx", - "begin": "(?\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", "captures": { "1": { "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" @@ -3785,33 +3752,12 @@ "5": { "name": "invalid.illegal.syntax.jsdoc" } - }, - "begin": "\\[", - "end": "\\]|(?=\\*/)", - "patterns": [ - { - "match": "(=)((?:[^\\]*]|\\*[^/])*)", - "captures": { - "1": { - "name": "keyword.operator.assignment.jsdoc" - }, - "2": { - "name": "source.embedded.tsx" - } - } - }, - { - "include": "#brackets" - }, - { - "include": "#quotes" - } - ] + } } ] }, { - "begin": "((@)(?:define|enum|exception|implements|modifies|namespace|private|protected|returns?|suppress|throws|type))\\s+(?={)", + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", "beginCaptures": { "1": { "name": "storage.type.class.jsdoc" @@ -3884,7 +3830,7 @@ }, { "name": "storage.type.class.jsdoc", - "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|global|host|ignore|implements|implicitCast|inherit[Dd]oc|inner|instance|interface |internal|kind|lends|license|listens|main|member|memberof!?|method|mixes|mixins?|modifies|module |name|namespace|noalias|nocollapse|nocompile|nosideeffects|override|overview|package|param|preserve |private|prop|property|protected|public|read[Oo]nly|record|require[ds]|returns?|see|since|static |struct|submodule|summary|suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted |uses|var|variation|version|virtual|writeOnce) \\b", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", "captures": { "1": { "name": "punctuation.definition.block.tag.jsdoc" @@ -3979,28 +3925,6 @@ } ] }, - "quotes": { - "patterns": [ - { - "begin": "'", - "end": "'|(?=\\*/)", - "patterns": [ - { - "include": "#quotes" - } - ] - }, - { - "begin": "\"", - "end": "\"|(?=\\*/)", - "patterns": [ - { - "include": "#quotes" - } - ] - } - ] - }, "jsdoctype": { "patterns": [ { @@ -4035,121 +3959,19 @@ } ] }, - "jsx-tag-attributes": { + "jsx": { "patterns": [ { - "include": "#jsx-tag-attribute-name" + "include": "#jsx-tag-without-attributes-in-expression" }, { - "include": "#jsx-tag-attribute-assignment" + "include": "#jsx-tag-in-expression" }, { - "include": "#jsx-string-double-quoted" - }, - { - "include": "#jsx-string-single-quoted" - }, - { - "include": "#jsx-evaluated-code" + "include": "#jsx-tag-invalid" } ] }, - "jsx-tag-attribute-name": { - "match": "(?x)\n \\s*\n ([_$a-zA-Z][-$\\w]*)\n (?=\\s|=|/?>|/\\*|//)", - "captures": { - "1": { - "name": "entity.other.attribute-name.tsx" - } - } - }, - "jsx-tag-attribute-assignment": { - "name": "keyword.operator.assignment.tsx", - "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" - }, - "jsx-string-double-quoted": { - "name": "string.quoted.double.tsx", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-string-single-quoted": { - "name": "string.quoted.single.tsx", - "begin": "'", - "end": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-entities": { - "patterns": [ - { - "name": "constant.character.entity.tsx", - "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", - "captures": { - "1": { - "name": "punctuation.definition.entity.tsx" - }, - "3": { - "name": "punctuation.definition.entity.tsx" - } - } - }, - { - "name": "invalid.illegal.bad-ampersand.tsx", - "match": "&" - } - ] - }, - "jsx-evaluated-code": { - "name": "meta.embedded.expression.tsx", - "begin": "\\{", - "end": "\\}", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.tsx" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "jsx-tag-attributes-illegal": { - "name": "invalid.illegal.attribute.tsx", - "match": "\\S+" - }, "jsx-tag-without-attributes-in-expression": { "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", @@ -4275,6 +4097,7 @@ } }, "end": "(?=[/]?>)", + "contentName": "meta.tag.attributes.tsx", "patterns": [ { "include": "#comment" @@ -4327,18 +4150,120 @@ } ] }, - "jsx": { + "jsx-evaluated-code": { + "name": "meta.embedded.expression.tsx", + "begin": "\\{", + "end": "\\}", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.tsx" + } + }, "patterns": [ { - "include": "#jsx-tag-without-attributes-in-expression" - }, - { - "include": "#jsx-tag-in-expression" - }, - { - "include": "#jsx-tag-invalid" + "include": "#expression" } ] + }, + "jsx-entities": { + "patterns": [ + { + "name": "constant.character.entity.tsx", + "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", + "captures": { + "1": { + "name": "punctuation.definition.entity.tsx" + }, + "3": { + "name": "punctuation.definition.entity.tsx" + } + } + }, + { + "name": "invalid.illegal.bad-ampersand.tsx", + "match": "&" + } + ] + }, + "jsx-tag-attributes": { + "patterns": [ + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n ([_$a-zA-Z][-$\\w]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.tsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.tsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.tsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.tsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.tsx", + "match": "\\S+" } } } \ No newline at end of file diff --git a/extensions/typescript/test/colorize-results/test-issue5431_ts.json b/extensions/typescript/test/colorize-results/test-issue5431_ts.json index 53b90902a23..e2fc02cc2ad 100644 --- a/extensions/typescript/test/colorize-results/test-issue5431_ts.json +++ b/extensions/typescript/test/colorize-results/test-issue5431_ts.json @@ -364,12 +364,12 @@ }, { "c": "startTime", - "t": "source.ts meta.function.ts meta.block.ts meta.var.expr.ts string.template.ts meta.template.expression.ts variable.other.readwrite.ts", + "t": "source.ts meta.function.ts meta.block.ts meta.var.expr.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts variable.other.readwrite.ts", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -408,12 +408,12 @@ }, { "c": "endTime", - "t": "source.ts meta.function.ts meta.block.ts meta.var.expr.ts string.template.ts meta.template.expression.ts variable.other.readwrite.ts", + "t": "source.ts meta.function.ts meta.block.ts meta.var.expr.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts variable.other.readwrite.ts", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, diff --git a/extensions/typescript/test/colorize-results/test-strings_ts.json b/extensions/typescript/test/colorize-results/test-strings_ts.json index 136549cfeba..5c1d4bb6c17 100644 --- a/extensions/typescript/test/colorize-results/test-strings_ts.json +++ b/extensions/typescript/test/colorize-results/test-strings_ts.json @@ -100,12 +100,12 @@ }, { "c": "foo", - "t": "source.ts meta.var.expr.ts string.template.ts meta.template.expression.ts variable.other.readwrite.ts", + "t": "source.ts meta.var.expr.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts variable.other.readwrite.ts", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, @@ -353,40 +353,40 @@ }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "a", - "t": "source.ts string.template.ts meta.template.expression.ts variable.other.readwrite.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts variable.other.readwrite.ts", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "+", - "t": "source.ts string.template.ts meta.template.expression.ts keyword.operator.arithmetic.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts keyword.operator.arithmetic.ts", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -397,35 +397,35 @@ }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "b", - "t": "source.ts string.template.ts meta.template.expression.ts variable.other.readwrite.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts variable.other.readwrite.ts", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { @@ -463,40 +463,40 @@ }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "a", - "t": "source.ts string.template.ts meta.template.expression.ts variable.other.readwrite.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts variable.other.readwrite.ts", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "*", - "t": "source.ts string.template.ts meta.template.expression.ts keyword.operator.arithmetic.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts keyword.operator.arithmetic.ts", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -507,35 +507,35 @@ }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { "c": "b", - "t": "source.ts string.template.ts meta.template.expression.ts variable.other.readwrite.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts variable.other.readwrite.ts", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", "hc_black": "variable: #9CDCFE" } }, { "c": " ", - "t": "source.ts string.template.ts meta.template.expression.ts", + "t": "source.ts string.template.ts meta.template.expression.ts meta.embedded.line.ts", "r": { - "dark_plus": "meta.template.expression: #D4D4D4", - "light_plus": "meta.template.expression: #000000", - "dark_vs": "meta.template.expression: #D4D4D4", - "light_vs": "meta.template.expression: #000000", - "hc_black": "meta.template.expression: #FFFFFF" + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" } }, { diff --git a/extensions/typescript/tsconfig.json b/extensions/typescript/tsconfig.json index da4f1bb399b..bec41102e78 100644 --- a/extensions/typescript/tsconfig.json +++ b/extensions/typescript/tsconfig.json @@ -7,7 +7,6 @@ "es2015.promise" ], "outDir": "./out", - "strictNullChecks": true, "noImplicitAny": true, "noImplicitReturns": true, "noUnusedLocals": true, diff --git a/extensions/vb/language-configuration.json b/extensions/vb/language-configuration.json index f1fabbd4f22..d9a6b21014a 100644 --- a/extensions/vb/language-configuration.json +++ b/extensions/vb/language-configuration.json @@ -20,5 +20,11 @@ ["(", ")"], ["\"", "\""], ["<", ">"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*#Region\\b", + "end": "^\\s*#End Region\\b" + } + } } \ No newline at end of file diff --git a/extensions/vb/snippets/vb.json b/extensions/vb/snippets/vb.json index e533e043d9a..447b43b0581 100644 --- a/extensions/vb/snippets/vb.json +++ b/extensions/vb/snippets/vb.json @@ -68,5 +68,19 @@ "End While" ], "description": "While ... End While" + }, + "Region Start": { + "prefix": "#Region", + "body": [ + "#Region $0" + ], + "description": "Folding Region Start" + }, + "Region End": { + "prefix": "#End Region", + "body": [ + "#End Region" + ], + "description": "Folding Region End" } } diff --git a/extensions/vscode-api-tests/.vscode/launch.json b/extensions/vscode-api-tests/.vscode/launch.json index b6ed0f7a674..8f8a11a2a5e 100644 --- a/extensions/vscode-api-tests/.vscode/launch.json +++ b/extensions/vscode-api-tests/.vscode/launch.json @@ -7,7 +7,7 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["${workspaceRoot}/../../", "${workspaceRoot}/testWorkspace", "--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out" ], + "args": ["${workspaceFolder}/../../", "${workspaceFolder}/testWorkspace", "--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out" ], "stopOnEntry": false, "sourceMaps": true, "outDir": "out", diff --git a/extensions/vscode-api-tests/.vscode/tasks.json b/extensions/vscode-api-tests/.vscode/tasks.json index d31b15910ee..e2a020d0645 100644 --- a/extensions/vscode-api-tests/.vscode/tasks.json +++ b/extensions/vscode-api-tests/.vscode/tasks.json @@ -1,5 +1,5 @@ // Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team +// ${workspaceFolder}: the root folder of the team // ${file}: the current opened file // ${fileBasename}: the current opened file's basename // ${fileDirname}: the current opened file's dirname diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 93ac38acad8..e93913708b9 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -3,6 +3,7 @@ "description": "API tests for VS Code", "version": "0.0.1", "publisher": "vscode", + "enableProposedApi": true, "private": true, "engines": { "vscode": "*" @@ -45,9 +46,9 @@ "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-api-tests ./tsconfig.json" }, "devDependencies": { - "@types/mocha": "^2.2.38", - "@types/node": "^7.0.4", + "@types/mocha": "2.2.43", + "@types/node": "7.0.43", "typescript": "^1.6.2", - "vscode": "1.0.1" + "vscode": "1.1.5" } -} \ No newline at end of file +} diff --git a/extensions/vscode-api-tests/src/commands.test.ts b/extensions/vscode-api-tests/src/commands.test.ts index 47b4d85f347..45da4f2df48 100644 --- a/extensions/vscode-api-tests/src/commands.test.ts +++ b/extensions/vscode-api-tests/src/commands.test.ts @@ -5,6 +5,7 @@ 'use strict'; +import 'mocha'; import * as assert from 'assert'; import { join } from 'path'; import { commands, workspace, window, Uri, ViewColumn, Range, Position } from 'vscode'; @@ -134,4 +135,4 @@ suite('commands namespace tests', () => { return Promise.all([a, b, c, d]); }); -}); +}); \ No newline at end of file diff --git a/extensions/vscode-api-tests/src/configuration.test.ts b/extensions/vscode-api-tests/src/configuration.test.ts index 65dc52e4537..ffd8b53e06c 100644 --- a/extensions/vscode-api-tests/src/configuration.test.ts +++ b/extensions/vscode-api-tests/src/configuration.test.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'mocha'; import * as assert from 'assert'; import * as vscode from 'vscode'; diff --git a/extensions/vscode-api-tests/src/languages.test.ts b/extensions/vscode-api-tests/src/languages.test.ts index 321b1b772f2..01dea3ddc3f 100644 --- a/extensions/vscode-api-tests/src/languages.test.ts +++ b/extensions/vscode-api-tests/src/languages.test.ts @@ -78,12 +78,12 @@ suite('languages namespace tests', () => { }); return workspace.openTextDocument(uri).then(doc => { - return commands.executeCommand('vscode.executeCompletionItemProvider', uri, new Position(1, 0)); - }).then((result: CompletionList) => { + return commands.executeCommand('vscode.executeCompletionItemProvider', uri, new Position(1, 0)); + }).then((result: CompletionList | undefined) => { r1.dispose(); assert.ok(ran); - console.log(result.items); - assert.equal(result.items[0].label, 'foo'); + console.log(result!.items); + assert.equal(result!.items[0].label, 'foo'); }); }); }); diff --git a/extensions/vscode-api-tests/src/typings/ref.d.ts b/extensions/vscode-api-tests/src/typings/ref.d.ts index 3bc58fa959d..77807029165 100644 --- a/extensions/vscode-api-tests/src/typings/ref.d.ts +++ b/extensions/vscode-api-tests/src/typings/ref.d.ts @@ -4,5 +4,4 @@ *--------------------------------------------------------------------------------------------*/ /// -/// /// diff --git a/extensions/vscode-api-tests/src/window.test.ts b/extensions/vscode-api-tests/src/window.test.ts index c92cae33aab..2a2f92c90e7 100644 --- a/extensions/vscode-api-tests/src/window.test.ts +++ b/extensions/vscode-api-tests/src/window.test.ts @@ -138,6 +138,26 @@ suite('window namespace tests', () => { assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.One); }); + test('issue #27408 - showTextDocument & vscode.diff always default to ViewColumn.One', async () => { + const [docA, docB, docC] = await Promise.all([ + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()) + ]); + + await window.showTextDocument(docA, ViewColumn.One); + await window.showTextDocument(docB, ViewColumn.Two); + + assert.ok(window.activeTextEditor); + assert.ok(window.activeTextEditor!.document === docB); + assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + + await window.showTextDocument(docC, ViewColumn.Active); + + assert.ok(window.activeTextEditor!.document === docC); + assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + }); + test('issue #5362 - Incorrect TextEditor passed by onDidChangeTextEditorSelection', (done) => { const file10Path = join(workspace.rootPath || '', './10linefile.ts'); const file30Path = join(workspace.rootPath || '', './30linefile.ts'); @@ -329,6 +349,35 @@ suite('window namespace tests', () => { return Promise.all([a, b]); }); + test('showWorkspaceFolderPick', function () { + const p = window.showWorkspaceFolderPick(undefined); + + return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => { + return p.then(workspace => { + assert.ok(true); + }, error => { + assert.ok(false); + }); + }); + }); + + test('Default value for showInput Box accepted even if fails validateInput, #33691', function () { + const result = window.showInputBox({ + validateInput: (value: string) => { + if (!value || value.trim().length === 0) { + return 'Cannot set empty description'; + } + return null; + } + }).then(value => { + assert.equal(value, undefined); + }); + + const exec = commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); + return Promise.all([result, exec]); + }); + + test('editor, selection change kind', () => { return workspace.openTextDocument(join(workspace.rootPath || '', './far.js')).then(doc => window.showTextDocument(doc)).then(editor => { diff --git a/extensions/vscode-api-tests/src/workspace.test.ts b/extensions/vscode-api-tests/src/workspace.test.ts index 77592f788cf..d4c4ae7013c 100644 --- a/extensions/vscode-api-tests/src/workspace.test.ts +++ b/extensions/vscode-api-tests/src/workspace.test.ts @@ -97,7 +97,7 @@ suite('workspace-namespace', () => { }); }); - test('openTextDocument, untitled closes on save', function (done) { + test('openTextDocument, untitled closes on save', function () { const path = join(vscode.workspace.rootPath || '', './newfile.txt'); return vscode.workspace.openTextDocument(vscode.Uri.parse('untitled:' + path)).then(doc => { @@ -115,7 +115,7 @@ suite('workspace-namespace', () => { d0.dispose(); - return deleteFile(vscode.Uri.file(join(vscode.workspace.rootPath || '', './newfile.txt'))).then(() => done(null)); + return deleteFile(vscode.Uri.file(join(vscode.workspace.rootPath || '', './newfile.txt'))); }); }); @@ -483,7 +483,7 @@ suite('workspace-namespace', () => { assert.equal(res.length, 1); assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'far.js'); }); - }).timeout(60 * 1000); // Increase timeout for search-based test + }); // TODO@Joh this test fails randomly // test('findFiles, cancellation', () => { diff --git a/extensions/vscode-api-tests/tsconfig.json b/extensions/vscode-api-tests/tsconfig.json index 26c357e374b..a8cae381174 100644 --- a/extensions/vscode-api-tests/tsconfig.json +++ b/extensions/vscode-api-tests/tsconfig.json @@ -3,11 +3,12 @@ "module": "commonjs", "target": "ES5", "outDir": "out", + "noUnusedLocals": true, "lib": [ "es2015" ], "sourceMap": true, - "strictNullChecks": true + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/vscode-colorize-tests/.vscode/launch.json b/extensions/vscode-colorize-tests/.vscode/launch.json index 76d6fa69865..73c3753c75c 100644 --- a/extensions/vscode-colorize-tests/.vscode/launch.json +++ b/extensions/vscode-colorize-tests/.vscode/launch.json @@ -7,10 +7,10 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["${workspaceRoot}/../../", "${workspaceRoot}/test", "--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out" ], + "args": ["${workspaceFolder}/../../", "${workspaceFolder}/test", "--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out" ], "stopOnEntry": false, "sourceMaps": true, - "outDir": "${workspaceRoot}/out", + "outDir": "${workspaceFolder}/out", "preLaunchTask": "npm" } ] diff --git a/extensions/vscode-colorize-tests/.vscode/tasks.json b/extensions/vscode-colorize-tests/.vscode/tasks.json index 97e40acf632..3b6c357da2d 100644 --- a/extensions/vscode-colorize-tests/.vscode/tasks.json +++ b/extensions/vscode-colorize-tests/.vscode/tasks.json @@ -1,5 +1,5 @@ // Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team +// ${workspaceFolder}: the root folder of the team // ${file}: the current opened file // ${relativeFile}: the current opened file relative to cwd // ${fileBasename}: the current opened file's basename diff --git a/extensions/vscode-colorize-tests/package.json b/extensions/vscode-colorize-tests/package.json index 2e886b67189..0d6da2add03 100644 --- a/extensions/vscode-colorize-tests/package.json +++ b/extensions/vscode-colorize-tests/package.json @@ -12,8 +12,7 @@ "postinstall": "node ./node_modules/vscode/bin/install" }, "devDependencies": { - "@types/mocha": "^2.2.38", - "@types/node": "^7.0.4", - "vscode": "1.0.1" + "@types/node": "7.0.43", + "vscode": "1.1.5" } } \ No newline at end of file diff --git a/extensions/vscode-colorize-tests/src/colorizer.test.ts b/extensions/vscode-colorize-tests/src/colorizer.test.ts index 4904195e835..7fb9ae02e62 100644 --- a/extensions/vscode-colorize-tests/src/colorizer.test.ts +++ b/extensions/vscode-colorize-tests/src/colorizer.test.ts @@ -5,12 +5,13 @@ 'use strict'; +import 'mocha'; import * as assert from 'assert'; import { commands, Uri } from 'vscode'; import { join, basename, normalize, dirname } from 'path'; import * as fs from 'fs'; -function assertUnchangedTokens(testFixurePath: string, done) { +function assertUnchangedTokens(testFixurePath: string, done: any) { let fileName = basename(testFixurePath); return commands.executeCommand('_workbench.captureSyntaxTokens', Uri.file(testFixurePath)).then(data => { diff --git a/extensions/vscode-colorize-tests/src/typings/ref.d.ts b/extensions/vscode-colorize-tests/src/typings/ref.d.ts index 0f121ddcf43..8ea9f802a47 100644 --- a/extensions/vscode-colorize-tests/src/typings/ref.d.ts +++ b/extensions/vscode-colorize-tests/src/typings/ref.d.ts @@ -3,5 +3,4 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/// /// diff --git a/extensions/vscode-colorize-tests/tsconfig.json b/extensions/vscode-colorize-tests/tsconfig.json index 366e25ea09c..a8cae381174 100644 --- a/extensions/vscode-colorize-tests/tsconfig.json +++ b/extensions/vscode-colorize-tests/tsconfig.json @@ -3,10 +3,12 @@ "module": "commonjs", "target": "ES5", "outDir": "out", + "noUnusedLocals": true, "lib": [ "es2015" ], - "sourceMap": true + "sourceMap": true, + "strict": true }, "include": [ "src/**/*" diff --git a/extensions/yaml/language-configuration.json b/extensions/yaml/language-configuration.json index cab4f6602ff..cc1aa26cde6 100644 --- a/extensions/yaml/language-configuration.json +++ b/extensions/yaml/language-configuration.json @@ -20,5 +20,8 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "offSide": true + } } \ No newline at end of file diff --git a/i18n/chs/extensions/azure-account/out/azure-account.i18n.json b/i18n/chs/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..d64636616d4 --- /dev/null +++ b/i18n/chs/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "å¤åˆ¶å¹¶ę‰“å¼€", + "azure-account.close": "关闭", + "azure-account.login": "登录", + "azure-account.loginFirst": "čæ˜ęœŖē™»å½•ļ¼ŒčÆ·å…ˆē™»å½•ć€‚", + "azure-account.userCodeFailed": "čŽ·å–ē”Øęˆ·ä»£ē å¤±č“„", + "azure-account.tokenFailed": "ē”Øč®¾å¤‡ä»£ē čŽ·å–ä»¤ē‰Œ", + "azure-account.tokenFromRefreshTokenFailed": "ē”Øåˆ·ę–°ēš„ä»¤ē‰ŒčŽ·å–ä»¤ē‰Œ" +} \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/common/folding.ts b/i18n/chs/extensions/azure-account/out/extension.i18n.json similarity index 61% rename from src/vs/editor/contrib/folding/common/folding.ts rename to i18n/chs/extensions/azure-account/out/extension.i18n.json index c0f677cb95c..d90c9399da5 100644 --- a/src/vs/editor/contrib/folding/common/folding.ts +++ b/i18n/chs/extensions/azure-account/out/extension.i18n.json @@ -2,14 +2,8 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - -import { IEditorContribution } from 'vs/editor/common/editorCommon'; - -export const ID = 'editor.contrib.folding'; - -export interface IFoldingController extends IEditorContribution { - - foldAll(): void; - unfoldAll(): void; - +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: ę­£åœØē™»å½•...", + "azure-account.loggedIn": "Azure: {0}" } \ No newline at end of file diff --git a/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index f1f362da927..4b77210ee8f 100644 --- a/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/chs/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "例如 myFile.txt", - "activeEditorMedium": "例如 myFolder/myFile.txt", - "activeEditorLong": "例如 /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "例如 myFolder1态myFolder2态myFolder3", - "rootPath": "例如 /Users/Development/myProject", - "folderName": "例如 myFolder", - "folderPath": "例如 /Users/Development/myFolder", + "activeEditorShort": "ę–‡ä»¶å (例如 myFile.txt)", + "activeEditorMedium": "ē›øåÆ¹äŗŽå·„ä½œåŒŗę–‡ä»¶å¤¹ēš„ę–‡ä»¶č·Æå¾„ (例如 myFolder/myFile.txt)", + "activeEditorLong": "ę–‡ä»¶ēš„å®Œę•“č·Æå¾„ (例如 /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "å·„ä½œåŒŗåē§° (例如 myFolder ꈖ myWorkspace)", + "rootPath": "å·„ä½œåŒŗč·Æå¾„ (例如 /Users/Development/myWorkspace)", + "folderName": "ę–‡ä»¶ę‰€åœØå·„ä½œåŒŗę–‡ä»¶å¤¹ēš„åē§° (例如 myFolder)", + "folderPath": "ę–‡ä»¶ę‰€åœØå·„ä½œåŒŗę–‡ä»¶å¤¹ēš„č·Æå¾„ (例如 /Users/Development/myFolder)", "appName": "例如 VS Code", "dirty": "äø€äøŖę›“ę–°ēš„ęŒ‡ē¤ŗå™Øļ¼ŒęŒ‡ē¤ŗę“»åŠØē¼–č¾‘å™Øę˜Æå¦ę›“ę–°", "separator": "äø€äøŖę”ä»¶åˆ†éš”ē¬¦(\"-\")ļ¼Œä»…åœØå·¦å³ę˜Æå…·ęœ‰å€¼ēš„å˜é‡ę—¶ę‰ę˜¾ē¤ŗ", diff --git a/i18n/chs/extensions/css/package.i18n.json b/i18n/chs/extensions/css/package.i18n.json index f5b62deb389..6b34f395c3d 100644 --- a/i18n/chs/extensions/css/package.i18n.json +++ b/i18n/chs/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "å‚ę•°ę•°é‡ę— ę•ˆ", "css.lint.boxModel.desc": "ä½æē”Øč¾¹č·ęˆ–č¾¹ę”†ę—¶ļ¼Œäøč¦ä½æē”Øå®½åŗ¦ęˆ–é«˜åŗ¦", "css.lint.compatibleVendorPrefixes.desc": "ä½æē”Øä¾›åŗ”å•†ē‰¹å®šå‰ē¼€ę—¶ļ¼Œē”®äæåŒę—¶åŒ…ę‹¬ę‰€ęœ‰å…¶ä»–ä¾›åŗ”å•†ē‰¹å®šå±žę€§", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "ęœŖēŸ„ēš„ä¾›åŗ”å•†ē‰¹å®šå±žę€§ć€‚", "css.lint.vendorPrefix.desc": "ä½æē”Øä¾›åŗ”å•†ē‰¹å®šå‰ē¼€ę—¶ļ¼Œčæ˜åŗ”åŒ…ę‹¬ę ‡å‡†å±žę€§", "css.lint.zeroUnits.desc": "é›¶äøéœ€č¦å•ä½", + "css.trace.server.desc": "跟踪 VS Code äøŽ CSS čÆ­čØ€ęœåŠ”å™Øä¹‹é—“ēš„é€šäæ”ć€‚", + "css.validate.title": "ęŽ§åˆ¶ CSS éŖŒčÆå’Œé—®é¢˜äø„é‡ę€§ć€‚", "css.validate.desc": "åÆē”Øęˆ–ē¦ē”Øę‰€ęœ‰éŖŒčÆ", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "å‚ę•°ę•°é‡ę— ę•ˆ", "less.lint.boxModel.desc": "ä½æē”Øč¾¹č·ęˆ–č¾¹ę”†ę—¶ļ¼Œäøč¦ä½æē”Øå®½åŗ¦ęˆ–é«˜åŗ¦", "less.lint.compatibleVendorPrefixes.desc": "ä½æē”Øä¾›åŗ”å•†ē‰¹å®šå‰ē¼€ę—¶ļ¼Œē”®äæåŒę—¶åŒ…ę‹¬ę‰€ęœ‰å…¶ä»–ä¾›åŗ”å•†ē‰¹å®šå±žę€§", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "ęœŖēŸ„ēš„ä¾›åŗ”å•†ē‰¹å®šå±žę€§ć€‚", "less.lint.vendorPrefix.desc": "ä½æē”Øä¾›åŗ”å•†ē‰¹å®šå‰ē¼€ę—¶ļ¼Œčæ˜åŗ”åŒ…ę‹¬ę ‡å‡†å±žę€§", "less.lint.zeroUnits.desc": "é›¶äøéœ€č¦å•ä½", + "less.validate.title": "ęŽ§åˆ¶ LESS éŖŒčÆå’Œé—®é¢˜äø„é‡ę€§ć€‚", "less.validate.desc": "åÆē”Øęˆ–ē¦ē”Øę‰€ęœ‰éŖŒčÆ", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "å‚ę•°ę•°é‡ę— ę•ˆ", "scss.lint.boxModel.desc": "ä½æē”Øč¾¹č·ęˆ–č¾¹ę”†ę—¶ļ¼Œäøč¦ä½æē”Øå®½åŗ¦ęˆ–é«˜åŗ¦", "scss.lint.compatibleVendorPrefixes.desc": "ä½æē”Øä¾›åŗ”å•†ē‰¹å®šå‰ē¼€ę—¶ļ¼Œē”®äæåŒę—¶åŒ…ę‹¬ę‰€ęœ‰å…¶ä»–ä¾›åŗ”å•†ē‰¹å®šå±žę€§", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "ęœŖēŸ„ēš„ä¾›åŗ”å•†ē‰¹å®šå±žę€§ć€‚", "scss.lint.vendorPrefix.desc": "ä½æē”Øä¾›åŗ”å•†ē‰¹å®šå‰ē¼€ę—¶ļ¼Œčæ˜åŗ”åŒ…ę‹¬ę ‡å‡†å±žę€§", "scss.lint.zeroUnits.desc": "é›¶äøéœ€č¦å•ä½", + "scss.validate.title": "ęŽ§åˆ¶ SCSS éŖŒčÆå’Œé—®é¢˜äø„é‡ę€§ć€‚", "scss.validate.desc": "åÆē”Øęˆ–ē¦ē”Øę‰€ęœ‰éŖŒčÆ", "less.colorDecorators.enable.desc": "åÆē”Øęˆ–ē¦ē”Øé¢œč‰²äæ®é„°å™Ø", "scss.colorDecorators.enable.desc": "åÆē”Øęˆ–ē¦ē”Øé¢œč‰²äæ®é„°å™Ø", - "css.colorDecorators.enable.desc": "åÆē”Øęˆ–ē¦ē”Øé¢œč‰²äæ®é„°å™Ø" + "css.colorDecorators.enable.desc": "åÆē”Øęˆ–ē¦ē”Øé¢œč‰²äæ®é„°å™Ø", + "css.colorDecorators.enable.deprecationMessage": "å·²å¼ƒē”Øč®¾ē½® \"css.colorDecorators.enabl\"ļ¼ŒčÆ·ę”¹ē”Ø \"editor.colorDecorators\"怂", + "scss.colorDecorators.enable.deprecationMessage": "å·²å¼ƒē”Øč®¾ē½® \"scss.colorDecorators.enable\"ļ¼ŒčÆ·ę”¹ē”Ø \"editor.colorDecorators\"怂", + "less.colorDecorators.enable.deprecationMessage": "å·²å¼ƒē”Øč®¾ē½® \"less.colorDecorators.enable\"ļ¼ŒčÆ·ę”¹ē”Ø \"editor.colorDecorators\"怂" } \ No newline at end of file diff --git a/i18n/chs/extensions/emmet/package.i18n.json b/i18n/chs/extensions/emmet/package.i18n.json index a6d0d75c963..c956f42aa07 100644 --- a/i18n/chs/extensions/emmet/package.i18n.json +++ b/i18n/chs/extensions/emmet/package.i18n.json @@ -4,9 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "ä½æē”Øē¼©å†™åŒ…å›“", + "command.wrapIndividualLinesWithAbbreviation": "č¾“å…„ē¼©å†™åŒ…å›“äøŖåˆ«č”Œ", "command.removeTag": "移除标签", "command.updateTag": "曓新标签", "command.matchTag": "č½¬č‡³åŒ¹é…åÆ¹", + "command.balanceIn": "平蔔(向内)", + "command.balanceOut": "平蔔(向外)", "command.prevEditPoint": "č½¬åˆ°äøŠäø€ē¼–č¾‘ē‚¹", "command.nextEditPoint": "č½¬åˆ°äø‹äø€ē¼–č¾‘ē‚¹", "command.mergeLines": "合并蔌", @@ -22,5 +26,28 @@ "command.incrementNumberByOneTenth": "增加 0.1", "command.decrementNumberByOneTenth": "减少 0.1", "command.incrementNumberByTen": "增加 10", - "command.decrementNumberByTen": "减少 10" + "command.decrementNumberByTen": "减少 10", + "emmetSyntaxProfiles": "äøŗęŒ‡å®šēš„čÆ­ę³•å®šä¹‰é…ē½®ę–‡ä»¶ęˆ–ä½æē”Øåø¦ęœ‰ē‰¹å®šč§„åˆ™ēš„é…ē½®ę–‡ä»¶ć€‚", + "emmetExclude": "äøåŗ”å±•å¼€ Emmet ē¼©å†™ēš„čÆ­čØ€ę•°ē»„ć€‚", + "emmetExtensionsPath": "包含 Emmet é…ē½®ę–‡ä»¶äøŽä»£ē ē‰‡ę®µēš„ę–‡ä»¶å¤¹č·Æå¾„ć€‚", + "emmetShowExpandedAbbreviation": "åœØå»ŗč®®äø­ę˜¾ē¤ŗå±•å¼€ēš„ Emmet 缩写。\n选ꋩ \"inMarkupAndStylesheetFilesOnly\" é€‰é”¹å°†ä»…åŗ”ē”ØäŗŽ html态haml态jade态slim态xml态xsl态css态scss态sass态lessĀ å’Œ stylus ꖇ件怂\n选ꋩ \"always\" é€‰é”¹å°†åŗ”ē”ØäŗŽę‰€ęœ‰é€‚ē”Øę–‡ä»¶äøé™äŗŽę ‡č®°ęˆ– CSS ēš„ę‰€ęœ‰éƒØåˆ†ć€‚", + "emmetShowAbbreviationSuggestions": "ę˜¾ē¤ŗåÆčƒ½ēš„ Emmet ē¼©å†™ä½œäøŗå»ŗč®®ć€‚åœØę ·å¼č”Øäø­ęˆ–å½“ emmet.showExpandedAbbreviation 设置为 \"never\" ę—¶äøé€‚ē”Øć€‚", + "emmetIncludeLanguages": "åœØé»˜č®¤äøę”ÆęŒ Emmet ēš„čÆ­čØ€äø­åÆē”Ø Emmet ē¼©å†™åŠŸčƒ½ć€‚åœØę­¤ę·»åŠ čÆ„čÆ­čØ€äøŽę”ÆęŒ Emmet ēš„čÆ­čØ€ä¹‹é—“ēš„ę˜ å°„ć€‚\n示例: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "ē”ØäŗŽ Emmet ä»£ē ē‰‡ę®µēš„å˜é‡", + "emmetTriggerExpansionOnTab": "åÆē”ØåŽļ¼ŒęŒ‰äø‹ TAB é”®ļ¼Œå°†å±•å¼€ Emmet 缩写。", + "emmetPreferences": "ē”ØäŗŽäæ®ę”¹ Emmet ęŸäŗ›ę“ä½œå’Œč§£ęžēØ‹åŗēš„č”Œäøŗēš„é¦–é€‰é”¹ć€‚", + "emmetPreferencesIntUnit": "ę•“ę•°å€¼ēš„é»˜č®¤å•ä½", + "emmetPreferencesFloatUnit": "ęµ®ē‚¹ę•°å€¼ēš„é»˜č®¤å•ä½", + "emmetPreferencesCssAfter": "展开 CSS ē¼©å†™ę—¶åœØ CSS å±žę€§ęœ«å°¾ę”¾ē½®ēš„ē¬¦å·", + "emmetPreferencesSassAfter": "在 Sass 文件中展开 CSS ē¼©å†™ę—¶åœØ CSS å±žę€§ęœ«å°¾ę”¾ē½®ēš„ē¬¦å·", + "emmetPreferencesStylusAfter": "在 Stylus 文件中展开 CSS ē¼©å†™ę—¶åœØ CSS å±žę€§ęœ«å°¾ę”¾ē½®ēš„ē¬¦å·", + "emmetPreferencesCssBetween": "展开 CSS ē¼©å†™ę—¶åœØ CSS å±žę€§ä¹‹é—“ę”¾ē½®ēš„ē¬¦å·", + "emmetPreferencesSassBetween": "在 Sass 文件中展开 CSS ē¼©å†™ę—¶åœØ CSS å±žę€§ä¹‹é—“ę”¾ē½®ēš„ē¬¦å·", + "emmetPreferencesStylusBetween": "在 Stylus 文件中展开 CSS ē¼©å†™ę—¶åœØ CSS å±žę€§ä¹‹é—“ę”¾ē½®ēš„ē¬¦å·", + "emmetShowSuggestionsAsSnippets": "č‹„äøŗ \"true\",Emmet å»ŗč®®å°†ę˜¾ē¤ŗäøŗä»£ē ē‰‡ę®µć€‚ä½ åÆä»„åœØ editor.snippetSuggestions č®¾ē½®äø­ęŽ’åˆ—é”ŗåŗć€‚", + "emmetPreferencesBemElementSeparator": "åœØä½æē”Ø BEM čæ‡ę»¤å™Øę—¶ļ¼Œē±»åä½æē”Øēš„å…ƒē“ åˆ†éš”ē¬¦", + "emmetPreferencesBemModifierSeparator": "åœØä½æē”Ø BEM čæ‡ę»¤å™Øę—¶ļ¼Œē±»åä½æē”Øēš„äæ®é„°ē¬¦åˆ†éš”ē¬¦", + "emmetPreferencesFilterCommentBefore": "ä½æē”Øę³Øé‡Ščæ‡ę»¤å™Øę—¶ļ¼Œåŗ”ē½®äŗŽåŒ¹é…å…ƒē“ å‰ę³Øé‡Šēš„å®šä¹‰ć€‚", + "emmetPreferencesFilterCommentAfter": "ä½æē”Øę³Øé‡Ščæ‡ę»¤å™Øę—¶ļ¼Œåŗ”ē½®äŗŽåŒ¹é…å…ƒē“ åŽę³Øé‡Šēš„å®šä¹‰ć€‚", + "emmetPreferencesFilterCommentTrigger": "ē”ØåŠč§’é€—å· (\",\") éš”å¼€ēš„å±žę€§åē¼©å†™ēš„ę•°ē»„ļ¼Œå°†ē”±ę³Øé‡Šē­›é€‰å™Øåŗ”ē”Ø" } \ No newline at end of file diff --git a/i18n/chs/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/chs/extensions/extension-editing/out/extensionLinter.i18n.json index f7e87a0d561..6e684ea67b0 100644 --- a/i18n/chs/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/chs/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "å›¾åƒåæ…é”»ä½æē”Ø HTTPS åč®®ć€‚", "svgsNotValid": "SVG äøę˜Æęœ‰ę•ˆēš„å›¾åƒęŗć€‚", "embeddedSvgsNotValid": "åµŒå…„ēš„ SVG äøę˜Æęœ‰ę•ˆēš„å›¾åƒęŗć€‚", - "dataUrlsNotValid": "ę•°ę® URL äøę˜Æęœ‰ę•ˆēš„å›¾åƒęŗć€‚" + "dataUrlsNotValid": "ę•°ę® URL äøę˜Æęœ‰ę•ˆēš„å›¾åƒęŗć€‚", + "relativeUrlRequiresHttpsRepository": "相关 URL č¦ę±‚åœØ package.json äø­ęŒ‡å®šä½æē”Ø HTTPSĀ åč®®ēš„å­˜å‚Øåŗ“ć€‚", + "relativeIconUrlRequiresHttpsRepository": "å›¾ę ‡č¦ę±‚åœØę­¤ package.json äø­ęŒ‡å®šä½æē”Ø HTTPS åč®®ēš„å­˜å‚Øåŗ“ć€‚", + "relativeBadgeUrlRequiresHttpsRepository": "相对徽章 URL č¦ę±‚åœØ package.json äø­ęŒ‡å®šä½æē”Ø HTTPS åč®®ēš„å­˜å‚Øåŗ“ć€‚" } \ No newline at end of file diff --git a/i18n/chs/extensions/git/out/commands.i18n.json b/i18n/chs/extensions/git/out/commands.i18n.json index 5aebef2e00e..ac60b0720fb 100644 --- a/i18n/chs/extensions/git/out/commands.i18n.json +++ b/i18n/chs/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "ę­£åœØå…‹éš† GIT å­˜å‚Øåŗ“...", "openrepo": "ę‰“å¼€å­˜å‚Øåŗ“", "proposeopen": "ę˜Æå¦č¦ę‰“å¼€å·²å…‹éš†å­˜å‚Øåŗ“?", + "init repo": "åˆå§‹åŒ–å­˜å‚Øåŗ“", + "create repo": "åˆå§‹åŒ–å­˜å‚Øåŗ“", + "are you sure": "å°†åœØā€œ{0}ā€äø­åˆ›å»ŗ Git å­˜å‚Øåŗ“ć€‚ē”®å®šč¦ē»§ē»­å—ļ¼Ÿ", "HEAD not available": "ā€œ{0}ā€ēš„ HEAD ē‰ˆęœ¬äøåÆē”Øć€‚", + "confirm stage files with merge conflicts": "ē”®å®šč¦ęš‚å­˜å«ęœ‰åˆå¹¶å†²ēŖēš„ {0} 个文件吗?", + "confirm stage file with merge conflicts": "ē”®å®šč¦ęš‚å­˜å«ęœ‰åˆå¹¶å†²ēŖēš„ {0} 吗?", + "yes": "是", "confirm revert": "ę˜Æå¦ē”®å®žč¦čæ˜åŽŸ {0} äø­ēš„å·²é€‰ę›“ę”¹?", "revert": "čæ˜åŽŸę›“ę”¹", + "discard": "ę”¾å¼ƒę›“ę”¹", + "confirm delete": "ę˜Æå¦ē”®å®šč¦åˆ é™¤ {0}?", + "delete file": "åˆ é™¤ę–‡ä»¶", "confirm discard": "ē”®å®šč¦ę”¾å¼ƒ {0} 中曓改吗?", "confirm discard multiple": "ę˜Æå¦ē”®å®žč¦ę”¾å¼ƒ {0} ę–‡ä»¶äø­ēš„ę›“ę”¹?", - "discard": "ę”¾å¼ƒę›“ę”¹", - "confirm discard all": "ē”®å®šč¦ę”¾å¼ƒę‰€ęœ‰ę›“ę”¹å—ļ¼Ÿę­¤ę“ä½œäøåÆę’¤é”€ļ¼", - "discardAll": "ę”¾å¼ƒę‰€ęœ‰ę›“ę”¹", + "warn untracked": "čæ™å°†åˆ é™¤ {0} äøŖęœŖč·ŸčøŖēš„ę–‡ä»¶!", + "confirm discard all single": "ē”®å®šč¦ę”¾å¼ƒ {0} 中曓改吗?", + "confirm discard all": "ē”®å®šč¦ę”¾å¼ƒåœØ {0} äøŖę–‡ä»¶äø­ēš„ę‰€ęœ‰ę›“ę”¹å—ļ¼Ÿ\nę­¤ę“ä½œäøåÆę’¤é”€!\nä½ å½“å‰ēš„å·„ä½œé›†å°†ä¼šę°øčæœäø¢å¤±ć€‚", + "discardAll multiple": "ę”¾å¼ƒ 1 个文件", + "discardAll": "ę”¾å¼ƒę‰€ęœ‰ {0} 个文件", + "confirm delete multiple": "ę˜Æå¦ē”®å®šč¦åˆ é™¤ {0} 个文件?", + "delete files": "åˆ é™¤ę–‡ä»¶", + "there are untracked files single": "č‹„ę”¾å¼ƒäø‹é¢ęœŖč·ŸčøŖēš„ę–‡ä»¶ļ¼Œå…¶å°†č¢«ä»Žē”¬ē›˜äøŠåˆ é™¤: {0}怂", + "there are untracked files": "č‹„ę”¾å¼ƒ {0} äøŖęœŖč·ŸčøŖēš„ę–‡ä»¶ļ¼Œå…¶å°†č¢«ä»Žē”¬ē›˜äøŠåˆ é™¤ć€‚", + "confirm discard all 2": "{0}\n\nę­¤ę“ä½œäøåÆę’¤é”€ļ¼Œä½ å½“å‰ēš„å·„ä½œé›†å°†ä¼šę°øčæœäø¢å¤±ć€‚", + "yes discard tracked": "ę”¾å¼ƒ 1 äøŖå·²č·ŸčøŖēš„ę–‡ä»¶", + "yes discard tracked multiple": "ę”¾å¼ƒ {0} äøŖå·²č·ŸčøŖēš„ę–‡ä»¶", "no staged changes": "ēŽ°åœØę²”ęœ‰ęš‚å­˜ēš„ę›“ę”¹ä»„ä¾›ęäŗ¤\n\nę˜Æå¦č¦ē›“ęŽ„č‡ŖåŠØęš‚å­˜ę‰€ęœ‰ę›“ę”¹å¹¶ęäŗ¤ļ¼Ÿ", - "yes": "是", "always": "å§‹ē»ˆ", "no changes": "ę²”ęœ‰č¦ęäŗ¤ēš„ę›“ę”¹ć€‚", "commit message": "ęäŗ¤ę¶ˆęÆ", @@ -34,16 +51,25 @@ "delete branch": "åˆ é™¤åˆ†ę”Æ", "select a branch to merge from": "é€‰ę‹©č¦ä»Žå…¶åˆå¹¶ēš„åˆ†ę”Æ", "merge conflicts": "å­˜åœØåˆå¹¶å†²ēŖć€‚čÆ·åœØęäŗ¤ä¹‹å‰č§£å†³čæ™äŗ›å†²ēŖć€‚", + "tag name": "ę ‡ē­¾åē§°", + "provide tag name": "čÆ·ęä¾›ę ‡ē­¾åē§°", + "tag message": "消息", + "provide tag message": "čÆ·ęä¾›ę¶ˆęÆä»„åÆ¹ę ‡ē­¾čæ›č”Œę³Øé‡Š", "no remotes to pull": "å­˜å‚Øåŗ“ęœŖé…ē½®ä»»ä½•ä»Žå…¶äø­čæ›č”Œę‹‰å–ēš„čæœēØ‹å­˜å‚Øåŗ“ć€‚", "pick remote pull repo": "é€‰ę‹©č¦ä»Žå…¶ę‹‰å–åˆ†ę”Æēš„čæœēØ‹ä½ē½®", "no remotes to push": "å­˜å‚Øåŗ“ęœŖé…ē½®ä»»ä½•č¦ęŽØé€åˆ°ēš„čæœēØ‹å­˜å‚Øåŗ“ć€‚", + "push with tags success": "å·²ęˆåŠŸåø¦ę ‡ē­¾čæ›č”ŒęŽØé€ć€‚", "nobranch": "čÆ·ē­¾å‡ŗäø€äøŖåˆ†ę”Æä»„ęŽØé€åˆ°čæœēØ‹ć€‚", "pick remote": "é€‰å–č¦å°†åˆ†ę”Æā€œ{0}ā€å‘åøƒåˆ°ēš„čæœēØ‹:", - "sync is unpredictable": "ę­¤ę“ä½œä»Žā€œ{0}ā€ęŽØé€å’Œę‹‰å–ęäŗ¤ć€‚", + "sync is unpredictable": "ę­¤ę“ä½œå°†ęŽØé€ęäŗ¤č‡³ā€œ{0}ā€ļ¼Œå¹¶ä»Žäø­ę‹‰å–ęäŗ¤ć€‚", "ok": "甮定", "never again": "å„½ļ¼Œę°øäøå†ę˜¾ē¤ŗ", "no remotes to publish": "å­˜å‚Øåŗ“ęœŖé…ē½®ä»»ä½•č¦å‘åøƒåˆ°ēš„čæœēØ‹å­˜å‚Øåŗ“ć€‚", - "disabled": "ę­¤å·„ä½œåŒŗå·²ē¦ē”Øęˆ–äøę”ÆęŒ GIT", + "no changes stash": "ę²”ęœ‰č¦å‚Øč—ēš„ę›“ę”¹ć€‚", + "provide stash message": "ęä¾›å‚Øč—ę¶ˆęÆ(åÆé€‰)", + "stash message": "å‚Øč—ę¶ˆęÆ", + "no stashes": "ę²”ęœ‰åÆä»„ę¢å¤ēš„å­˜å‚Øć€‚", + "pick stash to pop": "é€‰ę‹©č¦å¼¹å‡ŗēš„å‚Øč—", "clean repo": "åœØē­¾å‡ŗå‰ļ¼ŒčÆ·ęø…ē†å­˜å‚Øåŗ“å·„ä½œę ‘ć€‚", "cant push": "ę— ę³•ęŽØé€ refs åˆ°čæœē«Æć€‚čÆ·å…ˆčæč”Œā€œę‹‰å–ā€åŠŸčƒ½ä»„ę•“åˆä½ ēš„ę›“ę”¹ć€‚", "git error details": "Git:{0}", diff --git a/i18n/chs/extensions/git/out/model.i18n.json b/i18n/chs/extensions/git/out/model.i18n.json index 4ef0b1e6a74..e0223bbb637 100644 --- a/i18n/chs/extensions/git/out/model.i18n.json +++ b/i18n/chs/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "打开", - "merge changes": "åˆå¹¶ę›“ę”¹", - "staged changes": "ęš‚å­˜ēš„ę›“ę”¹", - "changes": "曓改", - "ok": "甮定", - "neveragain": "äøå†ę˜¾ē¤ŗ", - "huge": "Git å­˜å‚Øåŗ“ā€œ{0}ā€äø­å­˜åœØå¤§é‡ę“»åŠØę›“ę”¹ļ¼Œå°†ä»…åÆē”ØéƒØåˆ† Git åŠŸčƒ½ć€‚" + "no repositories": "ę²”ęœ‰åÆē”Øå­˜å‚Øåŗ“", + "pick repo": "é€‰ę‹©å­˜å‚Øåŗ“" } \ No newline at end of file diff --git a/i18n/chs/extensions/git/out/repository.i18n.json b/i18n/chs/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..8b700b3abe3 --- /dev/null +++ b/i18n/chs/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "打开", + "index modified": "已修改瓢引", + "modified": "已修改", + "index added": "å·²ę·»åŠ ē“¢å¼•", + "index deleted": "å·²åˆ é™¤ē“¢å¼•", + "deleted": "已删除", + "index renamed": "å·²é‡å‘½åē“¢å¼•", + "index copied": "å·²å¤åˆ¶ē“¢å¼•", + "untracked": "ęœŖč·ŸčøŖēš„", + "ignored": "已忽畄", + "both deleted": "äø¤č€…å‡å·²åˆ é™¤", + "added by us": "å·²ē”±ęˆ‘ä»¬ę·»åŠ ", + "deleted by them": "å·²č¢«ä»–ä»¬åˆ é™¤", + "added by them": "å·²ē”±ä»–ä»¬ę·»åŠ ", + "deleted by us": "å·²č¢«ęˆ‘ä»¬åˆ é™¤", + "both added": "äø¤č€…å‡å·²ę·»åŠ ", + "both modified": "äŗŒč€…å‡å·²äæ®ę”¹", + "commit": "ęäŗ¤", + "merge changes": "åˆå¹¶ę›“ę”¹", + "staged changes": "ęš‚å­˜ēš„ę›“ę”¹", + "changes": "曓改", + "ok": "甮定", + "neveragain": "äøå†ę˜¾ē¤ŗ", + "huge": "Git å­˜å‚Øåŗ“ā€œ{0}ā€äø­å­˜åœØå¤§é‡ę“»åŠØę›“ę”¹ļ¼Œå°†ä»…åÆē”ØéƒØåˆ† Git åŠŸčƒ½ć€‚" +} \ No newline at end of file diff --git a/i18n/chs/extensions/git/package.i18n.json b/i18n/chs/extensions/git/package.i18n.json index a4e031e5adb..7e5710c9d9f 100644 --- a/i18n/chs/extensions/git/package.i18n.json +++ b/i18n/chs/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "克隆", "command.init": "åˆå§‹åŒ–å­˜å‚Øåŗ“", + "command.close": "å…³é—­å­˜å‚Øåŗ“", "command.refresh": "åˆ·ę–°", "command.openChange": "打开曓改", "command.openFile": "打开文件", @@ -14,6 +15,8 @@ "command.stageAll": "ęš‚å­˜ę‰€ęœ‰ę›“ę”¹", "command.stageSelectedRanges": "ęš‚å­˜ę‰€é€‰čŒƒå›“", "command.revertSelectedRanges": "čæ˜åŽŸę‰€é€‰ę›“ę”¹", + "command.stageChange": "ęš‚å­˜ę›“ę”¹", + "command.revertChange": "čæ˜åŽŸę›“ę”¹", "command.unstage": "å–ę¶ˆęš‚å­˜ę›“ę”¹", "command.unstageAll": "å–ę¶ˆęš‚å­˜ę‰€ęœ‰ę›“ę”¹", "command.unstageSelectedRanges": "å–ę¶ˆęš‚å­˜ę‰€é€‰čŒƒå›“", @@ -22,22 +25,29 @@ "command.commit": "Commit", "command.commitStaged": "ęäŗ¤å·²ęš‚å­˜ę–‡ä»¶", "command.commitStagedSigned": "ęäŗ¤å·²ęš‚å­˜ę–‡ä»¶(å·²ē­¾å)", + "command.commitStagedAmend": "å·²ęš‚å­˜ęäŗ¤(修改)", "command.commitAll": "å…ØéƒØęäŗ¤", "command.commitAllSigned": "å…ØéƒØęäŗ¤(å·²ē­¾å)", + "command.commitAllAmend": "å…ØéƒØęäŗ¤(修改)", "command.undoCommit": "ę’¤ę¶ˆäøŠę¬”ęäŗ¤", "command.checkout": "ē­¾å‡ŗåˆ°...", "command.branch": "åˆ›å»ŗåˆ†ę”Æ...", "command.deleteBranch": "åˆ é™¤åˆ†ę”Æ...", "command.merge": "åˆå¹¶åˆ†ę”Æ...", + "command.createTag": "åˆ›å»ŗę ‡ē­¾", "command.pull": "ę‹‰å–", "command.pullRebase": "ę‹‰å–(å˜åŸŗ)", "command.pullFrom": "ę‹‰å–č‡Ŗ...", "command.push": "ęŽØé€", "command.pushTo": "ęŽØé€åˆ°...", + "command.pushWithTags": "åø¦ę ‡ē­¾ęŽØé€", "command.sync": "同歄", "command.publish": "å‘åøƒåˆ†ę”Æ", "command.showOutput": "显示 GIT 输出", "command.ignore": "å°†ę–‡ä»¶ę·»åŠ åˆ° .gitignore", + "command.stash": "å‚Øč—", + "command.stashPop": "å¼¹å‡ŗå‚Øč—...", + "command.stashPopLatest": "å¼¹å‡ŗęœ€ę–°å‚Øč—", "config.enabled": "ę˜Æå¦å·²åÆē”Ø GIT", "config.path": "Git åÆę‰§č”Œę–‡ä»¶č·Æå¾„", "config.autorefresh": "ę˜Æå¦å·²åÆē”Øč‡ŖåŠØåˆ·ę–°", @@ -45,9 +55,11 @@ "config.enableLongCommitWarning": "ę˜Æå¦é’ˆåÆ¹é•æę®µęäŗ¤ę¶ˆęÆčæ›č”Œč­¦å‘Š", "config.confirmSync": "同歄 Git å­˜å‚Øåŗ“å‰čæ›č”Œē”®č®¤", "config.countBadge": "ęŽ§åˆ¶ Git å¾½ē« č®”ę•°å™Øć€‚ā€œallā€č®”ē®—ę‰€ęœ‰ę›“ę”¹ć€‚ā€œtrackedā€åŖč®”ē®—č·ŸčøŖēš„ę›“ę”¹ć€‚ā€œoffā€å…³é—­ę­¤åŠŸčƒ½ć€‚", - "config.checkoutType": "ęŽ§åˆ¶čæč”Œā€œē­¾å‡ŗåˆ°...ā€ę—¶åˆ—å‡ŗēš„åˆ†ę”Æēš„ē±»åž‹ć€‚ā€œallā€ę˜¾ē¤ŗę‰€ęœ‰ refsļ¼Œā€œlocalā€åŖę˜¾ē¤ŗęœ¬åœ°åˆ†ę”Æļ¼Œā€œtagsā€åŖę˜¾ē¤ŗę ‡ē­¾ļ¼Œā€œremoteā€åŖę˜¾ē¤ŗčæœēØ‹åˆ†ę”Æć€‚", + "config.checkoutType": "ęŽ§åˆ¶čæč”Œā€œē­¾å‡ŗåˆ°...ā€å‘½ä»¤ę—¶åˆ—å‡ŗēš„åˆ†ę”Æēš„ē±»åž‹ć€‚\"all\" ę˜¾ē¤ŗę‰€ęœ‰ refs,\"local\" åŖę˜¾ē¤ŗęœ¬åœ°åˆ†ę”Æļ¼Œ\"tags\" åŖę˜¾ē¤ŗę ‡č®°ļ¼Œ\"remote\" åŖę˜¾ē¤ŗčæœēØ‹åˆ†ę”Æć€‚", "config.ignoreLegacyWarning": "åæ½ē•„ę—§ē‰ˆ Git č­¦å‘Š", "config.ignoreLimitWarning": "åæ½ē•„ā€œå­˜å‚Øåŗ“äø­å­˜åœØå¤§é‡ę›“ę”¹ā€ēš„č­¦å‘Š", "config.defaultCloneDirectory": "克隆 Git å­˜å‚Øåŗ“ēš„é»˜č®¤ä½ē½®", - "config.enableSmartCommit": "åœØę²”ęœ‰ęš‚å­˜ēš„ę›“ę”¹ę—¶ęäŗ¤ę‰€ęœ‰ę›“ę”¹ć€‚" + "config.enableSmartCommit": "åœØę²”ęœ‰ęš‚å­˜ēš„ę›“ę”¹ę—¶ęäŗ¤ę‰€ęœ‰ę›“ę”¹ć€‚", + "config.enableCommitSigning": "启用使用 GPG ē­¾åēš„ęäŗ¤", + "config.discardAllScope": "ęŽ§åˆ¶čæč”Œā€œę”¾å¼ƒę‰€ęœ‰ę›“ę”¹ā€å‘½ä»¤ę—¶ę”¾å¼ƒēš„ę›“ę”¹ē±»åž‹ć€‚\"all\" ę”¾å¼ƒę‰€ęœ‰ę›“ę”¹ć€‚\"tracked\" åŖę”¾å¼ƒč·ŸčøŖēš„ę–‡ä»¶ć€‚\"prompt\" č”Øē¤ŗåœØęÆę¬”čæč”Œę­¤ę“ä½œę—¶ę˜¾ē¤ŗęē¤ŗåÆ¹čÆę”†ć€‚" } \ No newline at end of file diff --git a/i18n/chs/extensions/grunt/out/main.i18n.json b/i18n/chs/extensions/grunt/out/main.i18n.json index 6f111606a09..70515dd5f8c 100644 --- a/i18n/chs/extensions/grunt/out/main.i18n.json +++ b/i18n/chs/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "č‡ŖåŠØę£€ęµ‹ Grunt å¤±č“„ļ¼Œé”™čÆÆļ¼š{0}" + "execFailed": "åœØę–‡ä»¶å¤¹ {0} äø­č‡ŖåŠØę£€ęµ‹ Grunt å¤±č“„ļ¼Œé”™čÆÆ: {1}" } \ No newline at end of file diff --git a/i18n/chs/extensions/gulp/out/main.i18n.json b/i18n/chs/extensions/gulp/out/main.i18n.json index bda8a250c25..1fa76c74238 100644 --- a/i18n/chs/extensions/gulp/out/main.i18n.json +++ b/i18n/chs/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "č‡ŖåŠØę£€ęµ‹ gulp å¤±č“„ļ¼Œé”™čÆÆļ¼š{0}" + "execFailed": "åœØę–‡ä»¶å¤¹ {0} äø­č‡ŖåŠØę£€ęµ‹ gulp å¤±č“„ļ¼Œé”™čÆÆ: {1}" } \ No newline at end of file diff --git a/i18n/chs/extensions/html/package.i18n.json b/i18n/chs/extensions/html/package.i18n.json index 054fbfdac59..61c50847e23 100644 --- a/i18n/chs/extensions/html/package.i18n.json +++ b/i18n/chs/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "启用/ē¦ē”Øé»˜č®¤ HTML ę ¼å¼åŒ–ēØ‹åŗ(éœ€č¦é‡åÆ)", + "html.format.enable.desc": "启用/ē¦ē”Øé»˜č®¤ HTML ę ¼å¼åŒ–ēØ‹åŗ", "html.format.wrapLineLength.desc": "ęÆč”Œęœ€å¤§å­—ē¬¦ę•°(0 = 禁用)怂", "html.format.unformatted.desc": "ä»„é€—å·åˆ†éš”ēš„ę ‡č®°åˆ—č”Øäøåŗ”é‡č®¾ę ¼å¼ć€‚\"null\" é»˜č®¤äøŗę‰€ęœ‰åˆ—äŗŽ https://www.w3.org/TR/html5/dom.html#phrasing-content ēš„ę ‡č®°ć€‚", "html.format.contentUnformatted.desc": "ä»„é€—å·åˆ†éš”ēš„ę ‡č®°åˆ—č”Øļ¼Œäøåŗ”åœØå…¶äø­é‡ę–°č®¾ē½®å†…å®¹ēš„ę ¼å¼ć€‚\"null\" 默认为 \"pre\" ꠇ记怂", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "é…ē½®å†…ē½® HTML čÆ­čØ€ę”ÆęŒę˜Æå¦å»ŗč®® Angular V1 ę ‡č®°å’Œå±žę€§ć€‚", "html.suggest.ionic.desc": "é…ē½®å†…ē½® HTML čÆ­čØ€ę”ÆęŒę˜Æå¦å»ŗč®® Ionic ę ‡č®°ć€å±žę€§å’Œå€¼ć€‚", "html.suggest.html5.desc": "é…ē½®å†…ē½® HTML čÆ­čØ€ę”ÆęŒę˜Æå¦å»ŗč®® HTML5 ę ‡č®°ć€å±žę€§å’Œå€¼ć€‚", + "html.trace.server.desc": "跟踪 VS Code äøŽ HTML čÆ­čØ€ęœåŠ”å™Øä¹‹é—“ēš„é€šäæ”ć€‚", "html.validate.scripts": "é…ē½®å†…ē½®ēš„ HTML čÆ­čØ€ę”ÆęŒę˜Æå¦åÆ¹åµŒå…„ēš„č„šęœ¬čæ›č”ŒéŖŒčÆć€‚", - "html.validate.styles": "é…ē½®å†…ē½®ēš„ HTML čÆ­čØ€ę”ÆęŒę˜Æå¦åÆ¹åµŒå…„ēš„ę ·å¼čæ›č”ŒéŖŒčÆć€‚" + "html.validate.styles": "é…ē½®å†…ē½®ēš„ HTML čÆ­čØ€ę”ÆęŒę˜Æå¦åÆ¹åµŒå…„ēš„ę ·å¼čæ›č”ŒéŖŒčÆć€‚", + "html.autoClosingTags": "启用/禁用 HTML ę ‡č®°ēš„č‡ŖåŠØå…³é—­ć€‚" } \ No newline at end of file diff --git a/i18n/chs/extensions/jake/out/main.i18n.json b/i18n/chs/extensions/jake/out/main.i18n.json index d2f56bdda98..21787a778e5 100644 --- a/i18n/chs/extensions/jake/out/main.i18n.json +++ b/i18n/chs/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "č‡ŖåŠØę£€ęµ‹ Jake å¤±č“„ļ¼Œé”™čÆÆļ¼š{0}" + "execFailed": "åœØę–‡ä»¶å¤¹ {0} äø­č‡ŖåŠØę£€ęµ‹ Jake å¤±č“„ļ¼Œé”™čÆÆ: {1}" } \ No newline at end of file diff --git a/i18n/chs/extensions/json/package.i18n.json b/i18n/chs/extensions/json/package.i18n.json index f147c64ed82..46d90c7f016 100644 --- a/i18n/chs/extensions/json/package.i18n.json +++ b/i18n/chs/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "ē»™å®š URL ēš„ęž¶ęž„å®šä¹‰ć€‚åŖéœ€ęä¾›čÆ„ęž¶ęž„ä»„éæå…åÆ¹ęž¶ęž„ URL ēš„č®æé—®ć€‚", "json.format.enable.desc": "启用/ē¦ē”Øé»˜č®¤ JSON ę ¼å¼åŒ–ēØ‹åŗ(éœ€č¦é‡åÆ)", "json.tracing.desc": "跟踪 VS Code äøŽ JSON čÆ­čØ€ęœåŠ”å™Øä¹‹é—“ēš„é€šäæ”ć€‚", - "json.colorDecorators.enable.desc": "åÆē”Øęˆ–ē¦ē”Øé¢œč‰²äæ®é„°å™Ø" + "json.colorDecorators.enable.desc": "åÆē”Øęˆ–ē¦ē”Øé¢œč‰²äæ®é„°å™Ø", + "json.colorDecorators.enable.deprecationMessage": "å·²å¼ƒē”Øč®¾ē½® \"json.colorDecorators.enable\"ļ¼ŒčÆ·ę”¹ē”Ø \"editor.colorDecorators\"怂" } \ No newline at end of file diff --git a/i18n/chs/extensions/markdown/out/extension.i18n.json b/i18n/chs/extensions/markdown/out/extension.i18n.json index 111330fed75..c145efb44ed 100644 --- a/i18n/chs/extensions/markdown/out/extension.i18n.json +++ b/i18n/chs/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "ę— ę³•åŠ č½½ā€œmarkdown.stylesā€ļ¼š{0}" + "onPreviewStyleLoadError": "ę— ę³•åŠ č½½ā€œmarkdown.stylesā€ļ¼š{0}", + "previewTitle": "é¢„č§ˆ {0}" } \ No newline at end of file diff --git a/i18n/chs/extensions/markdown/out/security.i18n.json b/i18n/chs/extensions/markdown/out/security.i18n.json index 602d9a27b46..dbe6ce5383f 100644 --- a/i18n/chs/extensions/markdown/out/security.i18n.json +++ b/i18n/chs/extensions/markdown/out/security.i18n.json @@ -4,9 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.strictTitle": "äø„ę ¼ęØ”å¼ļ¼Œä»…č½½å…„å®‰å…Øå†…å®¹ć€‚", - "preview.showPreviewSecuritySelector.currentSelection": "å½“å‰č®¾ē½®", - "preview.showPreviewSecuritySelector.insecureContentTitle": "å…č®øé€ščæ‡ http 载兄内容。", - "preview.showPreviewSecuritySelector.scriptsAndAllContent": "å…č®øę‰€ęœ‰å†…å®¹ļ¼Œę‰§č”Œę‰€ęœ‰č„šęœ¬ć€‚äøęŽØčć€‚", + "strict.title": "äø„ę ¼", + "strict.description": "仅载兄安全内容", + "insecureContent.title": "å…č®øäøå®‰å…Øå†…å®¹", + "insecureContent.description": "å…č®øé€ščæ‡ http 载兄内容", + "disable.title": "禁用", + "disable.description": "å…č®øę‰€ęœ‰å†…å®¹ļ¼Œę‰§č”Œę‰€ęœ‰č„šęœ¬ć€‚äøęŽØč", + "moreInfo.title": "详细俔息", "preview.showPreviewSecuritySelector.title": "é€‰ę‹©ę­¤å·„ä½œåŒŗäø­ Markdown é¢„č§ˆēš„å®‰å…Øč®¾ē½®" } \ No newline at end of file diff --git a/i18n/chs/extensions/markdown/package.i18n.json b/i18n/chs/extensions/markdown/package.i18n.json index d97d7e98507..6576e84f901 100644 --- a/i18n/chs/extensions/markdown/package.i18n.json +++ b/i18n/chs/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "č®¾ē½®ę¢č”Œē¬¦å¦‚ä½•åœØ markdown é¢„č§ˆäø­å‘ˆēŽ°ć€‚å°†å…¶č®¾ē½®äøŗ \"true\" ä¼šäøŗęÆäø€äøŖę–°č”Œåˆ›å»ŗäø€äøŖ
怂", + "markdown.preview.linkify": "在 Markdown é¢„č§ˆäø­åÆē”Øęˆ–ē¦ē”Øå°†ē±»ä¼¼ URL ēš„ę–‡ęœ¬č½¬ę¢äøŗé“¾ęŽ„ć€‚", "markdown.preview.doubleClickToSwitchToEditor.desc": "在 Markdown é¢„č§ˆäø­åŒå‡»åˆ‡ę¢åˆ°ē¼–č¾‘å™Øć€‚", "markdown.preview.fontFamily.desc": "ęŽ§åˆ¶ Markdown é¢„č§ˆäø­ä½æē”Øēš„å­—ä½“ē³»åˆ—ć€‚", "markdown.preview.fontSize.desc": "ęŽ§åˆ¶ Markdown é¢„č§ˆäø­ä½æē”Øēš„å­—å·(ä»„åƒē“ äøŗå•ä½)怂", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "ę‰“å¼€ä¾§č¾¹é¢„č§ˆ", "markdown.showSource.title": "显示源", "markdown.styles.dec": "要在 Markdown é¢„č§ˆäø­ä½æē”Øēš„ CSS ę ·å¼č”Øēš„ URL ęˆ–ęœ¬åœ°č·Æå¾„åˆ—č”Øć€‚ē›øåÆ¹č·Æå¾„č¢«č§£é‡Šäøŗē›øåÆ¹äŗŽčµ„ęŗē®”ē†å™Øäø­ę‰“å¼€ēš„ę–‡ä»¶å¤¹ć€‚å¦‚ęžœę²”ęœ‰ä»»ä½•ę‰“å¼€ēš„ę–‡ä»¶å¤¹ļ¼Œåˆ™ä¼šč¢«č§£é‡Šäøŗē›øåÆ¹äŗŽ Markdown ę–‡ä»¶ēš„ä½ē½®ć€‚ę‰€ęœ‰ēš„ \"\\\" éœ€å†™äøŗ \"\\\\\"怂", - "markdown.showPreviewSecuritySelector.title": "曓改 Markdown é¢„č§ˆå®‰å…Øč®¾ē½®", - "markdown.trace.desc": "对 Markdown ę‰©å±•åÆē”Øč°ƒčÆ•ę—„åæ—č®°å½•ć€‚" + "markdown.showPreviewSecuritySelector.title": "ę›“ę”¹é¢„č§ˆå®‰å…Øč®¾ē½®", + "markdown.trace.desc": "对 Markdown ę‰©å±•åÆē”Øč°ƒčÆ•ę—„åæ—č®°å½•ć€‚", + "markdown.refreshPreview.title": "åˆ·ę–°é¢„č§ˆ" } \ No newline at end of file diff --git a/i18n/chs/extensions/npm/out/main.i18n.json b/i18n/chs/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..11008f170c5 --- /dev/null +++ b/i18n/chs/extensions/npm/out/main.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "npm.parseError": "Npm ä»»åŠ”ę£€ęµ‹: ę— ę³•åˆ†ęžę–‡ä»¶ {0}" +} \ No newline at end of file diff --git a/i18n/chs/extensions/npm/package.i18n.json b/i18n/chs/extensions/npm/package.i18n.json index 32fe908c7bb..13082990df0 100644 --- a/i18n/chs/extensions/npm/package.i18n.json +++ b/i18n/chs/extensions/npm/package.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "config.npm.autoDetect": "ęŽ§åˆ¶č‡ŖåŠØę£€ęµ‹ npm č„šęœ¬ę˜Æå¦ę‰“å¼€ć€‚é»˜č®¤å¼€åÆć€‚", - "config.npm.runSilent": "使用 \"--silent\" é€‰é”¹čæč”Œ npm 命令" + "config.npm.runSilent": "使用 \"--silent\" é€‰é”¹čæč”Œ npm 命令", + "npm.parseError": "Npm ä»»åŠ”ę£€ęµ‹: ę— ę³•åˆ†ęžę–‡ä»¶ {0}" } \ No newline at end of file diff --git a/i18n/chs/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/chs/extensions/typescript/out/features/taskProvider.i18n.json index c64c6550622..d688f5f36e2 100644 --- a/i18n/chs/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/chs/extensions/typescript/out/features/taskProvider.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "buildAndWatchTscLabel": "监视 - {0}", - "buildTscLabel": "ęž„å»ŗ - {0}" + "buildTscLabel": "ęž„å»ŗ - {0}", + "buildAndWatchTscLabel": "监视 - {0}" } \ No newline at end of file diff --git a/i18n/chs/extensions/typescript/out/utils/api.i18n.json b/i18n/chs/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..39fa80741e9 --- /dev/null +++ b/i18n/chs/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "ę— ę•ˆē‰ˆęœ¬" +} \ No newline at end of file diff --git a/i18n/chs/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/chs/extensions/typescript/out/utils/versionPicker.i18n.json index 2f9d184dfef..71a73427ea1 100644 --- a/i18n/chs/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/chs/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "使用 VSCode ēš„ē‰ˆęœ¬", + "useVSCodeVersionOption": "使用 VS Code ēš„ē‰ˆęœ¬", "useWorkspaceVersionOption": "ä½æē”Øå·„ä½œåŒŗē‰ˆęœ¬", "learnMore": "了解详细俔息", "selectTsVersion": "é€‰ę‹©ē”ØäŗŽ JavaScript 和 TypeScript čÆ­čØ€åŠŸčƒ½ēš„ TypeScript ē‰ˆęœ¬" diff --git a/i18n/chs/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/chs/extensions/typescript/out/utils/versionProvider.i18n.json index 3a3d6c19c92..c51e8bf2303 100644 --- a/i18n/chs/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/chs/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "å…¶ä»–åŗ”ē”ØēØ‹åŗ(ä¾‹å¦‚čæč”Œå¼‚åøøēš„ē—…ęÆ’ę£€ęµ‹å·„å…·)已删除 VSCode ēš„ tsserverć€‚čÆ·é‡ę–°å®‰č£… VS Code怂" + "couldNotLoadTsVersion": "ę— ę³•čŽ·å–ę­¤ē›®å½• TypeScript ēš„ē‰ˆęœ¬", + "noBundledServerFound": "VS Code ēš„ tsserver å·²č¢«å…¶ä»–åŗ”ē”ØēØ‹åŗ(ä¾‹å¦‚čæč”Œå¼‚åøøēš„ē—…ęÆ’ę£€ęµ‹å·„å…·)åˆ é™¤ć€‚čÆ·é‡ę–°å®‰č£… VS Code怂" } \ No newline at end of file diff --git a/i18n/chs/extensions/typescript/package.i18n.json b/i18n/chs/extensions/typescript/package.i18n.json index f8529d51524..2c538284454 100644 --- a/i18n/chs/extensions/typescript/package.i18n.json +++ b/i18n/chs/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "å®Œęˆå‡½ę•°ēš„å‚ę•°ē­¾åć€‚", "typescript.tsdk.desc": "ęŒ‡å®šåŒ…å«č¦ä½æē”Øēš„ tsserver 和 lib*.d.ts ę–‡ä»¶ēš„ę–‡ä»¶å¤¹č·Æå¾„ć€‚", - "typescript.disableAutomaticTypeAcquisition": "ē¦ē”Øč‡ŖåŠØčŽ·å–ē±»åž‹ć€‚éœ€č¦ TypeScript >= 2.0.6ļ¼Œå¹¶äø”ę›“ę”¹åŽéœ€č¦é‡åÆć€‚", + "typescript.disableAutomaticTypeAcquisition": "ē¦ē”Øč‡ŖåŠØčŽ·å–ē±»åž‹ć€‚éœ€č¦ TypeScript >= 2.0.6怂", "typescript.tsserver.log": "将 TS ęœåŠ”å™Øēš„ę—„åæ—äæå­˜åˆ°äø€äøŖę–‡ä»¶ć€‚ę­¤ę—„åæ—åÆē”ØäŗŽčÆŠę–­ TS ęœåŠ”å™Øé—®é¢˜ć€‚ę—„åæ—åÆčƒ½åŒ…å«ä½ ēš„é”¹ē›®äø­ēš„ę–‡ä»¶č·Æå¾„ć€ęŗä»£ē å’Œå…¶ä»–åÆčƒ½ę•ę„Ÿēš„äæ”ęÆć€‚", "typescript.tsserver.trace": "åÆ¹å‘é€åˆ° TS ęœåŠ”å™Øēš„ę¶ˆęÆåÆē”Øč·ŸčøŖć€‚ę­¤č·ŸčøŖäæ”ęÆåÆē”ØäŗŽčÆŠę–­ TS ęœåŠ”å™Øé—®é¢˜ć€‚ č·ŸčøŖäæ”ęÆåÆčƒ½åŒ…å«ä½ ēš„é”¹ē›®äø­ēš„ę–‡ä»¶č·Æå¾„ć€ęŗä»£ē å’Œå…¶ä»–åÆčƒ½ę•ę„Ÿēš„äæ”ęÆć€‚", "typescript.validate.enable": "启用/禁用 TypeScript éŖŒčÆć€‚", @@ -44,7 +44,11 @@ "typescript.npm": "ęŒ‡å®šē”ØäŗŽč‡ŖåŠØčŽ·å–ē±»åž‹ēš„ NPM åÆę‰§č”Œę–‡ä»¶ēš„č·Æå¾„ć€‚č¦ę±‚ TypeScript >= 2.3.4怂", "typescript.check.npmIsInstalled": "ę£€ęŸ„ę˜Æå¦å®‰č£…äŗ† NPM ä»„č‡ŖåŠØčŽ·å–ē±»åž‹ć€‚", "javascript.nameSuggestions": "启用/ē¦ē”ØåœØ JavaScript å»ŗč®®åˆ—č”Øäø­åŒ…å«ę–‡ä»¶äø­ēš„å”Æäø€åē§°ć€‚", - "typescript.tsc.autoDetect": "ęŽ§åˆ¶č‡ŖåŠØę£€ęµ‹ tsc ä»»åŠ”ę˜Æå¦ę‰“å¼€ć€‚", + "typescript.tsc.autoDetect": "ęŽ§åˆ¶ tsc ä»»åŠ”ēš„č‡ŖåŠØę£€ęµ‹ć€‚\"off\" å…³é—­ę­¤åŠŸčƒ½ć€‚\"build\" ä»…åˆ›å»ŗå•ę¬”čæč”Œē¼–čÆ‘ä»»åŠ”ć€‚\"watch\" ä»…åˆ›å»ŗē¼–čÆ‘åŠē›‘č§†ä»»åŠ”ć€‚\"on\" åˆ›å»ŗęž„å»ŗåŠē›‘č§†ä»»åŠ”ć€‚é»˜č®¤å€¼äøŗ \"on\"怂", "typescript.problemMatchers.tsc.label": "TypeScript 问题", - "typescript.problemMatchers.tscWatch.label": "TypeScript 问题(č§‚ēœ‹ęØ”å¼)" + "typescript.problemMatchers.tscWatch.label": "TypeScript 问题(č§‚ēœ‹ęØ”å¼)", + "typescript.quickSuggestionsForPaths": "å½“č¾“å…„åÆ¼å…„č·Æå¾„ę—¶åÆē”Øęˆ–ē¦ē”Øåæ«é€Ÿå»ŗč®®ć€‚", + "typescript.locale": "č®¾ē½®ęŠ„å‘Š TypeScript é”™čÆÆę—¶ä½æē”Øēš„åŒŗåŸŸč®¾ē½®ć€‚č¦ę±‚ TypeScript >= 2.6.0ć€‚é»˜č®¤ (\"null\") 将使用 VS Code ēš„åŒŗåŸŸč®¾ē½®ć€‚", + "javascript.implicitProjectConfig.experimentalDecorators": "åÆ¹äøå±žäŗŽä»»ä½•å·„ēØ‹ēš„ JavaScript ę–‡ä»¶åÆē”Øęˆ–ē¦ē”Ø \"experimentalDecorators\" č®¾ē½®ć€‚ēŽ°ęœ‰ēš„ jsconfig.json ꈖ\n tsconfig.json ę–‡ä»¶ä¼šč¦†ē›–ę­¤č®¾ē½®ć€‚č¦ę±‚ TypeScript >=2.3.1怂", + "typescript.autoImportSuggestions.enabled": "åÆē”Øęˆ–ē¦ē”Øč‡ŖåŠØåÆ¼å…„å»ŗč®®ć€‚č¦ę±‚ TypeScript >= 2.6.1" } \ No newline at end of file diff --git a/i18n/chs/src/vs/code/electron-main/menus.i18n.json b/i18n/chs/src/vs/code/electron-main/menus.i18n.json index d020e9b1990..4b3a4e43c6e 100644 --- a/i18n/chs/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/chs/src/vs/code/electron-main/menus.i18n.json @@ -79,7 +79,7 @@ "miSmartSelectShrink": "ē¼©å°é€‰å®ščŒƒå›“(&&S)", "miViewExplorer": "资源箔理器(&&E)", "miViewSearch": "搜瓢(&&S)", - "miViewSCM": "SCM(&&C)", + "miViewSCM": "源代码箔理(&&C)", "miViewDebug": "č°ƒčÆ•(&&D)", "miViewExtensions": "扩展(&&X)", "miToggleOutput": "输出(&&O)", @@ -102,6 +102,7 @@ "miHideActivityBar": "éšč—ę“»åŠØę (&&A)", "miShowActivityBar": "ę˜¾ē¤ŗę“»åŠØę (&&A)", "miToggleWordWrap": "åˆ‡ę¢č‡ŖåŠØę¢č”Œ(&&W)", + "miToggleMinimap": "åˆ‡ę¢å°åœ°å›¾(&&M)", "miToggleRenderWhitespace": "åˆ‡ę¢å‘ˆēŽ°ē©ŗę ¼(&&R)", "miToggleRenderControlCharacters": "åˆ‡ę¢ęŽ§åˆ¶å­—ē¬¦(&&C)", "miZoomIn": "放大(&&Z)", @@ -150,6 +151,10 @@ "mZoom": "缩放", "mBringToFront": "å…ØéƒØē½®äŗŽé”¶å±‚", "miSwitchWindow": "åˆ‡ę¢ēŖ—å£(&&W)...", + "mShowPreviousTab": "ę˜¾ē¤ŗäøŠäø€äøŖé€‰é”¹å”", + "mShowNextTab": "ę˜¾ē¤ŗäø‹äø€äøŖé€‰é”¹å”", + "mMoveTabToNewWindow": "ē§»åŠØę ‡ē­¾é”µåˆ°ę–°ēŖ—å£", + "mMergeAllWindows": "åˆå¹¶ę‰€ęœ‰ēŖ—å£", "miToggleDevTools": "åˆ‡ę¢å¼€å‘äŗŗå‘˜å·„å…·(&&T)", "miAccessibilityOptions": "č¾…åŠ©åŠŸčƒ½é€‰é”¹(&&O)", "miReportIssues": "ęŠ„å‘Šé—®é¢˜(&&I)", @@ -170,8 +175,8 @@ "miRunningTask": "ę˜¾ē¤ŗę­£åœØčæč”Œēš„ä»»åŠ”(&&G)...", "miRestartTask": "é‡åÆę­£åœØčæč”Œēš„ä»»åŠ”(&&E)...", "miTerminateTask": "终止任劔(&&T)...", - "miConfigureTask": "é…ē½®ä»»åŠ”(&&C)", - "miConfigureBuildTask": "é…ē½®é»˜č®¤ē”Ÿęˆä»»åŠ”(&&F)", + "miConfigureTask": "é…ē½®ä»»åŠ”(&&C)...", + "miConfigureBuildTask": "é…ē½®é»˜č®¤ē”Ÿęˆä»»åŠ”(&&F)...", "accessibilityOptionsWindowTitle": "č¾…åŠ©åŠŸčƒ½é€‰é”¹", "miRestartToUpdate": "é‡åÆä»„ę›“ę–°...", "miCheckingForUpdates": "ę­£åœØę£€ęŸ„ę›“ę–°...", diff --git a/i18n/chs/src/vs/code/electron-main/windows.i18n.json b/i18n/chs/src/vs/code/electron-main/windows.i18n.json index 2c892bf97d0..a6bf5daf19d 100644 --- a/i18n/chs/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/chs/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,24 @@ "ok": "甮定", "pathNotExistTitle": "č·Æå¾„äøå­˜åœØ", "pathNotExistDetail": "ē£ē›˜äøŠä¼¼ä¹Žäøå†å­˜åœØč·Æå¾„ā€œ{0}ā€ć€‚", - "reopen": "é‡ę–°ę‰“å¼€", - "wait": "äæęŒē­‰å¾…", - "close": "关闭", + "reopen": "é‡ę–°ę‰“å¼€(&&R)", + "wait": "继续等待(&&K)", + "close": "关闭(&&C)", "appStalled": "ēŖ—å£äøå†å“åŗ”", - "appStalledDetail": "åÆä»„é‡ę–°ę‰“å¼€ęˆ–å…³é—­ēŖ—ļ¼Œęˆ–č€…äæęŒē­‰å¾…ć€‚", + "appStalledDetail": "ä½ åÆä»„é‡ę–°ę‰“å¼€ęˆ–å…³é—­ēŖ—å£ļ¼Œęˆ–č€…äæęŒē­‰å¾…ć€‚", "appCrashed": "ēŖ—å£å‡ŗēŽ°ę•…éšœ", "appCrashedDetail": "ęˆ‘ä»¬åÆ¹ę­¤å¼•čµ·ēš„äøä¾æč”Øē¤ŗęŠ±ę­‰! čÆ·é‡åÆčÆ„ēŖ—å£ä»ŽäøŠę¬”åœę­¢ēš„ä½ē½®ē»§ē»­ć€‚", + "open": "打开", + "openFolder": "打开文件夹", "openFile": "打开文件", - "openFolder": "打开文件夹" + "workspaceOpenedMessage": "ę— ę³•äæå­˜å·„ä½œåŒŗā€œ{0}ā€", + "workspaceOpenedDetail": "å·²åœØå¦äø€äøŖēŖ—å£ę‰“å¼€å·„ä½œåŒŗć€‚čÆ·å…ˆå…³é—­čÆ„ēŖ—å£ļ¼Œē„¶åŽé‡čÆ•ć€‚", + "openWorkspace": "打开(&&O)...", + "openWorkspaceTitle": "ę‰“å¼€å·„ä½œåŒŗ", + "save": "äæå­˜(&&S)", + "doNotSave": "äøäæå­˜(&&N)", + "cancel": "å–ę¶ˆ", + "saveWorkspaceMessage": "ä½ ę˜Æå¦č¦å°†ä½ ēš„å·„ä½œåŒŗé…ē½®äæå­˜äøŗę–‡ä»¶ļ¼Ÿ", + "saveWorkspaceDetail": "č‹„č¦å†ę¬”ę‰“å¼€ę­¤å·„ä½œåŒŗļ¼ŒčÆ·å…ˆäæå­˜ć€‚", + "saveWorkspace": "äæå­˜å·„ä½œåŒŗ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json index 9cdbb1a75e0..fc23def6012 100644 --- a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "ęŽ§åˆ¶č”Œé«˜ć€‚ä½æē”Ø 0 é€ščæ‡å­—å·č®”ē®—č”Œé«˜ć€‚", "letterSpacing": "ä»„åƒē“ äøŗå•ä½ęŽ§åˆ¶å­—ē¬¦é—“č·ć€‚", "lineNumbers": "ęŽ§åˆ¶č”Œå·ēš„ę˜¾ē¤ŗć€‚åÆčƒ½ēš„å€¼äøŗā€œå¼€ā€ć€ā€œå…³ā€å’Œā€œē›øåÆ¹ā€ć€‚ā€œē›øåÆ¹ā€å°†ę˜¾ē¤ŗä»Žå½“å‰å…‰ę ‡ä½ē½®å¼€å§‹č®”ę•°ēš„č”Œę•°ć€‚", - "rulers": "ę˜¾ē¤ŗåž‚ē›“ę ‡å°ŗēš„åˆ—", + "rulers": "åœØäø€å®šę•°é‡ēš„ē­‰å®½å­—ē¬¦åŽę˜¾ē¤ŗåž‚ē›“ę ‡å°ŗć€‚č¾“å…„å¤šäøŖå€¼ļ¼Œę˜¾ē¤ŗå¤šäøŖę ‡å°ŗć€‚č‹„ę•°ē»„äøŗē©ŗļ¼Œåˆ™äøē»˜åˆ¶ę ‡å°ŗć€‚", "wordSeparators": "ę‰§č”Œę–‡å­—ē›øå…³ēš„åÆ¼čˆŖęˆ–ę“ä½œę—¶å°†ē”Øä½œę–‡å­—åˆ†éš”ē¬¦ēš„å­—ē¬¦", "tabSize": "äø€äøŖåˆ¶č”Øē¬¦ē­‰äŗŽēš„ē©ŗę ¼ę•°ć€‚čÆ„č®¾ē½®åœØ `editor.detectIndentation` åÆē”Øę—¶ę ¹ę®ę–‡ä»¶å†…å®¹čæ›č”Œé‡å†™ć€‚", "tabSize.errorMessage": "åŗ”äøŗā€œnumberā€ć€‚ę³Øę„ļ¼Œå€¼ā€œautoā€å·²ē”±ā€œeditor.detectIndentationā€č®¾ē½®ę›æę¢ć€‚", @@ -20,8 +20,9 @@ "detectIndentation": "å½“ę‰“å¼€ę–‡ä»¶ę—¶ļ¼Œå°†åŸŗäŗŽę–‡ä»¶å†…å®¹ę£€ęµ‹ \"editor.tabSize\" 和 \"editor.insertSpaces\"怂", "roundedSelection": "ęŽ§åˆ¶é€‰å–čŒƒå›“ę˜Æå¦ęœ‰åœ†č§’", "scrollBeyondLastLine": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åÆä»„ę»šåŠØåˆ°ęœ€åŽäø€č”Œä¹‹åŽ", + "smoothScrolling": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åœØę»šåŠØę—¶ä½æē”ØåŠØē”»", "minimap.enabled": "ęŽ§åˆ¶ę˜Æå¦ę˜¾ē¤ŗ minimap", - "minimap.showSlider": "ęŽ§åˆ¶ę˜Æå¦č‡ŖåŠØéšč—čæ·ä½ åœ°å›¾ę»‘å—ć€‚ ", + "minimap.showSlider": "ęŽ§åˆ¶ę˜Æå¦č‡ŖåŠØéšč—å°åœ°å›¾ę»‘å—ć€‚åÆé€‰å€¼äøŗ \"always\" 和 \"mouseover\"", "minimap.renderCharacters": "å‘ˆēŽ°ęŸč”ŒäøŠēš„å®žé™…å­—ē¬¦(äøŽé¢œč‰²å—ē›øå)", "minimap.maxColumn": "é™åˆ¶ęœ€å°ę˜ å°„ēš„å®½åŗ¦ļ¼Œå°½é‡å¤šåœ°å‘ˆēŽ°ē‰¹å®šę•°é‡ēš„åˆ—", "find.seedSearchStringFromSelection": "ęŽ§åˆ¶ę˜Æå¦å°†ē¼–č¾‘å™Øēš„é€‰äø­å†…å®¹ä½œäøŗęœē“¢čÆå”«å…„åˆ°ęŸ„ę‰¾ē»„ä»¶", @@ -46,7 +47,7 @@ "autoClosingBrackets": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åŗ”čÆ„åœØå·¦ę‹¬å·åŽč‡ŖåŠØę’å…„å³ę‹¬å·", "formatOnType": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åŗ”åœØé”®å…„åŽč‡ŖåŠØč®¾ē½®č”Œēš„ę ¼å¼", "formatOnPaste": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åŗ”č‡ŖåŠØč®¾ē½®ē²˜č““å†…å®¹ēš„ę ¼å¼ć€‚ę ¼å¼åŒ–ēØ‹åŗåæ…é”»åÆē”Øå¹¶äø”čƒ½č®¾ē½®ę–‡ę”£äø­ęŸäø€čŒƒå›“ēš„ę ¼å¼ć€‚", - "autoIndent": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åŗ”åœØē”Øęˆ·é”®å…„ć€ē²˜č““ęˆ–ē§»åŠØč”Œę—¶č‡ŖåŠØč°ƒę•“ē¼©čæ›ć€‚čÆ­čØ€ēš„ē¼©čæ›č§„åˆ™åæ…é”»åÆē”Øć€‚", + "autoIndent": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åœØē”Øęˆ·é”®å…„ć€ē²˜č““ęˆ–ē§»åŠØč”Œę—¶č‡ŖåŠØč°ƒę•“ē¼©čæ›ć€‚čÆ­čØ€ēš„ē¼©čæ›č§„åˆ™åæ…é”»åÆē”Øć€‚", "suggestOnTriggerCharacters": "ęŽ§åˆ¶é”®å…„č§¦å‘å™Øå­—ē¬¦ę—¶ę˜Æå¦åŗ”č‡ŖåŠØę˜¾ē¤ŗå»ŗč®®", "acceptSuggestionOnEnter": "ęŽ§åˆ¶ęŒ‰ā€œEnterā€é”®ę˜Æå¦åƒęŒ‰ā€œTabā€é”®äø€ę ·ęŽ„å—å»ŗč®®ć€‚čæ™čƒ½åø®åŠ©éæå…ā€œę’å…„ę–°č”Œā€å’Œā€œęŽ„å—å»ŗč®®ā€ä¹‹é—“ēš„ę­§ä¹‰ć€‚å€¼äøŗā€œsmartā€ę—¶č”Øē¤ŗļ¼Œä»…å½“ę–‡å­—ę”¹å˜ę—¶ļ¼ŒęŒ‰ā€œEnterā€é”®ę‰čƒ½ęŽ„å—å»ŗč®®", "acceptSuggestionOnCommitCharacter": "ęŽ§åˆ¶ę˜Æå¦åŗ”åœØé‡åˆ°ęäŗ¤å­—ē¬¦ę—¶ęŽ„å—å»ŗč®®ć€‚ä¾‹å¦‚ļ¼ŒåœØ JavaScript äø­ļ¼Œåˆ†å·(\";\")åÆä»„äøŗęäŗ¤å­—ē¬¦ļ¼ŒåÆęŽ„å—å»ŗč®®å¹¶é”®å…„čÆ„å­—ē¬¦ć€‚", @@ -86,6 +87,8 @@ "accessibilitySupport.off": "ē¼–č¾‘å™Øå°†äøå†åÆ¹å±å¹•é˜…čÆ»å™Øēš„ä½æē”Øčæ›č”Œä¼˜åŒ–ć€‚", "accessibilitySupport": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åŗ”čæč”ŒåœØåÆ¹å±å¹•é˜…čÆ»å™Øčæ›č”Œä¼˜åŒ–ēš„ęØ”å¼ć€‚", "links": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦åŗ”ę£€ęµ‹é“¾ęŽ„å¹¶ä½æå®ƒä»¬åÆč¢«ē‚¹å‡»", + "colorDecorators": "ęŽ§åˆ¶ē¼–č¾‘å™Øę˜Æå¦ę˜¾ē¤ŗå†…č”é¢œč‰²äæ®é„°å™Øå’Œé¢œč‰²é€‰å–å™Øć€‚", + "codeActions": "åÆē”Øä»£ē ę“ä½œå°ēÆę³”ęē¤ŗ", "sideBySide": "ęŽ§åˆ¶ Diff ē¼–č¾‘å™Øä»„å¹¶ęŽ’ęˆ–å†…č”å½¢å¼ę˜¾ē¤ŗå·®å¼‚", "ignoreTrimWhitespace": "ęŽ§åˆ¶å·®å¼‚ē¼–č¾‘å™Øę˜Æå¦å°†åÆ¹å‰åÆ¼ē©ŗę ¼ęˆ–å°¾éšē©ŗę ¼ēš„ę›“ę”¹ę˜¾ē¤ŗäøŗå·®å¼‚", "renderIndicators": "ęŽ§åˆ¶å·®å¼‚ē¼–č¾‘å™Øę˜Æå¦äøŗå·²ę·»åŠ /åˆ é™¤ēš„ę›“ę”¹ę˜¾ē¤ŗ +/- ęŒ‡ē¤ŗē¬¦å·", diff --git a/i18n/chs/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/chs/src/vs/editor/common/view/editorColorRegistry.i18n.json index 9cfdf24e308..ad84081b84e 100644 --- a/i18n/chs/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/chs/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -9,9 +9,9 @@ "rangeHighlight": "ēŖå‡ŗę˜¾ē¤ŗčŒƒå›“ēš„čƒŒę™Æé¢œč‰²ļ¼Œä¾‹å¦‚ \"Quick Open\" å’Œā€œęŸ„ę‰¾ā€åŠŸčƒ½ć€‚", "caret": "ē¼–č¾‘å™Øå…‰ę ‡é¢œč‰²ć€‚", "editorCursorBackground": "ē¼–č¾‘å™Øå…‰ę ‡ēš„čƒŒę™Æč‰²ć€‚åÆä»„č‡Ŗå®šä¹‰å—åž‹å…‰ę ‡č¦†ē›–å­—ē¬¦ēš„é¢œč‰²ć€‚", - "editorWhitespaces": "ē¼–č¾‘å™Øäø­ē©ŗē™½å­—ē¬¦é¢œč‰²ć€‚", - "editorIndentGuides": "ē¼–č¾‘å™Øē¼©čæ›å‚č€ƒēŗæé¢œč‰²ć€‚", - "editorLineNumbers": "ē¼–č¾‘å™Øč”Œå·é¢œč‰²ć€‚", + "editorWhitespaces": "ē¼–č¾‘å™Øäø­ē©ŗē™½å­—ē¬¦ēš„é¢œč‰²ć€‚", + "editorIndentGuides": "ē¼–č¾‘å™Øē¼©čæ›å‚č€ƒēŗæēš„é¢œč‰²ć€‚", + "editorLineNumbers": "ē¼–č¾‘å™Øč”Œå·ēš„é¢œč‰²ć€‚", "editorRuler": "ē¼–č¾‘å™Øę ‡å°ŗēš„é¢œč‰²ć€‚", "editorCodeLensForeground": "编辑器 CodeLens ēš„å‰ę™Æč‰²", "editorBracketMatchBackground": "åŒ¹é…ę‹¬å·ēš„čƒŒę™Æč‰²", @@ -21,5 +21,11 @@ "errorForeground": "ē¼–č¾‘å™Øäø­é”™čÆÆę³¢ęµŖēŗæēš„å‰ę™Æč‰²ć€‚", "errorBorder": "ē¼–č¾‘å™Øäø­é”™čÆÆę³¢ęµŖēŗæēš„č¾¹ę”†é¢œč‰²ć€‚", "warningForeground": "ē¼–č¾‘å™Øäø­č­¦å‘Šę³¢ęµŖēŗæēš„å‰ę™Æč‰²ć€‚", - "warningBorder": "ē¼–č¾‘å™Øäø­č­¦å‘Šę³¢ęµŖēŗæēš„č¾¹ę”†é¢œč‰²ć€‚" + "warningBorder": "ē¼–č¾‘å™Øäø­č­¦å‘Šę³¢ęµŖēŗæēš„č¾¹ę”†é¢œč‰²ć€‚", + "infoForeground": "ē¼–č¾‘å™Øäø­äæ”ęÆę³¢ęµŖēŗæēš„å‰ę™Æč‰²ć€‚", + "infoBorder": "ē¼–č¾‘å™Øäø­äæ”ęÆę³¢ęµŖēŗæēš„č¾¹ę”†é¢œč‰²ć€‚", + "overviewRulerRangeHighlight": "ę¦‚čæ°čŒƒå›“ēŖå‡ŗę˜¾ē¤ŗēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "overviewRuleError": "ę¦‚čæ°é”™čÆÆēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "overviewRuleWarning": "ę¦‚čæ°č­¦å‘Šēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "overviewRuleInfo": "ę¦‚čæ°äæ”ęÆēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 214239c0607..9f9c20bbce2 100644 --- a/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "ę›æę¢", "label.replaceAllButton": "å…ØéƒØę›æę¢", "label.toggleReplaceButton": "åˆ‡ę¢ę›æę¢ęØ”å¼", - "title.matchesCountLimit": "仅前 999 äøŖē»“ęžœēŖå‡ŗę˜¾ē¤ŗļ¼Œä½†ę‰€ęœ‰ęŸ„ę‰¾ę“ä½œå‡é’ˆåÆ¹ę•“äøŖę–‡ęœ¬ć€‚", + "title.matchesCountLimit": "ä»…é«˜äŗ®äŗ†å‰ {0} äøŖē»“ęžœļ¼Œä½†ę‰€ęœ‰ęŸ„ę‰¾ę“ä½œå‡é’ˆåÆ¹å…Øę–‡ć€‚", "label.matchesLocation": "第 {0} äøŖ(共 {1} äøŖ)", "label.noResults": "ę— ē»“ęžœ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json index 8f77be77375..385ba32bfeb 100644 --- a/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "ęŸ„ę‰¾äø‹äø€äøŖé€‰ę‹©", "previousSelectionMatchFindAction": "ęŸ„ę‰¾äøŠäø€äøŖé€‰ę‹©", "startReplace": "ę›æę¢", - "addSelectionToNextFindMatch": "å°†é€‰ę‹©ę·»åŠ åˆ°äø‹äø€äøŖęŸ„ę‰¾åŒ¹é…é”¹", - "addSelectionToPreviousFindMatch": "å°†é€‰ę‹©å†…å®¹ę·»åŠ åˆ°äøŠäø€ęŸ„ę‰¾åŒ¹é…é”¹", - "moveSelectionToNextFindMatch": "å°†äøŠę¬”é€‰ę‹©ē§»åŠØåˆ°äø‹äø€äøŖęŸ„ę‰¾åŒ¹é…é”¹", - "moveSelectionToPreviousFindMatch": "å°†äøŠäøŖé€‰ę‹©å†…å®¹ē§»åŠØåˆ°äøŠäø€ęŸ„ę‰¾åŒ¹é…é”¹", - "selectAllOccurrencesOfFindMatch": "é€‰ę‹©ę‰€ęœ‰ę‰¾åˆ°ēš„ęŸ„ę‰¾åŒ¹é…é”¹", - "changeAll.label": "ę›“ę”¹ę‰€ęœ‰åŒ¹é…é”¹", "showNextFindTermAction": "ę˜¾ē¤ŗäø‹äø€äøŖęœē“¢ē»“ęžœ", "showPreviousFindTermAction": "ę˜¾ē¤ŗäøŠäø€äøŖęœē“¢ē»“ęžœ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/chs/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 7a87ba77804..628b8cc784e 100644 --- a/i18n/chs/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "在第 {1} č”Œčæ›č”Œäŗ† {0} ę¬”ę ¼å¼ē¼–č¾‘", "hint1n": "第 {0} 蔌到第 {1} č”Œé—“čæ›č”Œäŗ† 1 ę¬”ę ¼å¼ē¼–č¾‘", "hintnn": "第 {1} 蔌到第 {2} č”Œé—“čæ›č”Œäŗ† {0} ę¬”ę ¼å¼ē¼–č¾‘", + "no.provider": "ęŠ±ę­‰ļ¼Œå½“å‰ę²”ęœ‰å®‰č£…ā€œ{0}ā€ę–‡ä»¶ēš„ę ¼å¼åŒ–ēØ‹åŗć€‚", "formatDocument.label": "ę ¼å¼åŒ–ę–‡ä»¶", "formatSelection.label": "ę ¼å¼åŒ–é€‰å®šä»£ē " } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/chs/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 4464869131d..8dc6ee58760 100644 --- a/i18n/chs/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "č½¬åˆ°äøŠäø€äøŖé”™čÆÆęˆ–č­¦å‘Š", "editorMarkerNavigationError": "ē¼–č¾‘å™Øę ‡č®°åÆ¼čˆŖå°ē»„ä»¶é”™čÆÆé¢œč‰²ć€‚", "editorMarkerNavigationWarning": "ē¼–č¾‘å™Øę ‡č®°åÆ¼čˆŖå°ē»„ä»¶č­¦å‘Šé¢œč‰²ć€‚", + "editorMarkerNavigationInfo": "ē¼–č¾‘å™Øę ‡č®°åÆ¼čˆŖå°ē»„ä»¶äæ”ęÆé¢œč‰²ć€‚", "editorMarkerNavigationBackground": "ē¼–č¾‘å™Øę ‡č®°åÆ¼čˆŖå°ē»„ä»¶čƒŒę™Æč‰²ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/links/browser/links.i18n.json b/i18n/chs/src/vs/editor/contrib/links/browser/links.i18n.json index cec79732827..c228820d8fc 100644 --- a/i18n/chs/src/vs/editor/contrib/links/browser/links.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/links/browser/links.i18n.json @@ -8,7 +8,7 @@ "links.navigate": "Ctrl + å•å‡»ä»„č·ŸčøŖé“¾ęŽ„", "links.command.mac": "Cmd + å•å‡»ä»„ę‰§č”Œå‘½ä»¤", "links.command": "Ctrl + å•å‡»ä»„ę‰§č”Œå‘½ä»¤", - "links.navigate.al": "Alt + å•å‡»ä»„č®æé—®é“¾ęŽ„", + "links.navigate.al": "ęŒ‰ä½ Alt å¹¶å•å‡»åÆč®æé—®é“¾ęŽ„", "links.command.al": "Alt + å•å‡»ä»„ę‰§č”Œå‘½ä»¤", "invalid.url": "ęŠ±ę­‰ļ¼Œę— ę³•ę‰“å¼€ę­¤é“¾ęŽ„ļ¼Œå› äøŗå…¶ę ¼å¼äøę­£ē”®: {0}", "missing.url": "ęŠ±ę­‰ļ¼Œę— ę³•ę‰“å¼€ę­¤é“¾ęŽ„ļ¼Œå› äøŗå…¶ē›®ę ‡äø¢å¤±ć€‚", diff --git a/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 88bbf6c3a12..3c402b850dd 100644 --- a/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "åœØäøŠé¢ę·»åŠ å…‰ę ‡", "mutlicursor.insertBelow": "åœØäø‹é¢ę·»åŠ å…‰ę ‡", - "mutlicursor.insertAtEndOfEachLineSelected": "åœØč”Œå°¾ę·»åŠ å…‰ę ‡" + "mutlicursor.insertAtEndOfEachLineSelected": "åœØč”Œå°¾ę·»åŠ å…‰ę ‡", + "addSelectionToNextFindMatch": "å°†é€‰ę‹©ę·»åŠ åˆ°äø‹äø€äøŖęŸ„ę‰¾åŒ¹é…é”¹", + "addSelectionToPreviousFindMatch": "å°†é€‰ę‹©å†…å®¹ę·»åŠ åˆ°äøŠäø€ęŸ„ę‰¾åŒ¹é…é”¹", + "moveSelectionToNextFindMatch": "å°†äøŠę¬”é€‰ę‹©ē§»åŠØåˆ°äø‹äø€äøŖęŸ„ę‰¾åŒ¹é…é”¹", + "moveSelectionToPreviousFindMatch": "å°†äøŠäøŖé€‰ę‹©å†…å®¹ē§»åŠØåˆ°äøŠäø€ęŸ„ę‰¾åŒ¹é…é”¹", + "selectAllOccurrencesOfFindMatch": "é€‰ę‹©ę‰€ęœ‰ę‰¾åˆ°ēš„ęŸ„ę‰¾åŒ¹é…é”¹", + "changeAll.label": "ę›“ę”¹ę‰€ęœ‰åŒ¹é…é”¹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/chs/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..3ebf52a28ce --- /dev/null +++ b/i18n/chs/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "关闭" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/chs/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index 35b299bfd8a..7926047995c 100644 --- a/i18n/chs/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "čÆ»å–č®æé—®ę—¶ē¬¦å·ēš„čƒŒę™Æé¢œč‰²ļ¼Œä¾‹å¦‚čÆ»å–å˜é‡ę—¶ć€‚", - "wordHighlightStrong": "å†™å…„č®æé—®ę—¶ē¬¦å·ēš„čƒŒę™Æé¢œč‰²ļ¼Œä¾‹å¦‚å†™å…„å˜é‡ę—¶ć€‚" + "wordHighlightStrong": "å†™å…„č®æé—®ę—¶ē¬¦å·ēš„čƒŒę™Æé¢œč‰²ļ¼Œä¾‹å¦‚å†™å…„å˜é‡ę—¶ć€‚", + "overviewRulerWordHighlightForeground": "ę¦‚čæ°ē¬¦å·ēŖå‡ŗę˜¾ē¤ŗēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "overviewRulerWordHighlightStrongForeground": "ę¦‚čæ°å†™č®æé—®ē¬¦å·ēŖå‡ŗę˜¾ē¤ŗēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "wordHighlight.next.label": "č½¬åˆ°äø‹äø€äøŖēŖå‡ŗę˜¾ē¤ŗēš„ē¬¦å·", + "wordHighlight.previous.label": "č½¬åˆ°äøŠäø€äøŖēŖå‡ŗę˜¾ē¤ŗēš„ē¬¦å·" } \ No newline at end of file diff --git a/i18n/chs/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/chs/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 2e644c790f6..d9700a739f9 100644 --- a/i18n/chs/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/chs/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "ę­¤å‘½ä»¤ę‰€å±žēš„ē»„", "vscode.extension.contributes.menus": "å‘ē¼–č¾‘å™Øęä¾›čœå•é”¹", "menus.commandPalette": "å‘½ä»¤é¢ęæ", + "menus.touchBar": "Multi-Touch Bar (仅 macOS)", "menus.editorTitle": "ē¼–č¾‘å™Øę ‡é¢˜čœå•", "menus.editorContext": "ē¼–č¾‘å™ØäøŠäø‹ę–‡čœå•", "menus.explorerContext": "ę–‡ä»¶čµ„ęŗē®”ē†å™ØäøŠäø‹ę–‡čœå•", "menus.editorTabContext": "ē¼–č¾‘å™Øé€‰é”¹å”äøŠäø‹ę–‡čœå•", "menus.debugCallstackContext": "č°ƒčÆ•č°ƒē”Øå †ę ˆäøŠäø‹ę–‡čœå•", "menus.scmTitle": "ęŗä»£ē ē®”ē†ę ‡é¢˜čœå•", + "menus.scmSourceControl": "ęŗä»£ē ē®”ē†čœå•", "menus.resourceGroupContext": "ęŗä»£ē ē®”ē†čµ„ęŗē»„äøŠäø‹ę–‡čœå•", "menus.resourceStateContext": "ęŗä»£ē ē®”ē†čµ„ęŗēŠ¶ę€äøŠäø‹ę–‡čœå•", "view.viewTitle": "ęä¾›ēš„č§†å›¾ēš„ę ‡é¢˜čœå•", @@ -39,5 +41,5 @@ "missing.command": "čœå•é”¹å¼•ē”ØęœŖåœØā€œå‘½ä»¤ā€éƒØåˆ†čæ›č”Œå®šä¹‰ēš„å‘½ä»¤ā€œ{0}ā€ć€‚", "missing.altCommand": "čœå•é”¹å¼•ē”ØęœŖåœØā€œå‘½ä»¤ā€éƒØåˆ†čæ›č”Œå®šä¹‰ēš„ alt å‘½ä»¤ā€œ{0}ā€ć€‚", "dupe.command": "čœå•é”¹å¼•ē”ØäøŽé»˜č®¤å’Œ alt å‘½ä»¤ē›øåŒēš„å‘½ä»¤", - "nosupport.altCommand": "ęŠ±ę­‰ļ¼Œē›®å‰ä»…ęœ‰ā€œeditor/titleā€čœå•ēš„ā€œnavigationā€ē»„ę”ÆęŒ alt 命令" + "nosupport.altCommand": "ęŠ±ę­‰ļ¼Œē›®å‰ä»…ęœ‰ \"editor/title\" čœå•ēš„ \"navigation\" ē»„ę”ÆęŒę›æä»£å‘½ä»¤" } \ No newline at end of file diff --git a/i18n/chs/src/vs/platform/environment/node/argv.i18n.json b/i18n/chs/src/vs/platform/environment/node/argv.i18n.json index f5c7660b617..9fc0d95c7bd 100644 --- a/i18n/chs/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/chs/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "\"--goto\" ęØ”å¼äø­ēš„å‚ę•°ę ¼å¼åŗ”äøŗ \"FILE(:LINE(:CHARACTER))\"怂", - "diff": "ę‰“å¼€å·®å¼‚ē¼–č¾‘å™Øć€‚éœ€č¦ä¼ é€’äø¤äøŖę–‡ä»¶č·Æå¾„ä½œäøŗå‚ę•°ć€‚", - "goto": "åœØč·Æå¾„äø­ēš„č”Œå’Œå­—ē¬¦å¤„ę‰“å¼€ę–‡ä»¶(å‘č·Æå¾„ę·»åŠ  :line[:character])怂", + "diff": "å°†äø¤äøŖę–‡ä»¶ē›øäŗ’ęÆ”č¾ƒć€‚", + "add": "å°†ę–‡ä»¶å¤¹ę·»åŠ åˆ°ęœ€åŽäø€äøŖę“»åŠØēŖ—å£ć€‚", + "goto": "ę‰“å¼€č·Æå¾„äø‹ēš„ę–‡ä»¶å¹¶å®šä½åˆ°ē‰¹å®šč”Œå’Œē‰¹å®šå­—ē¬¦ć€‚", "locale": "č¦ä½æē”Øēš„åŒŗåŸŸč®¾ē½®(例如 en-US ꈖ zh-TW)怂", "newWindow": "å¼ŗåˆ¶åˆ›å»ŗäø€äøŖę–°ēš„ Code å®žä¾‹ć€‚", "performance": "é€ščæ‡åÆē”Ø \"Developer: Startup Performance\" 命令开始。", @@ -14,7 +15,7 @@ "reuseWindow": "åœØäøŠäø€ę“»åŠØēŖ—å£äø­å¼ŗåˆ¶ę‰“å¼€ę–‡ä»¶ęˆ–ę–‡ä»¶å¤¹ć€‚", "userDataDir": "ęŒ‡å®šå­˜ę”¾ē”Øęˆ·ę•°ę®ēš„ē›®å½•ļ¼Œę­¤ē›®å½•åœØä½œäøŗę ¹čæč”Œę—¶ååˆ†ęœ‰ē”Øć€‚", "verbose": "ę‰“å°čÆ¦ē»†č¾“å‡ŗ(蔨示 - 等待)怂", - "wait": "ē­‰ēŖ—å£å…³é—­åŽå†čæ”å›žć€‚", + "wait": "ē­‰ę–‡ä»¶å…³é—­åŽå†čæ”å›žć€‚", "extensionHomePath": "č®¾ē½®ę‰©å±•ēš„ę ¹č·Æå¾„ć€‚", "listExtensions": "åˆ—å‡ŗå·²å®‰č£…ēš„ę‰©å±•ć€‚", "showVersions": "使用 --list-extension ę—¶ļ¼Œę˜¾ē¤ŗå·²å®‰č£…ę‰©å±•ēš„ē‰ˆęœ¬ć€‚", diff --git a/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index c550c5e4e59..123f6947cde 100644 --- a/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "ę‰©å±•ę— ę•ˆ: package.json äøę˜Æ JSON ꖇ件怂", - "restartCode": "čÆ·å…ˆé‡åÆ Code å†é‡ę–°å®‰č£… {0}怂", - "installDependeciesConfirmation": "å®‰č£…ā€{0}ā€œčæ˜ä¼šå®‰č£…å…¶ä¾čµ–é”¹ć€‚ę˜Æå¦č¦ē»§ē»­?", - "install": "是", - "doNotInstall": "否", + "restartCodeLocal": "čÆ·å…ˆé‡åÆ Code å†é‡ę–°å®‰č£… {0}怂", + "restartCodeGallery": "čÆ·å…ˆé‡åÆ Code å†é‡ę–°å®‰č£…ć€‚", "uninstallDependeciesConfirmation": "č¦ä»…åøč½½ā€œ{0}ā€ęˆ–č€…å…¶ä¾čµ–é”¹ä¹Ÿäø€čµ·åøč½½?", "uninstallOnly": "仅", "uninstallAll": "å…ØéƒØ", diff --git a/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index feafccf3451..4ae3c02e3c1 100644 --- a/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "VS Code ę‰©å±•ēš„ęæ€ę“»äŗ‹ä»¶ć€‚", "vscode.extension.activationEvents.onLanguage": "åœØę‰“å¼€č¢«č§£ęžäøŗęŒ‡å®ščÆ­čØ€ēš„ę–‡ä»¶ę—¶å‘å‡ŗēš„ęæ€ę“»äŗ‹ä»¶ć€‚", "vscode.extension.activationEvents.onCommand": "åœØč°ƒē”ØęŒ‡å®šå‘½ä»¤ę—¶å‘å‡ŗēš„ęæ€ę“»äŗ‹ä»¶ć€‚", - "vscode.extension.activationEvents.onDebug": "åœØęŒ‡å®šē±»åž‹ēš„č°ƒčÆ•ä¼ščÆå¼€å§‹ę—¶å‘å‡ŗēš„ęæ€ę“»äŗ‹ä»¶ć€‚", + "vscode.extension.activationEvents.onDebug": "åœØē”Øęˆ·å‡†å¤‡č°ƒčÆ•ęˆ–å‡†å¤‡č®¾ē½®č°ƒčÆ•é…ē½®ę—¶å‘å‡ŗēš„ęæ€ę“»äŗ‹ä»¶ć€‚", "vscode.extension.activationEvents.workspaceContains": "åœØę‰“å¼€č‡³å°‘åŒ…å«äø€äøŖåŒ¹é…ęŒ‡å®š glob ęØ”å¼ēš„ę–‡ä»¶ēš„ę–‡ä»¶å¤¹ę—¶å‘å‡ŗēš„ęæ€ę“»äŗ‹ä»¶ć€‚", "vscode.extension.activationEvents.onView": "åœØęŒ‡å®šč§†å›¾č¢«å±•å¼€ę—¶å‘å‡ŗēš„ęæ€ę“»äŗ‹ä»¶ć€‚", "vscode.extension.activationEvents.star": "在 VS Code åÆåŠØę—¶å‘å‡ŗēš„ęæ€ę“»äŗ‹ä»¶ć€‚äøŗē”®äæč‰Æå„½ēš„ęœ€ē»ˆē”Øęˆ·ä½“éŖŒļ¼ŒčÆ·ä»…åœØå…¶ä»–ęæ€ę“»äŗ‹ä»¶ē»„åˆäøé€‚ē”ØäŗŽä½ ēš„ęƒ…å†µę—¶ļ¼Œę‰åœØę‰©å±•äø­ä½æē”Øę­¤äŗ‹ä»¶ć€‚", diff --git a/i18n/chs/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/chs/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..72e224481c5 --- /dev/null +++ b/i18n/chs/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "ęä¾›ē”±ę‰©å±•å®šä¹‰ēš„äø»é¢˜é¢œč‰²", + "contributes.color.id": "äø»é¢˜é¢œč‰²ę ‡čÆ†ē¬¦", + "contributes.color.id.format": "标识符应滔足 aa[.bb]*", + "contributes.color.description": "äø»é¢˜é¢œč‰²ęčæ°", + "contributes.defaults.light": "ęµ…č‰²äø»é¢˜ēš„é»˜č®¤é¢œč‰²ć€‚åŗ”äøŗåå…­čæ›åˆ¶é¢œč‰²å€¼ (#RRGGBB[AA]) ęˆ–ę˜Æäø»é¢˜é¢œč‰²ę ‡čÆ†ē¬¦ļ¼Œå…¶ęä¾›é»˜č®¤å€¼ć€‚", + "contributes.defaults.dark": "ę·±č‰²äø»é¢˜ēš„é»˜č®¤é¢œč‰²ć€‚åŗ”äøŗåå…­čæ›åˆ¶é¢œč‰²å€¼ (#RRGGBB[AA]) ęˆ–ę˜Æäø»é¢˜é¢œč‰²ę ‡čÆ†ē¬¦ļ¼Œå…¶ęä¾›é»˜č®¤å€¼ć€‚", + "contributes.defaults.highContrast": "é«˜åÆ¹ęÆ”åŗ¦äø»é¢˜ēš„é»˜č®¤é¢œč‰²ć€‚åŗ”äøŗåå…­čæ›åˆ¶é¢œč‰²å€¼ (#RRGGBB[AA]) ęˆ–ę˜Æäø»é¢˜é¢œč‰²ę ‡čÆ†ē¬¦ļ¼Œå…¶ęä¾›é»˜č®¤å€¼ć€‚", + "invalid.colorConfiguration": "\"configuration.colors\" åæ…é”»ę˜Æę•°ē»„", + "invalid.default.colorType": "{0} åæ…é”»äøŗåå…­čæ›åˆ¶é¢œč‰²å€¼ (#RRGGBB[AA] ꈖ #RGB[A]) ęˆ–ę˜Æäø»é¢˜é¢œč‰²ę ‡čÆ†ē¬¦ļ¼Œå…¶ęä¾›é»˜č®¤å€¼ć€‚", + "invalid.id": "åæ…é”»å®šä¹‰ \"configuration.colors.id\"ļ¼Œäø”äøčƒ½äøŗē©ŗ", + "invalid.id.format": "\"configuration.colors.id\" 必锻滔足 word[.word]*", + "invalid.description": "åæ…é”»å®šä¹‰ \"configuration.colors.description\"ļ¼Œäø”äøčƒ½äøŗē©ŗ", + "invalid.defaults": "åæ…é”»å®šä¹‰ ā€œconfiguration.colors.defaultsā€ļ¼Œäø”é”»åŒ…å« \"light\"(浅色)态\"dark\"(深色) 和 \"highContrast\"(é«˜åÆ¹ęÆ”åŗ¦)" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json index 8152a84933f..5827e2f251e 100644 --- a/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/chs/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "é¢œč‰²ę ¼å¼ę— ę•ˆć€‚čÆ·ä½æē”Ø #RGB态#RGBA态#RRGGBB ꈖ #RRGGBBAA", "schema.colors": "å·„ä½œå°äø­ä½æē”Øēš„é¢œč‰²ć€‚", "foreground": "ę•“ä½“å‰ę™Æč‰²ć€‚ę­¤é¢œč‰²ä»…åœØäøč¢«ē»„ä»¶č¦†ē›–ę—¶é€‚ē”Øć€‚", "errorForeground": "é”™čÆÆäæ”ęÆēš„ę•“ä½“å‰ę™Æč‰²ć€‚ę­¤é¢œč‰²ä»…åœØäøč¢«ē»„ä»¶č¦†ē›–ę—¶é€‚ē”Øć€‚", @@ -45,6 +44,7 @@ "listHoverForeground": "é¼ ę ‡åœØé”¹ē›®äøŠę‚¬åœę—¶ļ¼Œåˆ—č”Øęˆ–ę ‘ēš„å‰ę™Æé¢œč‰²ć€‚", "listDropBackground": "ä½æē”Øé¼ ę ‡ē§»åŠØé”¹ē›®ę—¶ļ¼Œåˆ—č”Øęˆ–ę ‘čæ›č”Œę‹–ę”¾ēš„čƒŒę™Æé¢œč‰²ć€‚", "highlight": "åœØåˆ—č”Øęˆ–ę ‘äø­ęœē“¢ę—¶ļ¼Œå…¶äø­åŒ¹é…å†…å®¹ēš„é«˜äŗ®é¢œč‰²ć€‚", + "invalidItemForeground": "åˆ—č”Øęˆ–ę ‘äø­ę— ę•ˆé”¹ēš„å‰ę™Æč‰²ļ¼Œä¾‹å¦‚čµ„ęŗē®”ē†å™Øäø­ę²”ęœ‰č§£ęžēš„ę ¹ē›®å½•ć€‚", "pickerGroupForeground": "åæ«é€Ÿé€‰å–å™Øåˆ†ē»„ę ‡ē­¾ēš„é¢œč‰²ć€‚", "pickerGroupBorder": "åæ«é€Ÿé€‰å–å™Øåˆ†ē»„č¾¹ę”†ēš„é¢œč‰²ć€‚", "buttonForeground": "ęŒ‰é’®å‰ę™Æč‰²ć€‚", @@ -85,5 +85,7 @@ "mergeBorder": "å†…č”åˆå¹¶å†²ēŖäø­ę ‡å¤“å’Œåˆ†å‰²ēŗæēš„č¾¹ę”†é¢œč‰²ć€‚", "overviewRulerCurrentContentForeground": "å†…č”åˆå¹¶å†²ēŖäø­å½“å‰ē‰ˆęœ¬åŒŗåŸŸēš„ę¦‚č§ˆę ‡å°ŗå‰ę™Æč‰²ć€‚", "overviewRulerIncomingContentForeground": "å†…č”åˆå¹¶å†²ēŖäø­ä¼ å…„ēš„ē‰ˆęœ¬åŒŗåŸŸēš„ę¦‚č§ˆę ‡å°ŗå‰ę™Æč‰²ć€‚", - "overviewRulerCommonContentForeground": "å†…č”åˆå¹¶å†²ēŖäø­å…±åŒē„–å…ˆåŒŗåŸŸēš„ę¦‚č§ˆę ‡å°ŗå‰ę™Æč‰²ć€‚" + "overviewRulerCommonContentForeground": "å†…č”åˆå¹¶å†²ēŖäø­å…±åŒē„–å…ˆåŒŗåŸŸēš„ę¦‚č§ˆę ‡å°ŗå‰ę™Æč‰²ć€‚", + "overviewRulerFindMatchForeground": "ę¦‚čæ°ęŸ„ę‰¾åŒ¹é…é”¹ēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "overviewRulerSelectionHighlightForeground": "ę¦‚čæ°é€‰ę‹©ēŖå‡ŗę˜¾ē¤ŗēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/chs/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..3e8a456134d --- /dev/null +++ b/i18n/chs/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "代码巄作区", + "untitledWorkspace": "ę— ę ‡é¢˜ (巄作区)", + "workspaceNameVerbose": "{0} (巄作区)", + "workspaceName": "{0} (巄作区)" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/chs/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..49eaa8fd6f3 --- /dev/null +++ b/i18n/chs/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "视图必锻为数组", + "requirestring": "å±žę€§ā€œ{0}ā€ę˜Æåæ…č¦å±žę€§ļ¼Œå…¶ē±»åž‹åæ…é”»ę˜Æ \"string\"", + "optstring": "å±žę€§ā€œ{0}ā€åÆä»„ēœē•„ļ¼Œå¦åˆ™å…¶ē±»åž‹åæ…é”»ę˜Æ \"string\"", + "vscode.extension.contributes.view.id": "č§†å›¾ēš„ę ‡čÆ†ē¬¦ć€‚ä½æē”Øę ‡čÆ†ē¬¦é€ščæ‡ā€œvscode.window.registerTreeDataProviderForViewā€ API ę³Øå†Œę•°ę®ęä¾›ēØ‹åŗć€‚åŒę—¶å°†ā€œonView:${id}ā€äŗ‹ä»¶ę³Øå†Œåˆ°ā€œactivationEventsā€ä»„ęæ€ę“»ä½ ēš„ę‰©å±•ć€‚", + "vscode.extension.contributes.view.name": "äŗŗē±»åÆčÆ»ēš„č§†å›¾åē§°ć€‚å°†ä¼šč¢«ę˜¾ē¤ŗ", + "vscode.extension.contributes.view.when": "ę˜¾ē¤ŗę­¤č§†å›¾åæ…é”»äøŗēœŸēš„ę”ä»¶", + "vscode.extension.contributes.views": "å‘ē¼–č¾‘å™Øęä¾›č§†å›¾", + "views.explorer": "资源箔理器视图", + "views.debug": "č°ƒčÆ•č§†å›¾", + "locationId.invalid": "ā€œ{0}ā€äøŗę— ę•ˆč§†å›¾ä½ē½®", + "duplicateView1": "ę— ę³•åœØä½ē½®ā€œ{1}ā€ę³Øå†Œå¤šäøŖ ID åŒäøŗā€œ{0}ā€ēš„č§†å›¾ć€‚", + "duplicateView2": "ID äøŗā€œ{0}ā€ēš„č§†å›¾åœØä½ē½®ā€œ{1}ā€å·²č¢«ę³Øå†Œ" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/chs/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..9e906e992b8 --- /dev/null +++ b/i18n/chs/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "ę— ę³•ęæ€ę“»ę‰©å±•ā€{1}ā€œć€‚åŽŸå› : ęœŖēŸ„ä¾čµ–å…³ē³»ā€œ{0}ā€ć€‚", + "failedDep1": "ę— ę³•ęæ€ę“»ę‰©å±•ā€{1}ā€œć€‚åŽŸå› : ę— ę³•ęæ€ę“»ä¾čµ–å…³ē³»ā€{0}ā€œć€‚", + "failedDep2": "ę— ę³•ęæ€ę“»ę‰©å±•ā€{0}ā€œć€‚åŽŸå› : ä¾čµ–å…³ē³»å¤šäŗŽ 10 ēŗ§(ęœ€åÆčƒ½ę˜Æä¾čµ–å…³ē³»å¾ŖēŽÆ)怂", + "activationError": "ęæ€ę“»ę‰©å±•ā€œ{0}ā€å¤±č“„: {1}怂" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 0ceae1d9a59..b282efac3d0 100644 --- a/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,23 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "打开文件...", "openFolder": "打开文件夹...", "openFileFolder": "打开...", - "reload": "é‡ę–°åŠ č½½(&&R)", - "cancel": "å–ę¶ˆ", - "select": "选ꋩ(&&S)", - "selectWorkspace": "é€‰ę‹©ę–‡ä»¶å¤¹ä½œäøŗå·„ä½œåŒŗ", - "addSupported": "éœ€č¦é‡č½½ēŖ—å£ä»„ę‰“å¼€å¤šäøŖę–‡ä»¶å¤¹ć€‚", "addFolderToWorkspace": "å°†ę–‡ä»¶å¤¹ę·»åŠ åˆ°å·„ä½œåŒŗ...", "add": "添加(&&A)", "addFolderToWorkspaceTitle": "å°†ę–‡ä»¶å¤¹ę·»åŠ åˆ°å·„ä½œåŒŗ", + "globalRemoveFolderFromWorkspace": "å°†ę–‡ä»¶å¤¹ä»Žå·„ä½œåŒŗåˆ é™¤ā€¦", "removeFolderFromWorkspace": "å°†ę–‡ä»¶å¤¹ä»Žå·„ä½œåŒŗåˆ é™¤", + "openFolderSettings": "打开文件夹设置", "saveWorkspaceAsAction": "å°†å·„ä½œåŒŗå¦å­˜äøŗ...", - "saveEmptyWorkspaceNotSupported": "čÆ·å…ˆę‰“å¼€äø€äøŖå·„ä½œåŒŗå†äæå­˜ć€‚", - "saveNotSupported": "éœ€č¦é‡č½½ēŖ—å£ä»„äæå­˜å·„ä½œåŒŗć€‚", "save": "äæå­˜(&&S)", "saveWorkspace": "äæå­˜å·„ä½œåŒŗ", "openWorkspaceAction": "ę‰“å¼€å·„ä½œåŒŗ...", - "newWorkspace": "ę–°å»ŗå·„ä½œåŒŗ...", - "openWorkspaceConfigFile": "ę‰“å¼€å·„ä½œåŒŗé…ē½®ę–‡ä»¶" + "openWorkspaceConfigFile": "ę‰“å¼€å·„ä½œåŒŗé…ē½®ę–‡ä»¶", + "openFolderAsWorkspaceInNewWindow": "åœØę–°ēŖ—å£äø­å°†ę–‡ä»¶å¤¹ä½œäøŗå·„ä½œåŒŗę‰“å¼€", + "workspaceFolderPickerPlaceholder": "é€‰ę‹©å·„ä½œåŒŗę–‡ä»¶å¤¹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 76938aceb7e..6484617f5e8 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "ä»Žę“»åŠØę åˆ é™¤", - "keepInActivityBar": "äæē•™ę“»åŠØę ", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "ä»Žę“»åŠØę äø­éšč—", + "keepInActivityBar": "äæē•™ę“»åŠØę ", "additionalViews": "其他视图", "numberBadge": "{0} ({1})", "manageExtension": "箔理扩展", diff --git a/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 9b17b8e6572..ab430ed5a0d 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "éšč—ę“»åŠØę ", - "activityBarAriaLabel": "ę“»åŠØč§†å›¾åˆ‡ę¢å™Ø", "globalActions": "å…Øå±€åŠØä½œ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..738f1c78726 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "ę“»åŠØč§†å›¾åˆ‡ę¢å™Ø" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..c6251151901 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "其他视图", + "numberBadge": "{0} ({1})", + "manageExtension": "箔理扩展", + "titleKeybinding": "{0} ({1})", + "hide": "隐藏", + "keep": "äæęŒ", + "toggle": "åˆ‡ę¢å·²å›ŗå®šēš„č§†å›¾" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 96695e518e9..a2f0727f579 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "åœØē¬¬äŗŒē»„äø­ę˜¾ē¤ŗē¼–č¾‘å™Ø", "groupThreePicker": "åœØē¬¬äø‰ē»„äø­ę˜¾ē¤ŗē¼–č¾‘å™Ø", "allEditorsPicker": "ę˜¾ē¤ŗę‰€ęœ‰å·²ę‰“å¼€ēš„ē¼–č¾‘å™Ø", - "view": "ęŸ„ēœ‹" + "view": "ęŸ„ēœ‹", + "file": "ꖇ件" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 129a5e91207..1e469098294 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "ę‰“å¼€ē»„äø­äøŠäø€äøŖē¼–č¾‘å™Ø", "navigateNext": "å‰čæ›", "navigatePrevious": "后退", + "navigateLast": "č½¬åˆ°ęœ€åŽ", "reopenClosedEditor": "é‡ę–°ę‰“å¼€å·²å…³é—­ēš„ē¼–č¾‘å™Ø", "clearRecentFiles": "ęø…é™¤ęœ€čæ‘ę‰“å¼€", "showEditorsInFirstGroup": "åœØē¬¬äø€ē»„äø­ę˜¾ē¤ŗē¼–č¾‘å™Ø", diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 0b7d6bc441e..67671aeb85c 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "ꌉ Tab ē§»åŠØē„¦ē‚¹", - "screenReaderDetected": "ę£€ęµ‹åˆ°å±å¹•é˜…čÆ»å™Ø", + "screenReaderDetected": "å·²äøŗå±å¹•é˜…čÆ»å™Øä¼˜åŒ–", "screenReaderDetectedExtra": "å¦‚ęžœä½ ę²”ęœ‰ä½æē”Øå±å¹•é˜…čÆ»å™Øļ¼ŒčÆ·å°†č®¾ē½®äø­ēš„ā€œeditor.accessibilitySupportā€ę”¹äøŗā€œoffā€ć€‚", "disableTabMode": "ē¦ē”Øč¾…åŠ©åŠŸčƒ½ęØ”å¼", "gotoLine": "转到蔌", @@ -47,5 +47,11 @@ "reopenWithEncoding": "é€ščæ‡ē¼–ē é‡ę–°ę‰“å¼€", "guessedEncoding": "é€ščæ‡å†…å®¹ēŒœęµ‹", "pickEncodingForReopen": "é€‰ę‹©ę–‡ä»¶ē¼–ē ä»„é‡ę–°ę‰“å¼€ę–‡ä»¶", - "pickEncodingForSave": "é€‰ę‹©ē”ØäŗŽäæå­˜ēš„ę–‡ä»¶ē¼–ē " + "pickEncodingForSave": "é€‰ę‹©ē”ØäŗŽäæå­˜ēš„ę–‡ä»¶ē¼–ē ", + "screenReaderDetectedExplanation.title": "å·²äøŗå±å¹•é˜…čÆ»å™Øä¼˜åŒ–", + "screenReaderDetectedExplanation.question": "ä½ åœØä½æē”Øå±å¹•é˜…čÆ»å™Øé¢ę„ę“ä½œ VS Code å—ļ¼Ÿ", + "screenReaderDetectedExplanation.answerYes": "是", + "screenReaderDetectedExplanation.answerNo": "否", + "screenReaderDetectedExplanation.body1": "VS Code å·²äøŗå±å¹•é˜…čÆ»å™Øēš„ä½æē”Øčæ›č”Œä¼˜åŒ–ć€‚", + "screenReaderDetectedExplanation.body2": "äø€äŗ›ē¼–č¾‘å™ØåŠŸčƒ½å°†ęœ‰äøåŒēš„č”Œäøŗ: ä¾‹å¦‚ļ¼Œę–‡å­—ę¢č”Œļ¼ŒęŠ˜å ļ¼Œč‡ŖåŠØå…³é—­ę‹¬å·ē­‰ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/titleControl.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/titleControl.i18n.json index 63726f32765..90dedb611fa 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/titleControl.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/titleControl.i18n.json @@ -8,7 +8,7 @@ "closeOthers": "关闭其他", "closeRight": "关闭到右侧", "closeAll": "å…ØéƒØå…³é—­", - "closeAllUnmodified": "å…³é—­ęœŖę›“ę”¹ēš„", + "closeAllUnmodified": "å…³é—­ęœŖę›“ę”¹", "keepOpen": "äæęŒę‰“å¼€ēŠ¶ę€", "showOpenedEditors": "ę˜¾ē¤ŗę‰“å¼€ēš„ē¼–č¾‘å™Ø", "araLabelEditorActions": "ē¼–č¾‘å™Øę“ä½œ" diff --git a/i18n/chs/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 5caf1942c05..b0d63f9ec3a 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "å…³é—­é¢ęæ", "togglePanel": "åˆ‡ę¢é¢ęæ", "focusPanel": "čšē„¦åˆ°é¢ęæäø­", + "toggledPanelPosition": "åˆ‡ę¢é¢ęæä½ē½®", + "moveToRight": "ē§»åŠØåˆ°å³ä¾§", + "moveToBottom": "ē§»åŠØåˆ°åŗ•éƒØ", "toggleMaximizedPanel": "åˆ‡ę¢ęœ€å¤§åŒ–é¢ęæ", "maximizePanel": "ęœ€å¤§åŒ–é¢ęæå¤§å°", "minimizePanel": "ę¢å¤é¢ęæå¤§å°", diff --git a/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 11e4c9243b7..fbfbe4e5483 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "å‘½ä»¤ā€œ{0}ā€å½“å‰ęœŖåÆē”Øļ¼Œę— ę³•čæč”Œć€‚", "manageExtension": "箔理扩展" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..08ebcb29e96 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} ę“ä½œ" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..1e211f7c694 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} ę“ä½œ", + "hideView": "ä»Žä¾§č¾¹ę äø­éšč—" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..85f57daaba0 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "ID äøŗā€œ{0}ā€ēš„č§†å›¾åœØä½ē½®ā€œ{1}ā€å·²č¢«ę³Øå†Œ" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..e9347e0a6fe --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "ä»Žä¾§č¾¹ę äø­éšč—" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/common/theme.i18n.json b/i18n/chs/src/vs/workbench/common/theme.i18n.json index 943141ce567..f927441d137 100644 --- a/i18n/chs/src/vs/workbench/common/theme.i18n.json +++ b/i18n/chs/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "ę“»åŠØé€‰é”¹å”ēš„čƒŒę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", "tabInactiveBackground": "éžę“»åŠØé€‰é”¹å”ēš„čƒŒę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", "tabBorder": "ē”ØäŗŽå°†é€‰é”¹å”å½¼ę­¤åˆ†éš”å¼€ēš„č¾¹ę”†ć€‚é€‰é”¹å”ę˜Æē¼–č¾‘å™ØåŒŗåŸŸäø­ē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„å­˜åœØå¤šäøŖē¼–č¾‘å™Øē»„ć€‚", + "tabActiveBorder": "ē”ØäŗŽé«˜äŗ®ę“»åŠØēš„é€‰é”¹å”ēš„č¾¹ę”†ć€‚é€‰é”¹å”ę˜Æē¼–č¾‘å™ØåŒŗåŸŸäø­ē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„å­˜åœØå¤šäøŖē¼–č¾‘å™Øē»„ć€‚", + "tabActiveUnfocusedBorder": "ē”ØäŗŽé«˜äŗ®äø€äøŖå¤±åŽ»ē„¦ē‚¹ēš„ē¼–č¾‘å™Øē»„äø­ēš„ę“»åŠØé€‰é”¹å”ēš„č¾¹ę”†ć€‚é€‰é”¹å”ę˜Æē¼–č¾‘å™ØåŒŗåŸŸäø­ē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„å­˜åœØå¤šäøŖē¼–č¾‘å™Øē»„ć€‚", "tabActiveForeground": "ę“»åŠØē»„äø­ę“»åŠØé€‰é”¹å”ēš„å‰ę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", "tabInactiveForeground": "ę“»åŠØē»„äø­éžę“»åŠØé€‰é”¹å”ēš„å‰ę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", - "tabUnfocusedActiveForeground": "éžę“»åŠØē»„äø­ę“»åŠØé€‰é”¹å”ēš„å‰ę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", - "tabUnfocusedInactiveForeground": "éžę“»åŠØē»„äø­éžę“»åŠØé€‰é”¹å”ēš„å‰ę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", + "tabUnfocusedActiveForeground": "äø€äøŖå¤±åŽ»ē„¦ē‚¹ēš„ē¼–č¾‘å™Øē»„äø­ēš„ę“»åŠØé€‰é”¹å”ēš„å‰ę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", + "tabUnfocusedInactiveForeground": "åœØäø€äøŖå¤±åŽ»ē„¦ē‚¹ēš„ē»„äø­éžę“»åŠØé€‰é”¹å”ēš„å‰ę™Æč‰²ć€‚åœØē¼–č¾‘å™ØåŒŗåŸŸļ¼Œé€‰é”¹å”ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚åÆåœØäø€äøŖē¼–č¾‘å™Øē»„äø­ę‰“å¼€å¤šäøŖé€‰é”¹å”ć€‚åÆä»„ęœ‰å¤šäøŖē¼–č¾‘å™Øē»„ć€‚", "editorGroupBackground": "ē¼–č¾‘å™Øē»„ēš„čƒŒę™Æé¢œč‰²ć€‚ē¼–č¾‘å™Øē»„ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚ę­¤é¢œč‰²åœØę‹–åŠØē¼–č¾‘å™Øē»„ę—¶ę˜¾ē¤ŗć€‚", "tabsContainerBackground": "åÆē”Øé€‰é”¹å”ę—¶ē¼–č¾‘å™Øē»„ę ‡é¢˜ēš„čƒŒę™Æé¢œč‰²ć€‚ē¼–č¾‘å™Øē»„ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚", "tabsContainerBorder": "é€‰é”¹å”åÆē”Øę—¶ē¼–č¾‘å™Øē»„ę ‡é¢˜ēš„č¾¹ę”†é¢œč‰²ć€‚ē¼–č¾‘å™Øē»„ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚", @@ -18,15 +20,16 @@ "editorGroupBorder": "å°†å¤šäøŖē¼–č¾‘å™Øē»„å½¼ę­¤åˆ†éš”å¼€ēš„é¢œč‰²ć€‚ē¼–č¾‘å™Øē»„ę˜Æē¼–č¾‘å™Øēš„å®¹å™Øć€‚", "editorDragAndDropBackground": "ę‹–åŠØē¼–č¾‘å™Øę—¶ēš„čƒŒę™Æé¢œč‰²ć€‚ę­¤é¢œč‰²åŗ”ęœ‰é€ę˜Žåŗ¦ļ¼Œä»„ä¾æē¼–č¾‘å™Øå†…å®¹čƒ½é€čæ‡čƒŒę™Æć€‚", "panelBackground": "é¢ęæēš„čƒŒę™Æč‰²ć€‚é¢ęæę˜¾ē¤ŗåœØē¼–č¾‘å™ØåŒŗåŸŸäø‹ę–¹ļ¼ŒåÆåŒ…å«č¾“å‡ŗå’Œé›†ęˆē»ˆē«Æē­‰č§†å›¾ć€‚", - "panelBorder": "åˆ†éš”åˆ°ē¼–č¾‘å™Øēš„é”¶éƒØé¢ęæč¾¹ę”†č‰²ć€‚é¢ęæę˜¾ē¤ŗåœØē¼–č¾‘å™ØåŒŗåŸŸäø‹ę–¹ļ¼ŒåÆåŒ…å«č¾“å‡ŗå’Œé›†ęˆē»ˆē«Æē­‰č§†å›¾ć€‚", "panelActiveTitleForeground": "ę“»åŠØé¢ęæēš„ę ‡é¢˜é¢œč‰²ć€‚é¢ęæę˜¾ē¤ŗåœØē¼–č¾‘å™ØåŒŗåŸŸäø‹ę–¹ļ¼Œå¹¶åŒ…å«č¾“å‡ŗå’Œé›†ęˆē»ˆē«Æē­‰č§†å›¾ć€‚", "panelInactiveTitleForeground": "éžę“»åŠØé¢ęæēš„ę ‡é¢˜é¢œč‰²ć€‚é¢ęæę˜¾ē¤ŗåœØē¼–č¾‘å™ØåŒŗåŸŸäø‹ę–¹ļ¼Œå¹¶åŒ…å«č¾“å‡ŗå’Œé›†ęˆē»ˆē«Æē­‰č§†å›¾ć€‚", "panelActiveTitleBorder": "ę“»åŠØé¢ęæēš„č¾¹ę”†é¢œč‰²ć€‚é¢ęæę˜¾ē¤ŗåœØē¼–č¾‘å™ØåŒŗåŸŸäø‹ę–¹ļ¼ŒåŒ…å«č¾“å‡ŗå’Œé›†ęˆē»ˆē«Æē­‰č§†å›¾ć€‚", - "statusBarForeground": "ēŠ¶ę€ę å‰ę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", + "panelDragAndDropBackground": "é¢ęæę ‡é¢˜é”¹åœØę‹–ę”¾ę—¶ēš„åé¦ˆé¢œč‰²ć€‚ę­¤é¢œč‰²åŗ”ęœ‰é€ę˜Žåŗ¦ļ¼Œä»„ä¾æé¢ęæé”¹ä»čƒ½é€čæ‡ć€‚é¢ęæę˜¾ē¤ŗåœØē¼–č¾‘å™ØåŒŗåŸŸäø‹ę–¹ļ¼ŒåŒ…å«č¾“å‡ŗå’Œé›†ęˆē»ˆē«Æē­‰č§†å›¾ć€‚", + "statusBarForeground": "å·„ä½œåŒŗę‰“å¼€ę—¶ēŠ¶ę€ę ēš„å‰ę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", "statusBarNoFolderForeground": "ę²”ęœ‰ę‰“å¼€ę–‡ä»¶å¤¹ę—¶ēŠ¶ę€ę ēš„å‰ę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", - "statusBarBackground": "ę ‡å‡†ēŠ¶ę€ę čƒŒę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", + "statusBarBackground": "å·„ä½œåŒŗę‰“å¼€ę—¶ēŠ¶ę€ę ēš„čƒŒę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", "statusBarNoFolderBackground": "ę²”ęœ‰ę‰“å¼€ę–‡ä»¶å¤¹ę—¶ēŠ¶ę€ę ēš„čƒŒę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", "statusBarBorder": "ēŠ¶ę€ę åˆ†éš”ä¾§č¾¹ę å’Œē¼–č¾‘å™Øēš„č¾¹ę”†é¢œč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", + "statusBarNoFolderBorder": "å½“ę²”ęœ‰ę‰“å¼€ę–‡ä»¶å¤¹ę—¶ļ¼Œē”Øę„ä½æēŠ¶ę€ę äøŽä¾§č¾¹ę ć€ē¼–č¾‘å™Øåˆ†éš”ēš„ēŠ¶ę€ę č¾¹ę”†é¢œč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", "statusBarItemActiveBackground": "å•å‡»ę—¶ēš„ēŠ¶ę€ę é”¹čƒŒę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", "statusBarItemHoverBackground": "ę‚¬åœę—¶ēš„ēŠ¶ę€ę é”¹čƒŒę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", "statusBarProminentItemBackground": "ēŠ¶ę€ę ēŖå‡ŗę˜¾ē¤ŗé”¹ēš„čƒŒę™Æé¢œč‰²ć€‚ēŖå‡ŗę˜¾ē¤ŗé”¹ęÆ”ēŠ¶ę€ę äø­ēš„å…¶ä»–ę”ē›®ę›“ę˜¾ēœ¼ļ¼Œč”Øę˜Žå…¶é‡č¦ę€§ę›“é«˜ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚", @@ -41,6 +44,7 @@ "sideBarForeground": "ä¾§č¾¹ę å‰ę™Æč‰²ć€‚ä¾§č¾¹ę ę˜Æčµ„ęŗē®”ē†å™Øå’Œęœē“¢ē­‰č§†å›¾ēš„å®¹å™Øć€‚", "sideBarBorder": "ä¾§č¾¹ę åˆ†éš”ē¼–č¾‘å™Øēš„č¾¹ę”†é¢œč‰²ć€‚ä¾§č¾¹ę åŒ…å«čµ„ęŗē®”ē†å™Øć€ęœē“¢ē­‰č§†å›¾ć€‚", "sideBarTitleForeground": "ä¾§č¾¹ę ę ‡é¢˜å‰ę™Æč‰²ć€‚ä¾§č¾¹ę ę˜Æčµ„ęŗē®”ē†å™Øå’Œęœē“¢ē­‰č§†å›¾ēš„å®¹å™Øć€‚", + "sideBarDragAndDropBackground": "ä¾§č¾¹ę äø­ēš„éƒØåˆ†åœØę‹–ę”¾ę—¶ēš„åé¦ˆé¢œč‰²ć€‚ę­¤é¢œč‰²åŗ”ęœ‰é€ę˜Žåŗ¦ļ¼Œä»„ä¾æä¾§č¾¹ę äø­ēš„éƒØåˆ†ä»čƒ½é€čæ‡ć€‚ä¾§č¾¹ę ę˜Æčµ„ęŗē®”ē†å™Øå’Œęœē“¢ē­‰č§†å›¾ēš„å®¹å™Øć€‚", "sideBarSectionHeaderBackground": "ä¾§č¾¹ę čŠ‚ę ‡é¢˜ēš„čƒŒę™Æé¢œč‰²ć€‚ä¾§č¾¹ę ę˜Æčµ„ęŗē®”ē†å™Øå’Œęœē“¢ē­‰č§†å›¾ēš„å®¹å™Øć€‚", "sideBarSectionHeaderForeground": "ä¾§č¾¹ę čŠ‚ę ‡é¢˜ēš„å‰ę™Æč‰²ć€‚ä¾§č¾¹ę åŒ…ę‹¬čµ„ęŗē®”ē†å™Øć€ęœē“¢ē­‰č§†å›¾ć€‚", "titleBarActiveForeground": "ēŖ—å£å¤„äŗŽę“»åŠØēŠ¶ę€ę—¶ēš„ę ‡é¢˜ę å‰ę™Æč‰²ć€‚čÆ·ę³Øę„ļ¼ŒčÆ„é¢œč‰²å½“å‰ä»…åœØ macOS äøŠå—ę”ÆęŒć€‚", diff --git a/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json index 8ae95a486e8..47bc050edeb 100644 --- a/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/chs/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "åÆ¼čˆŖåˆ°äøŠę–¹č§†å›¾", "navigateDown": "åÆ¼čˆŖåˆ°äø‹ę–¹č§†å›¾", "increaseViewSize": "å¢žåŠ å½“å‰č§†å›¾å¤§å°", - "decreaseViewSize": "å‡å°å½“å‰č§†å›¾å¤§å°" + "decreaseViewSize": "å‡å°å½“å‰č§†å›¾å¤§å°", + "showPreviousTab": "ę˜¾ē¤ŗäøŠäø€äøŖēŖ—å£é€‰é”¹å”", + "showNextWindowTab": "ę˜¾ē¤ŗäø‹äø€äøŖēŖ—å£é€‰é”¹å”", + "moveWindowTabToNewWindow": "å°†ēŖ—å£é€‰é”¹å”ē§»åŠØåˆ°ę–°ēŖ—å£", + "mergeAllWindowTabs": "åˆå¹¶ę‰€ęœ‰ēŖ—å£", + "toggleWindowTabsBar": "åˆ‡ę¢ēŖ—å£é€‰é”¹å”ę " } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/chs/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..c8f8f1edc8f --- /dev/null +++ b/i18n/chs/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "é…ē½®čÆ­čØ€", + "displayLanguage": "定义 VSCode ēš„ę˜¾ē¤ŗčÆ­čØ€ć€‚", + "doc": "čÆ·å‚é˜… {0}ļ¼Œäŗ†č§£ę”ÆęŒēš„čÆ­čØ€åˆ—č”Øć€‚", + "restart": "ę›“ę”¹ę­¤å€¼éœ€č¦é‡åÆ VSCode怂", + "fail.createSettings": "ę— ę³•åˆ›å»ŗā€œ{0}ā€({1})怂", + "JsonSchema.locale": "č¦ä½æē”Øēš„ UI 语言。" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json index 67f3c1b175d..b5e0d10d18f 100644 --- a/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,17 +10,25 @@ "workspaces": "巄作区", "developer": "å¼€å‘č€…", "showEditorTabs": "ęŽ§åˆ¶ę‰“å¼€ēš„ē¼–č¾‘å™Øę˜Æå¦ę˜¾ē¤ŗåœØé€‰é”¹å”äø­ć€‚", + "workbench.editor.labelFormat.default": "ę˜¾ē¤ŗę–‡ä»¶åć€‚å½“åÆē”Øé€‰é”¹å”äø”åœØåŒäø€ē»„å†…ęœ‰äø¤äøŖē›øåŒåē§°ēš„ę–‡ä»¶ę—¶ļ¼Œå°†ę·»åŠ ęÆäøŖę–‡ä»¶č·Æå¾„äø­åÆä»„ē”ØäŗŽåŒŗåˆ†ēš„éƒØåˆ†ć€‚åœØé€‰é”¹å”č¢«ē¦ē”Øäø”ē¼–č¾‘å™Øę“»åŠØę—¶ļ¼Œå°†ę˜¾ē¤ŗē›øåÆ¹äŗŽå·„ä½œåŒŗę–‡ä»¶å¤¹ēš„č·Æå¾„ć€‚", + "workbench.editor.labelFormat.short": "åœØę–‡ä»¶ēš„ē›®å½•åä¹‹åŽę˜¾ē¤ŗę–‡ä»¶åć€‚", + "workbench.editor.labelFormat.medium": "åœØę–‡ä»¶ē›øåÆ¹å½“å‰å·„ä½œåŒŗę–‡ä»¶å¤¹ēš„č·Æå¾„ä¹‹åŽę˜¾ē¤ŗę–‡ä»¶åć€‚", + "workbench.editor.labelFormat.long": "åœØę–‡ä»¶ēš„ē»åÆ¹č·Æå¾„ä¹‹åŽę˜¾ē¤ŗę–‡ä»¶åć€‚", + "tabDescription": "ęŽ§åˆ¶ē¼–č¾‘å™Øę ‡ē­¾ēš„ę ¼å¼ć€‚äæ®ę”¹čæ™é”¹č®¾ē½®ä¼šč®©ę–‡ä»¶ēš„č·Æå¾„ę›“å®¹ę˜“ē†č§£ļ¼š\n- short: \"parent\"\n- medium: \"workspace/src/parent\"\n- long: \"/home/user/workspace/src/parent\"\n- default: å½“äøŽå¦äø€é€‰é”¹å”ę ‡é¢˜ē›øåŒę—¶äøŗ \".../parent\"ć€‚é€‰é”¹å”č¢«ē¦ē”Øę—¶åˆ™äøŗē›øåÆ¹å·„ä½œåŒŗč·Æå¾„", "editorTabCloseButton": "ęŽ§åˆ¶ē¼–č¾‘å™Øēš„é€‰é”¹å”å…³é—­ęŒ‰é’®ēš„ä½ē½®ļ¼Œęˆ–å½“č®¾ē½®äøŗ \"off\" ę—¶ē¦ē”Øå…³é—­å®ƒä»¬ć€‚", "showIcons": "ęŽ§åˆ¶ę‰“å¼€ēš„ē¼–č¾‘å™Øę˜Æå¦éšå›¾ę ‡äø€čµ·ę˜¾ē¤ŗć€‚čæ™čæ˜éœ€åÆē”Øå›¾ę ‡äø»é¢˜ć€‚", - "enablePreview": "ęŽ§åˆ¶ę‰“å¼€ēš„ē¼–č¾‘å™Øę˜Æå¦ę˜¾ē¤ŗäøŗé¢„č§ˆć€‚é¢„č§ˆē¼–č¾‘å™ØåÆä»„é‡ę–°ä½æē”Øļ¼Œē›“åˆ°å°†å…¶äæē•™(ä¾‹å¦‚ļ¼ŒåŒå‡»ęˆ–ē¼–č¾‘)怂", + "enablePreview": "ęŽ§åˆ¶ę˜Æå¦å°†ę‰“å¼€ēš„ē¼–č¾‘å™Øę˜¾ē¤ŗäøŗé¢„č§ˆć€‚é¢„č§ˆē¼–č¾‘å™Øå°†ä¼šé‡ē”Øč‡³å…¶č¢«äæē•™(ä¾‹å¦‚ļ¼Œé€ščæ‡åŒå‡»ęˆ–ē¼–č¾‘)ļ¼Œäø”å…¶å­—ä½“ę ·å¼å°†äøŗę–œä½“ć€‚", "enablePreviewFromQuickOpen": "ęŽ§åˆ¶ Quick Open äø­ę‰“å¼€ēš„ē¼–č¾‘å™Øę˜Æå¦ę˜¾ē¤ŗäøŗé¢„č§ˆć€‚é¢„č§ˆē¼–č¾‘å™ØåÆä»„é‡ę–°ä½æē”Øļ¼Œē›“åˆ°å°†å…¶äæē•™(ä¾‹å¦‚ļ¼Œé€ščæ‡åŒå‡»ęˆ–ē¼–č¾‘)怂", "editorOpenPositioning": "ęŽ§åˆ¶ę‰“å¼€ē¼–č¾‘å™Øēš„ä½ē½®ć€‚é€‰ę‹©ā€œå·¦ä¾§ā€ęˆ–ā€œå³ä¾§ā€ä»„åœØå½“å‰ę“»åŠØä½ē½®ēš„å·¦ä¾§ęˆ–å³ä¾§ę‰“å¼€ē¼–č¾‘å™Øć€‚é€‰ę‹©ā€œē¬¬äø€äøŖā€ęˆ–ā€œęœ€åŽäø€äøŖā€ä»„ä»Žå½“å‰ę“»åŠØä½ē½®ē‹¬ē«‹ę‰“å¼€ē¼–č¾‘å™Øć€‚", "revealIfOpen": "ęŽ§åˆ¶ę‰“å¼€ę—¶ē¼–č¾‘å™Øę˜Æå¦ę˜¾ē¤ŗåœØä»»ä½•åÆč§ē»„äø­ć€‚å¦‚ęžœē¦ē”Øļ¼Œē¼–č¾‘å™Øä¼šä¼˜å…ˆåœØå½“å‰ę“»åŠØē¼–č¾‘å™Øē»„äø­ę‰“å¼€ć€‚å¦‚ęžœåÆē”Øļ¼Œä¼šę˜¾ē¤ŗå·²ę‰“å¼€ēš„ē¼–č¾‘å™Øč€Œäøę˜ÆåœØå½“å‰ę“»åŠØē¼–č¾‘å™Øē»„äø­å†ę¬”ę‰“å¼€ć€‚čÆ·ę³Øę„ļ¼Œęœ‰äŗ›ęƒ…å†µäø‹ä¼šåæ½ē•„ę­¤č®¾ē½®ļ¼Œä¾‹å¦‚å¼ŗåˆ¶ē¼–č¾‘å™ØåœØē‰¹å®šē»„äø­ęˆ–åœØå½“å‰ę“»åŠØē»„ēš„č¾¹ä¾§ę‰“å¼€ę—¶ć€‚", - "commandHistory": "ęŽ§åˆ¶å‘½ä»¤é¢ęæäø­äæē•™ęœ€čæ‘ä½æē”Øå‘½ä»¤ēš„ę•°é‡ć€‚č®¾ē½®äøŗ 0 åˆ™ē¦ē”Øå‘½ä»¤åŽ†å²č®°å½•ć€‚", + "commandHistory": "ęŽ§åˆ¶å‘½ä»¤é¢ęæäø­äæē•™ęœ€čæ‘ä½æē”Øå‘½ä»¤ēš„ę•°é‡ć€‚č®¾ē½®äøŗ 0 ę—¶ē¦ē”Øå‘½ä»¤åŽ†å²åŠŸčƒ½ć€‚", "preserveInput": "ęŽ§åˆ¶ę˜Æå¦åœØå†ę¬”ę‰“å¼€å‘½ä»¤é¢ęæę—¶ę¢å¤äøŠäø€ę¬”ēš„č¾“å…„å†…å®¹ć€‚", "closeOnFocusLost": "ęŽ§åˆ¶ Quick Open ę˜Æå¦åŗ”åœØå¤±åŽ»ē„¦ē‚¹ę—¶č‡ŖåŠØå…³é—­ć€‚", "openDefaultSettings": "ęŽ§åˆ¶ę‰“å¼€č®¾ē½®ę—¶ę˜Æå¦ę‰“å¼€ę˜¾ē¤ŗę‰€ęœ‰é»˜č®¤č®¾ē½®ēš„ē¼–č¾‘å™Øć€‚", + "experimentalFuzzySearchEndpoint": "č”Øē¤ŗē”ØäŗŽå®žéŖŒę€§č®¾ē½®ęœē“¢ēš„ē«Æē‚¹ć€‚", + "experimentalFuzzySearchKey": "č”Øē¤ŗē”ØäŗŽå®žéŖŒę€§č®¾ē½®ęœē“¢ēš„åÆ†é’„ć€‚", "sideBarLocation": "ęŽ§åˆ¶č¾¹ę ēš„ä½ē½®ć€‚å®ƒåÆę˜¾ē¤ŗåœØå·„ä½œå°ēš„å·¦ä¾§ęˆ–å³ä¾§ć€‚", + "panelLocation": "ęŽ§åˆ¶é¢ęæēš„ä½ē½®ć€‚å®ƒåÆę˜¾ē¤ŗåœØå·„ä½œå°ēš„åŗ•éƒØęˆ–å³ä¾§ć€‚", "statusBarVisibility": "ęŽ§åˆ¶å·„ä½œå°åŗ•éƒØēŠ¶ę€ę ēš„åÆč§ę€§ć€‚", "activityBarVisibility": "ęŽ§åˆ¶å·„ä½œå°äø­ę“»åŠØę ēš„åÆč§ę€§ć€‚", "closeOnFileDelete": "ęŽ§åˆ¶ę–‡ä»¶č¢«å…¶ä»–ęŸäŗ›čæ›ēØ‹åˆ é™¤ęˆ–é‡å‘½åę—¶ę˜Æå¦åŗ”čÆ„č‡ŖåŠØå…³é—­ę˜¾ē¤ŗę–‡ä»¶ēš„ē¼–č¾‘å™Øć€‚ē¦ē”Øę­¤é”¹ä¼šäæęŒē¼–č¾‘å™Øä½œäøŗę­¤ē±»äŗ‹ä»¶ēš„č„ę–‡ä»¶ę‰“å¼€ć€‚čÆ·ę³Øę„ļ¼Œä»Žåŗ”ē”ØēØ‹åŗå†…éƒØčæ›č”Œåˆ é™¤ę“ä½œä¼šå§‹ē»ˆå…³é—­ē¼–č¾‘å™Øļ¼Œå¹¶äø”č„ę–‡ä»¶å§‹ē»ˆäøä¼šå…³é—­ä»„äæå­˜ę•°ę®ć€‚", @@ -45,7 +53,7 @@ "restoreWindows": "ęŽ§åˆ¶é‡åÆåŽé‡ę–°ę‰“å¼€ēŖ—å£ēš„ę–¹å¼ć€‚é€‰ę‹© \"none\" åˆ™ę°øčæœåœØåÆåŠØę—¶ę‰“å¼€äø€äøŖē©ŗå·„ä½œåŒŗļ¼Œ\"one\" åˆ™é‡ę–°ę‰“å¼€ęœ€åŽä½æē”Øēš„ēŖ—å£ļ¼Œ\"folders\" åˆ™é‡ę–°ę‰“å¼€ę‰€ęœ‰å«ęœ‰ę–‡ä»¶å¤¹ēš„ēŖ—å£ļ¼Œ\"all\" åˆ™é‡ę–°ę‰“å¼€äøŠę¬”ä¼ščÆēš„ę‰€ęœ‰ēŖ—å£ć€‚", "restoreFullscreen": "å¦‚ęžœēŖ—å£å·²é€€å‡ŗå…Øå±ęØ”å¼ļ¼ŒęŽ§åˆ¶å…¶ę˜Æå¦åŗ”čæ˜åŽŸäøŗå…Øå±ęØ”å¼ć€‚", "zoomLevel": "č°ƒę•“ēŖ—å£ēš„ē¼©ę”¾ēŗ§åˆ«ć€‚åŽŸå§‹å¤§å°ę˜Æ 0ļ¼ŒęÆę¬”é€’å¢ž(例如 1)ęˆ–é€’å‡(例如 -1)č”Øē¤ŗę”¾å¤§ęˆ–ē¼©å° 20%ć€‚ä¹ŸåÆä»„č¾“å…„å°ę•°ä»„ä¾æä»„ę›“ē²¾ē»†ēš„ē²’åŗ¦č°ƒę•“ē¼©ę”¾ēŗ§åˆ«ć€‚", - "title": "åŸŗäŗŽę“»åŠØē¼–č¾‘å™ØęŽ§åˆ¶ēŖ—å£ę ‡é¢˜ć€‚å˜é‡åŸŗäŗŽäøŠäø‹ę–‡čæ›č”Œę›æę¢:\n${activeEditorShort}: 例如 myFile.txt\n${activeEditorMedium}: 例如 myFolder/myFile.txt\n${activeEditorLong}: 例如 /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 例如 myFolder\n${folderPath}: 例如 /Users/Development/myFolder\n${rootName}: 例如 myFolder1, myFolder2, myFolder3\n${rootPath}: 例如 /Users/Development/myWorkspace\n${appName}: 例如 VS Code\n${dirty}: ę›“ę–°ēš„ęŒ‡ē¤ŗå™Ø(å¦‚ęžœę“»åŠØē¼–č¾‘å™Øå·²ę›“ę–°)\n${separator}: ä»…åœØč¢«åø¦å€¼ēš„å˜é‡åŒ…å›“ę—¶ę˜¾ē¤ŗēš„ę”ä»¶åˆ†éš”ē¬¦(\" - \")", + "title": "ę ¹ę®ę“»åŠØē¼–č¾‘å™ØęŽ§åˆ¶ēŖ—å£ę ‡é¢˜ć€‚å˜é‡åŸŗäŗŽäøŠäø‹ę–‡čæ›č”Œę›æę¢:\n${activeEditorShort}: ę–‡ä»¶å (如 myFile.txt)\n${activeEditorMedium}: ē›øåÆ¹äŗŽå·„ä½œåŒŗę–‡ä»¶å¤¹ēš„ę–‡ä»¶č·Æå¾„ (如 myFolder/myFile.txt)\n${activeEditorLong}: ę–‡ä»¶ēš„å®Œę•“č·Æå¾„ (如 /Users/Development/myProject/myFolder/myFile.txt)\n${folderName}: ę–‡ä»¶ę‰€åœØå·„ä½œåŒŗę–‡ä»¶å¤¹åē§° (如 myFolder)\n${folderPath}: ę–‡ä»¶ę‰€åœØå·„ä½œåŒŗę–‡ä»¶å¤¹č·Æå¾„ (如 /Users/Development/myFolder)\n${rootName}: å·„ä½œåŒŗåē§° (如 myFolder ꈖ myWorkspace)\n${rootPath}: å·„ä½œåŒŗč·Æå¾„ (如 /Users/Development/myWorkspace)\n${appName}: 如 VS Code\n${dirty}: ę“»åŠØē¼–č¾‘å™Øęœ‰ę›“ę–°ę—¶ę˜¾ē¤ŗēš„ę›“ę–°ęŒ‡ē¤ŗå™Ø\n${separator}: ä»…åœØč¢«ęœ‰å€¼å˜é‡åŒ…å›“ę—¶ę˜¾ē¤ŗēš„åˆ†éš”ē¬¦ (\" - \")", "window.newWindowDimensions.default": "åœØå±å¹•äø­åæƒę‰“å¼€ę–°ēŖ—å£ć€‚", "window.newWindowDimensions.inherit": "ä»„äøŽäøŠäø€äøŖę“»åŠØēŖ—å£ē›øåŒēš„å°ŗåÆøę‰“å¼€ę–°ēŖ—å£ć€‚", "window.newWindowDimensions.maximized": "ę‰“å¼€ęœ€å¤§åŒ–ēš„ę–°ēŖ—å£ć€‚", diff --git a/i18n/chs/src/vs/workbench/electron-browser/window.i18n.json b/i18n/chs/src/vs/workbench/electron-browser/window.i18n.json index 8c0ddc480b2..b2c1d0e6763 100644 --- a/i18n/chs/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/chs/src/vs/workbench/electron-browser/window.i18n.json @@ -9,7 +9,5 @@ "cut": "å‰Ŗåˆ‡", "copy": "复制", "paste": "粘蓓", - "selectAll": "全选", - "confirmOpen": "ę˜Æå¦ē”®å®šč¦ę‰“å¼€ {0} 个巄作区?", - "confirmOpenButton": "打开(&&O)..." + "selectAll": "全选" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/cli/electron-browser/cli.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/cli/electron-browser/cli.contribution.i18n.json index add50cfaa2f..b65abddcfc9 100644 --- a/i18n/chs/src/vs/workbench/parts/cli/electron-browser/cli.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/cli/electron-browser/cli.contribution.i18n.json @@ -7,7 +7,7 @@ "install": "在 PATH äø­å®‰č£…ā€œ{0}ā€å‘½ä»¤", "not available": "ę­¤å‘½ä»¤äøåÆē”Ø", "successIn": "已成功在 PATH 中安装了 Shell å‘½ä»¤ā€œ{0}ā€ć€‚", - "warnEscalation": "ä»£ē å°†é€ščæ‡ \"osascript\" ęē¤ŗéœ€č¦ē®”ē†å‘˜ęƒé™ę‰åÆå®‰č£… shell 命令。", + "warnEscalation": "Code 将使用 \"osascript\" ę„ęē¤ŗčŽ·å–ē®”ē†å‘˜ęƒé™ļ¼Œčæ›äø€ę­„å®‰č£… shell 命令。", "ok": "甮定", "cantCreateBinFolder": "ę— ę³•åˆ›å»ŗ \"/usr/local/bin\"怂", "cancel2": "å–ę¶ˆ", diff --git a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.i18n.json b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.i18n.json index 9085c535771..c01de26c1f1 100644 --- a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "emergencyConfOn": "ę­£åœØę›“ę”¹ā€œeditor.accessibilitySupportā€č®¾ē½®äøŗā€œonā€ć€‚", + "emergencyConfOn": "ēŽ°åœØå°†č®¾ē½® \"editor.accessibilitySupport\" 曓改为 \"on\"怂", "openingDocs": "ę­£åœØę‰“å¼€ VS Code č¾…åŠ©åŠŸčƒ½ę–‡ę”£é”µé¢ć€‚", "introMsg": "ę„Ÿč°¢čÆ•ē”Ø VS Code ēš„č¾…åŠ©åŠŸčƒ½é€‰é”¹ć€‚", "status": "ēŠ¶ę€:", diff --git a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 93a9ae990e3..46005b8487d 100644 --- a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "å¦‚ęžœęŸäø€č”ŒåŒ¹é…ę­¤ęØ”å¼ļ¼Œé‚£ä¹ˆäøåŗ”ę›“ę”¹ę­¤č”Œēš„ē¼©čæ›ļ¼Œäø”äøåŗ”é’ˆåÆ¹å…¶ä»–č§„åˆ™åÆ¹å…¶čæ›č”Œč®”ē®—ć€‚", "schema.indentationRules.unIndentedLinePattern.pattern": "unIndentedLinePattern ēš„ę­£åˆ™č”Øč¾¾å¼ęØ”å¼ć€‚", "schema.indentationRules.unIndentedLinePattern.flags": "unIndentedLinePattern ēš„ę­£åˆ™č”Øč¾¾å¼ę ‡åæ—ć€‚", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "åæ…é”»åŒ¹é…ęØ”å¼ā€œ/^([gimuy]+)$/ā€ć€‚" + "schema.indentationRules.unIndentedLinePattern.errorMessage": "åæ…é”»åŒ¹é…ęØ”å¼ā€œ/^([gimuy]+)$/ā€ć€‚", + "schema.folding": "ę­¤čÆ­čØ€ēš„ęŠ˜å č®¾ē½®ć€‚", + "schema.folding.offSide": "č‹„äø€ē§čÆ­čØ€ä½æē”Øē¼©čæ›č”Øē¤ŗå…¶ä»£ē å—ļ¼Œå®ƒå°†éµå¾Ŗč¶Šä½č§„åˆ™ (off-side rule)ć€‚č‹„č®¾ē½®ę­¤é”¹ļ¼Œē©ŗē™½č”Œå°†å±žäŗŽå…¶ä¹‹åŽēš„ä»£ē å—ć€‚", + "schema.folding.markers": "čÆ­čØ€ē‰¹å®šēš„ęŠ˜å ę ‡č®°ć€‚ä¾‹å¦‚ļ¼Œ\"#region\" äøŽ \"#endregion\"ć€‚å¼€å§‹äøŽē»“ęŸę ‡č®°ēš„ę­£åˆ™č”Øč¾¾å¼éœ€č®¾č®”å¾—ę•ˆēŽ‡é«˜ļ¼Œå› å…¶å°†åÆ¹ęÆäø€č”Œēš„å†…å®¹čæ›č”Œęµ‹čÆ•ć€‚", + "schema.folding.markers.start": "å¼€å§‹ę ‡č®°ēš„ę­£åˆ™č”Øč¾¾å¼ęØ”å¼ć€‚å…¶åŗ”ä»„ \"^\" 开始。", + "schema.folding.markers.end": "ē»“ęŸę ‡č®°ēš„ę­£åˆ™č”Øč¾¾å¼ęØ”å¼ć€‚å…¶åŗ”ä»„ \"^\" 开始。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..a381c9562f9 --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "ęŸ„ēœ‹: åˆ‡ę¢å°åœ°å›¾" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index f19f82c9b16..8f88c510842 100644 --- a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "åˆ‡ę¢ęŽ§åˆ¶å­—ē¬¦" + "toggleRenderControlCharacters": "ęŸ„ēœ‹: åˆ‡ę¢ęŽ§åˆ¶å­—ē¬¦" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 455b405c313..4666a1892d7 100644 --- a/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "åˆ‡ę¢å‘ˆēŽ°ē©ŗę ¼" + "toggleRenderWhitespace": "ęŸ„ēœ‹: åˆ‡ę¢å‘ˆēŽ°ē©ŗę ¼" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 1b158fedfe7..6c03799a8b6 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}ļ¼Œč°ƒčÆ•", "debugAriaLabel": "é”®å…„åÆåŠØé…ē½®ēš„åē§°ä»„čæč”Œć€‚", + "addConfigTo": "ę·»åŠ é…ē½® ({0})...", + "addConfiguration": "ę·»åŠ é…ē½®...", "noConfigurationsMatching": "ę— ä»»ä½•č°ƒčÆ•é…ē½®åŒ¹é…", "noConfigurationsFound": "ę‰¾äøåˆ°ä»»ä½•č°ƒčÆ•é…ē½®ć€‚čÆ·åˆ›å»ŗäø€äøŖ \"launch.json\" ꖇ件怂" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..fcbe0434d7e --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "čšē„¦äŗŽå˜é‡č§†å›¾", + "debugFocusWatchView": "čšē„¦äŗŽē›‘č§†č§†å›¾", + "debugFocusCallStackView": "čšē„¦äŗŽč°ƒē”Øå †ę ˆč§†å›¾", + "debugFocusBreakpointsView": "čšē„¦äŗŽę–­ē‚¹č§†å›¾" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 327f1b6fd82..fd6211c4e06 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "ē”ØäŗŽē”Ÿęˆåˆå§‹ \"launch.json\" ēš„é…ē½®ć€‚", "vscode.extension.contributes.debuggers.languages": "åÆčƒ½č¢«č§†äøŗā€œé»˜č®¤č°ƒčÆ•ēØ‹åŗā€ēš„č°ƒčÆ•ę‰©å±•ēš„čÆ­čØ€åˆ—č”Øć€‚", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "å¦‚ęžœęŒ‡å®šēš„ VS Code å°†č°ƒē”Øę­¤å‘½ä»¤ä»„ē”®å®šč°ƒčÆ•é€‚é…å™Øēš„åÆę‰§č”Œč·Æå¾„å’Œč¦ä¼ é€’ēš„å‚ę•°ć€‚", - "vscode.extension.contributes.debuggers.startSessionCommand": "å¦‚ęžœęŒ‡å®šēš„ VS Code å°†äøŗé’ˆåÆ¹ę­¤ę‰©å±•ēš„ā€œč°ƒčÆ•ā€ęˆ–ā€œčæč”Œā€ę“ä½œč°ƒē”Øę­¤å‘½ä»¤ć€‚", "vscode.extension.contributes.debuggers.configurationSnippets": "ē”ØäŗŽåœØ \"launch.json\" äø­ę·»åŠ ę–°é…ē½®ēš„ä»£ē ę®µć€‚", "vscode.extension.contributes.debuggers.configurationAttributes": "ē”ØäŗŽéŖŒčÆ \"launch.json\" ēš„ JSON ęž¶ęž„é…ē½®ć€‚", "vscode.extension.contributes.debuggers.windows": "Windows ē‰¹å®šēš„č®¾ē½®ć€‚", diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 5156b83be6d..2447a5efc53 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,14 +12,14 @@ "breakpointRemoved": "å·²åˆ é™¤ę–­ē‚¹ļ¼Œč”Œ {0}ļ¼Œę–‡ä»¶ {1}", "compoundMustHaveConfigurations": "å¤åˆé”¹åæ…é”»ę‹„ęœ‰ \"configurations\" å±žę€§é›†ļ¼Œę‰čƒ½åÆåŠØå¤šäøŖé…ē½®ć€‚", "configMissing": "\"launch.json\" äø­ē¼ŗå°‘é…ē½®ā€œ{0}ā€ć€‚", + "debugRequestNotSupported": "ę‰€é€‰č°ƒčÆ•é…ē½®ēš„å±žę€§ā€œ{0}ā€ēš„å€¼ā€œ{1}ā€äøå—ę”ÆęŒć€‚", "debugTypeNotSupported": "é…ē½®ēš„ē±»åž‹ā€œ{0}ā€äøå—ę”ÆęŒć€‚", "debugTypeMissing": "ę‰€é€‰ēš„åÆåŠØé…ē½®ē¼ŗå°‘å±žę€§ \"type\"怂", + "debugAnyway": "ä»čæ›č”Œč°ƒčÆ•", "preLaunchTaskErrors": "preLaunchTaskā€œ{0}ā€ęœŸé—“ę£€ęµ‹åˆ°å¤šäøŖē”Ÿęˆé”™čÆÆć€‚", "preLaunchTaskError": "preLaunchTaskā€œ{0}ā€ęœŸé—“ę£€ęµ‹åˆ°äø€äøŖē”Ÿęˆé”™čÆÆć€‚", "preLaunchTaskExitCode": "preLaunchTaskā€œ{0}ā€å·²ē»ˆę­¢ļ¼Œé€€å‡ŗä»£ē äøŗ {1}怂", - "debugAnyway": "ä»čæ›č”Œč°ƒčÆ•", "noFolderWorkspaceDebugError": "ę— ę³•č°ƒčÆ•ę“»åŠØę–‡ä»¶ć€‚čÆ·ē”®äæå®ƒäæå­˜åœØē£ē›˜äøŠļ¼Œå¹¶ē”®äæå·²äøŗčÆ„ę–‡ä»¶ē±»åž‹å®‰č£…äŗ†č°ƒčÆ•ę‰©å±•ć€‚", "NewLaunchConfig": "čÆ·č®¾ē½®åŗ”ē”ØēØ‹åŗēš„åÆåŠØé…ē½®ę–‡ä»¶ć€‚{0}", - "DebugTaskNotFound": "ę‰¾äøåˆ° preLaunchTaskā€œ{0}ā€ć€‚", - "differentTaskRunning": "任劔 {0} ę­£åœØčæč”Œć€‚ę— ę³•čæč”Œå‰ē½®ä»»åŠ” \"{1}\"怂" + "DebugTaskNotFound": "ę‰¾äøåˆ° preLaunchTaskā€œ{0}ā€ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 16828d670d2..1de1dd184f1 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "变量 {0} å…·ęœ‰å€¼ {1}ć€čÆ»å– Eval ę‰“å°å¾ŖēŽÆļ¼Œč°ƒčÆ•", "replExpressionAriaLabel": "č”Øč¾¾å¼ {0} å…·ęœ‰å€¼ {1}ļ¼ŒčÆ»å– Eval ę‰“å°å¾ŖēŽÆļ¼Œč°ƒčÆ•", "replValueOutputAriaLabel": "{0}ļ¼ŒčÆ»å– Eval ę‰“å°å¾ŖēŽÆļ¼Œč°ƒčÆ•", - "replKeyValueOutputAriaLabel": "č¾“å‡ŗå˜é‡ {0} å…·ęœ‰å€¼ {1}ļ¼ŒčÆ»å– Eval ę‰“å°å¾ŖēŽÆļ¼Œč°ƒčÆ•" + "replRawObjectAriaLabel": "Replļ¼ˆäŗ¤äŗ’å¼č§£é‡Šå™Øļ¼‰å˜é‡ {0} å…·ęœ‰å€¼ {1}ļ¼ŒčÆ»å– 求值 输出 å¾ŖēŽÆļ¼Œč°ƒčÆ•" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index f5089c0197a..9852244f28d 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "č°ƒčÆ•ēØ‹åŗę—¶ēŠ¶ę€ę ēš„čƒŒę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØ", - "statusBarDebuggingForeground": "č°ƒčÆ•ēØ‹åŗę—¶ēŠ¶ę€ę ēš„å‰ę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØ" + "statusBarDebuggingForeground": "č°ƒčÆ•ēØ‹åŗę—¶ēŠ¶ę€ę ēš„å‰ę™Æč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØ", + "statusBarDebuggingBorder": "č°ƒčÆ•ēØ‹åŗę—¶åŒŗåˆ«äŗŽä¾§č¾¹ę å’Œē¼–č¾‘å™Øēš„ēŠ¶ę€ę č¾¹ę”†é¢œč‰²ć€‚ēŠ¶ę€ę ę˜¾ē¤ŗåœØēŖ—å£åŗ•éƒØć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 54243f83ce3..b29401c1945 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "č°ƒčÆ•é€‚é…å™ØåÆę‰§č”Œēš„ā€œ{0}ā€äøå­˜åœØć€‚", "debugAdapterCannotDetermineExecutable": "ę— ę³•ē”®å®šč°ƒčÆ•é€‚é…å™Øā€œ{0}ā€ēš„åÆę‰§č”Œę–‡ä»¶ć€‚", + "launch.config.comment1": "使用 IntelliSense äŗ†č§£ē›øå…³å±žę€§ć€‚ ", + "launch.config.comment2": "ę‚¬åœä»„ęŸ„ēœ‹ēŽ°ęœ‰å±žę€§ēš„ęčæ°ć€‚", + "launch.config.comment3": "ę¬²äŗ†č§£ę›“å¤šäæ”ęÆļ¼ŒčÆ·č®æé—®: {0}", "debugType": "é…ē½®ē±»åž‹ć€‚", "debugTypeNotRecognised": "ę— ę³•čÆ†åˆ«ę­¤č°ƒčÆ•ē±»åž‹ć€‚ē”®äæå·²ē»å®‰č£…å¹¶åÆē”Øē›øåŗ”ēš„č°ƒčÆ•ę‰©å±•ć€‚", "node2NotSupported": "äøå†ę”ÆęŒ \"node2\"ļ¼Œę”¹ē”Ø \"node\"ļ¼Œå¹¶å°† \"protocol\" å±žę€§č®¾äøŗ \"inspector\"怂", diff --git a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index f9491aa92e0..adb3d890c40 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "åē§°", "view location": "ä½ē½®", - "themes": "主题({0})", + "colorThemes": "é¢œč‰²äø»é¢˜ ({0})", + "iconThemes": "å›¾ę ‡äø»é¢˜ ({0})", + "colors": "é¢œč‰² ({0})", + "colorId": "ID", + "defaultDark": "ę·±č‰²é»˜č®¤", + "defaultLight": "ęµ…č‰²é»˜č®¤", + "defaultHC": "é«˜åÆ¹ęÆ”åŗ¦é»˜č®¤", "JSON Validation": "JSON 验证({0})", "commands": "命令({0})", "command name": "åē§°", diff --git a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 0d0d492ff6b..aa1f57a84b5 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,7 +34,6 @@ "postDisableMessage": "é‡č½½ę­¤ēŖ—å£ä»„åœē”Øę‰©å±•ā€œ{0}ā€?", "postUninstallTooltip": "é‡č½½ä»„åœē”Ø", "postUninstallMessage": "é‡č½½ę­¤ēŖ—å£ä»„åœē”ØęœŖå®‰č£…ēš„ę‰©å±•ā€œ{0}ā€?", - "reload": "é‡č½½ēŖ—å£(&&R)", "toggleExtensionsViewlet": "ę˜¾ē¤ŗę‰©å±•", "installExtensions": "安装扩展", "showEnabledExtensions": "ę˜¾ē¤ŗåÆē”Øēš„ę‰©å±•", @@ -44,14 +43,19 @@ "showOutdatedExtensions": "ę˜¾ē¤ŗčæ‡ę—¶ę‰©å±•", "showPopularExtensions": "ę˜¾ē¤ŗåøøē”Øēš„ę‰©å±•", "showRecommendedExtensions": "ę˜¾ē¤ŗęŽØčēš„ę‰©å±•", - "showWorkspaceRecommendedExtensions": "ę˜¾ē¤ŗå·„ä½œåŒŗå»ŗč®®ēš„ę‰©å±•å", + "installWorkspaceRecommendedExtensions": "å®‰č£…ę ¹ę®å·„ä½œåŒŗęŽØčēš„ę‰€ęœ‰ę‰©å±•", + "allExtensionsInstalled": "å·²å®‰č£…ę ¹ę®å·„ä½œåŒŗęŽØčēš„ę‰€ęœ‰ę‰©å±•", + "installRecommendedExtension": "å®‰č£…ęŽØčēš„ę‰©å±•", + "extensionInstalled": "ę‚Øå·²ē»å®‰č£…čæ‡ę­¤ęŽØčę‰©å±•", "showRecommendedKeymapExtensions": "ę˜¾ē¤ŗęŽØčé”®ę˜ å°„", "showRecommendedKeymapExtensionsShort": "é”®ę˜ å°„", "showLanguageExtensions": "ę˜¾ē¤ŗčÆ­čØ€ę‰©å±•", "showLanguageExtensionsShort": "语言扩展", - "configureWorkspaceRecommendedExtensions": "é…ē½®å»ŗč®®ēš„ę‰©å±•(巄作区)", - "ConfigureWorkspaceRecommendations.noWorkspace": "å»ŗč®®ä»…åœØå·„ä½œåŒŗę–‡ä»¶å¤¹äøŠåÆē”Øć€‚", + "showAzureExtensions": "显示 Azure 扩展", + "showAzureExtensionsShort": "Azure 扩展", "OpenExtensionsFile.failed": "ę— ę³•åœØ \".vscode\" 文件夹({0})å†…åˆ›å»ŗ \"extensions.json\" ꖇ件怂", + "configureWorkspaceRecommendedExtensions": "é…ē½®å»ŗč®®ēš„ę‰©å±•(巄作区)", + "configureWorkspaceFolderRecommendedExtensions": "é…ē½®å»ŗč®®ēš„ę‰©å±•(å·„ä½œåŒŗę–‡ä»¶å¤¹)", "builtin": "内置", "disableAll": "ē¦ē”Øę‰€ęœ‰å·²å®‰č£…ēš„ę‰©å±•", "disableAllWorkspace": "ē¦ē”Øę­¤å·„ä½œåŒŗēš„ę‰€ęœ‰å·²å®‰č£…ēš„ę‰©å±•", diff --git a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..9d3b2556c66 --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "ęŽØč" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index 5f3939025a7..6f09a313cda 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "ꌉ Enter ē®”ē†ä½ ēš„ę‰©å±•ć€‚", + "notfound": "ę²”ęœ‰åœØå•†åŗ—äø­ę‰¾åˆ°ę‰©å±•ā€œ{0}ā€ć€‚", + "install": "ꌉ Enter é”®åœØå•†åŗ—äø­å®‰č£…ā€œ{0}ā€ć€‚", "searchFor": "ꌉ Enter ä»„åœØåŗ”ē”Øå•†åŗ—äø­ęœē“¢ā€œ{0}ā€ć€‚", "noExtensionsToInstall": "é”®å…„ę‰©å±•åē§°" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 2db4a66e7e7..39cad7d69ee 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -4,11 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "fileBasedRecommendation": "ę ¹ę®ę‚Øęœ€čæ‘ę‰“å¼€ēš„ę–‡ä»¶ęŽØčę­¤ę‰©å±•ć€‚", + "workspaceRecommendation": "å½“å‰å·„ä½œåŒŗēš„ē”Øęˆ·ęŽØčę­¤ę‰©å±•ć€‚", "reallyRecommended2": "å»ŗč®®åÆ¹čæ™ē§ē±»åž‹ēš„ę–‡ä»¶ä½æē”Øā€œ{0}ā€ę‰©å±•ć€‚", + "reallyRecommendedExtensionPack": "å»ŗč®®åÆ¹čæ™ē§ē±»åž‹ēš„ę–‡ä»¶ä½æē”Øā€œ{0}ā€ę‰©å±•åŒ…ć€‚", "showRecommendations": "显示建议", + "install": "安装", "neverShowAgain": "äøå†ę˜¾ē¤ŗ", "close": "关闭", "workspaceRecommended": "ę­¤å·„ä½œåŒŗå…·ęœ‰ę‰©å±•å»ŗč®®ć€‚", + "installAll": "å…ØéƒØå®‰č£…", "ignoreExtensionRecommendations": "ä½ ę˜Æå¦č¦åæ½ē•„ę‰€ęœ‰ęŽØčēš„ę‰©å±•?", "ignoreAll": "ę˜Æļ¼Œåæ½ē•„å…ØéƒØ", "no": "否", diff --git a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 5956c73caa1..80cbfbdb1ae 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,6 +6,8 @@ { "openExtensionsFolder": "打开扩展文件夹", "installVSIX": "从 VSIX 安装...", + "installFromVSIX": "从 VSIX 文件安装", + "installButton": "安装(&&I)", "InstallVSIXAction.success": "å·²ęˆåŠŸå®‰č£…ę‰©å±•ć€‚é‡åÆä»„åÆē”Øå®ƒć€‚", "InstallVSIXAction.reloadNow": "ē«‹å³é‡ę–°åŠ č½½" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json index 0dc6a7005ec..b797d01df97 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json @@ -8,6 +8,8 @@ "installedExtensions": "已安装", "searchInstalledExtensions": "已安装", "recommendedExtensions": "ęŽØč", + "otherRecommendedExtensions": "å…¶ä»–ęŽØč", + "workspaceRecommendedExtensions": "å·„ä½œåŒŗęŽØč", "searchExtensions": "åœØåŗ”ē”Øå•†åŗ—äø­ęœē“¢ę‰©å±•", "sort by installs": "ęŽ’åŗä¾ę®: 安装讔数", "sort by rating": "ęŽ’åŗä¾ę®: åˆ†ēŗ§", diff --git a/i18n/chs/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json b/i18n/chs/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json index 42d15d217d2..a2b15babb5f 100644 --- a/i18n/chs/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/feedback/electron-browser/feedback.i18n.json @@ -7,7 +7,7 @@ "sendFeedback": "Tweet 反馈", "label.sendASmile": "é€ščæ‡ Tweet å‘ęˆ‘ä»¬å‘é€åé¦ˆć€‚", "patchedVersion1": "å®‰č£…å·²ęŸåć€‚", - "patchedVersion2": "å¦‚ęžœęäŗ¤äŗ† bugļ¼ŒčÆ·ęŒ‡å®šę­¤é”¹ć€‚", + "patchedVersion2": "å¦‚ęžœę‚Øęäŗ¤äŗ† bugļ¼ŒčÆ·ęŒ‡å®šę­¤é”¹ć€‚", "sentiment": "ę‚Øēš„ä½“éŖŒå¦‚ä½•?", "smileCaption": "愉快", "frownCaption": "忧伤", diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 81284f01099..6a30564b398 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "ę˜Æå¦ē”®å®žč¦åˆ é™¤ā€œ{0}ā€?", "undoBin": "åÆä»„ä»Žå›žę”¶ē«™čæ˜åŽŸć€‚", "undoTrash": "åÆä»„ä»Žå›žę”¶ē«™čæ˜åŽŸć€‚", + "doNotAskAgain": "äøå†čÆ¢é—®", "confirmDeleteMessageFolder": "ę˜Æå¦ē”®å®šč¦ę°øä¹…åˆ é™¤ā€œ{0}ā€åŠå…¶å†…å®¹?", "confirmDeleteMessageFile": "ę˜Æå¦ē”®å®šč¦ę°øä¹…åˆ é™¤ā€œ{0}ā€?", "irreversible": "ę­¤ę“ä½œäøåÆé€†!", @@ -37,17 +38,15 @@ "openToSide": "ę‰“å¼€åˆ°ä¾§č¾¹", "compareSource": "é€‰ę‹©ä»„čæ›č”ŒęÆ”č¾ƒ", "globalCompareFile": "ęÆ”č¾ƒę“»åŠØę–‡ä»¶äøŽ...", - "pickHistory": "é€‰ę‹©č¦čæ›č”ŒęÆ”č¾ƒēš„ä¹‹å‰å·²ę‰“å¼€ēš„ę–‡ä»¶", - "unableToFileToCompare": "ę— ę³•å°†ę‰€é€‰ę–‡ä»¶äøŽā€œ{0}ā€čæ›č”ŒęÆ”č¾ƒć€‚", "openFileToCompare": "é¦–å…ˆę‰“å¼€ę–‡ä»¶ä»„å°†å…¶äøŽå¦å¤–äø€äøŖę–‡ä»¶ęÆ”č¾ƒć€‚", - "compareWith": "äøŽā€œ{0}ā€ęÆ”č¾ƒ", + "compareWith": "å°†ā€œ{0}ā€äøŽā€œ{1}ā€ęÆ”č¾ƒ", "compareFiles": "ęÆ”č¾ƒę–‡ä»¶", "refresh": "åˆ·ę–°", "save": "äæå­˜", "saveAs": "å¦å­˜äøŗ...", "saveAll": "å…ØéƒØäæå­˜", "saveAllInGroup": "äæå­˜ē»„äø­ēš„å…ØéƒØå†…å®¹", - "saveFiles": "äæå­˜å·²ę›“ę–°ę–‡ä»¶", + "saveFiles": "äæå­˜ę‰€ęœ‰ę–‡ä»¶", "revert": "čæ˜åŽŸę–‡ä»¶", "focusOpenEditors": "äø“ę³ØäŗŽā€œę‰“å¼€ēš„ē¼–č¾‘å™Øā€č§†å›¾", "focusFilesExplorer": "å…³ę³Øę–‡ä»¶čµ„ęŗęµč§ˆå™Ø", @@ -55,7 +54,6 @@ "openFileToShow": "čÆ·å…ˆę‰“å¼€č¦åœØęµč§ˆå™Øäø­ę˜¾ē¤ŗēš„ę–‡ä»¶", "collapseExplorerFolders": "åœØčµ„ęŗē®”ē†å™Øäø­ęŠ˜å ę–‡ä»¶å¤¹", "refreshExplorer": "åˆ·ę–°čµ„ęŗē®”ē†å™Ø", - "openFile": "打开文件...", "openFileInNewWindow": "åœØę–°ēŖ—å£äø­ę‰“å¼€ę“»åŠØę–‡ä»¶", "openFileToShowInNewWindow": "čÆ·å…ˆę‰“å¼€č¦åœØę–°ēŖ—å£äø­ę‰“å¼€ēš„ę–‡ä»¶", "revealInWindows": "åœØčµ„ęŗē®”ē†å™Øäø­ę˜¾ē¤ŗ", diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 6e428891648..bfccea9a3b9 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "ę–‡ęœ¬ę–‡ä»¶ē¼–č¾‘å™Ø", "binaryFileEditor": "äŗŒčæ›åˆ¶ę–‡ä»¶ē¼–č¾‘å™Ø", "filesConfigurationTitle": "ꖇ件", - "exclude": "é…ē½® glob ęØ”å¼ä»„ęŽ’é™¤ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚", + "exclude": "é…ē½® glob ęØ”å¼ä»„åœØęœē“¢äø­ęŽ’é™¤ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚ä¾‹å¦‚ļ¼Œę–‡ä»¶čµ„ęŗē®”ē†å™Øę ¹ę®ę­¤č®¾ē½®å†³å®šę–‡ä»¶ęˆ–ę–‡ä»¶å¤¹ēš„ę˜¾ē¤ŗå’Œéšč—ć€‚", "files.exclude.boolean": "åŒ¹é…ę–‡ä»¶č·Æå¾„ę‰€ä¾ę®ēš„ glob ęØ”å¼ć€‚č®¾ē½®äøŗ true ꈖ false åÆåÆē”Øęˆ–ē¦ē”ØčÆ„ęØ”å¼ć€‚", "files.exclude.when": "åÆ¹åŒ¹é…ę–‡ä»¶ēš„åŒēŗ§ę–‡ä»¶ēš„å…¶ä»–ę£€ęŸ„ć€‚ä½æē”Ø $(basename) ä½œäøŗåŒ¹é…ę–‡ä»¶åēš„å˜é‡ć€‚", "associations": "é…ē½®čÆ­čØ€ēš„ę–‡ä»¶å…³č”(如: \"*.extension\": \"html\")ć€‚čæ™äŗ›å…³č”ēš„ä¼˜å…ˆēŗ§é«˜äŗŽå·²å®‰č£…čÆ­čØ€ēš„é»˜č®¤å…³č”ć€‚", - "encoding": "čÆ»å–å’Œē¼–å†™ę–‡ä»¶ę—¶å°†ä½æē”Øēš„é»˜č®¤å­—ē¬¦é›†ē¼–ē ć€‚", - "autoGuessEncoding": "åÆē”Øę—¶ļ¼Œä¼šåœØę‰“å¼€ę–‡ä»¶ę—¶å°čÆ•ēŒœęµ‹å­—ē¬¦é›†ē¼–ē ", + "encoding": "čÆ»å–å’Œē¼–å†™ę–‡ä»¶ę—¶ä½æē”Øēš„é»˜č®¤å­—ē¬¦é›†ē¼–ē ć€‚ä¹ŸåÆä»„ę ¹ę®čÆ­čØ€é…ē½®ę­¤č®¾ē½®ć€‚", + "autoGuessEncoding": "å¦‚ęžœåÆē”Øļ¼Œä¼šåœØę‰“å¼€ę–‡ä»¶ę—¶å°čÆ•ēŒœęµ‹å­—ē¬¦é›†ē¼–ē ć€‚ä¹ŸåÆä»„ę ¹ę®čÆ­čØ€é…ē½®ę­¤č®¾ē½®ć€‚", "eol": "é»˜č®¤č”Œå°¾å­—ē¬¦ć€‚ä½æē”Ø \\n 蔨示 LF,\\r\\n 蔨示 CRLF怂", "trimTrailingWhitespace": "åÆē”ØåŽļ¼Œå°†åœØäæå­˜ę–‡ä»¶ę—¶å‰Ŗč£å°¾éšē©ŗę ¼ć€‚", "insertFinalNewline": "åÆē”ØåŽļ¼Œäæå­˜ę–‡ä»¶ę—¶åœØę–‡ä»¶ęœ«å°¾ę’å…„äø€äøŖęœ€ē»ˆę–°č”Œć€‚", + "trimFinalNewlines": "åÆē”ØåŽļ¼Œäæå­˜ę–‡ä»¶ę—¶å°†åˆ é™¤åœØęœ€ē»ˆę–°č”ŒåŽēš„ę‰€ęœ‰ę–°č”Œć€‚", "files.autoSave.off": "ę°øäøč‡ŖåŠØäæå­˜ę›“ę–°åŽēš„ę–‡ä»¶ć€‚", "files.autoSave.afterDelay": "é…ē½® \"files.autoSaveDelay\" åŽč‡ŖåŠØäæå­˜ę›“ę–°åŽēš„ę–‡ä»¶ć€‚", "files.autoSave.onFocusChange": "ē¼–č¾‘å™Øå¤±åŽ»ē„¦ē‚¹ę—¶č‡ŖåŠØäæå­˜ę›“ę–°åŽēš„ę–‡ä»¶ć€‚", @@ -39,10 +40,13 @@ "dynamicHeight": "ęŽ§åˆ¶ę‰“å¼€ēš„ē¼–č¾‘å™ØéƒØåˆ†ēš„é«˜åŗ¦ę˜Æå¦åŗ”åŠØę€é€‚åŗ”å…ƒē“ ę•°é‡ć€‚", "autoReveal": "ęŽ§åˆ¶čµ„ęŗē®”ē†å™Øę˜Æå¦åŗ”åœØę‰“å¼€ę–‡ä»¶ę—¶č‡ŖåŠØę˜¾ē¤ŗå¹¶é€‰ę‹©å®ƒä»¬ć€‚", "enableDragAndDrop": "ęŽ§åˆ¶čµ„ęŗē®”ē†å™Øę˜Æå¦åŗ”čÆ„å…č®øé€ščæ‡ę‹–ę”¾ē§»åŠØę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚", - "sortOrder.default": "ęŒ‰åē§°ēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œē›®å½•ć€‚ē›®å½•ę˜¾ē¤ŗåœØę–‡ä»¶å‰ć€‚", - "sortOrder.mixed": "ęŒ‰åē§°ēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œē›®å½•ć€‚äø¤č€…ē©æę’ę˜¾ē¤ŗć€‚", - "sortOrder.filesFirst": "ęŒ‰åē§°ēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œē›®å½•ć€‚ę–‡ä»¶ę˜¾ē¤ŗåœØē›®å½•å‰ć€‚", - "sortOrder.type": "ęŒ‰ę‰©å±•åēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œē›®å½•ć€‚ē›®å½•ę˜¾ē¤ŗåœØę–‡ä»¶å‰ć€‚", - "sortOrder.modified": "ęŒ‰ęœ€åŽäæ®ę”¹ę—„ęœŸé™åŗęŽ’åˆ—ę–‡ä»¶å’Œē›®å½•ć€‚ē›®å½•ę˜¾ē¤ŗåœØę–‡ä»¶å‰ć€‚", - "sortOrder": "ęŽ§åˆ¶ę–‡ä»¶å’Œē›®å½•åœØčµ„ęŗē®”ē†å™Øäø­ēš„ęŽ’åˆ—ę–¹å¼ć€‚" + "confirmDelete": "ęŽ§åˆ¶čµ„ęŗē®”ē†å™Øę˜Æå¦åŗ”åœØåˆ é™¤ę–‡ä»¶åˆ°å›žę”¶ē«™ę—¶čæ›č”Œē”®č®¤ć€‚", + "sortOrder.default": "ęŒ‰åē§°ēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚ę–‡ä»¶å¤¹ę˜¾ē¤ŗåœØę–‡ä»¶å‰ć€‚", + "sortOrder.mixed": "ęŒ‰åē§°ēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚äø¤č€…ē©æę’ę˜¾ē¤ŗć€‚", + "sortOrder.filesFirst": "ęŒ‰åē§°ēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚ę–‡ä»¶ę˜¾ē¤ŗåœØę–‡ä»¶å¤¹å‰ć€‚", + "sortOrder.type": "ęŒ‰ę‰©å±•åēš„å­—ęÆé”ŗåŗęŽ’åˆ—ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚ę–‡ä»¶å¤¹ę˜¾ē¤ŗåœØę–‡ä»¶å‰ć€‚", + "sortOrder.modified": "ęŒ‰ęœ€åŽäæ®ę”¹ę—„ęœŸé™åŗęŽ’åˆ—ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚ę–‡ä»¶å¤¹ę˜¾ē¤ŗåœØę–‡ä»¶å‰ć€‚", + "sortOrder": "ęŽ§åˆ¶čµ„ęŗē®”ē†å™Øę–‡ä»¶å’Œę–‡ä»¶å¤¹ēš„ęŽ’åˆ—é”ŗåŗć€‚é™¤äŗ†é»˜č®¤ęŽ’åˆ—é”ŗåŗļ¼Œä½ ä¹ŸåÆä»„č®¾ē½®äøŗ \"mixed\" (ę–‡ä»¶å’Œę–‡ä»¶å¤¹äø€čµ·ęŽ’åŗ)态\"type\" (ęŒ‰ę–‡ä»¶ē±»åž‹ęŽ’)态\"modified\" (ęŒ‰ęœ€åŽäæ®ę”¹ę—„ęœŸęŽ’)ęˆ–ę˜Æ \"filesFirst\" (å°†ę–‡ä»¶ęŽ’åœØę–‡ä»¶å¤¹å‰)怂", + "explorer.decorations.colors": "ęŽ§åˆ¶ę–‡ä»¶äæ®é„°ę˜Æå¦ē”Øé¢œč‰²ć€‚", + "explorer.decorations.badges": "ęŽ§åˆ¶ę–‡ä»¶äæ®é„°ę˜Æå¦ē”Øå¾½ē« ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index d0cafa14bc6..8ebee88ce98 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "ä½æē”Øå³ä¾§ē¼–č¾‘å™Øå·„å…·ę ēš„ę“ä½œę„**ę’¤ę¶ˆ**ä½ ēš„ę›“ę”¹ęˆ–ē”Øä½ ēš„ę›“ę”¹ę„**覆盖**ē£ē›˜äøŠēš„å†…å®¹", "discard": "ę”¾å¼ƒ", "overwrite": "覆盖", "retry": "é‡čÆ•", @@ -11,6 +12,5 @@ "genericSaveError": "ęœŖčƒ½äæå­˜ā€œ{0}ā€: {1}", "staleSaveError": "ę— ę³•äæå­˜ā€œ{0}ā€: ē£ē›˜äøŠēš„å†…å®¹č¾ƒę–°ć€‚å•å‡» **ęÆ”č¾ƒ** ä»„ęÆ”č¾ƒä½ ēš„ē‰ˆęœ¬å’Œē£ē›˜äøŠēš„ē‰ˆęœ¬ć€‚", "compareChanges": "ęÆ”č¾ƒ", - "saveConflictDiffLabel": "{0} (on disk) ↔ {1} (in {2}) - č§£å†³äæå­˜ēš„å†²ēŖ", - "userGuide": "ä½æē”Øå³ä¾§ē¼–č¾‘å™Øå·„å…·ę ēš„ę“ä½œę„**ę’¤ę¶ˆ**ä½ ēš„ę›“ę”¹ęˆ–ē”Øä½ ēš„ę›“ę”¹ę„**覆盖**ē£ē›˜äøŠēš„å†…å®¹" + "saveConflictDiffLabel": "{0} (on disk) ↔ {1} (in {2}) - č§£å†³äæå­˜ēš„å†²ēŖ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 51ca4525bf3..5939052419b 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "ę— ę‰“å¼€ēš„ę–‡ä»¶å¤¹", "explorerSection": "ę–‡ä»¶čµ„ęŗē®”ē†å™ØéƒØåˆ†", - "noWorkspaceHelp": "å°šęœŖę‰“å¼€ę–‡ä»¶å¤¹ć€‚", + "noWorkspaceHelp": "ä½ čæ˜ę²”ęœ‰åœØå·„ä½œåŒŗäø­ę·»åŠ ę–‡ä»¶å¤¹ć€‚", + "addFolder": "ę·»åŠ ę–‡ä»¶å¤¹", + "noFolderHelp": "å°šęœŖę‰“å¼€ę–‡ä»¶å¤¹ć€‚", "openFolder": "打开文件夹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..d3333b0ae61 --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "资源箔理器" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index bc13e54543e..d97098d02f7 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,13 @@ { "fileInputAriaLabel": "é”®å…„ę–‡ä»¶åć€‚ęŒ‰ Enter ä»„ē”®č®¤ęˆ–ęŒ‰ Esc ä»„å–ę¶ˆć€‚", "filesExplorerViewerAriaLabel": "{0}ļ¼Œę–‡ä»¶čµ„ęŗē®”ē†å™Ø", + "dropFolders": "ä½ ę˜Æå¦č¦å°†ę–‡ä»¶å¤¹ę·»åŠ åˆ°å·„ä½œåŒŗ?", + "dropFolder": "ä½ ę˜Æå¦č¦å°†ę–‡ä»¶å¤¹ę·»åŠ åˆ°å·„ä½œåŒŗ?", + "addFolders": "ę·»åŠ ę–‡ä»¶å¤¹(&&A)", + "addFolder": "ę·»åŠ ę–‡ä»¶å¤¹(&&A)", + "confirmMove": "ę˜Æå¦ē”®å®žč¦ē§»åŠØā€œ{0}ā€?", + "doNotAskAgain": "äøå†čÆ¢é—®", + "moveButtonLabel": "移动(&&M)", "confirmOverwriteMessage": "ē›®ę ‡ę–‡ä»¶å¤¹äø­å·²å­˜åœØā€œ{0}ā€ć€‚ę˜Æå¦č¦å°†å…¶ę›æę¢?", "irreversible": "ę­¤ę“ä½œäøåÆé€†!", "replaceButtonLabel": "ę›æę¢(&&R)" diff --git a/i18n/chs/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json b/i18n/chs/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json index 651206b60ee..5b583f97926 100644 --- a/i18n/chs/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json @@ -7,7 +7,7 @@ "editorGroupAriaLabel": "{0}, 编辑器组", "openEditorAriaLabel": "{0}, 打开编辑器", "saveAll": "å…ØéƒØäæå­˜", - "closeAllUnmodified": "å…³é—­ęœŖę›“ę”¹ēš„", + "closeAllUnmodified": "å…³é—­ęœŖę›“ę”¹", "closeAll": "å…ØéƒØå…³é—­", "compareWithSaved": "äøŽå·²äæå­˜ę–‡ä»¶ęÆ”č¾ƒ", "close": "关闭", diff --git a/i18n/chs/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/chs/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 18dde6792fa..193bb96756e 100644 --- a/i18n/chs/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 äøŖęœŖäæå­˜ēš„ę–‡ä»¶", "dirtyFiles": "{0} äøŖęœŖäæå­˜ēš„ę–‡ä»¶" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/chs/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..6536d821661 --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "问题", + "tooltip.1": "ę­¤ę–‡ä»¶å­˜åœØ 1 äøŖé—®é¢˜", + "tooltip.N": "ę­¤ę–‡ä»¶å­˜åœØ {0} äøŖé—®é¢˜", + "markers.showOnFile": "ę˜¾ē¤ŗå…³äŗŽę–‡ä»¶äøŽę–‡ä»¶å¤¹ēš„é”™čÆÆäøŽč­¦å‘Šć€‚" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/chs/src/vs/workbench/parts/markers/common/messages.i18n.json index d7fcf292d22..b6d59b5586c 100644 --- a/i18n/chs/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "ęŸ„ēœ‹", + "problems.view.toggle.label": "åˆ‡ę¢ę˜¾ē¤ŗé—®é¢˜č§†å›¾", "problems.view.show.label": "ę˜¾ē¤ŗé—®é¢˜", + "problems.view.hide.label": "éšč—é—®é¢˜č§†å›¾", "problems.panel.configuration.title": "é—®é¢˜é¢„č§ˆ", "problems.panel.configuration.autoreveal": "ęŽ§åˆ¶é—®é¢˜é¢„č§ˆę˜Æå¦åŗ”åœØę‰“å¼€ę–‡ä»¶ę—¶č‡ŖåŠØę˜¾ē¤ŗå®ƒä»¬ć€‚", "markers.panel.title.problems": "问题", @@ -34,6 +36,6 @@ "problems.tree.aria.label.info.marker": "ē”± {0} ē”Ÿęˆēš„äæ”ęÆ: 第 {2} č”Œå¤„ēš„ {1} å’Œå­—ē¬¦ {3}", "problems.tree.aria.label.info.marker.nosource": "俔息: 第 {1} č”Œå¤„ēš„ {0} å’Œå­—ē¬¦ {2}", "problems.tree.aria.label.marker": "ē”± {0} ē”Ÿęˆēš„é—®é¢˜: 第 {2} č”Œå¤„ēš„ {1} å’Œå­—ē¬¦ {3}", - "problems.tree.aria.label.marker.nosource": "问题: 第 {1} č”Œå¤„ēš„ {0} å’Œå­—ē¬¦ {2}", + "problems.tree.aria.label.marker.nosource": "问题: {1} 蔌 {2} åˆ—ēš„ {0}", "errors.warnings.show.label": "ę˜¾ē¤ŗé”™čÆÆå’Œč­¦å‘Š" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/chs/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index 0de97ab3151..1ee0bad1c39 100644 --- a/i18n/chs/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "复制" + "copyMarker": "复制", + "copyMarkerMessage": "å¤åˆ¶ę¶ˆęÆ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index bb7e4ea7afa..9b26b94472e 100644 --- a/i18n/chs/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "ę£€ęµ‹åˆ°åÆåŠØē¼“ę…¢", - "slow.detail": "ęŠ±ę­‰ļ¼Œå‡ŗēŽ°äŗ†åÆåŠØē¼“ę…¢ēš„ęƒ…å†µć€‚čÆ·é‡åÆā€œ{0}ā€å¹¶åÆē”Øåˆ†ęžļ¼Œå°†åˆ†ęžę–‡ä»¶äøŽęˆ‘ä»¬å…±äŗ«ļ¼Œęˆ‘ä»¬ä¼šåŠŖåŠ›ęé«˜åÆåŠØé€Ÿåŗ¦ć€‚", "prof.message": "å·²ęˆåŠŸåˆ›å»ŗęčæ°ę–‡ä»¶ć€‚", "prof.detail": "čÆ·åˆ›å»ŗé—®é¢˜å¹¶ę‰‹åŠØé™„åŠ ä»„äø‹ę–‡ä»¶ļ¼š\n{0}", "prof.restartAndFileIssue": "åˆ›å»ŗé—®é¢˜å¹¶é‡åÆ", diff --git a/i18n/chs/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json index 3461ec0a523..a191f56abf9 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/browser/keybindingsEditor.i18n.json @@ -20,7 +20,7 @@ "error": "ē¼–č¾‘é”®ē»‘å®šę—¶å‘ē”Ÿé”™čÆÆā€œ{0}ā€ć€‚čÆ·ę‰“å¼€ \"keybindings.json\" ę–‡ä»¶å¹¶ę£€ęŸ„ć€‚", "command": "命令", "keybinding": "é”®ē»‘å®š", - "source": "源", + "source": "ę„ęŗ", "when": "何时", "editKeybindingLabelWithKey": "ę›“ę”¹é”®ē»‘å®š{0}", "editKeybindingLabel": "ę›“ę”¹é”®ē»‘å®š", diff --git a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index fefc047fe76..a6386fe575c 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "ę‰“å¼€é”®ē›˜åæ«ę·ę–¹å¼ę–‡ä»¶", "openWorkspaceSettings": "ę‰“å¼€å·„ä½œåŒŗč®¾ē½®", "openFolderSettings": "打开文件夹设置", - "pickFolder": "选择文件夹", "configureLanguageBasedSettings": "é…ē½®čÆ­čØ€ē‰¹å®šēš„č®¾ē½®...", "languageDescriptionConfigured": "({0})", "pickLanguage": "选择语言" diff --git a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index 1957f9a2f28..f3133e2e59b 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -13,5 +13,6 @@ "settingsFound": "{0} äøŖč®¾ē½®åŒ¹é…", "fileEditorWithInputAriaLabel": "{0}ć€‚ę–‡ęœ¬ę–‡ä»¶ē¼–č¾‘å™Øć€‚", "fileEditorAriaLabel": "ę–‡ęœ¬ę–‡ä»¶ē¼–č¾‘å™Øć€‚", + "defaultEditorReadonly": "åœØå³ä¾§ē¼–č¾‘å™Øäø­ē¼–č¾‘ä»„č¦†ē›–é»˜č®¤å€¼ć€‚", "preferencesAriaLabel": "é»˜č®¤é¦–é€‰é”¹ć€‚åŖčÆ»ę–‡ęœ¬ē¼–č¾‘å™Øć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index d2cf1b98e7b..94247b7df63 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,13 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·ę›“ę­£ę–‡ä»¶äø­ēš„é”™čÆÆ/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", + "emptyUserSettingsHeader": "将设置放兄此处仄覆盖\"默认设置\"怂", + "emptyWorkspaceSettingsHeader": "将设置放兄此处仄覆盖\"ē”Øęˆ·č®¾ē½®\"怂", + "emptyFolderSettingsHeader": "将文件夹设置放兄此处仄覆盖\"巄作区设置\"怂", "defaultFolderSettingsTitle": "é»˜č®¤ę–‡ä»¶å¤¹č®¾ē½®", "defaultSettingsTitle": "默认设置", - "noSettingsFound": "ęœŖę‰¾åˆ°č®¾ē½®ć€‚", "editTtile": "编辑", "replaceDefaultValue": "åœØč®¾ē½®äø­ę›æę¢", "copyDefaultValue": "å¤åˆ¶åˆ°č®¾ē½®", "unsupportedPHPExecutablePathSetting": "ę­¤č®¾ē½®åæ…é”»ę˜Æā€œē”Øęˆ·č®¾ē½®ā€ć€‚č‹„č¦äøŗå·„ä½œåŒŗé…ē½® PHPļ¼ŒčÆ·ę‰“å¼€ PHP ę–‡ä»¶å¹¶å•å‡»ēŠ¶ę€ę äø­ēš„ā€œPHP č·Æå¾„ā€ć€‚", - "unsupportedWorkspaceSetting": "ę­¤č®¾ē½®åæ…é”»ę˜Æā€œē”Øęˆ·č®¾ē½®ā€ć€‚" + "unsupportedWorkspaceSetting": "ę­¤č®¾ē½®åæ…é”»ę˜Æā€œē”Øęˆ·č®¾ē½®ā€ć€‚", + "unsupportedWorkbenchSetting": "å½“å‰ę— ę³•åŗ”ē”Øę­¤č®¾ē½®ć€‚å°†åœØē›“ęŽ„ę‰“å¼€ę­¤ę–‡ä»¶å¤¹ę—¶åŗ”ē”Øć€‚", + "unsupportedWorkbenchSettingDevMode": "å½“å‰ę— ę³•åŗ”ē”Øę­¤č®¾ē½®ć€‚å°†ä½ åœØę³Øå†Œę—¶å®šä¹‰å…¶ä½œē”ØåŸŸäøŗ \"resource\"ļ¼Œęˆ–ę˜Æē›“ęŽ„ę‰“å¼€ę­¤ę–‡ä»¶å¤¹ę—¶åŗ”ē”Øć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 03775ea2adc..51978e63faa 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "folderSettingsDetails": "文件夹设置" + "defaultSettingsFuzzyPrompt": "čÆ•čÆ•ęØ”ē³Šęœē“¢!", + "defaultSettings": "å°†ę‚Øēš„č®¾ē½®ę”¾å…„å³ä¾§ē¼–č¾‘å™Øä»„č¦†ē›–ć€‚", + "noSettingsFound": "ęœŖę‰¾åˆ°č®¾ē½®ć€‚", + "folderSettingsDetails": "文件夹设置", + "enableFuzzySearch": "åÆē”Øå®žéŖŒę€§ēš„ęØ”ē³Šęœē“¢" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index 7f2b487c29d..26f355bb382 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "常用设置", - "noSettings": "ę²”ęœ‰č®¾ē½®", + "mostRelevant": "ęœ€ē›øå…³", "defaultKeybindingsHeader": "é€ščæ‡å°†é”®ē»‘å®šę”¾å…„é”®ē»‘å®šę–‡ä»¶äø­ę„č¦†ē›–é”®ē»‘å®šć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index e66ea5624b1..30778096b47 100644 --- a/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "åœØå½“å‰äøŠäø‹ę–‡äø­ę²”ęœ‰åÆē”Øå‘½ä»¤ā€œ{0}ā€ć€‚", "recentlyUsed": "ęœ€čæ‘ä½æē”Ø", "morecCommands": "其他命令", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "ę²”ęœ‰åŒ¹é…ēš„å‘½ä»¤" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index d54e22f7680..e6c4f79ed65 100644 --- a/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "č®¾ē½®å·²ę›“ę”¹ļ¼Œéœ€č¦é‡åÆę‰čƒ½ē”Ÿę•ˆć€‚", "relaunchSettingDetail": "ęŒ‰äø‹ā€œé‡åÆā€ęŒ‰é’®ä»„é‡ę–°åÆåŠØ {0} 并启用评设置。", - "restart": "é‡åÆ", - "relaunchWorkspaceMessage": "ę­¤å·„ä½œåŒŗę›“ę”¹éœ€č¦é‡č½½ę‰©å±•ē³»ē»Ÿć€‚", - "reload": "é‡ę–°åŠ č½½" + "restart": "é‡åÆ(&&R)" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index bc3bae9c0e5..839def0b2a6 100644 --- a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "第 {0} 个曓改 (共 {1} äøŖ)", + "change": "第 {0} 个曓改 (共 {1} äøŖ)", + "show previous change": "ę˜¾ē¤ŗäøŠäø€äøŖę›“ę”¹", + "show next change": "ę˜¾ē¤ŗäø‹äø€äøŖę›“ę”¹", "editorGutterModifiedBackground": "ē¼–č¾‘å™ØåÆ¼čˆŖēŗæäø­č¢«äæ®ę”¹č”Œēš„čƒŒę™Æé¢œč‰²ć€‚", "editorGutterAddedBackground": "ē¼–č¾‘å™ØåÆ¼čˆŖēŗæäø­å·²ę’å…„č”Œēš„čƒŒę™Æé¢œč‰²ć€‚", - "editorGutterDeletedBackground": "ē¼–č¾‘å™ØåÆ¼čˆŖēŗæäø­č¢«åˆ é™¤č”Œēš„čƒŒę™Æé¢œč‰²ć€‚" + "editorGutterDeletedBackground": "ē¼–č¾‘å™ØåÆ¼čˆŖēŗæäø­č¢«åˆ é™¤č”Œēš„čƒŒę™Æé¢œč‰²ć€‚", + "overviewRulerModifiedForeground": "ę¦‚čæ°å·²äæ®ę”¹å†…å®¹ēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "overviewRulerAddedForeground": "ę¦‚čæ°å·²ę·»åŠ å†…å®¹ēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚", + "overviewRulerDeletedForeground": "ę¦‚čæ°å·²åˆ é™¤å†…å®¹ēš„ę ‡å°ŗę ‡č®°é¢œč‰²ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index 8ea8ff4f96e..cc08da73602 100644 --- a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,8 +5,7 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "显示 Git", - "installAdditionalSCMProviders": "安装其他 SCM ęä¾›ēØ‹åŗ...", "source control": "源代码箔理", - "toggleSCMViewlet": "显示 SCM", + "toggleSCMViewlet": "ę˜¾ē¤ŗęŗä»£ē ē®”ē†", "view": "ęŸ„ēœ‹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index c4fb0f2b279..a742f18f4d5 100644 --- a/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "ęŗä»£ē ē®”ē†ęä¾›ēØ‹åŗ", + "hideRepository": "隐藏", "commitMessage": "消息(ꌉ {0} ęäŗ¤)", + "installAdditionalSCMProviders": "å®‰č£…å…¶ä»–ęŗä»£ē ē®”ē†ęä¾›ēØ‹åŗ...", + "no open repo": "ę²”ęœ‰ę“»åŠØēš„ęŗä»£ē ē®”ē†ęä¾›ēØ‹åŗć€‚", "source control": "源代码箔理", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index e99f415edc0..3638ae24a14 100644 --- a/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "č½¬åˆ°å·„ä½œåŒŗäø­ēš„ē¬¦å·...", "name": "搜瓢", - "showSearchViewlet": "显示搜瓢", + "search": "搜瓢", "view": "ęŸ„ēœ‹", - "findInFiles": "åœØę–‡ä»¶äø­ęŸ„ę‰¾", "openAnythingHandlerDescription": "č½¬åˆ°ę–‡ä»¶", "openSymbolDescriptionNormal": "č½¬åˆ°å·„ä½œåŒŗäø­ēš„ē¬¦å·", "searchOutputChannelTitle": "搜瓢", @@ -16,7 +15,7 @@ "exclude": "é…ē½® glob ęØ”å¼ä»„åœØęœē“¢äø­ęŽ’é™¤ę–‡ä»¶å’Œę–‡ä»¶å¤¹ć€‚ä»Ž files.exclude č®¾ē½®äø­ē»§ę‰æę‰€ęœ‰ glob ęØ”å¼ć€‚", "exclude.boolean": "åŒ¹é…ę–‡ä»¶č·Æå¾„ę‰€ä¾ę®ēš„ glob ęØ”å¼ć€‚č®¾ē½®äøŗ true ꈖ false åÆåÆē”Øęˆ–ē¦ē”ØčÆ„ęØ”å¼ć€‚", "exclude.when": "åÆ¹åŒ¹é…ę–‡ä»¶ēš„åŒēŗ§ę–‡ä»¶ēš„å…¶ä»–ę£€ęŸ„ć€‚ä½æē”Ø $(basename) ä½œäøŗåŒ¹é…ę–‡ä»¶åēš„å˜é‡ć€‚", - "useRipgrep": "ęŽ§åˆ¶ę˜Æå¦åœØę–‡ęœ¬ęœē“¢äø­ä½æē”Ø ripgrep", - "useIgnoreFilesByDefault": "ęŽ§åˆ¶åœØę–°å·„ä½œåŒŗäø­ęœē“¢ę—¶ę˜Æå¦é»˜č®¤ä½æē”Ø .gitignore 和 .ignore ꖇ件怂", - "search.quickOpen.includeSymbols": "é…ē½®äøŗåœØ Quick Open ę–‡ä»¶ē»“ęžœäø­åŒ…ę‹¬å…Øå±€ē¬¦å·ęœē“¢ēš„ē»“ęžœć€‚" + "useRipgrep": "ęŽ§åˆ¶ę˜Æå¦åœØę–‡ęœ¬å’Œę–‡ä»¶ęœē“¢äø­ä½æē”Ø ripgrep", + "search.quickOpen.includeSymbols": "é…ē½®äøŗåœØ Quick Open ę–‡ä»¶ē»“ęžœäø­åŒ…ę‹¬å…Øå±€ē¬¦å·ęœē“¢ēš„ē»“ęžœć€‚", + "search.followSymlinks": "ęŽ§åˆ¶ę˜Æå¦åœØęœē“¢äø­č·ŸčøŖē¬¦å·é“¾ęŽ„ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 5645f876d21..02641d5492f 100644 --- a/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,18 +4,26 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "ę˜¾ē¤ŗäø‹äø€äøŖęœē“¢åŒ…å«ęØ”å¼", + "previousSearchIncludePattern": "ę˜¾ē¤ŗäøŠäø€äøŖęœē“¢åŒ…å«ęØ”å¼", + "nextSearchExcludePattern": "ę˜¾ē¤ŗäø‹äø€äøŖęœē“¢ęŽ’é™¤ęØ”å¼", + "previousSearchExcludePattern": "ę˜¾ē¤ŗäøŠäø€äøŖęœē“¢ęŽ’é™¤ęØ”å¼", "nextSearchTerm": "ę˜¾ē¤ŗäø‹äø€äøŖęœē“¢čÆ", "previousSearchTerm": "ę˜¾ē¤ŗäøŠäø€äøŖęœē“¢čÆ", "focusNextInputBox": "čšē„¦äø‹äø€äøŖč¾“å…„ę”†", "focusPreviousInputBox": "čšē„¦äøŠäø€äøŖč¾“å…„ę”†", + "showSearchViewlet": "显示搜瓢", + "findInFiles": "åœØę–‡ä»¶äø­ęŸ„ę‰¾", + "findInFilesWithSelectedText": "åœØę–‡ä»¶äø­ęŸ„ę‰¾ę‰€é€‰ę–‡ęœ¬", "replaceInFiles": "åœØę–‡ä»¶äø­ę›æę¢", + "replaceInFilesWithSelectedText": "åœØę–‡ä»¶äø­ę›æę¢ę‰€é€‰ę–‡ęœ¬", "findInWorkspace": "åœØå·„ä½œåŒŗäø­ęŸ„ę‰¾...", "findInFolder": "åœØę–‡ä»¶å¤¹äø­ęŸ„ę‰¾...", "RefreshAction.label": "åˆ·ę–°", "ClearSearchResultsAction.label": "ęø…é™¤ęœē“¢ē»“ęžœ", "FocusNextSearchResult.label": "čšē„¦äø‹äø€ęœē“¢ē»“ęžœ", "FocusPreviousSearchResult.label": "čšē„¦äøŠäø€ęœē“¢ē»“ęžœ", - "RemoveAction.label": "删除", + "RemoveAction.label": "ę¶ˆé™¤", "file.replaceAll.label": "å…ØéƒØę›æę¢", "match.replace.label": "ę›æę¢" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/chs/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 8bdf54da172..5638ff3ddc1 100644 --- a/i18n/chs/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "č¦ęŽ’é™¤ēš„ę–‡ä»¶", "label.excludes": "ęœē“¢ęŽ’é™¤ęØ”å¼", "replaceAll.confirmation.title": "å…ØéƒØę›æę¢", - "replaceAll.confirm.button": "ę›æę¢", + "replaceAll.confirm.button": "ę›æę¢(&&R)", "replaceAll.occurrence.file.message": "已将 {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0} ę›æę¢äøŗā€œ{2}ā€ć€‚", "removeAll.occurrence.file.message": "å·²ę›æę¢ {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0}怂", "replaceAll.occurrence.files.message": "已将 {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0} ę›æę¢äøŗā€œ{2}ā€ć€‚", @@ -25,31 +25,25 @@ "replaceAll.occurrence.files.confirmation.message": "ę˜Æå¦ę›æę¢ {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0}?", "removeAll.occurrences.file.confirmation.message": "ę˜Æå¦å°† {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0} ę›æę¢äøŗā€œ{2}ā€?", "replaceAll.occurrences.file.confirmation.message": "ę˜Æå¦ę›æę¢ {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0}?", - "removeAll.occurrences.files.confirmation.message": "ę˜Æå¦å°† {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0} ę›æę¢äøŗā€œ{2}ā€?", + "removeAll.occurrences.files.confirmation.message": "ę˜Æå¦å°† {1} äøŖę–‡ä»¶äø­ēš„ {0} ę¬”åŒ¹é…ę›æę¢äøŗā€œ{2}ā€?", "replaceAll.occurrences.files.confirmation.message": "ę˜Æå¦ę›æę¢ {1} ę–‡ä»¶äø­å‡ŗēŽ°ēš„ {0}?", "treeAriaLabel": "ęœē“¢ē»“ęžœ", + "searchPathNotFoundError": "ę‰¾äøåˆ°ęœē“¢č·Æå¾„: {0}", "searchMaxResultsWarning": "ē»“ęžœé›†ä»…åŒ…å«ę‰€ęœ‰åŒ¹é…é”¹ēš„å­é›†ć€‚čÆ·ä½æä½ ēš„ęœē“¢ę›“åŠ å…·ä½“ļ¼Œå‡å°‘ē»“ęžœć€‚", "searchCanceled": "åœØę‰¾åˆ°ē»“ęžœå‰å–ę¶ˆäŗ†ęœē“¢ - ", "noResultsIncludesExcludes": "åœØā€œ{0}ā€äø­ę‰¾äøåˆ°ē»“ęžœ(ā€œ{1}ā€é™¤å¤–) - ", "noResultsIncludes": "ā€œ{0}ā€äø­ęœŖę‰¾åˆ°ä»»ä½•ē»“ęžœ - ", "noResultsExcludes": "é™¤ā€œ{0}ā€å¤–ļ¼ŒęœŖę‰¾åˆ°ä»»ä½•ē»“ęžœ - ", - "noResultsFound": "ę‰¾äøåˆ°ē»“ęžœć€‚ęŸ„ēœ‹č®¾ē½®äø­é…ē½®ēš„ęŽ’é™¤é”¹ - ", + "noResultsFound": "ę‰¾äøåˆ°ē»“ęžœć€‚ęŸ„ēœ‹č®¾ē½®äø­é…ē½®ēš„ęŽ’é™¤é”¹å¹¶åæ½ē•„ę–‡ä»¶ - ", "rerunSearch.message": "å†ę¬”ęœē“¢", "rerunSearchInAll.message": "åœØę‰€ęœ‰ę–‡ä»¶äø­å†ę¬”ęœē“¢", "openSettings.message": "打开设置", + "openSettings.learnMore": "了解详细俔息", "ariaSearchResultsStatus": "搜瓢 {1} ę–‡ä»¶äø­čæ”å›žēš„ {0} äøŖē»“ęžœ", "search.file.result": "{1} ę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", "search.files.result": "{1} ę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", "search.file.results": "{1} ę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", "search.files.results": "{1} ę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folder.file.result": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folder.files.result": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folder.file.results": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folder.files.results": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folders.file.result": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folders.files.result": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folders.file.results": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", - "search.folders.files.results": "{2} äøŖę–‡ä»¶å¤¹äø­ēš„ {1} äøŖę–‡ä»¶äø­ęœ‰ {0} äøŖē»“ęžœ", "searchWithoutFolder": "å°šęœŖę‰“å¼€ę–‡ä»¶å¤¹ć€‚å½“å‰ä»…åÆęœē“¢ę‰“å¼€ēš„ę–‡ä»¶å¤¹ - ", "openFolder": "打开文件夹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/search/browser/searchWidget.i18n.json b/i18n/chs/src/vs/workbench/parts/search/browser/searchWidget.i18n.json index 00eca8a635d..67e2ed5ef21 100644 --- a/i18n/chs/src/vs/workbench/parts/search/browser/searchWidget.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/search/browser/searchWidget.i18n.json @@ -7,9 +7,10 @@ "search.action.replaceAll.disabled.label": "å…ØéƒØę›æę¢(ęäŗ¤ęœē“¢ä»„åÆē”Ø)", "search.action.replaceAll.enabled.label": "å…ØéƒØę›æę¢", "search.replace.toggle.button.title": "åˆ‡ę¢ę›æę¢", - "label.Search": "搜瓢: é”®å…„ęœē“¢ęœÆčÆ­ļ¼Œē„¶åŽęŒ‰ Enter čæ›č”Œęœē“¢ęˆ–ęŒ‰ Escape å–ę¶ˆ", + "label.Search": "搜瓢: é”®å…„ęœē“¢čÆļ¼Œē„¶åŽęŒ‰ Enter é”®ęœē“¢ęˆ–ęŒ‰ Esc é”®å–ę¶ˆ", "search.placeHolder": "搜瓢", - "label.Replace": "ę›æę¢: é”®å…„ę›æę¢ęœÆčÆ­ļ¼Œē„¶åŽęŒ‰ Enter é¢„č§ˆęˆ–ęŒ‰ Escape å–ę¶ˆ", + "label.Replace": "ę›æę¢: é”®å…„å¾…ę›æę¢čÆļ¼Œē„¶åŽęŒ‰ Enter é”®é¢„č§ˆęˆ–ęŒ‰ Esc é”®å–ę¶ˆ", "search.replace.placeHolder": "ę›æę¢", - "regexp.validationFailure": "č”Øč¾¾å¼äøŽę‰€ęœ‰å†…å®¹ē›øåŒ¹é…" + "regexp.validationFailure": "č”Øč¾¾å¼äøŽę‰€ęœ‰å†…å®¹ē›øåŒ¹é…", + "regexp.backreferenceValidationFailure": "äøę”ÆęŒåŽå‘å¼•ē”Ø" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/chs/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..2d30016b0fb --- /dev/null +++ b/i18n/chs/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "å·„ä½œåŒŗäø­ę²”ęœ‰åäøŗā€œ{0}ā€ēš„ę–‡ä»¶å¤¹ " +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 421ed1cedba..104c5e46e94 100644 --- a/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "ę’å…„ä»£ē ē‰‡ę®µ" + "snippet.suggestions.label": "ę’å…„ä»£ē ē‰‡ę®µ", + "sep.userSnippet": "ē”Øęˆ·ä»£ē ē‰‡ę®µ", + "sep.extSnippet": "扩展代码片段" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 85853c8d7c0..e4e7302f246 100644 --- a/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "ā€œcontributes.{0}.languageā€äø­å­˜åœØęœŖēŸ„ēš„čÆ­čØ€ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.0": "ā€œcontributes.{0}.pathā€äø­åŗ”äøŗå­—ē¬¦äø²ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.1": "ā€œcontributes.{0}.pathā€({1})åŗ”åŒ…å«åœØę‰©å±•ēš„ę–‡ä»¶å¤¹({2})å†…ć€‚čæ™åÆčƒ½ä¼šä½æę‰©å±•äøåÆē§»ę¤ć€‚", + "vscode.extension.contributes.snippets": "ę·»åŠ ä»£ē ę®µć€‚", + "vscode.extension.contributes.snippets-language": "ę­¤ä»£ē ē‰‡ę®µå‚äøŽēš„čÆ­čØ€ę ‡čÆ†ē¬¦ć€‚", + "vscode.extension.contributes.snippets-path": "ä»£ē ē‰‡ę®µę–‡ä»¶ēš„č·Æå¾„ć€‚čÆ„č·Æå¾„ē›øåÆ¹äŗŽę‰©å±•ę–‡ä»¶å¤¹ļ¼Œé€šåøøä»„ \"./snippets/\" 开夓。", + "badVariableUse": "ę‰©å±•ā€œ{0}ā€äø­ēš„äø€äøŖęˆ–å¤šäøŖä»£ē ē‰‡ę®µå¾ˆåÆčƒ½ę··ę·†äŗ†ē‰‡ę®µå˜é‡å’Œē‰‡ę®µå ä½ē¬¦ (ęœ‰å…³čÆ¦ē»†äæ”ęÆļ¼ŒčÆ·č®æé—® https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax )", + "badFile": "ę— ę³•čÆ»å–ä»£ē ē‰‡ę®µę–‡ä»¶ā€œ{0}ā€ć€‚", "source.snippet": "ē”Øęˆ·ä»£ē ē‰‡ę®µ", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0},{1}" diff --git a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index df453e33c6f..741469538d2 100644 --- a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "é…ē½®ē”ØäŗŽę˜¾ē¤ŗä»»åŠ”č¾“å‡ŗå’ŒčÆ»å–č¾“å…„ēš„é¢ęæć€‚", "JsonSchema.tasks.presentation.echo": "ęŽ§åˆ¶ę˜Æå¦å°†ę‰§č”Œēš„å‘½ä»¤ę˜¾ē¤ŗåˆ°é¢ęæäø­ć€‚é»˜č®¤å€¼äøŗā€œtrueā€ć€‚", "JsonSchema.tasks.presentation.focus": "ęŽ§åˆ¶é¢ęæę˜Æå¦čŽ·å–ē„¦ē‚¹ć€‚é»˜č®¤å€¼äøŗā€œfalseā€ć€‚å¦‚ęžœč®¾ē½®äøŗā€œtrueā€ļ¼Œé¢ęæä¹Ÿä¼šę˜¾ē¤ŗć€‚", + "JsonSchema.tasks.presentation.reveal.always": "ę€»ę˜ÆåœØę­¤ä»»åŠ”ę‰§č”Œę—¶ę˜¾ē¤ŗē»ˆē«Æć€‚", + "JsonSchema.tasks.presentation.reveal.silent": "ä»…åœØä»»åŠ”ę²”ęœ‰å…³č”é—®é¢˜åŒ¹é…ēØ‹åŗäø”åœØę‰§č”Œę—¶å‘ē”Ÿé”™čÆÆę—¶ę˜¾ē¤ŗē»ˆē«Æć€‚", + "JsonSchema.tasks.presentation.reveal.never": "äøč¦åœØę­¤ä»»åŠ”ę‰§č”Œę—¶ę˜¾ē¤ŗē»ˆē«Æć€‚", "JsonSchema.tasks.presentation.reveals": "ęŽ§åˆ¶ę˜Æå¦ę˜¾ē¤ŗčæč”Œę­¤ä»»åŠ”ēš„é¢ęæć€‚é»˜č®¤å€¼äøŗā€œalwaysā€ć€‚", "JsonSchema.tasks.presentation.instance": "ęŽ§åˆ¶ę˜Æå¦åœØä»»åŠ”é—“å…±äŗ«é¢ęæć€‚åŒäø€äøŖä»»åŠ”ä½æē”Øē›øåŒé¢ęæčæ˜ę˜ÆęÆę¬”čæč”Œę—¶ę–°åˆ›å»ŗäø€äøŖé¢ęæć€‚", "JsonSchema.tasks.terminal": "terminal å±žę€§å·²č¢«å¼ƒē”Øć€‚čÆ·ę”¹äøŗä½æē”Ø presentation", @@ -22,7 +25,8 @@ "JsonSchema.tasks.group.test": "å°†ä»»åŠ”ę ‡č®°äøŗåÆé€ščæ‡ā€œčæč”Œęµ‹čÆ•ä»»åŠ”ā€å‘½ä»¤č®æé—®ēš„ęµ‹čÆ•ä»»åŠ”ć€‚", "JsonSchema.tasks.group.none": "å°†ä»»åŠ”åˆ†é…äøŗę²”ęœ‰ē»„", "JsonSchema.tasks.group": "å®šä¹‰ę­¤ä»»åŠ”å±žäŗŽēš„ę‰§č”Œē»„ć€‚å®ƒę”ÆęŒ \"build\" ä»„å°†å…¶ę·»åŠ åˆ°ē”Ÿęˆē»„ļ¼Œä¹Ÿę”ÆęŒ \"test\" ä»„å°†å…¶ę·»åŠ åˆ°ęµ‹čÆ•ē»„ć€‚", - "JsonSchema.tasks.type": "å®šä¹‰ä»»åŠ”ę˜Æč¢«ä½œäøŗčæ›ēØ‹čæč”Œčæ˜ę˜ÆåœØ shell äø­ä½œäøŗå‘½ä»¤čæč”Œć€‚é»˜č®¤ä½œäøŗčæ›ēØ‹čæč”Œć€‚", + "JsonSchema.tasks.type": "å®šä¹‰ä»»åŠ”ę˜Æč¢«ä½œäøŗčæ›ēØ‹čæč”Œčæ˜ę˜ÆåœØ shell äø­ä½œäøŗå‘½ä»¤čæč”Œć€‚", + "JsonSchema.tasks.label": "ä»»åŠ”ēš„ē”Øęˆ·ē•Œé¢ę ‡ē­¾", "JsonSchema.version": "é…ē½®ēš„ē‰ˆęœ¬å·ć€‚", "JsonSchema.tasks.identifier": "ē”ØäŗŽåœØ launch.json ꈖ dependsOn å­å„äø­å¼•ē”Øä»»åŠ”ēš„ē”Øęˆ·å®šä¹‰ę ‡čÆ†ē¬¦ć€‚", "JsonSchema.tasks.taskLabel": "ä»»åŠ”ę ‡ē­¾", diff --git a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index c5130a55ee3..9e55d0c22e6 100644 --- a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "任劔", - "ConfigureTaskRunnerAction.noWorkspace": "ä»»åŠ”ä»…åœØå·„ä½œåŒŗę–‡ä»¶å¤¹äøŠåÆē”Øć€‚", - "ConfigureTaskRunnerAction.quickPick.template": "é€‰ę‹©ä»»åŠ”čæč”ŒēØ‹åŗ", - "ConfigureTaskRunnerAction.autoDetecting": "é€‚ē”ØäŗŽ {0} ēš„č‡ŖåŠØę£€ęµ‹ä»»åŠ”", - "ConfigureTaskRunnerAction.autoDetect": "č‡ŖåŠØę£€ęµ‹ē³»ē»Ÿä»»åŠ”å¤±č“„ć€‚čÆ·ä½æē”Øé»˜č®¤ęØ”ęæć€‚ęœ‰å…³čÆ¦ē»†äæ”ęÆļ¼ŒčÆ·å‚é˜…ä»»åŠ”č¾“å‡ŗć€‚", - "ConfigureTaskRunnerAction.autoDetectError": "č‡ŖåŠØę£€ęµ‹ä»»åŠ”ē³»ē»Ÿę—¶å‡ŗēŽ°é”™čÆÆć€‚ęœ‰å…³čÆ¦ē»†äæ”ęÆļ¼ŒčÆ·å‚é˜…ä»»åŠ”č¾“å‡ŗć€‚", - "ConfigureTaskRunnerAction.failed": "ę— ę³•åœØ \".vscode\" ę–‡ä»¶å¤¹äø­åˆ›å»ŗ \"tasks.json\" ę–‡ä»¶ć€‚ęŸ„ēœ‹ä»»åŠ”č¾“å‡ŗäŗ†č§£čÆ¦ē»†äæ”ęÆć€‚", - "ConfigureTaskRunnerAction.label": "é…ē½®ä»»åŠ”čæč”ŒēØ‹åŗ", + "ConfigureTaskRunnerAction.label": "é…ē½®ä»»åŠ”", "ConfigureBuildTaskAction.label": "é…ē½®ē”Ÿęˆä»»åŠ”", "CloseMessageAction.label": "关闭", "ShowTerminalAction.label": "ęŸ„ēœ‹ē»ˆē«Æ", @@ -19,12 +13,14 @@ "manyMarkers": "99+", "runningTasks": "ę˜¾ē¤ŗčæč”Œäø­ēš„ä»»åŠ”", "tasks": "任劔", - "TaskSystem.noHotSwap": "ę›“ę”¹ä»»åŠ”ę‰§č”Œå¼•ę“Žéœ€č¦é‡åÆ VS Code。已忽畄曓改。", + "TaskSystem.noHotSwap": "åœØęœ‰ę“»åŠØä»»åŠ”čæč”Œę—¶ę›“ę¢ä»»åŠ”ę‰§č”Œå¼•ę“Žéœ€č¦é‡ę–°åŠ č½½ēŖ—å£", + "TaskServer.folderIgnored": "ē”±äŗŽä½æē”Øä»»åŠ”ē‰ˆęœ¬ 0.1.0ļ¼Œę–‡ä»¶å¤¹ {0} 将被忽畄", "TaskService.noBuildTask1": "ęœŖå®šä¹‰ä»»ä½•ē”Ÿęˆä»»åŠ”ć€‚ä½æē”Ø \"isBuildCommand\" 在 tasks.json ę–‡ä»¶äø­ę ‡č®°ä»»åŠ”ć€‚", "TaskService.noBuildTask2": "ęœŖå®šä¹‰ä»»ä½•ē”Ÿęˆä»»åŠ”ć€‚åœØ tasks.json ę–‡ä»¶äø­å°†ä»»åŠ”ę ‡č®°äøŗ \"build\" 组。", "TaskService.noTestTask1": "ęœŖå®šä¹‰ä»»ä½•ęµ‹čÆ•ä»»åŠ”ć€‚ä½æē”Ø \"isTestCommand\" 在 tasks.json ę–‡ä»¶äø­ę ‡č®°ä»»åŠ”ć€‚", "TaskService.noTestTask2": "ęœŖå®šä¹‰ä»»ä½•ęµ‹čÆ•ä»»åŠ”ć€‚åœØ tasks.json ę–‡ä»¶äø­å°†ä»»åŠ”ę ‡č®°äøŗ \"test\" 组。", "TaskServer.noTask": "ęœŖę‰¾åˆ°č¦ę‰§č”Œēš„čÆ·ę±‚ä»»åŠ” {0}怂", + "TaskService.associate": "相关", "TaskService.attachProblemMatcher.continueWithout": "ē»§ē»­č€Œäøę‰«ęä»»åŠ”č¾“å‡ŗ", "TaskService.attachProblemMatcher.never": "ę°øäøę‰«ęä»»åŠ”č¾“å‡ŗ", "TaskService.attachProblemMatcher.learnMoreAbout": "äŗ†č§£ęœ‰å…³ę‰«ęä»»åŠ”č¾“å‡ŗēš„čÆ¦ē»†äæ”ęÆ", @@ -35,7 +31,9 @@ "TaskSystem.activeSame.noBackground": "任劔 \"{0}\" å·²å¤„äŗŽę“»åŠØēŠ¶ę€ć€‚č‹„č¦ē»ˆę­¢ä»»åŠ”ļ¼ŒčÆ·é€‰ę‹©ā€œä»»åŠ”ā€čœå•äø­ēš„ā€œē»ˆę­¢ä»»åŠ”...ā€ć€‚", "TaskSystem.active": "å½“å‰å·²ęœ‰ä»»åŠ”ę­£åœØčæč”Œć€‚čÆ·å…ˆē»ˆę­¢å®ƒļ¼Œē„¶åŽå†ę‰§č”Œå¦äø€é”¹ä»»åŠ”ć€‚", "TaskSystem.restartFailed": "ęœŖčƒ½ē»ˆę­¢å¹¶é‡åÆä»»åŠ” {0}", + "TaskService.noConfiguration": "错误: {0} ä»»åŠ”ę£€ęµ‹ę²”ęœ‰ęä¾›ę‹„ęœ‰äø‹åˆ—é…ē½®ēš„ä»»åŠ”:\n{1}\nå°†åæ½ē•„ę­¤ä»»åŠ”ć€‚", "TaskSystem.configurationErrors": "错误: ęä¾›ēš„ä»»åŠ”é…ē½®å…·ęœ‰éŖŒčÆé”™čÆÆļ¼Œę— ę³•ä½æē”Øć€‚čÆ·é¦–å…ˆę”¹ę­£é”™čÆÆć€‚", + "taskService.ignoreingFolder": "å°†åæ½ē•„å·„ä½œåŒŗę–‡ä»¶å¤¹ {0} ēš„ä»»åŠ”é…ē½®ć€‚å¤šę–‡ä»¶å¤¹å·„ä½œåŒŗä»»åŠ”ę”ÆęŒč¦ę±‚ę‰€ęœ‰ę–‡ä»¶å¤¹ä½æē”Øä»»åŠ”ē‰ˆęœ¬ 2.0.0\n", "TaskSystem.invalidTaskJson": "错误: tasks.json ę–‡ä»¶ēš„å†…å®¹å…·ęœ‰čÆ­ę³•é”™čÆÆć€‚čÆ·å…ˆę›“ę­£é”™čÆÆē„¶åŽå†ę‰§č”Œä»»åŠ”ć€‚\n", "TaskSystem.runningTask": "å­˜åœØčæč”Œäø­ēš„ä»»åŠ”ć€‚č¦ē»ˆę­¢å®ƒå—?", "TaskSystem.terminateTask": "终止任劔(&&T)", @@ -47,24 +45,33 @@ "recentlyUsed": "ęœ€čæ‘ä½æē”Øēš„ä»»åŠ”", "configured": "å·²é…ē½®ēš„ä»»åŠ”", "detected": "ę£€ęµ‹åˆ°ēš„ä»»åŠ”", + "TaskService.ignoredFolder": "ē”±äŗŽä½æē”Øä»»åŠ”ē‰ˆęœ¬ 0.1.0ļ¼Œä»„äø‹å·„ä½œåŒŗę–‡ä»¶å¤¹å°†č¢«åæ½ē•„:", + "TaskService.notAgain": "äøå†ę˜¾ē¤ŗ", + "TaskService.ok": "甮定", + "TaskService.pickRunTask": "é€‰ę‹©č¦čæč”Œēš„ä»»åŠ”", + "TaslService.noEntryToRun": "ę²”ęœ‰ę‰¾åˆ°č¦čæč”Œēš„ä»»åŠ”ć€‚é…ē½®ä»»åŠ”...", "TaskService.fetchingBuildTasks": "ę­£åœØčŽ·å–ē”Ÿęˆä»»åŠ”...", - "TaskService.noBuildTaskTerminal": "ęœŖčƒ½ę‰¾åˆ°ē”Ÿęˆä»»åŠ”ć€‚ęŒ‰ā€œé…ē½®ē”Ÿęˆä»»åŠ”ā€ę„å®šä¹‰äø€äøŖć€‚", "TaskService.pickBuildTask": "é€‰ę‹©č¦čæč”Œēš„ē”Ÿęˆä»»åŠ”", + "TaskService.noBuildTask": "ę²”ęœ‰ę‰¾åˆ°č¦čæč”Œēš„ē”Ÿęˆä»»åŠ”ć€‚é…ē½®ä»»åŠ”...", "TaskService.fetchingTestTasks": "ę­£åœØčŽ·å–ęµ‹čÆ•ä»»åŠ”...", - "TaskService.noTestTaskTerminal": "ęœŖčƒ½ę‰¾åˆ°ęµ‹čÆ•ä»»åŠ”ć€‚ęŒ‰ā€œé…ē½®ä»»åŠ”čæč”ŒēØ‹åŗā€ę„å®šä¹‰äø€äøŖć€‚", "TaskService.pickTestTask": "é€‰ę‹©č¦čæč”Œēš„ęµ‹čÆ•ä»»åŠ”", - "TaskService.noTaskRunning": "å½“å‰ę²”ęœ‰ä»»åŠ”åœØčæč”Œć€‚", + "TaskService.noTestTaskTerminal": "ę²”ęœ‰ę‰¾åˆ°č¦čæč”Œēš„ęµ‹čÆ•ä»»åŠ”ć€‚é…ē½®ä»»åŠ”...", "TaskService.tastToTerminate": "é€‰ę‹©č¦ē»ˆę­¢ēš„ä»»åŠ”", + "TaskService.noTaskRunning": "å½“å‰ę²”ęœ‰čæč”Œäø­ēš„ä»»åŠ”", "TerminateAction.noProcess": "åÆåŠØēš„čæ›ēØ‹äøå†å­˜åœØć€‚å¦‚ęžœä»»åŠ”č”ē”Ÿēš„åŽå°ä»»åŠ”é€€å‡ŗ VS Codeļ¼Œåˆ™åÆčƒ½ä¼šåÆ¼č‡“å‡ŗēŽ°å­¤ē«‹ēš„čæ›ēØ‹ć€‚", "TerminateAction.failed": "ęœŖčƒ½ē»ˆę­¢čæč”Œäø­ēš„ä»»åŠ”", - "TaskService.noTaskToRestart": "ę²”ęœ‰č¦é‡åÆēš„ä»»åŠ”ć€‚", "TaskService.tastToRestart": "é€‰ę‹©č¦é‡åÆēš„ä»»åŠ”", - "TaskService.defaultBuildTaskExists": "{0} å·²č¢«ę ‡č®°äøŗé»˜č®¤ē”Ÿęˆä»»åŠ”ć€‚", + "TaskService.noTaskToRestart": "ę²”ęœ‰č¦é‡åÆēš„ä»»åŠ”", + "TaskService.template": "é€‰ę‹©ä»»åŠ”ęØ”ęæ", + "TaskService.createJsonFile": "ä½æē”ØęØ”ęæåˆ›å»ŗ tasks.json ꖇ件", + "TaskService.openJsonFile": "打开 tasks.json ꖇ件", + "TaskService.pickTask": "é€‰ę‹©č¦é…ē½®ēš„ä»»åŠ”", + "TaskService.defaultBuildTaskExists": "{0} å·²č¢«ę ‡č®°äøŗé»˜č®¤ē”Ÿęˆä»»åŠ”", "TaskService.pickDefaultBuildTask": "é€‰ę‹©č¦ē”Øä½œé»˜č®¤ē”Ÿęˆä»»åŠ”ēš„ä»»åŠ”", "TaskService.defaultTestTaskExists": "{0} å·²č¢«ę ‡č®°äøŗé»˜č®¤ęµ‹čÆ•ä»»åŠ”ć€‚", "TaskService.pickDefaultTestTask": "é€‰ę‹©č¦ē”Øä½œé»˜č®¤ęµ‹čÆ•ä»»åŠ”ēš„ä»»åŠ”", - "TaskService.noTaskIsRunning": "ę²”ęœ‰ä»»åŠ”åœØčæč”Œć€‚", "TaskService.pickShowTask": "é€‰ę‹©č¦ę˜¾ē¤ŗč¾“å‡ŗēš„ä»»åŠ”", + "TaskService.noTaskIsRunning": "ę²”ęœ‰čæč”Œäø­ēš„ä»»åŠ”", "ShowLogAction.label": "ę˜¾ē¤ŗä»»åŠ”ę—„åæ—", "RunTaskAction.label": "运蔌任劔", "RestartTaskAction.label": "é‡åÆę­£åœØčæč”Œēš„ä»»åŠ”", diff --git a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 007d5c51e4a..c557a30ebe4 100644 --- a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "åœØę‰§č”Œä»»åŠ”ę—¶å‘ē”ŸęœŖēŸ„é”™čÆÆć€‚čÆ·å‚č§ä»»åŠ”č¾“å‡ŗę—„åæ—äŗ†č§£čÆ¦ē»†äæ”ęÆć€‚", + "dependencyFailed": "ę— ę³•č§£ęžåœØå·„ä½œåŒŗę–‡ä»¶å¤¹ā€œ{1}ā€äø­ēš„ä¾čµ–ä»»åŠ”ā€œ{0}ā€", "TerminalTaskSystem.terminalName": "任劔 - {0}", "reuseTerminal": "ē»ˆē«Æå°†č¢«ä»»åŠ”é‡ē”Øļ¼ŒęŒ‰ä»»ę„é”®å…³é—­ć€‚", "TerminalTaskSystem": "无法对 UNC é©±åŠØå™Øę‰§č”Œ shell 命令。", diff --git a/i18n/chs/src/vs/workbench/parts/tasks/node/processTaskSystem.i18n.json b/i18n/chs/src/vs/workbench/parts/tasks/node/processTaskSystem.i18n.json index 5b8a86d9c21..861f362db15 100644 --- a/i18n/chs/src/vs/workbench/parts/tasks/node/processTaskSystem.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/tasks/node/processTaskSystem.i18n.json @@ -6,7 +6,7 @@ { "TaskRunnerSystem.unknownError": "åœØę‰§č”Œä»»åŠ”ę—¶å‘ē”ŸęœŖēŸ„é”™čÆÆć€‚čÆ·å‚č§ä»»åŠ”č¾“å‡ŗę—„åæ—äŗ†č§£čÆ¦ē»†äæ”ęÆć€‚", "TaskRunnerSystem.watchingBuildTaskFinished": "\nē›‘č§†ē”Ÿęˆä»»åŠ”å·²å®Œęˆ", - "TaskRunnerSystem.childProcessError": "Failed to launch external program {0} {1}.", + "TaskRunnerSystem.childProcessError": "åÆåŠØå¤–éƒØēØ‹åŗ {0} {1} 失蓄。", "TaskRunnerSystem.cancelRequested": "\nå·²ę ¹ę®ē”Øęˆ·čÆ·ę±‚ē»ˆę­¢äŗ†ä»»åŠ”'{0}' ", "unkownProblemMatcher": "ę— ę³•č§£ęžé—®é¢˜åŒ¹é…ēØ‹åŗ {0}ć€‚ę­¤åŒ¹é…ēØ‹åŗå°†č¢«åæ½ē•„" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/chs/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index f94666c4e49..07d51f5b85c 100644 --- a/i18n/chs/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,6 +11,8 @@ "ConfigurationParser.unknownMatcherKind": "č­¦å‘Š: å·²å®šä¹‰ēš„é—®é¢˜åŒ¹é…ēØ‹åŗęœŖēŸ„ć€‚å—ę”ÆęŒēš„ē±»åž‹äøŗ string | ProblemMatcher | (string | ProblemMatcher)[]怂\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "错误: ę— ę•ˆēš„ problemMatcher 引用: {0}\n", "ConfigurationParser.noTaskType": "错误: ä»»åŠ”åæ…é”»ęä¾› type å±žę€§ć€‚å°†åæ½ē•„čÆ„ä»»åŠ”ć€‚\n{0}\n", + "ConfigurationParser.noTypeDefinition": "错误: ę²”ęœ‰ę³Øå†Œä»»åŠ”ē±»åž‹ā€œ{0}ā€ć€‚ä½ ę˜Æäøę˜Æåæ˜č®°å®‰č£…å«ęœ‰ē›øåŗ”ä»»åŠ”ęä¾›å™Øēš„ę‰©å±•?", + "ConfigurationParser.missingRequiredProperty": "错误: ä»»åŠ”é…ē½®ā€œ{0}ā€ē¼ŗå¤±åæ…č¦å±žę€§ā€œ{1}ā€ć€‚å°†åæ½ē•„čÆ„ä»»åŠ”ć€‚", "ConfigurationParser.notCustom": "错误: ä»»åŠ”ęœŖå£°ę˜Žäøŗč‡Ŗå®šä¹‰ä»»åŠ”ć€‚å°†åæ½ē•„é…ē½®ć€‚\n{0}\n", "ConfigurationParser.noTaskName": "错误: ä»»åŠ”åæ…é”»ęä¾› taskName å±žę€§ć€‚å°†åæ½ē•„čÆ„ä»»åŠ”ć€‚\n{0}\n", "taskConfiguration.shellArgs": "č­¦å‘Š: ä»»åŠ”ā€œ{0}ā€ę˜Æ shell å‘½ä»¤ļ¼ŒčÆ„å‘½ä»¤ēš„åē§°ęˆ–å…¶äø­äø€äøŖå‚ę•°å…·ęœ‰éžč½¬ä¹‰ē©ŗę ¼ć€‚č‹„č¦ē”®äæå‘½ä»¤č”Œå¼•ē”Øę­£ē”®ļ¼ŒčÆ·å°†å‚ę•°åˆå¹¶åˆ°čÆ„å‘½ä»¤ć€‚", diff --git a/i18n/chs/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 58e173605b1..b7523fc74cd 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "entryAriaLabel": "{0}ļ¼Œē»ˆē«Æé€‰å–å™Ø", + "termEntryAriaLabel": "{0}ļ¼Œē»ˆē«Æé€‰å–å™Ø", + "termCreateEntryAriaLabel": "{0}ļ¼Œę–°å»ŗē»ˆē«Æ", + "'workbench.action.terminal.newplus": "$(plus) ę–°å»ŗé›†ęˆē»ˆē«Æ", "noTerminalsMatching": "ę²”ęœ‰åŒ¹é…ēš„ē»ˆē«Æ", "noTerminalsFound": "ę²”ęœ‰ę‰“å¼€ē»ˆē«Æ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index b447c9db51b..892b51d9473 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -5,18 +5,19 @@ // Do not edit this file. It is machine generated. { "quickOpen.terminal": "ę˜¾ē¤ŗę‰€ęœ‰å·²ę‰“å¼€ēš„ē»ˆē«Æ", + "terminal": "终端", "terminalIntegratedConfigurationTitle": "é›†ęˆē»ˆē«Æ", "terminal.integrated.shell.linux": "终端在 Linux äøŠä½æē”Øēš„ shell ēš„č·Æå¾„ć€‚", "terminal.integrated.shellArgs.linux": "在 Linux ē»ˆē«ÆäøŠę—¶č¦ä½æē”Øēš„å‘½ä»¤č”Œå‚ę•°ć€‚", "terminal.integrated.shell.osx": "终端在 OS X äøŠä½æē”Øēš„ shell ēš„č·Æå¾„ć€‚", "terminal.integrated.shellArgs.osx": "在 OS X ē»ˆē«ÆäøŠę—¶č¦ä½æē”Øēš„å‘½ä»¤č”Œå‚ę•°ć€‚", + "terminal.integrated.shell.windows": "终端在 Windows ä½æē”Øēš„ shell č·Æå¾„ć€‚ä½æē”Øéš Windows äø€čµ·ęä¾›ēš„ shell (cmd态PowerShell ꈖ Bash on Ubuntu) ꗶ怂", "terminal.integrated.shellArgs.windows": "在 Windows ē»ˆē«ÆäøŠę—¶ä½æē”Øēš„å‘½ä»¤č”Œå‚ę•°ć€‚", "terminal.integrated.rightClickCopyPaste": "č®¾ē½®åŽļ¼ŒåœØē»ˆē«Æå†…å³é”®å•å‡»ę—¶ļ¼Œčæ™å°†é˜»ę­¢ę˜¾ē¤ŗäøŠäø‹ę–‡čœå•ļ¼Œē›øåļ¼Œå®ƒå°†åœØęœ‰é€‰é”¹ę—¶čæ›č”Œå¤åˆ¶ļ¼Œå¹¶äø”åœØę²”ęœ‰é€‰é”¹ę—¶čæ›č”Œē²˜č““ć€‚", "terminal.integrated.fontFamily": "ęŽ§åˆ¶ē»ˆē«Æēš„å­—ä½“ē³»åˆ—ļ¼Œčæ™åœØē¼–č¾‘å™Øäø­ę˜Æé»˜č®¤ēš„ć€‚fontFamily ēš„å€¼ć€‚", - "terminal.integrated.fontLigatures": "ęŽ§åˆ¶ę˜Æå¦åœØē»ˆē«Æäø­åÆē”Øå­—ä½“čæžå­—ć€‚", "terminal.integrated.fontSize": "ęŽ§åˆ¶ē»ˆē«Æēš„å­—å·(ä»„åƒē“ äøŗå•ä½)怂", "terminal.integrated.lineHeight": "ęŽ§åˆ¶ē»ˆē«Æēš„č”Œé«˜ļ¼Œę­¤ę•°å­—ä¹˜ä»„ē»ˆē«Æå­—å·å¾—åˆ°å®žé™…č”Œé«˜(ä»„åƒē“ č”Øē¤ŗ)怂", - "terminal.integrated.enableBold": "ę˜Æå¦åœØē»ˆē«Æå†…åÆē”Øē²—ä½“ę–‡ęœ¬ļ¼Œčæ™éœ€č¦ē»ˆē«Æ shell ēš„ę”ÆęŒć€‚", + "terminal.integrated.enableBold": "ę˜Æå¦åœØē»ˆē«Æå†…åÆē”Øē²—ä½“ę–‡ęœ¬ļ¼Œę³Øę„čæ™éœ€č¦ē»ˆē«Æå‘½ä»¤č”Œēš„ę”ÆęŒć€‚", "terminal.integrated.cursorBlinking": "ęŽ§åˆ¶ē»ˆē«Æå…‰ę ‡ę˜Æå¦é—Ŗēƒć€‚", "terminal.integrated.cursorStyle": "ęŽ§åˆ¶ē»ˆē«Æęøøę ‡ēš„ę ·å¼ć€‚", "terminal.integrated.scrollback": "ęŽ§åˆ¶ē»ˆē«ÆäæęŒåœØē¼“å†²åŒŗēš„ęœ€å¤§č”Œę•°ć€‚", @@ -27,7 +28,6 @@ "terminal.integrated.env.osx": "要添加到 VS Code čæ›ēØ‹äø­ēš„åø¦ęœ‰ēŽÆå¢ƒå˜é‡ēš„åÆ¹č±”ļ¼Œå…¶ä¼šč¢« OS X ē»ˆē«Æä½æē”Øć€‚", "terminal.integrated.env.linux": "要添加到 VS Code čæ›ēØ‹äø­ēš„åø¦ęœ‰ēŽÆå¢ƒå˜é‡ēš„åÆ¹č±”ļ¼Œå…¶ä¼šč¢« Linux ē»ˆē«Æä½æē”Øć€‚", "terminal.integrated.env.windows": "要添加到 VS Code čæ›ēØ‹äø­ēš„åø¦ęœ‰ēŽÆå¢ƒå˜é‡ēš„åÆ¹č±”ļ¼Œå…¶ä¼šč¢« Windows ē»ˆē«Æä½æē”Øć€‚", - "terminal": "终端", "terminalCategory": "终端", "viewCategory": "ęŸ„ēœ‹" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index c8746db7afb..d96d23dca0e 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "åˆ‡ę¢é›†ęˆē»ˆē«Æ", "workbench.action.terminal.kill": "ē»ˆę­¢ę“»åŠØē»ˆē«Æå®žä¾‹", "workbench.action.terminal.kill.short": "终止终端", + "workbench.action.terminal.quickKill": "ē»ˆę­¢ē»ˆē«Æå®žä¾‹", "workbench.action.terminal.copySelection": "å¤åˆ¶ę‰€é€‰å†…å®¹", "workbench.action.terminal.selectAll": "全选", + "workbench.action.terminal.deleteWordLeft": "åˆ é™¤å·¦ä¾§ēš„å­—ē¬¦", + "workbench.action.terminal.deleteWordRight": "åˆ é™¤å³ä¾§ēš„å­—ē¬¦", "workbench.action.terminal.new": "ę–°å»ŗé›†ęˆē»ˆē«Æ", "workbench.action.terminal.new.short": "ę–°ēš„ē»ˆē«Æ", "workbench.action.terminal.focus": "čšē„¦äŗŽē»ˆē«Æ", "workbench.action.terminal.focusNext": "čšē„¦äŗŽäø‹äø€ē»ˆē«Æ", - "workbench.action.terminal.focusAtIndex": "ē„¦ē‚¹ē»ˆē«Æ {0}", "workbench.action.terminal.focusPrevious": "čšē„¦äŗŽäøŠäø€ē»ˆē«Æ", "workbench.action.terminal.paste": "粘蓓到擻动终端中", "workbench.action.terminal.DefaultShell": "é€‰ę‹©é»˜č®¤ Shell", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "重命名", "workbench.action.terminal.rename.prompt": "č¾“å…„ē»ˆē«Æåē§°", "workbench.action.terminal.focusFindWidget": "čšē„¦äŗŽęŸ„ę‰¾å°ē»„ä»¶", - "workbench.action.terminal.hideFindWidget": "éšč—ęŸ„ę‰¾å°ē»„ä»¶" + "workbench.action.terminal.hideFindWidget": "éšč—ęŸ„ę‰¾å°ē»„ä»¶", + "nextTerminalFindTerm": "ę˜¾ē¤ŗäø‹äø€äøŖęœē“¢ē»“ęžœ", + "previousTerminalFindTerm": "ę˜¾ē¤ŗäøŠäø€äøŖęœē“¢ē»“ęžœ", + "quickOpenTerm": "åˆ‡ę¢ę“»åŠØē»ˆē«Æ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 4fb5b93d573..a1f48a18fc6 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "ē»ˆē«Æēš„å‰ę™Æé¢œč‰²ć€‚", "terminalCursor.foreground": "ē»ˆē«Æå…‰ę ‡ēš„å‰ę™Æč‰²ć€‚", "terminalCursor.background": "ē»ˆē«Æå…‰ę ‡ēš„čƒŒę™Æč‰²ć€‚å…č®øč‡Ŗå®šä¹‰č¢« block å…‰ę ‡é®ä½ēš„å­—ē¬¦ēš„é¢œč‰²ć€‚", + "terminal.selectionBackground": "ē»ˆē«Æé€‰äø­å†…å®¹ēš„čƒŒę™Æé¢œč‰²ć€‚", "terminal.ansiColor": "ē»ˆē«Æäø­ēš„ ANSI é¢œč‰²ā€œ{0}ā€ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.i18n.json index 7d549981898..e45ac7a3531 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "terminal.integrated.allowWorkspaceShell": "ę˜Æå¦å…č®øåœØē»ˆē«Æäø­åÆåŠØ {0} (å®šä¹‰äøŗå·„ä½œåŒŗč®¾ē½®)?", - "allow": "Allow", - "disallow": "Disallow" + "allow": "允许", + "disallow": "äøå…č®ø" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json index 204cfda7f73..6c965409e92 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.i18n.json @@ -6,5 +6,5 @@ { "terminalLinkHandler.followLinkAlt": "Alt + å•å‡»ä»„č®æé—®é“¾ęŽ„", "terminalLinkHandler.followLinkCmd": "Cmd + å•å‡»ä»„č·ŸčøŖé“¾ęŽ„", - "terminalLinkHandler.followLinkCtrl": "Ctrl + å•å‡»ä»„č·ŸčøŖé“¾ęŽ„" + "terminalLinkHandler.followLinkCtrl": "ęŒ‰ä½ Ctrl å¹¶å•å‡»åÆč®æé—®é“¾ęŽ„" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index d3e2c12d9a6..837bb66bacc 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "复制", - "createNewTerminal": "ę–°ēš„ē»ˆē«Æ", "paste": "粘蓓", "selectAll": "全选", "clear": "清除" diff --git a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 27b7ce1e9c3..6b431f37d7f 100644 --- a/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "å„½ļ¼Œę°øäøå†ę˜¾ē¤ŗ", "terminal.integrated.chooseWindowsShell": "é€‰ę‹©é¦–é€‰ēš„ē»ˆē«Æ shellļ¼Œä½ åÆēØåŽåœØč®¾ē½®äø­čæ›č”Œę›“ę”¹", "terminalService.terminalCloseConfirmationSingular": "å­˜åœØäø€äøŖę“»åŠØēš„ē»ˆē«Æä¼ščÆļ¼Œę˜Æå¦č¦ē»ˆę­¢ę­¤ä¼ščÆ?", - "terminalService.terminalCloseConfirmationPlural": "存在 {0} äøŖę“»åŠØēš„ē»ˆē«Æä¼ščÆļ¼Œę˜Æå¦č¦ē»ˆę­¢čæ™äŗ›ä¼ščÆ?", - "yes": "是" + "terminalService.terminalCloseConfirmationPlural": "存在 {0} äøŖę“»åŠØēš„ē»ˆē«Æä¼ščÆļ¼Œę˜Æå¦č¦ē»ˆę­¢čæ™äŗ›ä¼ščÆ?" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 8459b7e494e..d43fc9ca29b 100644 --- a/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,6 +14,7 @@ "licenseChanged": "ęˆ‘ä»¬ēš„č®øåÆę”ę¬¾å·²ę›“ę”¹ļ¼ŒčÆ·ä»”ē»†ęµč§ˆć€‚", "license": "čÆ»å–č®øåÆčÆ", "neveragain": "äøå†ę˜¾ē¤ŗ", + "64bitisavailable": "{0} ēš„ Windows 64 ä½ē‰ˆēŽ°å·²åÆē”Ø!", "learn more": "了解详细俔息", "updateIsReady": "ęœ‰ę–°ēš„ {0} ēš„ę›“ę–°åÆē”Øć€‚", "thereIsUpdateAvailable": "å­˜åœØåÆē”Øę›“ę–°ć€‚", diff --git a/i18n/chs/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/chs/src/vs/workbench/parts/views/browser/views.i18n.json index c293062101d..1e211f7c694 100644 --- a/i18n/chs/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/views/browser/views.i18n.json @@ -5,5 +5,5 @@ // Do not edit this file. It is machine generated. { "viewToolbarAriaLabel": "{0} ę“ä½œ", - "removeView": "ä»Žä¾§č¾¹ę åˆ é™¤" + "hideView": "ä»Žä¾§č¾¹ę äø­éšč—" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 5aa494cfd6f..634ceb97cb3 100644 --- a/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "开始", "welcomePage.newFile": "新建文件", "welcomePage.openFolder": "打开文件夹...", - "welcomePage.cloneGitRepository": "克隆 Git å­˜å‚Øåŗ“...", + "welcomePage.addWorkspaceFolder": "ę·»åŠ å·„ä½œåŒŗę–‡ä»¶å¤¹...", "welcomePage.recent": "ęœ€čæ‘", "welcomePage.moreRecent": "ę›“å¤š...", "welcomePage.noRecentFolders": "ę— ęœ€čæ‘ä½æē”Øę–‡ä»¶å¤¹", diff --git a/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json index 5c2a2259104..1f422ca6c00 100644 --- a/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json @@ -8,5 +8,6 @@ "workbench.startupEditor.none": "启动(äøåø¦ē¼–č¾‘å™Ø)怂", "workbench.startupEditor.welcomePage": "ę‰“å¼€ę¬¢čæŽé”µé¢ļ¼ˆé»˜č®¤ļ¼‰ć€‚", "workbench.startupEditor.newUntitledFile": "ę‰“å¼€ę–°ēš„ę— ę ‡é¢˜ę–‡ę”£", + "workbench.startupEditor": "åœØęœŖčƒ½ę¢å¤äøŠäø€ä¼ščÆäæ”ęÆēš„ęƒ…å†µäø‹ļ¼ŒęŽ§åˆ¶åÆåŠØę—¶ę˜¾ē¤ŗēš„ē¼–č¾‘å™Øć€‚é€‰ę‹© \"none\" č”Øē¤ŗåÆåŠØę—¶äøę‰“å¼€ē¼–č¾‘å™Øļ¼Œ\"welcomePage\" č”Øē¤ŗę‰“å¼€ę¬¢čæŽé”µé¢(默认),\"newUntitledFile\" č”Øē¤ŗę‰“å¼€ę–°ēš„ę— ę ‡é¢˜ę–‡ę”£(ä»…ę‰“å¼€äø€äøŖē©ŗå·„ä½œåŒŗ)怂", "help": "帮助" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 2ce7d16dc1f..96dfd2ea466 100644 --- a/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "显示 Azure 扩展", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/chs/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/chs/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 3fdab2ec275..a3461e4f301 100644 --- a/i18n/chs/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "äŗ¤äŗ’å¼ę¼”ē»ƒåœŗ", - "editorWalkThrough.title": "äŗ¤äŗ’å¼ę¼”ē»ƒåœŗ" + "editorWalkThrough.title": "äŗ¤äŗ’å¼ę¼”ē»ƒåœŗ", + "editorWalkThrough": "äŗ¤äŗ’å¼ę¼”ē»ƒåœŗ" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/chs/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..2eb80022de4 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "č®¾ē½®ę‘˜č¦ć€‚ę­¤ę ‡ē­¾å°†åœØč®¾ē½®ę–‡ä»¶äø­ē”Øä½œåˆ†éš”ę³Øé‡Šć€‚", + "vscode.extension.contributes.configuration.properties": "é…ē½®å±žę€§ēš„ęčæ°ć€‚", + "scope.window.description": "ē‰¹å®šäŗŽēŖ—å£ēš„é…ē½®ļ¼ŒåÆåœØā€œē”Øęˆ·ā€ęˆ–ā€œå·„ä½œåŒŗā€č®¾ē½®äø­é…ē½®ć€‚", + "scope.resource.description": "ē‰¹å®šäŗŽčµ„ęŗēš„é…ē½®ļ¼ŒåÆåœØā€œē”Øęˆ·ā€ć€ā€œå·„ä½œåŒŗā€ęˆ–ā€œę–‡ä»¶å¤¹ā€č®¾ē½®äø­é…ē½®ć€‚", + "scope.description": "é…ē½®é€‚ē”Øēš„čŒƒå›“ć€‚åÆē”ØčŒƒå›“ęœ‰ā€œēŖ—å£ā€å’Œā€œčµ„ęŗā€ć€‚", + "vscode.extension.contributes.configuration": "ē”ØäŗŽé…ē½®å­—ē¬¦äø²ć€‚", + "invalid.title": "configuration.title åæ…é”»ę˜Æå­—ē¬¦äø²", + "vscode.extension.contributes.defaultConfiguration": "ęŒ‰čÆ­čØ€ęä¾›é»˜č®¤ē¼–č¾‘å™Øé…ē½®č®¾ē½®ć€‚", + "invalid.properties": "configuration.properties åæ…é”»ę˜ÆåÆ¹č±”", + "invalid.allOf": "\"configuration.allOf\" å·²č¢«å¼ƒē”Øäø”äøåŗ”č¢«ä½æē”Øć€‚ä½ åÆä»„å°†å¤šäøŖé…ē½®å•å…ƒä½œäøŗę•°ē»„ä¼ é€’ē»™ \"configuration\" å‚äøŽē‚¹ć€‚", + "workspaceConfig.folders.description": "å°†č½½å…„åˆ°å·„ä½œåŒŗēš„ę–‡ä»¶å¤¹åˆ—č”Øć€‚", + "workspaceConfig.path.description": "文件路径。例如 \"/root/folderA\" ꈖ \"./folderA\"ć€‚åŽč€…č”Øē¤ŗę ¹ę®å·„ä½œåŒŗę–‡ä»¶ä½ē½®čæ›č”Œč§£ęžēš„ē›øåÆ¹č·Æå¾„ć€‚", + "workspaceConfig.name.description": "ę–‡ä»¶å¤¹ēš„åÆé€‰åē§°ć€‚", + "workspaceConfig.uri.description": "ę–‡ä»¶å¤¹ēš„ URI", + "workspaceConfig.settings.description": "巄作区设置", + "workspaceConfig.extensions.description": "å·„ä½œåŒŗę‰©å±•", + "unknownWorkspaceProperty": "ęœŖēŸ„ēš„å·„ä½œåŒŗé…ē½®å±žę€§" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json index 4d604a72c83..2eb80022de4 100644 --- a/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,12 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "ē”ØäŗŽé…ē½®å­—ē¬¦äø²ć€‚", "vscode.extension.contributes.configuration.title": "č®¾ē½®ę‘˜č¦ć€‚ę­¤ę ‡ē­¾å°†åœØč®¾ē½®ę–‡ä»¶äø­ē”Øä½œåˆ†éš”ę³Øé‡Šć€‚", "vscode.extension.contributes.configuration.properties": "é…ē½®å±žę€§ēš„ęčæ°ć€‚", - "invalid.type": "å¦‚ęžœčæ›č”Œč®¾ē½®ļ¼Œ\"configuration.type\" 必锻设置为对豔", + "scope.window.description": "ē‰¹å®šäŗŽēŖ—å£ēš„é…ē½®ļ¼ŒåÆåœØā€œē”Øęˆ·ā€ęˆ–ā€œå·„ä½œåŒŗā€č®¾ē½®äø­é…ē½®ć€‚", + "scope.resource.description": "ē‰¹å®šäŗŽčµ„ęŗēš„é…ē½®ļ¼ŒåÆåœØā€œē”Øęˆ·ā€ć€ā€œå·„ä½œåŒŗā€ęˆ–ā€œę–‡ä»¶å¤¹ā€č®¾ē½®äø­é…ē½®ć€‚", + "scope.description": "é…ē½®é€‚ē”Øēš„čŒƒå›“ć€‚åÆē”ØčŒƒå›“ęœ‰ā€œēŖ—å£ā€å’Œā€œčµ„ęŗā€ć€‚", + "vscode.extension.contributes.configuration": "ē”ØäŗŽé…ē½®å­—ē¬¦äø²ć€‚", "invalid.title": "configuration.title åæ…é”»ę˜Æå­—ē¬¦äø²", "vscode.extension.contributes.defaultConfiguration": "ęŒ‰čÆ­čØ€ęä¾›é»˜č®¤ē¼–č¾‘å™Øé…ē½®č®¾ē½®ć€‚", "invalid.properties": "configuration.properties åæ…é”»ę˜ÆåÆ¹č±”", - "workspaceConfig.settings.description": "巄作区设置" + "invalid.allOf": "\"configuration.allOf\" å·²č¢«å¼ƒē”Øäø”äøåŗ”č¢«ä½æē”Øć€‚ä½ åÆä»„å°†å¤šäøŖé…ē½®å•å…ƒä½œäøŗę•°ē»„ä¼ é€’ē»™ \"configuration\" å‚äøŽē‚¹ć€‚", + "workspaceConfig.folders.description": "å°†č½½å…„åˆ°å·„ä½œåŒŗēš„ę–‡ä»¶å¤¹åˆ—č”Øć€‚", + "workspaceConfig.path.description": "文件路径。例如 \"/root/folderA\" ꈖ \"./folderA\"ć€‚åŽč€…č”Øē¤ŗę ¹ę®å·„ä½œåŒŗę–‡ä»¶ä½ē½®čæ›č”Œč§£ęžēš„ē›øåÆ¹č·Æå¾„ć€‚", + "workspaceConfig.name.description": "ę–‡ä»¶å¤¹ēš„åÆé€‰åē§°ć€‚", + "workspaceConfig.uri.description": "ę–‡ä»¶å¤¹ēš„ URI", + "workspaceConfig.settings.description": "巄作区设置", + "workspaceConfig.extensions.description": "å·„ä½œåŒŗę‰©å±•", + "unknownWorkspaceProperty": "ęœŖēŸ„ēš„å·„ä½œåŒŗé…ē½®å±žę€§" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/chs/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index c709a1e567f..93901b17ec9 100644 --- a/i18n/chs/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/chs/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "打开设置", + "openTasksConfiguration": "ę‰“å¼€ä»»åŠ”é…ē½®", + "openLaunchConfiguration": "ę‰“å¼€åÆåŠØé…ē½®", "close": "关闭", - "saveAndRetry": "äæå­˜č®¾ē½®å¹¶é‡čÆ•", - "errorInvalidConfiguration": "无法写兄设置。请打开 **ē”Øęˆ·č®¾ē½®** ę›“ę­£ę–‡ä»¶äø­ēš„é”™čÆÆ/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", - "errorInvalidConfigurationWorkspace": "无法写兄设置。请打开 **巄作区设置** ę›“ę­£ę–‡ä»¶äø­ēš„é”™čÆÆ/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", - "errorConfigurationFileDirty": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·å…ˆäæå­˜ **ē”Øęˆ·č®¾ē½®** ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", - "errorConfigurationFileDirtyWorkspace": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·å…ˆäæå­˜ **巄作区设置** ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", + "open": "打开设置", + "saveAndRetry": "äæå­˜å¹¶é‡čÆ•", + "errorUnknownKey": "ę²”ęœ‰ę³Øå†Œé…ē½® {1}ļ¼Œå› ę­¤ę— ę³•å†™å…„ {0}怂", + "errorInvalidFolderConfiguration": "{0} äøę”ÆęŒę–‡ä»¶å¤¹čµ„ęŗåŸŸļ¼Œå› ę­¤ę— ę³•å†™å…„\"文件夹设置\"怂", + "errorInvalidUserTarget": "{0} äøę”ÆęŒå…Øå±€åŸŸļ¼Œå› ę­¤ę— ę³•å†™å…„\"ē”Øęˆ·č®¾ē½®\"怂", + "errorInvalidWorkspaceTarget": "{0} äøåœØå¤šę–‡ä»¶å¤¹å·„ä½œåŒŗēŽÆå¢ƒäø‹ę”ÆęŒå·„ä½œåŒŗä½œē”ØåŸŸļ¼Œå› ę­¤ę— ę³•å†™å…„ā€œå·„ä½œåŒŗč®¾ē½®ā€ć€‚", + "errorInvalidFolderTarget": "ęœŖęä¾›čµ„ęŗļ¼Œå› ę­¤ę— ę³•å†™å…„\"文件夹设置\"怂", + "errorNoWorkspaceOpened": "ę²”ęœ‰ę‰“å¼€ä»»ä½•å·„ä½œåŒŗļ¼Œå› ę­¤ę— ę³•å†™å…„ {0}ć€‚čÆ·å…ˆę‰“å¼€äø€äøŖå·„ä½œåŒŗļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorInvalidTaskConfiguration": "ę— ę³•å†™å…„ä»»åŠ”ę–‡ä»¶ć€‚čÆ·ę‰“å¼€**任劔**文件并清除错误/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorInvalidLaunchConfiguration": "ę— ę³•å†™å…„åÆåŠØę–‡ä»¶ć€‚čÆ·ę‰“å¼€**启动**文件并清除错误/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorInvalidConfiguration": "ę— ę³•å†™å…„ē”Øęˆ·č®¾ē½®ć€‚čÆ·ę‰“å¼€**ē”Øęˆ·č®¾ē½®**文件并清除错误/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorInvalidConfigurationWorkspace": "ę— ę³•å†™å…„å·„ä½œåŒŗč®¾ē½®ć€‚čÆ·ę‰“å¼€**巄作区设置**文件并清除错误/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorInvalidConfigurationFolder": "ę— ę³•å†™å…„ę–‡ä»¶å¤¹č®¾ē½®ć€‚čÆ·ę‰“å¼€åœØ **{0}** ę–‡ä»¶å¤¹äø‹ēš„**文件夹设置**文件并清除错误/č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorTasksConfigurationFileDirty": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·å…ˆäæå­˜**ä»»åŠ”é…ē½®**ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorLaunchConfigurationFileDirty": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·å…ˆäæå­˜**åÆåŠØé…ē½®**ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorConfigurationFileDirty": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·å…ˆäæå­˜**ē”Øęˆ·č®¾ē½®**ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorConfigurationFileDirtyWorkspace": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·å…ˆäæå­˜**巄作区设置**ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorConfigurationFileDirtyFolder": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„č®¾ē½®ć€‚čÆ·å…ˆäæå­˜åœØ **{0}** äø‹ēš„**文件夹设置**ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", "userTarget": "ē”Øęˆ·č®¾ē½®", "workspaceTarget": "巄作区设置", "folderTarget": "文件夹设置" diff --git a/i18n/chs/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/chs/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/chs/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..81f5e1cfda2 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "ę‰©å±•ęœŖåœØ 10 ē§’å†…åÆåŠØļ¼ŒåÆčƒ½åœØē¬¬äø€č”Œå·²åœę­¢ļ¼Œéœ€č¦č°ƒčÆ•å™Øę‰čƒ½ē»§ē»­ć€‚", + "extensionHostProcess.startupFail": "ę‰©å±•äø»ęœŗęœŖåœØ 10 ē§’å†…åÆåŠØļ¼ŒåÆčƒ½å‘ē”Ÿäŗ†äø€äøŖé—®é¢˜ć€‚", + "extensionHostProcess.error": "ę‰©å±•äø»ęœŗäø­ēš„é”™čÆÆ: {0}" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..eb7858e1e0c --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "ęœŖčƒ½åˆ†ęž {0}: {1}怂", + "fileReadFail": "ę— ę³•čÆ»å–ę–‡ä»¶ {0}: {1}怂", + "jsonsParseFail": "ęœŖčƒ½åˆ†ęž {0} ꈖ {1}: {2}怂", + "missingNLSKey": "ę— ę³•ę‰¾åˆ°é”® {0} ēš„ę¶ˆęÆć€‚" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..c6b9abd9ce6 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "å¼€å‘äŗŗå‘˜å·„å…·", + "restart": "é‡åÆę‰©å±•å®æäø»", + "extensionHostProcess.crash": "ę‰©å±•å®æäø»ę„å¤–ē»ˆę­¢ć€‚", + "extensionHostProcess.unresponsiveCrash": "ę‰©å±•å®æäø»å› ę²”ęœ‰å“åŗ”č€Œč¢«ē»ˆę­¢ć€‚", + "overwritingExtension": "ä½æē”Øę‰©å±•ēØ‹åŗ {1} č¦†ē›–ę‰©å±•ēØ‹åŗ {0}怂", + "extensionUnderDevelopment": "正在 {0} å¤„åŠ č½½å¼€å‘ę‰©å±•ēØ‹åŗ" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/chs/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..80b697be3d3 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "ę–‡ä»¶ä¼¼ä¹Žę˜ÆäŗŒčæ›åˆ¶ę–‡ä»¶ļ¼Œę— ę³•ä½œäøŗę–‡ę”£ę‰“å¼€" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/chs/src/vs/workbench/services/files/node/fileService.i18n.json index 0bd4e10c0c1..dfb188fa179 100644 --- a/i18n/chs/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/chs/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "ę— ę•ˆēš„ę–‡ä»¶čµ„ęŗ({0})", - "fileIsDirectoryError": "ę–‡ä»¶ę˜Æē›®å½•({0})", + "fileIsDirectoryError": "ę–‡ä»¶ę˜Æē›®å½•", "fileNotModifiedError": "č‡Ŗä»„äø‹ę—¶é—“ęœŖäæ®ę”¹ēš„ę–‡ä»¶:", "fileTooLargeError": "ę–‡ä»¶å¤Ŗå¤§ļ¼Œę— ę³•ę‰“å¼€", "fileBinaryError": "ę–‡ä»¶ä¼¼ä¹Žę˜ÆäŗŒčæ›åˆ¶ę–‡ä»¶ļ¼Œę— ę³•ä½œäøŗę–‡ę”£ę‰“å¼€", "fileNotFoundError": "ę‰¾äøåˆ°ę–‡ä»¶({0})", + "fileExists": "å·²å­˜åœØč¦åˆ›å»ŗēš„ę–‡ä»¶ ({0})", "fileMoveConflict": "ę— ę³•ē§»åŠØ/å¤åˆ¶ć€‚ę–‡ä»¶å·²å­˜åœØäŗŽē›®ę ‡ä½ē½®ć€‚", "unableToMoveCopyError": "ę— ę³•ē§»åŠØ/å¤åˆ¶ć€‚ę–‡ä»¶å°†ę›æę¢å…¶ę‰€åœØēš„ę–‡ä»¶å¤¹ć€‚", "foldersCopyError": "ę— ę³•å°†ę–‡ä»¶å¤¹å¤åˆ¶åˆ°å·„ä½œåŒŗäø­ć€‚čÆ·é€‰ę‹©å•ē‹¬ēš„ę–‡ä»¶ę„čæ›č”Œå¤åˆ¶ć€‚", diff --git a/i18n/chs/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/chs/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/chs/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/chs/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 24302866e1f..1c27ab2249d 100644 --- a/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/chs/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "č§„åˆ™å­—ä½“ę ·å¼:ā€œę–œä½“ā€ć€ā€œē²—ä½“ā€å’Œā€œäø‹åˆ’ēŗæā€äø­ēš„äø€ē§ęˆ–č€…ē»„åˆ", - "schema.colors": "čÆ­ę³•ēŖå‡ŗę˜¾ē¤ŗé¢œč‰²", - "schema.properties.name": "č§„åˆ™ęčæ°", - "schema.tokenColors.path": "tmTheme ę–‡ä»¶č·Æå¾„ļ¼ˆē›øåÆ¹äŗŽå½“å‰ę–‡ä»¶ļ¼‰" + "schema.token.settings": "ę ‡č®°ēš„é¢œč‰²å’Œę ·å¼ć€‚", + "schema.token.foreground": "ę ‡č®°ēš„å‰ę™Æč‰²ć€‚", + "schema.token.background.warning": "ęš‚äøę”ÆęŒę ‡č®°čƒŒę™Æč‰²ć€‚", + "schema.token.fontStyle": "č§„åˆ™å­—ä½“ę ·å¼:ā€œę–œä½“ā€ć€ā€œē²—ä½“ā€å’Œā€œäø‹åˆ’ēŗæā€äø­ēš„äø€ē§ęˆ–č€…ē»„åˆ", + "schema.fontStyle.error": "å­—ä½“ę ·å¼åæ…é”»äøŗ \"italic\"(ę–œä½“)态 \"bold\"(粗体)和 \"underline\"(äø‹åˆ’ēŗæ)ēš„ē»„åˆć€‚", + "schema.properties.name": "č§„åˆ™ēš„ęčæ°ć€‚", + "schema.properties.scope": "ę­¤č§„åˆ™é€‚ē”Øēš„čŒƒå›“é€‰ę‹©å™Øć€‚", + "schema.tokenColors.path": "tmTheme 文件路径(ē›øåÆ¹äŗŽå½“å‰ę–‡ä»¶)怂", + "schema.colors": "čÆ­ę³•ēŖå‡ŗę˜¾ē¤ŗé¢œč‰²" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 182830f549e..47cfacc0457 100644 --- a/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/chs/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "ä½æē”ØęŸē§å­—ä½“ę—¶: ę–‡ęœ¬å­—ä½“ēš„å­—ä½“å¤§å°(ä»„ē™¾åˆ†ęÆ”č”Øē¤ŗ)ć€‚å¦‚ęžœęœŖč®¾ē½®ļ¼Œåˆ™é»˜č®¤äøŗå­—ä½“å®šä¹‰äø­ēš„å¤§å°ć€‚", "schema.fontId": "ä½æē”ØęŸē§å­—ä½“ę—¶: å­—ä½“ēš„ IDć€‚å¦‚ęžœęœŖč®¾ē½®ļ¼Œåˆ™é»˜č®¤äøŗē¬¬äø€äøŖå­—ä½“å®šä¹‰ć€‚", "schema.light": "ęµ…č‰²äø»é¢˜äø­ę–‡ä»¶å›¾ę ‡ēš„åÆé€‰å…³č”ć€‚", - "schema.highContrast": "é«˜åÆ¹ęÆ”åŗ¦é¢œč‰²äø»é¢˜äø­ę–‡ä»¶å›¾ę ‡ēš„åÆé€‰å…³č”ć€‚" + "schema.highContrast": "é«˜åÆ¹ęÆ”åŗ¦é¢œč‰²äø»é¢˜äø­ę–‡ä»¶å›¾ę ‡ēš„åÆé€‰å…³č”ć€‚", + "schema.hidesExplorerArrows": "é…ē½®ę–‡ä»¶čµ„ęŗē®”ē†å™Øēš„ē®­å¤“ę˜Æå¦åŗ”åœØę­¤äø»é¢˜åÆē”Øę—¶éšč—ć€‚" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 88cd69f2451..224f57f3f64 100644 --- a/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "åˆ†ęž JSON äø»é¢˜ę–‡ä»¶ {0} ę—¶å‡ŗēŽ°é—®é¢˜", "error.invalidformat.colors": "åˆ†ęžé¢œč‰²äø»é¢˜ę–‡ä»¶ę—¶å‡ŗēŽ°é—®é¢˜ļ¼š{0}ć€‚å±žę€§ā€œcolorsā€äøę˜Æā€œobjectā€ē±»åž‹ć€‚", - "error.invalidformat.tokenColors": "åˆ†ęžé¢œč‰²äø»é¢˜ę–‡ä»¶ę—¶å‡ŗēŽ°é—®é¢˜ļ¼š{0}ć€‚å±žę€§ā€œtokenColorsā€åŗ”äøŗęŒ‡å®šé¢œč‰²ēš„ę•°ē»„ęˆ–ę˜ÆęŒ‡å‘ TextMate äø»é¢˜ę–‡ä»¶ēš„č·Æå¾„", + "error.invalidformat.tokenColors": "åˆ†ęžé¢œč‰²äø»é¢˜ę–‡ä»¶ę—¶å‡ŗēŽ°é—®é¢˜ļ¼š{0}ć€‚å±žę€§ \"tokenColors\" åŗ”äøŗęŒ‡å®šé¢œč‰²ēš„ę•°ē»„ęˆ–ę˜ÆęŒ‡å‘ TextMate äø»é¢˜ę–‡ä»¶ēš„č·Æå¾„", "error.plist.invalidformat": "åˆ†ęž tmTheme ę–‡ä»¶ę—¶å‡ŗēŽ°é—®é¢˜ļ¼š{0}ć€‚ā€œsettingsā€äøę˜Æę•°ē»„ć€‚", "error.cannotparse": "åˆ†ęž tmTheme ę–‡ä»¶ę—¶å‡ŗēŽ°é—®é¢˜ļ¼š{0}", "error.cannotload": "åˆ†ęž tmTheme ꖇ件 {0} ę—¶å‡ŗēŽ°é—®é¢˜ļ¼š{1}" diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..61d59fe560d --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "čÆ·ęä¾› TextMate é¢œč‰²äø»é¢˜ć€‚", + "vscode.extension.contributes.themes.id": "ē”Øęˆ·č®¾ē½®äø­ä½æē”Øēš„å›¾ę ‡äø»é¢˜ēš„ ID怂", + "vscode.extension.contributes.themes.label": "显示在 UI äø­ēš„é¢œč‰²äø»é¢˜ę ‡ē­¾ć€‚", + "vscode.extension.contributes.themes.uiTheme": "ē”ØäŗŽå®šä¹‰ē¼–č¾‘å™Øå‘Øå›“é¢œč‰²ēš„åŸŗęœ¬äø»é¢˜: \"vs\" ę˜Æęµ…č‰²äø»é¢˜ļ¼Œ\"vs-dark\" ę˜Æę·±č‰²äø»é¢˜ć€‚\"hc-black\" ę˜Æę·±č‰²é«˜åÆ¹ęÆ”åŗ¦äø»é¢˜ć€‚", + "vscode.extension.contributes.themes.path": "tmTheme ę–‡ä»¶ēš„č·Æå¾„ć€‚čÆ„č·Æå¾„ē›øåÆ¹äŗŽę‰©å±•ę–‡ä»¶å¤¹ļ¼Œé€šåøøäøŗ \"./themes/themeFile.tmTheme\"怂", + "reqarray": "ę‰©å±•ē‚¹ā€œ{0}ā€åæ…é”»ę˜Æäø€äøŖę•°ē»„ć€‚", + "reqpath": "ā€œcontributes.{0}.pathā€äø­åŗ”äøŗå­—ē¬¦äø²ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.1": "ā€œcontributes.{0}.pathā€({1})åŗ”åŒ…å«åœØę‰©å±•ēš„ę–‡ä»¶å¤¹({2})å†…ć€‚čæ™åÆčƒ½ä¼šä½æę‰©å±•äøåÆē§»ę¤ć€‚" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..0ccb5d7ff4d --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "åˆ†ęžę–‡ä»¶å›¾ę ‡ę–‡ä»¶ę—¶å‡ŗēŽ°é—®é¢˜: {0}" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..239f4582a9f --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "ęä¾›ę–‡ä»¶å›¾ę ‡äø»é¢˜ć€‚", + "vscode.extension.contributes.iconThemes.id": "ē”Øęˆ·č®¾ē½®äø­ä½æē”Øēš„å›¾ę ‡äø»é¢˜ēš„ ID怂", + "vscode.extension.contributes.iconThemes.label": "UI äø­ę˜¾ē¤ŗēš„å›¾ę ‡äø»é¢˜ēš„ę ‡ē­¾ć€‚", + "vscode.extension.contributes.iconThemes.path": "å›¾ę ‡äø»é¢˜å®šä¹‰ę–‡ä»¶ēš„č·Æå¾„ć€‚čÆ„č·Æå¾„ē›øåÆ¹äŗŽę‰©å±•ę–‡ä»¶å¤¹ļ¼Œé€šåøøę˜Æ \"./icons/awesome-icon-theme.json\"怂", + "reqarray": "ę‰©å±•ē‚¹ā€œ{0}ā€åæ…é”»ę˜Æäø€äøŖę•°ē»„ć€‚", + "reqpath": "ā€œcontributes.{0}.pathā€äø­åŗ”äøŗå­—ē¬¦äø²ć€‚ęä¾›ēš„å€¼: {1}", + "reqid": "contributes.{0}.id\" äø­ēš„é¢„ęœŸå­—ē¬¦äø²ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.1": "ā€œcontributes.{0}.pathā€({1})åŗ”åŒ…å«åœØę‰©å±•ēš„ę–‡ä»¶å¤¹({2})å†…ć€‚čæ™åÆčƒ½ä¼šä½æę‰©å±•äøåÆē§»ę¤ć€‚" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index ef537ea8255..ebff4844aaf 100644 --- a/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/chs/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,30 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "ē”Øęˆ·č®¾ē½®äø­ä½æē”Øēš„å›¾ę ‡äø»é¢˜ēš„ ID怂", - "vscode.extension.contributes.themes.label": "显示在 UI äø­ēš„é¢œč‰²äø»é¢˜ę ‡ē­¾ć€‚", - "vscode.extension.contributes.themes.uiTheme": "ē”ØäŗŽå®šä¹‰ē¼–č¾‘å™Øå‘Øå›“é¢œč‰²ēš„åŸŗęœ¬äø»é¢˜: \"vs\" ę˜Æęµ…č‰²äø»é¢˜ļ¼Œ\"vs-dark\" ę˜Æę·±č‰²äø»é¢˜ć€‚\"hc-black\" ę˜Æę·±č‰²é«˜åÆ¹ęÆ”åŗ¦äø»é¢˜ć€‚", - "vscode.extension.contributes.themes.path": "tmTheme ę–‡ä»¶ēš„č·Æå¾„ć€‚čÆ„č·Æå¾„ē›øåÆ¹äŗŽę‰©å±•ę–‡ä»¶å¤¹ļ¼Œé€šåøøäøŗ \"./themes/themeFile.tmTheme\"怂", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ē”Øęˆ·č®¾ē½®äø­ä½æē”Øēš„å›¾ę ‡äø»é¢˜ēš„ ID怂", - "vscode.extension.contributes.iconThemes.label": "UI äø­ę˜¾ē¤ŗēš„å›¾ę ‡äø»é¢˜ēš„ę ‡ē­¾ć€‚", - "vscode.extension.contributes.iconThemes.path": "å›¾ę ‡äø»é¢˜å®šä¹‰ę–‡ä»¶ēš„č·Æå¾„ć€‚čÆ„č·Æå¾„ē›øåÆ¹äŗŽę‰©å±•ę–‡ä»¶å¤¹ļ¼Œé€šåøøę˜Æ \"./icons/awesome-icon-theme.json\"怂", "migration.completed": "å·²å‘ē”Øęˆ·č®¾ē½®ę·»åŠ äŗ†ę–°ēš„äø»é¢˜č®¾ē½®ć€‚{0} äø­åÆå¤‡ä»½ć€‚", "error.cannotloadtheme": "ę— ę³•åŠ č½½ {0}: {1}", - "reqarray": "ę‰©å±•ē‚¹ā€œ{0}ā€åæ…é”»ę˜Æäø€äøŖę•°ē»„ć€‚", - "reqpath": "ā€œcontributes.{0}.pathā€äø­åŗ”äøŗå­—ē¬¦äø²ć€‚ęä¾›ēš„å€¼: {1}", - "invalid.path.1": "ā€œcontributes.{0}.pathā€({1})åŗ”åŒ…å«åœØę‰©å±•ēš„ę–‡ä»¶å¤¹({2})å†…ć€‚čæ™åÆčƒ½ä¼šä½æę‰©å±•äøåÆē§»ę¤ć€‚", - "reqid": "ā€œcontributes.{0}.idā€äø­åŗ”äøŗå­—ē¬¦äø²ć€‚ęä¾›ēš„å€¼: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "ęŒ‡å®šå·„ä½œå°äø­ä½æē”Øēš„é¢œč‰²äø»é¢˜ć€‚", "colorThemeError": "äø»é¢˜ęœŖēŸ„ęˆ–ęœŖå®‰č£…ć€‚", "iconTheme": "ęŒ‡å®šåœØå·„ä½œå°äø­ä½æē”Øēš„å›¾ę ‡äø»é¢˜ļ¼Œęˆ–ęŒ‡å®š \"null\" ä»„äøę˜¾ē¤ŗä»»ä½•ę–‡ä»¶å›¾ę ‡ć€‚", - "noIconThemeDesc": "No file icons", + "noIconThemeDesc": "无文件图标", "iconThemeError": "ę–‡ä»¶å›¾ę ‡äø»é¢˜ęœŖēŸ„ęˆ–ęœŖå®‰č£…ć€‚", "workbenchColors": "č¦†ē›–å½“å‰ę‰€é€‰é¢œč‰²äø»é¢˜ēš„é¢œč‰²ć€‚", - "workbenchColors.deprecated": "čÆ„č®¾ē½®äøå†ę˜Æå®žéŖŒę€§č®¾ē½®ļ¼Œå¹¶å·²é‡å‘½åäøŗā€œworkbench.colorCustomizationsā€", - "workbenchColors.deprecatedDescription": "ę”¹ē”Øā€œworkbench.colorCustomizationsā€", - "editorColors": "č¦†ē›–å½“å‰ę‰€é€‰é¢œč‰²äø»é¢˜äø­ēš„ē¼–č¾‘å™Øé¢œč‰²å’Œå­—ä½“ę ·å¼ć€‚" + "editorColors": "č¦†ē›–å½“å‰ę‰€é€‰é¢œč‰²äø»é¢˜äø­ēš„ē¼–č¾‘å™Øé¢œč‰²å’Œå­—ä½“ę ·å¼ć€‚", + "editorColors.comments": "č®¾ē½®ę³Øé‡Šēš„é¢œč‰²å’Œę ·å¼", + "editorColors.strings": "č®¾ē½®å­—ē¬¦äø²ę–‡ęœ¬ēš„é¢œč‰²å’Œę ·å¼", + "editorColors.keywords": "č®¾ē½®å…³é”®å­—ēš„é¢œč‰²å’Œę ·å¼ć€‚", + "editorColors.numbers": "č®¾ē½®ę•°å­—ēš„é¢œč‰²å’Œę ·å¼ć€‚", + "editorColors.types": "č®¾ē½®ē±»åž‹å®šä¹‰äøŽå¼•ē”Øēš„é¢œč‰²å’Œę ·å¼ć€‚", + "editorColors.functions": "č®¾ē½®å‡½ę•°å®šä¹‰äøŽå¼•ē”Øēš„é¢œč‰²å’Œę ·å¼ć€‚", + "editorColors.variables": "č®¾ē½®å˜é‡å®šä¹‰å’Œå¼•ē”Øēš„é¢œč‰²å’Œę ·å¼ć€‚", + "editorColors.textMateRules": "使用 TextMate äø»é¢˜č§„åˆ™č®¾ē½®é¢œč‰²å’Œę ·å¼(高级)怂" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/chs/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..11ecec6e1ac --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "ę— ę³•å†™å…„å·„ä½œåŒŗé…ē½®ę–‡ä»¶ć€‚čÆ·ę‰“å¼€ę–‡ä»¶ä»„ę›“ę­£é”™čÆÆęˆ–č­¦å‘Šļ¼Œē„¶åŽé‡čÆ•ć€‚", + "errorWorkspaceConfigurationFileDirty": "ę–‡ä»¶å·²å˜ę›“ļ¼Œå› ę­¤ę— ę³•å†™å…„å·„ä½œåŒŗé…ē½®ę–‡ä»¶ć€‚čÆ·å…ˆäæå­˜ę­¤ę–‡ä»¶ļ¼Œē„¶åŽé‡čÆ•ć€‚", + "openWorkspaceConfigurationFile": "ę‰“å¼€å·„ä½œåŒŗé…ē½®ę–‡ä»¶", + "close": "关闭", + "enterWorkspace.close": "关闭", + "enterWorkspace.dontShowAgain": "äøå†ę˜¾ē¤ŗ", + "enterWorkspace.moreInfo": "详细俔息", + "enterWorkspace.prompt": "äŗ†č§£ęœ‰å…³åœØ VS Code äø­ä½æē”Øå¤šäøŖę–‡ä»¶å¤¹ēš„čÆ¦ē»†äæ”ęÆć€‚" +} \ No newline at end of file diff --git a/i18n/cht/extensions/azure-account/out/azure-account.i18n.json b/i18n/cht/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..fbb65831a11 --- /dev/null +++ b/i18n/cht/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "č¤‡č£½å’Œę‰“é–‹", + "azure-account.close": "關閉", + "azure-account.login": "登兄", + "azure-account.loginFirst": "ęœŖē™»å…„ļ¼Œč«‹å…ˆē™»å…„ć€‚", + "azure-account.userCodeFailed": "å–å¾—ä½æē”Øč€…ä»£ē¢¼å¤±ę•—", + "azure-account.tokenFailed": "å–å¾—ę¬Šę–čˆ‡č£ē½®ä»£ē¢¼", + "azure-account.tokenFromRefreshTokenFailed": "å–å¾—ę¬Šę–čˆ‡é‡ę–°ę•“ē†ę¬Šę–" +} \ No newline at end of file diff --git a/i18n/cht/extensions/azure-account/out/extension.i18n.json b/i18n/cht/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..55e65eed602 --- /dev/null +++ b/i18n/cht/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: ę­£åœØē™»å…„...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 54a0b2aaf23..e86dc2dd29a 100644 --- a/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/cht/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "例如 myFile.txt", - "activeEditorMedium": "例如 myFolder/myFile.txt", - "activeEditorLong": "例如 /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "例如 myFolder1, , myFolder2, myFolder3", - "rootPath": "例如 /Users/Development/myProject", - "folderName": "例如 myFolder", - "folderPath": "例如 /Users/Development/myFolder", + "activeEditorShort": "ęŖ”ę”ˆåēØ±(ä¾‹å¦‚ļ¼šmyFile.txt)", + "activeEditorMedium": "ęŖ”ę”ˆē›øå°ę–¼å·„ä½œå€č³‡ę–™å¤¾ēš„ē›øå°č·Æå¾‘(ä¾‹å¦‚ļ¼šmyFolder/myFile.txt)", + "activeEditorLong": "ęŖ”ę”ˆå®Œę•“č·Æå¾‘ (例如 /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "å·„ä½œå€åēØ± (例如 myFolder or myWorkspace)", + "rootPath": "å·„ä½œå€ęŖ”ę”ˆč·Æå¾‘ (例如 /Users/Development/myWorkspace)", + "folderName": "åŒ…å«åœØå·„ä½œå€å…§ēš„ęŖ”ę”ˆåēØ± (例如 myFolder)", + "folderPath": "åŒ…å«åœØå·„ä½œå€å…§ēš„ęŖ”ę”ˆč·Æå¾‘ (例如 /Users/Development/myFolder)", "appName": "例如 VS Code", "dirty": "č‹„ä½æē”Øäø­ēš„ē·Øč¼Æå™Øå·²č®Šę›“ļ¼Œå³ē‚ŗå·²č®Šę›“ēš„ęŒ‡ē¤ŗå€", "separator": "ę¢ä»¶å¼åˆ†éš”ē¬¦č™Ÿ (' - ')ļ¼ŒåŖęœƒåœØå‰å¾Œē‚ŗå…·ęœ‰å€¼ēš„č®Šę•øę™‚é”Æē¤ŗ", diff --git a/i18n/cht/extensions/css/package.i18n.json b/i18n/cht/extensions/css/package.i18n.json index 4021c097143..b346ac6c6b8 100644 --- a/i18n/cht/extensions/css/package.i18n.json +++ b/i18n/cht/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "åƒę•øę•øē›®ē„”ę•ˆ", "css.lint.boxModel.desc": "ä½æē”Øå”«č£œęˆ–ę”†ē·šę™‚äøč¦ä½æē”ØåÆ¬åŗ¦ęˆ–é«˜åŗ¦ć€‚", "css.lint.compatibleVendorPrefixes.desc": "åœØä½æē”Øå» å•†å°ˆå±¬ēš„å‰ē½®č©žę™‚ļ¼Œč«‹ē¢ŗå®šä¹ŸåŒ…ę‹¬å…¶ä»–ę‰€ęœ‰ēš„å» å•†ē‰¹å®šå±¬ę€§ć€‚", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "ęœŖēŸ„ēš„å» å•†ē‰¹å®šå±¬ę€§ć€‚", "css.lint.vendorPrefix.desc": "åœØä½æē”Øå» å•†å°ˆå±¬ēš„å‰ē½®č©žę™‚ļ¼Œä¹ŸåŒ…ę‹¬ęØ™ęŗ–å±¬ę€§ć€‚", "css.lint.zeroUnits.desc": "é›¶äøéœ€č¦ä»»ä½•å–®ä½", + "css.trace.server.desc": "追蹤 VS Code 與 CSS čŖžčØ€ä¼ŗęœå™Øä¹‹é–“ēš„é€ščØŠć€‚", + "css.validate.title": "ęŽ§åˆ¶ CSS é©—č­‰čˆ‡å•é”Œåš“é‡ę€§ć€‚", "css.validate.desc": "å•Ÿē”Øęˆ–åœē”Øę‰€ęœ‰é©—č­‰", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "åƒę•øę•øē›®ē„”ę•ˆ", "less.lint.boxModel.desc": "ä½æē”Øå”«č£œęˆ–ę”†ē·šę™‚äøč¦ä½æē”ØåÆ¬åŗ¦ęˆ–é«˜åŗ¦ć€‚", "less.lint.compatibleVendorPrefixes.desc": "åœØä½æē”Øå» å•†å°ˆå±¬ēš„å‰ē½®č©žę™‚ļ¼Œč«‹ē¢ŗå®šä¹ŸåŒ…ę‹¬å…¶ä»–ę‰€ęœ‰ēš„å» å•†ē‰¹å®šå±¬ę€§ć€‚", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "ęœŖēŸ„ēš„å» å•†ē‰¹å®šå±¬ę€§ć€‚", "less.lint.vendorPrefix.desc": "åœØä½æē”Øå» å•†å°ˆå±¬ēš„å‰ē½®č©žę™‚ļ¼Œä¹ŸåŒ…ę‹¬ęØ™ęŗ–å±¬ę€§ć€‚", "less.lint.zeroUnits.desc": "é›¶äøéœ€č¦ä»»ä½•å–®ä½", + "less.validate.title": "ęŽ§åˆ¶ LESS é©—č­‰čˆ‡å•é”Œåš“é‡ę€§ć€‚", "less.validate.desc": "å•Ÿē”Øęˆ–åœē”Øę‰€ęœ‰é©—č­‰", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "åƒę•øę•øē›®ē„”ę•ˆ", "scss.lint.boxModel.desc": "ä½æē”Øå”«č£œęˆ–ę”†ē·šę™‚äøč¦ä½æē”ØåÆ¬åŗ¦ęˆ–é«˜åŗ¦ć€‚", "scss.lint.compatibleVendorPrefixes.desc": "åœØä½æē”Øå» å•†å°ˆå±¬ēš„å‰ē½®č©žę™‚ļ¼Œč«‹ē¢ŗå®šä¹ŸåŒ…ę‹¬å…¶ä»–ę‰€ęœ‰ēš„å» å•†ē‰¹å®šå±¬ę€§ć€‚", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "ęœŖēŸ„ēš„å» å•†ē‰¹å®šå±¬ę€§ć€‚", "scss.lint.vendorPrefix.desc": "åœØä½æē”Øå» å•†å°ˆå±¬ēš„å‰ē½®č©žę™‚ļ¼Œä¹ŸåŒ…ę‹¬ęØ™ęŗ–å±¬ę€§ć€‚", "scss.lint.zeroUnits.desc": "é›¶äøéœ€č¦ä»»ä½•å–®ä½", + "scss.validate.title": "ęŽ§åˆ¶ SCSS é©—č­‰čˆ‡å•é”Œåš“é‡ę€§ć€‚", "scss.validate.desc": "å•Ÿē”Øęˆ–åœē”Øę‰€ęœ‰é©—č­‰", "less.colorDecorators.enable.desc": "å•Ÿē”Øęˆ–åœē”Øå½©č‰²č£é£¾é …ē›®", "scss.colorDecorators.enable.desc": "å•Ÿē”Øęˆ–åœē”Øå½©č‰²č£é£¾é …ē›®", - "css.colorDecorators.enable.desc": "å•Ÿē”Øęˆ–åœē”Øå½©č‰²č£é£¾é …ē›®" + "css.colorDecorators.enable.desc": "å•Ÿē”Øęˆ–åœē”Øå½©č‰²č£é£¾é …ē›®", + "css.colorDecorators.enable.deprecationMessage": "設定 `css.colorDecorators.enable` å·²ę·˜ę±°ļ¼Œę”¹ē‚ŗ `editor.colorDecorators`怂", + "scss.colorDecorators.enable.deprecationMessage": "設定 `scss.colorDecorators.enable` å·²ę·˜ę±°ļ¼Œę”¹ē‚ŗ `editor.colorDecorators`怂", + "less.colorDecorators.enable.deprecationMessage": "設定 `less.colorDecorators.enable` å·²ę·˜ę±°ļ¼Œę”¹ē‚ŗ `editor.colorDecorators`怂" } \ No newline at end of file diff --git a/i18n/cht/extensions/emmet/package.i18n.json b/i18n/cht/extensions/emmet/package.i18n.json index a35321b4655..7bc2b17300e 100644 --- a/i18n/cht/extensions/emmet/package.i18n.json +++ b/i18n/cht/extensions/emmet/package.i18n.json @@ -4,17 +4,43 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "ä½æē”Øēø®åÆ«ę›č”Œ", + "command.wrapIndividualLinesWithAbbreviation": "ä½æē”Øēø®åÆ«ę›ęÆäø€č”Œ", + "command.removeTag": "移除標籤", + "command.updateTag": "ę›“ę–°ęØ™čØ˜", + "command.matchTag": "å‰å¾€ē›øē¬¦ēš„é…å°", "command.balanceIn": "平蔔(向內)", "command.balanceOut": "平蔔(向外)", + "command.prevEditPoint": "ē§»č‡³äøŠäø€å€‹ē·Øč¼Æē«Æé»ž", + "command.nextEditPoint": "ē§»č‡³äø‹äø€å€‹ē·Øč¼Æē«Æé»ž", "command.mergeLines": "合併蔌", "command.selectPrevItem": "éøå–äøŠäø€å€‹é …ē›®", "command.selectNextItem": "éøå–äø‹äø€å€‹é …ē›®", + "command.splitJoinTag": "分割/čÆēµęØ™čØ˜", "command.toggleComment": "åˆ‡ę›čØ»č§£", "command.evaluateMathExpression": "č©•ä¼°ę•øå­øé‹ē®—å¼", + "command.updateImageSize": "ę›“ę–°å½±åƒå¤§å°", + "command.reflectCSSValue": "反射 CSS 值", "command.incrementNumberByOne": "依 1 遞增", "command.decrementNumberByOne": "依 1 éžęø›", "command.incrementNumberByOneTenth": "依 0.1 遞增", "command.decrementNumberByOneTenth": "依 0.1 éžęø›", "command.incrementNumberByTen": "依 10 遞增", - "command.decrementNumberByTen": "依 10 éžęø›" + "command.decrementNumberByTen": "依 10 éžęø›", + "emmetSyntaxProfiles": "ē‚ŗęŒ‡å®šēš„čŖžę³•å®šē¾©čØ­å®šęŖ”ļ¼Œęˆ–é€éŽē‰¹å®šč¦å‰‡ä½æē”Øč‡Ŗå·±ēš„čØ­å®šęŖ”ć€‚", + "emmetExclude": "äøę‡‰å±•é–‹ Emmet ēø®åÆ«ēš„čŖžčØ€é™£åˆ—ć€‚", + "emmetExtensionsPath": "包含 Emmet čØ­å®šęŖ”åŠēØ‹å¼ē¢¼ē‰‡ę®µēš„č³‡ę–™å¤¾č·Æå¾‘", + "emmetShowAbbreviationSuggestions": "é”Æē¤ŗå»ŗč­°åÆčƒ½ēš„ Emmet ēø®åÆ«ć€‚ä½†åœØęØ£å¼č”Øå…§ęˆ– emmet.showExpandedAbbreviation čØ­ē‚ŗć€Œę°øäøć€ę™‚ļ¼Œå‰‡äøé©ē”Øć€‚", + "emmetVariables": "在 Emmet ēØ‹å¼ē¢¼ē‰‡ę®µäø­ä½æē”Øēš„č®Šę•ø", + "emmetTriggerExpansionOnTab": "å•Ÿē”Øę™‚ļ¼ŒęŒ‰äø‹ Tab éµå³åÆå±•é–‹ Emmet 縮寫。", + "emmetPreferences": "å–œå„½čØ­å®šļ¼Œē”Øä»„äæ®ę”¹ęŸäŗ›å‹•ä½œēš„č”Œē‚ŗåŠ Emmet ēš„č§£ęžēØ‹å¼ć€‚", + "emmetPreferencesIntUnit": "ę•“ę•øå€¼ēš„é čØ­å–®ä½", + "emmetPreferencesFloatUnit": "ęµ®é»žå€¼ēš„é čØ­å–®ä½", + "emmetPreferencesCssAfter": "展開 CSS ēø®åÆ«ę™‚ļ¼Œč¦ę”¾åœØ CSS å±¬ę€§ēµå°¾ēš„ē¬¦č™Ÿ ", + "emmetPreferencesSassAfter": "在 SASS ęŖ”ę”ˆäø­å±•é–‹ CSS ēø®åÆ«ę™‚ļ¼Œč¦ę”¾åœØ CSS å±¬ę€§ēµå°¾ēš„ē¬¦č™Ÿ", + "emmetPreferencesStylusAfter": "åœØę‰‹åÆ«ē­†ęŖ”ę”ˆäø­å±•é–‹ CSS ēø®åÆ«ę™‚ļ¼Œč¦ę”¾åœØ CSS å±¬ę€§ēµå°¾ēš„ē¬¦č™Ÿ", + "emmetPreferencesCssBetween": "展開 CSS ēø®åÆ«ę™‚ļ¼Œč¦ę”¾åœØ CSS å±¬ę€§čˆ‡å€¼ä¹‹é–“ēš„ē¬¦č™Ÿ", + "emmetPreferencesSassBetween": "在 SASS ęŖ”ę”ˆäø­å±•é–‹ CSS ēø®åÆ«ę™‚ļ¼Œč¦ę”¾åœØ CSS å±¬ę€§čˆ‡å€¼ä¹‹é–“ēš„ē¬¦č™Ÿ", + "emmetPreferencesStylusBetween": "åœØę‰‹åÆ«ē­†ęŖ”ę”ˆäø­å±•é–‹ CSS ēø®åÆ«ę™‚ļ¼Œč¦ę”¾åœØ CSS å±¬ę€§čˆ‡å€¼ä¹‹é–“ēš„ē¬¦č™Ÿ", + "emmetShowSuggestionsAsSnippets": "苄為 trueļ¼Œå‰‡ Emmet å»ŗč­°ęœƒé”Æē¤ŗē‚ŗēØ‹å¼ē¢¼ē‰‡ę®µļ¼ŒåÆč®“ę‚ØåœØęÆå€‹ editor.snippetSuggestions čØ­å®šē‚ŗå…¶ęŽ’åŗć€‚" } \ No newline at end of file diff --git a/i18n/cht/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/cht/extensions/extension-editing/out/extensionLinter.i18n.json index 425005b7245..7816e127fc1 100644 --- a/i18n/cht/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/cht/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "å½±åƒåæ…é ˆä½æē”Ø HTTPS é€ščØŠå”å®šć€‚", "svgsNotValid": "SVGs äøę˜Æęœ‰ę•ˆēš„å½±åƒä¾†ęŗć€‚", "embeddedSvgsNotValid": "內嵌 SVGs äøę˜Æęœ‰ę•ˆēš„å½±åƒä¾†ęŗć€‚", - "dataUrlsNotValid": "資料 URL äøę˜Æęœ‰ę•ˆēš„å½±åƒä¾†ęŗć€‚" + "dataUrlsNotValid": "資料 URL äøę˜Æęœ‰ę•ˆēš„å½±åƒä¾†ęŗć€‚", + "relativeUrlRequiresHttpsRepository": "ē›øå°å½±åƒ URL åæ…é ˆåœØ package.json äø­ęŒ‡å®šä½æē”Ø HTTPS é€ščØŠå”å®šēš„å­˜ę”¾åŗ«ć€‚", + "relativeIconUrlRequiresHttpsRepository": "åœ–ē¤ŗåæ…é ˆåœØ package.json äø­ęŒ‡å®šä½æē”Ø HTTPS é€ščØŠå”å®šēš„å­˜ę”¾åŗ«ć€‚", + "relativeBadgeUrlRequiresHttpsRepository": "ē›øå°å¾½ē«  URL åæ…é ˆåœØ package.json äø­ęŒ‡å®šä½æē”Ø HTTPS é€ščØŠå”å®šēš„å­˜ę”¾åŗ«ć€‚" } \ No newline at end of file diff --git a/i18n/cht/extensions/git/out/commands.i18n.json b/i18n/cht/extensions/git/out/commands.i18n.json index d15c4822a77..d7d2cf33969 100644 --- a/i18n/cht/extensions/git/out/commands.i18n.json +++ b/i18n/cht/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "ę­£åœØč¤‡č£½ Git å„²å­˜åŗ«...", "openrepo": "é–‹å•Ÿå„²å­˜åŗ«", "proposeopen": "č¦é–‹å•Ÿč¤‡č£½ēš„å„²å­˜åŗ«å—Ž?", + "init repo": "åˆå§‹åŒ–å„²å­˜åŗ«", + "create repo": "åˆå§‹åŒ–å„²å­˜åŗ«", + "are you sure": "é€™ęœƒå»ŗē«‹äø€å€‹ Git å„²å­˜åŗ«åœØ '{0}'ć€‚ē¢ŗå®šč¦ē¹¼ēŗŒå—Žļ¼Ÿ", "HEAD not available": "'{0}' ēš„ HEAD ē‰ˆęœ¬ē„”ę³•ä½æē”Øć€‚", + "confirm stage files with merge conflicts": "確定要暫存 {0} å€‹ęœ‰åˆä½µč”ēŖēš„ęŖ”ę”ˆå—Ž?", + "confirm stage file with merge conflicts": "ē¢ŗå®šč¦ęš«å­˜ęœ‰åˆä½µč”ēŖēš„ {0} 嗎?", + "yes": "是", "confirm revert": "ē¢ŗå®šč¦é‚„åŽŸę‚ØåœØ {0} äø­éøå–ēš„č®Šę›“å—Ž?", "revert": "é‚„åŽŸč®Šę›“", + "discard": "ęØę£„č®Šę›“", + "confirm delete": "ę‚Øē¢ŗå®šč¦åˆŖé™¤'{0}'嗎?", + "delete file": "åˆŖé™¤ęŖ”ę”ˆ", "confirm discard": "ē¢ŗå®šč¦ęØę£„ {0} äø­ēš„č®Šę›“å—Ž?", "confirm discard multiple": "ē¢ŗå®šč¦ęØę£„ {0} ęŖ”ę”ˆäø­ēš„č®Šę›“å—Ž?", - "discard": "ęØę£„č®Šę›“", - "confirm discard all": "ē¢ŗå®šč¦ęØę£„ę‰€ęœ‰č®Šę›“å—Ž? ę­¤å‹•ä½œē„”ę³•å¾©åŽŸ!", - "discardAll": "ęØę£„ę‰€ęœ‰č®Šę›“", + "warn untracked": "é€™ęœƒåˆŖé™¤ {0} å€‹ęœŖčæ½č¹¤ēš„ęŖ”ę”ˆļ¼", + "confirm discard all single": "ē¢ŗå®šč¦ęØę£„ {0} äø­ēš„č®Šę›“å—Ž?", + "confirm discard all": "ē¢ŗå®šč¦ęØę£„åœØ {0} å€‹ęŖ”ę”ˆäø­ēš„ę‰€ęœ‰č®Šę›“å—Ž? ę­¤å‹•ä½œē„”ę³•å¾©åŽŸ! ę‚Øęœƒę°øé å¤±åŽ»ē›®å‰ēš„å·„ä½œé›†ć€‚", + "discardAll multiple": "ęØę£„1å€‹ęŖ”ę”ˆ", + "discardAll": "ęØę£„ę‰€ęœ‰ {0} ęŖ”ę”ˆ", + "confirm delete multiple": "ē¢ŗå®šč¦åˆŖé™¤ {0} å€‹ęŖ”ę”ˆå—Ž?", + "delete files": "åˆŖé™¤ęŖ”ę”ˆ", + "there are untracked files single": "äø‹åˆ—ęœŖčæ½č¹¤ęŖ”ę”ˆč‹„č¢«ęØę£„ļ¼Œå°‡ęœƒå¾žē£ē¢Ÿäø­åˆŖé™¤: {0}怂", + "there are untracked files": "꜉ {0} å€‹ęœŖčæ½č¹¤ęŖ”ę”ˆč‹„č¢«ęØę£„ļ¼Œå°‡ęœƒå¾žē£ē¢Ÿäø­åˆŖé™¤ć€‚", + "confirm discard all 2": "{0}\n\né€™é …å‹•ä½œē„”ę³•å¾©åŽŸļ¼Œę‚Øęœƒę°øä¹…å¤±åŽ»ē›®å‰ēš„å·„ä½œé›†ć€‚", + "yes discard tracked": "ęØę£„ 1 å€‹čæ½č¹¤ēš„ęŖ”ę”ˆ", + "yes discard tracked multiple": "ęØę£„ {0} å€‹čæ½č¹¤ēš„ęŖ”ę”ˆ", "no staged changes": "ę²’ęœ‰ęš«å­˜č®Šę›“é€²č”Œęäŗ¤\n\nę‚ØåøŒęœ›č‡Ŗå‹•ęš«å­˜ę‚Øę‰€ęœ‰č®Šę›“äø¦ē›“ęŽ„ęäŗ¤?", - "yes": "是", "always": "永遠", "no changes": "ę²’ęœ‰ä»»ä½•č®Šę›“č¦čŖåÆć€‚", "commit message": "čŖåÆčØŠęÆ", @@ -34,16 +51,25 @@ "delete branch": "åˆŖé™¤åˆ†ę”Æ", "select a branch to merge from": "éøę“‡č¦åˆä½µēš„åˆ†ę”Æć€‚", "merge conflicts": "åˆä½µč”ēŖć€‚ęäŗ¤å‰č«‹č§£ę±ŗč”ēŖć€‚", + "tag name": "ęØ™ē±¤åēØ±", + "provide tag name": "č«‹ęä¾›ęØ™ē±¤åēØ±", + "tag message": "訊息", + "provide tag message": "č«‹ęä¾›čØŠęÆä»„ęØ™čØ»ęØ™ē±¤", "no remotes to pull": "ę‚Øēš„å„²å­˜åŗ«ęœŖčØ­å®šč¦ęå–ēš„é ē«Æä¾†ęŗć€‚", "pick remote pull repo": "ęŒ‘éøč¦å°‡åˆ†ę”Æęå–å‡ŗēš„é ē«Æ", "no remotes to push": "ę‚Øēš„å„²å­˜åŗ«ęœŖčØ­å®šč¦ęŽØé€ēš„é ē«Æē›®ęØ™ć€‚", + "push with tags success": "å·²ęˆåŠŸä½æē”ØęØ™ē±¤ęŽØé€ć€‚", "nobranch": "č«‹ē°½å‡ŗåˆ†ę”Æä»„ęŽØé€åˆ°é ē«Æć€‚", "pick remote": "ęŒ‘éøč¦ē™¼č”Œåˆ†ę”Æ '{0}' ēš„ē›®ęØ™é ē«Æ:", "sync is unpredictable": "ę­¤å‹•ä½œęœƒå°‡čŖåÆē™¼é€č‡³ '{0}' åŠå¾žäø­ęå–čŖåÆć€‚", "ok": "確定", "never again": "ē¢ŗå®šäøč¦å†é”Æē¤ŗ", "no remotes to publish": "ę‚Øēš„å„²å­˜åŗ«ęœŖčØ­å®šč¦ē™¼č”Œēš„é ē«Æē›®ęØ™ć€‚", - "disabled": "Git å·²åœē”Øļ¼Œęˆ–åœØę­¤å·„ä½œå€äøå—ę”Æę“", + "no changes stash": "ę²’ęœ‰č®Šę›“åÆä¾›éš±č—ć€‚", + "provide stash message": "åÆéøę“‡ęä¾›éš±č—čØŠęÆ", + "stash message": "éš±č—čØŠęÆ", + "no stashes": "ę²’ęœ‰č¦éš±č—åÆä¾›é‚„åŽŸć€‚", + "pick stash to pop": "č«‹ęŒ‘éøč¦åæ«é”Æēš„éš±č—", "clean repo": "č«‹å…ˆęø…é™¤ę‚Øēš„ęœ¬åœ°å„²å­˜åŗ«å·„ä½œå€å†ē°½å‡ŗć€‚", "cant push": "ē„”ę³•å°‡åƒč€ƒęŽØé€åˆ°é ē«Æć€‚č«‹å…ˆåŸ·č”Œ [ęå–] ä»„ę•“åˆę‚Øēš„č®Šę›“ć€‚", "git error details": "Git: {0}", diff --git a/i18n/cht/extensions/git/out/model.i18n.json b/i18n/cht/extensions/git/out/model.i18n.json index 9949e5c2164..300ab110fc6 100644 --- a/i18n/cht/extensions/git/out/model.i18n.json +++ b/i18n/cht/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "開啟", - "merge changes": "åˆä½µč®Šę›“", - "staged changes": "å·²åˆ†ę®µēš„č®Šę›“", - "changes": "變ꛓ", - "ok": "確定", - "neveragain": "äøč¦å†é”Æē¤ŗ", - "huge": "ä½ę–¼ '{0}' ēš„ Git å„²å­˜åŗ«ęœ‰éŽå¤šä½æē”Øäø­ēš„č®Šę›“ļ¼ŒåŖęœ‰éƒØä»½ Git åŠŸčƒ½ęœƒč¢«å•Ÿē”Øć€‚" + "no repositories": "ę²’ęœ‰å­˜ę”¾åŗ«åÆä¾›ä½æē”Ø", + "pick repo": "č«‹éøę“‡å­˜ę”¾åŗ«" } \ No newline at end of file diff --git a/i18n/cht/extensions/git/out/repository.i18n.json b/i18n/cht/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..c07485bdb63 --- /dev/null +++ b/i18n/cht/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "開啟", + "index modified": "已修改瓢引", + "modified": "已修改", + "index added": "å·²ę–°å¢žē“¢å¼•", + "index deleted": "å·²åˆŖé™¤ē“¢å¼•", + "deleted": "å·²åˆŖé™¤", + "index renamed": "å·²é‡ę–°å‘½åē“¢å¼•", + "index copied": "已複製瓢引", + "untracked": "å·²å–ę¶ˆčæ½č¹¤", + "ignored": "已忽畄", + "both deleted": "ēš†å·²åˆŖé™¤", + "added by us": "å·²ē”±ęˆ‘å€‘ę–°å¢ž", + "deleted by them": "å·²å—åˆ°ä»–å€‘åˆŖé™¤", + "added by them": "å·²ē”±ä»–å€‘ę–°å¢ž", + "deleted by us": "å·²å—åˆ°ęˆ‘å€‘åˆŖé™¤", + "both added": "ēš†å·²ę–°å¢ž", + "both modified": "ēš†å·²äæ®ę”¹", + "commit": "čŖåÆ", + "merge changes": "åˆä½µč®Šę›“", + "staged changes": "å·²åˆ†ę®µēš„č®Šę›“", + "changes": "變ꛓ", + "ok": "確定", + "neveragain": "äøč¦å†é”Æē¤ŗ", + "huge": "ä½ę–¼ '{0}' ēš„ Git å„²å­˜åŗ«ęœ‰éŽå¤šä½æē”Øäø­ēš„č®Šę›“ļ¼ŒåŖęœ‰éƒØä»½ Git åŠŸčƒ½ęœƒč¢«å•Ÿē”Øć€‚" +} \ No newline at end of file diff --git a/i18n/cht/extensions/git/package.i18n.json b/i18n/cht/extensions/git/package.i18n.json index a1542c760c0..a07211f8575 100644 --- a/i18n/cht/extensions/git/package.i18n.json +++ b/i18n/cht/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "複製", "command.init": "åˆå§‹åŒ–å„²å­˜åŗ«", + "command.close": "é—œé–‰å­˜ę”¾åŗ«", "command.refresh": "é‡ę–°ę•“ē†", "command.openChange": "é–‹å•Ÿč®Šę›“", "command.openFile": "é–‹å•ŸęŖ”ę”ˆ", @@ -14,6 +15,8 @@ "command.stageAll": "ęš«å­˜ę‰€ęœ‰č®Šę›“", "command.stageSelectedRanges": "ęš«å­˜éøå–ēš„ēÆ„åœ", "command.revertSelectedRanges": "é‚„åŽŸéøå–ēš„ēÆ„åœ", + "command.stageChange": "ęš«å­˜č®Šę›“", + "command.revertChange": "é‚„åŽŸč®Šę›“", "command.unstage": "å–ę¶ˆęš«å­˜č®Šę›“", "command.unstageAll": "å–ę¶ˆęš«å­˜ę‰€ęœ‰č®Šę›“", "command.unstageSelectedRanges": "å–ę¶ˆęš«å­˜éøå–ēš„ēÆ„åœ", @@ -22,22 +25,29 @@ "command.commit": "Commit", "command.commitStaged": "čŖåÆęš«å­˜", "command.commitStagedSigned": "čŖåÆęš«å­˜ (已簽章)", + "command.commitStagedAmend": "čŖåÆęš«å­˜ (修改)", "command.commitAll": "å…ØéƒØčŖåÆ", "command.commitAllSigned": "å…ØéƒØčŖåÆ (已簽章)", + "command.commitAllAmend": "å…ØéƒØčŖåÆ(修改)", "command.undoCommit": "å¾©åŽŸäøŠę¬”čŖåÆ", "command.checkout": "簽出至...", "command.branch": "å»ŗē«‹åˆ†ę”Æ...", "command.deleteBranch": "åˆŖé™¤åˆ†ę”Æ...", "command.merge": "åˆä½µåˆ†ę”Æ...", + "command.createTag": "建立標籤", "command.pull": "ęå–", "command.pullRebase": "ęå– (é‡čØ‚åŸŗåŗ•)", "command.pullFrom": "從...ęå–", "command.push": "ęŽØé€", "command.pushTo": "ęŽØé€č‡³...", + "command.pushWithTags": "ä½æē”ØęØ™ē±¤ęŽØé€", "command.sync": "åŒę­„č™•ē†", "command.publish": "ē™¼č”Œåˆ†ę”Æ", "command.showOutput": "锯示 Git 輸出", "command.ignore": "å°‡ęŖ”ę”ˆę–°å¢žåˆ° .gitignore", + "command.stash": "éš±č—", + "command.stashPop": "åæ«é”Æéš±č—...", + "command.stashPopLatest": "åæ«é”ÆäøŠäø€ę¬”ēš„éš±č—", "config.enabled": "ę˜Æå¦å•Ÿē”Ø GIT", "config.path": "Git åÆåŸ·č”ŒęŖ”ēš„č·Æå¾‘", "config.autorefresh": "ę˜Æå¦å•Ÿē”Øč‡Ŗå‹•é‡ę–°ę•“ē†", @@ -49,5 +59,7 @@ "config.ignoreLegacyWarning": "ē•„éŽčˆŠēš„ Git č­¦å‘Š", "config.ignoreLimitWarning": "ē•¶å„²å­˜åŗ«äø­ęœ‰éŽå¤šč®Šę›“ę™‚ļ¼Œē•„éŽč­¦å‘Šć€‚", "config.defaultCloneDirectory": "複製 Git å„²å­˜åŗ«ēš„é čØ­ä½ē½®", - "config.enableSmartCommit": "ē„”ęš«å­˜č®Šę›“ę™‚ęäŗ¤ę‰€ęœ‰č®Šę›“ć€‚" + "config.enableSmartCommit": "ē„”ęš«å­˜č®Šę›“ę™‚ęäŗ¤ę‰€ęœ‰č®Šę›“ć€‚", + "config.enableCommitSigning": "å•Ÿē”Ø GPG čŖåÆē°½ē½²ć€‚", + "config.discardAllScope": "ęŽ§åˆ¶ `Discard all changes` å‘½ä»¤ęœƒęØę£„ēš„č®Šę›“ć€‚`all` ęœƒęØę£„ę‰€ęœ‰č®Šę›“ć€‚`tracked` åŖęœƒęØę£„čæ½č¹¤ēš„ęŖ”ę”ˆć€‚`prompt` ęœƒåœØęÆę¬”å‹•ä½œåŸ·č”Œę™‚é”Æē¤ŗęē¤ŗå°č©±ę–¹å”Šć€‚" } \ No newline at end of file diff --git a/i18n/cht/extensions/grunt/out/main.i18n.json b/i18n/cht/extensions/grunt/out/main.i18n.json index 39e6cf64ecb..d21ced5e00c 100644 --- a/i18n/cht/extensions/grunt/out/main.i18n.json +++ b/i18n/cht/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Grunt ēš„č‡Ŗå‹•åµęø¬å¤±ę•—ć€‚éŒÆčŖ¤: {0}" + "execFailed": "Grunt åœØč³‡ę–™å¤¾ {0} ēš„č‡Ŗå‹•åµęø¬å¤±ę•—ć€‚éŒÆčŖ¤: {1}" } \ No newline at end of file diff --git a/i18n/cht/extensions/gulp/out/main.i18n.json b/i18n/cht/extensions/gulp/out/main.i18n.json index 019ce972d1c..c5300fc3cd5 100644 --- a/i18n/cht/extensions/gulp/out/main.i18n.json +++ b/i18n/cht/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Gulp ēš„č‡Ŗå‹•åµęø¬å¤±ę•—ć€‚éŒÆčŖ¤: {0}" + "execFailed": "Gulp åœØč³‡ę–™å¤¾ {0} ēš„č‡Ŗå‹•åµęø¬å¤±ę•—ć€‚éŒÆčŖ¤: {1}" } \ No newline at end of file diff --git a/i18n/cht/extensions/html/package.i18n.json b/i18n/cht/extensions/html/package.i18n.json index ecac49c7559..5594c3d11ac 100644 --- a/i18n/cht/extensions/html/package.i18n.json +++ b/i18n/cht/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "å•Ÿē”Ø/åœē”Øé čØ­ HTML ę ¼å¼å™Ø (éœ€č¦é‡ę–°å•Ÿå‹•)", + "html.format.enable.desc": "å•Ÿē”Ø/åœē”Øé čØ­ HTML ę ¼å¼å™Ø", "html.format.wrapLineLength.desc": "ęÆč”Œēš„å­—å…ƒę•øäøŠé™ (0 = åœē”Ø)怂", "html.format.unformatted.desc": "äøę‡‰é‡ę–°ę ¼å¼åŒ–ēš„é€—č™Ÿåˆ†éš”ęØ™čØ˜ęø…å–®ć€‚'null' 預設為 https://www.w3.org/TR/html5/dom.html#phrasing-content äø­åˆ—å‡ŗēš„ę‰€ęœ‰ęØ™čØ˜ć€‚", "html.format.contentUnformatted.desc": "é€—é»žåˆ†éš”ēš„ęØ™čØ˜ęø…å–®ļ¼Œå…¶äø­å…§å®¹ēš„ę ¼å¼äøę‡‰é‡ę–°čØ­å®šć€‚'null' 預設為 'pre' ęØ™čØ˜ć€‚", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "čØ­å®šå…§å»ŗ HTML čŖžčØ€ę”Æę“ę˜Æå¦å»ŗč­° Angular V1 ęØ™čØ˜å’Œå±¬ę€§ć€‚", "html.suggest.ionic.desc": "čØ­å®šå…§å»ŗ HTML čŖžčØ€ę”Æę“ę˜Æå¦å»ŗč­° Ionic ęØ™čØ˜ć€å±¬ę€§å’Œå€¼ć€‚", "html.suggest.html5.desc": "čØ­å®šå…§å»ŗ HTML čŖžčØ€ę”Æę“ę˜Æå¦å»ŗč­° HTML5 ęØ™čØ˜ć€å±¬ę€§å’Œå€¼ć€‚", + "html.trace.server.desc": "追蹤 VS Code 與 HTML čŖžčØ€ä¼ŗęœå™Øä¹‹é–“ēš„é€ščØŠć€‚", "html.validate.scripts": "čØ­å®šå…§å»ŗ HTML čŖžčØ€ę”Æę“ę˜Æå¦ęœƒé©—č­‰å…§åµŒęŒ‡å®šē¢¼ć€‚", - "html.validate.styles": "čØ­å®šå…§å»ŗ HTML čŖžčØ€ę”Æę“ę˜Æå¦ęœƒé©—č­‰å…§åµŒęØ£å¼ć€‚" + "html.validate.styles": "čØ­å®šå…§å»ŗ HTML čŖžčØ€ę”Æę“ę˜Æå¦ęœƒé©—č­‰å…§åµŒęØ£å¼ć€‚", + "html.autoClosingTags": "å•Ÿē”Ø/åœē”Ø HTML ęØ™ē±¤ēš„č‡Ŗå‹•é—œé–‰åŠŸčƒ½ć€‚" } \ No newline at end of file diff --git a/i18n/cht/extensions/jake/out/main.i18n.json b/i18n/cht/extensions/jake/out/main.i18n.json index f85adc82182..4b806a251b4 100644 --- a/i18n/cht/extensions/jake/out/main.i18n.json +++ b/i18n/cht/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Jake ēš„č‡Ŗå‹•åµęø¬å¤±ę•—ć€‚éŒÆčŖ¤: {0}" + "execFailed": "Jake åœØč³‡ę–™å¤¾ {0} ēš„č‡Ŗå‹•åµęø¬å¤±ę•—ć€‚éŒÆčŖ¤: {1}" } \ No newline at end of file diff --git a/i18n/cht/extensions/json/package.i18n.json b/i18n/cht/extensions/json/package.i18n.json index 3e40bd3dd2e..999ac85b405 100644 --- a/i18n/cht/extensions/json/package.i18n.json +++ b/i18n/cht/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "ęŒ‡å®š URL ēš„ēµę§‹ęčæ°å®šē¾©ć€‚åŖé ˆęä¾›ēµę§‹ęčæ°ä»„éæå…å­˜å–ēµę§‹ęčæ° URL怂", "json.format.enable.desc": "å•Ÿē”Ø/åœē”Øé čØ­ JSON ę ¼å¼å™Ø (éœ€č¦é‡ę–°å•Ÿå‹•)", "json.tracing.desc": "追蹤 VS Code 與 JSON čŖžčØ€ä¼ŗęœå™Øä¹‹é–“ēš„é€ščØŠć€‚", - "json.colorDecorators.enable.desc": "å•Ÿē”Øęˆ–åœē”Øå½©č‰²č£é£¾é …ē›®" + "json.colorDecorators.enable.desc": "å•Ÿē”Øęˆ–åœē”Øå½©č‰²č£é£¾é …ē›®", + "json.colorDecorators.enable.deprecationMessage": "設定 `json.colorDecorators.enable` å·²ę·˜ę±°ļ¼Œå°‡ę”¹ē‚ŗ `editor.colorDecorators`怂" } \ No newline at end of file diff --git a/i18n/cht/extensions/markdown/out/extension.i18n.json b/i18n/cht/extensions/markdown/out/extension.i18n.json index f8b580fc8f0..240d5457c78 100644 --- a/i18n/cht/extensions/markdown/out/extension.i18n.json +++ b/i18n/cht/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "焔法載兄 ā€˜markdown.style' ęØ£å¼:{0}" + "onPreviewStyleLoadError": "焔法載兄 ā€˜markdown.style' ęØ£å¼:{0}", + "previewTitle": "預覽 [0]" } \ No newline at end of file diff --git a/i18n/cht/extensions/markdown/out/previewContentProvider.i18n.json b/i18n/cht/extensions/markdown/out/previewContentProvider.i18n.json index 85a64933fcc..66d00227018 100644 --- a/i18n/cht/extensions/markdown/out/previewContentProvider.i18n.json +++ b/i18n/cht/extensions/markdown/out/previewContentProvider.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.securityMessage.text": "ę­¤ę–‡ä»¶å·²åœē”ØéƒØåˆ†å…§å®¹", + "preview.securityMessage.text": "ę­¤ę–‡ä»¶äø­ēš„éƒØåˆ†å…§å®¹å·²åœē”Ø", + "preview.securityMessage.title": "Markdown é č¦½äø­å·²åœē”ØåÆčƒ½äøå®‰å…Øęˆ–äøå®‰å…Øēš„å…§å®¹ć€‚č«‹å°‡ Markdown é č¦½ēš„å®‰å…Øę€§čØ­å®šč®Šę›“ē‚ŗå…čØ±äøå®‰å…Øå…§å®¹ļ¼Œęˆ–å•Ÿē”ØęŒ‡ä»¤ē¢¼", "preview.securityMessage.label": "å…§å®¹å·²åœē”Øå®‰å…Øę€§č­¦å‘Š" } \ No newline at end of file diff --git a/i18n/cht/extensions/markdown/out/security.i18n.json b/i18n/cht/extensions/markdown/out/security.i18n.json index 9cec2a47a61..870789578bf 100644 --- a/i18n/cht/extensions/markdown/out/security.i18n.json +++ b/i18n/cht/extensions/markdown/out/security.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.currentSelection": "ē›®å‰ēš„čØ­å®š", - "preview.showPreviewSecuritySelector.insecureContentTitle": "å…čØ±é€šéŽ http 載兄內容。", - "preview.showPreviewSecuritySelector.scriptsAndAllContent": "å…čØ±åŸ·č”Œę‰€ęœ‰å…§å®¹čˆ‡ęŒ‡ä»¤ē¢¼ć€‚äøå»ŗč­°ä½æē”Øć€‚", + "strict.title": "嚓謹", + "strict.description": "åƒ…č¼‰å…„å®‰å…Øå…§å®¹", + "insecureContent.title": "å…čØ±äøå®‰å…Øēš„å…§å®¹", + "insecureContent.description": "å•Ÿē”Ø http 載兄內容", + "disable.title": "åœē”Ø", + "disable.description": "å…čØ±ę‰€ęœ‰å…§å®¹čˆ‡ęŒ‡ä»¤ē¢¼åŸ·č”Œć€‚äøå»ŗč­°", + "moreInfo.title": "č©³ē“°č³‡čØŠ", "preview.showPreviewSecuritySelector.title": "éøę“‡ę­¤å·„ä½œå€ Markdown é č¦½ēš„å®‰å…Øę€§čØ­å®š" } \ No newline at end of file diff --git a/i18n/cht/extensions/markdown/package.i18n.json b/i18n/cht/extensions/markdown/package.i18n.json index 2834fa93cb5..0a35a23533d 100644 --- a/i18n/cht/extensions/markdown/package.i18n.json +++ b/i18n/cht/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "設定在 Markdown é č¦½äø­å¦‚ä½•é”Æē¤ŗåˆ†č”Œē¬¦č™Ÿć€‚čØ­ē‚ŗ 'trure' ē‚ŗęÆå€‹ę–°č”Œå»ŗē«‹
", + "markdown.preview.linkify": "å•Ÿē”Øęˆ–åœē”ØåœØ Markdown é č¦½äø­å°‡é”žä¼¼ URL ēš„ę–‡å­—č½‰ę›ē‚ŗé€£ēµć€‚", "markdown.preview.doubleClickToSwitchToEditor.desc": "在 Markdown é č¦½äø­ęŒ‰å…©äø‹ęœƒåˆ‡ę›åˆ°ē·Øč¼Æå™Øć€‚", "markdown.preview.fontFamily.desc": "ęŽ§åˆ¶ Markdown é č¦½äø­ä½æē”Øēš„å­—åž‹å®¶ę—ć€‚", "markdown.preview.fontSize.desc": "ęŽ§åˆ¶ Markdown é č¦½äø­ä½æē”Øēš„å­—åž‹å¤§å° (ä»„åƒē“ ē‚ŗå–®ä½)怂", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "åœØäø€å“é–‹å•Ÿé č¦½", "markdown.showSource.title": "锯示來源", "markdown.styles.dec": "åÆå¾ž Markdown 預覽使用之 CSS ęØ£å¼č”Øēš„ URL ęˆ–ęœ¬ę©Ÿč·Æå¾‘ęø…å–®ć€‚ē›øå°č·Æå¾‘ę˜Æē›øå°ę–¼åœØēø½ē®”äø­é–‹å•Ÿēš„č³‡ę–™å¤¾ä¾†é€²č”Œč§£é‡‹ć€‚č‹„ę²’ęœ‰é–‹å•Ÿč³‡ę–™å¤¾ļ¼Œč·Æå¾‘å‰‡ę˜Æē›øå°ę–¼ Markdown ęŖ”ę”ˆēš„ä½ē½®ä¾†é€²č”Œč§£é‡‹ć€‚ę‰€ęœ‰ '\\' éƒ½åæ…é ˆåÆ«ęˆ '\\\\'怂", - "markdown.showPreviewSecuritySelector.title": "變ꛓ Markdown é č¦½å®‰å…Øę€§čØ­å®š", - "markdown.trace.desc": "允許 Markdown å»¶ä¼øęØ”ēµ„é€²č”ŒåµéŒÆčØ˜éŒ„ć€‚" + "markdown.showPreviewSecuritySelector.title": "č®Šę›“é č¦½ēš„å®‰å…Øę€§čØ­å®š", + "markdown.trace.desc": "允許 Markdown å»¶ä¼øęØ”ēµ„é€²č”ŒåµéŒÆčØ˜éŒ„ć€‚", + "markdown.refreshPreview.title": "é‡ę–°ę•“ē†é č¦½" } \ No newline at end of file diff --git a/i18n/cht/extensions/npm/out/main.i18n.json b/i18n/cht/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/cht/extensions/npm/out/main.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/cht/extensions/npm/package.i18n.json b/i18n/cht/extensions/npm/package.i18n.json index 74cbc6cffe4..439c8e3bb27 100644 --- a/i18n/cht/extensions/npm/package.i18n.json +++ b/i18n/cht/extensions/npm/package.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "config.npm.autoDetect": "ęŽ§åˆ¶ę˜Æå¦č‡Ŗå‹•ęŖ¢ęø¬npmč…³ęœ¬.é čØ­ē‚ŗé–‹å•Ÿ." + "config.npm.autoDetect": "ęŽ§åˆ¶ę˜Æå¦č‡Ŗå‹•ęŖ¢ęø¬npmč…³ęœ¬.é čØ­ē‚ŗé–‹å•Ÿ.", + "config.npm.runSilent": "仄 '--silent' éøé …åŸ·č”Œ npm 命令 " } \ No newline at end of file diff --git a/i18n/cht/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/cht/extensions/typescript/out/features/taskProvider.i18n.json index 8b6ad71cd4e..49c12d247cc 100644 --- a/i18n/cht/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/cht/extensions/typescript/out/features/taskProvider.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "buildTscLabel": "建置 - {0}", + "buildAndWatchTscLabel": "ē›£ēœ‹ - {0}" +} \ No newline at end of file diff --git a/i18n/cht/extensions/typescript/out/utils/api.i18n.json b/i18n/cht/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..1fed6af09c8 --- /dev/null +++ b/i18n/cht/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "ē„”ę•ˆēš„ē‰ˆęœ¬" +} \ No newline at end of file diff --git a/i18n/cht/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/cht/extensions/typescript/out/utils/versionPicker.i18n.json index 2849b6d3fb1..d88c2947fea 100644 --- a/i18n/cht/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/cht/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "使用 VSCode ēš„ē‰ˆęœ¬", + "useVSCodeVersionOption": "使用 VS Code ēš„ē‰ˆęœ¬", "useWorkspaceVersionOption": "ä½æē”Øå·„ä½œå€ē‰ˆęœ¬", "learnMore": "深兄了解", "selectTsVersion": "éøå– JavaScript 與 TypeScript åŠŸčƒ½ä½æē”Øēš„ TypeScript ē‰ˆęœ¬" diff --git a/i18n/cht/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/cht/extensions/typescript/out/utils/versionProvider.i18n.json index f883c34b144..d24a4e2a05e 100644 --- a/i18n/cht/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/cht/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "å…¶ä»–ę‡‰ē”ØēØ‹å¼å·²åˆŖé™¤äŗ† VSCode ēš„ tsserverļ¼Œä¾‹å¦‚č”Œē‚ŗäøē•¶ēš„ē—…ęÆ’åµęø¬å·„å…·ć€‚č«‹é‡ę–°å®‰č£ VS Code怂" + "couldNotLoadTsVersion": "ē„”ę³•åœØę­¤č·Æå¾‘č¼‰å…„ TypeScript ē‰ˆęœ¬", + "noBundledServerFound": "å…¶ä»–ę‡‰ē”ØēØ‹å¼å·²åˆŖé™¤äŗ† VS Code ēš„ tsserverļ¼Œä¾‹å¦‚č”Œē‚ŗäøē•¶ēš„ē—…ęÆ’åµęø¬å·„å…·ć€‚č«‹é‡ę–°å®‰č£ VS Code怂" } \ No newline at end of file diff --git a/i18n/cht/extensions/typescript/package.i18n.json b/i18n/cht/extensions/typescript/package.i18n.json index 36c016dd769..cd9c40de367 100644 --- a/i18n/cht/extensions/typescript/package.i18n.json +++ b/i18n/cht/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "ä½æē”Øå…¶åƒę•øē°½ē« å®Œęˆå‡½å¼ć€‚", "typescript.tsdk.desc": "ęŒ‡å®šč³‡ę–™å¤¾č·Æå¾‘ļ¼Œå…¶äø­åŒ…å«č¦ä½æē”Øēš„ tsserver 和 lib*.d.ts ęŖ”ę”ˆć€‚", - "typescript.disableAutomaticTypeAcquisition": "åœē”Øč‡Ŗå‹•é”žåž‹å–å¾—ć€‚éœ€č¦ TypeScript >= 2.0.6ļ¼Œäø¦éœ€č¦åœØč®Šę›“å¾Œé‡ę–°å•Ÿå‹•ć€‚", + "typescript.disableAutomaticTypeAcquisition": "åœē”Øč‡Ŗå‹•é”žåž‹å–å¾—ć€‚éœ€č¦ TypeScript >= 2.0.6怂", "typescript.tsserver.log": "允許 TS ä¼ŗęœå™ØčØ˜éŒ„åˆ°ęŖ”ę”ˆć€‚ę­¤čØ˜éŒ„åÆē”Øä¾†čØŗę–· TS ä¼ŗęœå™Øå•é”Œć€‚čØ˜éŒ„åÆčƒ½åŒ…å«ęŖ”ę”ˆč·Æå¾‘ć€åŽŸå§‹ēØ‹å¼ē¢¼åŠę‚Øå°ˆę”ˆäø­åÆčƒ½å…·ęœ‰ę•ę„Ÿę€§ēš„å…¶ä»–č³‡čØŠć€‚", "typescript.tsserver.trace": "å…čØ±å°‡čØŠęÆčæ½č¹¤å‚³é€åˆ° TS ä¼ŗęœå™Øć€‚ę­¤čæ½č¹¤åÆē”Øä¾†čØŗę–· TS ä¼ŗęœå™Øå•é”Œć€‚čæ½č¹¤åÆčƒ½åŒ…å«ęŖ”ę”ˆč·Æå¾‘ć€åŽŸå§‹ēØ‹å¼ē¢¼åŠę‚Øå°ˆę”ˆäø­åÆčƒ½å…·ęœ‰ę•ę„Ÿę€§ēš„å…¶ä»–č³‡čØŠć€‚", "typescript.validate.enable": "å•Ÿē”Ø/åœē”Ø TypeScript 驗證怂", @@ -44,7 +44,9 @@ "typescript.npm": "ęŒ‡å®šē”Øę–¼č‡Ŗå‹•é”žåž‹å–å¾—ēš„ NPM åÆåŸ·č”ŒęŖ”č·Æå¾‘ć€‚TypeScript åæ…é ˆ >= 2.3.4.", "typescript.check.npmIsInstalled": "ęŖ¢ęŸ„ę˜Æå¦å·²å®‰č£NPMē”Øä»„å–å¾—č‡Ŗå‹•é”žåž‹ę“·å–.", "javascript.nameSuggestions": "從JavaScriptęŽØč–¦č”ØęŖ”ę”ˆäø­å•Ÿē”Ø/åœē”ØåŒ…å«å”Æäø€ęŖ”å", - "typescript.tsc.autoDetect": "ęŽ§åˆ¶ tsc å·„ä½œēš„č‡Ŗå‹•åµęø¬ē‚ŗé–‹å•Ÿęˆ–é—œé–‰ć€‚", + "typescript.tsc.autoDetect": "ęŽ§åˆ¶č‡Ŗå‹•åµęø¬ tsc 任務。 'off' åœē”Øę­¤åŠŸčƒ½ć€‚ 'build' åƒ…å»ŗē«‹å–®ę¬”ē·Øč­Æä»»å‹™ć€‚ 'watch' åƒ…å»ŗē«‹ē·Øč­Æäø¦ē›£ēœ‹ä»»å‹™ć€‚ 'on' åŒę™‚å»ŗē«‹ē·Øč­ÆåŠē›£ēœ‹ä»»å‹™ć€‚é čØ­å€¼ē‚ŗ 'on'怂", "typescript.problemMatchers.tsc.label": "TypeScript 問锌", - "typescript.problemMatchers.tscWatch.label": " TypeScript 問锌 (ē›£ēœ‹ęØ”å¼)" + "typescript.problemMatchers.tscWatch.label": " TypeScript 問锌 (ē›£ēœ‹ęØ”å¼)", + "typescript.quickSuggestionsForPaths": "å•Ÿē”Ø/åœē”ØåœØč¼øå…„åŒÆå…„č·Æå¾‘é”Æē¤ŗå³ę™‚å»ŗč­°ć€‚", + "typescript.locale": "čØ­å®šå ±å‘Š TypeScript éŒÆčŖ¤ēš„čŖžē³»ć€‚éœ€č¦ TypeScript >= 2.6.0。預設值 'null' 則使用 VS Code ēš„čŖžē³»ä¾†é”Æē¤ŗ TypeScript éŒÆčŖ¤ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/code/electron-main/auth.i18n.json b/i18n/cht/src/vs/code/electron-main/auth.i18n.json index 8b6ad71cd4e..3eef4974467 100644 --- a/i18n/cht/src/vs/code/electron-main/auth.i18n.json +++ b/i18n/cht/src/vs/code/electron-main/auth.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "authRequire": "åæ…é ˆé€²č”Œ Proxy é©—č­‰ ", + "proxyauth": "Proxy {0} åæ…é ˆé€²č”Œé©—č­‰ć€‚" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/code/electron-main/menus.i18n.json b/i18n/cht/src/vs/code/electron-main/menus.i18n.json index 6448fc6cba3..080129a4e8a 100644 --- a/i18n/cht/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/cht/src/vs/code/electron-main/menus.i18n.json @@ -22,9 +22,11 @@ "miQuit": "ēµęŸ {0}", "miNewFile": "ę–°å¢žęŖ”ę”ˆ(&&N)", "miOpen": "開啟(&&O)...", + "miOpenWorkspace": "開啟巄作區(&&O)...", "miOpenFolder": "é–‹å•Ÿč³‡ę–™å¤¾(&&F)...", "miOpenFile": "é–‹å•ŸęŖ”ę”ˆ(&&O)...", "miOpenRecent": "é–‹å•Ÿęœ€čæ‘ēš„ęŖ”ę”ˆ(&&R)", + "miSaveWorkspaceAs": "å°‡å·„ä½œå€å¦å­˜ē‚ŗ(&&S)...", "miAddFolderToWorkspace": "å°‡č³‡ę–™å¤¾ę–°å¢žåˆ°å·„ä½œå€(&&A)", "miSave": "儲存(&&S)", "miSaveAs": "å¦å­˜ę–°ęŖ”(&&A)...", @@ -32,6 +34,7 @@ "miAutoSave": "č‡Ŗå‹•å„²å­˜", "miRevert": "é‚„åŽŸęŖ”ę”ˆ(&&V)", "miCloseWindow": "é—œé–‰č¦–ēŖ—(&&E)", + "miCloseWorkspace": "關閉巄作區(&&W)", "miCloseFolder": "é—œé–‰č³‡ę–™å¤¾(&&F)", "miCloseEditor": "é—œé–‰ē·Øč¼Æå™Ø(&&C)", "miExit": "ēµęŸ(&&X)", @@ -44,6 +47,7 @@ "miPreferences": "å–œå„½čØ­å®š(&&P)", "miReopenClosedEditor": "é‡ę–°é–‹å•Ÿå·²é—œé–‰ēš„ē·Øč¼Æå™Ø(&&R)", "miMore": "ę›“å¤š(&&M)...", + "miClearRecentOpen": "ęø…é™¤ęœ€čæ‘é–‹å•Ÿēš„(&&C)", "miUndo": "復原(&&U)", "miRedo": "重做(&&R)", "miCut": "剪下(&&T)", @@ -98,6 +102,7 @@ "miHideActivityBar": "éš±č—ę“»å‹•åˆ—(&&A)", "miShowActivityBar": "é”Æē¤ŗę“»å‹•åˆ—(&&A)", "miToggleWordWrap": "åˆ‡ę›č‡Ŗå‹•ę›č”Œ(&&W)", + "miToggleMinimap": "åˆ‡ę›čæ·ä½ åœ°åœ–(&M)", "miToggleRenderWhitespace": "åˆ‡ę›č½‰č­Æē©ŗē™½å­—å…ƒ(&&R)", "miToggleRenderControlCharacters": "åˆ‡ę›&&ęŽ§åˆ¶å­—å…ƒ", "miZoomIn": "放大(&&Z)", @@ -146,6 +151,10 @@ "mZoom": "縮放", "mBringToFront": "å…ØéƒØęåˆ°ęœ€äøŠå±¤", "miSwitchWindow": "åˆ‡ę›č¦–ēŖ—(&&W)", + "mShowPreviousTab": "é”Æē¤ŗäøŠäø€å€‹é ē±¤", + "mShowNextTab": "锯示下一個頁籤", + "mMoveTabToNewWindow": "移動頁籤至新視窗", + "mMergeAllWindows": "åˆä½µę‰€ęœ‰č¦–ēŖ—", "miToggleDevTools": "åˆ‡ę›é–‹ē™¼äŗŗå“”å·„å…·(&&T)", "miAccessibilityOptions": "å”åŠ©å·„å…·éøé …(&&O)", "miReportIssues": "回報問锌(&&I)", @@ -163,10 +172,11 @@ "miAbout": "é—œę–¼(&&A)", "miRunTask": "執蔌巄作(&&R)", "miBuildTask": " 執蔌建置巄作(&&B)...", + "miRunningTask": "é”Æē¤ŗåŸ·č”Œäø­ēš„å·„ä½œ(&&G)...", "miRestartTask": "é‡ę–°é–‹å§‹åŸ·č”Œå·„ä½œ(&&E)...", "miTerminateTask": "ēµ‚ę­¢å·„ä½œ(&&T)...", "miConfigureTask": "設定巄作(&&C)", - "miConfigureBuildTask": "設定預設建置巄作(&&F)", + "miConfigureBuildTask": "設定預設建置巄作(&&F)...", "accessibilityOptionsWindowTitle": "å”åŠ©å·„å…·éøé …", "miRestartToUpdate": "é‡ę–°å•Ÿå‹•ä»„ę›“ę–°...", "miCheckingForUpdates": "ę­£åœØęŸ„ēœ‹ę˜Æå¦ęœ‰ę›“ę–°...", @@ -174,5 +184,6 @@ "miDownloadingUpdate": "ę­£åœØäø‹č¼‰ę›“ę–°...", "miInstallingUpdate": "ę­£åœØå®‰č£ę›“ę–°...", "miCheckForUpdates": "ęŸ„ēœ‹ę˜Æå¦ęœ‰ę›“ę–°", + "aboutDetail": "\nē‰ˆęœ¬ {0}\nčŖåÆ {1}\nę—„ęœŸ {2}\nShell {3}\n轉譯器 {4}\nēÆ€é»ž {5}\nęž¶ę§‹ {6}", "okButton": "確定" } \ No newline at end of file diff --git a/i18n/cht/src/vs/code/electron-main/windows.i18n.json b/i18n/cht/src/vs/code/electron-main/windows.i18n.json index 6137785c587..531bddc0287 100644 --- a/i18n/cht/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/cht/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,21 @@ "ok": "確定", "pathNotExistTitle": "č·Æå¾‘äøå­˜åœØ", "pathNotExistDetail": "ē£ē¢ŸäøŠä¼¼ä¹Žå·²ę²’ęœ‰č·Æå¾‘ '{0}'怂", - "reopen": "é‡ę–°é–‹å•Ÿ", - "wait": "ē¹¼ēŗŒē­‰å€™", - "close": "關閉", "appStalled": "č¦–ēŖ—å·²ę²’ęœ‰å›žę‡‰", "appStalledDetail": "ę‚ØåÆä»„é‡ę–°é–‹å•Ÿęˆ–é—œé–‰č¦–ēŖ—ļ¼Œęˆ–ę˜Æē¹¼ēŗŒē­‰å€™ć€‚", "appCrashed": "č¦–ēŖ—å·²ęęÆ€", "appCrashedDetail": "å¾ˆęŠ±ę­‰é€ ęˆę‚Øēš„äøä¾æ! ę‚ØåÆä»„é‡ę–°é–‹å•Ÿč¦–ēŖ—ļ¼Œå¾žę‚Øé›¢é–‹ēš„åœ°ę–¹ē¹¼ēŗŒé€²č”Œć€‚", + "open": "開啟", + "openFolder": "é–‹å•Ÿč³‡ę–™å¤¾", "openFile": "é–‹å•ŸęŖ”ę”ˆ", - "openFolder": "é–‹å•Ÿč³‡ę–™å¤¾" + "workspaceOpenedMessage": "ē„”ę³•å„²å­˜å·„ä½œå€ '{0}'", + "workspaceOpenedDetail": "ę­¤å·„ä½œå€å·²åœØå…¶ä»–č¦–ēŖ—äø­é–‹å•Ÿć€‚č«‹å…ˆé—œé–‰č©²č¦–ēŖ—å†é‡č©¦äø€ę¬”ć€‚", + "openWorkspace": "開啟(&&O)...", + "openWorkspaceTitle": "開啟巄作區", + "save": "儲存(&&S)", + "doNotSave": "äøč¦å„²å­˜(&&N)", + "cancel": "å–ę¶ˆ", + "saveWorkspaceMessage": "č¦å°‡å·„ä½œå€ēµ„ę…‹å„²å­˜ē‚ŗęŖ”ę”ˆå—Ž?", + "saveWorkspaceDetail": "å¦‚ęžœę‚Øé čØˆå†ę¬”é–‹å•Ÿå·„ä½œå€ļ¼Œč«‹å„²å­˜å·„ä½œå€ć€‚", + "saveWorkspace": "儲存巄作區" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/browser/widget/diffEditorWidget.i18n.json b/i18n/cht/src/vs/editor/browser/widget/diffEditorWidget.i18n.json index 8b6ad71cd4e..3a28fce1fa6 100644 --- a/i18n/cht/src/vs/editor/browser/widget/diffEditorWidget.i18n.json +++ b/i18n/cht/src/vs/editor/browser/widget/diffEditorWidget.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "diff.tooLarge": "å› å…¶äø­äø€å€‹ęŖ”ę”ˆéŽå¤§č€Œē„”ę³•ęÆ”č¼ƒć€‚" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json index c05e2bee113..042d523ea96 100644 --- a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "ęŽ§åˆ¶č”Œé«˜ć€‚ä½æē”Ø 0 ęœƒå¾ž fontSize čØˆē®— lineHeight怂", "letterSpacing": "ęŽ§åˆ¶å­—å…ƒé–“č· (ä»„åƒē“ ē‚ŗå–®ä½)", "lineNumbers": "ęŽ§åˆ¶č”Œč™Ÿé”Æē¤ŗć€‚åÆčƒ½ēš„å€¼ęœ‰ 'on'态'off' 及 'relative'怂'relative' ęœƒå¾žē›®å‰ēš„č³‡ę–™ęŒ‡ęØ™ä½ē½®é”Æē¤ŗč”Œę•øć€‚", - "rulers": "č¦åœØå…¶äø­é”Æē¤ŗåž‚ē›“å°ŗč¦ēš„č³‡ę–™č”Œ", + "rulers": "åœØē‰¹å®šēš„ē­‰åÆ¬å­—å…ƒę•øä¹‹å¾Œč½‰č­Æåž‚ē›“å°ŗč¦ć€‚ęœ‰å¤šå€‹å°ŗč¦å°±ä½æē”Øå¤šå€‹å€¼ć€‚č‹„é™£åˆ—ē‚ŗē©ŗļ¼Œå‰‡äøē¹Ŗč£½ä»»ä½•å°ŗč¦ć€‚", "wordSeparators": "åŸ·č”Œę–‡å­—ē›øé—œå°Žč¦½ęˆ–ä½œę„­ę™‚å°‡ä½œē‚ŗę–‡å­—åˆ†éš”ē¬¦č™Ÿēš„å­—å…ƒ", "tabSize": "與 Tab ē›øē­‰ēš„ē©ŗę ¼ę•øé‡ć€‚ē•¶ `editor.detectIndentation` å·²é–‹å•Ÿę™‚ļ¼Œęœƒę ¹ę“šęŖ”ę”ˆå…§å®¹č¦†åÆ«ę­¤čØ­å®šć€‚", "tabSize.errorMessage": "åæ…é ˆę˜Æ 'number'ć€‚č«‹ę³Øę„ļ¼Œå€¼ \"auto\" 已由 `editor.detectIndentation` čØ­å®šå–ä»£ć€‚", @@ -20,8 +20,9 @@ "detectIndentation": "é–‹å•ŸęŖ”ę”ˆę™‚ļ¼Œęœƒä¾ę“šęŖ”ę”ˆå…§å®¹ä¾†åµęø¬ `editor.tabSize` 及 `editor.insertSpaces`怂", "roundedSelection": "ęŽ§åˆ¶éøå–ēÆ„åœę˜Æå¦ęœ‰åœ“č§’", "scrollBeyondLastLine": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ęœƒę²å‹•åˆ°ęœ€å¾Œäø€č”Œä¹‹å¾Œ", + "smoothScrolling": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ęœƒä½æē”Øå‹•ē•«ę²å‹•", "minimap.enabled": "ęŽ§åˆ¶ę˜Æå¦ęœƒé”Æē¤ŗčæ·ä½ åœ°åœ–", - "minimap.showSlider": "č‡Ŗå‹•éš±č—čæ·ä½ åœ°åœ–ę»‘ę”æ", + "minimap.showSlider": "ęŽ§åˆ¶ę˜Æå¦ęœƒč‡Ŗå‹•éš±č—čæ·ä½ åœ°åœ–ę»‘ę”æć€‚åÆčƒ½ēš„å€¼ē‚ŗ 'always' 與 'mouseover'", "minimap.renderCharacters": "å‘ˆē¾č”Œå…§ēš„åÆ¦éš›å­—å…ƒ (č€Œäøę˜Æå½©č‰²å€å”Š)", "minimap.maxColumn": "é™åˆ¶čæ·ä½ åœ°åœ–ēš„åÆ¬åŗ¦ļ¼Œä»„å‘ˆē¾ęœ€å¤šēš„č³‡ę–™č”Œ", "find.seedSearchStringFromSelection": "ęŽ§åˆ¶ē·Øč­Æå™Øéøå–ēÆ„åœę˜Æå¦é čØ­ē‚ŗå°‹ę‰¾å·„å…·ēš„ęœå°‹å­—äø²", @@ -46,10 +47,14 @@ "autoClosingBrackets": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ę‡‰åœØå·¦ę‹¬č™Ÿå¾Œč‡Ŗå‹•ę’å…„å³ę‹¬č™Ÿ", "formatOnType": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ę‡‰åœØč¼øå…„äø€č”Œå¾Œč‡Ŗå‹•ę ¼å¼åŒ–", "formatOnPaste": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ę‡‰č‡Ŗå‹•čØ­å®šč²¼äøŠēš„å…§å®¹ę ¼å¼ć€‚ę ¼å¼å™Øåæ…é ˆåÆä¾›ä½æē”Øļ¼Œč€Œäø”ę ¼å¼å™Øę‡‰č©²čƒ½å¤ čØ­å®šę–‡ä»¶äø­äø€å€‹ēÆ„åœēš„ę ¼å¼ć€‚", - "autoIndent": "ęŽ§åˆ¶ē•¶ä½æē”Øč€…č¼øå…„, č²¼äøŠęˆ–ē§»č”Œę™‚ļ¼Œē·Øč¼Æå™Øåæ…é ˆč‡Ŗå‹•čŖæę•“ēø®ęŽ’\nčŖžčØ€ēš„ēø®ęŽ’č¦å‰‡åæ…é ˆåÆē”Ø", + "autoIndent": "ęŽ§åˆ¶ē•¶ä½æē”Øč€…č¼øå…„, č²¼äøŠęˆ–ē§»č”Œę™‚ļ¼Œē·Øč¼Æå™Øę‡‰č‡Ŗå‹•čŖæę•“ēø®ęŽ’ć€‚čŖžčØ€ēš„ēø®ęŽ’č¦å‰‡åæ…é ˆåÆē”Ø", "suggestOnTriggerCharacters": "ęŽ§åˆ¶č¼øå…„č§øē™¼å­—å…ƒę™‚ļ¼Œę˜Æå¦ę‡‰č‡Ŗå‹•é”Æē¤ŗå»ŗč­°", "acceptSuggestionOnEnter": "ęŽ§åˆ¶é™¤äŗ† 'Tab' å¤–ļ¼Œę˜Æå¦ä¹Ÿč—‰ē”±ęŒ‰äø‹ 'Enter' ęŽ„å—å»ŗč­°ć€‚å¦‚ę­¤åÆéæå…ę··ę·†č¦ę’å…„ę–°č”Œęˆ–ęŽ„å—å»ŗč­°ć€‚čØ­å®šå€¼'smart'č”Øē¤ŗåœØę–‡å­—č®Šę›“åŒę™‚ļ¼ŒåŖé€éŽEnteręŽ„å—å»ŗč­°ć€‚", "acceptSuggestionOnCommitCharacter": "ęŽ§åˆ¶čŖåÆå­—å…ƒę˜Æå¦ę‡‰ęŽ„å—å»ŗč­°ć€‚ä¾‹å¦‚åœØ JavaScript äø­ļ¼Œåˆ†č™Ÿ (';') åÆä»„ę˜ÆęŽ„å—å»ŗč­°äø¦éµå…„č©²å­—å…ƒēš„čŖåÆå­—å…ƒć€‚", + "snippetSuggestions.top": "å°‡ēØ‹å¼ē¢¼ē‰‡ę®µå»ŗč­°é”Æē¤ŗę–¼å…¶ä»–å»ŗč­°ēš„é ‚ē«Æć€‚", + "snippetSuggestions.bottom": "å°‡ēØ‹å¼ē¢¼ē‰‡ę®µå»ŗč­°é”Æē¤ŗę–¼å…¶ä»–å»ŗč­°ēš„äø‹ę–¹ć€‚", + "snippetSuggestions.inline": "å°‡ēØ‹å¼ē¢¼ē‰‡ę®µå»ŗč­°čˆ‡å…¶ä»–å»ŗč­°äø€åŒé”Æē¤ŗć€‚", + "snippetSuggestions.none": "äøé”Æē¤ŗēØ‹å¼ē¢¼ē‰‡ę®µå»ŗč­°ć€‚", "snippetSuggestions": "ęŽ§åˆ¶ēØ‹å¼ē¢¼ē‰‡ę®µę˜Æå¦éšØå…¶ä»–å»ŗč­°é”Æē¤ŗļ¼Œä»„åŠå…¶ęŽ’åŗę–¹å¼ć€‚", "emptySelectionClipboard": "ęŽ§åˆ¶č¤‡č£½ę™‚äøéøå–ä»»ä½•é …ē›®ę˜Æå¦ęœƒč¤‡č£½ē›®å‰ēØ‹å¼č”Œć€‚", "wordBasedSuggestions": "ęŽ§åˆ¶ę˜Æå¦ę‡‰ę ¹ę“šę–‡ä»¶äø­ēš„å–®å­—čØˆē®—č‡Ŗå‹•å®Œęˆć€‚", @@ -82,6 +87,8 @@ "accessibilitySupport.off": "ē·Øč¼Æå™Øäøęœƒē‚ŗčž¢å¹•åŠ©č®€ēØ‹å¼ēš„ä½æē”Øę–¹å¼é€²č”Œęœ€ä½³åŒ–ć€‚", "accessibilitySupport": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ę‡‰ę–¼å·²ē‚ŗčž¢å¹•åŠ©č®€ēØ‹å¼ęœ€ä½³åŒ–ēš„ęØ”å¼äø­åŸ·č”Œć€‚", "links": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ę‡‰åµęø¬é€£ēµäø”č®“å®ƒåÆé»žę“Š", + "colorDecorators": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦ę‡‰č½‰č­Æå…§åµŒč‰²å½©č£é£¾é …ē›®čˆ‡č‰²å½©éøę“‡å™Øć€‚", + "codeActions": "å•Ÿē”ØēØ‹å¼å‹•ä½œē‡ˆę³”ęē¤ŗ", "sideBySide": "ęŽ§åˆ¶ Diff ē·Øč¼Æå™Øč¦äø¦ęŽ’ęˆ–å…§åµŒé”Æē¤ŗå·®ē•°", "ignoreTrimWhitespace": "ęŽ§åˆ¶ Diff ē·Øč¼Æå™Øę˜Æå¦å°‡é–‹é ­ęˆ–å°¾ē«Æē©ŗē™½å­—å…ƒēš„č®Šę›“é”Æē¤ŗē‚ŗå·®ē•°", "renderIndicators": "ęŽ§åˆ¶ Diff ē·Øč¼Æå™Øę˜Æå¦č¦ē‚ŗę–°å¢žēš„/ē§»é™¤ēš„č®Šę›“é”Æē¤ŗ +/- ęØ™čØ˜", diff --git a/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json index a64950d25e3..85ff9ee951e 100644 --- a/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/cht/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -6,8 +6,9 @@ { "lineHighlight": "ē›®å‰ęøøęØ™ä½ē½®č”Œēš„åē™½é”Æē¤ŗčƒŒę™Æč‰²å½©ć€‚", "lineHighlightBorderBox": "ē›®å‰ęøøęØ™ä½ē½®č”Œä¹‹å‘Øåœę”†ē·šēš„čƒŒę™Æč‰²å½©ć€‚", - "rangeHighlight": "åē™½é”Æē¤ŗēÆ„åœēš„čƒŒę™Æč‰²å½©ļ¼Œä¾‹å¦‚ Quick Open čˆ‡å°‹ę‰¾åŠŸčƒ½ć€‚", + "rangeHighlight": "åē™½é”Æē¤ŗēÆ„åœēš„čƒŒę™Æč‰²å½©ļ¼Œä¾‹å¦‚åæ«é€Ÿé–‹å•Ÿčˆ‡å°‹ę‰¾åŠŸčƒ½ć€‚", "caret": "ē·Øč¼Æå™ØęøøęØ™ēš„č‰²å½©ć€‚", + "editorCursorBackground": "ē·Øč¼Æå™ØęøøęØ™ēš„čƒŒę™Æč‰²å½©ć€‚å…čØ±č‡ŖčØ‚å€å”ŠęøøęØ™é‡ē–Šēš„å­—å…ƒč‰²å½©ć€‚", "editorWhitespaces": "ē·Øč¼Æå™Øäø­ē©ŗē™½å­—å…ƒēš„č‰²å½©ć€‚", "editorIndentGuides": "ē·Øč¼Æå™Øēø®ęŽ’č¼”åŠ©ē·šēš„č‰²å½©ć€‚", "editorLineNumbers": "ē·Øč¼Æå™Øč”Œč™Ÿēš„č‰²å½©ć€‚", @@ -20,5 +21,11 @@ "errorForeground": "ē·Øč¼Æå™Øå…§éŒÆčŖ¤ęē¤ŗē·šēš„å‰ę™Æč‰²å½©.", "errorBorder": "ē·Øč¼Æå™Øå…§éŒÆčŖ¤ęē¤ŗē·šēš„é‚Šę”†č‰²å½©.", "warningForeground": "ē·Øč¼Æå™Øå…§č­¦å‘Šęē¤ŗē·šēš„å‰ę™Æč‰²å½©.", - "warningBorder": "ē·Øč¼Æå™Øå…§č­¦å‘Šęē¤ŗē·šēš„é‚Šę”†č‰²å½©." + "warningBorder": "ē·Øč¼Æå™Øå…§č­¦å‘Šęē¤ŗē·šēš„é‚Šę”†č‰²å½©.", + "infoForeground": "ē·Øč¼Æå™Øå…§č³‡čØŠęē¤ŗē·šēš„å‰ę™Æč‰²å½©", + "infoBorder": "ē·Øč¼Æå™Øå…§č³‡čØŠęē¤ŗē·šēš„é‚Šę”†č‰²å½©", + "overviewRulerRangeHighlight": "ēÆ„åœé†’ē›®ęē¤ŗēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚", + "overviewRuleError": "éŒÆčŖ¤ēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚", + "overviewRuleWarning": "č­¦ē¤ŗēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚", + "overviewRuleInfo": "č³‡čØŠēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 32ac75ef725..7b79c72e500 100644 --- a/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "取代", "label.replaceAllButton": "å…ØéƒØå–ä»£", "label.toggleReplaceButton": "åˆ‡ę›å–ä»£ęØ”å¼", - "title.matchesCountLimit": "åŖęœƒå°‡å‰ 999 ē­†ēµęžœé†’ē›®ęē¤ŗļ¼Œä½†ę‰€ęœ‰å°‹ę‰¾ä½œę„­ęœƒåœØå®Œę•“ę–‡å­—äøŠåŸ·č”Œć€‚", + "title.matchesCountLimit": "åƒ…åē™½é”Æē¤ŗå‰ {0} ē­†ēµęžœļ¼Œä½†ę‰€ęœ‰å°‹ę‰¾ä½œę„­ęœƒåœØå®Œę•“ę–‡å­—äøŠåŸ·č”Œć€‚", "label.matchesLocation": "{0} / {1}", "label.noResults": "ę²’ęœ‰ēµęžœ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json index 0de30c3bd71..cbbf89b710f 100644 --- a/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,10 +10,6 @@ "nextSelectionMatchFindAction": "å°‹ę‰¾äø‹äø€å€‹éøå–é …ē›®", "previousSelectionMatchFindAction": "å°‹ę‰¾äøŠäø€å€‹éøå–é …ē›®", "startReplace": "取代", - "addSelectionToNextFindMatch": "å°‡éøå–é …ē›®åŠ å…„äø‹äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …", - "addSelectionToPreviousFindMatch": "å°‡éøå–é …ē›®åŠ å…„å‰äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …äø­", - "moveSelectionToNextFindMatch": "å°‡ęœ€å¾Œäø€å€‹éøę“‡é …ē›®ē§»č‡³äø‹äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …", - "moveSelectionToPreviousFindMatch": "å°‡ęœ€å¾Œäø€å€‹éøę“‡é …ē›®ē§»č‡³å‰äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …", - "selectAllOccurrencesOfFindMatch": "éøå–ę‰€ęœ‰ę‰¾åˆ°ēš„ē›øē¬¦é …ē›®", - "changeAll.label": "č®Šę›“ę‰€ęœ‰ē™¼ē”Ÿę¬”ę•ø" + "showNextFindTermAction": "é”Æē¤ŗäø‹äø€å€‹å°‹ę‰¾å­—č©ž", + "showPreviousFindTermAction": "é”Æē¤ŗäøŠäø€å€‹å°‹ę‰¾å­—č©ž" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/cht/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 5c9e753d706..84321c58d5f 100644 --- a/i18n/cht/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "在蔌 {1} 編輯了 {0} é …ę ¼å¼", "hint1n": "在蔌 {0} čˆ‡č”Œ {1} 之間編輯了 1 é …ę ¼å¼", "hintnn": "在蔌 {1} čˆ‡č”Œ {2} 之間編輯了 {0} é …ę ¼å¼", + "no.provider": "ęŠ±ę­‰ļ¼Œå°šē„”å®‰č£é©ē”Øę–¼ '{0}' ęŖ”ę”ˆēš„ę ¼å¼å™Ø", "formatDocument.label": "å°‡ę–‡ä»¶ę ¼å¼åŒ–", "formatSelection.label": "å°‡éøå–é …ē›®ę ¼å¼åŒ–" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/cht/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 292795a8acd..9fbf329131b 100644 --- a/i18n/cht/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "ē§»č‡³äøŠäø€å€‹éŒÆčŖ¤ęˆ–č­¦å‘Š", "editorMarkerNavigationError": "ē·Øč¼Æå™ØęØ™čØ˜å°Žč¦½å°å·„å…·éŒÆčŖ¤ēš„č‰²å½©ć€‚", "editorMarkerNavigationWarning": "ē·Øč¼Æå™ØęØ™čØ˜å°Žč¦½å°å·„å…·č­¦å‘Šēš„č‰²å½©ć€‚", + "editorMarkerNavigationInfo": "ē·Øč¼Æå™ØęØ™čØ˜å°Žč¦½å°å·„å…·č³‡čØŠēš„č‰²å½©", "editorMarkerNavigationBackground": "ē·Øč¼Æå™ØęØ™čØ˜å°Žč¦½å°å·„å…·ēš„čƒŒę™Æć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/links/browser/links.i18n.json b/i18n/cht/src/vs/editor/contrib/links/browser/links.i18n.json index 6f5daa0aa3c..5b2914f9c87 100644 --- a/i18n/cht/src/vs/editor/contrib/links/browser/links.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/links/browser/links.i18n.json @@ -6,7 +6,10 @@ { "links.navigate.mac": "ęŒ‰ä½ Cmd äø¦ęŒ‰äø€äø‹ęŒ‰éµä»„čæ½č¹¤é€£ēµ", "links.navigate": "ęŒ‰ä½ Ctrl äø¦ęŒ‰äø€äø‹ę»‘é¼ ęŒ‰éˆ•åÆé€£å…„é€£ēµ", + "links.command.mac": "ęŒ‰ä½ Cmd äø¦ęŒ‰äø€äø‹ę»‘é¼ ä»„åŸ·č”Œå‘½ä»¤", + "links.command": "ęŒ‰ä½ Ctrl äø¦ęŒ‰äø€äø‹ę»‘é¼ ä»„åŸ·č”Œå‘½ä»¤", "links.navigate.al": "ęŒ‰ä½Altäø¦é»žę“Šä»„čæ½č¹¤é€£ēµ", + "links.command.al": "ęŒ‰ä½ Alt äø¦ęŒ‰äø€äø‹ę»‘é¼ ä»„åŸ·č”Œå‘½ä»¤", "invalid.url": "ęŠ±ę­‰ļ¼Œå› ē‚ŗę­¤é€£ēµēš„čŖžå¼äøę­£ē¢ŗļ¼Œę‰€ä»„ē„”ę³•åŠ ä»„é–‹å•Ÿ: {0}", "missing.url": "ęŠ±ę­‰ļ¼Œå› ē‚ŗę­¤é€£ēµéŗå¤±ē›®ęØ™ļ¼Œę‰€ä»„ē„”ę³•åŠ ä»„é–‹å•Ÿć€‚", "label": "é–‹å•Ÿé€£ēµ" diff --git a/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 722b3100d2e..381e4cfcb4c 100644 --- a/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "åœØäøŠę–¹åŠ å…„ęøøęØ™", "mutlicursor.insertBelow": "åœØäø‹ę–¹åŠ å…„ęøøęØ™", - "mutlicursor.insertAtEndOfEachLineSelected": "åœØč”Œå°¾ę–°å¢žęøøęØ™" + "mutlicursor.insertAtEndOfEachLineSelected": "åœØč”Œå°¾ę–°å¢žęøøęØ™", + "addSelectionToNextFindMatch": "å°‡éøå–é …ē›®åŠ å…„äø‹äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …", + "addSelectionToPreviousFindMatch": "å°‡éøå–é …ē›®åŠ å…„å‰äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …äø­", + "moveSelectionToNextFindMatch": "å°‡ęœ€å¾Œäø€å€‹éøę“‡é …ē›®ē§»č‡³äø‹äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …", + "moveSelectionToPreviousFindMatch": "å°‡ęœ€å¾Œäø€å€‹éøę“‡é …ē›®ē§»č‡³å‰äø€å€‹ę‰¾åˆ°ēš„ē›øē¬¦é …", + "selectAllOccurrencesOfFindMatch": "éøå–ę‰€ęœ‰ę‰¾åˆ°ēš„ē›øē¬¦é …ē›®", + "changeAll.label": "č®Šę›“ę‰€ęœ‰ē™¼ē”Ÿę¬”ę•ø" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/cht/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..8b7662c4c93 --- /dev/null +++ b/i18n/cht/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "關閉" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/cht/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index f72027e45a8..97c113d82f0 100644 --- a/i18n/cht/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "č®€å–å­˜å–ęœŸé–“ (ä¾‹å¦‚č®€å–č®Šę•øę™‚) ē¬¦č™Ÿēš„čƒŒę™Æč‰²å½©ć€‚", - "wordHighlightStrong": "åÆ«å…„å­˜å–ęœŸé–“ (ä¾‹å¦‚åÆ«å…„č®Šę•øę™‚) ē¬¦č™Ÿēš„čƒŒę™Æč‰²å½©ć€‚" + "wordHighlightStrong": "åÆ«å…„å­˜å–ęœŸé–“ (ä¾‹å¦‚åÆ«å…„č®Šę•øę™‚) ē¬¦č™Ÿēš„čƒŒę™Æč‰²å½©ć€‚", + "overviewRulerWordHighlightForeground": "ē¬¦č™Ÿé†’ē›®ęē¤ŗēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚", + "overviewRulerWordHighlightStrongForeground": "åÆ«å…„ę¬Šé™ē¬¦č™Ÿé†’ē›®ęē¤ŗēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚", + "wordHighlight.next.label": "ē§»č‡³äø‹äø€å€‹åē™½ē¬¦č™Ÿ", + "wordHighlight.previous.label": "ē§»č‡³äøŠäø€å€‹åē™½ē¬¦č™Ÿ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/cht/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 8a8133f764f..3484e0af5e7 100644 --- a/i18n/cht/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/cht/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "此命令所屬群組", "vscode.extension.contributes.menus": "å°‡åŠŸčƒ½č”Øé …ē›®ęä¾›ēµ¦ē·Øč¼Æå™Ø", "menus.commandPalette": "å‘½ä»¤éøę“‡å€", + "menus.touchBar": "Touch Bar (macOS)", "menus.editorTitle": "ē·Øč¼Æå™ØęØ™é”ŒåŠŸčƒ½č”Ø", "menus.editorContext": "ē·Øč¼Æå™Øę“ä½œåŠŸčƒ½č”Ø", "menus.explorerContext": "ęŖ”ę”ˆēø½ē®”ę“ä½œåŠŸčƒ½č”Ø", "menus.editorTabContext": "ē·Øč¼Æå™Øē“¢å¼•ęØ™ē±¤ę“ä½œåŠŸčƒ½č”Ø", "menus.debugCallstackContext": "åµéŒÆå‘¼å«å †ē–Šę“ä½œåŠŸčƒ½č”Ø", "menus.scmTitle": "åŽŸå§‹ęŖ”ęŽ§åˆ¶ęØ™é”ŒåŠŸčƒ½č”Ø", + "menus.scmSourceControl": "åŽŸå§‹ęŖ”ęŽ§åˆ¶åŠŸčƒ½č”Ø", "menus.resourceGroupContext": "åŽŸå§‹ęŖ”ęŽ§åˆ¶č³‡ęŗē¾¤ēµ„ę“ä½œåŠŸčƒ½č”Ø", "menus.resourceStateContext": "åŽŸå§‹ęŖ”ęŽ§åˆ¶č³‡ęŗē¾¤ēµ„ē‹€ę…‹ę“ä½œåŠŸčƒ½č”Ø", "view.viewTitle": "é€™ęœ‰åŠ©ę–¼ęŸ„ēœ‹ęØ™é”ŒåŠŸčƒ½č”Ø", diff --git a/i18n/cht/src/vs/platform/environment/node/argv.i18n.json b/i18n/cht/src/vs/platform/environment/node/argv.i18n.json index e5703d3b951..3b2c99dd58b 100644 --- a/i18n/cht/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/cht/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "`--goto` ęØ”å¼äø­ēš„å¼•ę•øę ¼å¼ę‡‰ē‚ŗ `FILE(:LINE(:CHARACTER))`怂", - "diff": "開啟 Diff ē·Øč¼Æå™Øć€‚č¦ę±‚å‚³éžå…©å€‹ęŖ”ę”ˆč·Æå¾‘ä½œē‚ŗå¼•ę•øć€‚", - "goto": "é–‹å•Ÿä½ę–¼č”Œčˆ‡å­—å…ƒäø­č·Æå¾‘ēš„ęŖ”ę”ˆ (將 :line[:character] ę–°å¢žåˆ°č·Æå¾‘)怂", + "diff": "äŗ’ē›øęÆ”č¼ƒå…©å€‹ęŖ”ę”ˆć€‚", + "add": "å°‡č³‡ę–™å¤¾ę–°å¢žč‡³äøŠäø€å€‹ä½æē”Øäø­ēš„č¦–ēŖ—ć€‚", + "goto": "åœØč·Æå¾‘äøŠēš„ęŒ‡å®šč”Œčˆ‡å­—å…ƒä½ē½®é–‹å•ŸęŖ”ę”ˆć€‚", "locale": "č¦ä½æē”Øēš„åœ°å€čØ­å®š (例如 en-US ꈖ zh-TW)怂", "newWindow": "強制執蔌 Code ēš„ę–°åŸ·č”Œå€‹é«”ć€‚", "performance": "åœØå·²å•Ÿē”Ø 'Developer: Startup Performance' å‘½ä»¤ēš„ęƒ…ę³äø‹é–‹å§‹ć€‚", @@ -14,7 +15,7 @@ "reuseWindow": "å¼·åˆ¶åœØęœ€čæ‘ä½æē”Øēš„č¦–ēŖ—äø­é–‹å•ŸęŖ”ę”ˆęˆ–č³‡ę–™å¤¾ć€‚", "userDataDir": "ęŒ‡å®šäæē•™ä½æē”Øč€…č³‡ę–™ēš„ē›®éŒ„ļ¼Œé€™åœØä»„ę ¹ē›®éŒ„čŗ«åˆ†åŸ·č”Œę™‚ęœ‰ē”Øć€‚", "verbose": "åˆ—å°č©³ē“°č³‡čØŠč¼øå‡ŗ (蔨示 --wait)怂", - "wait": "ē­‰å€™č¦–ēŖ—åœØå‚³å›žå‰é—œé–‰ć€‚", + "wait": "ē­‰å€™ęŖ”ę”ˆåœØå‚³å›žå‰é—œé–‰ć€‚", "extensionHomePath": "čØ­å®šę““å……åŠŸčƒ½ēš„ę ¹č·Æå¾‘ć€‚", "listExtensions": "åˆ—å‡ŗå·²å®‰č£ēš„ę““å……åŠŸčƒ½ć€‚", "showVersions": "使用 --list-extension ę™‚ļ¼Œé”Æē¤ŗå®‰č£ēš„ę““å……åŠŸčƒ½ē‰ˆęœ¬ć€‚", diff --git a/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 2a73c1b3b28..91ed221b018 100644 --- a/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "ę““å……åŠŸčƒ½ē„”ę•ˆ: package.json äøę˜Æ JSON ęŖ”ę”ˆć€‚", - "restartCode": "č«‹å…ˆé‡ę–°å•Ÿå‹• Codeļ¼Œå†é‡ę–°å®‰č£ {0}怂", - "installDependeciesConfirmation": "å®‰č£ '{0}' ä¹Ÿęœƒå®‰č£å…¶ē›øä¾ę€§ć€‚č¦ē¹¼ēŗŒå—Ž?", - "install": "是", - "doNotInstall": "否", + "restartCodeLocal": "č«‹å…ˆé‡ę–°å•Ÿå‹• Codeļ¼Œå†é‡ę–°å®‰č£ {0}怂", + "restartCodeGallery": "é‡ę–°å®‰č£ä¹‹å‰ļ¼Œč«‹å…ˆé‡ę–°å•Ÿå‹• Code怂", "uninstallDependeciesConfirmation": "åŖč¦å°‡ '{0}' č§£é™¤å®‰č£ļ¼Œęˆ–č¦åŒ…å«å…¶ē›øä¾ę€§?", "uninstallOnly": "åŖęœ‰", "uninstallAll": "å…ØéƒØ", diff --git a/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 8586f1686ce..50abb35f281 100644 --- a/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "VS Code ę““å……åŠŸčƒ½ēš„å•Ÿå‹•äŗ‹ä»¶ć€‚", "vscode.extension.activationEvents.onLanguage": "ē•¶ęŒ‡å®ščŖžčØ€ęŖ”ę”ˆé–‹å•Ÿę™‚ęæ€ē™¼č©²äŗ‹ä»¶", "vscode.extension.activationEvents.onCommand": "ē•¶ęŒ‡å®šēš„å‘½ä»¤č¢«čŖæē”Øę™‚ęæ€ē™¼č©²äŗ‹ä»¶", - "vscode.extension.activationEvents.onDebug": "ē•¶ęŒ‡å®šēš„å·„ä½œåµéŒÆéšŽę®µé–‹å§‹ę™‚ęæ€ē™¼č©²äŗ‹ä»¶", + "vscode.extension.activationEvents.onDebug": "ē•¶ä½æē”Øč€…ę­£č¦é–‹å§‹åµéŒÆęˆ–ę˜ÆčØ­å®šåµéŒÆēµ„ę…‹ę™‚ęæ€ē™¼č©²äŗ‹ä»¶", "vscode.extension.activationEvents.workspaceContains": "ē•¶é–‹å•ŸęŒ‡å®šēš„ę–‡ä»¶å¤¾åŒ…å«globęØ”å¼åŒ¹é…ēš„ę–‡ä»¶ę™‚ęæ€ē™¼č©²äŗ‹ä»¶", "vscode.extension.activationEvents.onView": "ē•¶ęŒ‡å®šēš„ęŖ¢č¦–č¢«ę““å±•ę™‚ęæ€ē™¼č©²äŗ‹ä»¶", "vscode.extension.activationEvents.star": "ē•¶VS Codeå•Ÿå‹•ę™‚ęæ€ē™¼č©²äŗ‹ä»¶,ē‚ŗäŗ†ē¢ŗäæęœ€å„½ēš„ä½æē”Øč€…é«”é©—,ē•¶ę‚Øēš„ę““å……åŠŸčƒ½ę²’ęœ‰å…¶ä»–ēµ„åˆä½œę„­ę™‚,請激擻此事件.", diff --git a/i18n/cht/src/vs/platform/history/electron-main/historyMainService.i18n.json b/i18n/cht/src/vs/platform/history/electron-main/historyMainService.i18n.json index 79e27db5d9b..39b78314b96 100644 --- a/i18n/cht/src/vs/platform/history/electron-main/historyMainService.i18n.json +++ b/i18n/cht/src/vs/platform/history/electron-main/historyMainService.i18n.json @@ -7,5 +7,6 @@ "newWindow": "開新視窗", "newWindowDesc": "é–‹å•Ÿę–°č¦–ēŖ—", "recentFolders": "ęœ€čæ‘ä½æē”Øēš„å·„ä½œå€", - "folderDesc": "{0} {1}" + "folderDesc": "{0} {1}", + "codeWorkspace": "Code 巄作區" } \ No newline at end of file diff --git a/i18n/cht/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/cht/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..4c27d1b8aa4 --- /dev/null +++ b/i18n/cht/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "ęä¾›å»¶ä¼øęØ”ēµ„å®šē¾©ēš„åÆčØ­å®šä½ˆę™Æäø»é”Œč‰²å½©", + "contributes.color.id": "åÆčØ­å®šä½ˆę™Æäø»é”Œč‰²å½©ēš„č­˜åˆ„ē¢¼ ", + "contributes.color.id.format": "č­˜åˆ„ē¢¼ēš„ę ¼å¼ę‡‰ē‚ŗ aa[.bb]*", + "contributes.color.description": "åÆčØ­å®šä½ˆę™Æäø»é”Œč‰²å½©ēš„ęčæ° ", + "contributes.defaults.light": "ę·ŗč‰²ä½ˆę™Æäø»é”Œēš„é čØ­č‰²å½©ć€‚ę‡‰ē‚ŗåå…­é€²ä½ (#RRGGBB[AA]) ēš„č‰²å½©å€¼ļ¼Œęˆ–ęä¾›é čØ­ēš„åÆčØ­å®šä½ˆę™Æäø»é”Œč‰²å½©ć€‚", + "contributes.defaults.dark": "ę·±č‰²ä½ˆę™Æäø»é”Œēš„é čØ­č‰²å½©ć€‚ę‡‰ē‚ŗåå…­é€²ä½ (#RRGGBB[AA]) ēš„č‰²å½©å€¼ļ¼Œęˆ–ęä¾›é čØ­ēš„åÆčØ­å®šä½ˆę™Æäø»é”Œč‰²å½©ć€‚ ", + "contributes.defaults.highContrast": "é«˜å°ęÆ”ä½ˆę™Æäø»é”Œēš„é čØ­č‰²å½©ć€‚ę‡‰ē‚ŗåå…­é€²ä½ (#RRGGBB[AA]) ēš„č‰²å½©å€¼ļ¼Œęˆ–ęä¾›é čØ­ēš„åÆčØ­å®šä½ˆę™Æäø»é”Œč‰²å½©ć€‚", + "invalid.colorConfiguration": "'configuration.colors' åæ…é ˆę˜Æé™£åˆ—", + "invalid.default.colorType": "{0} åæ…é ˆę˜Æåå…­é€²ä½ (#RRGGBB[AA] or #RGB[A]) ēš„č‰²å½©å€¼ļ¼Œęˆ–ę˜Æęä¾›é čØ­ēš„åÆčØ­å®šä½ˆę™Æäø»é”Œč‰²å½©ä¹‹č­˜åˆ„ē¢¼ć€‚", + "invalid.id": "'configuration.colors.id' åæ…é ˆå®šē¾©äø”äøå¾—ē‚ŗē©ŗē™½", + "invalid.id.format": "'configuration.colors.id' åæ…é ˆä¾ē…§ word[.word]*", + "invalid.description": "'configuration.colors.description' åæ…é ˆå®šē¾©äø”äøå¾—ē‚ŗē©ŗē™½", + "invalid.defaults": "'configuration.colors.defaults' åæ…é ˆå®šē¾©ļ¼Œäø”åæ…é ˆåŒ…å« 'light'态'dark' 及 'highContrast'" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json index 16223f6ab7b..1ec0770a363 100644 --- a/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/cht/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "č‰²å½©ę ¼å¼ē„”ę•ˆć€‚č«‹ä½æē”Ø #RGB态#RGBA态#RRGGBB ꈖ #RRGGBBAA", "schema.colors": "å·„ä½œå°äø­ä½æē”Øēš„č‰²å½©ć€‚", "foreground": "ę•“é«”ēš„å‰ę™Æč‰²å½©ć€‚åƒ…ē•¶ęœŖč¢«ä»»ä½•å…ƒä»¶č¦†ē–Šę™‚ļ¼Œę‰ęœƒä½æē”Øę­¤č‰²å½©ć€‚", "errorForeground": "ę•“é«”éŒÆčŖ¤čØŠęÆēš„å‰ę™Æč‰²å½©ć€‚åƒ…ē•¶ęœŖč¢«ä»»ä½•å…ƒä»¶č¦†č“‹ę™‚ļ¼Œę‰ęœƒä½æē”Øę­¤č‰²å½©ć€‚", @@ -53,6 +52,9 @@ "badgeBackground": "ęØ™čØ˜ēš„čƒŒę™Æé”č‰²ć€‚ęØ™čØ˜ē‚ŗå°åž‹ēš„čØŠęÆęØ™ē±¤,ä¾‹å¦‚ęœå°‹ēµęžœēš„ę•øé‡ć€‚", "badgeForeground": "ęØ™čØ˜ēš„å‰ę™Æé”č‰²ć€‚ęØ™čØ˜ē‚ŗå°åž‹ēš„čØŠęÆęØ™ē±¤,ä¾‹å¦‚ęœå°‹ēµęžœēš„ę•øé‡ć€‚", "scrollbarShadow": "ęŒ‡å‡ŗåœØę²å‹•č©²ęŖ¢č¦–ēš„ę²č»øé™°å½±ć€‚", + "scrollbarSliderBackground": "ę²č»øę»‘ę”æēš„čƒŒę™Æé”č‰²ć€‚", + "scrollbarSliderHoverBackground": "å‹•ę…‹é”Æē¤ŗę™‚ę²č»øę»‘ę”æēš„čƒŒę™Æé”č‰²ć€‚", + "scrollbarSliderActiveBackground": "ä½æē”Øäø­ē‹€ę…‹äø‹ę²č»øę»‘ę”æēš„čƒŒę™Æé”č‰²ć€‚", "progressBarBackground": "é•·ę™‚é–“é‹č”Œé€²åŗ¦ę¢ēš„čƒŒę™Æč‰²å½©.", "editorBackground": "ē·Øč¼Æå™Øēš„čƒŒę™Æč‰²å½©ć€‚", "editorForeground": "ē·Øč¼Æå™Øēš„é čØ­å‰ę™Æč‰²å½©ć€‚", @@ -82,5 +84,7 @@ "mergeBorder": "å…§åµŒåˆä½µč”ēŖäø­ęØ™é ­åŠåˆ†éš”å™Øēš„é‚Šē•Œč‰²å½©ć€‚", "overviewRulerCurrentContentForeground": "ē›®å‰å…§åµŒåˆä½µč”ēŖēš„ę¦‚č§€å°ŗč¦å‰ę™Æć€‚", "overviewRulerIncomingContentForeground": "å‚³å…„å…§åµŒåˆä½µč”ēŖēš„ę¦‚č§€å°ŗč¦å‰ę™Æć€‚", - "overviewRulerCommonContentForeground": "å…§åµŒåˆä½µč”ēŖäø­ēš„å…±åŒäøŠéšŽę¦‚č§€å°ŗč¦å‰ę™Æć€‚" + "overviewRulerCommonContentForeground": "å…§åµŒåˆä½µč”ēŖäø­ēš„å…±åŒäøŠéšŽę¦‚č§€å°ŗč¦å‰ę™Æć€‚", + "overviewRulerFindMatchForeground": "å°‹ę‰¾ęÆ”å°ēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚", + "overviewRulerSelectionHighlightForeground": "éøå–é …ē›®é†’ē›®ęē¤ŗēš„ę¦‚č§€å°ŗč¦ęØ™čØ˜č‰²å½©ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/cht/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..95909b5153f --- /dev/null +++ b/i18n/cht/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Code 巄作區", + "untitledWorkspace": "ęœŖå‘½å (巄作區)", + "workspaceNameVerbose": "{0} (巄作區)", + "workspaceName": "{0} (巄作區)" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/cht/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..1a48cc1d694 --- /dev/null +++ b/i18n/cht/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "é …ē›®åæ…é ˆē‚ŗé™£åˆ—", + "requirestring": "屬性 '{0}' ē‚ŗå¼·åˆ¶é …ē›®äø”åæ…é ˆå±¬ę–¼ `string` 锞型", + "optstring": "屬性 `{0}` åÆä»„ēœē•„ęˆ–åæ…é ˆå±¬ę–¼ `string` 锞型", + "vscode.extension.contributes.view.id": "ęŖ¢č¦–ēš„č­˜åˆ„ē¢¼ć€‚č«‹ä½æē”Øę­¤č­˜åˆ„ē¢¼é€éŽ `vscode.window.registerTreeDataProviderForView` API ē™»éŒ„č³‡ę–™ęä¾›č€…ć€‚äø¦č—‰ē”±å°‡ `onView:${id}` äŗ‹ä»¶ē™»éŒ„č‡³ `activationEvents` ä»„č§øē™¼å•Ÿē”Øę‚Øēš„å»¶ä¼øęØ”ēµ„ć€‚", + "vscode.extension.contributes.view.name": "ä½æē”Øäŗŗę€§åŒ–é”Æē¤ŗåēØ±.", + "vscode.extension.contributes.view.when": "åæ…é ˆē‚ŗ true ä»„é”Æē¤ŗę­¤ęŖ¢č¦–ēš„ę¢ä»¶", + "vscode.extension.contributes.views": "ęä¾›ę„č¦‹ēµ¦ē·Øč¼Æč€…", + "views.explorer": "ęŖ”ę”ˆēø½ē®”ęŖ¢č¦–", + "views.debug": "åµéŒÆęŖ¢č¦–", + "locationId.invalid": "`{0}`äøę˜Æęœ‰ę•ˆēš„č­˜åˆ„ä½ē½®", + "duplicateView1": "ē„”ę³•åœØä½ē½® '{1}' ä½æē”Øē›øåŒēš„č­˜åˆ„ē¢¼ '{0}' čØ»å†Šå¤šå€‹ęŖ¢č¦–", + "duplicateView2": "č­˜åˆ„ē¢¼ē‚ŗ '{0}' ēš„ęŖ¢č¦–å·²åœØä½ē½® '{1}' čØ»å†Š" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/cht/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..99e2a181c4d --- /dev/null +++ b/i18n/cht/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "ę““å……åŠŸčƒ½ `{1}` ē„”ę³•å•Ÿå‹•ć€‚åŽŸå› : ęœŖēŸ„ēš„ē›øä¾ę€§ `{0}`怂", + "failedDep1": "ę““å……åŠŸčƒ½ `{1}` ē„”ę³•å•Ÿå‹•ć€‚åŽŸå› : ē›øä¾ę€§ `{0}` ē„”ę³•å•Ÿå‹•ć€‚", + "failedDep2": "ę““å……åŠŸčƒ½ `{0}` ē„”ę³•å•Ÿå‹•ć€‚åŽŸå› : ē›øä¾ę€§č¶…éŽ 10 å€‹å±¤ē“š (å¾ˆåÆčƒ½ę˜Æē›øä¾ę€§čæ“åœˆ)怂", + "activationError": "å•Ÿå‹•ę““å……åŠŸčƒ½ `{0}` 失敗: {1}怂" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json index db42e723deb..abe1e77c797 100644 --- a/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,14 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "é–‹å•ŸęŖ”ę”ˆ...", "openFolder": "é–‹å•Ÿč³‡ę–™å¤¾...", "openFileFolder": "開啟...", - "cancel": "å–ę¶ˆ", - "newWorkspaceFormExisting": "ę–°ēš„å·„ä½œå€å¾žē¾ęœ‰...", "addFolderToWorkspace": "å°‡č³‡ę–™å¤¾ę–°å¢žåˆ°å·„ä½œå€...", "add": "ę–°å¢ž", "addFolderToWorkspaceTitle": "å°‡č³‡ę–™å¤¾ę–°å¢žåˆ°å·„ä½œå€", + "globalRemoveFolderFromWorkspace": "å°‡č³‡ę–™å¤¾å¾žå·„ä½œå€ē§»é™¤...", "removeFolderFromWorkspace": "å°‡č³‡ę–™å¤¾å¾žå·„ä½œå€ē§»é™¤", + "openFolderSettings": "é–‹å•Ÿč³‡ę–™å¤¾čØ­å®š", "saveWorkspaceAsAction": "å¦å­˜å·„ä½œå€ē‚ŗ...", - "save": "儲存(&&S)" + "save": "儲存(&&S)", + "saveWorkspace": "儲存巄作區", + "openWorkspaceAction": "開啟巄作區...", + "openWorkspaceConfigFile": "é–‹å•Ÿå·„ä½œå€ēµ„ę…‹ęŖ”", + "openFolderAsWorkspaceInNewWindow": "åœØę–°č¦–ēŖ—äø­é–‹å•Ÿč³‡ę–™å¤¾ä½œē‚ŗå·„ä½œå€", + "workspaceFolderPickerPlaceholder": "éøå–å·„ä½œå€č³‡ę–™å¤¾" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 41c6f379e9d..28f1a55a24c 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "å¾žę“»å‹•åˆ—ē§»é™¤", - "keepInActivityBar": "äæē•™åœØę“»å‹•åˆ—", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "å¾žę“»å‹•åˆ—éš±č—", + "keepInActivityBar": "äæē•™åœØę“»å‹•åˆ—", "additionalViews": "其他檢視", "numberBadge": "{0} ({1})", "manageExtension": "箔理延伸樔組", diff --git a/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index e2c33864cd6..1ca947dd5de 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "éš±č—ę“»å‹•åˆ—", - "activityBarAriaLabel": "å³ę™‚ęŖ¢č¦–åˆ‡ę›å™Ø", "globalActions": "å…ØåŸŸå‹•ä½œ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..313c717e038 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "å³ę™‚ęŖ¢č¦–åˆ‡ę›å™Ø" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..0ab2723d455 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "其他檢視", + "numberBadge": "{0} ({1})", + "manageExtension": "箔理延伸樔組", + "titleKeybinding": "{0} ({1})", + "hide": "éš±č—", + "toggle": "åˆ‡ę›é‡˜éøēš„ęŖ¢č¦–" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 156d3f5bd02..fc25ce13ad0 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "åœØē¬¬äŗŒå€‹ē¾¤ēµ„é”Æē¤ŗē·Øč¼Æå™Ø", "groupThreePicker": "åœØē¬¬äø‰å€‹ē¾¤ēµ„é”Æē¤ŗē·Øč¼Æå™Ø", "allEditorsPicker": "é”Æē¤ŗę‰€ęœ‰é–‹å•Ÿēš„ē·Øč¼Æå™Ø", - "view": "檢視" + "view": "檢視", + "file": "ęŖ”ę”ˆ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 96160a8359a..ee6864d5c65 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "é–‹å•Ÿē¾¤ēµ„äø­äøŠäø€å€‹ē·Øč¼Æå™Ø", "navigateNext": "向前", "navigatePrevious": "向後", + "navigateLast": "ē§»č‡³ęœ€å¾Œ", "reopenClosedEditor": "é‡ę–°é–‹å•Ÿå·²é—œé–‰ēš„ē·Øč¼Æå™Ø", "clearRecentFiles": "ęø…ē†ęœ€čæ‘é–‹å•Ÿēš„", "showEditorsInFirstGroup": "åœØē¬¬äø€å€‹ē¾¤ēµ„é”Æē¤ŗē·Øč¼Æå™Ø", diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 31e2ba3cca7..e8b2ace0bcf 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "用 Tab éµē§»å‹•ē„¦é»ž", - "screenReaderDetected": "åµęø¬åˆ°čž¢å¹•åŠ©č®€ēØ‹å¼", + "screenReaderDetected": "å·²å°‡čž¢å¹•åŠ©č®€ēØ‹å¼ęœ€ä½³åŒ–", "screenReaderDetectedExtra": "č‹„ę‚Øäøę‰“ē®—ä½æē”Øčž¢å¹•åŠ©č®€ēØ‹å¼ļ¼Œč«‹å°‡čØ­å®š `editor.accessibilitySupport` č®Šę›“ē‚ŗ \"off\"怂", "disableTabMode": "åœē”Øå”åŠ©å·„å…·ęØ”å¼", "gotoLine": "ē§»č‡³č”Œ", @@ -47,5 +47,11 @@ "reopenWithEncoding": "ä»„ē·Øē¢¼é‡ę–°é–‹å•Ÿ", "guessedEncoding": "å·²å¾žå…§å®¹ēŒœęø¬", "pickEncodingForReopen": "éøå–ęŖ”ę”ˆēš„ē·Øē¢¼ä»„é‡ę–°é–‹å•ŸęŖ”ę”ˆ", - "pickEncodingForSave": "éøå–ē”Øä¾†å„²å­˜ēš„ęŖ”ę”ˆē·Øē¢¼" + "pickEncodingForSave": "éøå–ē”Øä¾†å„²å­˜ēš„ęŖ”ę”ˆē·Øē¢¼", + "screenReaderDetectedExplanation.title": "å·²å°‡čž¢å¹•åŠ©č®€ēØ‹å¼ęœ€ä½³åŒ–", + "screenReaderDetectedExplanation.question": "ę‚Øę­£ä½æē”Øčž¢å¹•åŠ©č®€ēØ‹å¼ä¾†ę“ä½œ VS Code 嗎?", + "screenReaderDetectedExplanation.answerYes": "是", + "screenReaderDetectedExplanation.answerNo": "否", + "screenReaderDetectedExplanation.body1": "已將 VS Code ęœ€ä½³åŒ–ļ¼Œē¾åœØåÆę­é…čž¢å¹•åŠ©č®€ēØ‹å¼ä½æē”Øć€‚", + "screenReaderDetectedExplanation.body2": "ęŸäŗ›ē·Øč¼Æå™ØåŠŸčƒ½ęœƒå…·ęœ‰äøåŒēš„č”Œē‚ŗ: ä¾‹å¦‚ę–‡å­—ę›č”Œć€ęŠ˜ē–Šć€č‡Ŗå‹•ę‹¬äøŠę‹¬č™Ÿē­‰ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 8debfb36393..0f7f13446d0 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "é—œé–‰é¢ęæ", "togglePanel": "åˆ‡ę›é¢ęæ", "focusPanel": "å°‡ē„¦é»žē§»č‡³é¢ęæ", diff --git a/i18n/cht/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json index 4e7c8606cb8..bed067ba4a6 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "compositePart.hideSideBarLabel": "éš±č—ęč¦ę¬„ä½", "focusSideBar": "ē€č¦½č‡³ęč¦ę¬„ä½", "viewCategory": "檢視" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index d59f4257e4e..05f1e85eb7b 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "命令 '{0}' ē›®å‰ęœŖå•Ÿē”Øļ¼Œå› ę­¤ē„”ę³•åŸ·č”Œć€‚", "manageExtension": "箔理延伸樔組" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..6894078d8f2 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} 個動作" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..d9eedec6006 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} 個動作", + "hideView": "å¾žęč¦ę¬„ä½éš±č—" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..e29734f7644 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "č­˜åˆ„ē¢¼ē‚ŗ '{0}' ēš„ęŖ¢č¦–å·²åœØä½ē½® '{1}' äø­čØ»å†Š" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..e0fd97c7bae --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "å¾žęč¦ę¬„ä½éš±č—" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/common/theme.i18n.json b/i18n/cht/src/vs/workbench/common/theme.i18n.json index 5fde1a30107..d1c20d9850d 100644 --- a/i18n/cht/src/vs/workbench/common/theme.i18n.json +++ b/i18n/cht/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "ä½æē”Øäø­ä¹‹ē“¢å¼•ęØ™ē±¤ēš„čƒŒę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", "tabInactiveBackground": "éžä½æē”Øäø­ä¹‹ē“¢å¼•ęØ™ē±¤ēš„čƒŒę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", "tabBorder": "ē”Øä»„åˆ†éš”ē“¢å¼•ęØ™ē±¤å½¼ę­¤ēš„ę”†ē·šć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", + "tabActiveBorder": "ē”Øä»„é†’ē›®ęē¤ŗä½æē”Øäø­ē“¢å¼•ęØ™ē±¤ēš„ę”†ē·šć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", + "tabActiveUnfocusedBorder": "ē”Øä»„åœØéžē„¦é»žē¾¤ēµ„äø­é†’ē›®ęē¤ŗä½æē”Øäø­ē“¢å¼•ęØ™ē±¤ēš„ę”†ē·šć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚ ", "tabActiveForeground": "ä½æē”Øäø­ēš„ē¾¤ēµ„å…§ļ¼Œä½æē”Øäø­ä¹‹ē“¢å¼•ęØ™ē±¤ēš„å‰ę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", "tabInactiveForeground": "ä½æē”Øäø­ēš„ē¾¤ēµ„å…§ļ¼Œéžä½æē”Øäø­ä¹‹ē“¢å¼•ęØ™ē±¤ēš„å‰ę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", - "tabUnfocusedActiveForeground": "éžä½æē”Øäø­ēš„ē¾¤ēµ„å…§ļ¼Œä½æē”Øäø­ä¹‹ē“¢å¼•ęØ™ē±¤ēš„å‰ę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", - "tabUnfocusedInactiveForeground": "éžä½æē”Øäø­ēš„ē¾¤ēµ„å…§ļ¼Œéžä½æē”Øäø­ä¹‹ē“¢å¼•ęØ™ē±¤ēš„å‰ę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", + "tabUnfocusedActiveForeground": "éžē„¦é»žē¾¤ēµ„äø­ēš„ä½æē”Øäø­ē“¢å¼•ęØ™ē±¤å‰ę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", + "tabUnfocusedInactiveForeground": "éžē„¦é»žē¾¤ēµ„äø­ēš„éžä½æē”Øäø­ē“¢å¼•ęØ™ē±¤å‰ę™Æč‰²å½©ć€‚ē“¢å¼•ęØ™ē±¤ę˜Æē·Øč¼Æå™ØåœØē·Øč¼Æå™Øå€åŸŸäø­ēš„å®¹å™Øć€‚åŒäø€å€‹ē·Øč¼Æå™Øē¾¤ēµ„äø­ēš„å¤šå€‹ē“¢å¼•ęØ™ē±¤åÆä»„åŒę™‚é–‹å•Ÿć€‚åÆčƒ½ęœƒęœ‰å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„ć€‚", "editorGroupBackground": "ē·Øč¼Æå™Øē¾¤ēµ„ēš„čƒŒę™Æč‰²å½©ć€‚ē·Øč¼Æå™Øē¾¤ēµ„ę˜Æē·Øč¼Æå™Øēš„å®¹å™Øć€‚ē•¶ę‹–ę›³ē·Øč¼Æå™Øē¾¤ēµ„ę™‚ęœƒé”Æē¤ŗčƒŒę™Æč‰²å½©ć€‚", "tabsContainerBackground": "ē•¶ē“¢å¼•ęØ™ē±¤å•Ÿē”Øēš„ę™‚å€™ē·Øč¼Æå™Øē¾¤ēµ„ęØ™é”Œēš„čƒŒę™Æč‰²å½©ć€‚ē·Øč¼Æå™Øē¾¤ēµ„ę˜Æē·Øč¼Æå™Øēš„å®¹å™Øć€‚", "tabsContainerBorder": "ē•¶ē“¢å¼•ęØ™ē±¤å•Ÿē”Øę™‚ļ¼Œē·Øč¼Æå™Øē¾¤ēµ„ęØ™é”Œēš„ę”†ē·šč‰²å½©ć€‚ē·Øč¼Æå™Øē¾¤ēµ„ę˜Æē·Øč¼Æå™Øēš„å®¹å™Øć€‚", @@ -18,15 +20,15 @@ "editorGroupBorder": "ē”Øä»„åˆ†éš”å¤šå€‹ē·Øč¼Æå™Øē¾¤ēµ„å½¼ę­¤ēš„č‰²å½©ć€‚ē·Øč¼Æå™Øē¾¤ēµ„ę˜Æē·Øč¼Æå™Øēš„å®¹å™Øć€‚", "editorDragAndDropBackground": "ę‹–ę‹‰ē·Øč¼Æå™Øę™‚ēš„čƒŒę™Æé”č‰²,åÆčØ­ē½®é€ę˜Žåŗ¦č®“å…§å®¹ē©æé€é”Æē¤ŗ.", "panelBackground": "é¢ęæēš„å‰ę™Æč‰²å½©ć€‚é¢ęæęœƒé”Æē¤ŗåœØē·Øč¼Æå™Øå€åŸŸēš„äø‹ę–¹ļ¼Œå…¶äø­åŒ…å«č«øå¦‚č¼øå‡ŗčˆ‡ę•“åˆå¼ēµ‚ē«Æę©Ÿē­‰ęŖ¢č¦–ć€‚", - "panelBorder": "é¢ęæé ‚ē«Æē”Øä»„åˆ†éš”ē·Øč¼Æå™Øēš„é‚Šę”†č‰²å½©ć€‚é¢ęæęœƒé”Æē¤ŗåœØē·Øč¼Æå™Øå€åŸŸēš„äø‹ę–¹ļ¼Œå…¶äø­åŒ…å«č«øå¦‚č¼øå‡ŗčˆ‡ę•“åˆå¼ēµ‚ē«Æę©Ÿē­‰ęŖ¢č¦–ć€‚", "panelActiveTitleForeground": "ä½æē”Øäø­ä¹‹é¢ęæęØ™é”Œēš„ęØ™é”Œč‰²å½©ć€‚é¢ęæęœƒé”Æē¤ŗåœØē·Øč¼Æå™Øå€åŸŸēš„äø‹ę–¹ļ¼Œå…¶äø­åŒ…å«č«øå¦‚č¼øå‡ŗčˆ‡ę•“åˆå¼ēµ‚ē«Æę©Ÿē­‰ęŖ¢č¦–ć€‚", "panelInactiveTitleForeground": "éžä½æē”Øäø­ä¹‹é¢ęæęØ™é”Œēš„ęØ™é”Œč‰²å½©ć€‚é¢ęæęœƒé”Æē¤ŗåœØē·Øč¼Æå™Øå€åŸŸēš„äø‹ę–¹ļ¼Œå…¶äø­åŒ…å«č«øå¦‚č¼øå‡ŗčˆ‡ę•“åˆå¼ēµ‚ē«Æę©Ÿē­‰ęŖ¢č¦–ć€‚", "panelActiveTitleBorder": "ä½æē”Øäø­ä¹‹é¢ęæęØ™é”Œēš„ę”†ē·šč‰²å½©ć€‚é¢ęæęœƒé”Æē¤ŗåœØē·Øč¼Æå™Øå€åŸŸēš„äø‹ę–¹ļ¼Œå…¶äø­åŒ…å«č«øå¦‚č¼øå‡ŗčˆ‡ę•“åˆå¼ēµ‚ē«Æę©Ÿē­‰ęŖ¢č¦–ć€‚", - "statusBarForeground": "ē‹€ę…‹åˆ—ēš„å‰ę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", + "statusBarForeground": "ē•¶äø€å€‹å·„ä½œå€č¢«é–‹å•Ÿę™‚ļ¼Œē‹€ę…‹åˆ—ēš„å‰ę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", "statusBarNoFolderForeground": "ē•¶ęœŖé–‹å•Ÿä»»ä½•č³‡ę–™å¤¾ę™‚ļ¼Œē‹€ę…‹åˆ—ēš„å‰ę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", - "statusBarBackground": "ęØ™ęŗ–ē‹€ę…‹åˆ—ēš„čƒŒę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", + "statusBarBackground": "ē•¶äø€å€‹å·„ä½œå€č¢«é–‹å•Ÿę™‚ļ¼Œē‹€ę…‹åˆ—ēš„čƒŒę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", "statusBarNoFolderBackground": "ē•¶ęœŖé–‹å•Ÿä»»ä½•č³‡ę–™å¤¾ę™‚ļ¼Œē‹€ę…‹åˆ—ēš„čƒŒę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", "statusBarBorder": "ē”Øä»„åˆ†éš”č³‡čØŠēœ‹ęæčˆ‡ē·Øč¼Æå™Øēš„ē‹€ę…‹åˆ—ę”†ē·šč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", + "statusBarNoFolderBorder": "ęœŖé–‹å•Ÿč³‡ę–™å¤¾ę™‚ļ¼Œē”Øä»„åˆ†éš”č³‡čØŠēœ‹ęæčˆ‡ē·Øč¼Æå™Øēš„ē‹€ę…‹åˆ—ę”†ē·šč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚ ", "statusBarItemActiveBackground": "ęŒ‰äø‹ę»‘é¼ ęŒ‰éˆ•ę™‚ļ¼Œē‹€ę…‹åˆ—é …ē›®ēš„čƒŒę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", "statusBarItemHoverBackground": "å‹•ę…‹é”Æē¤ŗę™‚ļ¼Œē‹€ę…‹åˆ—é …ē›®ēš„čƒŒę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", "statusBarProminentItemBackground": "ē‹€ę…‹åˆ—ēŖå‡ŗé …ē›®ēš„čƒŒę™Æé”č‰²ć€‚ēŖå‡ŗé …ē›®ęÆ”ē‹€ę…‹åˆ—ēš„å…¶ä»–é …ē›®ę›“é”Æēœ¼ļ¼Œē”Øę–¼č”Øē¤ŗé‡č¦ę€§ę›“é«˜ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚", @@ -41,6 +43,7 @@ "sideBarForeground": "å“ę¬„ēš„å‰ę™Æé”č‰².å“ę¬„åŒ…å«Explorerčˆ‡ęœå°‹.", "sideBarBorder": "ē”Øä»„åˆ†éš”ē·Øč¼Æå™Øēš„å“é‚Šęč¦ę¬„ä½ę”†ē·šč‰²å½©ć€‚č©²ęč¦ę¬„ä½ę˜ÆęŖ¢č¦– (例如 Explorer åŠęœå°‹) ēš„å®¹å™Øć€‚", "sideBarTitleForeground": "ęč¦ę¬„ä½ęØ™é”Œēš„å‰ę™Æč‰²å½©ć€‚ęč¦ę¬„ä½ę˜ÆęŖ¢č¦– (例如 Explorer čˆ‡ęœå°‹) ēš„å®¹å™Øć€‚", + "sideBarDragAndDropBackground": "ę‹–ę”¾ęč¦ę¬„ä½å€ę®µēš„ę„č¦‹å›žę‡‰č‰²å½©ć€‚č‰²å½©ę‡‰å…·é€ę˜Žåŗ¦ļ¼Œä»„ä¾æč®“ęč¦ę¬„ä½å€ę®µē©æé€é”Æē¤ŗć€‚ęč¦ę¬„ä½ę˜Æēø½ē®”å’Œęœå°‹ē­‰ęŖ¢č¦–ē”Øēš„å®¹å™Øć€‚", "sideBarSectionHeaderBackground": "ęč¦ę¬„ä½å€ę®µęØ™é ­ēš„čƒŒę™Æč‰²å½©ć€‚ęč¦ę¬„ä½ę˜ÆęŖ¢č¦– (例如 Explorer čˆ‡ęœå°‹) ēš„å®¹å™Øć€‚", "sideBarSectionHeaderForeground": "ęč¦ę¬„ä½å€ę®µęØ™é ­ēš„å‰ę™Æč‰²å½©ć€‚ęč¦ę¬„ä½ę˜ÆęŖ¢č¦– (例如 Explorer čˆ‡ęœå°‹) ēš„å®¹å™Øć€‚", "titleBarActiveForeground": "ä½œē”Øäø­č¦–ēŖ—ä¹‹ęØ™é”Œåˆ—ēš„å‰ę™Æć€‚č«‹ę³Øę„ļ¼Œē›®å‰åŖęœ‰ macOS ę”Æę“ę­¤č‰²å½©ć€‚", diff --git a/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json index a76c05ee2f6..c44f42dbd5d 100644 --- a/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/cht/src/vs/workbench/electron-browser/actions.i18n.json @@ -24,6 +24,9 @@ "quickSwitchWindow": "åæ«é€Ÿåˆ‡ę›č¦–ēŖ—...", "workspaces": "巄作區", "files": "ęŖ”ę”ˆ", + "openRecentPlaceHolderMac": "éøå–ä»„é–‹å•Ÿ (ęŒ‰ä½ Cmd éµä»„åœØę–°č¦–ēŖ—äø­é–‹å•Ÿ)", + "openRecentPlaceHolder": "éøå–ä»„é–‹å•Ÿ (ęŒ‰ä½ Ctrl éµä»„åœØę–°č¦–ēŖ—äø­é–‹å•Ÿ)", + "remove": "å¾žęœ€čæ‘é–‹å•Ÿēš„ęŖ”ę”ˆäø­ē§»é™¤", "openRecent": "é–‹å•Ÿęœ€čæ‘ä½æē”Øēš„ęŖ”ę”ˆ...", "quickOpenRecent": "åæ«é€Ÿé–‹å•Ÿęœ€čæ‘ä½æē”Øēš„ęŖ”ę”ˆ...", "closeMessages": "é—œé–‰é€šēŸ„čØŠęÆ", @@ -39,5 +42,10 @@ "navigateUp": "å°Žč¦½č‡³ [ęŖ¢č¦–äøŠę–¹]", "navigateDown": "å°Žč¦½č‡³ [檢視下方]", "increaseViewSize": "å¢žåŠ ē›®å‰ēš„ęŖ¢č¦–å¤§å°", - "decreaseViewSize": "ēø®å°ē›®å‰ēš„ęŖ¢č¦–å¤§å°" + "decreaseViewSize": "ēø®å°ē›®å‰ēš„ęŖ¢č¦–å¤§å°", + "showPreviousTab": "é”Æē¤ŗå‰äø€å€‹č¦–ēŖ—ē“¢å¼•ęØ™ē±¤", + "showNextWindowTab": "锯示下一個視窗瓢引標籤", + "moveWindowTabToNewWindow": "å°‡č¦–ēŖ—ē“¢å¼•ęØ™ē±¤ē§»č‡³ę–°ēš„č¦–ēŖ—", + "mergeAllWindowTabs": "åˆä½µę‰€ęœ‰č¦–ēŖ—", + "toggleWindowTabsBar": "åˆ‡ę›č¦–ēŖ—ē“¢å¼•ęØ™ē±¤åˆ—" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/cht/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..10a65101c17 --- /dev/null +++ b/i18n/cht/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "čØ­å®ščŖžčØ€", + "displayLanguage": "定義 VSCode ēš„é”Æē¤ŗčŖžčØ€ć€‚", + "doc": "å¦‚éœ€ę”Æę“ēš„čŖžčØ€ęø…å–®ļ¼Œč«‹åƒé–± {0}怂", + "restart": "ę”¹č®ŠčØ­å®šå€¼å¾Œéœ€č¦é‡ę–°å•Ÿå‹• VSCode.", + "fail.createSettings": "焔法建立 '{0}' ({1})怂", + "JsonSchema.locale": "č¦ä½æē”Øēš„ UI čŖžčØ€ć€‚" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json index 06d815243f2..214d9764606 100644 --- a/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -7,15 +7,18 @@ "view": "檢視", "help": "čŖŖę˜Ž", "file": "ęŖ”ę”ˆ", + "workspaces": "巄作區", "developer": "開發人哔", "showEditorTabs": "ęŽ§åˆ¶å·²é–‹å•Ÿēš„ē·Øč¼Æå™Øę˜Æå¦ę‡‰é”Æē¤ŗåœØē“¢å¼•ęØ™ē±¤äø­ć€‚", + "workbench.editor.labelFormat.short": "é”Æē¤ŗęŖ”ę”ˆēš„åēØ±ļ¼Œäø¦åœØåēØ±å¾ŒęŽ„č‘—č©²ęŖ”ę”ˆēš„ē›®éŒ„åēØ±ć€‚", + "workbench.editor.labelFormat.medium": "é”Æē¤ŗęŖ”ę”ˆēš„åēØ±ļ¼Œäø¦åœØåēØ±å¾ŒęŽ„č‘—č©²ęŖ”ę”ˆčˆ‡å·„ä½œå€č³‡ę–™å¤¾ēš„ē›øå°č·Æå¾‘ć€‚", + "workbench.editor.labelFormat.long": "é”Æē¤ŗęŖ”ę”ˆēš„åēØ±ļ¼Œäø¦åœØåēØ±å¾ŒęŽ„č‘—č©²ęŖ”ę”ˆēš„ēµ•å°č·Æå¾‘ć€‚", + "tabDescription": "ęŽ§åˆ¶ē·Øč¼Æå™Øēš„ęØ™ē±¤ę ¼å¼ć€‚č®Šę›“ę­¤čØ­å®šå…·ęœ‰å¤šé …å„Ŗé»žļ¼Œä¾‹å¦‚åÆč®“ęŖ”ę”ˆēš„ä½ē½®ę›“åŠ ęø…ę„š:\n-簔短: 'parent'\n-äø­ē­‰: 'workspace/src/parent'\n-å®Œę•“: '/home/user/workspace/src/parent'\n-預設: '.../parent'ļ¼Œē•¶å¦äø€å€‹ē“¢å¼•ęØ™ē±¤å…±ē”Øē›øåŒēš„ęØ™é”Œļ¼Œęˆ–č‹„č·Æå¾‘åœē”Øļ¼Œå»å…±ē”Øē›øé—œēš„å·„ä½œå€č·Æå¾‘ę™‚", "editorTabCloseButton": "ęŽ§åˆ¶ē·Øč¼Æå™Øēš„ē“¢å¼•ęØ™ē±¤é—œé–‰ęŒ‰éˆ•ä½ē½®ļ¼Œęˆ–åœØčØ­ē‚ŗ 'off' ę™‚å°‡å…¶åœē”Øć€‚", "showIcons": "ęŽ§åˆ¶é–‹å•Ÿēš„ē·Øč¼Æå™Øę˜Æå¦ę­é…åœ–ē¤ŗé”Æē¤ŗć€‚é€™éœ€č¦åŒę™‚å•Ÿē”Øåœ–ē¤ŗä½ˆę™Æäø»é”Œć€‚", - "enablePreview": "ęŽ§åˆ¶å·²é–‹å•Ÿēš„ē·Øč¼Æå™Øę˜Æå¦é”Æē¤ŗē‚ŗé č¦½ć€‚é č¦½ē·Øč¼Æå™Øęœƒé‡č¤‡ä½æē”Øåˆ°č¢«äæē•™ (ä¾‹å¦‚ęŒ‰å…©äø‹ęˆ–é€²č”Œē·Øč¼Æ) 為止。", + "enablePreview": "ęŽ§åˆ¶å·²é–‹å•Ÿēš„ē·Øč¼Æå™Øę˜Æå¦é”Æē¤ŗē‚ŗé č¦½ć€‚é č¦½ē·Øč¼Æå™Øęœƒé‡č¤‡ä½æē”Øåˆ°č¢«äæē•™ (ä¾‹å¦‚ęŒ‰å…©äø‹ęˆ–é€²č”Œē·Øč¼Æ) äø¦ä»„ę–œé«”å­—åž‹ęØ£å¼é”Æē¤ŗē‚ŗę­¢ć€‚", "enablePreviewFromQuickOpen": "ęŽ§åˆ¶é€éŽ Quick Open ę‰€é–‹å•Ÿēš„ē·Øč¼Æå™Øę˜Æå¦é”Æē¤ŗē‚ŗé č¦½ć€‚é č¦½ē·Øč¼Æå™Øęœƒé‡č¤‡ä½æē”Øåˆ°č¢«äæē•™ (ä¾‹å¦‚ęŒ‰å…©äø‹ęˆ–é€²č”Œē·Øč¼Æ) 為止。", - "editorOpenPositioning": "ęŽ§åˆ¶č¦åœØä½•č™•é–‹å•Ÿē·Øč¼Æå™Øć€‚éøå– [å·¦] ꈖ [右] åœØē›®å‰ä½æē”Øäø­ē·Øč¼Æå™Øēš„å·¦å“ęˆ–å³å“é–‹å•Ÿē·Øč¼Æå™Øć€‚éøå– [先] ꈖ [後] å¾žē›®å‰ä½æē”Øäø­ē·Øč¼Æå™Øå¦å¤–é–‹å•Ÿē·Øč¼Æå™Øć€‚", "revealIfOpen": "ęŽ§åˆ¶ē·Øč¼Æå™Øę˜Æå¦č¦åœØä»»ä½•é”Æē¤ŗēš„ē¾¤ēµ„é–‹å•Ÿę™‚ļ¼ŒåœØå…¶äø­é”Æē¤ŗć€‚č‹„å•Ÿē”Øę­¤éøé …ļ¼Œå·²ē¶“é–‹å•Ÿēš„ē·Øč¼Æå™Øå°‡ęœƒē¹¼ēŗŒé”Æē¤ŗļ¼Œč€ŒäøęœƒåœØē›®å‰ä½æē”Øäø­ēš„ē·Øč¼Æå™Øē¾¤ēµ„äø­å†é–‹å•Ÿäø€ę¬”ć€‚č«‹ę³Øę„ļ¼Œęœ‰äø€äŗ›ęƒ…ę³ęœƒåæ½ē•„ę­¤čØ­å®šļ¼Œä¾‹å¦‚ē•¶å¼·åˆ¶ē·Øč¼Æå™ØåœØē‰¹å®šē¾¤ēµ„äø­é–‹å•Ÿļ¼Œęˆ–å¼·åˆ¶ē·Øč¼Æå™ØåœØē›®å‰ä½æē”Øäø­ēš„ē¾¤ēµ„ę—é–‹å•Ÿē­‰ęƒ…ę³ć€‚", - "commandHistory": "ęŽ§åˆ¶ę˜Æå¦č¦äæē•™åœØå‘½ä»¤éøę“‡å€ę­·ēØ‹čØ˜éŒ„äø­ęœ€čæ‘ę‰€ä½æē”Øēš„å‘½ä»¤ę•øē›®ć€‚čØ­å®šē‚ŗ 0 ä»„åœē”Øå‘½ä»¤ę­·ēØ‹čØ˜éŒ„ć€‚", "preserveInput": "ęŽ§åˆ¶äø‹ę¬”é–‹å•Ÿå‘½ä»¤éøę“‡å€ę™‚ļ¼Œęœ€å¾Œéµå…„ēš„č¼øå…„ę˜Æå¦ę‡‰č©²é‚„åŽŸć€‚", "closeOnFocusLost": "ęŽ§åˆ¶ę˜Æå¦åœØ Quick Open å¤±åŽ»ē„¦é»žę™‚č‡Ŗå‹•é—œé–‰ć€‚", "openDefaultSettings": "ęŽ§åˆ¶é–‹å•ŸčØ­å®šę™‚ę˜Æå¦ä¹Ÿęœƒé–‹å•Ÿé”Æē¤ŗę‰€ęœ‰é čØ­čØ­å®šēš„ē·Øč¼Æå™Øć€‚", @@ -23,6 +26,9 @@ "statusBarVisibility": "ęŽ§åˆ¶ Workbench åŗ•ē«Æē‹€ę…‹åˆ—ēš„åÆč¦–ę€§ć€‚", "activityBarVisibility": "ęŽ§åˆ¶ę“»å‹•åˆ—åœØ workbench äø­ēš„åÆč¦‹åŗ¦ć€‚", "closeOnFileDelete": "ęŽ§åˆ¶é”Æē¤ŗęŖ”ę”ˆēš„ē·Øč¼Æå™Øę˜Æå¦ę‡‰åœØå…¶ä»–č™•ē†åŗåˆŖé™¤ęˆ–é‡ę–°å‘½åč©²ęŖ”ę”ˆę™‚č‡Ŗå‹•é—œé–‰ć€‚č‹„åœē”Øę­¤éøé …ļ¼Œē•¶ē™¼ē”Ÿå‰čæ°ē‹€ę³ę™‚ļ¼Œē·Øč¼Æå™ØęœƒäæęŒé–‹å•Ÿļ¼Œäø¦å‘ˆē¾å·²č®Šę›“ēš„ē‹€ę…‹ć€‚č«‹ę³Øę„ļ¼Œå¾žę‡‰ē”ØēØ‹å¼å…§åˆŖé™¤äø€å¾‹ęœƒé—œé–‰ē·Øč¼Æå™Øļ¼Œä½†å·²č®Šę›“ēš„ęŖ”ę”ˆåœØč³‡ę–™ęœŖå„²å­˜å‰äø€å¾‹äøęœƒé—œé–‰ć€‚", + "fontAliasing": "在 Workbench äø­ęŽ§åˆ¶å­—åž‹é‹øé½’åŒ–ēš„ę–¹ę³•ć€‚- 預設: å­åƒē“ å­—åž‹å¹³ę»‘č™•ē†ć€‚åœØå¤§éƒØåˆ†éž Retina é”Æē¤ŗå™ØäøŠęœƒé”Æē¤ŗå‡ŗęœ€éŠ³åˆ©ēš„ę–‡å­—- å·²ę¶ˆé™¤é‹øé½’: ē›øå°ę–¼å­åƒē“ ļ¼Œę ¹ę“šåƒē“ å±¤ē“šå¹³ę»‘å­—åž‹ć€‚åÆč®“å­—åž‹ę•“é«”é”Æå¾—č¼ƒē“°- ē„”: åœē”Øå­—åž‹å¹³ę»‘č™•ē†ć€‚ę–‡å­—ęœƒä»„é‹øé½’ē‹€ēš„éŠ³é‚Šé”Æē¤ŗ ", + "workbench.fontAliasing.default": "å­åƒē“ å­—åž‹å¹³ę»‘č™•ē†ć€‚åœØå¤§éƒØåˆ†éž Retina é”Æē¤ŗå™ØäøŠęœƒé”Æē¤ŗå‡ŗęœ€éŠ³åˆ©ēš„ę–‡å­—ć€‚", + "workbench.fontAliasing.antialiased": "ē›øå°ę–¼å­åƒē“ ļ¼Œę ¹ę“šåƒē“ å±¤ē“šå¹³ę»‘å­—åž‹ć€‚åÆä»„č®“å­—åž‹ę•“é«”é”Æå¾—č¼ƒē“°ć€‚", "workbench.fontAliasing.none": "禁用字體平滑.ę–‡å­—å°‡ęœƒé”Æē¤ŗé‹øé½’ē‹€čˆ‡é‹’åˆ©ēš„é‚Šē·£.", "swipeToNavigate": "åˆ©ē”Øäø‰ęŒ‡ę°“å¹³ę’„å‹•åœØé–‹å•Ÿēš„ęŖ”ę”ˆé–“ē€č¦½ć€‚", "workbenchConfigurationTitle": "巄作台", @@ -38,14 +44,15 @@ "window.reopenFolders.folders": "é‡ę–°é–‹å•Ÿę‰€ęœ‰č³‡ę–™å¤¾ć€‚ē©ŗē™½å·„ä½œå€å°‡äøęœƒé‚„åŽŸć€‚", "window.reopenFolders.one": "é‡ę–°é–‹å•ŸäøŠäø€å€‹ä½æē”Øäø­ēš„č¦–ēŖ—ć€‚", "window.reopenFolders.none": "äø€å¾‹äøé‡ę–°é–‹å•Ÿč¦–ēŖ—ć€‚ę°øé å¾žē©ŗē™½ēš„č¦–ēŖ—é–‹å§‹ć€‚", + "restoreWindows": "ęŽ§åˆ¶é‡ę–°å•Ÿå‹•å¾Œč¦–ēŖ—é‡ę–°é–‹å•Ÿēš„ę–¹å¼ć€‚éøå– [ē„”] äø€å¾‹ä»„ē©ŗē™½å·„ä½œå€é–‹å§‹ć€éøå– [äø€] å¾žäøŠäø€å€‹ē·Øč¼Æēš„č¦–ēŖ—é‡ę–°é–‹å•Ÿć€éøå– [資料夾] é‡ę–°é–‹å•Ÿę‰€ęœ‰č³‡ę–™å¤¾ę›¾ē¶“é–‹å•Ÿēš„č¦–ēŖ—ļ¼Œęˆ–éøå– [å…ØéƒØ] é‡ę–°é–‹å•ŸäøŠäø€å€‹å·„ä½œéšŽę®µēš„ę‰€ęœ‰č¦–ēŖ—ć€‚", "restoreFullscreen": "ęŽ§åˆ¶ē•¶č¦–ēŖ—åœØå…Øčž¢å¹•ęØ”å¼äø‹ēµęŸå¾Œļ¼Œäø‹ę¬”ę˜Æå¦ä»ä»„å…Øčž¢å¹•ęØ”å¼é–‹å•Ÿć€‚", "zoomLevel": "čŖæę•“č¦–ēŖ—ēš„ēø®ę”¾ęÆ”ä¾‹ć€‚åŽŸå§‹å¤§å°ē‚ŗ 0ļ¼Œč€Œäø”ęÆå€‹å‘äøŠå¢žé‡ (例如 1) ęˆ–å‘äø‹å¢žé‡ (例如 -1) ä»£č”Øę”¾å¤§ęˆ–ēø®å° 20%ć€‚ę‚Øä¹ŸåÆä»„č¼øå…„å°ę•øļ¼Œę›“ē“°å¾®åœ°čŖæę•“ēø®ę”¾ęÆ”ä¾‹ć€‚", - "title": "ä¾ę“šä½æē”Øäø­ēš„ē·Øč¼Æå™ØęŽ§åˆ¶č¦–ēŖ—ęØ™é”Œć€‚č®Šę•øęœƒä¾ę“šå…§å®¹ę›æę›:\n${activeEditorShort}: 例如 myFile.txt\n${activeEditorMedium}: 例如 myFolder/myFile.txt\n${activeEditorLong}: 例如 /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 例如 myFolder\n${folderPath}: 例如 /Users/Development/myFolder\n${rootName}: 例如 myFolder1,myFolder2,myFolder3\n${rootPath}: 例如 /Users/Development/myWorkspace\n${appName}: 例如 VS Code\n${dirty}: ē”Øä»„ęŒ‡å‡ŗē·Øč¼Æå™Øē¶“éŽč®Šę›“ēš„ęŒ‡ęØ™\n${separator}: ę¢ä»¶å¼åˆ†éš”ē¬¦č™Ÿ (' - ')ļ¼ŒåŖęœƒåœØå‰å¾Œē‚ŗå…·ęœ‰å€¼ēš„č®Šę•øę™‚é”Æē¤ŗ", "window.newWindowDimensions.default": "åœØčž¢å¹•äø­å¤®é–‹å•Ÿę–°č¦–ēŖ—ć€‚", "window.newWindowDimensions.inherit": "ä»„ē›øåŒę–¼äøŠäø€å€‹ä½æē”Øäø­ä¹‹č¦–ēŖ—ēš„ē¶­åŗ¦é–‹å•Ÿę–°č¦–ēŖ—ć€‚", "window.newWindowDimensions.maximized": "é–‹å•Ÿäø¦ęœ€å¤§åŒ–ę–°č¦–ēŖ—ć€‚", "window.newWindowDimensions.fullscreen": "åœØå…Øčž¢å¹•ęØ”å¼äø‹é–‹å•Ÿę–°č¦–ēŖ—ć€‚", "newWindowDimensions": "ęŽ§åˆ¶ē•¶č‡³å°‘äø€å€‹č¦–ēŖ—å·²ę‰“é–‹ēš„ęƒ…ę³äø‹é–‹å•Ÿę–°č¦–ēŖ—ēš„ē¶­åŗ¦ć€‚ę ¹ę“šé čØ­ļ¼Œę–°č¦–ēŖ—ęœƒä»„å°åž‹ē¶­åŗ¦åœØē•«é¢äø­å¤®é–‹å•Ÿć€‚čØ­ē‚ŗ 'inherit' ę™‚ļ¼Œč¦–ēŖ—ēš„ē¶­åŗ¦ęœƒå’Œęœ€å¾Œé–‹å•Ÿēš„č¦–ēŖ—ē›øåŒć€‚čØ­ē‚ŗ 'maximized' ę™‚ļ¼Œč¦–ēŖ—ęœƒé–‹åˆ°ęœ€å¤§ļ¼Œč‹„čØ­ē‚ŗ 'fullscreen' å‰‡å…Øčž¢å¹•é–‹å•Ÿć€‚", + "closeWhenEmpty": "ęŽ§åˆ¶åœØé—œé–‰ęœ€å¾Œäø€å€‹ē·Øč¼Æå™Øę™‚ļ¼Œę˜Æå¦ä¹Ÿę‡‰é—œé–‰č¦–ēŖ—ć€‚ę­¤čØ­å®šåƒ…é©ē”Øę–¼ęœŖé”Æē¤ŗč³‡ę–™å¤¾ēš„č¦–ēŖ—ć€‚", "window.menuBarVisibility.default": "åŖåœØå…Øčž¢å¹•ęØ”å¼ę™‚éš±č—åŠŸčƒ½č”Øć€‚", "window.menuBarVisibility.visible": "äø€å¾‹é”Æē¤ŗåŠŸčƒ½č”Øļ¼Œå³ä½æåœØå…Øčž¢å¹•ęØ”å¼ę™‚äŗ¦ē„¶ć€‚", "window.menuBarVisibility.toggle": "éš±č—åŠŸčƒ½č”Øļ¼Œä½†åÆē¶“ē”± Alt éµåŠ ä»„é”Æē¤ŗć€‚", diff --git a/i18n/cht/src/vs/workbench/electron-browser/window.i18n.json b/i18n/cht/src/vs/workbench/electron-browser/window.i18n.json index 21628fd8aa6..84c2c075664 100644 --- a/i18n/cht/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/cht/src/vs/workbench/electron-browser/window.i18n.json @@ -9,6 +9,5 @@ "cut": "剪下", "copy": "複製", "paste": "貼上", - "selectAll": "全選", - "confirmOpenButton": "開啟(&&O)..." + "selectAll": "全選" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index eae39827b01..06716533a4d 100644 --- a/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "č‹„ęœ‰ē¬¦åˆę­¤ęØ”å¼ēš„č”Œļ¼Œå‰‡äøę‡‰č©²č®Šę›“å…¶ēø®ęŽ’ļ¼Œäø¦äø”äøä½æē”Øå…¶ä»–č¦å‰‡ęÆ”å°ć€‚", "schema.indentationRules.unIndentedLinePattern.pattern": "適用於 unIndentedLinePattern ēš„ RegExp ęØ”å¼ć€‚", "schema.indentationRules.unIndentedLinePattern.flags": "適用於 unIndentedLinePattern ēš„ RegExp 旗標。", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "åæ…é ˆē¬¦åˆęØ£å¼ `/^([gimuy]+)$/`" + "schema.indentationRules.unIndentedLinePattern.errorMessage": "åæ…é ˆē¬¦åˆęØ£å¼ `/^([gimuy]+)$/`", + "schema.folding": "čŖžčØ€ēš„ę‘ŗē–ŠčØ­å®šć€‚", + "schema.folding.offSide": "č‹„čŖžčØ€äø­ēš„å€å”Šē”±å…¶ēø®ęŽ’č”Øē¤ŗļ¼Œå‰‡č©²čŖžčØ€ęœƒä¾å¾Ŗč¶Šä½č¦å‰‡ć€‚č‹„å·²čØ­å®šļ¼Œå‰‡ē©ŗē™½č”Œęœƒå±¬ę–¼å¾ŒēŗŒå€å”Šć€‚", + "schema.folding.markers": "čŖžčØ€ēš„ē‰¹å®šę‘ŗē–ŠęØ™čØ˜ļ¼Œä¾‹å¦‚ '#region' 和 '#endregion'ć€‚ęœƒé‡å°ę‰€ęœ‰č”Œēš„å…§å®¹ęø¬č©¦čµ·å§‹å’Œēµå°¾ regexļ¼Œč€Œåæ…é ˆęœ‰ę•ˆåœ°čØ­čØˆčµ·å§‹å’Œēµå°¾ regex", + "schema.folding.markers.start": "é–‹å§‹ęØ™čØ˜ēš„ RegExp ęØ”å¼ć€‚regexp åæ…é ˆä»„ '^' ä½œē‚ŗé–‹é ­ć€‚", + "schema.folding.markers.end": "ēµęŸęØ™čØ˜ēš„ RegExp ęØ”å¼ć€‚regexp åæ…é ˆä»„ '^' ä½œē‚ŗé–‹é ­ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..71382a34611 --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "檢視: åˆ‡ę›čæ·ä½ åœ°åœ–" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index c0e9f1c54f2..52fe8ed02e5 100644 --- a/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "åˆ‡ę›ęŽ§åˆ¶å­—å…ƒ" + "toggleRenderControlCharacters": "檢視: åˆ‡ę›ęŽ§åˆ¶å­—å…ƒ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 507d54a8855..f69ad28329c 100644 --- a/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "åˆ‡ę›č½‰č­Æē©ŗē™½å­—å…ƒ" + "toggleRenderWhitespace": "檢視: åˆ‡ę›č½‰č­Æē©ŗē™½å­—å…ƒ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index 5e486240657..810ba433105 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "ę²’ęœ‰ēµ„ę…‹", + "addConfigTo": "ę–°å¢žēµ„ę…‹ ({0})...", "addConfiguration": "ę–°å¢žēµ„ę…‹..." } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index b6a825d8df7..86768e58c63 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0},偵錯", "debugAriaLabel": "č¼øå…„č¦åŸ·č”Œä¹‹å•Ÿå‹•ēµ„ę…‹ēš„åēØ±ć€‚", + "addConfigTo": "ę–°å¢žēµ„ę…‹ ({0})...", + "addConfiguration": "ę–°å¢žēµ„ę…‹...", "noConfigurationsMatching": "ę²’ęœ‰ä»»ä½•ē›øē¬¦ēš„åµéŒÆēµ„ę…‹", "noConfigurationsFound": "ę‰¾äøåˆ°ä»»ä½•åµéŒÆēµ„ę…‹ć€‚č«‹å»ŗē«‹'launch.json' ęŖ”ę”ˆć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index d0e90daa9e8..19f502a82ef 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "ēµ„ę…‹ļ¼Œē”Øę–¼ē”¢ē”Ÿåˆå§‹ 'launch.json'怂", "vscode.extension.contributes.debuggers.languages": "åÆå°‡åµéŒÆå»¶ä¼øęØ”ēµ„č¦–ē‚ŗć€Œé čØ­åµéŒÆå·„å…·ć€ēš„čŖžčØ€ęø…å–®ć€‚", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "å¦‚ęœ‰ęŒ‡å®šļ¼ŒVS Code ęœƒå‘¼å«ę­¤å‘½ä»¤ä»„ę±ŗå®šåµéŒÆé…ęŽ„å™Øēš„åÆåŸ·č”ŒęŖ”č·Æå¾‘åŠč¦å‚³éžēš„å¼•ę•øć€‚", - "vscode.extension.contributes.debuggers.startSessionCommand": "å¦‚ęœ‰ęŒ‡å®šļ¼ŒVS Code ęœƒē‚ŗä»„ę­¤å»¶ä¼øęØ”ēµ„ē‚ŗē›®ęØ™ēš„ć€ŒåµéŒÆć€ęˆ–ć€ŒåŸ·č”Œć€å‹•ä½œå‘¼å«ę­¤å‘½ä»¤ć€‚", "vscode.extension.contributes.debuggers.configurationSnippets": "ē”Øę–¼åœØ 'launch.json' äø­ę–°å¢žēµ„ę…‹ēš„ēØ‹å¼ē¢¼ē‰‡ę®µć€‚", "vscode.extension.contributes.debuggers.configurationAttributes": "JSON ēµę§‹ęčæ°ēµ„ę…‹ļ¼Œē”Øę–¼é©—č­‰ 'launch.json'怂", "vscode.extension.contributes.debuggers.windows": "Windows ē‰¹å®ščØ­å®šć€‚", diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 74156fbcb3a..d0f395c762c 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -13,13 +13,12 @@ "compoundMustHaveConfigurations": "č¤‡åˆåæ…é ˆčØ­ęœ‰ \"configurations\" å±¬ę€§ļ¼Œę‰čƒ½å•Ÿå‹•å¤šå€‹ēµ„ę…‹ć€‚", "configMissing": "'launch.json' äø­éŗę¼ēµ„ę…‹ '{0}'怂", "debugTypeNotSupported": "äøę”Æę“čØ­å®šēš„åµéŒÆé”žåž‹ '{0}'怂", - "debugTypeMissing": "éŗę¼ę‰€éøå•Ÿå‹•čØ­å®šēš„å±¬ę€§ 'type'怂", + "debugTypeMissing": "éŗę¼ę‰€éøå•Ÿå‹•čØ­å®šēš„å±¬ę€§ `type`怂", + "debugAnyway": "ä»č¦åµéŒÆ", "preLaunchTaskErrors": "執蔌 preLaunchTask '{0}' ęœŸé–“åµęø¬åˆ°å»ŗē½®éŒÆčŖ¤ć€‚", "preLaunchTaskError": "執蔌 preLaunchTask '{0}' ęœŸé–“åµęø¬åˆ°å»ŗē½®éŒÆčŖ¤ć€‚", "preLaunchTaskExitCode": "preLaunchTask '{0}' å·²ēµ‚ę­¢ļ¼ŒēµęŸä»£ē¢¼ē‚ŗ {1}怂", - "debugAnyway": "ä»č¦åµéŒÆ", "noFolderWorkspaceDebugError": "ē„”ę³•å°ä½æē”Øäø­ēš„ęŖ”ę”ˆåµéŒÆć€‚č«‹ē¢ŗčŖęŖ”ę”ˆå·²å„²å­˜åœØē£ē¢ŸäøŠļ¼Œč€Œäø”ę‚Øå·²ē¶“ē‚ŗč©²ęŖ”ę”ˆé”žåž‹å®‰č£åµéŒÆå»¶ä¼øęØ”ēµ„ć€‚", "NewLaunchConfig": "č«‹ē‚ŗę‚Øēš„ę‡‰ē”ØēØ‹å¼čØ­å®šå•Ÿå‹•ēµ„ę…‹ęŖ”ć€‚{0}", - "DebugTaskNotFound": "ę‰¾äøåˆ° preLaunchTask '{0}'怂", - "differentTaskRunning": "巄作{0}å·²ę­£åœØåŸ·č”Œć€‚ē„”ę³•åœØå•Ÿå‹•å·„ä½œ\"{1}\"å‰åŸ·č”Œ" + "DebugTaskNotFound": "ę‰¾äøåˆ° preLaunchTask '{0}'怂" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index e7982d93dfd..39f259be4a4 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "ē¬¬äø€ę¬”č©•ä¼°ęœƒę“·å–ē‰©ä»¶ē‹€ę…‹", "replVariableAriaLabel": "č®Šę•ø {0} å…·ęœ‰å€¼ {1}ļ¼Œć€Œč®€å–ć€ę±‚å€¼ć€č¼øå‡ŗć€čæ“åœˆļ¼ŒåµéŒÆ", "replExpressionAriaLabel": "é‹ē®—å¼ {0} å…·ęœ‰å€¼ {1}ļ¼Œć€Œč®€å–ć€ę±‚å€¼ć€č¼øå‡ŗć€čæ“åœˆļ¼ŒåµéŒÆ", - "replValueOutputAriaLabel": "{0}ļ¼Œć€Œč®€å–ć€ę±‚å€¼ć€č¼øå‡ŗć€čæ“åœˆļ¼ŒåµéŒÆ", - "replKeyValueOutputAriaLabel": "č¼øå‡ŗč®Šę•ø {0} å…·ęœ‰å€¼ {1}ļ¼Œć€Œč®€å–ć€ę±‚å€¼ć€č¼øå‡ŗć€čæ“åœˆļ¼ŒåµéŒÆ" + "replValueOutputAriaLabel": "{0}ļ¼Œć€Œč®€å–ć€ę±‚å€¼ć€č¼øå‡ŗć€čæ“åœˆļ¼ŒåµéŒÆ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index 81362151ea4..315d0d6089a 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "å°ēØ‹å¼åŸ·č”ŒåµéŒÆę™‚ē‹€ę…‹åˆ—ēš„čƒŒę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØ", - "statusBarDebuggingForeground": "å°ēØ‹å¼åŸ·č”ŒåµéŒÆę™‚ē‹€ę…‹åˆ—ēš„å‰ę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØ" + "statusBarDebuggingForeground": "å°ēØ‹å¼åŸ·č”ŒåµéŒÆę™‚ē‹€ę…‹åˆ—ēš„å‰ę™Æč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØ", + "statusBarDebuggingBorder": "ę­£åœØåµéŒÆē”Øä»„åˆ†éš”č³‡čØŠēœ‹ęæčˆ‡ē·Øč¼Æå™Øēš„ē‹€ę…‹åˆ—ę”†ē·šč‰²å½©ć€‚ē‹€ę…‹åˆ—ęœƒé”Æē¤ŗåœØč¦–ēŖ—ēš„åŗ•éƒØć€‚ " } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 246786aab6c..4036d2c2e6e 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "åµéŒÆé…ęŽ„å™ØåÆåŸ·č”ŒęŖ” '{0}' äøå­˜åœØć€‚", "debugAdapterCannotDetermineExecutable": "ē„”ę³•åˆ¤ę–·åµéŒÆé…ęŽ„å™Ø '{0}' ēš„åÆåŸ·č”ŒęŖ”ć€‚", + "launch.config.comment1": "使用 IntelliSense ä»„å¾—ēŸ„åÆē”Øēš„å±¬ę€§ć€‚", + "launch.config.comment2": "ęš«ē•™ä»„ęŖ¢č¦–ē¾ęœ‰å±¬ę€§ēš„ęčæ°ć€‚", + "launch.config.comment3": "å¦‚éœ€č©³ē“°č³‡čØŠļ¼Œč«‹ē€č¦½: {0}", "debugType": "ēµ„ę…‹ēš„é”žåž‹ć€‚", "debugTypeNotRecognised": "ē„”ę³•č¾Øč­˜ę­¤åµéŒÆé”žåž‹.č«‹ē¢ŗčŖå·²ęœ‰å®‰č£äø¦å•Ÿē”Øē›øå°ę‡‰ēš„åµéŒÆę““å……åŠŸčƒ½.", "node2NotSupported": "\"node2\" å·²äøå†ę”Æę“ļ¼Œč«‹ę”¹ē”Ø \"node\"ļ¼Œäø¦å°‡ \"protocol\" 屬性設為 \"inspector\"怂", diff --git a/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 53bdbc473d2..9d0f768770d 100644 --- a/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "識刄碼", "view name": "åēØ±", "view location": "ä½ē½®", - "themes": "ä½ˆę™Æäø»é”Œ ({0})", + "colorThemes": "č‰²å½©ä½ˆę™Æäø»é”Œ ({0})", + "iconThemes": "åœ–ē¤ŗä½ˆę™Æäø»é”Œ ({0}) ", + "colors": "色彩 ({0})", + "colorId": "識刄碼", + "defaultDark": "預設深色", + "defaultLight": "預設淺色", + "defaultHC": "é čØ­é«˜å°ęÆ”", "JSON Validation": "JSON é©—č­‰ ({0})", "commands": "命令 ({0})", "command name": "åēØ±", diff --git a/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index dce745aeaf8..0f96abef009 100644 --- a/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,23 +34,25 @@ "postDisableMessage": "č¦é‡ę–°č¼‰å…„ę­¤č¦–ēŖ—ä»„åœē”Øå»¶ä¼øęØ”ēµ„ '{0}' 嗎?", "postUninstallTooltip": "é‡ę–°č¼‰å…„ä»„åœē”Ø", "postUninstallMessage": "č¦é‡ę–°č¼‰å…„ę­¤č¦–ēŖ—ä»„åœē”Øå·²č§£é™¤å®‰č£ēš„å»¶ä¼øęØ”ēµ„ '{0}' 嗎?", - "reload": "é‡ę–°č¼‰å…„č¦–ēŖ—(&&R)", "toggleExtensionsViewlet": "é”Æē¤ŗę““å……åŠŸčƒ½", "installExtensions": "å®‰č£ę““å……åŠŸčƒ½", + "showEnabledExtensions": "é”Æē¤ŗå•Ÿē”Øēš„å»¶ä¼øęØ”ēµ„", "showInstalledExtensions": "é”Æē¤ŗå®‰č£ēš„ę““å……åŠŸčƒ½", "showDisabledExtensions": "é”Æē¤ŗåœē”Øēš„å»¶ä¼øęØ”ēµ„", "clearExtensionsInput": "ęø…é™¤ę““å……åŠŸčƒ½č¼øå…„", "showOutdatedExtensions": "é”Æē¤ŗéŽęœŸēš„ę““å……åŠŸčƒ½", "showPopularExtensions": "é”Æē¤ŗē†±é–€ę““å……åŠŸčƒ½", "showRecommendedExtensions": "é”Æē¤ŗå»ŗč­°ēš„ę““å……åŠŸčƒ½", - "showWorkspaceRecommendedExtensions": "é”Æē¤ŗå·„ä½œå€ēš„å»ŗč­°ę““å……åŠŸčƒ½", + "installRecommendedExtension": "å®‰č£å»ŗč­°ēš„ę““å……åŠŸčƒ½", "showRecommendedKeymapExtensions": "é”Æē¤ŗå»ŗč­°ēš„ęŒ‰éµå°ę‡‰", "showRecommendedKeymapExtensionsShort": "ęŒ‰éµå°ę‡‰", "showLanguageExtensions": "é”Æē¤ŗčŖžčØ€ę““å……åŠŸčƒ½", "showLanguageExtensionsShort": "čŖžčØ€ę““å……åŠŸčƒ½", - "configureWorkspaceRecommendedExtensions": "čØ­å®šå»ŗč­°ēš„å»¶ä¼øęØ”ēµ„ (巄作區)", - "ConfigureWorkspaceRecommendations.noWorkspace": "åŖęœ‰åœØå·„ä½œå€č³‡ę–™å¤¾äø­ę‰čƒ½ä½æē”Øå»ŗč­°ć€‚", + "showAzureExtensions": "锯示 Azure 延伸樔組", + "showAzureExtensionsShort": "Azure 延伸樔組", "OpenExtensionsFile.failed": "ē„”ę³•åœØ '.vscode' 資料夾 ({0}) 中建立 'extensions.json' ęŖ”ę”ˆć€‚", + "configureWorkspaceRecommendedExtensions": "čØ­å®šå»ŗč­°ēš„å»¶ä¼øęØ”ēµ„ (巄作區)", + "configureWorkspaceFolderRecommendedExtensions": "čØ­å®šå»ŗč­°ēš„å»¶ä¼øęØ”ēµ„ (å·„ä½œå€č³‡ę–™å¤¾) ", "builtin": "內建", "disableAll": "åœē”Øę‰€ęœ‰å·²å®‰č£ēš„å»¶ä¼øęØ”ēµ„", "disableAllWorkspace": "åœē”Øę­¤å·„ä½œå€ēš„ę‰€ęœ‰å·²å®‰č£å»¶ä¼øęØ”ēµ„", diff --git a/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..e3b6043c38d --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": " ęŽØč–¦é …ē›®" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 9e97614cd5e..654ea0ca06e 100644 --- a/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -5,11 +5,13 @@ // Do not edit this file. It is machine generated. { "reallyRecommended2": "å»ŗč­°å°ę­¤ęŖ”ę”ˆé”žåž‹ä½æē”Ø '{0}' 延伸樔組。", + "reallyRecommendedExtensionPack": "å»ŗč­°å°ę­¤ęŖ”ę”ˆé”žåž‹ä½æē”Ø '{0}' 延伸樔組儗件。", "showRecommendations": "锯示建議", + "install": "å®‰č£", "neverShowAgain": "äøč¦å†é”Æē¤ŗ", "close": "關閉", "workspaceRecommended": "ę­¤å·„ä½œå€å…·ęœ‰ę““å……åŠŸčƒ½å»ŗč­°ć€‚", - "ignoreExtensionRecommendations": "ę˜Æå¦ē•„éŽę‰€ęœ‰å»ŗč­°ēš„ę““å……åŠŸčƒ½ļ¼Ÿ", + "ignoreExtensionRecommendations": "ę˜Æå¦ē•„éŽę‰€ęœ‰ēš„å»¶ä¼øęØ”ēµ„å»ŗč­°?", "ignoreAll": "ę˜Æļ¼Œē•„éŽå…ØéƒØ", "no": "否", "cancel": "å–ę¶ˆ" diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index bf768be736b..8edf8023225 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -5,5 +5,7 @@ // Do not edit this file. It is machine generated. { "filesCategory": "ęŖ”ę”ˆ", - "revealInSideBar": "åœØęč¦ę¬„ä½äø­é”Æē¤ŗ" + "revealInSideBar": "åœØęč¦ę¬„ä½äø­é”Æē¤ŗ", + "acceptLocalChanges": "ä½æē”Øę‚Øēš„č®Šę›“äø¦č¦†åÆ«ē£ē¢Ÿå…§å®¹ ", + "revertLocalChanges": "ęØę£„ę‚Øēš„č®Šę›“äø¦é‚„åŽŸęˆē£ē¢ŸäøŠēš„å…§å®¹" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 0dbbb1af8ef..d858ed8a7c4 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,17 +37,14 @@ "openToSide": "é–‹č‡³å“é‚Š", "compareSource": "éøå–ē”Øä»„ęÆ”č¼ƒ", "globalCompareFile": "ä½æē”Øäø­ęŖ”ę”ˆēš„ęÆ”č¼ƒå°č±”...", - "pickHistory": "éøå–å…ˆå‰é–‹å•Ÿēš„ęŖ”ę”ˆä»„ē›øęÆ”č¼ƒ", - "unableToFileToCompare": "éøå–ēš„ęŖ”ę”ˆē„”ę³•čˆ‡ '{0}' é€²č”ŒęÆ”č¼ƒć€‚", "openFileToCompare": "å…ˆé–‹å•ŸęŖ”ę”ˆä»„čˆ‡å…¶ä»–ęŖ”ę”ˆé€²č”ŒęÆ”č¼ƒ", - "compareWith": "與 '{0}' ęÆ”č¼ƒ", + "compareWith": "ęÆ”č¼ƒ '{0}' 與 '{1}'", "compareFiles": "ęÆ”č¼ƒęŖ”ę”ˆ", "refresh": "é‡ę–°ę•“ē†", "save": "儲存", "saveAs": "å¦å­˜ę–°ęŖ”...", "saveAll": "å…ØéƒØå„²å­˜", "saveAllInGroup": "å…ØéƒØå„²å­˜åœØē¾¤ēµ„äø­", - "saveFiles": "å„²å­˜å·²č®Šę›“ēš„ęŖ”ę”ˆ", "revert": "é‚„åŽŸęŖ”ę”ˆ", "focusOpenEditors": "čšē„¦åœØ [é–‹ę”¾å¼ē·Øč¼Æå™Ø] 檢視", "focusFilesExplorer": "å°‡ē„¦é»žčØ­åœØęŖ”ę”ˆēø½ē®”äøŠ", @@ -55,7 +52,6 @@ "openFileToShow": "å…ˆé–‹å•ŸęŖ”ę”ˆļ¼Œä»„åœØēø½ē®”äø­åŠ ä»„é”Æē¤ŗ", "collapseExplorerFolders": "ę‘ŗē–Š Explorer äø­ēš„č³‡ę–™å¤¾", "refreshExplorer": "é‡ę–°ę•“ē† Explorer", - "openFile": "é–‹å•ŸęŖ”ę”ˆ...", "openFileInNewWindow": "åœØę–°č¦–ēŖ—äø­é–‹å•Ÿä½æē”Øäø­ēš„ęŖ”ę”ˆ", "openFileToShowInNewWindow": "å…ˆé–‹å•ŸęŖ”ę”ˆä»„åœØę–°č¦–ēŖ—äø­é–‹å•Ÿ", "revealInWindows": "åœØęŖ”ę”ˆēø½ē®”äø­é”Æē¤ŗ", @@ -69,5 +65,7 @@ "emptyFileNameError": "åæ…é ˆęä¾›ęŖ”ę”ˆęˆ–č³‡ę–™å¤¾åēØ±ć€‚", "fileNameExistsError": "é€™å€‹ä½ē½®å·²å­˜åœØęŖ”ę”ˆęˆ–č³‡ę–™å¤¾ **{0}**ć€‚č«‹éøę“‡äøåŒēš„åēØ±ć€‚", "invalidFileNameError": "åēØ± **{0}** äøčƒ½ä½œē‚ŗęŖ”ę”ˆęˆ–č³‡ę–™å¤¾åēØ±ć€‚č«‹éøę“‡äøåŒēš„åēØ±ć€‚", - "filePathTooLongError": "åēØ± **{0}** å°Žč‡“č·Æå¾‘å¤Ŗé•·ć€‚č«‹éøę“‡č¼ƒēŸ­ēš„åēØ±ć€‚" + "filePathTooLongError": "åēØ± **{0}** å°Žč‡“č·Æå¾‘å¤Ŗé•·ć€‚č«‹éøę“‡č¼ƒēŸ­ēš„åēØ±ć€‚", + "compareWithSaved": "ęÆ”č¼ƒä½æē”Øäø­ēš„ęŖ”ę”ˆå’Œå·²å„²å­˜ēš„ęŖ”ę”ˆ", + "modifiedLabel": "{0} (在磁碟上) ↔ {1}" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index f49cef6b9b3..fef80808ee4 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "文字檔編輯器", "binaryFileEditor": "äŗŒé€²ä½ęŖ”ę”ˆē·Øč¼Æå™Ø", "filesConfigurationTitle": "ęŖ”ę”ˆ", - "exclude": "設定 Glob ęØ”å¼åÆåŒ…å«ęŖ”ę”ˆåŠč³‡ę–™å¤¾ć€‚", + "exclude": "設定 Glob ęØ”å¼ļ¼Œä»„ęŽ’é™¤ęŖ”ę”ˆåŠč³‡ę–™å¤¾ć€‚ä¾‹å¦‚ļ¼ŒęŖ”ę”ˆēø½ē®”ęœƒę ¹ę“šę­¤é …čØ­å®šļ¼Œåˆ¤ę–·ä½•ēØ®ęŖ”ę”ˆå’Œč³‡ę–™å¤¾č©²é”Æē¤ŗęˆ–éš±č—ć€‚", "files.exclude.boolean": "č¦ē¬¦åˆęŖ”ę”ˆč·Æå¾‘ēš„ Glob ęØ”å¼ć€‚čØ­ē‚ŗ True ꈖ False åÆå•Ÿē”Øęˆ–åœē”ØęØ”å¼ć€‚", "files.exclude.when": "åœØē›øē¬¦ęŖ”ę”ˆåŒå±¤ē“šäøŠé”å¤–ēš„ęŖ¢ęŸ„ć€‚č«‹ä½æē”Ø $(basename) ä½œē‚ŗē›øē¬¦ęŖ”ę”ˆåēØ±ēš„č®Šę•øć€‚", "associations": "å°‡ęŖ”ę”ˆé—œčÆčØ­å®šē‚ŗčŖžčØ€ (例如 \"*.extension\": \"html\")ć€‚é€™äŗ›čŖžčØ€å„Ŗå…ˆę–¼å·²å®‰č£čŖžčØ€ēš„é čØ­é—œčÆć€‚", - "encoding": "č®€å–čˆ‡åÆ«å…„ęŖ”ę”ˆę™‚č¦ä½æē”Øēš„é čØ­å­—å…ƒé›†ē·Øē¢¼ć€‚", - "autoGuessEncoding": "å¦‚ęœ‰å•Ÿē”Øļ¼Œå°‡ęœƒåœØé–‹å•ŸęŖ”ę”ˆę™‚ļ¼Œå˜—č©¦ēŒœęø¬å­—å…ƒé›†ē·Øē¢¼", + "encoding": "åœØč®€å–å’ŒåÆ«å…„ęŖ”ę”ˆę™‚č¦ä½æē”Øēš„é čØ­å­—å…ƒé›†ē·Øē¢¼ć€‚ę­¤é …čØ­å®šä¹ŸåÆę ¹ę“šęÆå€‹čŖžčØ€åŠ ä»„čØ­å®šć€‚", + "autoGuessEncoding": "ē•¶å•Ÿē”Øę­¤åŠŸčƒ½ę™‚ļ¼Œęœƒå˜—č©¦åœØé–‹å•ŸęŖ”ę”ˆę™‚ęŽØęø¬å­—å…ƒé›†ē·Øē¢¼ć€‚ę­¤é …čØ­å®šä¹ŸåÆę ¹ę“šęÆå€‹čŖžčØ€åŠ ä»„čØ­å®šć€‚", "eol": "é čØ­ēµå°¾ę–·č”Œå­—å…ƒ.LF使用 \\n , CRLF使用\\r\\n ", "trimTrailingWhitespace": "č‹„å•Ÿē”Øļ¼Œå°‡åœØå„²å­˜ęŖ”ę”ˆę™‚äæ®å‰Ŗå°¾ē«Æē©ŗē™½ć€‚", "insertFinalNewline": "å•Ÿē”Øę™‚ļ¼Œč«‹åœØå„²å­˜ęŖ”ę”ˆę™‚åœØå…¶ēµå°¾ę’å…„ęœ€å¾Œäø€å€‹ę–°č”Œć€‚", + "trimFinalNewlines": "č‹„å•Ÿē”Øļ¼Œå‰‡ęœƒåœØå„²å­˜ęŖ”ę”ˆę™‚ļ¼Œäæ®å‰ŖęŖ”ę”ˆęœ«ę–°č”Œå°¾ēš„ę‰€ęœ‰ę–°č”Œć€‚", "files.autoSave.off": "å·²č®Šę›“ēš„ęŖ”ę”ˆäø€å¾‹äøęœƒč‡Ŗå‹•å„²å­˜ć€‚", "files.autoSave.afterDelay": "å·²č®Šę›“ēš„ęŖ”ę”ˆęœƒåœØčØ­å®šēš„ 'files.autoSaveDelay' ä¹‹å¾Œč‡Ŗå‹•å„²å­˜ć€‚", "files.autoSave.onFocusChange": "å·²č®Šę›“ēš„ęŖ”ę”ˆęœƒåœØē·Øč¼Æå™Øå¤±åŽ»ē„¦é»žę™‚č‡Ŗå‹•å„²å­˜ć€‚", @@ -38,5 +39,11 @@ "openEditorsVisible": "[é–‹ę”¾å¼ē·Øč¼Æå™Ø] ēŖ—ę ¼äø­é”Æē¤ŗēš„ē·Øč¼Æå™Øę•øē›®ć€‚å°‡å…¶čØ­å®šē‚ŗ 0 ä»„éš±č—ēŖ—ę ¼ć€‚", "dynamicHeight": "ęŽ§åˆ¶ [é–‹ę”¾å¼ē·Øč¼Æå™Ø] å€ę®µēš„é«˜åŗ¦ę˜Æå¦ę‡‰ä¾å…ƒē“ ę•øē›®å‹•ę…‹čŖæę•“ć€‚", "autoReveal": "ęŽ§åˆ¶ēø½ē®”ę˜Æå¦åœØé–‹å•ŸęŖ”ę”ˆę™‚č‡Ŗå‹•åŠ ä»„é”Æē¤ŗåŠéøå–ć€‚", - "enableDragAndDrop": "ęŽ§åˆ¶ēø½ē®”ę˜Æå¦ę‡‰č©²å…čØ±é€éŽę‹–ę”¾åŠŸčƒ½ē§»å‹•ęŖ”ę”ˆå’Œč³‡ę–™å¤¾ć€‚" + "enableDragAndDrop": "ęŽ§åˆ¶ēø½ē®”ę˜Æå¦ę‡‰č©²å…čØ±é€éŽę‹–ę”¾åŠŸčƒ½ē§»å‹•ęŖ”ę”ˆå’Œč³‡ę–™å¤¾ć€‚", + "sortOrder.default": "ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾ęœƒä¾ē…§åēØ±ä»„å­—ęÆé †åŗęŽ’åŗć€‚č³‡ę–™å¤¾ęœƒé”Æē¤ŗåœØęŖ”ę”ˆå‰ć€‚", + "sortOrder.mixed": "ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾ęœƒä¾ē…§åēØ±ä»„å­—ęÆé †åŗęŽ’åŗć€‚ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾ęœƒäŗ¤éŒÆęŽ’åˆ—ć€‚", + "sortOrder.filesFirst": "ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾ęœƒä¾ē…§åēØ±ä»„å­—ęÆé †åŗęŽ’åŗć€‚ęŖ”ę”ˆęœƒé”Æē¤ŗåœØč³‡ę–™å¤¾å‰ć€‚", + "sortOrder.type": "ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾ęœƒä¾ē…§å»¶ä¼øęØ”ēµ„ä»„å­—ęÆé †åŗęŽ’åŗć€‚č³‡ę–™å¤¾ęœƒé”Æē¤ŗåœØęŖ”ę”ˆå‰ć€‚", + "sortOrder.modified": "ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾ęœƒä¾ē…§ęœ€å¾Œäæ®ę”¹ę—„ęœŸä»„å­—ęÆé †åŗęŽ’åŗć€‚č³‡ę–™å¤¾ęœƒé”Æē¤ŗåœØęŖ”ę”ˆå‰ć€‚", + "sortOrder": "ęŽ§åˆ¶ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾åœØēø½ē®”äø­ēš„ęŽ’åˆ—é †åŗć€‚é™¤äŗ†é čØ­ęŽ’åŗå¤–ļ¼Œę‚Øä¹ŸåÆä»„å°‡é †åŗčØ­å®šē‚ŗ 'mixed' (ęŖ”ę”ˆčˆ‡č³‡ę–™å¤¾)态'type' (ä¾ęŖ”ę”ˆé”žåž‹)态'modified' (ä¾ęœ€å¾Œäæ®ę”¹ę—„ęœŸ) ꈖ 'filesFirst' (å°‡ęŖ”ę”ˆęŽ’åŗåœØč³‡ę–™å¤¾å‰)怂" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 91195575cae..7a6f0b075f7 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "åœØå³ę–¹ä½æē”Øē·Øč¼Æå™Øå·„å…·åˆ—äø­ēš„å‹•ä½œä¾† **復原** ę‚Øēš„č®Šę›“ļ¼Œęˆ–ä»„ę‚Øēš„č®Šę›“ **覆寫** ē£ē¢ŸäøŠēš„å…§å®¹", "discard": "ęØę£„", "overwrite": "覆寫", "retry": "é‡č©¦", diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 22aa2fcc887..19ea692c744 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "ę²’ęœ‰é–‹å•Ÿēš„č³‡ę–™å¤¾", "explorerSection": "ęŖ”ę”ˆēø½ē®”å€ę®µ", - "noWorkspaceHelp": "ę‚Øå°šęœŖé–‹å•Ÿč³‡ę–™å¤¾ć€‚", + "noFolderHelp": "ę‚Øå°šęœŖé–‹å•Ÿč³‡ę–™å¤¾ć€‚", "openFolder": "é–‹å•Ÿč³‡ę–™å¤¾" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..6d9b110ef6b --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "ęŖ”ę”ˆēø½ē®”" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 9d81839c00d..48600edd9b5 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,10 @@ { "fileInputAriaLabel": "č¼øå…„ęŖ”ę”ˆåēØ±ć€‚č«‹ęŒ‰ Enter éµē¢ŗčŖęˆ–ęŒ‰ Esc éµå–ę¶ˆć€‚", "filesExplorerViewerAriaLabel": "{0}ļ¼ŒęŖ”ę”ˆēø½ē®”", + "dropFolders": "č¦åœØå·„ä½œå€ę–°å¢žč³‡ę–™å¤¾å—Ž?", + "dropFolder": "č¦åœØå·„ä½œå€ę–°å¢žč³‡ę–™å¤¾å—Ž?", + "addFolders": "ę–°å¢žč³‡ę–™å¤¾(&A)", + "addFolder": "ę–°å¢žč³‡ę–™å¤¾(&A)", "confirmOverwriteMessage": "ē›®ēš„č³‡ę–™å¤¾äø­å·²å­˜åœØ '{0}'ć€‚č¦å–ä»£å®ƒå—Ž?", "irreversible": "ę­¤å‹•ä½œē„”ę³•å›žå¾©!", "replaceButtonLabel": "取代(&&R)" diff --git a/i18n/cht/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json b/i18n/cht/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json index 53460cbff1f..f93f9a1f277 100644 --- a/i18n/cht/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json @@ -9,6 +9,7 @@ "saveAll": "å…ØéƒØå„²å­˜", "closeAllUnmodified": "é—œé–‰ęœŖč®Šę›“ēš„ęŖ”ę”ˆ", "closeAll": "å…ØéƒØé—œé–‰", + "compareWithSaved": "čˆ‡å·²å„²å­˜ēš„ęŖ”ę”ˆęÆ”č¼ƒ", "close": "關閉", "closeOthers": "關閉其他" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/cht/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 953df2579ae..cd31ffc72aa 100644 --- a/i18n/cht/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 å€‹ęœŖå„²å­˜ēš„ęŖ”ę”ˆ", "dirtyFiles": "{0} å€‹ęœŖå„²å­˜ēš„ęŖ”ę”ˆ" } \ No newline at end of file diff --git a/src/typings/original-fs.d.ts b/i18n/cht/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json similarity index 82% rename from src/typings/original-fs.d.ts rename to i18n/cht/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json index 2a5636d2a44..79cb63cbd79 100644 --- a/src/typings/original-fs.d.ts +++ b/i18n/cht/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -2,9 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - -declare module 'original-fs' { - import * as fs from 'fs'; - - export = fs; +// Do not edit this file. It is machine generated. +{ + "label": "問锌" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index 2699d76ae09..7f9c895661a 100644 --- a/i18n/cht/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "åµęø¬åˆ°å•Ÿå‹•é€Ÿåŗ¦ę…¢", - "slow.detail": "ꊱꭉ! å…ˆå‰ēš„å•Ÿå‹•é€Ÿåŗ¦éŽę…¢ć€‚č«‹é‡ę–°å•Ÿå‹• '{0}' äø¦å•Ÿē”Øå‰–ęžåŠŸčƒ½ļ¼ŒåŒę™‚å°‡čØ­å®šęŖ”ęä¾›ēµ¦ęˆ‘å€‘ļ¼Œęˆ‘å€‘å°‡åŠŖåŠ›ęå‡å•Ÿå‹•ēš„å“č³Ŗć€‚", "prof.message": "å·²ęˆåŠŸå»ŗē«‹čØ­å®šęŖ”ć€‚", "prof.detail": "č«‹å»ŗē«‹å•é”Œļ¼Œäø¦ę‰‹å‹•é™„åŠ äø‹åˆ—ęŖ”ę”ˆ:\n{0}", "prof.restartAndFileIssue": "å»ŗē«‹å•é”Œäø¦é‡ę–°å•Ÿå‹•", diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index a92d2c49e8b..21867210659 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -8,6 +8,7 @@ "openGlobalKeybindings": "é–‹å•Ÿéµē›¤åæ«é€Ÿéµ", "openGlobalKeybindingsFile": "é–‹å•Ÿéµē›¤åæ«é€ŸéµęŖ”ę”ˆ", "openWorkspaceSettings": "é–‹å•Ÿå·„ä½œå€čØ­å®š", + "openFolderSettings": "é–‹å•Ÿč³‡ę–™å¤¾čØ­å®š", "configureLanguageBasedSettings": "čØ­å®ščŖžčØ€å°ˆå±¬čØ­å®š...", "languageDescriptionConfigured": "({0})", "pickLanguage": "éøå–čŖžčØ€" diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index ec85dfcb778..e7ace859036 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "ē„”ę³•åÆ«å…„čØ­å®š.č«‹é–‹å•Ÿä½æē”Øč€…čØ­å®šäø¦äæ®ę­£ęŖ”ę”ˆäø­ēš„éŒÆčŖ¤/č­¦å‘Šå¾Œå†č©¦äø€ę¬”.", + "emptyUserSettingsHeader": "å°‡ę‚Øēš„čØ­å®šę”¾ē½®åœØę­¤ä»„č¦†åÆ«é čØ­čØ­å®šć€‚", + "emptyWorkspaceSettingsHeader": "å°‡ę‚Øēš„čØ­å®šę”¾ē½®åœØę­¤ä»„č¦†åÆ«ä½æē”Øč€…čØ­å®šć€‚", + "emptyFolderSettingsHeader": "å°‡ę‚Øēš„č³‡ę–™å¤¾čØ­å®šę”¾ē½®åœØę­¤ä»„č¦†åÆ«å·„ä½œå€čØ­å®šēš„č³‡ę–™å¤¾čØ­å®šć€‚", + "defaultFolderSettingsTitle": "é čØ­č³‡ę–™å¤¾čØ­å®š", "defaultSettingsTitle": "預設設定", - "noSettingsFound": "ę‰¾äøåˆ°ä»»ä½•čØ­å®šć€‚", "editTtile": "編輯", "replaceDefaultValue": "åœØčØ­å®šäø­å–ä»£", "copyDefaultValue": "č¤‡č£½åˆ°čØ­å®š", "unsupportedPHPExecutablePathSetting": "é€™é …čØ­å®šåæ…é ˆę˜Æä½æē”Øč€…čØ­å®šć€‚č‹„č¦čØ­å®šå·„ä½œå€ēš„ PHPļ¼Œč«‹é–‹å•Ÿ PHP ęŖ”ę”ˆäø¦ęŒ‰äø€äø‹ē‹€ę…‹åˆ—äø­ēš„ [PHP 路徑]怂", - "unsupportedWorkspaceSetting": "é€™é …čØ­å®šåæ…é ˆę˜Æä½æē”Øč€…čØ­å®šć€‚" + "unsupportedWorkspaceSetting": "é€™é …čØ­å®šåæ…é ˆę˜Æä½æē”Øč€…čØ­å®šć€‚", + "unsupportedWorkbenchSetting": "ē›®å‰ē„”ę³•å„—ē”Øę­¤čØ­å®šć€‚č¦åœØę‚Øē›“ęŽ„é–‹å•Ÿę­¤č³‡ę–™å¤¾ę™‚ę‰ęœƒå„—ē”Øć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json index 68d504b7842..ea581bd5e89 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json @@ -7,5 +7,6 @@ "openFolderFirst": "å…ˆé–‹å•Ÿč³‡ę–™å¤¾ä»„å»ŗē«‹å·„ä½œå€čØ­å®š", "emptyKeybindingsHeader": "å°‡ę‚Øēš„ęŒ‰éµēµ„åˆę”¾å…„ę­¤ęŖ”ę”ˆäø­ä»„č¦†åÆ«é čØ­å€¼", "defaultKeybindings": "é čØ­ęŒ‰éµē¹«ēµé—œäæ‚", + "folderSettingsName": "{0} (č³‡ę–™å¤¾čØ­å®š)", "fail.createSettings": "焔法建立 '{0}' ({1})怂" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 8b6ad71cd4e..a459e99912a 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "noSettingsFound": "ę‰¾äøåˆ°ä»»ä½•čØ­å®šć€‚", + "folderSettingsDetails": "č³‡ę–™å¤¾čØ­å®š" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index 3899f5e3a45..4a5625894bd 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "ē¶“åøøä½æē”Øēš„", - "noSettings": "ę²’ęœ‰ä»»ä½•čØ­å®š", "defaultKeybindingsHeader": "å°‡ęŒ‰éµēµ„åˆę”¾å…„ę‚Øēš„ęŒ‰éµēµ„åˆęŖ”ę”ˆäø­åŠ ä»„č¦†åÆ«ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 6b7c584d6f2..510d9ec3ad3 100644 --- a/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "ē›®å‰å…§å®¹äø­ęœŖå•Ÿē”Øå‘½ä»¤ '{0}'怂", "recentlyUsed": "ęœ€čæ‘ä½æē”Øēš„", "morecCommands": "其他命令", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "ę²’ęœ‰ē›øē¬¦ēš„å‘½ä»¤" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index a4c089ec5ce..31900ffc0bc 100644 --- a/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -5,7 +5,5 @@ // Do not edit this file. It is machine generated. { "relaunchSettingMessage": "čØ­å®šå·²ē¶“č®Šę›“ļ¼Œåæ…é ˆé‡ę–°å•Ÿå‹•ę‰ęœƒē”Ÿę•ˆć€‚", - "relaunchSettingDetail": "č«‹ęŒ‰ [é‡ę–°å•Ÿå‹•] ęŒ‰éˆ•ä»„é‡ę–°å•Ÿå‹• {0} äø¦å•Ÿē”ØčØ­å®šć€‚", - "restart": "é‡ę–°å•Ÿå‹•", - "reload": "é‡ę–°č¼‰å…„" + "relaunchSettingDetail": "č«‹ęŒ‰ [é‡ę–°å•Ÿå‹•] ęŒ‰éˆ•ä»„é‡ę–°å•Ÿå‹• {0} äø¦å•Ÿē”ØčØ­å®šć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/cht/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index eea295d4066..8c7471e9952 100644 --- a/i18n/cht/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -6,5 +6,8 @@ { "editorGutterModifiedBackground": "äæ®ę”¹äø­ēš„č”Œę–¼ē·Øč¼Æå™Øé‚Šę”†ēš„čƒŒę™Æč‰²å½©", "editorGutterAddedBackground": "ę–°å¢žå¾Œēš„č”Œę–¼ē·Øč¼Æå™Øé‚Šę”†ēš„čƒŒę™Æč‰²å½©", - "editorGutterDeletedBackground": "åˆŖé™¤å¾Œēš„č”Œę–¼ē·Øč¼Æå™Øé‚Šę”†ēš„čƒŒę™Æč‰²å½©" + "editorGutterDeletedBackground": "åˆŖé™¤å¾Œēš„č”Œę–¼ē·Øč¼Æå™Øé‚Šę”†ēš„čƒŒę™Æč‰²å½©", + "overviewRulerModifiedForeground": "å·²äæ®ę”¹å…§å®¹ēš„ę¦‚č§€å°ŗč¦č‰²å½©ć€‚", + "overviewRulerAddedForeground": "å·²ę–°å¢žå…§å®¹ēš„ēš„ę¦‚č§€å°ŗč¦č‰²å½©ć€‚", + "overviewRulerDeletedForeground": "å·²åˆŖé™¤å…§å®¹ēš„ēš„ę¦‚č§€å°ŗč¦č‰²å½©ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index cafed393010..c0bccd6864c 100644 --- a/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "锯示 Git", - "installAdditionalSCMProviders": "å®‰č£é”å¤–SCMęä¾›č€…...", "source control": "åŽŸå§‹ęŖ”ęŽ§åˆ¶", "toggleSCMViewlet": "锯示 SCM", "view": "檢視" diff --git a/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 29eba85f240..e0a612882ae 100644 --- a/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "åŽŸå§‹ęŖ”ęŽ§åˆ¶ęä¾›č€…", + "hideRepository": "éš±č—", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "å®‰č£é”å¤–SCMęä¾›č€…...", + "no open repo": "ę²’ęœ‰ä½æē”Øäø­ēš„åŽŸå§‹ęŖ”ęŽ§åˆ¶ęä¾›č€…ć€‚", "source control": "åŽŸå§‹ęŖ”ęŽ§åˆ¶", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 1a4174cfa0b..7bbfb9ecd08 100644 --- a/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "å‰å¾€å·„ä½œå€äø­ēš„ē¬¦č™Ÿ...", "name": "ęœå°‹", - "showSearchViewlet": "é”Æē¤ŗęœå°‹", + "search": "ęœå°‹", "view": "檢視", - "findInFiles": "åœØęŖ”ę”ˆäø­å°‹ę‰¾", "openAnythingHandlerDescription": "å‰å¾€ęŖ”ę”ˆ", "openSymbolDescriptionNormal": "å‰å¾€å·„ä½œå€äø­ēš„ē¬¦č™Ÿ", "searchOutputChannelTitle": "ęœå°‹", @@ -16,7 +15,5 @@ "exclude": "設定 Glob ęØ”å¼ļ¼Œä»„ęŽ’é™¤äøč¦ęœå°‹ēš„ęŖ”ę”ˆåŠč³‡ę–™å¤¾ć€‚č«‹å¾ž file.exclude čØ­å®šē¹¼ę‰æę‰€ęœ‰ēš„ Glob ęØ”å¼ć€‚", "exclude.boolean": "č¦ē¬¦åˆęŖ”ę”ˆč·Æå¾‘ēš„ Glob ęØ”å¼ć€‚čØ­ē‚ŗ True ꈖ False åÆå•Ÿē”Øęˆ–åœē”ØęØ”å¼ć€‚", "exclude.when": "åœØē›øē¬¦ęŖ”ę”ˆåŒå±¤ē“šäøŠé”å¤–ēš„ęŖ¢ęŸ„ć€‚č«‹ä½æē”Ø $(basename) ä½œē‚ŗē›øē¬¦ęŖ”ę”ˆåēØ±ēš„č®Šę•øć€‚", - "useRipgrep": "ęŽ§åˆ¶ę˜Æå¦č¦åœØę–‡å­—ęœå°‹äø­ä½æē”Ø ripgrep", - "useIgnoreFilesByDefault": "ęŽ§åˆ¶åœØęœå°‹ę–°ēš„å·„ä½œå€ę™‚ļ¼Œę˜Æå¦č¦ę ¹ę“šé čØ­ä½æē”Ø .gitignore 及 .ignore ęŖ”ę”ˆć€‚", "search.quickOpen.includeSymbols": "čØ­å®šä»„å°‡å…ØåŸŸē¬¦č™Ÿęœå°‹ēš„ēµęžœē“å…„ Quick Open ēš„ęŖ”ę”ˆēµęžœäø­ć€‚" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 5d095421436..0c44c7464bb 100644 --- a/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,16 +4,23 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "é”Æē¤ŗäø‹äø€å€‹ęœå°‹åŒ…å«ęØ”å¼", + "previousSearchIncludePattern": "é”Æē¤ŗäøŠäø€å€‹ęœå°‹åŒ…å«ęØ”å¼", + "nextSearchExcludePattern": "é”Æē¤ŗäø‹äø€å€‹ęœå°‹ęŽ’é™¤ęØ”å¼", + "previousSearchExcludePattern": "é”Æē¤ŗäøŠäø€å€‹ęœå°‹ęŽ’é™¤ęØ”å¼", "nextSearchTerm": "é”Æē¤ŗäø‹äø€å€‹ęœå°‹å­—č©ž", "previousSearchTerm": "é”Æē¤ŗäøŠäø€å€‹ęœå°‹å­—č©ž", "focusNextInputBox": "čšē„¦ę–¼äø‹äø€å€‹č¼øå…„ę–¹å”Š", "focusPreviousInputBox": "čšē„¦ę–¼äøŠäø€å€‹č¼øå…„ę–¹å”Š", + "showSearchViewlet": "é”Æē¤ŗęœå°‹", + "findInFiles": "åœØęŖ”ę”ˆäø­å°‹ę‰¾", "replaceInFiles": "ęŖ”ę”ˆäø­å–ä»£", + "findInWorkspace": "åœØå·„ä½œå€äø­å°‹ę‰¾...", + "findInFolder": "åœØč³‡ę–™å¤¾äø­å°‹ę‰¾...", "RefreshAction.label": "é‡ę–°ę•“ē†", "ClearSearchResultsAction.label": "ęø…é™¤ęœå°‹ēµęžœ", "FocusNextSearchResult.label": "čšē„¦ę–¼äø‹äø€å€‹ęœå°‹ēµęžœ", "FocusPreviousSearchResult.label": "čšē„¦ę–¼äøŠäø€å€‹ęœå°‹ēµęžœ", - "RemoveAction.label": "移除", "file.replaceAll.label": "å…ØéƒØå–ä»£", "match.replace.label": "取代" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json b/i18n/cht/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json index 0780f0f62bd..5a3224c66f5 100644 --- a/i18n/cht/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "searchFolderMatch.other.label": "å…¶ä»–ęŖ”ę”ˆ", + "searchFileMatches": "ę‰¾åˆ° {0} å€‹ęŖ”ę”ˆ", + "searchFileMatch": "ę‰¾åˆ° {0} å€‹ęŖ”ę”ˆ", "searchMatches": "ę‰¾åˆ° {0} 個相符", "searchMatch": "ę‰¾åˆ° {0} 個相符", + "folderMatchAriaLabel": "č³‡ę–™å¤¾ę ¹ē›®éŒ„ {1} äø­ęœ‰ {0} å€‹ē›øē¬¦ļ¼Œęœå°‹ēµęžœ", "fileMatchAriaLabel": "資料夾 {2} ēš„ęŖ”ę”ˆ {1} äø­ęœ‰ {0} å€‹ē›øē¬¦ļ¼Œęœå°‹ēµęžœ", "replacePreviewResultAria": "ę ¹ę“šę–‡å­—({3})在({2})ę¬„ä½åˆ—č”Øäø­å°‡({1})替代為文字{{0}}", "searchResultAria": "ę ¹ę“šę–‡å­—({2})並在({1})ę¬„ä½åˆ—č”Øäø­ę‰¾åˆ°ē¬¦åˆ({0})ēš„é …ē›®" diff --git a/i18n/cht/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/cht/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index ffc0ef1d621..a502d53fe8c 100644 --- a/i18n/cht/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "č¦ęŽ’é™¤ēš„ęŖ”ę”ˆ", "label.excludes": "ęœå°‹ęŽ’é™¤ęØ”å¼", "replaceAll.confirmation.title": "å…ØéƒØå–ä»£", - "replaceAll.confirm.button": "取代", + "replaceAll.confirm.button": "取代(&&R)", "replaceAll.occurrence.file.message": "已將 {1} å€‹ęŖ”ę”ˆäø­ēš„ {0} å€‹ē›øē¬¦é …ē›®å–ä»£ē‚ŗ '{2}'怂", "removeAll.occurrence.file.message": "已取代 {1} å€‹ęŖ”ę”ˆäø­ēš„ {0} 個相符項目。", "replaceAll.occurrence.files.message": "已將 {1} å€‹ęŖ”ę”ˆäø­ēš„ {0} å€‹ē›øē¬¦é …ē›®å–ä»£ē‚ŗ '{2}'怂", @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "要將 {1} å€‹ęŖ”ę”ˆäø­ēš„ {0} å€‹ē›øē¬¦é …ē›®å–ä»£ē‚ŗ '{2}' 嗎?", "replaceAll.occurrences.files.confirmation.message": "č¦å–ä»£ {1} å€‹ęŖ”ę”ˆäø­ēš„ {0} å€‹ē›øē¬¦é …ē›®å—Ž?", "treeAriaLabel": "ęœå°‹ēµęžœ", + "searchPathNotFoundError": "ę‰¾äøåˆ°ęœå°‹č·Æå¾‘: {0}", "searchMaxResultsWarning": "ēµęžœé›†åŖåŒ…å«ę‰€ęœ‰ē¬¦åˆé …ēš„å­é›†ć€‚č«‹ęä¾›ę›“å…·é«”ēš„ęœå°‹ę¢ä»¶ä»„ēø®å°ēµęžœēÆ„åœć€‚", "searchCanceled": "åœØåÆčƒ½ę‰¾åˆ°ä»»ä½•ēµęžœä¹‹å‰å·²å–ę¶ˆęœå°‹ - ", "noResultsIncludesExcludes": "在 '{0}' äø­ę‰¾äøåˆ°ęŽ’é™¤ '{1}' ēš„ēµęžœ - ", "noResultsIncludes": "在 '{0}' äø­ę‰¾äøåˆ°ēµęžœ - ", "noResultsExcludes": "ę‰¾äøåˆ°ęŽ’é™¤ '{0}' ēš„ēµęžœ - ", - "noResultsFound": "ę‰¾äøåˆ°ēµęžœć€‚č«‹ęŖ¢é–±ę‰€čØ­å®šęŽ’é™¤ēš„čØ­å®š - ", + "noResultsFound": "ę‰¾äøåˆ°ēµęžœć€‚č«‹ęŖ¢é–±ę‰€čØ­å®šēš„ęŽ’é™¤å’Œåæ½ē•„ęŖ”ę”ˆä¹‹čØ­å®š - ", "rerunSearch.message": "å†ę¬”ęœå°‹", "rerunSearchInAll.message": "åœØę‰€ęœ‰ęŖ”ę”ˆäø­å†ę¬”ęœå°‹", "openSettings.message": "é–‹å•ŸčØ­å®š", + "openSettings.learnMore": "深兄了解", "ariaSearchResultsStatus": "ęœå°‹å‚³å›ž {1} å€‹ęŖ”ę”ˆäø­ēš„ {0} å€‹ēµęžœ", "search.file.result": "{1} å€‹ęŖ”ę”ˆäø­ęœ‰ {0} å€‹ēµęžœ", "search.files.result": "{1} å€‹ęŖ”ę”ˆäø­ęœ‰ {0} å€‹ēµęžœ", diff --git a/i18n/cht/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/cht/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..1b13478684c --- /dev/null +++ b/i18n/cht/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "å·„ä½œå€å…§ē„”ę­¤åēØ±č³‡ę–™å¤¾: {0}" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index de9b42f6ace..fb65a26db13 100644 --- a/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "ę’å…„ēØ‹å¼ē¢¼ē‰‡ę®µ" + "snippet.suggestions.label": "ę’å…„ēØ‹å¼ē¢¼ē‰‡ę®µ", + "sep.userSnippet": "ä½æē”Øč€…ēØ‹å¼ē¢¼ē‰‡ę®µ", + "sep.extSnippet": "å»¶ä¼øęØ”ēµ„ēØ‹å¼ē¢¼ē‰‡ę®µ" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index bfbf6a8011c..bfcd3e1c0bb 100644 --- a/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "`contributes.{0}.language` äø­ēš„äøę˜ŽčŖžčØ€ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.0": "'contributes.{0}.path' äø­ę‡‰ęœ‰å­—äø²ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.1": "ę““å……åŠŸčƒ½č³‡ę–™å¤¾ ({2}) ę‡‰åŒ…å« 'contributes.{0}.path' ({1})ć€‚é€™åÆčƒ½ęœƒå°Žč‡“ę““å……åŠŸčƒ½ē„”ę³•ē§»ę¤ć€‚", + "vscode.extension.contributes.snippets": "ęä¾›ēØ‹å¼ē¢¼ē‰‡ę®µć€‚", + "vscode.extension.contributes.snippets-language": "č¦äŗˆä»„ęä¾›ę­¤ēØ‹å¼ē¢¼ē‰‡ę®µēš„čŖžčØ€č­˜åˆ„ē¢¼ć€‚", + "vscode.extension.contributes.snippets-path": "ēØ‹å¼ē¢¼ē‰‡ę®µęŖ”ę”ˆēš„č·Æå¾‘ć€‚ę­¤č·Æå¾‘ę˜Æę““å……åŠŸčƒ½č³‡ę–™å¤¾ēš„ē›øå°č·Æå¾‘ļ¼Œč€Œäø”äø€čˆ¬ęœƒä»„ './snippets/' 開頭怂", + "badFile": "ē„”ę³•č®€å–ēØ‹å¼ē¢¼ē‰‡ę®µęŖ”ę”ˆ \"{0}\"怂", "source.snippet": "ä½æē”Øč€…ēØ‹å¼ē¢¼ē‰‡ę®µ", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0},{1}" diff --git a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 095028d433a..aabd84b6270 100644 --- a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "čØ­å®šé¢ęæļ¼Œē”Øę–¼å‘ˆē¾å·„ä½œēš„č¼øå‡ŗäø¦č®€å–å…¶č¼øå…„ć€‚", "JsonSchema.tasks.presentation.echo": "ęŽ§åˆ¶ę˜Æå¦ęœƒå°‡åŸ·č”Œēš„å‘½ä»¤å›žę‡‰ēµ¦é¢ęæć€‚é čØ­ē‚ŗ true怂", "JsonSchema.tasks.presentation.focus": "ęŽ§åˆ¶é¢ęæę˜Æå¦č¦ęŽ„å—ē„¦é»žć€‚é čØ­ē‚ŗ trueć€‚č‹„čØ­å®šē‚ŗ trueļ¼Œä¹Ÿęœƒä½æé”Æē¤ŗé¢ęæć€‚", + "JsonSchema.tasks.presentation.reveal.always": "åŸ·č”Œę­¤å·„ä½œę™‚ļ¼Œäø€å¾‹é”Æē¤ŗēµ‚ē«Æę©Ÿć€‚", + "JsonSchema.tasks.presentation.reveal.silent": "ę²’ęœ‰čˆ‡å·„ä½œē›øé—œēš„å•é”ŒęÆ”å°å™Øļ¼Œäø”åŸ·č”ŒęœŖē™¼ē”ŸéŒÆčŖ¤ę™‚ļ¼Œę‰é”Æē¤ŗēµ‚ē«Æę©Ÿć€‚", + "JsonSchema.tasks.presentation.reveal.never": "åŸ·č”Œę­¤å·„ä½œę™‚ļ¼Œę°øäøé”Æē¤ŗēµ‚ē«Æę©Ÿć€‚", "JsonSchema.tasks.presentation.reveals": "ęŽ§åˆ¶ę˜Æå¦č¦é”Æē¤ŗåŸ·č”Œå·„ä½œēš„é¢ęæć€‚é čØ­ē‚ŗ [永遠]怂", "JsonSchema.tasks.presentation.instance": "ęŽ§åˆ¶é¢ęæę˜Æå¦ęœƒåœØå·„ä½œä¹‹é–“å…±ē”Øć€å°ˆå±¬ę–¼ę­¤å·„ä½œęˆ–ę˜ÆåœØęÆå€‹å›žåˆå»ŗē«‹äø€å€‹ę–°ēš„é¢ęæć€‚", "JsonSchema.tasks.terminal": "å·²ę·˜ę±°ēµ‚ē«Æę©Ÿå±¬ę€§ć€‚č«‹ę”¹ē”Øē°”å ±", @@ -22,7 +25,6 @@ "JsonSchema.tasks.group.test": "å°‡å·„ä½œęØ™čØ˜ē‚ŗēµ„å»ŗå·„ä½œļ¼Œäø¦äø”čƒ½ä½æē”Ø [執蔌測試巄作] å‘½ä»¤å­˜å–ć€‚", "JsonSchema.tasks.group.none": "ęŒ‡ę“¾å·„ä½œåˆ°ę²’ęœ‰ē¾¤ēµ„", "JsonSchema.tasks.group": "å®šē¾©å·„ä½œå±¬ę–¼å“Ŗå€‹åŸ·č”Œē¾¤ēµ„ć€‚ę”Æę“å°‡ ć€Œēµ„å»ŗć€ę–°å¢žåˆ°ēµ„å»ŗē¾¤ēµ„ļ¼Œä»„åŠå°‡ć€Œęø¬č©¦ć€ę–°å¢žåˆ°ęø¬č©¦ē¾¤ēµ„ć€‚", - "JsonSchema.tasks.type": "å®šē¾©å·„ä½œę˜Æä½œē‚ŗč™•ē†åŗęˆ–ę®¼å±¤äø­ēš„å‘½ä»¤åŸ·č”Œć€‚é čØ­ē‚ŗč™•ē†åŗć€‚", "JsonSchema.version": "ēµ„ę…‹ē‰ˆęœ¬č™Ÿē¢¼", "JsonSchema.tasks.identifier": "ē”Øä»„åƒč€ƒåœØ launch.json ꈖ dependsOn å­å„äø­å·„ä½œēš„ä½æē”Øč€…å®šē¾©č­˜åˆ„ē¢¼ć€‚", "JsonSchema.tasks.taskLabel": "å·„ä½œēš„ęØ™ē±¤", @@ -35,8 +37,10 @@ "JsonSchema.tasks.customize.deprecated": "å·²ę·˜ę±°č‡ŖčØ‚å±¬ę€§ć€‚č«‹åƒé–± 1.14 ē‰ˆęœ¬č³‡čØŠļ¼Œä»„äŗ†č§£å¦‚ä½•é·ē§»åˆ°ę–°ēš„å·„ä½œč‡ŖčØ‚ę–¹ę³•", "JsonSchema.tasks.showOputput.deprecated": "å·²ę·˜ę±°å±¬ę€§ showOutputć€‚č«‹ę”¹ē”Øē°”å ±å±¬ę€§äø­ēš„é”Æē¤ŗå±¬ę€§ć€‚ę­¤å¤–ä¹Ÿč«‹åƒé–± 1.14 ē‰ˆęœ¬č³‡čØŠć€‚", "JsonSchema.tasks.echoCommand.deprecated": "å·²ę·˜ę±°å±¬ę€§ echoCommandć€‚č«‹ę”¹ē”Øē°”å ±å±¬ę€§äø­ēš„å›žę‡‰å±¬ę€§ć€‚ę­¤å¤–ä¹Ÿč«‹åƒé–± 1.14 ē‰ˆęœ¬č³‡čØŠć€‚ ", + "JsonSchema.tasks.suppressTaskName.deprecated": "屬性 suppressTaskName å·²ę·˜ę±°ć€‚č«‹ę”¹ē‚ŗå°‡å‘½ä»¤čˆ‡å…¶å¼•ę•øå…§åµŒč‡³å·„ä½œć€‚å¦č«‹åƒé–± 1.14 ē‰ˆęœ¬č³‡čØŠć€‚", "JsonSchema.tasks.isBuildCommand.deprecated": "å·²ę·˜ę±°å±¬ę€§ isBuildCommandć€‚č«‹ę”¹ē”Øē¾¤ēµ„å±¬ę€§ć€‚ę­¤å¤–ä¹Ÿč«‹åƒé–± 1.14 ē‰ˆęœ¬č³‡čØŠć€‚", "JsonSchema.tasks.isTestCommand.deprecated": "å·²ę·˜ę±°å±¬ę€§ isTestCommandć€‚č«‹ę”¹ē”Øē¾¤ēµ„å±¬ę€§ć€‚ę­¤å¤–ä¹Ÿč«‹åƒé–± 1.14 ē‰ˆęœ¬č³‡čØŠć€‚", + "JsonSchema.tasks.taskSelector.deprecated": "屬性 taskSelector å·²ę·˜ę±°ć€‚č«‹ę”¹ē‚ŗå°‡å‘½ä»¤čˆ‡å…¶å¼•ę•øå…§åµŒč‡³å·„ä½œć€‚å¦č«‹åƒé–± 1.14 ē‰ˆęœ¬č³‡čØŠć€‚ ", "JsonSchema.windows": "Windows ē‰¹å®šå‘½ä»¤ēµ„ę…‹", "JsonSchema.mac": "Mac ē‰¹å®šå‘½ä»¤ēµ„ę…‹", "JsonSchema.linux": "Linux ē‰¹å®šå‘½ä»¤ēµ„ę…‹" diff --git a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index e34e2f41cb7..c9cc1fc25d5 100644 --- a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "巄作", - "ConfigureTaskRunnerAction.noWorkspace": "é€™äŗ›å·„ä½œåŖęœƒå‡ŗē¾åœØå·„ä½œå€č³‡ę–™å¤¾äø­ć€‚", - "ConfigureTaskRunnerAction.quickPick.template": "éøå–å·„ä½œåŸ·č”Œå™Ø", - "ConfigureTaskRunnerAction.autoDetecting": "自動偵測 {0} ēš„å·„ä½œ", - "ConfigureTaskRunnerAction.autoDetect": "č‡Ŗå‹•åµęø¬å·„ä½œē³»ēµ±å¤±ę•—ć€‚ę­£åœØä½æē”Øé čØ­ēÆ„ęœ¬ć€‚å¦‚éœ€č©³ē“°č³‡ę–™ļ¼Œč«‹åƒé–±å·„ä½œč¼øå‡ŗć€‚", - "ConfigureTaskRunnerAction.autoDetectError": "č‡Ŗå‹•åµęø¬å·„ä½œē³»ēµ±ē”¢ē”Ÿēš„éŒÆčŖ¤ć€‚å¦‚éœ€č©³ē“°č³‡ę–™ļ¼Œč«‹ęŸ„ēœ‹å·„ä½œč¼øå‡ŗć€‚", - "ConfigureTaskRunnerAction.failed": "ē„”ę³•åœØ '.vscode' 資料夾中建立 'tasks.json' ęŖ”ę”ˆć€‚å¦‚éœ€č©³ē“°č³‡čØŠļ¼Œč«‹åƒé–±å·„ä½œč¼øå‡ŗć€‚", - "ConfigureTaskRunnerAction.label": "čØ­å®šå·„ä½œåŸ·č”Œå™Ø", + "ConfigureTaskRunnerAction.label": "設定巄作", "ConfigureBuildTaskAction.label": "設定建置巄作", "CloseMessageAction.label": "關閉", "ShowTerminalAction.label": "ęŖ¢č¦–ēµ‚ē«Æę©Ÿ", @@ -19,19 +13,25 @@ "manyMarkers": "99+", "runningTasks": "é”Æē¤ŗåŸ·č”Œäø­ēš„å·„ä½œ", "tasks": "巄作", - "TaskSystem.noHotSwap": "č®Šę›“å·„ä½œåŸ·č”Œå¼•ę“Žéœ€č¦é‡ę–°å•Ÿå‹• VS Codeć€‚å·²ē•„éŽč®Šę›“ć€‚", + "TaskSystem.noHotSwap": "åæ…é ˆé‡ę–°č¼‰å…„č¦–ēŖ—ę‰åÆč®Šę›“åŸ·č”Œä½æē”Øäø­å·„ä½œēš„å·„ä½œåŸ·č”Œå¼•ę“Ž", "TaskService.noBuildTask1": "ęœŖå®šē¾©ä»»ä½•å»ŗē½®å·„ä½œć€‚č«‹ä½æē”Ø 'isBuildCommand' ęØ™čØ˜ tasks.json ęŖ”ę”ˆäø­ēš„å·„ä½œć€‚", "TaskService.noBuildTask2": "ęœŖå®šē¾©ä»»ä½•ēµ„å»ŗå·„ä½œļ¼Œč«‹åœØ tasks.json ęŖ”ę”ˆäø­å°‡å·„ä½œęØ™čØ˜ē‚ŗ 'build' 群組。", "TaskService.noTestTask1": "ęœŖå®šē¾©ä»»ä½•å»ŗē½®å·„ä½œć€‚č«‹ä½æē”Ø 'isTestCommand' ęØ™čØ˜ tasks.json ęŖ”ę”ˆäø­ēš„å·„ä½œć€‚", "TaskService.noTestTask2": "ęœŖå®šē¾©ä»»ä½•ęø¬č©¦å·„ä½œļ¼Œč«‹åœØ tasks.json ęŖ”ę”ˆäø­å°‡å·„ä½œęØ™čØ˜ē‚ŗ 'test' 群組。", "TaskServer.noTask": "ę‰¾äøåˆ°ę‰€č¦ę±‚č¦åŸ·č”Œēš„å·„ä½œ {0}怂", + "TaskService.associate": "å»ŗē«‹é—œčÆ", + "TaskService.attachProblemMatcher.continueWithout": "åœØäøęŽƒęå·„ä½œč¼øå‡ŗēš„ęƒ…ę³äø‹ē¹¼ēŗŒ", "TaskService.attachProblemMatcher.never": "ę°øäøęŽƒęå·„ä½œč¼øå‡ŗ", "TaskService.attachProblemMatcher.learnMoreAbout": "ę·±å…„äŗ†č§£ęŽƒęå·„ä½œč¼øå‡ŗ", + "selectProblemMatcher": "éøå–éŒÆčŖ¤å’Œč­¦å‘Šēš„ēØ®é”žä»„ęŽƒęå·„ä½œč¼øå‡ŗ", "customizeParseErrors": "ē•¶å‰ēš„å·„ä½œēµ„ę…‹å­˜åœØéŒÆčŖ¤.č«‹ę›“ę­£éŒÆčŖ¤å†åŸ·č”Œå·„ä½œ.", "moreThanOneBuildTask": "å®šē¾©äŗ†å¾ˆå¤šå»ŗē½®å·„ä½œę–¼tasks.json.åŸ·č”Œē¬¬äø€å€‹.", + "TaskSystem.activeSame.background": "巄作 '{0}' å·²åœØä½æē”Øäø­ļ¼Œäø”č™•ę–¼čƒŒę™ÆęØ”å¼äø­ć€‚č«‹ä½æē”Øå·„ä½œåŠŸčƒ½č”Øēš„ [ēµ‚ę­¢å·„ä½œ...] 將其終止。", + "TaskSystem.activeSame.noBackground": "巄作 '{0}' å·²åœØä½æē”Øäø­ć€‚č«‹ä½æē”Øå·„ä½œåŠŸčƒ½č”Øēš„ [ēµ‚ę­¢å·„ä½œ...] 將其終止。 ", "TaskSystem.active": "å·²ęœ‰å·„ä½œåœØåŸ·č”Œć€‚č«‹å…ˆēµ‚ę­¢č©²å·„ä½œļ¼Œē„¶å¾Œå†åŸ·č”Œå…¶ä»–å·„ä½œć€‚", "TaskSystem.restartFailed": "ē„”ę³•ēµ‚ę­¢å†é‡ę–°å•Ÿå‹•å·„ä½œ {0}", "TaskSystem.configurationErrors": "錯誤: ęä¾›ēš„å·„ä½œēµ„ę…‹å…·ęœ‰é©—č­‰éŒÆčŖ¤č€Œē„”ę³•ä½æē”Øć€‚č«‹å…ˆę›“ę­£é€™äŗ›éŒÆčŖ¤ć€‚", + "taskService.ignoreingFolder": "ē•„éŽå·„ä½œå€č³‡ę–™å¤¾ {0} ēš„å·„ä½œēµ„ę…‹ć€‚ę‰€ęœ‰ēš„č³‡ę–™å¤¾éƒ½åæ…é ˆä½æē”Øå·„ä½œē‰ˆęœ¬ 2.0.0 ę‰åÆä½æē”Øå¤šč³‡ę–™å¤¾å·„ä½œå€å·„ä½œę”Æę“\n", "TaskSystem.invalidTaskJson": "錯誤: tasks.json ęŖ”ę”ˆēš„å…§å®¹å…·ęœ‰čŖžę³•éŒÆčŖ¤ć€‚č«‹ę›“ę­£éŒÆčŖ¤ļ¼Œå†åŸ·č”Œå·„ä½œ\n", "TaskSystem.runningTask": "ęœ‰äø€å€‹å·„ä½œę­£åœØåŸ·č”Œć€‚č¦ēµ‚ę­¢å·„ä½œå—Ž?", "TaskSystem.terminateTask": "ēµ‚ę­¢å·„ä½œ(&&T)", @@ -43,23 +43,33 @@ "recentlyUsed": "ęœ€čæ‘ä½æē”Øēš„å·„ä½œ", "configured": "čØ­å®šēš„å·„ä½œ", "detected": "åµęø¬åˆ°ēš„å·„ä½œ", + "TaskService.ignoredFolder": "äø‹åˆ—å·„ä½œå€č³‡ę–™å¤¾å› ē‚ŗä½æē”Øå·„ä½œē‰ˆęœ¬ 0.1.0ļ¼Œę‰€ä»„å·²ē•„éŽ:", + "TaskService.notAgain": "äøč¦å†é”Æē¤ŗ", + "TaskService.ok": "確定", + "TaskService.pickRunTask": "č«‹éøå–č¦åŸ·č”Œēš„å·„ä½œ", + "TaslService.noEntryToRun": "ę‰¾äøåˆ°ä»»ä½•č¦åŸ·č”Œēš„å·„ä½œć€‚č«‹čØ­å®šå·„ä½œ...", "TaskService.fetchingBuildTasks": "ę­£åœØę“·å–ēµ„å»ŗå·„ä½œ...", - "TaskService.noBuildTaskTerminal": "ę‰¾äøåˆ°ä»»ä½•ēµ„å»ŗå·„ä½œć€‚č«‹ęŒ‰äø€äø‹ [čØ­å®šēµ„å»ŗå·„ä½œ] ä»„åŠ ä»„å®šē¾©ć€‚", "TaskService.pickBuildTask": "č«‹éøå–č¦åŸ·č”Œēš„ēµ„å»ŗå·„ä½œ", + "TaskService.noBuildTask": "ę‰¾äøåˆ°ä»»ä½•č¦åŸ·č”Œēš„ēµ„å»ŗå·„ä½œć€‚č«‹čØ­å®šå·„ä½œ...", "TaskService.fetchingTestTasks": "ę­£åœØę“·å–ęø¬č©¦å·„ä½œ...", - "TaskService.noTestTaskTerminal": "ę‰¾äøåˆ°ä»»ä½•ęø¬č©¦å·„ä½œć€‚č«‹ęŒ‰äø€äø‹ [čØ­å®šęø¬č©¦åŸ·č”Œå™Ø] ä»„åŠ ä»„å®šē¾©ć€‚", "TaskService.pickTestTask": "č«‹éøå–č¦åŸ·č”Œēš„ęø¬č©¦å·„ä½œ", - "TaskService.noTaskRunning": "ē›®å‰ę²’ęœ‰åŸ·č”Œäø­ēš„å·„ä½œć€‚", + "TaskService.noTestTaskTerminal": "ę‰¾äøåˆ°ä»»ä½•č¦åŸ·č”Œēš„ęø¬č©¦å·„ä½œć€‚č«‹čØ­å®šå·„ä½œ...", "TaskService.tastToTerminate": "č«‹éøå–č¦ēµ‚ę­¢ēš„å·„ä½œ", + "TaskService.noTaskRunning": "ē›®å‰ęœŖåŸ·č”Œä»»ä½•å·„ä½œ", "TerminateAction.noProcess": "å•Ÿå‹•ēš„č™•ē†åŗå·²äøå­˜åœØć€‚å¦‚ęžœå·„ä½œē¹č”ēš„čƒŒę™Æå·„ä½œēµęŸļ¼ŒVS Code åÆčƒ½ęœƒē”¢ē”Ÿå­¤ē«‹ēš„č™•ē†åŗć€‚", "TerminateAction.failed": "ē„”ę³•ēµ‚ę­¢åŸ·č”Œäø­ēš„å·„ä½œ", - "TaskService.noTaskToRestart": "ę²’ęœ‰ä»»ä½•č¦é‡ę–°å•Ÿå‹•ēš„å·„ä½œć€‚", "TaskService.tastToRestart": "č«‹éøå–č¦é‡ę–°å•Ÿå‹•ēš„å·„ä½œ", - "TaskService.defaultBuildTaskExists": "已經將 {0} ęØ™čØ˜ē‚ŗé čØ­ēµ„å»ŗå·„ä½œć€‚", + "TaskService.noTaskToRestart": "ę²’ęœ‰č¦é‡ę–°å•Ÿå‹•ēš„å·„ä½œ", + "TaskService.template": "éøå–å·„ä½œēÆ„ęœ¬", + "TaskService.createJsonFile": "å¾žēÆ„ęœ¬å»ŗē«‹ tasks.json ęŖ”ę”ˆ", + "TaskService.openJsonFile": "開啟 tasks.json ęŖ”ę”ˆ", + "TaskService.pickTask": "éøå–č¦čØ­å®šēš„å·„ä½œ", + "TaskService.defaultBuildTaskExists": "已經將 {0} ęØ™čØ˜ē‚ŗé čØ­ēµ„å»ŗå·„ä½œ", "TaskService.pickDefaultBuildTask": "č«‹éøå–č¦ē”Øä½œé čØ­ēµ„å»ŗå·„ä½œēš„å·„ä½œ", "TaskService.defaultTestTaskExists": "已經將 {0} ęØ™čØ˜ē‚ŗé čØ­ęø¬č©¦å·„ä½œć€‚", "TaskService.pickDefaultTestTask": "č«‹éøå–č¦ē”Øä½œé čØ­ęø¬č©¦å·„ä½œēš„å·„ä½œ", - "TaskService.noTaskIsRunning": "ę²’ęœ‰åŸ·č”Œäø­ēš„å·„ä½œć€‚", + "TaskService.pickShowTask": "éøå–č¦é”Æē¤ŗč¼øå‡ŗēš„å·„ä½œ", + "TaskService.noTaskIsRunning": "ęœŖåŸ·č”Œä»»ä½•å·„ä½œ", "ShowLogAction.label": "é”Æē¤ŗå·„ä½œčØ˜éŒ„ęŖ”", "RunTaskAction.label": "執蔌巄作", "RestartTaskAction.label": "é‡ę–°é–‹å§‹åŸ·č”Œå·„ä½œ", diff --git a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 871f4fbea5a..a45b9045bdb 100644 --- a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "åŸ·č”Œå·„ä½œę™‚ē™¼ē”Ÿäøę˜ŽéŒÆčŖ¤ć€‚å¦‚éœ€č©³ē“°č³‡čØŠļ¼Œč«‹åƒé–±å·„ä½œč¼øå‡ŗčØ˜éŒ„ęŖ”ć€‚", + "dependencyFailed": "ē„”ę³•č§£ę±ŗåœØå·„ä½œå€č³‡ę–™å¤¾ '{1}' äø­ēš„ē›øä¾å·„ä½œ '{0}'", "TerminalTaskSystem.terminalName": "巄作 - {0}", "reuseTerminal": "å·„ä½œå°‡č¢«é‡ę–°å•Ÿē”Ø.ęŒ‰ä»»ę„éµé—œé–‰.", "TerminalTaskSystem": "ē„”ę³•åœØ UNC ē£ē¢Ÿę©ŸäøŠåŸ·č”Œę®¼å±¤å‘½ä»¤ć€‚", diff --git a/i18n/cht/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/cht/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index 49ff9315f1a..61b47eff6f8 100644 --- a/i18n/cht/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,9 +11,12 @@ "ConfigurationParser.unknownMatcherKind": "č­¦å‘Š: å®šē¾©ēš„å•é”ŒęÆ”å°å™ØęœŖēŸ„ć€‚ę”Æę“ēš„é”žåž‹ē‚ŗ string | ProblemMatcher | (string | ProblemMatcher)[]怂\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "錯誤: problemMatcher åƒč€ƒē„”ę•ˆ: {0}\n", "ConfigurationParser.noTaskType": "錯誤: å·„ä½œēµ„ę…‹åæ…é ˆå…·ęœ‰åž‹åˆ„å±¬ę€§ć€‚å°‡ęœƒåæ½ē•„č©²ēµ„ę…‹ć€‚\n{0}\n", + "ConfigurationParser.noTypeDefinition": "錯誤: ę²’ęœ‰å·²čØ»å†Šå·„ä½œé”žåž‹ '{0}'ć€‚ę‚Øę˜Æå¦åæ˜čØ˜å®‰č£ęä¾›ē›øę‡‰å·„ä½œęä¾›č€…ēš„å»¶ä¼øęØ”ēµ„?", + "ConfigurationParser.missingRequiredProperty": "錯誤: å·„ä½œēµ„ę…‹ '{0}' ē¼ŗå°‘č¦ę±‚ēš„å±¬ę€§ '{1}'ć€‚ęœƒē•„éŽå·„ä½œēµ„ę…‹ć€‚", "ConfigurationParser.notCustom": "錯誤: ęœŖå°‡å·„ä½œå®£å‘Šē‚ŗč‡ŖčØ‚å·„ä½œć€‚å°‡ęœƒåæ½ē•„č©²ēµ„ę…‹ć€‚\n{0}\n", "ConfigurationParser.noTaskName": "錯誤: å·„ä½œåæ…é ˆęä¾› taskName å±¬ę€§ć€‚å³å°‡åæ½ē•„ę­¤å·„ä½œć€‚\n{0}\n", "taskConfiguration.shellArgs": "č­¦å‘Š: 巄作 '{0}' ę˜Æę®¼å±¤å‘½ä»¤ļ¼Œä½†å‘½ä»¤åēØ±ęˆ–å…¶äø­äø€å€‹å¼•ę•øęœ‰ēš„ęœŖé€øå‡ŗēš„ē©ŗę ¼ć€‚č‹„č¦ē¢ŗäæå‘½ä»¤åˆ—ę­£ē¢ŗå¼•čæ°ļ¼Œč«‹å°‡å¼•ę•øåˆä½µåˆ°å‘½ä»¤äø­ć€‚", "taskConfiguration.noCommandOrDependsOn": "錯誤: 巄作 '{0}' ęœŖęŒ‡å®šå‘½ä»¤čˆ‡ dependsOn å±¬ę€§ć€‚å°‡ęœƒē•„éŽč©²å·„ä½œć€‚å…¶å®šē¾©ē‚ŗ: \n{1}", - "taskConfiguration.noCommand": "錯誤: 巄作 '{0}' ęœŖå®šē¾©å‘½ä»¤ć€‚å³å°‡ē•„éŽč©²å·„ä½œć€‚å…¶å®šē¾©ē‚ŗ:\n{1}" + "taskConfiguration.noCommand": "錯誤: 巄作 '{0}' ęœŖå®šē¾©å‘½ä»¤ć€‚å³å°‡ē•„éŽč©²å·„ä½œć€‚å…¶å®šē¾©ē‚ŗ:\n{1}", + "TaskParse.noOsSpecificGlobalTasks": "å·„ä½œē‰ˆęœ¬ 2.0.0 äøę”Æę“å…ØåŸŸ OS ē‰¹å®šå·„ä½œć€‚č«‹ä½æē”Ø OS ē‰¹å®šå‘½ä»¤ä¾†č½‰ę›é€™äŗ›å·„ä½œć€‚å—å½±éŸæēš„å·„ä½œē‚ŗ:\n{0}" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 8b6ad71cd4e..a83e0f14425 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "termEntryAriaLabel": "{0} , ēµ‚ē«Æę©Ÿéøę“‡å™Ø", + "termCreateEntryAriaLabel": "{0}ļ¼Œå»ŗē«‹ę–°ēš„ēµ‚ē«Æę©Ÿ", + "'workbench.action.terminal.newplus": "$(plus) å»ŗē«‹ę–°ēš„ę•“åˆå¼ēµ‚ē«Æę©Ÿ", + "noTerminalsMatching": "ē„”ē›øē¬¦ēš„ēµ‚ē«Æę©Ÿ", + "noTerminalsFound": "ē„”é–‹å•Ÿēš„ēµ‚ē«Æę©Ÿ" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index e4baafd4cb1..5a928b9d911 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -4,18 +4,19 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "quickOpen.terminal": "é”Æē¤ŗę‰€ęœ‰å·²é–‹å•Ÿēš„ēµ‚ē«Æę©Ÿ", + "terminal": "ēµ‚ē«Æę©Ÿ", "terminalIntegratedConfigurationTitle": "ę•“åˆå¼ēµ‚ē«Æę©Ÿ", "terminal.integrated.shell.linux": "ēµ‚ē«Æę©ŸåœØ Linux äøŠä½æē”Øēš„ę®¼å±¤č·Æå¾‘ć€‚", "terminal.integrated.shellArgs.linux": "在 Linux ēµ‚ē«Æę©Ÿč¦ä½æē”Øēš„å‘½ä»¤åˆ—å¼•ę•øć€‚", "terminal.integrated.shell.osx": "ēµ‚ē«Æę©ŸåœØ OS X äøŠä½æē”Øēš„ę®¼å±¤č·Æå¾‘ć€‚", "terminal.integrated.shellArgs.osx": "在 OS X ēµ‚ē«Æę©Ÿč¦ä½æē”Øēš„å‘½ä»¤åˆ—å¼•ę•øć€‚", + "terminal.integrated.shell.windows": "ēµ‚ē«Æę©ŸåœØ Windows äøŠä½æē”Øēš„ę®¼å±¤č·Æå¾‘ć€‚ä½æē”ØéšØé™„ę–¼ Windows ēš„ę®¼å±¤ (cmd态PowerShell ꈖ Bash on Ubuntu) Ꙃ怂", "terminal.integrated.shellArgs.windows": "在 Windows ēµ‚ē«Æę©ŸäøŠę™‚č¦ä½æē”Øēš„å‘½ä»¤åˆ—å¼•ę•øć€‚", "terminal.integrated.rightClickCopyPaste": "å¦‚ęœ‰čØ­å®šļ¼Œé€™ęœƒé˜²ę­¢åœØēµ‚ē«Æę©Ÿå…§ęŒ‰ę»‘é¼ å³éµę™‚é”Æē¤ŗę“ä½œåŠŸčƒ½č”Øļ¼Œč€Œę˜ÆåœØęœ‰éøå–é …ē›®ę™‚č¤‡č£½ć€ę²’ęœ‰éøå–é …ē›®ę™‚č²¼äøŠć€‚", "terminal.integrated.fontFamily": "ęŽ§åˆ¶ēµ‚ē«Æę©Ÿēš„å­—åž‹å®¶ę—ļ¼Œé čØ­ē‚ŗ editor.fontFamily ēš„å€¼ć€‚", - "terminal.integrated.fontLigatures": "ęŽ§åˆ¶ę˜Æå¦åœØēµ‚ē«Æę©Ÿäø­å•Ÿē”Øé€£å­—å­—åž‹ć€‚", "terminal.integrated.fontSize": "ęŽ§åˆ¶ēµ‚ē«Æę©Ÿēš„å­—åž‹å¤§å° (ä»„åƒē“ ē‚ŗå–®ä½)怂", "terminal.integrated.lineHeight": "ęŽ§åˆ¶ēµ‚ē«Æę©Ÿēš„č”Œé«˜ļ¼Œę­¤ę•øå­—ęœƒä¹˜äøŠēµ‚ē«Æę©Ÿå­—åž‹å¤§å°ļ¼Œä»„å–å¾—ä»„åƒē“ ē‚ŗå–®ä½ēš„åÆ¦éš›č”Œé«˜ć€‚", - "terminal.integrated.enableBold": "ę˜Æå¦č¦åœØēµ‚ē«Æę©Ÿå…§å•Ÿē”Øē²—é«”ę–‡å­—ć€‚ę­¤å‹•ä½œéœ€č¦ēµ‚ē«Æę©Ÿę®¼å±¤ēš„ę”Æę“ć€‚", "terminal.integrated.cursorBlinking": "ęŽ§åˆ¶ēµ‚ē«Æę©Ÿč³‡ę–™ęŒ‡ęØ™ę˜Æå¦é–ƒēˆć€‚", "terminal.integrated.cursorStyle": "ęŽ§åˆ¶ēµ‚ē«Æę©Ÿč³‡ę–™ęŒ‡ęØ™ēš„ęØ£å¼ć€‚", "terminal.integrated.scrollback": "ęŽ§åˆ¶ēµ‚ē«Æę©Ÿäæē•™åœØå…¶ē·©č”å€äø­ēš„č”Œę•øäøŠé™ć€‚", @@ -23,7 +24,9 @@ "terminal.integrated.cwd": "ēµ‚ē«Æę©Ÿå•Ÿå‹•ä½ē½®ēš„ę˜Žē¢ŗčµ·å§‹č·Æå¾‘ļ¼Œé€™ęœƒē”Øä½œę®¼å±¤č™•ē†åŗēš„ē›®å‰å·„ä½œē›®éŒ„ (cwd)ć€‚ē•¶ę ¹ē›®éŒ„äøę˜Æę–¹ä¾æēš„ cwd ę™‚ļ¼Œé€™åœØå·„ä½œå€čØ­å®šäø­ē‰¹åˆ„å„½ē”Øć€‚", "terminal.integrated.confirmOnExit": "ē•¶ęœ‰ä½æē”Øäø­ēš„ēµ‚ē«Æę©Ÿå·„ä½œéšŽę®µę™‚ļ¼Œę˜Æå¦č¦åœØēµęŸę™‚ē¢ŗčŖć€‚", "terminal.integrated.commandsToSkipShell": "äø€ēµ„å‘½ä»¤č­˜åˆ„ē¢¼ļ¼Œå…¶ęŒ‰éµē¹«ēµé—œäæ‚å°‡äøęœƒå‚³é€åˆ°ę®¼å±¤ļ¼Œč€Œęœƒäø€å¾‹ē”± Code č™•ē†ć€‚é€™č®“é€šåøøē”±ę®¼å±¤å–ē”Øēš„ęŒ‰éµē¹«ēµé—œäæ‚ļ¼ŒåœØä½æē”ØäøŠčˆ‡ęœŖčšē„¦ę–¼ēµ‚ē«Æę©Ÿę™‚č”Œē‚ŗē›øåŒļ¼Œä¾‹å¦‚ Ctrl+P åÆå•Ÿå‹• Quick Open怂", - "terminal": "ēµ‚ē«Æę©Ÿ", + "terminal.integrated.env.osx": "OS X äøŠēš„ēµ‚ē«Æę©Ÿč¦ä½æē”Øä¹‹å…·ęœ‰å°‡ę–°å¢žč‡³ VS Code ęµēØ‹ä¹‹ē’°å¢ƒč®Šę•øēš„ē‰©ä»¶", + "terminal.integrated.env.linux": "Linux äøŠēš„ēµ‚ē«Æę©Ÿč¦ä½æē”Øä¹‹å…·ęœ‰å°‡ę–°å¢žč‡³ VS Code ęµēØ‹ä¹‹ē’°å¢ƒč®Šę•øēš„ē‰©ä»¶", + "terminal.integrated.env.windows": "Windows äøŠēš„ēµ‚ē«Æę©Ÿč¦ä½æē”Øä¹‹å…·ęœ‰å°‡ę–°å¢žč‡³ VS Code ęµēØ‹ä¹‹ē’°å¢ƒč®Šę•øēš„ē‰©ä»¶", "terminalCategory": "ēµ‚ē«Æę©Ÿ", "viewCategory": "檢視" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index e7485a609ef..40342458179 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "åˆ‡ę›ę•“åˆå¼ēµ‚ē«Æę©Ÿ", "workbench.action.terminal.kill": "ēµ‚ę­¢ä½æē”Øäø­ēš„ēµ‚ē«Æę©ŸåŸ·č”Œå€‹é«”", "workbench.action.terminal.kill.short": "ēµ‚ę­¢ēµ‚ē«Æę©Ÿ", + "workbench.action.terminal.quickKill": "ēµ‚ę­¢ēµ‚ē«Æę©ŸåŸ·č”Œå€‹é«”", "workbench.action.terminal.copySelection": "č¤‡č£½éøå–é …ē›®", "workbench.action.terminal.selectAll": "全選", + "workbench.action.terminal.deleteWordLeft": "åˆŖé™¤å·¦ę–¹ę–‡å­—", + "workbench.action.terminal.deleteWordRight": "åˆŖé™¤å³ę–¹ę–‡å­—", "workbench.action.terminal.new": "å»ŗē«‹ę–°ēš„ę•“åˆå¼ēµ‚ē«Æę©Ÿ", "workbench.action.terminal.new.short": "ę–°å¢žēµ‚ē«Æę©Ÿ", "workbench.action.terminal.focus": "čšē„¦ēµ‚ē«Æę©Ÿ", "workbench.action.terminal.focusNext": "čšē„¦äø‹äø€å€‹ēµ‚ē«Æę©Ÿ", - "workbench.action.terminal.focusAtIndex": "čšē„¦ēµ‚ē«Æę©Ÿ {0}", "workbench.action.terminal.focusPrevious": "čšē„¦äøŠäø€å€‹ēµ‚ē«Æę©Ÿ", "workbench.action.terminal.paste": "č²¼å…„ä½æē”Øäø­ēš„ēµ‚ē«Æę©Ÿ", "workbench.action.terminal.DefaultShell": "éøå–é čØ­ę®¼å±¤", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "é‡ę–°å‘½å", "workbench.action.terminal.rename.prompt": "č¼øå…„ēµ‚ē«Æę©ŸåēØ±", "workbench.action.terminal.focusFindWidget": "ē„¦é»žå°‹ę‰¾å°å·„å…·", - "workbench.action.terminal.hideFindWidget": "éš±č—å°‹ę‰¾å°å·„å…·" + "workbench.action.terminal.hideFindWidget": "éš±č—å°‹ę‰¾å°å·„å…·", + "nextTerminalFindTerm": "é”Æē¤ŗäø‹äø€å€‹å°‹ę‰¾å­—č©ž", + "previousTerminalFindTerm": "é”Æē¤ŗäøŠäø€å€‹å°‹ę‰¾å­—č©ž", + "quickOpenTerm": "åˆ‡ę›ä½æē”Øäø­ēš„ēµ‚ē«Æę©Ÿ " } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 6016a0077c1..3c4cccada80 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -6,5 +6,8 @@ { "terminal.background": "ēµ‚ē«Æę©Ÿēš„čƒŒę™Æč‰²å½©ļ¼Œå…čØ±ēµ‚ē«Æę©Ÿå’Œé¢ęæēš„č‰²å½©äøåŒć€‚", "terminal.foreground": "ēµ‚ē«Æę©Ÿēš„å‰ę™Æč‰²å½©ć€‚", + "terminalCursor.foreground": "ēµ‚ē«Æę©ŸęøøęØ™ēš„å‰ę™Æč‰²å½©ć€‚", + "terminalCursor.background": "ēµ‚ē«Æę©ŸęøøęØ™ēš„čƒŒę™Æč‰²å½©ć€‚å…čØ±å€å”ŠęøøęØ™é‡ē–Šę–¼č‡ŖčØ‚å­—å…ƒč‰²å½©ć€‚", + "terminal.selectionBackground": "ēµ‚ē«Æę©Ÿēš„éøå–é …ē›®čƒŒę™Æč‰²å½©ć€‚", "terminal.ansiColor": "ēµ‚ē«Æę©Ÿäø­ēš„ '{0}' ANSI 色彩。" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index f9f8c2b8d9e..4c35ec5d698 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "複製", - "createNewTerminal": "ę–°å¢žēµ‚ē«Æę©Ÿ", "paste": "貼上", "selectAll": "全選", "clear": "清除" diff --git a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 19e71491bf0..fc6b0624a08 100644 --- a/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "ē¢ŗå®šļ¼Œäøč¦å†é”Æē¤ŗ", "terminal.integrated.chooseWindowsShell": "č«‹éøå–ę‰€éœ€ēš„ēµ‚ē«Æę©Ÿę®¼å±¤ć€‚ę‚Øä¹‹å¾ŒåÆä»„åœØčØ­å®šäø­č®Šę›“ę­¤éøę“‡", "terminalService.terminalCloseConfirmationSingular": "ä»ęœ‰äø€å€‹ä½æē”Øäø­ēš„ēµ‚ē«Æę©Ÿå·„ä½œéšŽę®µć€‚č¦äŗˆä»„ēµ‚ę­¢å—Ž?", - "terminalService.terminalCloseConfirmationPlural": "ē›®å‰å…±ęœ‰ {0} å€‹ä½æē”Øäø­ēš„ēµ‚ē«Æę©Ÿå·„ä½œéšŽę®µć€‚č¦äŗˆä»„ēµ‚ę­¢å—Ž?", - "yes": "是" + "terminalService.terminalCloseConfirmationPlural": "ē›®å‰å…±ęœ‰ {0} å€‹ä½æē”Øäø­ēš„ēµ‚ē«Æę©Ÿå·„ä½œéšŽę®µć€‚č¦äŗˆä»„ēµ‚ę­¢å—Ž?" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json index bcb5723b6fb..e043af15328 100644 --- a/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,9 @@ "licenseChanged": "ęŽˆę¬Šę¢ę¬¾å·²ęœ‰ę‰€č®Šę›“ļ¼Œč«‹ä»”ē“°é–±č®€ć€‚", "license": "é–±č®€ęŽˆę¬Š", "neveragain": "äøč¦å†é”Æē¤ŗ", + "64bitisavailable": "適用於 64 位元 Windows ēš„ {0} ē¾å·²ęŽØå‡ŗ! ", "learn more": "深兄了解", + "updateIsReady": "ę–°ēš„ {0} ę›“ę–°å·²åÆē”Øć€‚", "thereIsUpdateAvailable": "å·²ęœ‰ę›“ę–°åÆē”Øć€‚", "updateAvailable": "{0} é‡ę–°å•Ÿå‹•å¾Œå°‡ęœƒę›“ę–°ć€‚", "noUpdatesAvailable": "ē›®å‰ę²’ęœ‰åÆē”Øēš„ę›“ę–°ć€‚", diff --git a/i18n/cht/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/cht/src/vs/workbench/parts/views/browser/views.i18n.json index 723de346790..d9eedec6006 100644 --- a/i18n/cht/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/views/browser/views.i18n.json @@ -5,5 +5,5 @@ // Do not edit this file. It is machine generated. { "viewToolbarAriaLabel": "{0} 個動作", - "removeView": "å¾žęč¦ę¬„ä½ē§»é™¤" + "hideView": "å¾žęč¦ę¬„ä½éš±č—" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json b/i18n/cht/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json index efe1cddf382..98b2d3ba1ce 100644 --- a/i18n/cht/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json @@ -12,5 +12,6 @@ "vscode.extension.contributes.view.when": "åæ…é ˆē‚ŗ true ä»„é”Æē¤ŗę­¤ęŖ¢č¦–ēš„ę¢ä»¶", "vscode.extension.contributes.views": "ęä¾›ę„č¦‹ēµ¦ē·Øč¼Æč€…", "views.explorer": "ęŖ”ę”ˆēø½ē®”ęŖ¢č¦–", + "views.debug": "åµéŒÆęŖ¢č¦–", "locationId.invalid": "`{0}`äøę˜Æęœ‰ę•ˆēš„č­˜åˆ„ä½ē½®" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 69805b63ee1..4fe3fc6f2b7 100644 --- a/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "開始", "welcomePage.newFile": "ę–°å¢žęŖ”ę”ˆ", "welcomePage.openFolder": "é–‹å•Ÿč³‡ę–™å¤¾...", - "welcomePage.cloneGitRepository": "複製 Git å­˜ę”¾åŗ«...", + "welcomePage.addWorkspaceFolder": "ę–°å¢žå·„ä½œå€č³‡ę–™å¤¾...", "welcomePage.recent": "ęœ€čæ‘ä½æē”Ø", "welcomePage.moreRecent": "ę›“å¤š...", "welcomePage.noRecentFolders": "ę²’ęœ‰ęœ€čæ‘ä½æē”Øēš„č³‡ę–™å¤¾", diff --git a/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json index 4acbaf6f0ac..d624449b463 100644 --- a/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json @@ -8,5 +8,6 @@ "workbench.startupEditor.none": "äøä½æē”Øē·Øč¼Æå™Øé–‹å§‹ć€‚", "workbench.startupEditor.welcomePage": "é–‹å•Ÿę­”čæŽé é¢ (預設)怂", "workbench.startupEditor.newUntitledFile": "é–‹å•Ÿę–°ēš„ē„”ęØ™é”ŒęŖ”ę”ˆć€‚", + "workbench.startupEditor": "č‹„ęœŖå¾žä¹‹å‰ēš„å·„ä½œéšŽę®µé‚„åŽŸä»»ä½•ē·Øč¼Æå™Øļ¼ŒęœƒęŽ§åˆ¶å•Ÿå‹•ę™‚č¦é”Æē¤ŗēš„ē·Øč¼Æå™Øć€‚éøå– 'none' äøä½æē”Øē·Øč¼Æå™Øå•Ÿå‹•ļ¼Œéøå– 'welcomePage' é–‹å•Ÿę­”čæŽé é¢ (預設)ļ¼Œéøå– 'newUntitledFile' é–‹å•Ÿę–°ēš„ē„”ęØ™é”ŒęŖ”ę”ˆ (åƒ…ę­£åœØé–‹å•Ÿē©ŗē™½å·„ä½œå€é©ē”Ø)怂", "help": "čŖŖę˜Ž" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 266ab6448f8..05765cddefd 100644 --- a/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,9 +9,11 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "锯示 Azure ę““å……åŠŸčƒ½", "welcomePage.docker": "Docker", - "welcomePage.vim": "ę“»åŠ›", - "welcomePage.sublime": "壯麗", + "welcomePage.vim": "Vim", + "welcomePage.sublime": "Sublime", "welcomePage.atom": "Atom", "welcomePage.extensionPackAlreadyInstalled": "ę”Æę“åŠŸčƒ½{0}å·²č¢«å®‰č£ć€‚", "welcomePage.willReloadAfterInstallingExtensionPack": "{0} ēš„å…¶ä»–ę”Æę“å®‰č£å®Œęˆå¾Œļ¼Œå°‡ęœƒé‡ę–°č¼‰å…„ę­¤č¦–ēŖ—ć€‚", diff --git a/i18n/cht/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/cht/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index a9e03459023..576f7739ced 100644 --- a/i18n/cht/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "Interactive Playground", - "editorWalkThrough.title": "Interactive Playground" + "editorWalkThrough.title": "Interactive Playground", + "editorWalkThrough": "Interactive Playground" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/cht/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..2bc73e75628 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "čØ­å®šēš„ę‘˜č¦ć€‚ę­¤ęØ™ē±¤å°‡ęœƒåœØčØ­å®šęŖ”äø­ä½œē‚ŗåˆ†éš”čØ»č§£ä½æē”Øć€‚", + "vscode.extension.contributes.configuration.properties": "ēµ„ę…‹å±¬ę€§ēš„ęčæ°ć€‚", + "scope.window.description": "č¦–ēŖ—ē‰¹å®šēµ„ę…‹ļ¼ŒåÆåœØä½æē”Øč€…ęˆ–å·„ä½œå€čØ­å®šäø­äŗˆä»„čØ­å®šć€‚", + "scope.resource.description": "č³‡ęŗē‰¹å®ščØ­å®šļ¼ŒåÆåœØä½æē”Øč€…ć€å·„ä½œå€ęˆ–č³‡ę–™å¤¾čØ­å®šäø­äŗˆä»„čØ­å®šć€‚", + "scope.description": "ēµ„ę…‹é©ē”Øēš„ēÆ„åœć€‚åÆē”Øēš„ēÆ„åœē‚ŗć€Œč¦–ēŖ—ć€å’Œć€Œč³‡ęŗć€ć€‚", + "vscode.extension.contributes.configuration": "ęä¾›ēµ„ę…‹čØ­å®šć€‚", + "invalid.title": "'configuration.title' åæ…é ˆę˜Æå­—äø²", + "vscode.extension.contributes.defaultConfiguration": "ä¾čŖžčØ€č²¢ē»é čØ­ē·Øč¼Æå™Øēµ„ę…‹čØ­å®šć€‚", + "invalid.properties": "'configuration.properties' åæ…é ˆę˜Æē‰©ä»¶", + "invalid.allOf": "'configuration.allOf' å·²å–ä»£č€Œäøę‡‰å†ä½æē”Øć€‚č«‹ę”¹ē‚ŗå°‡å¤šå€‹ēµ„ę…‹å€ę®µä½œē‚ŗé™£åˆ—ļ¼Œå‚³éžč‡³ć€Œēµ„ę…‹ć€č²¢ē»é»žć€‚", + "workspaceConfig.folders.description": "č¦č¼‰å…„å·„ä½œå€ä¹‹č³‡ę–™å¤¾ēš„ęø…å–®ć€‚", + "workspaceConfig.path.description": "ęŖ”ę”ˆč·Æå¾‘ļ¼Œä¾‹å¦‚ `/root/folderA` ꈖ `./folderA` å³ē‚ŗęœƒå°å·„ä½œå€ęŖ”ę”ˆä½ē½®č§£ęžēš„ē›øé—œč·Æå¾‘ć€‚", + "workspaceConfig.name.description": "č³‡ę–™å¤¾ēš„éøē”ØåēØ±ć€‚", + "workspaceConfig.uri.description": "č³‡ę–™å¤¾ēš„ URI", + "workspaceConfig.settings.description": "å·„ä½œå€čØ­å®š", + "workspaceConfig.extensions.description": "å·„ä½œå€å»¶ä¼øęØ”ēµ„", + "unknownWorkspaceProperty": "ęœŖēŸ„ēš„å·„ä½œå€ēµ„ę…‹å±¬ę€§" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json index 8fd534084bb..2bc73e75628 100644 --- a/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,11 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "ęä¾›ēµ„ę…‹čØ­å®šć€‚", "vscode.extension.contributes.configuration.title": "čØ­å®šēš„ę‘˜č¦ć€‚ę­¤ęØ™ē±¤å°‡ęœƒåœØčØ­å®šęŖ”äø­ä½œē‚ŗåˆ†éš”čØ»č§£ä½æē”Øć€‚", "vscode.extension.contributes.configuration.properties": "ēµ„ę…‹å±¬ę€§ēš„ęčæ°ć€‚", - "invalid.type": "å¦‚ęžœå·²čØ­å®šļ¼Œ'configuration.type' åæ…é ˆčØ­å®šē‚ŗē‰©ä»¶", + "scope.window.description": "č¦–ēŖ—ē‰¹å®šēµ„ę…‹ļ¼ŒåÆåœØä½æē”Øč€…ęˆ–å·„ä½œå€čØ­å®šäø­äŗˆä»„čØ­å®šć€‚", + "scope.resource.description": "č³‡ęŗē‰¹å®ščØ­å®šļ¼ŒåÆåœØä½æē”Øč€…ć€å·„ä½œå€ęˆ–č³‡ę–™å¤¾čØ­å®šäø­äŗˆä»„čØ­å®šć€‚", + "scope.description": "ēµ„ę…‹é©ē”Øēš„ēÆ„åœć€‚åÆē”Øēš„ēÆ„åœē‚ŗć€Œč¦–ēŖ—ć€å’Œć€Œč³‡ęŗć€ć€‚", + "vscode.extension.contributes.configuration": "ęä¾›ēµ„ę…‹čØ­å®šć€‚", "invalid.title": "'configuration.title' åæ…é ˆę˜Æå­—äø²", "vscode.extension.contributes.defaultConfiguration": "ä¾čŖžčØ€č²¢ē»é čØ­ē·Øč¼Æå™Øēµ„ę…‹čØ­å®šć€‚", - "invalid.properties": "'configuration.properties' åæ…é ˆę˜Æē‰©ä»¶" + "invalid.properties": "'configuration.properties' åæ…é ˆę˜Æē‰©ä»¶", + "invalid.allOf": "'configuration.allOf' å·²å–ä»£č€Œäøę‡‰å†ä½æē”Øć€‚č«‹ę”¹ē‚ŗå°‡å¤šå€‹ēµ„ę…‹å€ę®µä½œē‚ŗé™£åˆ—ļ¼Œå‚³éžč‡³ć€Œēµ„ę…‹ć€č²¢ē»é»žć€‚", + "workspaceConfig.folders.description": "č¦č¼‰å…„å·„ä½œå€ä¹‹č³‡ę–™å¤¾ēš„ęø…å–®ć€‚", + "workspaceConfig.path.description": "ęŖ”ę”ˆč·Æå¾‘ļ¼Œä¾‹å¦‚ `/root/folderA` ꈖ `./folderA` å³ē‚ŗęœƒå°å·„ä½œå€ęŖ”ę”ˆä½ē½®č§£ęžēš„ē›øé—œč·Æå¾‘ć€‚", + "workspaceConfig.name.description": "č³‡ę–™å¤¾ēš„éøē”ØåēØ±ć€‚", + "workspaceConfig.uri.description": "č³‡ę–™å¤¾ēš„ URI", + "workspaceConfig.settings.description": "å·„ä½œå€čØ­å®š", + "workspaceConfig.extensions.description": "å·„ä½œå€å»¶ä¼øęØ”ēµ„", + "unknownWorkspaceProperty": "ęœŖēŸ„ēš„å·„ä½œå€ēµ„ę…‹å±¬ę€§" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/cht/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index b20ee8ce75f..2775ad9c28f 100644 --- a/i18n/cht/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/cht/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "é–‹å•ŸčØ­å®š", + "openTasksConfiguration": "é–‹å•Ÿå·„ä½œēµ„ę…‹", + "openLaunchConfiguration": "é–‹å•Ÿå•Ÿå‹•ēµ„ę…‹", "close": "關閉", - "saveAndRetry": "å„²å­˜čØ­å®šäø¦é‡å•Ÿ", - "errorInvalidConfiguration": "ē„”ę³•åÆ«å…„čØ­å®š.č«‹é–‹å•Ÿ**ä½æē”Øč€…čØ­å®š**並修正錯誤/č­¦å‘Šå¾Œå†č©¦äø€ę¬”.", - "errorInvalidConfigurationWorkspace": "ē„”ę³•åÆ«å…„čØ­å®š.č«‹é–‹å•Ÿ**å·„ä½œå€čØ­å®š**äø¦äæ®ę­£ęŖ”ę”ˆäø­ēš„éŒÆčŖ¤/č­¦å‘Šå¾Œå†č©¦äø€ę¬”.", - "errorConfigurationFileDirty": "ē„”ę³•åÆ«å…„čØ­å®š,å› ē‚ŗęŖ”ę”ˆå·²č®Šę›“.č«‹å„²å­˜**ä½æē”Øč€…čØ­å®š**å¾Œå†č©¦äø€ę¬”", - "errorConfigurationFileDirtyWorkspace": "ē„”ę³•åÆ«å…„čØ­å®š,å› ęŖ”ę”ˆå·²č®Šę›“.č«‹å„²å­˜**å·„ä½œå€čØ­å®š**å¾Œå†č©¦äø€ę¬”.", + "open": "é–‹å•ŸčØ­å®š", + "saveAndRetry": "å„²å­˜äø¦é‡č©¦", + "errorUnknownKey": "因為 {1} éžå·²čØ»å†Šēš„ēµ„ę…‹ļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„č‡³ {0}怂", + "errorInvalidFolderConfiguration": "因為 {0} äøę”Æę“č³‡ę–™å¤¾č³‡ęŗēÆ„åœļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„č‡³č³‡ę–™å¤¾čØ­å®šć€‚", + "errorInvalidUserTarget": "因為 {0} äøę”Æę“å…ØåŸŸēÆ„åœļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„č‡³ä½æē”Øč€…čØ­å®šć€‚", + "errorInvalidFolderTarget": "å› ē‚ŗęœŖęä¾›č³‡ęŗļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„č‡³č³‡ę–™å¤¾čØ­å®šć€‚", + "errorNoWorkspaceOpened": "å› ē‚ŗęœŖé–‹å•Ÿå·„ä½œå€ļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„č‡³ {0}ć€‚č«‹å…ˆé–‹å•Ÿå·„ä½œå€ļ¼Œå†č©¦äø€ę¬”ć€‚", + "errorInvalidTaskConfiguration": "ē„”ę³•åÆ«å…„å·„ä½œęŖ”ę”ˆć€‚č«‹é–‹å•Ÿ **巄作** ęŖ”ę”ˆä»„äæ®ę­£å…¶äø­ēš„éŒÆčŖ¤/č­¦å‘Šļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorInvalidLaunchConfiguration": "ē„”ę³•åÆ«å…„å•Ÿå‹•ęŖ”ę”ˆć€‚č«‹é–‹å•Ÿ **啟動** ęŖ”ę”ˆä»„äæ®ę­£å…¶äø­ēš„éŒÆčŖ¤/č­¦å‘Šļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorInvalidConfiguration": "ē„”ę³•åÆ«å…„ä½æē”Øč€…čØ­å®šć€‚č«‹é–‹å•Ÿ **ä½æē”Øč€…čØ­å®š** ęŖ”ę”ˆä»„äæ®ę­£å…¶äø­ēš„éŒÆčŖ¤/č­¦å‘Šļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorInvalidConfigurationWorkspace": "ē„”ę³•åÆ«å…„å·„ä½œå€čØ­å®šć€‚č«‹é–‹å•Ÿ **å·„ä½œå€čØ­å®š** ęŖ”ę”ˆä»„äæ®ę­£å…¶äø­ēš„éŒÆčŖ¤/č­¦å‘Šļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorInvalidConfigurationFolder": "ē„”ę³•åÆ«å…„č³‡ę–™å¤¾čØ­å®šć€‚č«‹é–‹å•Ÿ **{0}** č³‡ę–™å¤¾äø‹ēš„ **č³‡ę–™å¤¾čØ­å®š** ęŖ”ę”ˆä»„äæ®ę­£å…¶äø­ēš„éŒÆčŖ¤/č­¦å‘Šļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorTasksConfigurationFileDirty": "å› ē‚ŗęŖ”ę”ˆå·²č®Šę›“ļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„å·„ä½œęŖ”ę”ˆć€‚č«‹å„²å­˜ **å·„ä½œēµ„ę…‹** ęŖ”ę”ˆļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorLaunchConfigurationFileDirty": "å› ē‚ŗęŖ”ę”ˆå·²č®Šę›“ļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„å•Ÿå‹•ęŖ”ę”ˆć€‚č«‹å„²å­˜ **å•Ÿå‹•ēµ„ę…‹** ęŖ”ę”ˆļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorConfigurationFileDirty": "å› ē‚ŗęŖ”ę”ˆå·²č®Šę›“ļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„ä½æē”Øč€…čØ­å®šć€‚č«‹å„²å­˜ **ä½æē”Øč€…čØ­å®š** ęŖ”ę”ˆļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorConfigurationFileDirtyWorkspace": "å› ē‚ŗęŖ”ę”ˆå·²č®Šę›“ļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„å·„ä½œå€čØ­å®šć€‚č«‹å„²å­˜ **å·„ä½œå€čØ­å®š** ęŖ”ę”ˆļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", + "errorConfigurationFileDirtyFolder": "å› ē‚ŗęŖ”ę”ˆå·²č®Šę›“ļ¼Œę‰€ä»„ē„”ę³•åÆ«å…„č³‡ę–™å¤¾čØ­å®šć€‚č«‹å„²å­˜ **{0}** č³‡ę–™å¤¾äø‹ēš„ **č³‡ę–™å¤¾čØ­å®š** ęŖ”ę”ˆļ¼Œē„¶å¾Œé‡č©¦äø€ę¬”ć€‚", "userTarget": "ä½æē”Øč€…čØ­å®š", - "workspaceTarget": "å·„ä½œå€čØ­å®š" + "workspaceTarget": "å·„ä½œå€čØ­å®š", + "folderTarget": "č³‡ę–™å¤¾čØ­å®š" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/cht/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/cht/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..38415d518f4 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "å»¶ä¼øäø»ę©ŸęœŖę–¼ 10 ē§’å…§é–‹å§‹ļ¼ŒåÆčƒ½åœØē¬¬äø€č”Œå°±å·²åœę­¢ļ¼Œäø¦éœ€č¦åµéŒÆå·„å…·ę‰čƒ½ē¹¼ēŗŒć€‚", + "extensionHostProcess.startupFail": "延伸主機未在 10 ē§’å…§å•Ÿå‹•ļ¼ŒåÆčƒ½ē™¼ē”Ÿäŗ†å•é”Œć€‚", + "extensionHostProcess.error": "å»¶ä¼øäø»ę©Ÿē™¼ē”ŸéŒÆčŖ¤: {0}" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..f08aebf3331 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "ē„”ę³•å‰–ęž {0}: {1}怂", + "fileReadFail": "ē„”ę³•č®€å–ęŖ”ę”ˆ {0}: {1}怂", + "jsonsParseFail": "ē„”ę³•å‰–ęž {0} ꈖ {1}: {2}怂", + "missingNLSKey": "ę‰¾äøåˆ°é‡‘é‘° {0} ēš„čØŠęÆć€‚" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..e9e580ceb96 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "開發人哔巄具", + "restart": "é‡ę–°å•Ÿå‹•å»¶ä¼øäø»ę©Ÿ", + "extensionHostProcess.crash": "å»¶ä¼øäø»ę©Ÿę„å¤–ēµ‚ę­¢ć€‚", + "extensionHostProcess.unresponsiveCrash": "å› ē‚ŗå»¶ä¼øäø»ę©Ÿę²’ęœ‰å›žę‡‰ļ¼Œę‰€ä»„ę„å¤–ēµ‚ę­¢ć€‚", + "overwritingExtension": "正在仄 {1} 覆寫延伸樔組 {0}怂", + "extensionUnderDevelopment": "ę­£åœØč¼‰å…„ä½ę–¼ {0} ēš„é–‹ē™¼å»¶ä¼øęØ”ēµ„" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/cht/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..067f2923a48 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "ęŖ”ę”ˆä¼¼ä¹Žę˜ÆäŗŒé€²ä½ęŖ”ļ¼Œå› ę­¤ē„”ę³•ē•¶åšę–‡å­—é–‹å•Ÿ" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/cht/src/vs/workbench/services/files/node/fileService.i18n.json index 67227a075fa..745c027703e 100644 --- a/i18n/cht/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/cht/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "ęŖ”ę”ˆč³‡ęŗ ({0}) ē„”ę•ˆ", - "fileIsDirectoryError": "ęŖ”ę”ˆę˜Æē›®éŒ„ ({0})", + "fileIsDirectoryError": "ęŖ”ę”ˆę˜Æē›®éŒ„", "fileNotModifiedError": "ęœŖäæ®ę”¹ęŖ”ę”ˆēš„ę™‚é–“", "fileTooLargeError": "ęŖ”ę”ˆå¤Ŗå¤§ē„”ę³•é–‹å•Ÿ", "fileBinaryError": "ęŖ”ę”ˆä¼¼ä¹Žę˜ÆäŗŒé€²ä½ęŖ”ļ¼Œå› ę­¤ē„”ę³•ē•¶åšę–‡å­—é–‹å•Ÿ", "fileNotFoundError": "ę‰¾äøåˆ°ęŖ”ę”ˆ ({0})", + "fileExists": "č¦å»ŗē«‹ēš„ęŖ”ę”ˆå·²å­˜åœØ ({0})", "fileMoveConflict": "焔法移動/č¤‡č£½ć€‚ē›®ēš„åœ°å·²å­˜åœØęŖ”ę”ˆć€‚", "unableToMoveCopyError": "焔法移動/č¤‡č£½ć€‚ęŖ”ę”ˆęœƒå–ä»£å…¶ę‰€åœØēš„č³‡ę–™å¤¾ć€‚", "foldersCopyError": "č³‡ę–™å¤¾äøčƒ½č¤‡č£½åˆ°å·„ä½œå€ć€‚č«‹éøå–å€‹åˆ„ęŖ”ę”ˆé€²č”Œč¤‡č£½ć€‚", diff --git a/i18n/cht/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/cht/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/cht/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/cht/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/cht/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index c11894b2666..6603fae31c1 100644 --- a/i18n/cht/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/cht/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "č¦å‰‡ēš„å­—åž‹ęØ£å¼:ć€Œę–œé«”ć€ć€ć€Œē²—é«”ć€ęˆ–ć€Œåŗ•ē·šć€ä¹‹äø€ęˆ–å…¶ēµ„åˆ", - "schema.colors": "åē™½é”Æē¤ŗčŖžę³•ę™‚ēš„č‰²å½©", - "schema.properties.name": "č¦å‰‡ęčæ°", - "schema.tokenColors.path": "tmTheme ęŖ”ę”ˆēš„č·Æå¾‘ (ē›øå°ę–¼ē›®å‰ęŖ”ę”ˆ)怂" + "schema.token.settings": "ę¬Šę–ēš„č‰²å½©čˆ‡ęØ£å¼ć€‚", + "schema.token.foreground": "ę¬Šę–ēš„å‰ę™Æč‰²å½©ć€‚", + "schema.token.fontStyle": "č¦å‰‡ēš„å­—åž‹ęØ£å¼:ć€Œę–œé«”ć€ć€ć€Œē²—é«”ć€ęˆ–ć€Œåŗ•ē·šć€ä¹‹äø€ęˆ–å…¶ēµ„åˆ", + "schema.fontStyle.error": "å­—å½¢ęØ£å¼åæ…é ˆę˜Æć€Œę–œé«”ć€ć€ć€Œē²—é«”ć€åŠć€Œåŗ•ē·šć€ēš„ēµ„åˆ", + "schema.properties.name": "č¦å‰‡ēš„ęčæ°ć€‚", + "schema.properties.scope": "é‡å°ę­¤č¦å‰‡ē¬¦åˆēš„ēÆ„åœéøå–å™Øć€‚", + "schema.tokenColors.path": "tmTheme ęŖ”ę”ˆēš„č·Æå¾‘ (ē›øå°ę–¼ē›®å‰ęŖ”ę”ˆ)怂", + "schema.colors": "åē™½é”Æē¤ŗčŖžę³•ę™‚ēš„č‰²å½©" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 7c45152f8a5..fed5cb1c363 100644 --- a/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "å‰–ęž JSON ä½ˆę™Æäø»é”ŒęŖ”ę”ˆę™‚ē™¼ē”Ÿå•é”Œ: {0}", "error.invalidformat.colors": "å‰–ęžå½©č‰²ä½ˆę™Æäø»é”ŒęŖ”ę”ˆ {0} ę™‚å‡ŗē¾å•é”Œć€‚å±¬ę€§ 'settings' äøę˜Æ 'object' é”žåž‹ć€‚", - "error.invalidformat.tokenColors": "å‰–ęžå½©č‰²ä½ˆę™Æäø»é”ŒęŖ”ę”ˆ {0} ę™‚å‡ŗē¾å•é”Œć€‚å±¬ę€§ 'tokenColors' ę‡‰ē‚ŗęŒ‡å®šé”č‰²ēš„é™£åˆ—ļ¼Œęˆ–ē‚ŗé€šå¾€ę–‡å­—é…å°ä½ˆę™Æäø»é”ŒęŖ”ę”ˆēš„č·Æå¾‘", + "error.invalidformat.tokenColors": "å‰–ęžč‰²å½©ä½ˆę™Æäø»é”ŒęŖ”ę”ˆ {0} ę™‚ē™¼ē”Ÿå•é”Œć€‚å±¬ę€§ 'tokenColors' ę‡‰ę˜ÆęŒ‡å®šč‰²å½©ēš„é™£åˆ—ęˆ–ę˜Æ TextMate ä½ˆę™Æäø»é”ŒęŖ”ę”ˆēš„č·Æå¾‘ć€‚", "error.plist.invalidformat": "å‰–ęž tmTheme ęŖ”ę”ˆ {0} ę™‚å‡ŗē¾å•é”Œć€‚'settings' äøę˜Æé™£åˆ—ć€‚", "error.cannotparse": "å‰–ęž tmTheme ęŖ”ę”ˆ {0} ę™‚ē™¼ē”Ÿå•é”Œ", "error.cannotload": "載兄 tmTheme ęŖ”ę”ˆ {0} ę™‚ē™¼ē”Ÿå•é”Œ: {1}" diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..f1b7981878d --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "ęä¾› Textmate å½©č‰²ä½ˆę™Æäø»é”Œć€‚", + "vscode.extension.contributes.themes.id": "ē”ØåœØä½æē”Øč€…čØ­å®šäø­ēš„åœ–ē¤ŗä½ˆę™Æäø»é”Œč­˜åˆ„ē¢¼ć€‚", + "vscode.extension.contributes.themes.label": "如 UI äø­ę‰€ē¤ŗēš„å½©č‰²ä½ˆę™Æäø»é”ŒęØ™ē±¤ć€‚", + "vscode.extension.contributes.themes.uiTheme": "åŸŗåŗ•ä½ˆę™Æäø»é”Œå®šē¾©ē·Øč¼Æå™Øēš„č‰²å½©: 'vs' ę˜Æę·ŗč‰²ä½ˆę™Æäø»é”Œļ¼Œ'vs-dark' ę˜Æę·±č‰²ä½ˆę™Æäø»é”Œć€‚'hc-black' ę˜Æę·±č‰²é«˜å°ęÆ”ä½ˆę™Æäø»é”Œć€‚", + "vscode.extension.contributes.themes.path": "tmTheme ęŖ”ę”ˆēš„č·Æå¾‘ć€‚ę­¤č·Æå¾‘ę˜Æę““å……åŠŸčƒ½č³‡ę–™å¤¾ēš„ē›øå°č·Æå¾‘ļ¼Œé€šåøøē‚ŗ './themes/themeFile.tmTheme'怂", + "reqarray": "ę““å……é»ž '{0}' åæ…é ˆę˜Æé™£åˆ—ć€‚", + "reqpath": "'contributes.{0}.path' äø­ę‡‰ęœ‰å­—äø²ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.1": "ę““å……åŠŸčƒ½č³‡ę–™å¤¾ ({2}) ę‡‰åŒ…å« 'contributes.{0}.path' ({1})ć€‚é€™åÆčƒ½ęœƒå°Žč‡“ę““å……åŠŸčƒ½ē„”ę³•ē§»ę¤ć€‚" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..e7493947e49 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "å‰–ęžęŖ”ę”ˆēš„åœ–ē¤ŗęŖ”ę™‚ē™¼ē”Ÿå•é”Œ: {0}" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..dd6a68fb722 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "č²¢ē»ęŖ”ę”ˆåœ–ē¤ŗä½ˆę™Æäø»é”Œć€‚", + "vscode.extension.contributes.iconThemes.id": "ē”ØåœØä½æē”Øč€…čØ­å®šäø­ēš„åœ–ē¤ŗä½ˆę™Æäø»é”Œč­˜åˆ„ē¢¼ć€‚", + "vscode.extension.contributes.iconThemes.label": "仄 UI é”Æē¤ŗēš„åœ–ē¤ŗä½ˆę™Æäø»é”ŒęØ™ē±¤ć€‚", + "vscode.extension.contributes.iconThemes.path": "åœ–ē¤ŗä½ˆę™Æäø»é”Œå®šē¾©ęŖ”ę”ˆć€‚č·Æå¾‘ē›øå°ę–¼ę““å……åŠŸčƒ½č³‡ę–™å¤¾ļ¼Œé€šåøøē‚ŗ './icons/awesome-icon-theme.json'怂", + "reqarray": "ę““å……é»ž '{0}' åæ…é ˆę˜Æé™£åˆ—ć€‚", + "reqpath": "'contributes.{0}.path' äø­ę‡‰ęœ‰å­—äø²ć€‚ęä¾›ēš„å€¼: {1}", + "reqid": "`contributes.{0}.id` äø­ę‡‰ęœ‰å­—äø²ć€‚ęä¾›ēš„å€¼: {1}", + "invalid.path.1": "ę““å……åŠŸčƒ½č³‡ę–™å¤¾ ({2}) ę‡‰åŒ…å« 'contributes.{0}.path' ({1})ć€‚é€™åÆčƒ½ęœƒå°Žč‡“ę““å……åŠŸčƒ½ē„”ę³•ē§»ę¤ć€‚" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index b10dcde2a95..5ab16a62ce2 100644 --- a/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/cht/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,29 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "ē”ØåœØä½æē”Øč€…čØ­å®šäø­ēš„åœ–ē¤ŗä½ˆę™Æäø»é”Œč­˜åˆ„ē¢¼ć€‚", - "vscode.extension.contributes.themes.label": "如 UI äø­ę‰€ē¤ŗēš„å½©č‰²ä½ˆę™Æäø»é”ŒęØ™ē±¤ć€‚", - "vscode.extension.contributes.themes.uiTheme": "åŸŗåŗ•ä½ˆę™Æäø»é”Œå®šē¾©ē·Øč¼Æå™Øēš„č‰²å½©: 'vs' ę˜Æę·ŗč‰²ä½ˆę™Æäø»é”Œļ¼Œ'vs-dark' ę˜Æę·±č‰²ä½ˆę™Æäø»é”Œć€‚'hc-black' ę˜Æę·±č‰²é«˜å°ęÆ”ä½ˆę™Æäø»é”Œć€‚", - "vscode.extension.contributes.themes.path": "tmTheme ęŖ”ę”ˆēš„č·Æå¾‘ć€‚ę­¤č·Æå¾‘ę˜Æę““å……åŠŸčƒ½č³‡ę–™å¤¾ēš„ē›øå°č·Æå¾‘ļ¼Œé€šåøøē‚ŗ './themes/themeFile.tmTheme'怂", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ē”ØåœØä½æē”Øč€…čØ­å®šäø­ēš„åœ–ē¤ŗä½ˆę™Æäø»é”Œč­˜åˆ„ē¢¼ć€‚", - "vscode.extension.contributes.iconThemes.label": "仄 UI é”Æē¤ŗēš„åœ–ē¤ŗä½ˆę™Æäø»é”ŒęØ™ē±¤ć€‚", - "vscode.extension.contributes.iconThemes.path": "åœ–ē¤ŗä½ˆę™Æäø»é”Œå®šē¾©ęŖ”ę”ˆć€‚č·Æå¾‘ē›øå°ę–¼ę““å……åŠŸčƒ½č³‡ę–™å¤¾ļ¼Œé€šåøøē‚ŗ './icons/awesome-icon-theme.json'怂", "migration.completed": "å·²å°‡ę–°ēš„ä½ˆę™Æäø»é”ŒčØ­å®šę–°å¢žåˆ°ä½æē”Øč€…čØ­å®šć€‚å‚™ä»½ä½ę–¼ {0}怂", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "`contributes.{0}.path` äø­ēš„é ęœŸå­—äø²ć€‚ęä¾›ēš„å€¼: {1}", - "invalid.path.1": "č¦åŒ…å«åœØę““å……åŠŸčƒ½č³‡ę–™å¤¾ ({2}) äø­ēš„é ęœŸ `contributes.{0}.path` ({1})ć€‚é€™åÆčƒ½ęœƒä½æę““å……åŠŸčƒ½ē„”ę³•ē§»ę¤ć€‚", - "reqid": "`contributes.{0}.id` äø­ēš„é ęœŸå­—äø²ć€‚ęä¾›ēš„å€¼: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "ęŒ‡å®šåœØå·„ä½œå°äø­ä½æē”Øēš„åœ–ē¤ŗäø»é”Œļ¼Œęˆ–čØ­å®šē‚ŗ 'null' äøé”Æē¤ŗä»»ä½•ęŖ”ę”ˆåœ–ē¤ŗć€‚", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "ä¾ē›®å‰éøę“‡ēš„å½©č‰²ä½ˆę™Æäø»é”Œč¦†åÆ«é”č‰²", - "workbenchColors.deprecated": "ę­¤čØ­å®šäøå†ē‚ŗåÆ¦é©—ę€§ļ¼Œäø”å·²č¢«é‡ę–°å‘½åē‚ŗ 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "改用'workbench.colorCustomizations'" + "editorColors": "ä¾ē›®å‰éøå–ēš„č‰²å½©ä½ˆę™Æäø»é”Œč¦†åÆ«ē·Øč¼Æå™Øč‰²å½©čˆ‡å­—åž‹ęØ£å¼ć€‚", + "editorColors.comments": "čØ­å®ščØ»č§£ēš„č‰²å½©čˆ‡ęØ£å¼", + "editorColors.strings": "čØ­å®šå­—äø²åøøå€¼ēš„č‰²å½©čˆ‡ęØ£å¼ć€‚", + "editorColors.keywords": "čØ­å®šé—œéµå­—ēš„č‰²å½©čˆ‡ęØ£å¼ć€‚", + "editorColors.numbers": "čØ­å®šę•øå­—åøøå€¼ēš„č‰²å½©čˆ‡ęØ£å¼ć€‚", + "editorColors.types": "čØ­å®šåž‹åˆ„å®£å‘Ščˆ‡åƒč€ƒēš„č‰²å½©čˆ‡ęØ£å¼ć€‚", + "editorColors.functions": "čØ­å®šå‡½å¼å®£å‘Ščˆ‡åƒč€ƒēš„č‰²å½©čˆ‡ęØ£å¼ć€‚", + "editorColors.variables": "čØ­å®šč®Šę•øå®£å‘Ščˆ‡åƒč€ƒēš„č‰²å½©čˆ‡ęØ£å¼ć€‚", + "editorColors.textMateRules": "使用 TextMate ä½ˆę™Æäø»é”Œč¦å‰‡čØ­å®šč‰²å½©čˆ‡ęØ£å¼ (進階)怂" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/cht/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..96e1b32dbec --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "openWorkspaceConfigurationFile": "é–‹å•Ÿå·„ä½œå€ēµ„ę…‹ęŖ”", + "close": "關閉", + "enterWorkspace.close": "關閉", + "enterWorkspace.dontShowAgain": "äøč¦å†é”Æē¤ŗ", + "enterWorkspace.moreInfo": "č©³ē“°č³‡čØŠ" +} \ No newline at end of file diff --git a/i18n/deu/extensions/azure-account/out/azure-account.i18n.json b/i18n/deu/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..f949c193bfe --- /dev/null +++ b/i18n/deu/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "Kopieren & Ɩffnen", + "azure-account.close": "Schließen", + "azure-account.login": "Anmelden", + "azure-account.loginFirst": "Nicht angemeldet, bitte zuerst anmelden.", + "azure-account.userCodeFailed": "Fehler beim Erfassen von Benutzercode.", + "azure-account.tokenFailed": "Token wird mit GerƤtecode erfasst", + "azure-account.tokenFromRefreshTokenFailed": "Token wird mit Aktualisierungstoken erfasst" +} \ No newline at end of file diff --git a/i18n/deu/extensions/azure-account/out/extension.i18n.json b/i18n/deu/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..1b7d65fb173 --- /dev/null +++ b/i18n/deu/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: Melde an...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 7dc4d240d04..c0f121afb2f 100644 --- a/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/deu/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "z.Ā B. myFile.txt", - "activeEditorMedium": "e.g. myFolder/myFile.txt", - "activeEditorLong": "e.g. /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "z. B. meinOrdner1, meinOrdner2, meinOrdner3", - "rootPath": "z.Ā B. /Users/Development/myProject", - "folderName": "z. B. meinOrdner", - "folderPath": "z. B. /Users/Development/meinOrdner", + "activeEditorShort": "Der Dateiname (z.B. meineDatei.txt)", + "activeEditorMedium": "der Pfad der Datei relativ zum Workspace-Ordner (z.B. myFolder/myFile.txt)", + "activeEditorLong": "Der vollstƤndige Pfad der Datei (z.B. /Benutzer/Entwicklung/meinProjekt/meinOrdner/meineDatei.txt)", + "rootName": "Name des Arbeitsbereichs (z.B. meinOrdner oder meinArbeitsberech)", + "rootPath": "Dateipfad des Arbeitsbereichs (z.B. /Benutzer/Entwicklung/meinArbeitsbereich)", + "folderName": "Name des Workspace-Ordners, der die Datei enthƤlt (z.B. MeinOrdner)", + "folderPath": "Dateipfad des Workspace-Ordners, der die Datei enthƤlt (z.B. /Benutzer/Entwicklung/MeinOrdner)", "appName": "z.Ā B. VS Code", "dirty": "Ein geƤnderter Indikator, wenn der aktive Editor geƤndert wurde", "separator": "Ein bedingtes Trennzeichen (' - '), das nur in der Umgebung von Variablen mit Werten angezeigt wird", diff --git a/i18n/deu/extensions/css/package.i18n.json b/i18n/deu/extensions/css/package.i18n.json index 3f52af8f41e..2fd30b43e1f 100644 --- a/i18n/deu/extensions/css/package.i18n.json +++ b/i18n/deu/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "Ungültige Parameteranzahl.", "css.lint.boxModel.desc": "Verwenden Sie width oder height nicht beim Festlegen von padding oder border", "css.lint.compatibleVendorPrefixes.desc": "Stellen Sie beim Verwenden vom anbieterspezifischen PrƤfix sicher, dass alle anderen anbieterspezifischen Eigenschaften miteinbezogen werden", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "Unbekannte anbieterspezifische Eigenschaft.", "css.lint.vendorPrefix.desc": "Beim Verwenden von anbieterspezifischen PrƤfix auch die Standardeigenschaft miteinbeziehen", "css.lint.zeroUnits.desc": "Keine Einheit für Null erforderlich", + "css.trace.server.desc": "Verfolgt die Kommunikation zwischen VS Code und dem CSS-Sprachserver.", + "css.validate.title": "Steuert die CSS-Validierung und Problemschweregrade.", "css.validate.desc": "Aktiviert oder deaktiviert alle Überprüfungen.", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "Ungültige Parameteranzahl.", "less.lint.boxModel.desc": "Verwenden Sie width oder height nicht beim Festlegen von padding oder border", "less.lint.compatibleVendorPrefixes.desc": "Stellen Sie beim Verwenden vom anbieterspezifischen PrƤfix sicher, dass alle anderen anbieterspezifischen Eigenschaften miteinbezogen werden", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "Unbekannte anbieterspezifische Eigenschaft.", "less.lint.vendorPrefix.desc": "Beim Verwenden von anbieterspezifischen PrƤfix auch die Standardeigenschaft miteinbeziehen", "less.lint.zeroUnits.desc": "Keine Einheit für Null erforderlich", + "less.validate.title": "Steuert die LESS-Validierung und Problemschweregrade.", "less.validate.desc": "Aktiviert oder deaktiviert alle Überprüfungen.", + "scss.title": "SCSS (SASS)", "scss.lint.argumentsInColorFunction.desc": "Ungültige Parameteranzahl.", "scss.lint.boxModel.desc": "Verwenden Sie width oder height nicht beim Festlegen von padding oder border", "scss.lint.compatibleVendorPrefixes.desc": "Stellen Sie beim Verwenden vom anbieterspezifischen PrƤfix sicher, dass alle anderen anbieterspezifischen Eigenschaften miteinbezogen werden", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "Unbekannte anbieterspezifische Eigenschaft.", "scss.lint.vendorPrefix.desc": "Beim Verwenden von anbieterspezifischen PrƤfix auch die Standardeigenschaft miteinbeziehen", "scss.lint.zeroUnits.desc": "Keine Einheit für Null erforderlich", + "scss.validate.title": "Steuert die SCSS-Überprüfung und Problemschweregrade.", "scss.validate.desc": "Aktiviert oder deaktiviert alle Überprüfungen.", "less.colorDecorators.enable.desc": "Aktiviert oder deaktiviert Farb-Decorators", "scss.colorDecorators.enable.desc": "Aktiviert oder deaktiviert Farb-Decorators", - "css.colorDecorators.enable.desc": "Aktiviert oder deaktiviert Farb-Decorators" + "css.colorDecorators.enable.desc": "Aktiviert oder deaktiviert Farb-Decorators", + "css.colorDecorators.enable.deprecationMessage": "Die Einstellung \"css.colorDecorators.enable\" ist veraltet und wurde durch \"editor.colorDecorators\" ersetzt.", + "scss.colorDecorators.enable.deprecationMessage": "Die Einstellung \"scss.colorDecorators.enable\" ist veraltet und wurde durch \"editor.colorDecorators\" ersetzt.", + "less.colorDecorators.enable.deprecationMessage": "Die Einstellung \"less.colorDecorators.enable\" ist veraltet und wurde durch \"editor.colorDecorators\" ersetzt." } \ No newline at end of file diff --git a/i18n/deu/extensions/emmet/package.i18n.json b/i18n/deu/extensions/emmet/package.i18n.json index 8b6ad71cd4e..7c71a6c1109 100644 --- a/i18n/deu/extensions/emmet/package.i18n.json +++ b/i18n/deu/extensions/emmet/package.i18n.json @@ -3,4 +3,38 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "command.wrapWithAbbreviation": "Mit Abkürzung umschließen", + "command.wrapIndividualLinesWithAbbreviation": "Einzelne Zeilen mit Abkürzung umschließen", + "command.removeTag": "Tag entfernen", + "command.updateTag": "Tag aktualisieren", + "command.matchTag": "Gehe zu übereinstimmendem Paar", + "command.balanceIn": "Ausgleichen (einwƤrts)", + "command.balanceOut": "Ausgleichen (auswƤrts)", + "command.prevEditPoint": "Gehe zum vorherigen Bearbeitungspunkt", + "command.nextEditPoint": "Gehe zum nƤchsten Bearbeitungspunkt", + "command.mergeLines": "Zeilen mergen", + "command.selectPrevItem": "Vorheriges Element auswƤhlen", + "command.selectNextItem": "NƤchstes Element auswƤhlen", + "command.splitJoinTag": "Tag teilen/verknüpfen", + "command.toggleComment": "Kommentar ein-/ausschalten", + "command.evaluateMathExpression": "Mathematischen Ausdruck auswerten", + "command.updateImageSize": "Bildgröße aktualisieren", + "command.reflectCSSValue": "CSS-Wert reflektieren", + "command.incrementNumberByOne": "Um 1 erhƶhen", + "command.decrementNumberByOne": "Um 1 verringern", + "command.incrementNumberByOneTenth": "Um 0,1 erhƶhen", + "command.decrementNumberByOneTenth": "Um 0,1 verringern", + "command.incrementNumberByTen": "Um 10 erhƶhen", + "command.decrementNumberByTen": "Um 10 verringern", + "emmetSyntaxProfiles": "Definieren Sie das Profil für die angegebene Syntax, oder verwenden Sie Ihr eigenes Profil mit bestimmten Regeln.", + "emmetPreferences": "Einstellungen, die zum Ƅndern des Verhaltens einiger Aktionen und Konfliktlƶser von Emmet verwendet werden.", + "emmetPreferencesIntUnit": "Standardeinheit für Integerwerte", + "emmetPreferencesFloatUnit": "Standardeinheit für Floatwerte", + "emmetPreferencesCssAfter": "Symbol, das beim Erweitern von CSS-Abkürzungen am Ende der CSS-Eigenschaft eingefügt werden soll", + "emmetPreferencesSassAfter": "Symbol, das beim Erweitern von CSS-Abkürzungen in Sass-Dateien am Ende der CSS-Eigenschaft eingefügt werden soll", + "emmetPreferencesStylusAfter": "Symbol, das beim Erweitern von CSS-Abkürzungen in Stylus-Dateien am Ende der CSS-Eigenschaft eingefügt werden soll", + "emmetPreferencesCssBetween": "Symbol, das beim Erweitern von CSS-Abkürzungen zwischen der CSS-Eigenschaft und dem Wert eingefügt werden soll", + "emmetPreferencesSassBetween": "Symbol, das beim Erweitern von CSS-Abkürzungen in Sass-Dateien zwischen der CSS-Eigenschaft und dem Wert eingefügt werden soll", + "emmetPreferencesStylusBetween": "Symbol, das beim Erweitern von CSS-Abkürzungen in Stylus-Dateien zwischen der CSS-Eigenschaft und dem Wert eingefügt werden soll" +} \ No newline at end of file diff --git a/i18n/deu/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/deu/extensions/extension-editing/out/extensionLinter.i18n.json index 03fa4d766d9..31af64199eb 100644 --- a/i18n/deu/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/deu/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "Für Bilder muss das HTTPS-Protokoll verwendet werden.", "svgsNotValid": "SVGs sind keine gültige Bildquelle.", "embeddedSvgsNotValid": "Eingebettete SVGs sind keine gültige Bildquelle.", - "dataUrlsNotValid": "Daten-URLs sind keine gültige Bildquelle." + "dataUrlsNotValid": "Daten-URLs sind keine gültige Bildquelle.", + "relativeUrlRequiresHttpsRepository": "Relative Bild-URLs erfordern die Angabe eines Repositorys mit dem HTTPS-Protokoll in der Datei \"package.json\".", + "relativeIconUrlRequiresHttpsRepository": "Ein Symbol erfordert die Angabe eines Repositorys mit dem HTTPS-Protokoll in dieser Datei \"package.json\".", + "relativeBadgeUrlRequiresHttpsRepository": "Relative Badge-URLs erfordern die Angabe eines Repositorys mit dem HTTPS-Protokoll in dieser Datei \"package.json\"." } \ No newline at end of file diff --git a/i18n/deu/extensions/git/out/commands.i18n.json b/i18n/deu/extensions/git/out/commands.i18n.json index 87d98409dd9..3f2fcad2989 100644 --- a/i18n/deu/extensions/git/out/commands.i18n.json +++ b/i18n/deu/extensions/git/out/commands.i18n.json @@ -6,21 +6,39 @@ { "tag at": "Tag bei {0}", "remote branch at": "Remotebranch unter {0}", + "create branch": "$(plus) Neuen Branch erstellen", "repourl": "Repository-URL", "parent": "Übergeordnetes Verzeichnis", "cloning": "Git-Repository wird geklont...", "openrepo": "Repository ƶffnen", "proposeopen": "Mƶchten Sie das geklonte Repository ƶffnen?", + "init repo": "Repository initialisieren", + "create repo": "Repository initialisieren", + "are you sure": "Erstellt ein Git-Repository unter '{0}'. Sind Sie sicher das Sie weiterfahren mƶchten?", "HEAD not available": "Es ist keine HEAD-Version von \"{0}\" verfügbar.", + "confirm stage files with merge conflicts": "Mƶchten Sie {0} Dateien mit Mergingkonflikten bereitstellen?", + "confirm stage file with merge conflicts": "Mƶchten Sie {0} mit Mergingkonflikten bereitstellen?", + "yes": "Ja", "confirm revert": "Mƶchten Sie ausgewƤhlten Ƅnderungen in {0} wirklich zurücksetzen?", "revert": "Ƅnderungen zurücksetzen", + "discard": "Ƅnderungen verwerfen", + "confirm delete": "Mƶchten Sie \"{0}\" wirklich LƖSCHEN?", + "delete file": "Datei lƶschen", "confirm discard": "Mƶchten Sie die Ƅnderungen in {0} wirklich verwerfen?", "confirm discard multiple": "Mƶchten Sie wirklich Ƅnderungen in {0} Dateien verwerfen?", - "discard": "Ƅnderungen verwerfen", - "confirm discard all": "Mƶchten Sie wirklich ALLE Ƅnderungen verwerfen? Dieser Vorgang kann nicht rückgƤngig gemacht werden!", - "discardAll": "ALLE Ƅnderungen verwerfen", + "warn untracked": "Dies wird {0} nicht verfolgte Dateien LƖSCHEN!", + "confirm discard all single": "Mƶchten Sie die Ƅnderungen in {0} wirklich verwerfen?", + "confirm discard all": "Mƶchten Sie ALLE Ƅnderungen in {0} Dateien verwerfen?\nDies kann NICHT rückgƤngig gemacht werden.\nIhr aktueller Arbeitssatz geht dadurch DAUERHAFT verloren.", + "discardAll multiple": "Eine Datei verwerfen", + "discardAll": "Alle {0} Dateien verwerfen", + "confirm delete multiple": "Mƶchten Sie {0} Dateien LƖSCHEN?", + "delete files": "Dateien lƶschen", + "there are untracked files single": "Die folgende nicht verfolgte Datei wird VOM DATENTRƄGER GELƖSCHT, wenn sie verworfen wird: {0}.", + "there are untracked files": "Es sind {0} nicht verfolgte Dateien vorhanden, die VOM DATENTRƄGER GELƖSCHT werden, wenn sie verworfen werden.", + "confirm discard all 2": "{0}\n\nDies kann NICHT rückgƤngig gemacht werden, und Ihr aktueller Arbeitssatz geht DAUERHAFT verloren.", + "yes discard tracked": "1 verfolgte Datei verwerfen", + "yes discard tracked multiple": "{0} verfolgte Dateien verwerfen", "no staged changes": "Es sind keine Ƅnderungen bereitgestellt.\n\nMƶchten Sie alle Ihre Ƅnderungen automatisch bereitstellen und direkt committen?", - "yes": "Ja", "always": "Immer", "no changes": "Keine Ƅnderungen zum Speichern vorhanden.", "commit message": "Commit-Nachricht", @@ -33,16 +51,25 @@ "delete branch": "Branch lƶschen", "select a branch to merge from": "Branch für die Zusammenführung auswƤhlen", "merge conflicts": "Es liegen Zusammenführungskonflikte vor. Beheben Sie die Konflikte vor dem Committen.", + "tag name": "Tag-Name", + "provide tag name": "Geben Sie einen Tagnamen an.", + "tag message": "Nachricht", + "provide tag message": "Geben Sie eine Meldung ein, um das Tag mit einer Anmerkung zu versehen.", "no remotes to pull": "In Ihrem Repository wurden keine Remoteelemente für den Pull konfiguriert.", "pick remote pull repo": "Remoteelement zum Pullen des Branch auswƤhlen", "no remotes to push": "In Ihrem Repository wurden keine Remoteelemente für den Push konfiguriert.", + "push with tags success": "Push mit Tags erfolgreich ausgeführt.", "nobranch": "WƤhlen Sie ein Branch für den Push zu einem Remoteelement aus.", "pick remote": "Remotespeicherort auswƤhlen, an dem der Branch \"{0}\" verƶffentlicht wird:", "sync is unpredictable": "Mit dieser Aktion werden Commits per Push und Pull an und von \"{0}\" übertragen.", "ok": "OK", "never again": "OK, nicht mehr anzeigen", "no remotes to publish": "In Ihrem Repository wurden keine Remoteelemente für die Verƶffentlichung konfiguriert.", - "disabled": "Git ist deaktiviert oder wird in diesem Arbeitsbereich nicht unterstützt.", + "no changes stash": "Es sind keine Ƅnderungen vorhanden, für die ein Stash ausgeführt werden kann.", + "provide stash message": "Geben Sie optional eine Stash-Nachricht ein.", + "stash message": "Stash-Nachricht", + "no stashes": "Es ist kein Stash zum Wiederherstellen vorhanden.", + "pick stash to pop": "WƤhlen Sie einen Stash aus, für den ein Pop ausgeführt werden soll.", "clean repo": "Bereinigen Sie Ihre Repository-Arbeitsstruktur vor Auftragsabschluss.", "cant push": "Verweise kƶnnen nicht per Push an einen Remotespeicherort übertragen werden. Führen Sie zuerst \"Pull\" aus, um Ihre Ƅnderungen zu integrieren.", "git error details": "Git: {0}", diff --git a/i18n/deu/extensions/git/out/model.i18n.json b/i18n/deu/extensions/git/out/model.i18n.json index 681e5ffa795..5e1088116a0 100644 --- a/i18n/deu/extensions/git/out/model.i18n.json +++ b/i18n/deu/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Ɩffnen", - "merge changes": "Ƅnderungen zusammenführen", - "staged changes": "Bereitgestellte Ƅnderungen", - "changes": "Ƅnderungen", - "ok": "OK", - "neveragain": "Nie wieder anzeigen", - "huge": "Das Git-Repository unter {0} umfasst zu viele aktive Ƅnderungen. Nur ein Teil der Git-Features wird aktiviert." + "no repositories": "Es sind keine verfügbaren Repositorys vorhanden.", + "pick repo": "Repository auswƤhlen" } \ No newline at end of file diff --git a/i18n/deu/extensions/git/out/repository.i18n.json b/i18n/deu/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..eeff60b713c --- /dev/null +++ b/i18n/deu/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "Ɩffnen", + "index modified": "Index geƤndert", + "modified": "GeƤndert am", + "index added": "Index hinzugefügt", + "index deleted": "Index gelƶscht", + "deleted": "Gelƶscht", + "index renamed": "Index umbenannt", + "index copied": "Index kopiert", + "untracked": "Nicht verfolgt", + "ignored": "Ignoriert", + "both deleted": "Beide gelƶscht", + "added by us": "Hinzugefügt von uns", + "deleted by them": "Gelƶscht von anderen", + "added by them": "Hinzugefügt von anderen", + "deleted by us": "Gelƶscht von uns", + "both added": "Beide hinzugefügt", + "both modified": "Beide geƤndert", + "commit": "Commit", + "merge changes": "Ƅnderungen zusammenführen", + "staged changes": "Bereitgestellte Ƅnderungen", + "changes": "Ƅnderungen", + "ok": "OK", + "neveragain": "Nie wieder anzeigen", + "huge": "Das Git-Repository unter {0} umfasst zu viele aktive Ƅnderungen. Nur ein Teil der Git-Features wird aktiviert." +} \ No newline at end of file diff --git a/i18n/deu/extensions/git/package.i18n.json b/i18n/deu/extensions/git/package.i18n.json index baffc6c4018..42eb8374ef1 100644 --- a/i18n/deu/extensions/git/package.i18n.json +++ b/i18n/deu/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "Klonen", "command.init": "Repository initialisieren", + "command.close": "Repository schließen", "command.refresh": "Aktualisieren", "command.openChange": "Ƅnderungen ƶffnen", "command.openFile": "Datei ƶffnen", @@ -14,6 +15,8 @@ "command.stageAll": "Alle Ƅnderungen bereitstellen", "command.stageSelectedRanges": "GewƤhlte Bereiche bereitstellen", "command.revertSelectedRanges": "AusgewƤhlte Bereiche zurücksetzen", + "command.stageChange": "Ƅnderung bereitstellen", + "command.revertChange": "Ƅnderung zurücksetzen", "command.unstage": "Bereitstellung der Ƅnderungen aufheben", "command.unstageAll": "Bereitstellung aller Ƅnderungen aufheben", "command.unstageSelectedRanges": "Bereitstellung gewƤhlter Bereiche aufheben", @@ -22,22 +25,29 @@ "command.commit": "Commit", "command.commitStaged": "Commit bereitgestellt", "command.commitStagedSigned": "Bereitgestelltes committen (unterzeichnet)", + "command.commitStagedAmend": "Gestaffelt committen (Ƅndern)", "command.commitAll": "Commit für alle ausführen", "command.commitAllSigned": "Alle committen (unterzeichnet)", + "command.commitAllAmend": "Commit für alle ausführen (Ƅndern)", "command.undoCommit": "Letzten Commit rückgƤngig machen", "command.checkout": "Auschecken an...", "command.branch": "Branch erstellen...", "command.deleteBranch": "Branch lƶschen...", "command.merge": "Branch zusammenführen...", + "command.createTag": "Tag erstellen", "command.pull": "Pull", "command.pullRebase": "Pull (Rebase)", "command.pullFrom": "Pullen von...", "command.push": "Push", "command.pushTo": "Push zu...", + "command.pushWithTags": "Push mit Tags ausführen", "command.sync": "Synchronisierung", "command.publish": "Branch verƶffentlichen", "command.showOutput": "Git-Ausgabe anzeigen", "command.ignore": "Datei zu .gitignore hinzufügen", + "command.stash": " Stash ausführen", + "command.stashPop": "Pop für Stash ausführen...", + "command.stashPopLatest": "Pop für letzten Stash ausführen", "config.enabled": "Gibt an, ob Git aktiviert ist.", "config.path": "Der Pfad zur ausführbaren Git-Datei.", "config.autorefresh": "Gibt an, ob die automatische Aktualisierung aktiviert ist.", @@ -49,5 +59,7 @@ "config.ignoreLegacyWarning": "Ignoriert die Legacy-Git-Warnung.", "config.ignoreLimitWarning": "Ignoriert Warnung bei zu hoher Anzahl von Ƅnderungen in einem Repository", "config.defaultCloneDirectory": "Das Standard-Verzeichnis für einen Klon eines Git-Repositorys", - "config.enableSmartCommit": "Alle Ƅnderungen committen, wenn keine bereitgestellten Ƅnderungen vorhanden sind." + "config.enableSmartCommit": "Alle Ƅnderungen committen, wenn keine bereitgestellten Ƅnderungen vorhanden sind.", + "config.enableCommitSigning": "Aktiviert das Signieren von Commits per GPG.", + "config.discardAllScope": "Legt fest, welche Ƅnderungen vom Befehl \"Alle Ƅnderungen verwerfen\" verworfen werden. \"all\" verwirft alle Ƅnderungen. \"tracked\" verwirft nur verfolgte Dateien. \"prompt\" zeigt immer eine Eingabeaufforderung an, wenn die Aktion ausgeführt wird." } \ No newline at end of file diff --git a/i18n/deu/extensions/grunt/out/main.i18n.json b/i18n/deu/extensions/grunt/out/main.i18n.json index b1c5165293c..47bed6eef41 100644 --- a/i18n/deu/extensions/grunt/out/main.i18n.json +++ b/i18n/deu/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Fehler bei der automatischen Grunt-Erkennung. Fehlermeldung: {0}" + "execFailed": "Fehler bei der automatischen Grunt-Erkennung für den Ordner {0}. Fehlermeldung: {1}" } \ No newline at end of file diff --git a/i18n/deu/extensions/gulp/out/main.i18n.json b/i18n/deu/extensions/gulp/out/main.i18n.json index a4ddf3b18b8..7d146a15f94 100644 --- a/i18n/deu/extensions/gulp/out/main.i18n.json +++ b/i18n/deu/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Fehler bei der automatischen Gulp-Erkennung. Fehlermeldung: {0}" + "execFailed": "Fehler bei der automatischen Gulp-Erkennung für den Ordner {0}. Fehlermeldung: {1}" } \ No newline at end of file diff --git a/i18n/deu/extensions/html/package.i18n.json b/i18n/deu/extensions/html/package.i18n.json index fa64ca7a131..276d5c08aae 100644 --- a/i18n/deu/extensions/html/package.i18n.json +++ b/i18n/deu/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "Standard-HTML-Formatierer aktivieren/deaktivieren (Neustart erforderlich)", + "html.format.enable.desc": "Standard-HTML-Formatierer aktivieren/deaktivieren", "html.format.wrapLineLength.desc": "Die maximale Anzahl von Zeichen pro Zeile (0 = deaktiviert).", "html.format.unformatted.desc": "Die Liste der Tags (durch Kommas getrennt), die nicht erneut formatiert werden sollen. \"null\" bezieht sich standardmäßig auf alle Tags, die unter https://www.w3.org/TR/html5/dom.html#phrasing-content aufgeführt werden.", "html.format.contentUnformatted.desc": "Liste der Tags (durch Trennzeichen getrennt), in der der Inhalt nicht neu formatiert werden muss. \"null\" entspricht standardmäßig dem Tag \"pre\".", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "Konfiguriert, ob die integrierte HTML-Sprachuntersützung Angular V1-Tags und -Eigenschaften vorschlƤgt.", "html.suggest.ionic.desc": "Konfiguriert, ob die integrierte HTML-Sprachuntersützung Ionic-Tags, -Eigenschaften und -Werte vorschlƤgt.", "html.suggest.html5.desc": "Konfiguriert, ob die integrierte HTML-Sprachuntersützung HTML5-Tags, -Eigenschaften und -Werte vorschlƤgt.", + "html.trace.server.desc": "Verfolgt die Kommunikation zwischen VS Code und dem HTML-Sprachserver.", "html.validate.scripts": "Konfiguriert, ob die integrierte HTML-Sprachunterstützung eingebettete Skripts unterstützt.", - "html.validate.styles": "Konfiguriert, ob die integrierte HTML-Sprachunterstützung eingebettete Skripts validiert." + "html.validate.styles": "Konfiguriert, ob die integrierte HTML-Sprachunterstützung eingebettete Skripts validiert.", + "html.autoClosingTags": "Automatisches Schließen von HTML-Tags aktivieren/deaktivieren." } \ No newline at end of file diff --git a/i18n/deu/extensions/jake/out/main.i18n.json b/i18n/deu/extensions/jake/out/main.i18n.json index 83268c00071..48ad4462aeb 100644 --- a/i18n/deu/extensions/jake/out/main.i18n.json +++ b/i18n/deu/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Fehler bei der automatischen Jake-Erkennung. Fehlermeldung: {0}" + "execFailed": "Fehler bei der automatischen Jake-Erkennung für den Ordner {0}. Fehlermeldung: {1}" } \ No newline at end of file diff --git a/i18n/deu/extensions/json/package.i18n.json b/i18n/deu/extensions/json/package.i18n.json index 63c14903906..7536827f7aa 100644 --- a/i18n/deu/extensions/json/package.i18n.json +++ b/i18n/deu/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "Die Schemadefinition für die angegebene URL. Das Schema muss nur angegeben werden, um Zugriffe auf die Schema-URL zu vermeiden.", "json.format.enable.desc": "Standard-JSON-Formatierer aktivieren/deaktivieren (Neustart erforderlich)", "json.tracing.desc": "Verfolgt die Kommunikation zwischen VS Code und JSON-Sprachserver nach.", - "json.colorDecorators.enable.desc": "Aktiviert oder deaktiviert Farb-Decorators" + "json.colorDecorators.enable.desc": "Aktiviert oder deaktiviert Farb-Decorators", + "json.colorDecorators.enable.deprecationMessage": "Die Einstellung \"json.colorDecorators.enable\" ist veraltet und wurde durch \"editor.colorDecorators\" ersetzt." } \ No newline at end of file diff --git a/i18n/deu/extensions/markdown/out/extension.i18n.json b/i18n/deu/extensions/markdown/out/extension.i18n.json index 490139dcf55..9c9948137e9 100644 --- a/i18n/deu/extensions/markdown/out/extension.i18n.json +++ b/i18n/deu/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "'markdown.styles' konnte nicht geladen werden: {0}" + "onPreviewStyleLoadError": "'markdown.styles' konnte nicht geladen werden: {0}", + "previewTitle": "Vorschau von {0}" } \ No newline at end of file diff --git a/i18n/deu/extensions/markdown/out/previewContentProvider.i18n.json b/i18n/deu/extensions/markdown/out/previewContentProvider.i18n.json index 8b6ad71cd4e..5a04ed5447d 100644 --- a/i18n/deu/extensions/markdown/out/previewContentProvider.i18n.json +++ b/i18n/deu/extensions/markdown/out/previewContentProvider.i18n.json @@ -3,4 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "preview.securityMessage.text": "In diesem Dokument wurden einige Inhalte deaktiviert.", + "preview.securityMessage.title": "Potenziell unsichere Inhalte wurden in der Markdown-Vorschau deaktiviert. Ƅndern Sie die Sicherheitseinstellung der Markdown-Vorschau, um unsichere Inhalte zuzulassen oder Skripts zu aktivieren.", + "preview.securityMessage.label": "Sicherheitswarnung – Inhalt deaktiviert" +} \ No newline at end of file diff --git a/i18n/deu/extensions/markdown/out/security.i18n.json b/i18n/deu/extensions/markdown/out/security.i18n.json index 62705e93d91..70533ed2e5d 100644 --- a/i18n/deu/extensions/markdown/out/security.i18n.json +++ b/i18n/deu/extensions/markdown/out/security.i18n.json @@ -4,5 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.currentSelection": "Aktuelle Einstellung" + "strict.title": "Strict", + "strict.description": "Nur sicheren Inhalt laden", + "insecureContent.title": "Unsicheren Inhalt zulassen", + "insecureContent.description": "Laden von Inhalten über HTTP aktivieren", + "disable.title": "Deaktivieren", + "disable.description": "Alle Inhalte und Skriptausführung zulassen. Nicht empfohlen.", + "moreInfo.title": "Weitere Informationen", + "preview.showPreviewSecuritySelector.title": "Sicherheitseinstellungen für die Markdown-Vorschau in diesem Arbeitsbereich auswƤhlen" } \ No newline at end of file diff --git a/i18n/deu/extensions/markdown/package.i18n.json b/i18n/deu/extensions/markdown/package.i18n.json index 1e0e2709f9c..14ba4116cc2 100644 --- a/i18n/deu/extensions/markdown/package.i18n.json +++ b/i18n/deu/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "Legt fest, wie Zeilenumbrüche in der Markdown-Vorschau gerendert werden. Die Einstellung 'true' erzeugt ein
für jede neue Zeile.", + "markdown.preview.linkify": "Aktiviert oder deaktiviert die Konvertierung von URL-Ƥhnlichem Text in Links in der Markdown-Vorschau.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Doppelklicken Sie in die Markdown-Vorschau, um zum Editor zu wechseln.", "markdown.preview.fontFamily.desc": "Steuert die Schriftfamilie, die in der Markdownvorschau verwendet wird.", "markdown.preview.fontSize.desc": "Steuert den Schriftgrad in Pixeln, der in der Markdownvorschau verwendet wird.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "Vorschau an der Seite ƶffnen", "markdown.showSource.title": "Quelle anzeigen", "markdown.styles.dec": "Eine Liste von URLs oder lokalen Pfaden zu CSS-Stylesheets aus der Markdownvorschau, die verwendet werden sollen. Relative Pfade werden relativ zu dem Ordner interpretiert, der im Explorer geƶffnet ist. Wenn kein Ordner geƶffnet ist, werden sie relativ zum Speicherort der Markdowndatei interpretiert. Alle '\\' müssen als '\\\\' geschrieben werden.", - "markdown.showPreviewSecuritySelector.title": "Sicherheitseinstellungen für Markdown-Vorschau Ƥndern", - "markdown.trace.desc": "Aktiviert die Debugprotokollierung für die Markdown-Erweiterung." + "markdown.showPreviewSecuritySelector.title": "Sicherheitseinstellungen für Vorschau Ƥndern", + "markdown.trace.desc": "Aktiviert die Debugprotokollierung für die Markdown-Erweiterung.", + "markdown.refreshPreview.title": "Vorschau aktualisieren" } \ No newline at end of file diff --git a/i18n/deu/extensions/npm/out/main.i18n.json b/i18n/deu/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/deu/extensions/npm/out/main.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/deu/extensions/npm/package.i18n.json b/i18n/deu/extensions/npm/package.i18n.json index df3491b4c05..6d17843d6df 100644 --- a/i18n/deu/extensions/npm/package.i18n.json +++ b/i18n/deu/extensions/npm/package.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "config.npm.autoDetect": "Steuert, ob die automatische Erkennung von NPM-Skripts aktiviert oder deaktiviert ist. Standardmäßig ist die Funktion aktiviert." + "config.npm.autoDetect": "Steuert, ob die automatische Erkennung von NPM-Skripts aktiviert oder deaktiviert ist. Standardmäßig ist die Funktion aktiviert.", + "config.npm.runSilent": "npm-Befehle mit der Option \"--silent\" ausführen" } \ No newline at end of file diff --git a/i18n/deu/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/deu/extensions/typescript/out/features/taskProvider.i18n.json index 8b6ad71cd4e..a83c5139202 100644 --- a/i18n/deu/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/deu/extensions/typescript/out/features/taskProvider.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "buildTscLabel": "Erstellen – {0}", + "buildAndWatchTscLabel": "Überwachen – {0}" +} \ No newline at end of file diff --git a/i18n/deu/extensions/typescript/out/utils/api.i18n.json b/i18n/deu/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..ac7390c715a --- /dev/null +++ b/i18n/deu/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "Ungültige Version" +} \ No newline at end of file diff --git a/i18n/deu/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/deu/extensions/typescript/out/utils/versionPicker.i18n.json index 26d4c60ec0c..ffcda022595 100644 --- a/i18n/deu/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/deu/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "Version von VSCode verwenden", + "useVSCodeVersionOption": "Version von VS Code verwenden", "useWorkspaceVersionOption": "Arbeitsbereichsversion verwenden", "learnMore": "Weitere Informationen", "selectTsVersion": "WƤhlen Sie die für die JavaScript- und TypeScript-Sprachfunktionen verwendete TypeScript-Version aus." diff --git a/i18n/deu/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/deu/extensions/typescript/out/utils/versionProvider.i18n.json index 06879a8a5e4..620d3948729 100644 --- a/i18n/deu/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/deu/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "Der tsserver von VSCode wurde von einer anderen Anwendung wie etwa einem fehlerhaften Tool zur Viruserkennung gelƶscht. Führen Sie eine Neuinstallation von VS Code durch." + "couldNotLoadTsVersion": "Die TypeScript-Version konnte unter diesem Pfad nicht geladen werden.", + "noBundledServerFound": "Der tsserver von VS Code wurde von einer anderen Anwendung wie etwa einem fehlerhaften Tool zur Viruserkennung gelƶscht. Führen Sie eine Neuinstallation von VS Code durch." } \ No newline at end of file diff --git a/i18n/deu/extensions/typescript/package.i18n.json b/i18n/deu/extensions/typescript/package.i18n.json index a0a44b0a6f3..3725f9400c0 100644 --- a/i18n/deu/extensions/typescript/package.i18n.json +++ b/i18n/deu/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "VervollstƤndigen Sie Funktionen mit deren Parametersignatur.", "typescript.tsdk.desc": "Gibt den Ordnerpfad mit den zu verwendenden tsserver- und lib*.d.ts-Dateien an.", - "typescript.disableAutomaticTypeAcquisition": "Deaktiviert die automatische Typerfassung. Erfordert TypeScript >= 2.0.6 und einen Neustart nach der Ƅnderung.", + "typescript.disableAutomaticTypeAcquisition": "Deaktiviert die automatische Typerfassung. Erfordert TypeScript >= 2.0.6.", "typescript.tsserver.log": "Aktiviert die Protokollierung des TS-Servers in eine Datei. Mithilfe der Protokolldatei lassen sich Probleme beim TS-Server diagnostizieren. Die Protokolldatei kann Dateipfade, Quellcode und weitere potenziell sensible Informationen aus Ihrem Projekt enthalten.", "typescript.tsserver.trace": "Aktiviert die Ablaufverfolgung von an den TS-Server gesendeten Nachrichten. Mithilfe der Ablaufverfolgung lassen sich Probleme beim TS-Server diagnostizieren. Die Ablaufverfolgung kann Dateipfade, Quellcode und weitere potenziell sensible Informationen aus Ihrem Projekt enthalten.", "typescript.validate.enable": "TypeScript-Überprüfung aktivieren/deaktivieren.", @@ -44,7 +44,6 @@ "typescript.npm": "Gibt den Pfad zur ausführbaren NPM-Datei an, die für die automatische Typerfassung verwendet wird. Hierfür ist TypeScript 2.3.4 oder hƶher erforderlich.", "typescript.check.npmIsInstalled": "Überprüfen Sie, ob NPM für die automatische Typerfassung installiert ist.", "javascript.nameSuggestions": "Das Einbeziehen eindeutiger Namen von der Datei in der JavaScript-Vorschlagsliste aktivieren/deaktivieren.", - "typescript.tsc.autoDetect": "Steuert, ob die automatische Erkennung von tsc-Tasks aktiviert oder deaktiviert ist.\n", "typescript.problemMatchers.tsc.label": "TypeScript-Probleme", "typescript.problemMatchers.tscWatch.label": "TypeScript-Probleme (Überwachungsmodus)" } \ No newline at end of file diff --git a/i18n/deu/src/vs/code/electron-main/auth.i18n.json b/i18n/deu/src/vs/code/electron-main/auth.i18n.json index 8b6ad71cd4e..84f927c08ed 100644 --- a/i18n/deu/src/vs/code/electron-main/auth.i18n.json +++ b/i18n/deu/src/vs/code/electron-main/auth.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "authRequire": "Proxyauthentifizierung erforderlich", + "proxyauth": "Der Proxy {0} erfordert eine Authentifizierung." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/code/electron-main/menus.i18n.json b/i18n/deu/src/vs/code/electron-main/menus.i18n.json index 587b2aaa069..26bf3d1e020 100644 --- a/i18n/deu/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/deu/src/vs/code/electron-main/menus.i18n.json @@ -22,9 +22,11 @@ "miQuit": "{0} beenden", "miNewFile": "&&Neue Datei", "miOpen": "&&Ɩffnen...", + "miOpenWorkspace": "&&Arbeitsbereich ƶffnen...", "miOpenFolder": "&&Ordner ƶffnen...", "miOpenFile": "Datei &&ƶffnen...", "miOpenRecent": "&&Zuletzt verwendete ƶffnen", + "miSaveWorkspaceAs": "Arbeitsbereich &&speichern unter...", "miAddFolderToWorkspace": "&&Ordner zum Arbeitsbereich hinzufügen...", "miSave": "&&Speichern", "miSaveAs": "Speichern &&unter...", @@ -32,6 +34,7 @@ "miAutoSave": "Automatisch speichern", "miRevert": "D&&atei wiederherstellen", "miCloseWindow": "&&Fenster schließen", + "miCloseWorkspace": "A&&rbeitsbereich schließen", "miCloseFolder": "&&Ordner schließen", "miCloseEditor": "Editor s&&chließen", "miExit": "Beenden", @@ -44,6 +47,7 @@ "miPreferences": "&&Einstellungen", "miReopenClosedEditor": "&&Geschlossenen Editor erneut ƶffnen", "miMore": "&&Mehr...", + "miClearRecentOpen": "Zul&&etzt geƶffnete lƶschen", "miUndo": "&&RückgƤngig", "miRedo": "&&Wiederholen", "miCut": "Ausschneiden", @@ -98,6 +102,7 @@ "miHideActivityBar": "&&AktivitƤtsleiste ausblenden", "miShowActivityBar": "&&AktivitƤtsleiste anzeigen", "miToggleWordWrap": "&&Zeilenumbruch umschalten", + "miToggleMinimap": "&&Minikarte umschalten", "miToggleRenderWhitespace": "&&Rendern von Leerzeichen umschalten", "miToggleRenderControlCharacters": "&&Steuerzeichen umschalten", "miZoomIn": "&&Vergrößern", @@ -146,6 +151,10 @@ "mZoom": "Zoom", "mBringToFront": "Alle in den Vordergrund", "miSwitchWindow": "Fenster &&wechseln...", + "mShowPreviousTab": "Vorherige Registerkarte anzeigen", + "mShowNextTab": "NƤchste Registerkarte anzeigen", + "mMoveTabToNewWindow": "Registerkarte in neues Fenster verschieben", + "mMergeAllWindows": "Alle Fenster zusammenführen", "miToggleDevTools": "&&Entwicklertools umschalten", "miAccessibilityOptions": "&&Optionen für erleichterte Bedienung", "miReportIssues": "&&Probleme melden", @@ -163,10 +172,11 @@ "miAbout": "&&Info", "miRunTask": "Aufgabe ausfüh&&ren...", "miBuildTask": "&&Buildaufgabe ausführen...", + "miRunningTask": "Aktive Auf&&gaben anzeigen...", "miRestartTask": "Aktuell&&e Aufgabe neu starten...", "miTerminateTask": "&&Aufgabe beenden...", - "miConfigureTask": "Aufgaben &&konfigurieren", - "miConfigureBuildTask": "Standardbuildaufgabe kon&&figurieren", + "miConfigureTask": "Aufgaben &&konfigurieren...", + "miConfigureBuildTask": "Standardbuildaufgabe kon&&figurieren...", "accessibilityOptionsWindowTitle": "Optionen für erleichterte Bedienung", "miRestartToUpdate": "Zum Aktualisieren neu starten...", "miCheckingForUpdates": "Überprüfen auf Updates...", @@ -174,5 +184,6 @@ "miDownloadingUpdate": "Das Update wird heruntergeladen...", "miInstallingUpdate": "Update wird installiert...", "miCheckForUpdates": "Nach Aktualisierungen suchen...", + "aboutDetail": "\nVersion {0}\nCommit {1}\nDatum {2}\nShell {3}\nRenderer {4}\nNode {5}\nArchitektur {6}", "okButton": "OK" } \ No newline at end of file diff --git a/i18n/deu/src/vs/code/electron-main/windows.i18n.json b/i18n/deu/src/vs/code/electron-main/windows.i18n.json index 72c02e88f74..c4b92351759 100644 --- a/i18n/deu/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/deu/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,21 @@ "ok": "OK", "pathNotExistTitle": "Der Pfad ist nicht vorhanden.", "pathNotExistDetail": "Der Pfad \"{0}\" scheint auf dem DatentrƤger nicht mehr vorhanden zu sein.", - "reopen": "Erneut ƶffnen", - "wait": "Bitte warten.", - "close": "Schließen", "appStalled": "Das Fenster reagiert nicht mehr.", "appStalledDetail": "Sie kƶnnen das Fenster erneut ƶffnen oder schließen oder weiterhin warten.", "appCrashed": "Das Fenster ist abgestürzt.", "appCrashedDetail": "Bitte entschuldigen Sie die Unannehmlichkeiten. Sie kƶnnen das Fenster erneut ƶffnen und dort weitermachen, wo Sie aufgehƶrt haben.", + "open": "Ɩffnen", + "openFolder": "Ordner ƶffnen", "openFile": "Datei ƶffnen", - "openFolder": "Ordner ƶffnen" + "workspaceOpenedMessage": "Der Arbeitsbereich \"{0}\" kann nicht gespeichert werden.", + "workspaceOpenedDetail": "Der Arbeitsbereich ist bereits in einem anderen Fenster geƶffnet. Schließen Sie zuerst das andere Fenster, und versuchen Sie anschließend noch mal.", + "openWorkspace": "&&Ɩffnen", + "openWorkspaceTitle": "Arbeitsbereich ƶffnen", + "save": "&&Speichern", + "doNotSave": "&&Nicht speichern", + "cancel": "Abbrechen", + "saveWorkspaceMessage": "Mƶchten Sie Ihre Arbeitsbereichskonfiguration als Datei speichern?", + "saveWorkspaceDetail": "Speichern Sie Ihren Arbeitsbereich, wenn Sie ihn erneut ƶffnen mƶchten.", + "saveWorkspace": "Arbeitsbereich speichern" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/browser/widget/diffEditorWidget.i18n.json b/i18n/deu/src/vs/editor/browser/widget/diffEditorWidget.i18n.json index 8b6ad71cd4e..59257f107ff 100644 --- a/i18n/deu/src/vs/editor/browser/widget/diffEditorWidget.i18n.json +++ b/i18n/deu/src/vs/editor/browser/widget/diffEditorWidget.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "diff.tooLarge": "Kann die Dateien nicht vergleichen, da eine Datei zu groß ist." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json index c96d13745a4..74231bf551a 100644 --- a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "Steuert die Zeilenhƶhe. Verwenden Sie 0, um LineHeight aus der FontSize-Angabe zu berechnen.", "letterSpacing": "Steuert den Zeichenabstand in Pixeln.", "lineNumbers": "Steuert die Anzeige von Zeilennummern. Mƶgliche Werte sind \"Ein\", \"Aus\" und \"Relativ\". \"Relativ\" zeigt die Zeilenanzahl ab der aktuellen Cursorposition.", - "rulers": "Spalten, an denen vertikale Lineale angezeigt werden sollen", + "rulers": "VertikaleĀ Linien nach einer bestimmten Anzahl von Monospace Zeichen zeichnen. Verwenden Sie mehrere Werte für mehrere Linien. Keine Linie wird gezeichnet, wenn das Array leer ist.", "wordSeparators": "Zeichen, die als Worttrennzeichen verwendet werden, wenn wortbezogene Navigationen oder VorgƤnge ausgeführt werden.", "tabSize": "Die Anzahl der Leerzeichen, denen ein Tabstopp entspricht. Diese Einstellung wird basierend auf dem Inhalt der Datei überschrieben, wenn \"editor.detectIndentation\" aktiviert ist.", "tabSize.errorMessage": "\"number\" wurde erwartet. Beachten Sie, dass der Wert \"auto\" durch die Einstellung \"editor.detectIndentation\" ersetzt wurde.", @@ -20,8 +20,9 @@ "detectIndentation": "Beim Ɩffnen einer Datei werden \"editor.tabSize\" und \"editor.insertSpaces\" basierend auf den Dateiinhalten erkannt.", "roundedSelection": "Steuert, ob die Auswahl runde Ecken aufweist.", "scrollBeyondLastLine": "Legt fest, ob der Editor BildlƤufe über die letzte Zeile hinaus ausführt.", + "smoothScrolling": "Legt fest, ob der Editor BildlƤufe animiert ausführt.", "minimap.enabled": "Steuert, ob die Minikarte angezeigt wird", - "minimap.showSlider": "Steuert, ob der Minimap-Schieberegler automatisch ausgeblendet wird.", + "minimap.showSlider": "Steuert, ob der Minimap-Schieberegler automatisch ausgeblendet wird. Mƶgliche Werte sind \"always\" und \"mouseover\".", "minimap.renderCharacters": "Die tatsƤchlichen Zeichen in einer Zeile rendern (im Gegensatz zu Farbblƶcken)", "minimap.maxColumn": "Breite der Minikarte beschrƤnken, um hƶchstens eine bestimmte Anzahl von Spalten zu rendern", "find.seedSearchStringFromSelection": "Steuert, ob wir für die Suchzeichenfolge im Suchwidget aus der Editorauswahl ein Seeding ausführen.", @@ -46,10 +47,13 @@ "autoClosingBrackets": "Steuert, ob der Editor Klammern automatisch nach dem Ɩffnen schließt.", "formatOnType": "Steuert, ob der Editor Zeilen automatisch nach der Eingabe formatiert.", "formatOnPaste": "Steuert, ob der Editor den eingefügten Inhalt automatisch formatiert.", - "autoIndent": "Steuert, ob der Editor die Einzüge automatisch anpasst, wenn Benutzer Text eingeben oder Zeilen einfügen oder verschieben. Einzugsregeln der Sprache müssen verfügbar sein. ", "suggestOnTriggerCharacters": "Steuert, ob VorschlƤge automatisch bei der Eingabe von Triggerzeichen angezeigt werden.", "acceptSuggestionOnEnter": "Steuert, ob VorschlƤge über die Eingabetaste (zusƤtzlich zur TAB-Taste) angenommen werden sollen. Vermeidet Mehrdeutigkeit zwischen dem Einfügen neuer Zeilen oder dem Annehmen von VorschlƤgen. Der Wert \"smart\" bedeutet, dass ein Vorschlag nur über die Eingabetaste akzeptiert wird, wenn eine TextƤnderung vorgenommen wird.", "acceptSuggestionOnCommitCharacter": "Steuert, ob VorschlƤge über Commitzeichen angenommen werden sollen. In JavaScript kann ein Semikolon (\";\") beispielsweise ein Commitzeichen sein, das einen Vorschlag annimmt und dieses Zeichen eingibt.", + "snippetSuggestions.top": "Zeige Snippet VorschlƤge über den anderen VorschlƤgen.", + "snippetSuggestions.bottom": "Snippet VorschlƤge unter anderen VorschlƤgen anzeigen.", + "snippetSuggestions.inline": "Zeige Snippet VorschlƤge mit anderen VorschlƤgen.", + "snippetSuggestions.none": "Snippet VorschlƤge nicht anzeigen.", "snippetSuggestions": "Steuert, ob Codeausschnitte mit anderen VorschlƤgen angezeigt und wie diese sortiert werden.", "emptySelectionClipboard": "Steuert, ob ein Kopiervorgang ohne Auswahl die aktuelle Zeile kopiert.", "wordBasedSuggestions": "Steuert, ob VervollstƤndigungen auf Grundlage der Wƶrter im Dokument berechnet werden sollen.", @@ -82,6 +86,8 @@ "accessibilitySupport.off": "Der Editor wird nie für die Verwendung mit einer Sprachausgabe optimiert. ", "accessibilitySupport": "Steuert, ob der Editor in einem Modus ausgeführt werden soll, in dem er für die Sprachausgabe optimiert wird.", "links": "Steuert, ob der Editor Links erkennen und anklickbar machen soll", + "colorDecorators": "Steuert, ob der Editor die Inline-Farbdecorators und die Farbauswahl rendern soll.", + "codeActions": "Ermƶglicht die Code-Aktion \"lightbulb\"", "sideBySide": "Steuert, ob der Diff-Editor das Diff nebeneinander oder inline anzeigt.", "ignoreTrimWhitespace": "Steuert, ob der Diff-Editor Ƅnderungen in führenden oder nachgestellten Leerzeichen als Diffs anzeigt.", "renderIndicators": "Steuert, ob der Diff-Editor die Indikatoren \"+\" und \"-\" für hinzugefügte/entfernte Ƅnderungen anzeigt.", diff --git a/i18n/deu/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/deu/src/vs/editor/common/view/editorColorRegistry.i18n.json index 56e0924a36c..fa37f670425 100644 --- a/i18n/deu/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/deu/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -8,6 +8,7 @@ "lineHighlightBorderBox": "Hintergrundfarbe für den Rahmen um die Zeile an der Cursorposition.", "rangeHighlight": "Hintergrundfarbe hervorgehobener Bereiche (beispielsweise durch Features wie Quick Open und Suche).", "caret": "Farbe des Cursors im Editor.", + "editorCursorBackground": "Hintergrundfarbe vom Editor-Cursor. Erlaubt die Anpassung der Farbe von einem Zeichen, welches von einem Block-Cursor überdeckt wird.", "editorWhitespaces": "Farbe der Leerzeichen im Editor.", "editorIndentGuides": "Farbe der Führungslinien für Einzüge im Editor.", "editorLineNumbers": "Zeilennummernfarbe im Editor.", @@ -20,5 +21,11 @@ "errorForeground": "Vordergrundfarbe von Fehlerunterstreichungen im Editor.", "errorBorder": "Rahmenfarbe von Fehlerunterstreichungen im Editor.", "warningForeground": "Vordergrundfarbe von Warnungsunterstreichungen im Editor.", - "warningBorder": "Rahmenfarbe von Warnungsunterstreichungen im Editor." + "warningBorder": "Rahmenfarbe von Warnungsunterstreichungen im Editor.", + "infoForeground": "Vordergrundfarbe von Informationsunterstreichungen im Editor.", + "infoBorder": "Rahmenfarbe von Informationsunterstreichungen im Editor.", + "overviewRulerRangeHighlight": "Übersichtslineal-Markierungsfarbe für Bereichshervorhebungen.", + "overviewRuleError": "Übersichtslineal-Markierungsfarbe für Fehler.", + "overviewRuleWarning": "Übersichtslineal-Markierungsfarbe für Warnungen.", + "overviewRuleInfo": "Übersichtslineal-Markierungsfarbe für Informationen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json index bbffc013c9e..62d72aaf355 100644 --- a/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "Ersetzen", "label.replaceAllButton": "Alle ersetzen", "label.toggleReplaceButton": "Ersetzen-Modus wechseln", - "title.matchesCountLimit": "Nur die ersten 999 Ergebnisse werden hervorgehoben, alle SuchvorgƤnge beziehen sich aber auf den gesamten Text.", + "title.matchesCountLimit": "Nur die ersten {0} Ergebnisse wurden hervorgehoben, aber alle Suchoperationen werden auf dem gesamten Text durchgeführt.", "label.matchesLocation": "{0} von {1}", "label.noResults": "Keine Ergebnisse" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json index 1766611d9a4..966c9eafe93 100644 --- a/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,10 +10,6 @@ "nextSelectionMatchFindAction": "NƤchste Auswahl suchen", "previousSelectionMatchFindAction": "Vorherige Auswahl suchen", "startReplace": "Ersetzen", - "addSelectionToNextFindMatch": "Auswahl zur nƤchsten Übereinstimmungssuche hinzufügen", - "addSelectionToPreviousFindMatch": "Letzte Auswahl zu vorheriger Übereinstimmungssuche hinzufügen", - "moveSelectionToNextFindMatch": "Letzte Auswahl in nƤchste Übereinstimmungssuche verschieben", - "moveSelectionToPreviousFindMatch": "Letzte Auswahl in vorherige Übereinstimmungssuche verschieben", - "selectAllOccurrencesOfFindMatch": "Alle Vorkommen auswƤhlen und Übereinstimmung suchen", - "changeAll.label": "Alle Vorkommen Ƥndern" + "showNextFindTermAction": "NƤchsten Suchbegriff anzeigen", + "showPreviousFindTermAction": "Vorherigen Suchbegriff anzeigen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/deu/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 52715dd20db..9ead4227c99 100644 --- a/i18n/deu/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "{0} Formatierungen in Zeile {1} vorgenommen", "hint1n": "1 Formatierung zwischen Zeilen {0} und {1} vorgenommen", "hintnn": "{0} Formatierungen zwischen Zeilen {1} und {2} vorgenommen", - "formatDocument.label": "Format Document", - "formatSelection.label": "Format Selection" + "no.provider": "Tut mir leid, aber es gibt keine Formatierer für \"{0}\"-Dateien installiert.", + "formatDocument.label": "Dokument formatieren", + "formatSelection.label": "Auswahl formatieren" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/deu/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 4be670f8913..02553773e89 100644 --- a/i18n/deu/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "Gehe zum vorherigen Fehler oder zur vorherigen Warnung", "editorMarkerNavigationError": "Editormarkierung: Farbe bei Fehler des Navigationswidgets.", "editorMarkerNavigationWarning": "Editormarkierung: Farbe bei Warnung des Navigationswidgets.", + "editorMarkerNavigationInfo": "Editormarkierung: Farbe bei Warnung des Navigationswidgets.", "editorMarkerNavigationBackground": "Editormarkierung: Hintergrund des Navigationswidgets." } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/links/browser/links.i18n.json b/i18n/deu/src/vs/editor/contrib/links/browser/links.i18n.json index 3c582ab348d..e9f6f2ae5ad 100644 --- a/i18n/deu/src/vs/editor/contrib/links/browser/links.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/links/browser/links.i18n.json @@ -6,7 +6,10 @@ { "links.navigate.mac": "BEFEHLSTASTE + Mausklick zum Aufrufen des Links", "links.navigate": "STRG + Mausklick zum Aufrufen des Links", + "links.command.mac": "Cmd + Klick um Befehl auszuführen", + "links.command": "Ctrl + Klick um Befehl auszuführen.", "links.navigate.al": "ALT + Mausklick zum Aufrufen des Links", + "links.command.al": "Alt + Klick um Befehl auszuführen.", "invalid.url": "Fehler beim Ɩffnen dieses Links, weil er nicht wohlgeformt ist: {0}", "missing.url": "Fehler beim Ɩffnen dieses Links, weil das Ziel fehlt.", "label": "Link ƶffnen" diff --git a/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 58edd06f8f7..66385866668 100644 --- a/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Cursor oberhalb hinzufügen", "mutlicursor.insertBelow": "Cursor unterhalb hinzufügen", - "mutlicursor.insertAtEndOfEachLineSelected": "Cursor an Zeilenenden hinzufügen" + "mutlicursor.insertAtEndOfEachLineSelected": "Cursor an Zeilenenden hinzufügen", + "addSelectionToNextFindMatch": "Auswahl zur nƤchsten Übereinstimmungssuche hinzufügen", + "addSelectionToPreviousFindMatch": "Letzte Auswahl zu vorheriger Übereinstimmungssuche hinzufügen", + "moveSelectionToNextFindMatch": "Letzte Auswahl in nƤchste Übereinstimmungssuche verschieben", + "moveSelectionToPreviousFindMatch": "Letzte Auswahl in vorherige Übereinstimmungssuche verschieben", + "selectAllOccurrencesOfFindMatch": "Alle Vorkommen auswƤhlen und Übereinstimmung suchen", + "changeAll.label": "Alle Vorkommen Ƥndern" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/deu/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..d057bbcc407 --- /dev/null +++ b/i18n/deu/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "Schließen" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/deu/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index 02d8b1577c9..d706ff2e9b2 100644 --- a/i18n/deu/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Hintergrundfarbe eines Symbols beim Lesezugriff (beispielsweise beim Lesen einer Variablen).", - "wordHighlightStrong": "Hintergrundfarbe eines Symbols beim Schreibzugriff (beispielsweise beim Schreiben in eine Variable)." + "wordHighlightStrong": "Hintergrundfarbe eines Symbols beim Schreibzugriff (beispielsweise beim Schreiben in eine Variable).", + "overviewRulerWordHighlightForeground": "Übersichtslineal-Markierungsfarbe für Symbolhervorhebungen.", + "overviewRulerWordHighlightStrongForeground": "Übersichtslineal-Markierungsfarbe für Schreibzugriffs-Symbolhervorhebungen.", + "wordHighlight.next.label": "Gehe zur nƤchsten Symbolhervorhebungen", + "wordHighlight.previous.label": "Gehe zur vorherigen Symbolhervorhebungen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/deu/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index e957466c8a6..5cd50df300a 100644 --- a/i18n/deu/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/deu/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "Die Gruppe, zu der dieser Befehl gehƶrt.", "vscode.extension.contributes.menus": "TrƤgt Menüelemente zum Editor bei.", "menus.commandPalette": "Die Befehlspalette ", + "menus.touchBar": "Die Touch Bar (nur macOS)", "menus.editorTitle": "Das Editor-Titelmenü.", "menus.editorContext": "Das Editor-Kontextmenü.", "menus.explorerContext": "Das Kontextmenü des Datei-Explorers.", "menus.editorTabContext": "Das Kontextmenü für die Editor-Registerkarten", "menus.debugCallstackContext": "Das Kontextmenü für den Debug-Callstack", "menus.scmTitle": "Das Titelmenü der Quellcodeverwaltung", + "menus.scmSourceControl": "Das Menü \"Quellcodeverwaltung\"", "menus.resourceGroupContext": "Das Ressourcengruppen-Kontextmenü der Quellcodeverwaltung", "menus.resourceStateContext": "Das Ressourcenstatus-Kontextmenü der Quellcodeverwaltung", "view.viewTitle": "Das beigetragene Editor-Titelmenü.", diff --git a/i18n/deu/src/vs/platform/environment/node/argv.i18n.json b/i18n/deu/src/vs/platform/environment/node/argv.i18n.json index 058d98933af..25a0dca34be 100644 --- a/i18n/deu/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/deu/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "Argumente im Modus \"--goto\" müssen im Format \"DATEI(:ZEILE(:ZEICHEN))\" vorliegen.", - "diff": "Ɩffnet einen Diff-Editor. Es müssen zwei Dateipfade als Argumente übergeben werden.", - "goto": "Ɩffnet die Datei im Pfad in der Zeile und beim Zeichen (fügen Sie dem Pfad \":line[:character]\" hinzu).", + "diff": "Vergleicht zwei Dateien.", + "add": "Fügt einen oder mehrere Ordner zum letzten aktiven Fenster hinzu.", + "goto": "Ɩffnet eine Datei im Pfad in der angegebenen Zeile und an der Zeichenposition.", "locale": "Das zu verwendende Gebietsschema (z. B. en-US oder zh-TW).", "newWindow": "Erzwingt eine neue Instanz des Codes.", "performance": "Startet mit aktiviertem Befehl \"Developer: Startup Performance\".", @@ -14,7 +15,7 @@ "reuseWindow": "Erzwingt das Ɩffnen einer Datei oder eines Ordners im letzten aktiven Fenster.", "userDataDir": "Gibt das Verzeichnis an, in dem Benutzerdaten gespeichert werden. Nützlich, wenn die Ausführung als \"root\" erfolgt.", "verbose": "Ausführliche Ausgabe (impliziert \"-wait\").", - "wait": "Wartet, bis das Fenster geschlossen wurde, bevor die Rückgabe erfolgt.", + "wait": "Warten Sie, bis die Dateien geschlossen sind, bevor Sie zurück gehen kƶnnen.", "extensionHomePath": "Legen Sie den Stammpfad für Extensions fest.", "listExtensions": "Listet die installierten Extensions auf.", "showVersions": "Zeigt Versionen der installierten Erweiterungen an, wenn \"--list-extension\" verwendet wird.", diff --git a/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index cd123a52668..521e20ed207 100644 --- a/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Die Erweiterung ist ungültig: \"package.json\" ist keine JSON-Datei.", - "restartCode": "Bitte starten Sie Code vor der Neuinstallation von {0} neu.", - "installDependeciesConfirmation": "Durch das Installieren von \"{0}\" werden auch die abhƤngigen Komponenten installiert. Mƶchten Sie den Vorgang fortsetzen?", - "install": "Ja", - "doNotInstall": "Nein", + "restartCodeLocal": "Bitte starten Sie Code vor der Neuinstallation von {0} neu.", + "restartCodeGallery": "Bitte vor der Neuinstallation VSCode neu starten.", "uninstallDependeciesConfirmation": "Mƶchten Sie nur \"{0}\" oder auch die zugehƶrigen AbhƤngigkeiten deinstallieren?", "uninstallOnly": "Nur", "uninstallAll": "Alle", diff --git a/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 2a33dae4abf..e0774394ce8 100644 --- a/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "Aktivierungsereignisse für die VS Code-Extension.", "vscode.extension.activationEvents.onLanguage": "Ein Aktivierungsereignis wird beim Ɩffnen einer Datei ausgegeben, die in die angegebene Sprache aufgelƶst wird.", "vscode.extension.activationEvents.onCommand": "Ein Aktivierungsereignis wird beim Aufrufen des angegebenen Befehls ausgegeben.", - "vscode.extension.activationEvents.onDebug": "Ein Aktivierungsereignis wird beim Starten einer Debugsitzung des angegebenen Typs ausgegeben.", + "vscode.extension.activationEvents.onDebug": "Ein Aktivierungsereignis wird ausgesandt, wenn ein Benutzer eine Debugging startet, oder eine Debug-Konfiguration erstellt.", "vscode.extension.activationEvents.workspaceContains": "Ein Aktivierungsereignis wird beim Ɩffnen eines Ordners ausgegeben, der mindestens eine Datei enthƤlt, die mit dem angegebenen Globmuster übereinstimmt.", "vscode.extension.activationEvents.onView": "Ein Aktivierungsereignis wird beim Erweitern der angegebenen Ansicht ausgegeben.", "vscode.extension.activationEvents.star": "Ein Aktivierungsereignis wird beim Start von VS Code ausgegeben. Damit für die Endbenutzer eine bestmƶgliche Benutzerfreundlichkeit sichergestellt ist, verwenden Sie dieses Aktivierungsereignis in Ihrer Erweiterung nur dann, wenn in Ihrem Anwendungsfall keine andere Kombination an Aktivierungsereignissen funktioniert.", diff --git a/i18n/deu/src/vs/platform/history/electron-main/historyMainService.i18n.json b/i18n/deu/src/vs/platform/history/electron-main/historyMainService.i18n.json index 88af0de928a..5d0462e717a 100644 --- a/i18n/deu/src/vs/platform/history/electron-main/historyMainService.i18n.json +++ b/i18n/deu/src/vs/platform/history/electron-main/historyMainService.i18n.json @@ -6,5 +6,7 @@ { "newWindow": "Neues Fenster", "newWindowDesc": "Ɩffnet ein neues Fenster.", - "folderDesc": "{0} {1}" + "recentFolders": "Aktueller Arbeitsbereich", + "folderDesc": "{0} {1}", + "codeWorkspace": "Codearbeitsbereich" } \ No newline at end of file diff --git a/i18n/deu/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/deu/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..27b155956bb --- /dev/null +++ b/i18n/deu/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "Fügt in Erweiterung definierte verwendbare Farben hinzu", + "contributes.color.id": "Der Bezeichner der verwendbaren Farbe", + "contributes.color.id.format": "Bezeichner sollten in folgendem Format vorliegen: aa [.bb] *", + "contributes.color.description": "Die Beschreibung der verwendbaren Farbe", + "contributes.defaults.light": "Die Standardfarbe für helle Themen. Entweder eine Farbe als Hex-Code (#RRGGBB[AA]) oder der Bezeichner einer verwendbaren Farbe, der eine Standardeinstellung bereitstellt.", + "contributes.defaults.dark": "Die Standardfarbe für dunkle Themen. Entweder eine Farbe als Hex-Code (#RRGGBB[AA]) oder der Bezeichner einer verwendbaren Farbe, der eine Standardeinstellung bereitstellt.", + "contributes.defaults.highContrast": "Die Standardfarbe für Themen mit hohem Kontrast. Entweder eine Farbe als Hex-Code (#RRGGBB[AA]) oder der Bezeichner einer verwendbaren Farbe, der eine Standardeinstellung bereitstellt.", + "invalid.colorConfiguration": "\"configuration.colors\" muss ein Array sein.", + "invalid.default.colorType": "{0} muss entweder eine Farbe als Hex-Code (#RRGGBB[AA] oder #RGB[A]) sein oder der Bezeichner einer verwendbaren Farbe, der eine Standardeinstellung bereitstellt.", + "invalid.id": "\"configuration.colors.id\" muss definiert und nicht leer sein", + "invalid.id.format": "\"configuration.colors.id\" muss auf das Wort[.word]* folgen", + "invalid.description": "\"configuration.colors.description\" muss definiert und darf nicht leer sein", + "invalid.defaults": "\"configuration.colors.defaults\" muss definiert sein, und \"light\", \"dark\" und \"highContrast\" enthalten" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json index a66c145ad23..b1b17e724eb 100644 --- a/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/deu/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Ungültiges Farbformat. Verwenden Sie #RGB, #RGBA, #RRGGBB oder #RRGGBBAA.", "schema.colors": "In der Workbench verwendete Farben.", "foreground": "Allgemeine Vordergrundfarbe. Diese Farbe wird nur verwendet, wenn sie nicht durch eine Komponente überschrieben wird.", "errorForeground": "Allgemeine Vordergrundfarbe. Diese Farbe wird nur verwendet, wenn sie nicht durch eine Komponente überschrieben wird.", @@ -53,6 +52,9 @@ "badgeBackground": "Badge - Hintergrundfarbe. Badges sind kurze Info-Texte, z. B. für Anzahl Suchergebnisse.", "badgeForeground": "Badge - Vordergrundfarbe. Badges sind kurze Info-Texte, z. B. für Anzahl Suchergebnisse.", "scrollbarShadow": "Schatten der Scrollleiste, um anzuzeigen, dass die Ansicht gescrollt wird.", + "scrollbarSliderBackground": "Hintergrundfarbe vom Scrollbar-Schieber", + "scrollbarSliderHoverBackground": "Hintergrundfarbe des Schiebereglers, wenn darauf gezeigt wird.", + "scrollbarSliderActiveBackground": "Hintergrundfarbe des Schiebereglers, wenn dieser aktiv ist.", "progressBarBackground": "Hintergrundfarbe des Fortschrittbalkens, der für lang ausgeführte VorgƤnge angezeigt werden kann.", "editorBackground": "Hintergrundfarbe des Editors.", "editorForeground": "Standardvordergrundfarbe des Editors.", @@ -82,5 +84,7 @@ "mergeBorder": "Rahmenfarbe für Kopfzeilen und die Aufteilung in Inline-Mergingkonflikten.", "overviewRulerCurrentContentForeground": "Aktueller Übersichtslineal-Vordergrund für Inline-Mergingkonflikte.", "overviewRulerIncomingContentForeground": "Eingehender Übersichtslineal-Vordergrund für Inline-Mergingkonflikte. ", - "overviewRulerCommonContentForeground": "Hintergrund des Übersichtslineals des gemeinsamen übergeordneten Elements bei Inlinezusammenführungskonflikten." + "overviewRulerCommonContentForeground": "Hintergrund des Übersichtslineals des gemeinsamen übergeordneten Elements bei Inlinezusammenführungskonflikten.", + "overviewRulerFindMatchForeground": "Übersichtslineal-Markierungsfarbe für Suchübereinstimmungen.", + "overviewRulerSelectionHighlightForeground": "Übersichtslineal-Markierungsfarbe für Auswahlhervorhebungen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/deu/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..7da0a031def --- /dev/null +++ b/i18n/deu/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Codearbeitsbereich", + "untitledWorkspace": "Ohne Titel (Arbeitsbereich)", + "workspaceNameVerbose": "{0} (Arbeitsbereich)", + "workspaceName": "{0} (Arbeitsbereich)" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/deu/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..fecc67b154d --- /dev/null +++ b/i18n/deu/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "Ansichten müssen ein Array sein.", + "requirestring": "Die Eigenschaft \"{0}\" ist erforderlich. Sie muss vom Typ \"string\" sein.", + "optstring": "Die Eigenschaft \"{0}\" kann ausgelassen werden oder muss vom Typ \"string\" sein.", + "vscode.extension.contributes.view.id": "Bezeichner der Ansicht. Damit kƶnnen Sie einen Datenanbieter über die API \"vscode.window.registerTreeDataProviderForView\" registrieren. Er dient auch zum Aktivieren Ihrer Erweiterung, indem Sie das Ereignis \"onView:${id}\" für \"activationEvents\" registrieren.", + "vscode.extension.contributes.view.name": "Der visuell lesbare Name der Ansicht. Wird angezeigt", + "vscode.extension.contributes.view.when": "Bedingung, die zum Anzeigen dieser Ansicht erfüllt sein muss", + "vscode.extension.contributes.views": "TrƤgt Ansichten zum Editor bei.", + "views.explorer": "Explorer-Ansicht", + "views.debug": "Debugansicht", + "locationId.invalid": "{0}\" ist kein gültiger Ansichtenspeicherort", + "duplicateView1": "Mehrere Ansichten kƶnnen nicht mit derselben ID \"{0}\" am Speicherort \"{1}\" registriert werden.", + "duplicateView2": "Eine Ansicht mit der ID \"{0}\" ist am Speicherort \"{1}\" bereits registriert." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/deu/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..76ebdf6051e --- /dev/null +++ b/i18n/deu/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "Fehler beim Aktivieren der Extension \"{1}\". Ursache: unbekannte AbhƤngigkeit \"{0}\".", + "failedDep1": "Fehler beim Aktivieren der Extension \"{1}\". Ursache: Fehler beim Aktivieren der Extension \"{0}\".", + "failedDep2": "Fehler beim Aktivieren der Extension \"{0}\". Ursache: mehr als 10 Ebenen von AbhƤngigkeiten (wahrscheinlich eine AbhƤngigkeitsschleife).", + "activationError": "Fehler beim Aktivieren der Extension \"{0}\": {1}." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 2c55bed538b..174408464b6 100644 --- a/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,11 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "Datei ƶffnen...", "openFolder": "Ordner ƶffnen...", "openFileFolder": "Ɩffnen...", - "cancel": "Abbrechen", "addFolderToWorkspace": "Ordner zum Arbeitsbereich hinzufügen...", + "add": "&&Hinzufügen", "addFolderToWorkspaceTitle": "Ordner zum Arbeitsbereich hinzufügen", + "globalRemoveFolderFromWorkspace": "Ordner aus dem Arbeitsbereich entfernen...", "removeFolderFromWorkspace": "Ordner aus dem Arbeitsbereich entfernen", - "save": "&&Speichern" + "openFolderSettings": "Ordnereinstellungen ƶffnen", + "saveWorkspaceAsAction": "Arbeitsbereich speichern unter...", + "save": "&&Speichern", + "saveWorkspace": "Arbeitsbereich speichern", + "openWorkspaceAction": "Arbeitsbereich ƶffnen...", + "openWorkspaceConfigFile": "Konfigurationsdatei des Arbeitsbereichs ƶffnen", + "openFolderAsWorkspaceInNewWindow": "Ordner als Arbeitsbereich in neuem Fenster ƶffnen", + "workspaceFolderPickerPlaceholder": "Arbeitsbereichsordner auswƤhlen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 745ba80b274..9ce0dd879da 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "Aus AktivitƤtsleiste entfernen", - "keepInActivityBar": "In AktivitƤtsleiste behalten", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Auf AktivitƤtsleiste ausblenden", + "keepInActivityBar": "In AktivitƤtsleiste behalten", "additionalViews": "ZusƤtzliche Ansichten", "numberBadge": "{0} ({1})", "manageExtension": "Erweiterung verwalten", diff --git a/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 419bdb09927..4bf40f11e3b 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "AktivitƤtsleiste ausblenden", - "activityBarAriaLabel": "Umschaltung der aktiven Ansicht", "globalActions": "Globale Aktionen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..a2d382d743c --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "Umschaltung der aktiven Ansicht" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..ced21f95b89 --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "ZusƤtzliche Ansichten", + "numberBadge": "{0} ({1})", + "manageExtension": "Erweiterung verwalten", + "titleKeybinding": "{0} ({1})", + "hide": "Ausblenden", + "keep": "Beibehalten", + "toggle": "Ansichtsfixierung umschalten" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 7ce49db8855..0812b9299a4 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Editoren in zweiter Gruppe anzeigen", "groupThreePicker": "Editoren in dritter Gruppe anzeigen", "allEditorsPicker": "Alle geƶffneten Editoren anzeigen", - "view": "Anzeigen" + "view": "Anzeigen", + "file": "Datei" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index fe0b21dfd66..842738eb092 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,7 +35,9 @@ "openPreviousEditorInGroup": "Vorherigen Editor in der Gruppe ƶffnen", "navigateNext": "Weiter", "navigatePrevious": "Zurück", + "navigateLast": "Zum Ende gehen", "reopenClosedEditor": "Geschlossenen Editor erneut ƶffnen", + "clearRecentFiles": "Zuletzt geƶffnete lƶschen", "showEditorsInFirstGroup": "Editoren in erster Gruppe anzeigen", "showEditorsInSecondGroup": "Editoren in zweiter Gruppe anzeigen", "showEditorsInThirdGroup": "Editoren in dritter Gruppe anzeigen", diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 594b9956e82..fb5b37b0028 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "TAB-TASTE verschiebt Fokus", - "screenReaderDetected": "Sprachausgabe erkannt", + "screenReaderDetected": "Für Sprachausgabe optimiert", "screenReaderDetectedExtra": "Wenn Sie keine Sprachausgabe verwenden, Ƥndern Sie die Einstellung \"editor.accessibilitySupport\" in \"Aus\".", "disableTabMode": "Barrierefreiheitsmodus deaktivieren", "gotoLine": "Gehe zu Zeile", @@ -47,5 +47,11 @@ "reopenWithEncoding": "Mit Codierung erneut ƶffnen", "guessedEncoding": "Vom Inhalt abgeleitet", "pickEncodingForReopen": "Dateicodierung zum erneuten Ɩffnen der Datei auswƤhlen", - "pickEncodingForSave": "Dateicodierung auswƤhlen, mit der gespeichert werden soll" + "pickEncodingForSave": "Dateicodierung auswƤhlen, mit der gespeichert werden soll", + "screenReaderDetectedExplanation.title": "Für Sprachausgabe optimiert", + "screenReaderDetectedExplanation.question": "Verwenden Sie eine Sprachausgabe zum Bedienen von VS Code?", + "screenReaderDetectedExplanation.answerYes": "Ja", + "screenReaderDetectedExplanation.answerNo": "Nein", + "screenReaderDetectedExplanation.body1": "VS Code ist jetzt für die Verwendung mit einer Sprachausgabe optimiert. ", + "screenReaderDetectedExplanation.body2": "Einige Editorfunktionen weisen ein anderes Verhalten auf, z. B. in Bezug auf den Zeilenumbruch, Faltung, automatisches Schließen von Klammern usw." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index c2b8d205a42..db033ae76d2 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Bereich schließen", "togglePanel": "Bereich umschalten", "focusPanel": "Fokus im Bereich", + "moveToRight": "Verschieben nach rechts", + "moveToBottom": "Nach unten verschieben", "toggleMaximizedPanel": "Maximierten Bereich umschalten", "maximizePanel": "Panelgröße maximieren", "minimizePanel": "Panelgröße wiederherstellen", diff --git a/i18n/deu/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json index 870bcf2795a..e6a57361024 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "compositePart.hideSideBarLabel": "Randleiste ausblenden", "focusSideBar": "Fokus in Randleiste", "viewCategory": "Anzeigen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index f86613230bf..cda94be8348 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "Der Befehl \"{0}\" ist zurzeit nicht aktiviert und kann nicht ausgeführt werden.", "manageExtension": "Erweiterung verwalten" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..b7eb39e941e --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0}-Aktionen" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..17abacb1d8c --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0}-Aktionen", + "hideView": "Auf Randleiste ausblenden" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..a36d97eb0e0 --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "Eine Ansicht mit der ID \"{0}\" ist am Speicherort \"{1}\" bereits registriert." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..147a1680ae9 --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "Auf Randleiste ausblenden" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/common/theme.i18n.json b/i18n/deu/src/vs/workbench/common/theme.i18n.json index 20f046bd07c..9e592858f8d 100644 --- a/i18n/deu/src/vs/workbench/common/theme.i18n.json +++ b/i18n/deu/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "Hintergrundfarbe der aktiven Registerkarte. Registerkarten sind die Container für Editors im Editorbereich. In einer Editorgruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editorgruppen kƶnnen vorhanden sein.", "tabInactiveBackground": "Hintergrundfarbe der inaktiven Registerkarte. Registerkarten sind die Container für Editors im Editorbereich. In einer Editorgruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editorgruppen kƶnnen vorhanden sein.", "tabBorder": "Rahmen zum Trennen von Registerkarten. Registerkarten sind die Container für Editoren im Editor-Bereich. In einer Editor-Gruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editor-Gruppen sind mƶglich.", + "tabActiveBorder": "Rahmen zum Hervorheben aktiver Registerkarten. Registerkarten sind die Container für Editoren im Editor-Bereich. In einer Editor-Gruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editor-Gruppen sind mƶglich.", + "tabActiveUnfocusedBorder": "Rahmen zum Hervorheben aktiver Registerkarten in einer unfokussierten Gruppe. Registerkarten sind die Container für Editoren im Editor-Bereich. In einer Editor-Gruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editor-Gruppen sind mƶglich.", "tabActiveForeground": "Vordergrundfarbe der aktiven Registerkarte in einer aktiven Gruppe. Registerkarten sind die Container für Editors im Editorbereich. In einer Editorgruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editorgruppen kƶnnen vorhanden sein.", "tabInactiveForeground": "Vordergrundfarbe der inaktiven Registerkarte in einer aktiven Gruppe. Registerkarten sind die Container für Editors im Editorbereich. In einer Editorgruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editorgruppen kƶnnen vorhanden sein.", - "tabUnfocusedActiveForeground": "Vordergrundfarbe der aktiven Registerkarte in einer inaktiven Gruppe. Registerkarten sind die Container für Editors im Editorbereich. In einer Editorgruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editorgruppen kƶnnen vorhanden sein.", - "tabUnfocusedInactiveForeground": "Vordergrundfarbe der inaktiven Registerkarte in einer inaktiven Gruppe. Registerkarten sind die Container für Editors im Editorbereich. In einer Editorgruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editorgruppen kƶnnen vorhanden sein.", + "tabUnfocusedActiveForeground": "Vordergrundfarbe für aktive Registerkarten in einer unfokussierten Gruppe. Registerkarten sind die Container für Editoren im Editor-Bereich. In einer Editor-Gruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editor-Gruppen sind mƶglich.", + "tabUnfocusedInactiveForeground": "Vordergrundfarbe für inaktive Registerkarten in einer unfokussierten Gruppe. Registerkarten sind die Container für Editoren im Editor-Bereich. In einer Editor-Gruppe kƶnnen mehrere Registerkarten geƶffnet werden. Mehrere Editor-Gruppen sind mƶglich.", "editorGroupBackground": "Hintergrundfarbe einer Editor-Gruppe. Editor-Gruppen sind die Container der Editoren. Die Hintergrundfarbe wird beim Ziehen von Editoren angezeigt.", "tabsContainerBackground": "Hintergrundfarbe der Titelüberschrift der Editor-Gruppe, wenn die Registerkarten deaktiviert sind. Editor-Gruppen sind die Container der Editoren.", "tabsContainerBorder": "Rahmenfarbe der Titelüberschrift der Editor-Gruppe, wenn die Registerkarten deaktiviert sind. Editor-Gruppen sind die Container der Editoren.", @@ -18,15 +20,15 @@ "editorGroupBorder": "Farbe zum Trennen mehrerer Editor-Gruppen. Editor-Gruppen sind die Container der Editoren.", "editorDragAndDropBackground": "Ā Hintergrundfarbe beim Ziehen von Editoren. Die Farbe muss transparent sein, damit der Editor-Inhalt noch sichtbar sind.", "panelBackground": "Hintergrundfarbe des Panels. Panels werden unter dem Editorbereich angezeigt und enthalten Ansichten wie die Ausgabe und das integrierte Terminal.", - "panelBorder": "Farbe des oberen Panelrahmens, der das Panel vom Editor abtrennt. Panels werden unter dem Editorbereich angezeigt und enthalten Ansichten wie die Ausgabe und das integrierten Terminal.", "panelActiveTitleForeground": "Titelfarbe für den aktiven Bereich. Bereiche werden unter dem Editorbereich angezeigt und enthalten Ansichten wie Ausgabe und integriertes Terminal.", "panelInactiveTitleForeground": "Titelfarbe für den inaktiven Bereich. Bereiche werden unter dem Editorbereich angezeigt und enthalten Ansichten wie Ausgabe und integriertes Terminal.", "panelActiveTitleBorder": "Rahmenfarbe für den Titel des aktiven Bereichs. Bereiche werden unter dem Editorbereich angezeigt und enthalten Ansichten wie Ausgabe und integriertes Terminal.", - "statusBarForeground": "Vordergrundfarbe der Statusleiste. Die Statusleiste wird unten im Fenster angezeigt.", + "statusBarForeground": "Vordergrundfarbe der Statusleiste beim Ɩffnen eines Arbeitsbereichs. Die Statusleiste wird unten im Fenster angezeigt.", "statusBarNoFolderForeground": "Vordergrundfarbe der Statusleiste, wenn kein Ordner geƶffnet ist. Die Statusleiste wird unten im Fenster angezeigt.", - "statusBarBackground": "Standardhintergrundfarbe der Statusleiste. Die Statusleiste wird unten im Fenster angezeigt.", + "statusBarBackground": "Hintergrundfarbe der Statusleiste beim Ɩffnen eines Arbeitsbereichs. Die Statusleiste wird unten im Fenster angezeigt.", "statusBarNoFolderBackground": "Hintergrundfarbe der Statusleiste, wenn kein Ordner geƶffnet ist. Die Statusleiste wird unten im Fenster angezeigt.", "statusBarBorder": "Rahmenfarbe der Statusleiste für die Abtrennung von der Seitenleiste und dem Editor. Die Statusleiste wird unten im Fenster angezeigt.", + "statusBarNoFolderBorder": "Rahmenfarbe der Statusleiste zur Abtrennung von der Randleiste und dem Editor, wenn kein Ordner geƶffnet ist. Die Statusleiste wird unten im Fenster angezeigt.", "statusBarItemActiveBackground": "Hintergrundfarbe für Statusleistenelemente beim Klicken. Die Statusleiste wird am unteren Rand des Fensters angezeigt.", "statusBarItemHoverBackground": "Hintergrundfarbe der Statusleistenelemente beim Daraufzeigen. Die Statusleiste wird am unteren Seitenrand angezeigt.", "statusBarProminentItemBackground": "Hintergrundfarbe für markante Elemente der Statusleiste. Markante Elemente sind im Vergleich zu anderen StatusleisteneintrƤgen hervorgehoben, um auf ihre Bedeutung hinzuweisen. Die Statusleiste wird unten im Fenster angezeigt.", @@ -41,12 +43,14 @@ "sideBarForeground": "Vordergrundfarbe der Seitenleiste. Die Seitenleiste ist der Container für Ansichten wie den Explorer und die Suche.", "sideBarBorder": "Rahmenfarbe der Seitenleiste zum Abtrennen an der Seite zum Editor. Die Seitenleiste ist der Container für Ansichten wie den Explorer und die Suche.", "sideBarTitleForeground": "Vordergrundfarbe der Seitenleiste. Die Seitenleiste ist der Container für Ansichten wie den Explorer und die Suche.", + "sideBarDragAndDropBackground": "Drag & Drop-Feedbackfarbe für die Abschnitte der Randleiste. Die Farbe muss transparent sein, damit die Abschnitte der Randleiste noch sichtbar sind. Die Randleiste ist der Container für Ansichten wie den Explorer und die Suche. ", "sideBarSectionHeaderBackground": "Hintergrundfarbe der Abschnittsüberschrift der Seitenleiste. Die Seitenleiste ist der Container für Ansichten wie den Explorer und die Suche.", "sideBarSectionHeaderForeground": "Vordergrundfarbe der Abschnittsüberschrift der Seitenleiste. Die Seitenleiste ist der Container für Ansichten wie den Explorer und die Suche.", "titleBarActiveForeground": "Vordergrund der Titelleiste, wenn das Fenster aktiv ist. Diese Farbe wird derzeit nur von MacOS unterstützt.", "titleBarInactiveForeground": "Vordergrund der Titelleiste, wenn das Fenster inaktiv ist. Diese Farbe wird derzeit nur von MacOS unterstützt.", "titleBarActiveBackground": "Hintergrund der Titelleiste, wenn das Fenster aktiv ist. Diese Farbe wird derzeit nur von MacOS unterstützt.", "titleBarInactiveBackground": "Hintergrund der Titelleiste, wenn das Fenster inaktiv ist. Diese Farbe wird derzeit nur von MacOS unterstützt.", + "titleBarBorder": "Rahmenfarbe der Titelleiste. Diese Farbe wird derzeit nur unter MacOS unterstützt.", "notificationsForeground": "Vordergrundfarbe für Benachrichtigungen. Benachrichtigungen werden oben im Fenster eingeblendet.", "notificationsBackground": "Hintergrundfarbe für Benachrichtigungen. Benachrichtigungen werden oben im Fenster eingeblendet.", "notificationsButtonBackground": "Hintergrundfarbe der BenachrichtigungsschaltflƤche. Benachrichtigungen werden oben im Fenster eingeblendet.", diff --git a/i18n/deu/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/deu/src/vs/workbench/electron-browser/actions.i18n.json index 6af3818bfee..bff17f6154d 100644 --- a/i18n/deu/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/deu/src/vs/workbench/electron-browser/actions.i18n.json @@ -6,6 +6,8 @@ { "closeActiveEditor": "Editor schließen", "closeWindow": "Fenster schließen", + "closeWorkspace": "Arbeitsbereich schließen", + "noWorkspaceOpened": "Zurzeit ist kein Arbeitsbereich in dieser Instanz geƶffnet, der geschlossen werden kann.", "newWindow": "Neues Fenster", "toggleFullScreen": "Vollbild umschalten", "toggleMenuBar": "Menüleiste umschalten", @@ -20,7 +22,11 @@ "close": "Fenster schließen", "switchWindow": "Fenster wechseln...", "quickSwitchWindow": "Fenster schnell wechseln...", + "workspaces": "Arbeitsbereiche", "files": "Dateien", + "openRecentPlaceHolderMac": "Zum Ɩffnen auswƤhlen (zum Ɩffnen in einem neuen Fenster die BEFEHLSTASTE gedrückt halten)", + "openRecentPlaceHolder": "Zum Ɩffnen auswƤhlen (zum Ɩffnen in einem neuen Fenster die STRG-TASTE gedrückt halten)", + "remove": "Aus zuletzt geƶffneten entfernen", "openRecent": "Zuletzt benutzt...", "quickOpenRecent": "Zuletzt benutzte schnell ƶffnen...", "closeMessages": "Benachrichtigungs-E-Mail schließen", @@ -36,5 +42,10 @@ "navigateUp": "Zur Ansicht darüber navigieren", "navigateDown": "Zur Ansicht darunter navigieren", "increaseViewSize": "Aktuelle Ansicht vergrößern", - "decreaseViewSize": "Aktuelle Ansicht verkleinern" + "decreaseViewSize": "Aktuelle Ansicht verkleinern", + "showPreviousTab": "Vorherige Fensterregisterkarte anzeigen", + "showNextWindowTab": "NƤchste Fensterregisterkarte anzeigen", + "moveWindowTabToNewWindow": "Fensterregisterkarte in neues Fenster verschieben", + "mergeAllWindowTabs": "Alle Fenster zusammenführen", + "toggleWindowTabsBar": "Fensterregisterkarten-Leiste umschalten" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/deu/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..f17cc2cd8aa --- /dev/null +++ b/i18n/deu/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "Sprache konfigurieren", + "displayLanguage": "Definiert die Anzeigesprache von VSCode.", + "doc": "Unter {0} finden Sie eine Liste der unterstützten Sprachen.", + "restart": "Das Ƅndern dieses Wertes erfordert einen Neustart von VSCode.", + "fail.createSettings": "{0} ({1}) kann nicht erstellt werden.", + "JsonSchema.locale": "Die zu verwendende Sprache der BenutzeroberflƤche." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json index 624c0ec5539..9febb7b51bf 100644 --- a/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -7,15 +7,19 @@ "view": "Anzeigen", "help": "Hilfe", "file": "Datei", + "workspaces": "Arbeitsbereiche", "developer": "Entwickler", "showEditorTabs": "Steuert, ob geƶffnete Editoren auf Registerkarten angezeigt werden sollen.", + "workbench.editor.labelFormat.default": "Zeigt den Namen der Datei. Wenn Registerkarten aktiviert sind und zwei Dateien in einer Gruppe den gleichen Namen haben, werden die unterscheidenden Abschnitte der Pfade jeder Datei hinzugefügt. Wenn die Registerkarten deaktiviert sind, wird der Pfad relativ zum Arbeitsbereich-Ordner angezeigt, wenn der Editor aktiv ist. ", + "workbench.editor.labelFormat.short": "Den Namen der Datei anzeigen, gefolgt von dessen Verzeichnisnamen.", + "workbench.editor.labelFormat.medium": "Zeigt den Namen der Datei, gefolgt von dessen Pfad relativ zum Arbeitsbereich-Ordner.", + "workbench.editor.labelFormat.long": "Zeigt den Namen der Datei an, gefolgt von ihrem absoluten Pfad.", + "tabDescription": "Steuert das Format der Beschriftung für einen Editor. Wenn Sie diese Einstellung Ƥndern, ist beispielsweise der Speicherort einer Datei besser ersichtlich:\n- kurz: \"parent\"\n- mittel: \"workspace/src/parent\"\n- lang: \"/home/user/workspace/src/parent\"\n- Standard: \".../parent\", wenn eine andere Registerkarte denselben Titel hat, oder den relativen Arbeitsbereichspfad, wenn Registerkarten deaktiviert sind.", "editorTabCloseButton": "Steuert die Position der Schließen-SchaltflƤchen der Editor-Registerkarten oder deaktiviert sie bei der Einstellung \"off\".", "showIcons": "Steuert, ob geƶffnete Editoren mit einem Symbol angezeigt werden sollen. Hierzu muss auch ein Symboldesign aktiviert werden.", - "enablePreview": "Steuert, ob geƶffnete Editoren als Vorschau angezeigt werden. Vorschau-Editoren werden wiederverwendet, bis sie gespeichert werden (z. B. über Doppelklicken oder Bearbeiten).", + "enablePreview": "Steuert, ob geƶffnete Editoren als Vorschau angezeigt werden. Vorschau-Editoren werden wiederverwendet, bis sie gespeichert werden (z. B. über Doppelklicken oder Bearbeiten), und sie werden mit kursivem Schriftschnitt angezeigt.", "enablePreviewFromQuickOpen": "Steuert, ob geƶffnete Editoren aus Quick Open als Vorschau angezeigt werden. Vorschau-Editoren werden wiederverwendet, bis sie gespeichert werden (z. B. über Doppelklicken oder Bearbeiten).", - "editorOpenPositioning": "Steuert, wo Editoren geƶffnet werden. WƤhlen Sie \"Links\" oder \"Rechts\" aus, um Editoren links oder rechts vom aktuellen aktiven Editor zu ƶffnen. WƤhlen Sie \"Erster\" oder \"Letzter\" aus, um Editoren unabhƤngig vom aktuell aktiven Editor zu ƶffnen.", "revealIfOpen": "Steuert, ob ein geƶffneter Editor in einer der sichtbaren Gruppen angezeigt wird. Ist diese Option deaktiviert, wird ein Editor vorzugsweise in der aktuell aktiven Editorgruppe geƶffnet. Ist diese Option aktiviert, wird ein bereits geƶffneter Editor angezeigt und nicht in der aktuell aktiven Editorgruppe erneut geƶffnet. In einigen FƤllen wird diese Einstellung ignoriert, z.Ā B. wenn das Ɩffnen eines Editors in einer bestimmten Gruppe oder neben der aktuell aktiven Gruppe erzwungen wird.", - "commandHistory": "Steuert, ob die Anzahl zuletzt verwendeter Befehle im Verlauf für die Befehlspalette gespeichert wird. Legen Sie diese Option auf 0 fest, um den Befehlsverlauf zu deaktivieren.", "preserveInput": "Steuert, ob die letzte typisierte Eingabe in die Befehlspalette beim nƤchsten Ɩffnen wiederhergestellt wird.", "closeOnFocusLost": "Steuert, ob Quick Open automatisch geschlossen werden soll, sobald das Feature den Fokus verliert.", "openDefaultSettings": "Steuert, ob beim Ɩffnen der Einstellungen auch ein Editor geƶffnet wird, der alle Standardeinstellungen anzeigt.", @@ -23,6 +27,10 @@ "statusBarVisibility": "Steuert die Sichtbarkeit der Statusleiste im unteren Bereich der Workbench.", "activityBarVisibility": "Steuert die Sichtbarkeit der AktivitƤtsleiste in der Workbench.", "closeOnFileDelete": "Steuert, ob Editoren, die eine Datei anzeigen, automatisch geschlossen werden sollen, wenn die Datei von einem anderen Prozess umbenannt oder gelƶscht wird. Wenn Sie diese Option deaktivieren, bleibt der Editor bei einem solchen Ereignis als geƤndert offen. Bei LƶschvorgƤngen innerhalb der Anwendung wird der Editor immer geschlossen, und geƤnderte Dateien werden nie geschlossen, damit Ihre Daten nicht verloren gehen.", + "fontAliasing": "Steuert die Schriftartaliasingmethode in der Workbench.\n- default: Subpixel-SchriftartglƤttung. Auf den meisten Nicht-Retina-Displays wird Text bei dieser Einstellung am schƤrfsten dargestellt.\n- antialiased: GlƤttet die Schriftart auf der Pixelebene (im Gegensatz zur Subpixelebene). Bei dieser Einstellung kann die Schriftart insgesamt heller wirken.\n- none: Deaktiviert die SchriftartglƤttung. Text wird mit gezackten scharfen Kanten dargestellt.\n", + "workbench.fontAliasing.default": "Subpixel-SchriftartglƤttung. Auf den meisten Nicht-Retina-Displays wird Text bei dieser Einstellung am schƤrfsten dargestellt.", + "workbench.fontAliasing.antialiased": "GlƤttet die Schriftart auf der Pixelebene (im Gegensatz zur Subpixelebene). Bei dieser Einstellung kann die Schriftart insgesamt heller wirken.", + "workbench.fontAliasing.none": "Deaktiviert die SchriftartglƤttung. Text wird mit gezackten scharfen Kanten dargestellt.", "swipeToNavigate": "Hiermit navigieren Sie per waagrechtem Wischen mit drei Fingen zwischen geƶffneten Dateien.", "workbenchConfigurationTitle": "Workbench", "window.openFilesInNewWindow.on": "Dateien werden in einem neuen Fenster geƶffnet.", @@ -34,16 +42,18 @@ "window.openFoldersInNewWindow.default": "Ordner werden in einem neuen Fenster geƶffnet, sofern kein Ordner innerhalb der Anwendung ausgewƤhlt wird (z.Ā B. über das Dateimenü).", "openFoldersInNewWindow": "Steuert, ob Ordner in einem neuen Fenster geƶffnet werden oder das letzte aktive Fenster ersetzen.\n- default: Die Ordner werden in einem neuen Fenster geƶffnet, sofern kein Ordner innerhalb der Anwendung ausgewƤhlt wird (z. B. über das Dateimenü).\n- on: Die Ordner werden in einem neuen Fenster geƶffnet.\n- off: Die Ordner ersetzen das letzte aktive Fenster.\nIn einigen FƤllen wird diese Einstellung unter UmstƤnden ignoriert (z. B. bei der Befehlszeilenoption \"-new-window\" oder \"-reuse-window\").", "window.reopenFolders.all": "Alle Fenster erneut ƶffnen.", + "window.reopenFolders.folders": "Alle Ordner erneut ƶffnen. Leere Arbeitsbereiche werden nicht wiederhergestellt.", "window.reopenFolders.one": "Das letzte aktive Fenster erneut ƶffnen. ", "window.reopenFolders.none": "Fenster nie erneut ƶffnen und immer mit einem leeren Fenster beginnen.", + "restoreWindows": "Steuert, wie Fenster nach einem Neustart erneut geƶffnet werden. WƤhlen Sie \"none\", um immer mit einem leeren Arbeitsbereich zu beginnen, \"one\", um das zuletzt verwendete Fenster erneut zu ƶffnen, \"folders\", um alle Fenster, in denen Ordner geƶffnet waren, erneut zu ƶffnen, oder \"all\", um alle Fenster der letzten Sitzung erneut zu ƶffnen.", "restoreFullscreen": "Steuert, ob ein Fenster im Vollbildmodus wiederhergestellt wird, wenn es im Vollbildmodus beendet wurde.", "zoomLevel": "Passen Sie den Zoomfaktor des Fensters an. Die ursprüngliche Größe ist 0. Jede Inkrementierung nach oben (z. B. 1) oder unten (z. B. -1) stellt eine Vergrößerung bzw. Verkleinerung um 20 % dar. Sie kƶnnen auch Dezimalwerte eingeben, um den Zoomfaktor genauer anzupassen.", - "title": "Steuert den Fenstertitel basierend auf dem aktiven Editor. Variablen werden abhƤngig vom Kontext ersetzt:\n${activeEditorShort}: z. B. meineDatei.txt\n${activeEditorMedium}: z. B. meinOrdner/meineDatei.txt\n${activeEditorLong}: z. B. /Users/Development/meinProjekt/meinOrdner/meineDatei.txt\n${folderName}: z. B. \nmeinOrdner${folderPath}: z. B. /Users/Development/meinOrdner\n${rootName}: z. B. meinOrdner1, meinOrdner2, meinOrdner3\n${rootPath}: z. B. /Users/Development/meinArbeitsbereich\n${appName}: z. B. VS Code\n${dirty}: ein Ƅnderungsindikator, wenn der aktive Editor geƤndert wurde\n${separator}: ein bedingtes Trennzeichen (\" - \"), das nur angezeigt wird, wenn es zwischen Variablen mit Werten steht", "window.newWindowDimensions.default": "Ɩffnet neue Fenster in der Mitte des Bildschirms.", "window.newWindowDimensions.inherit": "Ɩffnet neue Fenster mit den gleichen Abmessungen wie das letzte aktive Fenster.", "window.newWindowDimensions.maximized": "Ɩffnet neue Fenster maximiert.", "window.newWindowDimensions.fullscreen": "Ɩffnet neue Fenster im Vollbildmodus.", "newWindowDimensions": "Steuert die Abmessungen beim Ɩffnen eines neuen Fensters. Standardmäßig wird in der Mitte des Bildschirms ein neues Fenster mit kleinen Abmessungen geƶffnet. Bei der Einstellung \"inherit\" erhƤlt das Fenster die gleichen Abmessungen wie das letzte aktive Fenster. Bei der Einstellung \"maximized\" wird das Fenster maximiert geƶffnet, und bei \"fullscreen\" wird es im Vollbildmodus geƶffnet. Die Einstellung hat keine Auswirkungen auf das zuerst geƶffnete Fenster. Größe und Position des ersten Fensters werden immer so wiederhergestellt, wie sie vor dem Schließen waren.", + "closeWhenEmpty": "Steuert, ob das Fenster beim Schließen des letzten Editors geschlossen wird. Diese Einstellung gilt nur für Fenster, in denen keine Ordner angezeigt werden.", "window.menuBarVisibility.default": "Das Menü ist nur im Vollbildmodus ausgeblendet.", "window.menuBarVisibility.visible": "Das Menu wird immer angezeigt, auch im Vollbildmodus.", "window.menuBarVisibility.toggle": "Das Menu ist ausgeblendet, kann aber mit der Alt-Taste angezeigt werden.", diff --git a/i18n/deu/src/vs/workbench/electron-browser/window.i18n.json b/i18n/deu/src/vs/workbench/electron-browser/window.i18n.json index fcfa5e59e8f..dac54eb81af 100644 --- a/i18n/deu/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/deu/src/vs/workbench/electron-browser/window.i18n.json @@ -9,6 +9,5 @@ "cut": "Ausschneiden", "copy": "Kopieren", "paste": "Einfügen", - "selectAll": "Alles auswƤhlen", - "confirmOpenButton": "&&Ɩffnen" + "selectAll": "Alles auswƤhlen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 51de9385764..3deaa385b55 100644 --- a/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Wenn eine Zeile diesem Muster entspricht, sollte ihr Einzug nicht geƤndert und die Zeile nicht mit den anderen Regeln ausgewertet werden.", "schema.indentationRules.unIndentedLinePattern.pattern": "Das RegExp-Muster für unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Die RegExp-Flags für unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Muss mit dem Muster `/^([gimuy]+)$/` übereinstimmen." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Muss mit dem Muster `/^([gimuy]+)$/` übereinstimmen.", + "schema.folding": "Die Faltungseinstellungen der Sprache.", + "schema.folding.offSide": "Für eine Sprache gilt die Abseitsregel, wenn Blƶcke in dieser Sprache durch die Einrücktiefe ausgedrückt werden. Wenn dies festgelegt ist, gehƶren leere Zeilen zum nƤchsten Block.", + "schema.folding.markers": "Sprachspezifische Faltungsmarkierungen wie \"#region\" und \"#endregion\". Die regulƤren Anfangs- und Endausdrücke werden im Hinblick auf den Inhalt aller Zeilen getestet und müssen effizient erstellt werden.", + "schema.folding.markers.start": "Das RegExp-Muster für die Startmarkierung. Das Regexp muss mit \"^\" beginnen.", + "schema.folding.markers.end": "Das RegExp-Muster für die Endmarkierung. Das Regexp muss mit \"^\" beginnen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..6e8241b309f --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "Ansicht: Minikarte umschalten" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index a6a0523716f..09199c6fa32 100644 --- a/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "Steuerzeichen umschalten" + "toggleRenderControlCharacters": "Ansicht: Steuerzeichen umschalten" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 1c96dfb4c00..4fad63eb321 100644 --- a/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "Rendern von Leerzeichen umschalten" + "toggleRenderWhitespace": "Ansicht: Rendern von Leerzeichen umschalten" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index 3886214271e..f8f92c8accf 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "Keine Konfigurationen", + "addConfigTo": "Konfiguration hinzufügen ({0})...", "addConfiguration": "Konfiguration hinzufügen..." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index be338b43ea2..b06443ae9ef 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, Debugging", "debugAriaLabel": "Geben Sie den Namen einer auszuführenden Startkonfiguration ein.", + "addConfigTo": "Konfiguration hinzufügen ({0})...", + "addConfiguration": "Konfiguration hinzufügen...", "noConfigurationsMatching": "Keine übereinstimmenden Debugkonfigurationen", "noConfigurationsFound": "Keine Debugkonfiguration gefunden. Erstellen Sie die Datei \"launch.json\"." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..ceda8e419e5 --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "Fokus-Variablen", + "debugFocusCallStackView": "Fokus-CallStack" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 427b79c92de..1c098b69622 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Konfigurationen zum Generieren der anfƤnglichen Datei \"launch.json\".", "vscode.extension.contributes.debuggers.languages": "Liste der Sprachen, für die die Debugerweiterung als \"Standarddebugger\" angesehen werden kann", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Wenn dies festgelegt ist, ruft der VS Code diesen Befehl auf, um den ausführbaren Pfad des Debugadapters und die zu übergebenden Argumente zu bestimmen.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Wenn dies festgelegt ist, ruft der VS Code diesen Befehl für die Debug- oder Ausführungsaktionen aus, die für diese Erweiterung bestimmt sind.", "vscode.extension.contributes.debuggers.configurationSnippets": "Snippets zum Hinzufügen neuer Konfigurationen in \"launch.json\".", "vscode.extension.contributes.debuggers.configurationAttributes": "JSON-Schemakonfigurationen zum Überprüfen von \"launch.json\".", "vscode.extension.contributes.debuggers.windows": "Windows-spezifische Einstellungen.", diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 4588894202a..a02407d3bd9 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -13,11 +13,11 @@ "compoundMustHaveConfigurations": "Für den Verbund muss das Attribut \"configurations\" festgelegt werden, damit mehrere Konfigurationen gestartet werden kƶnnen.", "configMissing": "Konfiguration \"{0}\" fehlt in \"launch.json\".", "debugTypeNotSupported": "Der konfigurierte Debugtyp \"{0}\" wird nicht unterstützt.", - "debugTypeMissing": "Fehlende Eigenschaft \"type\" für die ausgewƤhlte Startkonfiguration.", + "debugTypeMissing": "Fehlende Eigenschaft `type` für die ausgewƤhlte Startkonfiguration.", + "debugAnyway": "Trotzdem debuggen", "preLaunchTaskErrors": "Buildfehler wƤhrend preLaunchTask \"{0}\".", "preLaunchTaskError": "Buildfehler wƤhrend preLaunchTask \"{0}\".", "preLaunchTaskExitCode": "Der preLaunchTask \"{0}\" wurde mit dem Exitcode {1} beendet.", - "debugAnyway": "Trotzdem debuggen", "noFolderWorkspaceDebugError": "Debuggen der aktiven Datei ist nicht mƶglich. Stellen Sie sicher, dass sie auf einem DatentrƤger gespeichert ist und dass Sie die Debugerweiterung für diesen Dateityp installiert haben.", "NewLaunchConfig": "Richten Sie die Startkonfigurationsdatei für Ihre Anwendung ein. {0}", "DebugTaskNotFound": "Der preLaunchTask \"{0}\" wurde nicht gefunden." diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index dded802b64c..fc3e3434fee 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "Der Objektstatus wird aus der ersten Auswertung erfasst.", "replVariableAriaLabel": "Variable {0} besitzt den Wert {1}, Read Eval Print-Loop, Debuggen", "replExpressionAriaLabel": "Ausdruck {0} besitzt den Wert {1}, Read Eval Print-Loop, Debuggen", - "replValueOutputAriaLabel": "{0}, Read Eval Print-Loop, Debuggen", - "replKeyValueOutputAriaLabel": "Ausgabevariable {0} besitzt den Wert {1}, Read Eval Print-Loop, Debuggen" + "replValueOutputAriaLabel": "{0}, Read Eval Print-Loop, Debuggen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index 57d2b620042..3de79db297e 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "Hintergrundfarbe der Statusleiste beim Debuggen eines Programms. Die Statusleiste wird unten im Fenster angezeigt.", - "statusBarDebuggingForeground": "Vordergrundfarbe der Statusleiste beim Debuggen eines Programms. Die Statusleiste wird unten im Fenster angezeigt." + "statusBarDebuggingForeground": "Vordergrundfarbe der Statusleiste beim Debuggen eines Programms. Die Statusleiste wird unten im Fenster angezeigt.", + "statusBarDebuggingBorder": "Rahmenfarbe der Statusleiste zur Abtrennung von der Randleiste und dem Editor, wenn ein Programm debuggt wird. Die Statusleiste wird unten im Fenster angezeigt." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 1bcee0dbf6e..db6aa85dc0e 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "Die ausführbare Datei \"{0}\" des Debugadapters ist nicht vorhanden.", "debugAdapterCannotDetermineExecutable": "Die ausführbare Datei \"{0}\" des Debugadapters kann nicht bestimmt werden.", + "launch.config.comment1": "Verwendet IntelliSense zum Ermitteln mƶglicher Attribute.", + "launch.config.comment2": "Zeigen Sie auf vorhandene Attribute, um die zugehƶrigen Beschreibungen anzuzeigen.", + "launch.config.comment3": "Weitere Informationen finden Sie unter {0}", "debugType": "Der Typ der Konfiguration.", "debugTypeNotRecognised": "Dieser Debugging-Typ wurde nicht erkannt. Bitte installieren und aktivieren Sie die dazugehƶrige Debugging-Erweiterung.", "node2NotSupported": "\"node2\" wird nicht mehr unterstützt, verwenden Sie stattdessen \"node\", und legen Sie das Attribut \"protocol\" auf \"inspector\" fest.", diff --git a/i18n/deu/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json index f14a2f53165..0b10a031064 100644 --- a/i18n/deu/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "terminalConfigurationTitle": "Externes Terminal", + "explorer.openInTerminalKind": "Passt an, welches Terminal ausgeführt werden soll.", "terminal.external.windowsExec": "Passt an, welches Terminal für Windows ausgeführt werden soll.", "terminal.external.osxExec": "Passt an, welche Terminalanwendung unter OS X ausgeführt werden soll.", "terminal.external.linuxExec": "Passt an, welches Terminal unter Linux ausgeführt werden soll.", diff --git a/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 8ecbab6f2e9..2d51a131a66 100644 --- a/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "Name", "view location": "Wo", - "themes": "Designs ({0})", + "colorThemes": "Farbdesigns ({0})", + "iconThemes": "Symboldesigns ({0})", + "colors": "Farben ({0})", + "colorId": "ID", + "defaultDark": "Standard, dunkel", + "defaultLight": "Standard, hell", + "defaultHC": "Standard, hoher Kontrast", "JSON Validation": "JSON-Validierung ({0})", "commands": "Befehle ({0})", "command name": "Name", diff --git a/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 0e32d73283c..9974d8c4709 100644 --- a/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,23 +34,26 @@ "postDisableMessage": "Dieses Fenster erneut laden, um die Erweiterung \"{0}\" zu deaktivieren?", "postUninstallTooltip": "Zum Deaktivieren erneut laden", "postUninstallMessage": "Dieses Fenster erneut laden, um die deinstallierte Erweiterung \"{0}\" zu deaktivieren?", - "reload": "Fenster &&erneut laden", "toggleExtensionsViewlet": "Erweiterungen anzeigen", "installExtensions": "Erweiterungen installieren", + "showEnabledExtensions": "Aktivierte Erweiterungen anzeigen", "showInstalledExtensions": "Installierte Erweiterungen anzeigen", "showDisabledExtensions": "Deaktivierte Erweiterungen anzeigen", "clearExtensionsInput": "Extensioneingabe lƶschen", "showOutdatedExtensions": "Veraltete Erweiterungen anzeigen", "showPopularExtensions": "Beliebte Erweiterungen anzeigen", "showRecommendedExtensions": "Empfohlene Erweiterungen anzeigen", - "showWorkspaceRecommendedExtensions": "Für den Arbeitsbereich empfohlene Erweiterungen anzeigen", + "installWorkspaceRecommendedExtensions": "Installieren Sie alle empfohlenen Erweiterungen für Ihren Arbeitsbereich", + "installRecommendedExtension": "Empfohlene Erweiterung installieren", "showRecommendedKeymapExtensions": "Empfohlene Tastenzuordnungen anzeigen", "showRecommendedKeymapExtensionsShort": "Tastenzuordnungen", "showLanguageExtensions": "Spracherweiterungen anzeigen", "showLanguageExtensionsShort": "Spracherweiterungen", - "configureWorkspaceRecommendedExtensions": "Empfohlene Erweiterungen konfigurieren (Arbeitsbereich)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Empfehlungen sind nur für einen Arbeitsbereichsordner verfügbar.", + "showAzureExtensions": "Azure-Erweiterungen anzeigen", + "showAzureExtensionsShort": "Azure-Erweiterungen", "OpenExtensionsFile.failed": "Die Datei \"extensions.json\" kann nicht im Ordner \".vscode\" erstellt werden ({0}).", + "configureWorkspaceRecommendedExtensions": "Empfohlene Erweiterungen konfigurieren (Arbeitsbereich)", + "configureWorkspaceFolderRecommendedExtensions": "Empfohlene Erweiterungen konfigurieren (Arbeitsbereichsordner)", "builtin": "Integriert", "disableAll": "Alle installierten Erweiterungen lƶschen", "disableAllWorkspace": "Alle installierten Erweiterungen für diesen Arbeitsbereich deaktivieren", diff --git a/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..b13de0b2ad0 --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "Empfohlen" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index b580aff8fbe..d8e69ffc518 100644 --- a/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -5,10 +5,13 @@ // Do not edit this file. It is machine generated. { "reallyRecommended2": "Für diesen Dateityp wird die Erweiterung \"{0}\" empfohlen.", + "reallyRecommendedExtensionPack": "Für diesen Dateityp wird das Erweiterungspaket \"{0}\" empfohlen.", "showRecommendations": "Empfehlungen anzeigen", + "install": "Installieren", "neverShowAgain": "Nicht mehr anzeigen", "close": "Schließen", "workspaceRecommended": "Für diesen Arbeitsbereich sind Erweiterungsempfehlungen verfügbar.", + "installAll": "Alle installieren", "ignoreExtensionRecommendations": "Mƶchten Sie alle Erweiterungsempfehlungen ignorieren?", "ignoreAll": "Ja, alles ignorieren", "no": "Nein", diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 72876f0d4f6..46de1e8541a 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Dateien", - "revealInSideBar": "In Seitenleiste anzeigen" + "filesCategory": "Datei", + "revealInSideBar": "In Seitenleiste anzeigen", + "acceptLocalChanges": "Ƅnderungen verwenden und DatentrƤgerinhalte überschreiben", + "revertLocalChanges": "Ƅnderungen verwerfen und DatentrƤgerinhalte wiederherstellen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 074e91a4e39..146bfaf2e06 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Mƶchten Sie \"{0}\" wirklich lƶschen?", "undoBin": "Die Wiederherstellung kann aus dem Papierkorb erfolgen.", "undoTrash": "Die Wiederherstellung kann aus dem Papierkorb erfolgen.", + "doNotAskAgain": "Nicht erneut fragen", "confirmDeleteMessageFolder": "Mƶchten Sie \"{0}\" samt Inhalt wirklich endgültig lƶschen?", "confirmDeleteMessageFile": "Mƶchten Sie \"{0}\" wirklich endgültig lƶschen?", "irreversible": "Diese Aktion kann nicht rückgƤngig gemacht werden.", @@ -37,17 +38,15 @@ "openToSide": "Zur Seite ƶffnen", "compareSource": "Für Vergleich auswƤhlen", "globalCompareFile": "Aktive Datei vergleichen mit...", - "pickHistory": "Zuvor geƶffnete Datei für den Vergleich auswƤhlen", - "unableToFileToCompare": "Die ausgewƤhlte Datei kann nicht mit \"{0}\" verglichen werden.", "openFileToCompare": "Zuerst eine Datei ƶffnen, um diese mit einer anderen Datei zu vergleichen", - "compareWith": "Mit '{0}' vergleichen", + "compareWith": "'{0}' mit '{1}' vergleichen", "compareFiles": "Dateien vergleichen", "refresh": "Aktualisieren", "save": "Speichern", "saveAs": "Speichern unter...", "saveAll": "Alle speichern", "saveAllInGroup": "Alle in der Gruppe speichern", - "saveFiles": "GeƤnderte Dateien speichern", + "saveFiles": "Alle Dateien speichern", "revert": "Datei wiederherstellen", "focusOpenEditors": "Fokus auf Ansicht \"Geƶffnete Editoren\"", "focusFilesExplorer": "Fokus auf Datei-Explorer", @@ -55,7 +54,6 @@ "openFileToShow": "Ɩffnet zuerst eine Datei, um sie im Explorer anzuzeigen.", "collapseExplorerFolders": "Ordner im Explorer zuklappen", "refreshExplorer": "Explorer aktualisieren", - "openFile": "Datei ƶffnen...", "openFileInNewWindow": "Aktive Datei in neuem Fenster ƶffnen", "openFileToShowInNewWindow": "Datei zuerst ƶffnen, um sie in einem neuen Fenster zu ƶffnen", "revealInWindows": "Im Explorer anzeigen", @@ -69,5 +67,7 @@ "emptyFileNameError": "Es muss ein Datei- oder Ordnername angegeben werden.", "fileNameExistsError": "Eine Datei oder ein Ordner **{0}** ist an diesem Ort bereits vorhanden. WƤhlen Sie einen anderen Namen.", "invalidFileNameError": "Der Name **{0}** ist als Datei- oder Ordnername ungültig. Bitte wƤhlen Sie einen anderen Namen aus.", - "filePathTooLongError": "Der Name **{0}** führt zu einem Pfad, der zu lang ist. WƤhlen Sie einen kürzeren Namen." + "filePathTooLongError": "Der Name **{0}** führt zu einem Pfad, der zu lang ist. WƤhlen Sie einen kürzeren Namen.", + "compareWithSaved": "Aktive Datei mit gespeicherter Datei vergleichen", + "modifiedLabel": "{0} (auf DatentrƤger) ↔ {1}" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index a959a89e774..8ddd57efb6a 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "Textdatei-Editor", "binaryFileEditor": "BinƤrdatei-Editor", "filesConfigurationTitle": "Dateien", - "exclude": "Konfiguriert die Globmuster zum Ausschließen von Dateien und Ordnern.", + "exclude": "Konfigurieren Sie Globmuster zum Ausschließen von Dateien und Ordnern. Zum Beispiel entscheidet Explorer welche Dateien und Ordner gezeigt oder ausgeblendet werden anhand dieser Einstellung.", "files.exclude.boolean": "Das Globmuster, mit dem Dateipfade verglichen werden sollen. Legen Sie diesen Wert auf \"true\" oder \"false\" fest, um das Muster zu aktivieren bzw. zu deaktivieren.", "files.exclude.when": "ZusƤtzliche Überprüfung der gleichgeordneten Elemente einer entsprechenden Datei. Verwenden Sie \"$(basename)\" als Variable für den entsprechenden Dateinamen.", "associations": "Konfigurieren Sie Dateizuordnungen zu Sprachen (beispielsweise \"*.extension\": \"html\"). Diese besitzen Vorrang vor den Standardzuordnungen der installierten Sprachen.", - "encoding": "Die Standardzeichensatz-Codierung, die beim Lesen und Schreiben von Dateien verwendet werden soll.", - "autoGuessEncoding": "Ist diese Option aktiviert, wird beim Ɩffnen von Dateien versucht, die Zeichensatzcodierung automatisch zu ermitteln.", + "encoding": "Die Standardzeichensatz-Codierung, die beim Lesen und Schreiben von Dateien verwendet werden soll. Diese Einstellung kann auch pro Sprache konfiguriert werden.", + "autoGuessEncoding": "Wenn diese Option aktiviert ist, wird beim Ɩffnen von Dateien versucht, die Zeichensatzcodierung automatisch zu ermitteln. Diese Einstellung kann auch pro Sprache konfiguriert werden.", "eol": "Das Zeilenende-Standardzeichen. Verwenden Sie \\n für LF und \\r\\n für CRLF.", "trimTrailingWhitespace": "Bei Aktivierung werden nachgestellte Leerzeichen beim Speichern einer Datei gekürzt.", "insertFinalNewline": "Bei Aktivierung wird beim Speichern einer Datei eine abschließende neue Zeile am Dateiende eingefügt.", + "trimFinalNewlines": "Wenn diese Option aktiviert ist, werden beim Speichern alle neuen Zeilen nach der abschließenden neuen Zeile am Dateiende gekürzt.", "files.autoSave.off": "Eine geƤnderte Datei wird nie automatisch gespeichert.", "files.autoSave.afterDelay": "Eine geƤnderte Datei wird automatisch nach der konfigurierten \"files.autoSaveDelay\" gespeichert.", "files.autoSave.onFocusChange": "Eine geƤnderte Datei wird automatisch gespeichert, wenn der Editor den Fokus verliert.", @@ -38,5 +39,12 @@ "openEditorsVisible": "Die Anzahl der Editoren, die im Bereich \"Geƶffnete Editoren\" angezeigt werden. Legen Sie diesen Wert auf 0 fest, um den Bereich auszublenden.", "dynamicHeight": "Steuert, ob sich die Hƶhe des Abschnitts \"Geƶffnete Editoren\" dynamisch an die Anzahl der Elemente anpassen soll.", "autoReveal": "Steuert, ob der Explorer Dateien beim Ɩffnen automatisch anzeigen und auswƤhlen soll.", - "enableDragAndDrop": "Steuert, ob der Explorer das Verschieben von Dateien und Ordnern mithilfe von Drag Drop zulassen soll." + "enableDragAndDrop": "Steuert, ob der Explorer das Verschieben von Dateien und Ordnern mithilfe von Drag Drop zulassen soll.", + "confirmDelete": "Steuert, ob der Explorer um BestƤtigung bitten soll, wenn Sie eine Datei über den Papierkorb lƶschen.", + "sortOrder.default": "Dateien und Ordner werden nach ihren Namen in alphabetischer Reihenfolge sortiert. Ordner werden vor Dateien angezeigt. ", + "sortOrder.mixed": "Dateien und Ordner werden nach ihren Namen in alphabetischer Reihenfolge sortiert. Dateien und Ordner werden vermischt angezeigt.", + "sortOrder.filesFirst": "Dateien und Ordner werden nach ihren Namen in alphabetischer Reihenfolge sortiert. Dateien werden vor Ordnern angezeigt.", + "sortOrder.type": "Dateien und Ordner werden nach ihren Erweiterungen in alphabetischer Reihenfolge sortiert. Ordner werden vor Dateien angezeigt.", + "sortOrder.modified": "Dateien und Ordner werden nach dem letzten Ƅnderungsdatum in absteigender Reihenfolge sortiert. Ordner werden vor Dateien angezeigt.", + "sortOrder": "Steuert die Sortierreihenfolge von Dateien und Ordnern im Explorer. ZusƤtzlich zur Standardsortierreihenfolge kƶnnen Sie die Reihenfolge auf \"mixed\" (kombinierte Sortierung von Dateien und Ordnern), \"type\" (nach Dateityp), \"modified\" (nach letztem Ƅnderungsdatum) oder \"filesFirst\" (Dateien vor Ordnern anzeigen) festlegen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index a9804d972b2..55ed6344bee 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "Verwenden Sie die Aktionen auf der Editor-Symbolleiste auf der rechten Seite, um Ihre Ƅnderungen **rückgƤngig zu machen** oder den Inhalt auf dem DatentrƤger mit Ihren Ƅnderungen zu **überschreiben**.", "discard": "Verwerfen", "overwrite": "Überschreiben", "retry": "Wiederholen", diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index e04313a8208..e3de54fe532 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Es ist kein Ordner geƶffnet.", "explorerSection": "Datei-Explorer-Abschnitt", - "noWorkspaceHelp": "Sie haben noch keinen Ordner geƶffnet.", + "noWorkspaceHelp": "Sie haben noch keinen Ordner zum Arbeitsbereich hinzugefügt.", + "addFolder": "Ordner hinzufügen", + "noFolderHelp": "Sie haben noch keinen Ordner geƶffnet.", "openFolder": "Ordner ƶffnen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..cc08efae6c8 --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Explorer" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index fb2ebc77680..ea87cbae459 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,12 @@ { "fileInputAriaLabel": "Geben Sie den Dateinamen ein. Drücken Sie zur BestƤtigung die EINGABETASTE oder ESC, um den Vorgang abzubrechen.", "filesExplorerViewerAriaLabel": "{0}, Datei-Explorer", + "dropFolders": "Mƶchten Sie die Ordner zum Arbeitsbereich hinzufügen?", + "dropFolder": "Mƶchten Sie den Ordner zum Arbeitsbereich hinzufügen?", + "addFolders": "&&Ordner hinzufügen", + "addFolder": "&&Ordner hinzufügen", + "confirmMove": "Sind Sie sicher, dass Sie \"{0}\" verschieben mƶchten?", + "doNotAskAgain": "Nicht erneut fragen", "confirmOverwriteMessage": "{0} ist im Zielordner bereits vorhanden. Mƶchten Sie das Element ersetzen?", "irreversible": "Diese Aktion kann nicht rückgƤngig gemacht werden.", "replaceButtonLabel": "&&Ersetzen" diff --git a/i18n/deu/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json b/i18n/deu/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json index cbb93b3996b..aebc7895072 100644 --- a/i18n/deu/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json @@ -9,6 +9,7 @@ "saveAll": "Alle speichern", "closeAllUnmodified": "Nicht geƤnderte schließen", "closeAll": "Alle schließen", + "compareWithSaved": "Mit gespeicherter Datei vergleichen", "close": "Schließen", "closeOthers": "Andere schließen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/deu/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 26ccd3a8679..efb4c5dd0f4 100644 --- a/i18n/deu/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 nicht gespeicherte Datei", "dirtyFiles": "{0} nicht gespeicherte Dateien" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/deu/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..cf58a240413 --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Probleme", + "tooltip.1": "1 Problem in dieser Datei", + "tooltip.N": "{0} Probleme in dieser Datei", + "markers.showOnFile": "Fehler & Warnungen auf Dateien und Ordnern anzeigen." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/deu/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index e17b9389cf1..fb35833a3f1 100644 --- a/i18n/deu/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "Kopieren" + "copyMarker": "Kopieren", + "copyMarkerMessage": "Nachricht kopieren" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index 7fb4c04c827..4aa1862f5cc 100644 --- a/i18n/deu/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "Langsamer Start erkannt", - "slow.detail": "Es tut uns leid, dass Ihr Start so langsam war. Starten Sie \"{0}\" mit aktivierter Profilerstellung neu, geben Sie die Profile für uns frei, und wir tun unser Bestes, damit der Start bald wieder perfekt funktioniert.", "prof.message": "Profile wurden erfolgreich erstellt.", "prof.detail": "Erstellen Sie ein Problem, und fügen Sie die folgenden Dateien manuell an:\n{0}", "prof.restartAndFileIssue": "Problem erstellen und neu starten", diff --git a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 157325389a5..503c8aa631f 100644 --- a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -8,6 +8,7 @@ "openGlobalKeybindings": "Tastaturkurzbefehle ƶffnen", "openGlobalKeybindingsFile": "Datei mit Tastaturkurzbefehlen ƶffnen", "openWorkspaceSettings": "Arbeitsbereichseinstellungen ƶffnen", + "openFolderSettings": "Ordnereinstellungen ƶffnen", "configureLanguageBasedSettings": "Sprachspezifische Einstellungen konfigurieren...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Sprache auswƤhlen" diff --git a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index e39c41141f0..06345a8acb0 100644 --- a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "Einstellungen kƶnnen nicht geschrieben werden. Ɩffnen Sie die Datei, um Fehler/Warnungen in der Datei zu korrigieren. Versuchen Sie es anschließend noch mal.", + "emptyUserSettingsHeader": "Platzieren Sie Ihre Einstellungen hier, um die Standardeinstellungen zu überschreiben.", + "emptyWorkspaceSettingsHeader": "Platzieren Sie Ihre Einstellungen hier, um die Benutzereinstellungen zu überschreiben.", + "emptyFolderSettingsHeader": "Platzieren Sie Ihre Ordnereinstellungen hier, um die Einstellungen in den Arbeitsbereichseinstellungen zu überschreiben.", + "defaultFolderSettingsTitle": "Standardordnereinstellungen", "defaultSettingsTitle": "Standardeinstellungen", - "noSettingsFound": "Keine Einstellungen gefunden.", "editTtile": "Bearbeiten", "replaceDefaultValue": "In Einstellungen ersetzen", "copyDefaultValue": "In Einstellungen kopieren", "unsupportedPHPExecutablePathSetting": "Diese Einstellung muss eine Benutzereinstellung sein. Ɩffnen Sie zum Konfigurieren von PHP für den Arbeitsbereich eine PHP-Datei, und klicken Sie in der Statusleiste auf \"PHP-Pfad\".", - "unsupportedWorkspaceSetting": "Diese Einstellung muss eine Benutzereinstellung sein." + "unsupportedWorkspaceSetting": "Diese Einstellung muss eine Benutzereinstellung sein.", + "unsupportedWorkbenchSetting": "Diese Einstellung kann jetzt nicht angewendet werden. Sie wird angewendet, wenn Sie den Ordner direkt ƶffnen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json index f28cfa282a3..29ee08e9ffc 100644 --- a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json @@ -7,5 +7,6 @@ "openFolderFirst": "Zuerst einen Ordner ƶffnen, um Arbeitsbereicheinstellungen zu erstellen", "emptyKeybindingsHeader": "Platzieren Sie Ihre Tastenzuordnungen in dieser Datei, um die Standardwerte zu überschreiben.", "defaultKeybindings": "Standardtastenzuordnungen", + "folderSettingsName": "{0} (Ordnereinstellungen)", "fail.createSettings": "{0} ({1}) kann nicht erstellt werden." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 8b6ad71cd4e..8bf5f390edb 100644 --- a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "noSettingsFound": "Keine Einstellungen gefunden.", + "folderSettingsDetails": "Ordnereinstellungen" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/deu/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index 753c62c2cec..f93cea2858c 100644 --- a/i18n/deu/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "Am hƤufigsten verwendet", - "noSettings": "Keine Einstellungen", "defaultKeybindingsHeader": "Überschreiben Sie Tastenzuordnungen, indem Sie sie in die Tastenzuordnungsdatei einfügen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 321ccab5284..77769778060 100644 --- a/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "Der Befehl \"{0}\" ist im aktuellen Kontext nicht aktiviert.", "recentlyUsed": "zuletzt verwendet", "morecCommands": "andere Befehle", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Keine übereinstimmenden Befehle." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 30e347510d4..8615a77c33b 100644 --- a/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -5,7 +5,5 @@ // Do not edit this file. It is machine generated. { "relaunchSettingMessage": "Eine Einstellung wurde geƤndert, welche einen Neustart benƶtigt.", - "relaunchSettingDetail": "Drücke den Neu starten-Button, um {0} neuzustarten und die Einstellung zu aktivieren.", - "restart": "Neu starten", - "reload": "Neu starten" + "relaunchSettingDetail": "Drücke den Neu starten-Button, um {0} neuzustarten und die Einstellung zu aktivieren." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 3a196327770..bd63f3fb9cd 100644 --- a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} von {1} Ƅnderungen", + "change": "{0} von {1} Ƅnderung", + "show previous change": "Vorherige Ƅnderung anzeigen", + "show next change": "NƤchste Ƅnderung anzeigen", "editorGutterModifiedBackground": "Hintergrundfarbe für die Editor-Leiste für Zeilen, die geƤndert wurden.", "editorGutterAddedBackground": "Hintergrundfarbe für die Editor-Leiste für Zeilen, die hinzugefügt wurden.", - "editorGutterDeletedBackground": "Hintergrundfarbe für die Editor-Leiste für Zeilen, die gelƶscht wurden." + "editorGutterDeletedBackground": "Hintergrundfarbe für die Editor-Leiste für Zeilen, die gelƶscht wurden.", + "overviewRulerModifiedForeground": "Übersichtslineal-Markierungsfarbe für geƤnderte Inhalte.", + "overviewRulerAddedForeground": "Übersichtslineal-Markierungsfarbe für hinzugefügte Inhalte.", + "overviewRulerDeletedForeground": "Übersichtslineal-Markierungsfarbe für gelƶschte Inhalte." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index 11d322e7129..cfb59dde790 100644 --- a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Git anzeigen", - "installAdditionalSCMProviders": "Installiere weiter SCM Provider...", "source control": "Quellcodeverwaltung", "toggleSCMViewlet": "SCM anzeigen", "view": "Anzeigen" diff --git a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index e79bc2ec954..c5c0985f4fc 100644 --- a/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Quellcodeanbieter", + "hideRepository": "Ausblenden", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "Installiere weiter SCM Provider...", + "no open repo": "Es gibt keine aktiven Quellcodeanbieter.", "source control": "Quellcodeverwaltung", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index fccafa19088..451df58f63e 100644 --- a/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "Zu Symbol im Arbeitsbereich wechseln...", "name": "Suchen", - "showSearchViewlet": "Suche anzeigen", + "search": "Suchen", "view": "Anzeigen", - "findInFiles": "In Dateien suchen", "openAnythingHandlerDescription": "Zu Datei wechseln", "openSymbolDescriptionNormal": "Zu Symbol im Arbeitsbereich wechseln", "searchOutputChannelTitle": "Suchen", @@ -16,7 +15,5 @@ "exclude": "Konfigurieren Sie Globmuster zum Ausschließen von Dateien und Ordnern in SuchvorgƤngen. Alle Globmuster werden von der files.exclude-Einstellung geerbt.", "exclude.boolean": "Das Globmuster, mit dem Dateipfade verglichen werden sollen. Legen Sie diesen Wert auf \"true\" oder \"false\" fest, um das Muster zu aktivieren bzw. zu deaktivieren.", "exclude.when": "ZusƤtzliche Überprüfung der gleichgeordneten Elemente einer entsprechenden Datei. Verwenden Sie \"$(basename)\" als Variable für den entsprechenden Dateinamen.", - "useRipgrep": "Steuert, ob \"ripgrep\" in der Textsuche verwendet wird", - "useIgnoreFilesByDefault": "Steuert, ob bei der Suche in einem neuen Arbeitsbereich standardmäßig GITIGNORE- und IGNORE-Dateien verwendet werden sollen.", "search.quickOpen.includeSymbols": "Konfigurieren Sie diese Option, um Ergebnisse aus einer globalen Symbolsuche in die Dateiergebnisse für Quick Open einzuschließen." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 2914ad5ba59..d0c6fa6941c 100644 --- a/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,16 +4,23 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "NƤchstes Sucheinschlussmuster anzeigen", + "previousSearchIncludePattern": "Vorheriges Sucheinschlussmuster anzeigen", + "nextSearchExcludePattern": "NƤchstes Suchausschlussmuster anzeigen", + "previousSearchExcludePattern": "Vorheriges Suchausschlussmuster anzeigen", "nextSearchTerm": "NƤchsten Suchbegriff anzeigen", "previousSearchTerm": "Vorherigen Suchbegriff anzeigen", "focusNextInputBox": "Fokus im nƤchsten Eingabefeld", "focusPreviousInputBox": "Fokus im vorherigen Eingabefeld", + "showSearchViewlet": "Suche anzeigen", + "findInFiles": "In Dateien suchen", "replaceInFiles": "In Dateien ersetzen", + "findInWorkspace": "In Arbeitsbereich suchen...", + "findInFolder": "In Ordner suchen...", "RefreshAction.label": "Aktualisieren", "ClearSearchResultsAction.label": "Suchergebnisse lƶschen", "FocusNextSearchResult.label": "Fokus auf nƤchstes Suchergebnis", "FocusPreviousSearchResult.label": "Fokus auf vorheriges Suchergebnis", - "RemoveAction.label": "Entfernen", "file.replaceAll.label": "Alle ersetzen", "match.replace.label": "Ersetzen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json b/i18n/deu/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json index 8ec0049b3b3..66ba97093a9 100644 --- a/i18n/deu/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "searchFolderMatch.other.label": "Andere Dateien", + "searchFileMatches": "{0} Dateien gefunden", + "searchFileMatch": "{0} Datei gefunden", "searchMatches": "{0} Übereinstimmungen gefunden", "searchMatch": "{0} Übereinstimmung gefunden", + "folderMatchAriaLabel": "{0} Übereinstimmungen im Ordnerstamm {1}, Suchergebnis", "fileMatchAriaLabel": "{0} Übereinstimmungen in der Datei \"{1}\" des Ordners \"{2}\", Suchergebnis", "replacePreviewResultAria": "Ersetze Term {0} mit {1} an Spaltenposition {2} in Zeile mit Text {3}", "searchResultAria": "Term {0} an Spaltenposition {1} in Zeile mit Text {2} gefunden" diff --git a/i18n/deu/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/deu/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 86e0e518608..446ebb0ddc2 100644 --- a/i18n/deu/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "Auszuschließende Dateien", "label.excludes": "Suchausschlussmuster", "replaceAll.confirmation.title": "Alle ersetzen", - "replaceAll.confirm.button": "Ersetzen", + "replaceAll.confirm.button": "&&Ersetzen", "replaceAll.occurrence.file.message": "{0} Vorkommen in {1} Datei durch \"{2}\" ersetzt.", "removeAll.occurrence.file.message": "{0} Vorkommen in {1} Datei ersetzt.", "replaceAll.occurrence.files.message": "{0} Vorkommen in {1} Dateien durch \"{2}\" ersetzt.", @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "{0} Vorkommen in {1} Dateien durch \"{2}\" ersetzen?", "replaceAll.occurrences.files.confirmation.message": "{0} Vorkommen in {1} Dateien ersetzen?", "treeAriaLabel": "Suchergebnisse", + "searchPathNotFoundError": "Der Suchpfad wurde nicht gefunden: {0}.", "searchMaxResultsWarning": "Das Resultset enthƤlt nur eine Teilmenge aller Übereinstimmungen. Verfeinern Sie Ihre Suche, um die Ergebnisse einzugrenzen.", "searchCanceled": "Die Suche wurde abgebrochen, bevor Ergebnisse gefunden werden konnten – ", "noResultsIncludesExcludes": "Keine Ergebnisse in \"{0}\" unter Ausschluss von \"{1}\" gefunden – ", "noResultsIncludes": "Keine Ergebnisse in \"{0}\" gefunden – ", "noResultsExcludes": "Keine Ergebnisse gefunden, die \"{0}\" ausschließen – ", - "noResultsFound": "Es wurden keine Ergebnisse gefunden. Überprüfen Sie Ihre Einstellungen für konfigurierte Ausschlüsse – ", + "noResultsFound": "Es wurden keine Ergebnisse gefunden. Überprüfen Sie Ihre Einstellungen für konfigurierte Ausschlüsse und das Ignorieren von Dateien –", "rerunSearch.message": "Erneut suchen", "rerunSearchInAll.message": "Erneut in allen Dateien suchen", "openSettings.message": "Einstellungen ƶffnen", + "openSettings.learnMore": "Weitere Informationen", "ariaSearchResultsStatus": "Die Suche hat {0} Ergebnisse in {1} Dateien zurückgegeben.", "search.file.result": "{0} Ergebnis in {1} Datei", "search.files.result": "{0} Ergebnis in {1} Dateien", diff --git a/i18n/deu/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/deu/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..4e9dc03fa81 --- /dev/null +++ b/i18n/deu/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Kein Ordner im Arbeitsbereich mit Namen: {0}" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 1fb6b028507..04501ed578a 100644 --- a/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "Codeausschnitt einfügen" + "snippet.suggestions.label": "Codeausschnitt einfügen", + "sep.userSnippet": "Benutzercodeausschnitte", + "sep.extSnippet": "Erweiterungscodeausschnitte" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index d7eacd9f7d8..f7ba361f2c6 100644 --- a/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "Unbekannte Sprache in \"contributes.{0}.language\". Bereitgestellter Wert: {1}", + "invalid.path.0": "Expected string in `contributes.{0}.path`. Provided value: {1}", + "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Erweiterung enthalten ist. Dies führt ggf. dazu, dass die Erweiterung nicht portierbar ist.", + "vscode.extension.contributes.snippets": "TrƤgt Codeausschnitte bei.", + "vscode.extension.contributes.snippets-language": "Der Sprachbezeichner, für den dieser Codeausschnitt beigetragen wird.", + "vscode.extension.contributes.snippets-path": "Der Pfad der Codeausschnittdatei. Der Pfad ist relativ zum Erweiterungsordner und beginnt normalerweise mit \". /snippets/\".", + "badFile": "Die Ausschnittsdatei \"{0}\" konnte nicht gelesen werden.", "source.snippet": "Benutzercodeausschnitt", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 76d6135b7eb..232837396be 100644 --- a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "Konfiguriert das zum Darstellen der Aufgabenausgabe verwendete Panel und liest die Eingabe.", "JsonSchema.tasks.presentation.echo": "Steuert, ob der ausgeführte Befehl im Panel angezeigt wird. Der Standardwert ist \"true\". ", "JsonSchema.tasks.presentation.focus": "Steuert, ob das Panel den Fokus hat. der Standardwert ist \"false\". Bei Einstellung auf \"true\" wird das Panel ebenfalls angezeigt.", + "JsonSchema.tasks.presentation.reveal.always": "Zeigt immer das Terminal an, wenn diese Aufgabe ausgeführt wird.", + "JsonSchema.tasks.presentation.reveal.silent": "Zeigt das Terminal nur an, wenn der Aufgabe kein Problemabgleicher zugeordnet ist und bei der Ausführung Fehler auftreten.", + "JsonSchema.tasks.presentation.reveal.never": "Zeigt das Terminal beim Ausführen dieser Aufgabe nie an.", "JsonSchema.tasks.presentation.reveals": "Steuert, ob das Panel, das die Aufgabe ausführt, angezeigt wird. Der Standardwert ist \"always\".", "JsonSchema.tasks.presentation.instance": "Steuert, ob das Panel von Aufgaben gemeinsam genutzt wird, ob es dieser Aufgabe zugewiesen wird oder ob bei jeder Ausführung ein neues Panel erstellt wird.", "JsonSchema.tasks.terminal": "Die terminal-Eigenschaft ist veraltet. Verwenden Sie stattdessen \"presentation\". ", @@ -22,7 +25,6 @@ "JsonSchema.tasks.group.test": "Markiert die Aufgaben als eine Testaufgabe, die über den Befehl \"Testtask ausführen\" zugƤnglich ist.", "JsonSchema.tasks.group.none": "Weist die Aufgabe keiner Gruppe zu.", "JsonSchema.tasks.group": "Definiert die Ausführungsgruppe, zu der diese Aufgabe gehƶrt. Zum Hinzufügen der Aufgabe zur Buildgruppe wird \"build\" unterstützt und zum Hinzufügen zur Testgruppe \"test\".", - "JsonSchema.tasks.type": "Definiert, ob die Aufgabe als Prozess oder als Befehl innerhalb einer Shell ausgeführt wird. Standardmäßig wird sie als Prozess ausgeführt.", "JsonSchema.version": "Die Versionsnummer der Konfiguration.", "JsonSchema.tasks.identifier": "Ein vom Benutzer definierter Bezeichner, mit dem in \"launch.json\" oder in einer dependsOn-Klausel auf die Aufgabe verwiesen wird.", "JsonSchema.tasks.taskLabel": "Die Bezeichnung der Aufgabe", @@ -35,8 +37,10 @@ "JsonSchema.tasks.customize.deprecated": "Die customize-Eigenschaft ist veraltet. Informationen zur Migration zum neuen Ansatz für die Aufgabenanpassung finden Sie in den Anmerkungen zur Version 1.14.", "JsonSchema.tasks.showOputput.deprecated": "Die showOutput-Eigenschaft ist veraltet. Verwenden Sie stattdessen die reveal-Eigenschaft innerhalb der presentation-Eigenschaft. Weitere Informationen finden Sie auch in den Anmerkungen zur Version 1.14.", "JsonSchema.tasks.echoCommand.deprecated": "Die echoCommand-Eigenschaft ist veraltet. Verwenden Sie stattdessen die echo-Eigenschaft innerhalb der presentation-Eigenschaft. Weitere Informationen finden Sie auch in den Anmerkungen zur Version 1.14. ", + "JsonSchema.tasks.suppressTaskName.deprecated": "Die suppressTaskName-Eigenschaft ist veraltet. Binden Sie den Befehl mit den zugehƶrigen Argumenten stattdessen in die Aufgabe ein. Weitere Informationen finden Sie auch in den Anmerkungen zur Version 1.14.", "JsonSchema.tasks.isBuildCommand.deprecated": "Die isBuildCommand-Eigenschaft ist veraltet. Verwenden Sie stattdessen die group-Eigenschaft. Weitere Informationen finden Sie auch in den Anmerkungen zur Version 1.14. ", "JsonSchema.tasks.isTestCommand.deprecated": "Die isTestCommand-Eigenschaft ist veraltet. Verwenden Sie stattdessen die group-Eigenschaft. Weitere Informationen finden Sie auch in den Anmerkungen zur Version 1.14.", + "JsonSchema.tasks.taskSelector.deprecated": "Die taskSelector-Eigenschaft ist veraltet. Binden Sie den Befehl mit den zugehƶrigen Argumenten stattdessen in die Aufgabe ein. Weitere Informationen finden Sie auch in den Anmerkungen zur Version 1.14.", "JsonSchema.windows": "Windows-spezifische Befehlskonfiguration", "JsonSchema.mac": "Mac-spezifische Befehlskonfiguration", "JsonSchema.linux": "Linux-spezifische Befehlskonfiguration" diff --git a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index b85cadb9245..09fd787097a 100644 --- a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,30 +5,34 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Aufgaben", - "ConfigureTaskRunnerAction.noWorkspace": "Aufgaben sind nur für einen Arbeitsbereichsordner verfügbar.", - "ConfigureTaskRunnerAction.quickPick.template": "Taskausführung auswƤhlen", - "ConfigureTaskRunnerAction.autoDetecting": "Tasks für {0} werden automatisch erkannt.", - "ConfigureTaskRunnerAction.autoDetect": "Fehler bei der automatischen Erkennung des Tasksystems. Die Standardvorlage wird verwendet. Einzelheiten finden Sie in der Taskausgabe.", - "ConfigureTaskRunnerAction.autoDetectError": "Bei der automatischen Erkennung des Tasksystems sind Fehler aufgetreten. Einzelheiten finden Sie in der Taskausgabe.", - "ConfigureTaskRunnerAction.failed": "Die Datei \"tasks.json\" kann nicht im Ordner \".vscode\" erstellt werden. Einzelheiten finden Sie in der Taskausgabe.", - "ConfigureTaskRunnerAction.label": "Taskausführung konfigurieren", + "ConfigureTaskRunnerAction.label": "Aufgabe konfigurieren", "ConfigureBuildTaskAction.label": "Buildtask konfigurieren", "CloseMessageAction.label": "Schließen", "ShowTerminalAction.label": "Terminal anzeigen", "problems": "Probleme", "manyMarkers": "mehr als 99", + "runningTasks": "Aktive Aufgaben anzeigen", "tasks": "Aufgaben", - "TaskSystem.noHotSwap": "Zum Ƅndern des Aufgabenausführungsmoduls muss VS Code neu gestartet werden. Die Ƅnderung wird ignoriert.", + "TaskSystem.noHotSwap": "Zum Ƅndern des Aufgabenausführungsmoduls mit einem aktiven Task muss das Fenster erneut geladen werden.", + "TaskServer.folderIgnored": "Der Ordner {0} wird ignoriert, da er Aufgabenversion 0.1.0 verwendet", "TaskService.noBuildTask1": "Keine Buildaufgabe definiert. Markieren Sie eine Aufgabe mit 'isBuildCommand' in der tasks.json-Datei.", "TaskService.noBuildTask2": "Es ist keine Buildaufgabe definiert. Markieren Sie eine Aufgabe in der Datei \"tasks.json\" als \"Buildgruppe\". ", "TaskService.noTestTask1": "Keine Testaufgabe definiert. Markieren Sie eine Aufgabe mit 'isTestCommand' in der tasks.json-Datei.", "TaskService.noTestTask2": "Es ist keine Testaufgabe definiert. Markieren Sie eine Aufgabe in der Datei \"tasks.json\" als \"Testgruppe\". ", "TaskServer.noTask": "Die angeforderte auszuführende Aufgabe {0} wurde nicht gefunden.", + "TaskService.associate": "assoziieren", + "TaskService.attachProblemMatcher.continueWithout": "Ohne Überprüfung der Aufgabenausgabe fortsetzen", + "TaskService.attachProblemMatcher.never": "Aufgabenausgabe nie überprüfen", + "TaskService.attachProblemMatcher.learnMoreAbout": "Weitere Informationen zur Überprüfung der Aufgabenausgabe", + "selectProblemMatcher": "Fehler- und Warnungsarten auswƤhlen, auf die die Aufgabenausgabe überprüft werden soll", "customizeParseErrors": "Die aktuelle Aufgabenkonfiguration weist Fehler auf. Beheben Sie die Fehler, bevor Sie eine Aufgabe anpassen.", "moreThanOneBuildTask": "In \"tasks.json\" sind mehrere Buildaufgaben definiert. Die erste wird ausgeführt.\n", + "TaskSystem.activeSame.background": "Die Aufgabe \"{0}\" ist bereits im Hintergrundmodus aktiv. Klicken Sie zum Beenden der Aufgabe im Menü \"Aufgaben\" auf \"Aufgabe beenden\".", + "TaskSystem.activeSame.noBackground": "Die Aufgabe \"{0}\" ist bereits aktiv. Klicken Sie zum Beenden der Aufgabe im Menü \"Aufgaben\" auf \"Aufgabe beenden\".", "TaskSystem.active": "Eine aktive Aufgabe wird bereits ausgeführt. Beenden Sie diese, bevor Sie eine andere Aufgabe ausführen.", "TaskSystem.restartFailed": "Fehler beim Beenden und Neustarten der Aufgabe \"{0}\".", "TaskSystem.configurationErrors": "Fehler: Die angegebene Aufgabenkonfiguration weist Validierungsfehler auf und kann nicht verwendet werden. Beheben Sie zuerst die Fehler.", + "taskService.ignoreingFolder": "Die Aufgabenkonfigurationen für den Arbeitsbereichsordner {0} werden ignoriert. Für die Aufgabenunterstützung von Arbeitsbereichen mit mehreren Ordner müssen alle Ordner die Aufgabenversion 2.0.0 verwenden.\n", "TaskSystem.invalidTaskJson": "Fehler: Der Inhalt der Datei \"tasks.json\" weist Syntaxfehler auf. Bitte korrigieren sie diese, bevor Sie einen Task ausführen.\n", "TaskSystem.runningTask": "Es wird ein Task ausgeführt wird. Mƶchten Sie ihn beenden?", "TaskSystem.terminateTask": "&&Task beenden", @@ -40,25 +44,37 @@ "recentlyUsed": "zuletzt verwendete Aufgaben", "configured": "konfigurierte Aufgaben", "detected": "erkannte Aufgaben", + "TaskService.ignoredFolder": "Die folgenden Arbeitsbereichsordner werden ignoriert, da sie Aufgabenversion 0.1.0 verwenden: ", + "TaskService.notAgain": "Nicht mehr anzeigen", + "TaskService.ok": "OK", + "TaskService.pickRunTask": "Auszuführende Aufgabe auswƤhlen", + "TaslService.noEntryToRun": "Es wurde keine auszuführende Aufgabe gefunden. Aufgaben konfigurieren...", "TaskService.fetchingBuildTasks": "Buildaufgaben werden abgerufen...", - "TaskService.noBuildTaskTerminal": "Es wurde keine Buildaufgabe gefunden. Klicken Sie auf \"Buildtask konfigurieren\", um eine Aufgabe zu definieren.", "TaskService.pickBuildTask": "Auszuführende Buildaufgabe auswƤhlen", + "TaskService.noBuildTask": "Es wurde keine auszuführende Buildaufgabe gefunden. Aufgaben konfigurieren...", "TaskService.fetchingTestTasks": "Testaufgaben werden abgerufen...", - "TaskService.noTestTaskTerminal": "Es wurde keine Testaufgabe gefunden. Klicken Sie auf \"Taskausführung konfigurieren\", um eine Aufgabe zu definieren.", "TaskService.pickTestTask": "Auszuführende Testaufgabe auswƤhlen", - "TaskService.noTaskRunning": "Zurzeit wird keine Aufgabe ausgeführt.", + "TaskService.noTestTaskTerminal": "Es wurde keine auszuführende Testaufgabe gefunden. Aufgaben konfigurieren...", "TaskService.tastToTerminate": "Zu beendende Aufgabe auswƤhlen", + "TaskService.noTaskRunning": "Zurzeit wird keine Aufgabe ausgeführt.", "TerminateAction.noProcess": "Der gestartete Prozess ist nicht mehr vorhanden. Wenn der Task Hintergrundtasks erzeugt hat, kann das Beenden von VS Code ggf. zu verwaisten Prozessen führen.", "TerminateAction.failed": "Fehler beim Beenden des ausgeführten Tasks.", - "TaskService.noTaskToRestart": "Es ist keine neu zu startende Aufgabe vorhanden.", "TaskService.tastToRestart": "Neu zu startende Aufgabe auswƤhlen", + "TaskService.noTaskToRestart": "Es ist keine neu zu startende Aufgabe vorhanden.", + "TaskService.template": "Aufgabenvorlage auswƤhlen", + "TaskService.createJsonFile": "Datei \"tasks.json\" aus Vorlage erstellen", + "TaskService.openJsonFile": "Datei \"tasks.json\" ƶffnen", + "TaskService.pickTask": "Zu konfigurierende Aufgabe auswƤhlen", "TaskService.defaultBuildTaskExists": "{0} ist bereits als Standardbuildaufgabe markiert.", "TaskService.pickDefaultBuildTask": "Als Standardbuildaufgabe zu verwendende Aufgabe auswƤhlen", "TaskService.defaultTestTaskExists": "{0} ist bereits als Standardtestaufgabe markiert.", "TaskService.pickDefaultTestTask": "Als Standardtestaufgabe zu verwendende Aufgabe auswƤhlen", + "TaskService.pickShowTask": "Aufgabe zum Anzeigen der Ausgabe auswƤhlen", + "TaskService.noTaskIsRunning": "Es wird keine Aufgabe ausgeführt.", "ShowLogAction.label": "Taskprotokoll anzeigen", "RunTaskAction.label": "Task ausführen", "RestartTaskAction.label": "Ausgeführte Aufgabe neu starten", + "ShowTasksAction.label": "Aktive Aufgaben anzeigen", "BuildAction.label": "Buildtask ausführen", "TestAction.label": "Testtask ausführen", "ConfigureDefaultBuildTask.label": "Standardbuildaufgabe konfigurieren ", diff --git a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 0ad146b3785..197256b0631 100644 --- a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Unbekannter Fehler beim Ausführen eines Tasks. Details finden Sie im Taskausgabeprotokoll.", + "dependencyFailed": "Die abhƤngige Aufgabe \"{0}\" im Arbeitsbereichsordner \"{1}\" konnte nicht aufgelƶst werden.", "TerminalTaskSystem.terminalName": "Aufgabe - {0}", "reuseTerminal": "Das Terminal wird von Aufgaben wiederverwendet, drücken Sie zum Schließen eine beliebige Taste.", "TerminalTaskSystem": "Ein Shell-Befehl kann nicht auf einem UNC-Laufwerk ausgeführt werden.", diff --git a/i18n/deu/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/deu/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index 6064eccbd98..89dde23b864 100644 --- a/i18n/deu/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,9 +11,12 @@ "ConfigurationParser.unknownMatcherKind": "Warnung: Der definierte Problemabgleich ist unbekannt. Die folgenden Typen werden unterstützt: string | ProblemMatcher | (string | ProblemMatcher)[].\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "Fehler: Ungültiger ProblemMatcher-Verweis: {0}\n", "ConfigurationParser.noTaskType": "Fehler: Die Aufgabenkonfiguration muss eine type-Eigenschaft enthalten. Die Konfiguration wird ignoriert.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "Fehler: Der registrierte Aufgabentyp \"{0}\" ist nicht vorhanden. Wurde mƶglicherweise eine Erweiterung nicht installiert, die den entsprechenden Aufgabenanbieter bereitstellt?", + "ConfigurationParser.missingRequiredProperty": "Fehler: Die Aufgabenkonfiguration \"{0}\" enthƤlt die erforderlich Eigenschaft \"{1}\" nicht. Die Aufgabenkonfiguration wird ignoriert.", "ConfigurationParser.notCustom": "Fehler: Die Aufgabe ist nicht als benutzerdefinierte Aufgabe deklariert. Die Konfiguration wird ignoriert.\n{0}\n", "ConfigurationParser.noTaskName": "Fehler: Tasks müssen eine Eigenschaft \"TaskName\" angeben. Der Task wird ignoriert.\n{0}\n", "taskConfiguration.shellArgs": "Warnung: Die Aufgabe \"{0}\" ist ein Shellbefehl, und der Befehlsname oder eines seiner Argumente enthƤlt Leerzeichen ohne Escapezeichen. Führen Sie Argumente im Befehl zusammen, um eine korrekte Angabe der Befehlszeile sicherzustellen.", "taskConfiguration.noCommandOrDependsOn": "Fehler: Aufgabe \"{0}\" definiert keinen Befehl bzw. keine depondsOn-Eigenschaft. Die Aufgabe wird ignoriert. Die Definition lautet:\n{1}", - "taskConfiguration.noCommand": "Fehler: Aufgabe \"{0}\" definiert keinen Befehl. Die Aufgabe wird ignoriert. Die Definition lautet:\n{1}" + "taskConfiguration.noCommand": "Fehler: Aufgabe \"{0}\" definiert keinen Befehl. Die Aufgabe wird ignoriert. Die Definition lautet:\n{1}", + "TaskParse.noOsSpecificGlobalTasks": "Die Aufgabenversion 2.0.0 unterstützt globale betriebssystemspezifische Aufgaben nicht. Konvertieren Sie sie in eine Aufgabe mit einem betriebssystemspezifischen Befehl. Folgende Aufgaben sind hiervon betroffen:\n{0}" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 8b6ad71cd4e..331fd59e24c 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "termEntryAriaLabel": "{0}, Terminalauswahl", + "termCreateEntryAriaLabel": "{0}, neues Terminal erstellen", + "'workbench.action.terminal.newplus": "$(plus) Neues integriertes Terminal erstellen", + "noTerminalsMatching": "Keine übereinstimmenden Terminals", + "noTerminalsFound": "Keine geƶffneten Terminals" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 4d0a1893044..caa7dd980fd 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -4,18 +4,19 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "quickOpen.terminal": "Alle geƶffneten Terminals anzeigen", + "terminal": "Terminal", "terminalIntegratedConfigurationTitle": "Integriertes Terminal", "terminal.integrated.shell.linux": "Der Pfad der Shell, den das Terminal unter Linux verwendet.", "terminal.integrated.shellArgs.linux": "Die Befehlszeilenargumente, die für das Linux-Terminal verwendet werden sollen.", "terminal.integrated.shell.osx": "Der Pfad der Shell, den das Terminal unter OS X verwendet.", "terminal.integrated.shellArgs.osx": "Die Befehlszeilenargumente, die für das OS X-Terminal verwendet werden sollen.", + "terminal.integrated.shell.windows": "Der Pfad der Shell, den das Terminal unter Windows verwendet, wenn in Windows enthaltene Terminals verwendet werden (cmd, PowerShell oder Bash unter Ubuntu).", "terminal.integrated.shellArgs.windows": "Die Befehlszeilenargumente, die im Windows-Terminal verwendet werden sollen.", "terminal.integrated.rightClickCopyPaste": "Wenn dies festgelegt ist, erscheint das Kontextmenü bei einem Rechtsklick im Terminal nicht mehr. Stattdessen erfolgen die VorgƤnge Kopieren, wenn eine Auswahl vorgenommen wurde, sowie Einfügen, wenn keine Auswahl vorgenommen wurde.", "terminal.integrated.fontFamily": "Steuert die Schriftartfamilie des Terminals. Der Standardwert ist \"editor.fontFamily\".", - "terminal.integrated.fontLigatures": "Steuert, ob Schriftartligaturen im Terminal aktiviert sind.", "terminal.integrated.fontSize": "Steuert den Schriftgrad des Terminals in Pixeln.", "terminal.integrated.lineHeight": "Steuert die Zeilenhƶhe für das Terminal. Dieser Wert wird mit dem Schriftgrad des Terminals multipliziert, um die tatsƤchliche Zeilenhƶhe in Pixeln zu erhalten.", - "terminal.integrated.enableBold": "Gibt an, ob Fettdruck im Terminal aktiviert werden soll. Dies muss durch die Terminalshell unterstützt werden.", "terminal.integrated.cursorBlinking": "Steuert, ob der Terminalcursor blinkt.", "terminal.integrated.cursorStyle": "Steuert den Stil des Terminalcursors.", "terminal.integrated.scrollback": "Steuert die maximale Anzahl von Zeilen, die das Terminal im Puffer beibehƤlt.", @@ -23,7 +24,9 @@ "terminal.integrated.cwd": "Ein expliziter Startpfad zum Starten des Terminals, dies dient als das aktuelle Arbeitsverzeichnis (CWD) für den Shellprozess. Dies ist insbesondere in Arbeitsbereichseinstellungen praktisch, wenn das Stammverzeichnis kein passendes CWD ist.", "terminal.integrated.confirmOnExit": "Ob aktive Terminalsitzungen beim Beenden bestƤtigt werden sollen.", "terminal.integrated.commandsToSkipShell": "Eine Sammlung von Befehls-IDs, deren Tastenzuordnungen nicht an die Shell gesendet und die stattdessen immer durch Code verarbeitet werden. Dies ermƶglicht die Verwendung von Tastenzuordnungen, die normalerweise von der Shell verwendet würden, um das gleiche Verhalten wie bei einem Terminal ohne Fokus zu erzielen, z. B. STRG+P zum Starten von Quick Open.", - "terminal": "Terminal", + "terminal.integrated.env.osx": "Objekt mit Umgebungsvariablen, das dem unter OS X vom Terminal zu verwendenden VS Code-Prozess hinzugefügt wird", + "terminal.integrated.env.linux": "Objekt mit Umgebungsvariablen, das dem unter Linux vom Terminal zu verwendenden VS Code-Prozess hinzugefügt wird", + "terminal.integrated.env.windows": "Objekt mit Umgebungsvariablen, das dem unter Windows vom Terminal zu verwendenden VS Code-Prozess hinzugefügt wird", "terminalCategory": "Terminal", "viewCategory": "Anzeigen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 31e96cf587e..93a8b04286a 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "Integriertes Terminal umschalten", "workbench.action.terminal.kill": "Aktive Terminalinstanz beenden", "workbench.action.terminal.kill.short": "Terminal beenden", + "workbench.action.terminal.quickKill": "Terminalinstanz beenden", "workbench.action.terminal.copySelection": "Auswahl kopieren", "workbench.action.terminal.selectAll": "Alles auswƤhlen", + "workbench.action.terminal.deleteWordLeft": "Wort links lƶschen", + "workbench.action.terminal.deleteWordRight": "Wort rechts lƶschen", "workbench.action.terminal.new": "Neues integriertes Terminal erstellen", "workbench.action.terminal.new.short": "Neues Terminal", "workbench.action.terminal.focus": "Fokus im Terminal", "workbench.action.terminal.focusNext": "Fokus im nƤchsten Terminal", - "workbench.action.terminal.focusAtIndex": "Terminal {0} im Fokus", "workbench.action.terminal.focusPrevious": "Fokus im vorherigen Terminal", "workbench.action.terminal.paste": "In aktives Terminal einfügen", "workbench.action.terminal.DefaultShell": "Standardshell auswƤhlen", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "Umbenennen", "workbench.action.terminal.rename.prompt": "Terminalnamen eingeben", "workbench.action.terminal.focusFindWidget": "Widget zum Anzeigen der Suche mit Fokus", - "workbench.action.terminal.hideFindWidget": "Widget zum Ausblenden der Suche" + "workbench.action.terminal.hideFindWidget": "Widget zum Ausblenden der Suche", + "nextTerminalFindTerm": "NƤchsten Suchbegriff anzeigen", + "previousTerminalFindTerm": "Vorherigen Suchbegriff anzeigen", + "quickOpenTerm": "Aktives Terminal wechseln" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 9d4810761f2..76d17079ae8 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -6,5 +6,8 @@ { "terminal.background": "Die Hintergrundfarbe des Terminals, dies ermƶglicht eine unterschiedliche FƤrbung des Terminals im Panel.", "terminal.foreground": "Die Vordergrundfarbe des Terminal.", + "terminalCursor.foreground": "Die Vordergrundfarbe des Terminalcursors.", + "terminalCursor.background": "Die Hintergrundfarbe des Terminalcursors. Ermƶglicht das Anpassen der Farbe eines Zeichens, das von einem Blockcursor überdeckt wird.", + "terminal.selectionBackground": "Die Auswahlvordergrundfarbe des Terminals.", "terminal.ansiColor": "\"{0}\": ANSI-Farbe im Terminal" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 558f228c1f1..cf9ef31e248 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Kopieren", - "createNewTerminal": "Neues Terminal", "paste": "Einfügen", "selectAll": "Alles auswƤhlen", "clear": "Lƶschen" diff --git a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index e01f30f61a5..ac6f1dfc78c 100644 --- a/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OK, nicht mehr anzeigen", "terminal.integrated.chooseWindowsShell": "WƤhlen Sie Ihre bevorzugte Terminalshell. Sie kƶnnen diese spƤter in Ihren Einstellungen Ƥndern.", "terminalService.terminalCloseConfirmationSingular": "Eine aktive Terminalsitzung ist vorhanden. Mƶchten Sie sie beenden?", - "terminalService.terminalCloseConfirmationPlural": "{0} aktive Terminalsitzungen sind vorhanden. Mƶchten Sie sie beenden?", - "yes": "Ja" + "terminalService.terminalCloseConfirmationPlural": "{0} aktive Terminalsitzungen sind vorhanden. Mƶchten Sie sie beenden?" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json index f579c5cd19f..7c24ef226ba 100644 --- a/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,9 @@ "licenseChanged": "Unsere Lizenzbedingungen haben sich geƤndert. Bitte lesen Sie die neuen Bedingungen.", "license": "Lizenz lesen", "neveragain": "Nie wieder anzeigen", + "64bitisavailable": "{0} für 64-Bit-Windows ist jetzt verfügbar!", "learn more": "Weitere Informationen", + "updateIsReady": "Neues {0}-Update verfügbar.", "thereIsUpdateAvailable": "Ein Update ist verfügbar.", "updateAvailable": "{0} wird nach dem Neustart aktualisiert.", "noUpdatesAvailable": "Zurzeit sind keine Updates verfügbar.", diff --git a/i18n/deu/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/deu/src/vs/workbench/parts/views/browser/views.i18n.json index b7eb39e941e..17abacb1d8c 100644 --- a/i18n/deu/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/views/browser/views.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "viewToolbarAriaLabel": "{0}-Aktionen" + "viewToolbarAriaLabel": "{0}-Aktionen", + "hideView": "Auf Randleiste ausblenden" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json b/i18n/deu/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json index e7bf7cc8642..79702d24961 100644 --- a/i18n/deu/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json @@ -12,5 +12,6 @@ "vscode.extension.contributes.view.when": "Bedingung, die zum Anzeigen dieser Ansicht erfüllt sein muss", "vscode.extension.contributes.views": "TrƤgt Ansichten zum Editor bei.", "views.explorer": "Explorer-Ansicht", + "views.debug": "Debugansicht", "locationId.invalid": "{0}\" ist kein gültiger Ansichtenspeicherort" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 75f68335e05..c83506c4afe 100644 --- a/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "welcomePage.vscode": "Visual Studio Code", - "welcomePage.editingEvolved": "Fortschrittliche Bearbeitung", + "welcomePage.editingEvolved": "Editing evolved", "welcomePage.start": "Starten", "welcomePage.newFile": "Neue Datei", "welcomePage.openFolder": "Ordner ƶffnen...", - "welcomePage.cloneGitRepository": "Git-Repository klonen...", + "welcomePage.addWorkspaceFolder": "Arbeitsbereichsordner hinzufügen...", "welcomePage.recent": "Zuletzt verwendet", "welcomePage.moreRecent": "Weitere Informationen...", "welcomePage.noRecentFolders": "Keine kürzlich verwendeten Ordner", diff --git a/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json index 465e7168207..dfd27d2d8c3 100644 --- a/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json @@ -8,5 +8,6 @@ "workbench.startupEditor.none": "Ohne Editor starten.", "workbench.startupEditor.welcomePage": "Willkommensseite ƶffnen (Standard).", "workbench.startupEditor.newUntitledFile": "Eine neue unbenannte Datei ƶffnen.", + "workbench.startupEditor": "Steuert, welcher Editor beim Start angezeigt wird, sofern kein Editor aus der vorherigen Sitzung wiederhergestellt wird. WƤhlen Sie \"none\" zum Starten ohne Editor, \"welcomePage\" zum Ɩffnen der Startseite (Standard) oder \"newUntitledFile\" zum Ɩffnen einer neuen unbenannten Datei (nur beim Ɩffnen eines leeren Arbeitsbereichs).", "help": "Hilfe" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 99cd19e8bb5..ee2a9825fed 100644 --- a/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Azure-Erweiterungen anzeigen", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/deu/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/deu/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 080faf979f6..5f5cf83edf8 100644 --- a/i18n/deu/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "Interaktiver Playground", - "editorWalkThrough.title": "Interaktiver Playground" + "editorWalkThrough.title": "Interaktiver Playground", + "editorWalkThrough": "Interaktiver Playground" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/deu/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..ce08826d007 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Eine Zusammenfassung der Einstellungen. Diese Bezeichnung wird in der Einstellungsdatei als trennender Kommentar verwendet.", + "vscode.extension.contributes.configuration.properties": "Die Beschreibung der Konfigurationseigenschaften.", + "scope.window.description": "Fensterspezifische Konfiguration, die in den Benutzer- oder Arbeitsbereichseinstellungen konfiguriert werden kann.", + "scope.resource.description": "Ressourcenspezifische Konfiguration, die in den Benutzer-, Arbeitsbereichs- oder Ordnereinstellungen konfiguriert werden kann.", + "scope.description": "Bereich, in dem die Konfiguration gültig ist. Verfügbare Gültigkeitsbereiche sind \"window\" und \"resource\".", + "vscode.extension.contributes.configuration": "TrƤgt Konfigurationseigenschaften bei.", + "invalid.title": "configuration.title muss eine Zeichenfolge sein.", + "vscode.extension.contributes.defaultConfiguration": "TrƤgt zu Konfigurationeinstellungen des Standard-Editors für die jeweilige Sprache bei.", + "invalid.properties": "\"configuration.properties\" muss ein Objekt sein.", + "invalid.allOf": "\"configuration.allOf\" ist veraltet und sollte nicht mehr verwendet werden. Übergeben Sie stattdessen mehrere Konfigurationsabschnitte als Array an den Beitragspunkt \"configuration\".", + "workspaceConfig.folders.description": "Liste von Ordnern, die in den Arbeitsbereich geladen werden.", + "workspaceConfig.path.description": "Ein Dateipfad, z. B. \" /root/folderA\" oder \"./folderA\" bei einem relativen Pfad, der in Bezug auf den Speicherort der Arbeitsbereichsdatei aufgelƶst wird.", + "workspaceConfig.name.description": "Ein optionaler Name für den Ordner.", + "workspaceConfig.extensions.description": "Arbeitsbereichserweiterungen", + "unknownWorkspaceProperty": "Unbekannte Arbeitsbereichs-Konfigurationseigenschaft" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json index 57926d3c88c..d6a37d8334e 100644 --- a/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,11 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "TrƤgt Konfigurationseigenschaften bei.", "vscode.extension.contributes.configuration.title": "Eine Zusammenfassung der Einstellungen. Diese Bezeichnung wird in der Einstellungsdatei als trennender Kommentar verwendet.", "vscode.extension.contributes.configuration.properties": "Die Beschreibung der Konfigurationseigenschaften.", - "invalid.type": "Wenn eine Festlegung erfolgt, muss \"configuration.type\" auf \"object\" festgelegt werden.", + "scope.window.description": "Fensterspezifische Konfiguration, die in den Benutzer- oder Arbeitsbereichseinstellungen konfiguriert werden kann.", + "scope.resource.description": "Ressourcenspezifische Konfiguration, die in den Benutzer-, Arbeitsbereichs- oder Ordnereinstellungen konfiguriert werden kann.", + "scope.description": "Bereich, in dem die Konfiguration gültig ist. Verfügbare Gültigkeitsbereiche sind \"window\" und \"resource\".", + "vscode.extension.contributes.configuration": "TrƤgt Konfigurationseigenschaften bei.", "invalid.title": "configuration.title muss eine Zeichenfolge sein.", "vscode.extension.contributes.defaultConfiguration": "TrƤgt zu Konfigurationeinstellungen des Standard-Editors für die jeweilige Sprache bei.", - "invalid.properties": "\"configuration.properties\" muss ein Objekt sein." + "invalid.properties": "\"configuration.properties\" muss ein Objekt sein.", + "invalid.allOf": "\"configuration.allOf\" ist veraltet und sollte nicht mehr verwendet werden. Übergeben Sie stattdessen mehrere Konfigurationsabschnitte als Array an den Beitragspunkt \"configuration\".", + "workspaceConfig.folders.description": "Liste von Ordnern, die in den Arbeitsbereich geladen werden.", + "workspaceConfig.path.description": "Ein Dateipfad, z. B. \" /root/folderA\" oder \"./folderA\" bei einem relativen Pfad, der in Bezug auf den Speicherort der Arbeitsbereichsdatei aufgelƶst wird.", + "workspaceConfig.name.description": "Ein optionaler Name für den Ordner.", + "workspaceConfig.uri.description": "URI des Ordners", + "workspaceConfig.settings.description": "Arbeitsbereichseinstellungen", + "workspaceConfig.extensions.description": "Arbeitsbereichserweiterungen", + "unknownWorkspaceProperty": "Unbekannte Arbeitsbereichs-Konfigurationseigenschaft" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/deu/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index d1f34002c59..2420a104c15 100644 --- a/i18n/deu/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/deu/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Einstellungen ƶffnen", + "openTasksConfiguration": "Aufgabenkonfiguration ƶffnen", + "openLaunchConfiguration": "Startkonfiguration ƶffnen", "close": "Schließen", - "saveAndRetry": "Ƅnderungen Speichern und Wiederholen", - "errorInvalidConfiguration": "In die Einstellungen kann nicht geschrieben werden. Ɩffnen Sie **Benutzereinstellungen**, um Fehler/Warnungen in der Datei zu korrigieren, und versuchen Sie es noch mal.", - "errorInvalidConfigurationWorkspace": "In die Einstellungen kann nicht geschrieben werden. Ɩffnen Sie die **Arbeitsbereichseinstellungen**, um Fehler/Warnungen in der Datei zu korrigieren, und versuchen Sie es noch mal.", - "errorConfigurationFileDirty": "In die Einstellungen kann nicht geschrieben werden, weil die Datei geƤndert wurde. Speichern Sie die Datei **Benutzereinstellungen**, und versuchen Sie es noch mal.", - "errorConfigurationFileDirtyWorkspace": "In die Einstellungen kann nicht geschrieben werden, weil die Datei geƤndert wurde. Speichern Sie die Datei **Arbeitsbereichseinstellungen**, und versuchen Sie es noch mal.", + "open": "Einstellungen ƶffnen", + "saveAndRetry": "Speichern und wiederholen", + "errorUnknownKey": "In {0} kann nicht geschrieben werden, weil {1} keine registrierte Konfiguration ist.", + "errorInvalidFolderConfiguration": "In die Ordnereinstellungen kann nicht geschrieben werden, weil {0} den Gültigkeitsbereich für Ordnerressourcen nicht unterstützt.", + "errorInvalidUserTarget": "In die Benutzereinstellungen kann nicht geschrieben werden, weil {0} den globalen Gültigkeitsbereich nicht unterstützt.", + "errorInvalidFolderTarget": "In die Ordnereinstellungen kann nicht geschrieben werden, weil keine Ressource angegeben ist.", + "errorNoWorkspaceOpened": "In {0} kann nicht geschrieben werden, weil kein Arbeitsbereich geƶffnet ist. Ɩffnen Sie zuerst einen Arbeitsbereich, und versuchen Sie es noch mal.", + "errorInvalidTaskConfiguration": "In die Aufgabendatei kann nicht geschrieben werden. Ɩffnen Sie die Datei **Aufgaben**, um Fehler/Warnungen darin zu beheben, und versuchen Sie es noch mal.", + "errorInvalidLaunchConfiguration": "In die Startdatei kann nicht geschrieben werden. Ɩffnen Sie die Datei **Starten**, um Fehler/Warnungen in der Datei zu beheben, und versuchen Sie es noch mal.", + "errorInvalidConfiguration": "In die Benutzereinstellungen kann nicht geschrieben werden. Ɩffnen Sie die Datei **Benutzereinstellungen**, um Fehler/Warnungen darin zu korrigieren, und versuchen Sie es noch mal.", + "errorInvalidConfigurationWorkspace": "In die Arbeitsbereichseinstellungen kann nicht geschrieben werden. Ɩffnen Sie die Datei **Arbeitsbereichseinstellungen**, um Fehler/Warnungen darin zu korrigieren, und versuchen Sie es noch mal.", + "errorInvalidConfigurationFolder": "In die Ordnereinstellungen kann nicht geschrieben werden. Ɩffnen Sie die Datei **Ordnereinstellungen** unter **{0}**, um Fehler/Warnungen darin zu korrigieren, und versuchen Sie es noch mal.", + "errorTasksConfigurationFileDirty": "In die Aufgabendatei kann nicht geschrieben werden, da sie geƤndert wurde. Speichern Sie die Datei **Aufgabenkonfiguration**, und versuchen Sie es noch mal.", + "errorLaunchConfigurationFileDirty": "In die Startdatei kann nicht geschrieben werden, da sie geƤndert wurde. Speichern Sie die Datei **Startkonfiguration**, und versuchen Sie es noch mal.", + "errorConfigurationFileDirty": "In die Einstellungen kann nicht geschrieben werden, da die Datei geƤndert wurde. Speichern Sie die Datei **Benutzereinstellungen**, und versuchen Sie es noch mal.", + "errorConfigurationFileDirtyWorkspace": "In die Arbeitsbereichseinstellungen kann nicht geschrieben werden, da die Datei geƤndert wurde. Speichern Sie die Datei **Arbeitsbereichseinstellungen**, und versuchen Sie es noch mal.", + "errorConfigurationFileDirtyFolder": "In die Ordnereinstellungen kann nicht geschrieben werden, da die Datei geƤndert wurde. Speichern Sie die Datei **Ordnereinstellungen** unter **{0}**, und versuchen Sie es noch mal.", "userTarget": "Benutzereinstellungen", - "workspaceTarget": "Arbeitsbereichseinstellungen" + "workspaceTarget": "Arbeitsbereichseinstellungen", + "folderTarget": "Ordnereinstellungen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json b/i18n/deu/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json index 8b6ad71cd4e..789de4230c1 100644 --- a/i18n/deu/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json +++ b/i18n/deu/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "errorInvalidFile": "In die Datei kann nicht geschrieben werden. Ɩffnen Sie die Datei, um Fehler/Warnungen in der Datei zu beheben, und versuchen Sie es noch mal.", + "errorFileDirty": "In die Datei kann nicht geschrieben werden, weil sie geƤndert wurde. Speichern Sie die Datei, und versuchen Sie es noch mal." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/deu/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/deu/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..19669518abf --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "Der Erweiterungshost wurde nicht innerhalb von 10 Sekunden gestartet. Mƶglicherweise wurde er in der ersten Zeile beendet und benƶtigt einen Debugger, um die Ausführung fortzusetzen.", + "extensionHostProcess.startupFail": "Der Erweiterungshost wurde nicht innerhalb von 10 Sekunden gestartet. Dies stellt ggf. ein Problem dar.", + "extensionHostProcess.error": "Fehler vom Erweiterungshost: {0}" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..fc6d616a745 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "Fehler beim Analysieren von {0}: {1}.", + "fileReadFail": "Die Datei \"{0}\" kann nicht gelesen werden: {1}", + "jsonsParseFail": "Fehler beim Analysieren von {0} oder {1}: {2}.", + "missingNLSKey": "Die Nachricht für den Schlüssel {0} wurde nicht gefunden." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..9dfb4d17cca --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "Entwicklertools", + "restart": "Erweiterungshost neu starten", + "extensionHostProcess.crash": "Der Erweiterungshost wurde unerwartet beendet.", + "extensionHostProcess.unresponsiveCrash": "Der Erweiterungshost wurde beendet, weil er nicht reagiert hat.", + "overwritingExtension": "Die Erweiterung \"{0}\" wird mit \"{1}\" überschrieben.", + "extensionUnderDevelopment": "Die Entwicklungserweiterung unter \"{0}\" wird geladen." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/deu/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..ed6cda9de2a --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Die Datei scheint eine BinƤrdatei zu sein und kann nicht als Text geƶffnet werden." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/deu/src/vs/workbench/services/files/node/fileService.i18n.json index 43bafc03826..82912560d86 100644 --- a/i18n/deu/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/deu/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "Ungültige Dateiressource ({0})", - "fileIsDirectoryError": "Die Datei ist ein Verzeichnis ({0}).", + "fileIsDirectoryError": "Die Datei ist ein Verzeichnis", "fileNotModifiedError": "Datei nicht geƤndert seit", "fileTooLargeError": "Die Datei ist zu groß, um sie zu ƶffnen.", "fileBinaryError": "Die Datei scheint eine BinƤrdatei zu sein und kann nicht als Text geƶffnet werden.", "fileNotFoundError": "Die Datei wurde nicht gefunden ({0}).", + "fileExists": "Die zu erstellende Datei ist bereits vorhanden ({0}). ", "fileMoveConflict": "Verschieben/Kopieren kann nicht ausgeführt werden. Die Datei ist am Ziel bereits vorhanden.", "unableToMoveCopyError": "Der Verschiebe-/Kopiervorgang kann nicht ausgeführt werden. Die Datei würde den Ordner ersetzen, in dem sie enthalten ist.", "foldersCopyError": "Ordner kƶnnen nicht in den Arbeitsbereich kopiert werden. Bitte wƤhlen Sie einzelne Dateien aus, um sie zu kopieren.", diff --git a/i18n/deu/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/deu/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/deu/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/deu/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index e8f5434b0d7..d13ca944626 100644 --- a/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/deu/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "Schriftschnitt der Regel: kursiv, fett und unterstrichen (einzeln oder in Kombination)", - "schema.colors": "Farben für die Syntaxhervorhebung", - "schema.properties.name": "Beschreibung der Regel", - "schema.tokenColors.path": "Pfad zu einer tmTheme-Designdatei (relativ zur aktuellen Datei)" + "schema.token.settings": "Farben und Stile für das Token.", + "schema.token.foreground": "Vordergrundfarbe für das Token.", + "schema.token.background.warning": "Token Hintergrundfarben werden derzeit nicht unterstützt.", + "schema.token.fontStyle": "Schriftschnitt der Regel: kursiv, fett und unterstrichen (einzeln oder in Kombination)", + "schema.fontStyle.error": "Der Schriftschnitt muss eine Kombination aus \"kursiv\", \"fett\" und \"unterstrichen\" sein.", + "schema.properties.name": "Beschreibung der Regel.", + "schema.properties.scope": "Bereichsauswahl, mit der diese Regel einen Abgleich ausführt.", + "schema.tokenColors.path": "Pfad zu einer tmTheme-Designdatei (relativ zur aktuellen Datei).", + "schema.colors": "Farben für die Syntaxhervorhebung" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 86353589189..cce0737bd42 100644 --- a/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/deu/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Wenn eine Schriftart verwendet wird: der Schriftgrad als Prozentsatz der Textschriftart. Wenn diese Angabe nicht festgelegt wird, wird standardmäßig die Größe in der Schriftartdefinition verwendet.", "schema.fontId": "Bei Verwendung einer Schriftart: die ID der Schriftart. Wenn diese Angabe nicht festgelegt wird, wird standardmäßig die erste Schriftartdefinition verwendet.", "schema.light": "Optionale Zuordnungen für Dateisymbole in hellen Farbdesigns.", - "schema.highContrast": "Optionale Zuordnungen für Dateisymbole in Farbdesigns mit hohem Kontrast." + "schema.highContrast": "Optionale Zuordnungen für Dateisymbole in Farbdesigns mit hohem Kontrast.", + "schema.hidesExplorerArrows": "Konfiguriert, ob die Datei-Explorer Pfeile ausgeblendet werden sollen, wenn dieses Motiv aktiv ist." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 2d04a1d985b..5c396ea44d1 100644 --- a/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "Probleme beim Analysieren der JSON-Designdatei: {0}", "error.invalidformat.colors": "Probleme beim Analysieren der Farbdesigndatei: {0}. Die Eigenschaft \"colors\" ist nicht vom Typ \"object\".", - "error.invalidformat.tokenColors": "Probleme beim Analysieren der Farbdesigndatei: {0}. Die Eigenschaft \"tokenColors\" muss entweder ein Array sein, das Farben angibt, oder ein Pfad zu einer TextMate-Designdatei.", + "error.invalidformat.tokenColors": "Problem beim Analysieren der Farbdesigndatei: {0}. Die Eigenschaft \"tokenColors\" muss entweder ein Array sein, das Farben festlegt, oder ein Pfad zu einer TextMate-Designdatei.", "error.plist.invalidformat": "Probleme beim Analysieren der tmTheme-Designdatei: {0}. \"settings\" ist kein Array", "error.cannotparse": "Probleme beim Analysieren der tmTheme-Designdatei: {0}", "error.cannotload": "Probleme beim Laden der tmTheme-Designdatei {0}: {1}" diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..667f131a465 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", + "vscode.extension.contributes.themes.label": "Die Bezeichnung des Farbdesigns wie in der BenutzeroberflƤche angezeigt.", + "vscode.extension.contributes.themes.uiTheme": "Das Basisdesign, das die Farben um den Editor definiert: \"vs\" ist das helle Farbdesign, \"vs-dark\" das dunkle Farbdesign. \"hc-black\" ist das dunkle Design mit hohem Kontrast.", + "vscode.extension.contributes.themes.path": "Der Pfad der TMTHEME-Datei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./themes/themeFile.tmTheme\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Expected string in `contributes.{0}.path`. Provided value: {1}", + "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Erweiterung enthalten ist. Dies führt ggf. dazu, dass die Erweiterung nicht portierbar ist." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..65109048ac5 --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", + "vscode.extension.contributes.iconThemes.label": "Die Bezeichnung des Symboldesigns wie in der BenutzeroberflƤche angezeigt.", + "vscode.extension.contributes.iconThemes.path": "Der Pfad der Symboldesign-Definitionsdatei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./icons/awesome-icon-theme.json\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Expected string in `contributes.{0}.path`. Provided value: {1}", + "reqid": "In \"contributes.{0}.id\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", + "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Erweiterung enthalten ist. Dies führt ggf. dazu, dass die Erweiterung nicht portierbar ist." +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 374e2c223ed..d551e506d69 100644 --- a/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/deu/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,29 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", - "vscode.extension.contributes.themes.label": "Die Bezeichnung des Farbdesigns wie in der BenutzeroberflƤche angezeigt.", - "vscode.extension.contributes.themes.uiTheme": "Das Basisdesign, das die Farben um den Editor definiert: \"vs\" ist das helle Farbdesign, \"vs-dark\" das dunkle Farbdesign. \"hc-black\" ist das dunkle Design mit hohem Kontrast.", - "vscode.extension.contributes.themes.path": "Der Pfad der TMTHEME-Datei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./themes/themeFile.tmTheme\".", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "Die ID des Symboldesigns wie in den Benutzereinstellungen verwendet.", - "vscode.extension.contributes.iconThemes.label": "Die Bezeichnung des Symboldesigns wie in der BenutzeroberflƤche angezeigt.", - "vscode.extension.contributes.iconThemes.path": "Der Pfad der Symboldesign-Definitionsdatei. Der Pfad ist relativ zum Erweiterungsordner und lautet normalerweise \"./icons/awesome-icon-theme.json\".", "migration.completed": "Den Benutzereinstellungen wurden neue Designeinstellungen hinzugefügt. Sicherung verfügbar unter {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "In \"contributes.{0}.path\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", - "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Erweiterung enthalten ist. Dies führt ggf. dazu, dass die Erweiterung nicht portierbar ist.", - "reqid": "In \"contributes.{0}.id\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Gibt das in der Workbench verwendete Symboldesign oder \"null\", um keine Dateisymbole anzuzeigen, an.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Überschreibt Farben aus dem derzeit ausgewƤhlte Farbdesign.", - "workbenchColors.deprecated": "Diese Einstellung ist nicht mehr experimentell und wurde in \"workbench.colorCustomizations\" umbenannt.", - "workbenchColors.deprecatedDescription": "Verwenden Sie stattdessen \"workbench.colorCustomizations\"." + "editorColors": "Überschreibt Editorfarben und den Schriftschnitt aus dem momentan ausgewƤhlten Farbdesign.", + "editorColors.comments": "Legt die Farben und Stile für Kommentare fest.", + "editorColors.strings": "Legt die Farben und Stile für Zeichenfolgenliterale fest.", + "editorColors.keywords": "Legt die Farben und Stile für Schlüsselwƶrter fest.", + "editorColors.numbers": "Legt die Farben und Stile für Nummernliterale fest.", + "editorColors.types": "Legt die Farben und Stile für Typdeklarationen und Verweise fest.", + "editorColors.functions": "Legt die Farben und Stile für Funktionsdeklarationen und Verweise fest.", + "editorColors.variables": "Legt die Farben und Stile für Variablendeklarationen und Verweise fest.", + "editorColors.textMateRules": "Legt Farben und Stile mithilfe von Textmate-Designregeln fest (erweitert)." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/deu/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..85f4c3818ed --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "openWorkspaceConfigurationFile": "Konfigurationsdatei des Arbeitsbereichs ƶffnen", + "close": "Schließen", + "enterWorkspace.close": "Schließen", + "enterWorkspace.dontShowAgain": "Nicht mehr anzeigen", + "enterWorkspace.moreInfo": "Weitere Informationen" +} \ No newline at end of file diff --git a/i18n/esn/extensions/azure-account/out/azure-account.i18n.json b/i18n/esn/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..787c5816b1d --- /dev/null +++ b/i18n/esn/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "Copiar y abrir", + "azure-account.close": "Cerrar", + "azure-account.login": "Iniciar sesión", + "azure-account.loginFirst": "No ha iniciado sesión, inicie sesión primero.", + "azure-account.userCodeFailed": "Error adquiriendo el código de usuario", + "azure-account.tokenFailed": "Adquiriendo token con el código de dispositivo", + "azure-account.tokenFromRefreshTokenFailed": "Adquiriendo token con token de actualización" +} \ No newline at end of file diff --git a/i18n/esn/extensions/azure-account/out/extension.i18n.json b/i18n/esn/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..33e171e85c5 --- /dev/null +++ b/i18n/esn/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: Iniciando sesión...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 6f2a10e46de..0fea08772ca 100644 --- a/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/esn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "p. ej. myFile.txt", - "activeEditorMedium": "e.g. myFolder/myFile.txt", - "activeEditorLong": "e.g. /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "p. ej. myFolder1, myFolder2, myFolder3", - "rootPath": "p. ej. /Users/Development/myProject", - "folderName": "p. ej. myFolder", - "folderPath": "p. ej. /Users/Development/myFolder", + "activeEditorShort": "el nombre del archivo (por ejemplo miarchivo.txt)", + "activeEditorMedium": "la ruta de acceso del archivo relativa a la carpeta del espacio de trabajo (p. ej. miCarpeta/miArchivo.txt)", + "activeEditorLong": "la ruta de acceso completa del archivo (por ejemplo, /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nombre del Ć”rea de trabajo (p. ej. myFolder o myWorkspace)", + "rootPath": "ruta del archivo del Ć”rea de trabajo (p. ej. /Users/Development/myWorkspace)", + "folderName": "nombre de la carpeta del Ć”rea de trabajo en la que el archivo estĆ” contenido (p. ej. myFolder)", + "folderPath": "ruta de acceso de archivo de la carpeta del Ć”rea de trabajo en la que el archivo estĆ” contenido (p. ej. /Users/Development/myFolder)", "appName": "p. ej. VS Code", "dirty": "un indicador con modificaciones si el editor activo tiene modificaciones", "separator": "un separador condicional (\"-\") que aparece solo cuando estĆ” rodeado de variables con valores", diff --git a/i18n/esn/extensions/css/package.i18n.json b/i18n/esn/extensions/css/package.i18n.json index 7a5a71fe55c..3dd3dce11b7 100644 --- a/i18n/esn/extensions/css/package.i18n.json +++ b/i18n/esn/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "NĆŗmero de parĆ”metros no vĆ”lido", "css.lint.boxModel.desc": "No use ancho o alto con el relleno o los bordes.", "css.lint.compatibleVendorPrefixes.desc": "Cuando use un prefijo especĆ­fico del proveedor, compruebe que tambiĆ©n haya incluido el resto de propiedades especĆ­ficas del proveedor.", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "Propiedad especĆ­fica del proveedor desconocida.", "css.lint.vendorPrefix.desc": "Cuando use un prefijo especĆ­fico del proveedor, incluya tambiĆ©n la propiedad estĆ”ndar.", "css.lint.zeroUnits.desc": "No se necesita una unidad para cero", + "css.trace.server.desc": "Hace un seguimiento de la comunicación entre VSCode y el servidor de lenguaje CSS.", + "css.validate.title": "Controla la validación de CSS y la gravedad de los problemas.", "css.validate.desc": "Habilita o deshabilita todas las validaciones", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "NĆŗmero de parĆ”metros no vĆ”lido", "less.lint.boxModel.desc": "No use ancho o alto con el relleno o los bordes.", "less.lint.compatibleVendorPrefixes.desc": "Cuando use un prefijo especĆ­fico del proveedor, compruebe que tambiĆ©n haya incluido el resto de propiedades especĆ­ficas del proveedor.", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "Propiedad especĆ­fica del proveedor desconocida.", "less.lint.vendorPrefix.desc": "Cuando use un prefijo especĆ­fico del proveedor, incluya tambiĆ©n la propiedad estĆ”ndar.", "less.lint.zeroUnits.desc": "No se necesita una unidad para cero", + "less.validate.title": "Controla la validación de LESS y la gravedad de los problemas.", "less.validate.desc": "Habilita o deshabilita todas las validaciones", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "NĆŗmero de parĆ”metros no vĆ”lido", "scss.lint.boxModel.desc": "No use ancho o alto con el relleno o los bordes.", "scss.lint.compatibleVendorPrefixes.desc": "Cuando use un prefijo especĆ­fico del proveedor, compruebe que tambiĆ©n haya incluido el resto de propiedades especĆ­ficas del proveedor.", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "Propiedad especĆ­fica del proveedor desconocida.", "scss.lint.vendorPrefix.desc": "Cuando use un prefijo especĆ­fico del proveedor, incluya tambiĆ©n la propiedad estĆ”ndar.", "scss.lint.zeroUnits.desc": "No se necesita una unidad para cero", + "scss.validate.title": "Controla la validación de SCSS y la gravedad de los problemas.", "scss.validate.desc": "Habilita o deshabilita todas las validaciones", "less.colorDecorators.enable.desc": "Habilita o deshabilita decoradores de color", "scss.colorDecorators.enable.desc": "Habilita o deshabilita decoradores de color", - "css.colorDecorators.enable.desc": "Habilita o deshabilita decoradores de color" + "css.colorDecorators.enable.desc": "Habilita o deshabilita decoradores de color", + "css.colorDecorators.enable.deprecationMessage": "El valor \"css.colorDecorators.enable\" estĆ” en desuso en favor de \"editor.colorDecorators\".", + "scss.colorDecorators.enable.deprecationMessage": "El valor \"scss.colorDecorators.enable\" estĆ” en desuso en favor de \"editor.colorDecorators\".", + "less.colorDecorators.enable.deprecationMessage": "El valor \"less.colorDecorators.enable\" estĆ” en desuso en favor de \"editor.colorDecorators\"." } \ No newline at end of file diff --git a/i18n/esn/extensions/emmet/package.i18n.json b/i18n/esn/extensions/emmet/package.i18n.json index 26c61c87280..5f790214764 100644 --- a/i18n/esn/extensions/emmet/package.i18n.json +++ b/i18n/esn/extensions/emmet/package.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "Encapsular con abreviatura", + "command.wrapIndividualLinesWithAbbreviation": "Encapsular las lĆ­neas individuales con abreviatura", "command.removeTag": "Quitar etiqueta", "command.updateTag": "Actualizar etiqueta", "command.matchTag": "Ir al par coincidente", @@ -24,5 +26,28 @@ "command.incrementNumberByOneTenth": "Aumentar por 0.1", "command.decrementNumberByOneTenth": "Disminuir por 0.1", "command.incrementNumberByTen": "Aumentar por 10", - "command.decrementNumberByTen": "Disminuir por 10" + "command.decrementNumberByTen": "Disminuir por 10", + "emmetSyntaxProfiles": "Defina el perfil de la sintaxis especificada o use su propio perfil con reglas especĆ­ficas.", + "emmetExclude": "Una serie de idiomas donde no deben ampliar las abreviaturas de Emmet.", + "emmetExtensionsPath": "Ruta de acceso a una carpeta que contiene los perfiles y fragmentos de Emmet.", + "emmetShowExpandedAbbreviation": "Muestra abreviaciones Emmet expandidas como sugerencias. La opción \"inMarkupAndStylesheetFilesOnly\" se aplica a HTML, HAML, Jade, Slim, XML, XSL, CSS, SCSS, SASS, LESS y Stylus. La opción \"always\" se aplica a todas las partes del archivo, independientemente de que sea de marcado o CSS. ", + "emmetShowAbbreviationSuggestions": "Muestra posibles abreviaciones Emmet como sugerencias. No se aplica a hojas de estilos ni cuando emmet.showExpandedAbbreviation estĆ” establecido en \"never\". ", + "emmetIncludeLanguages": "Habilita abreviaciones Emmet en lenguajes que no se admiten de forma predeterminada. Agregue una asignación aquĆ­ entre el lenguaje y el lenguaje que admite Emmet. Ejemplo: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"} ", + "emmetVariables": "Variables para ser utilizadas en fragmentos de código de Emmet", + "emmetTriggerExpansionOnTab": "Cuando se habilita, se expande la abreviación Emmet al presionar la tecla TAB. ", + "emmetPreferences": "Preferencias usadas para modificar el comportamiento de algunas acciones y resoluciones de Emmet.", + "emmetPreferencesIntUnit": "Unidad predeterminada para valores enteros", + "emmetPreferencesFloatUnit": "Unidad predeterminada para valores float", + "emmetPreferencesCssAfter": "SĆ­mbolo que debe colocarse al final de una propiedad CSS cuando se expanden abreviaturas CSS", + "emmetPreferencesSassAfter": "SĆ­mbolo que debe colocarse al final de una propiedad CSS cuando se expanden abreviaturas CSS en archivos SASS", + "emmetPreferencesStylusAfter": "SĆ­mbolo que debe colocarse al final de una propiedad CSS cuando se expanden abreviaturas CSS en archivos Stylus", + "emmetPreferencesCssBetween": "SĆ­mbolo que debe colocarse entre una propiedad CSS y un valor cuando se expanden abreviaturas CSS", + "emmetPreferencesSassBetween": "SĆ­mbolo que debe colocarse entre una propiedad CSS y un valor cuando se expanden abreviaturas CSS en archivos SASS", + "emmetPreferencesStylusBetween": "SĆ­mbolo que debe colocarse entre una propiedad CSS y un valor cuando se expanden abreviaturas CSS en archivos Stylus", + "emmetShowSuggestionsAsSnippets": "Si es \"true\", las sugerencias Emmet se muestran como fragmentos de código, de modo que puede ordenarlas por el valor editor.snippetSuggestions. ", + "emmetPreferencesBemElementSeparator": "Separador de elemento utilizado para las clases cuando se utiliza el filtro BEM", + "emmetPreferencesBemModifierSeparator": "Separador de modificador utilizado para las clases cuando se utiliza el filtro BEM", + "emmetPreferencesFilterCommentBefore": "Una definición de comentario que debe ser colocado antes de elemento emparejado cuando se aplica el filtro de comentarios.", + "emmetPreferencesFilterCommentAfter": "Una definición de comentario que debe colocarse despuĆ©s de elemento emparejado cuando se aplica el filtro de comentarios.", + "emmetPreferencesFilterCommentTrigger": "Una lista separada por comas de nombres de atributos que debe existir en la abreviatura para el filtro de comentarios ser aplicado" } \ No newline at end of file diff --git a/i18n/esn/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/esn/extensions/extension-editing/out/extensionLinter.i18n.json index 4a97190b0ee..085b3559502 100644 --- a/i18n/esn/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/esn/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "Las imĆ”genes deben utilizar el protocolo HTTPS.", "svgsNotValid": "Los SVG no son un origen de imagen vĆ”lido.", "embeddedSvgsNotValid": "Los SGV insertados no son un origen de imagen vĆ”lido.", - "dataUrlsNotValid": "Las direcciones URL de datos no son un origen de imagen vĆ”lido." + "dataUrlsNotValid": "Las direcciones URL de datos no son un origen de imagen vĆ”lido.", + "relativeUrlRequiresHttpsRepository": "Las direcciones URL relativas de imĆ”genes requieren un repositorio con el protocolo HTTPS especificado en el archivo package.json.", + "relativeIconUrlRequiresHttpsRepository": "Un icono requiere un repositorio con el protocolo HTTPS especificado en este archivo package.json.", + "relativeBadgeUrlRequiresHttpsRepository": "Las direcciones URL relativas de distintivos requieren un repositorio con el protocolo HTTPS especificado en este archivo package.json." } \ No newline at end of file diff --git a/i18n/esn/extensions/git/out/commands.i18n.json b/i18n/esn/extensions/git/out/commands.i18n.json index bd1bce4b2db..69862736c9d 100644 --- a/i18n/esn/extensions/git/out/commands.i18n.json +++ b/i18n/esn/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "Clonando el repositorio GIT...", "openrepo": "Abrir repositorio", "proposeopen": "ĀæDesea abrir el repositorio clonado?", + "init repo": "Inicializar el repositorio", + "create repo": "Inicializar el repositorio", + "are you sure": "Esto crearĆ” un repositorio Git en '{0}'. ĀæEstĆ” seguro de que desea continuar?", "HEAD not available": "La versión HEAD de '{0}' no estĆ” disponible.", + "confirm stage files with merge conflicts": "ĀæEstĆ” seguro de que quiere hacer una copia intermedia de {0} archivos con conflictos de fusión mediante combinación?", + "confirm stage file with merge conflicts": "ĀæEstĆ” seguro de que quiere hacer una copia intermedia de {0} con conflictos de fusión mediante combinación? ", + "yes": "SĆ­", "confirm revert": "ĀæEstĆ” seguro de que desea revertir los cambios seleccionados en {0}?", "revert": "Revertir cambios", + "discard": "Descartar cambios", + "confirm delete": "ĀæEstĆ” seguro que desea eliminar {0}?", + "delete file": "Eliminar archivo", "confirm discard": "ĀæEstĆ” seguro de que quiere descartar los cambios de {0}?", "confirm discard multiple": "ĀæEstĆ” seguro de que quiere descartar los cambios de {0} archivos?", - "discard": "Descartar cambios", - "confirm discard all": "ĀæEstĆ” seguro de que quiere descartar TODOS los cambios? Esta acción es irreversible.", - "discardAll": "Descartar cambios", + "warn untracked": "Ā”Esto ELIMINARƁ {0} archivos sin seguimiento!", + "confirm discard all single": "ĀæEstĆ” seguro de que quiere descartar los cambios de {0}?", + "confirm discard all": "ĀæEstĆ” seguro de que quiere descartar TODOS los cambios en {0} archivos?\nEsta acción es IRREVERSIBLE.\nSu espacio de trabajo actual SE PERDERƁ PARA SIEMPRE.", + "discardAll multiple": "Descartar un archivo", + "discardAll": "Descartar todos los archivos ({0})", + "confirm delete multiple": "ĀæEstĆ” seguro de que quiere ELIMINAR {0} archivos?", + "delete files": "Eliminar archivos", + "there are untracked files single": "El siguiente archivo sin seguimiento se ELIMINARƁ DEL DISCO si se descarta: {0}.", + "there are untracked files": "Hay {0} archivos sin seguimiento que se ELIMINARƁN DEL DISCO si se descartan.", + "confirm discard all 2": "{0}\n\nEsta acción es IRREVERSIBLE. Su espacio de trabajo actual SE PERDERƁ PARA SIEMPRE.", + "yes discard tracked": "Descartar un archivo con seguimiento", + "yes discard tracked multiple": "Descartar {0} archivos con seguimiento", "no staged changes": "No hay elementos almacenados provisionalmente.\n\nĀæDesea almacenar de forma provisional todos sus cambios y confirmarlos directamente?", - "yes": "SĆ­", "always": "Siempre", "no changes": "No hay cambios para confirmar.", "commit message": "Mensaje de confirmación", @@ -34,16 +51,25 @@ "delete branch": "Borrar rama...", "select a branch to merge from": "Seleccione una rama desde la que fusionar", "merge conflicts": "Hay conflictos de fusión. Resuelvalos antes de confirmar.", + "tag name": "Nombre de la etiqueta", + "provide tag name": "Por favor proporcione un nombre de etiqueta", + "tag message": "Mensaje", + "provide tag message": "Por favor, especifique un mensaje para anotar la etiqueta", "no remotes to pull": "El repositorio no tiene remotos configurados de los que extraer.", "pick remote pull repo": "Seleccione un origen remoto desde el que extraer la rama", "no remotes to push": "El repositorio no tiene remotos configurados en los que insertar.", + "push with tags success": "Insertado con etiquetas correctamente.", "nobranch": "Extraiga del repositorio una rama para insertar un remoto.", "pick remote": "Seleccionar un elemento remoto para publicar la rama '{0}':", "sync is unpredictable": "Esta acción insertarĆ” y extraerĆ” confirmaciones en '{0}'.", "ok": "Aceptar", "never again": "De acuerdo, no volver a mostrar este mensaje.", "no remotes to publish": "El repositorio no tiene remotos configurados en los que publicar.", - "disabled": "GIT estĆ” deshabilitado o no se admite en esta Ć”rea de trabajo", + "no changes stash": "No existen cambios para el guardado provisional.", + "provide stash message": "Opcionalmente, proporcionar un mensaje para el guardado provisional", + "stash message": "Mensaje para el guardado provisional", + "no stashes": "No hay cambios guardados provisionalmente para restaurar.", + "pick stash to pop": "Elija un cambio guardado provisionalmente para aplicarlo y quitarlo", "clean repo": "Limpie el Ć”rbol de trabajo del repositorio antes de la desprotección.", "cant push": " No puede ejecutar la solicitud de inserción remotamente. Solicite un Pull para integrar los cambios.", "git error details": "GIT: {0}", diff --git a/i18n/esn/extensions/git/out/model.i18n.json b/i18n/esn/extensions/git/out/model.i18n.json index f05f241d928..4fc1dc343c5 100644 --- a/i18n/esn/extensions/git/out/model.i18n.json +++ b/i18n/esn/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Abrir", - "merge changes": "Fusionar cambios mediante combinación", - "staged changes": "Cambios almacenados provisionalmente", - "changes": "Cambios", - "ok": "Aceptar", - "neveragain": "No volver a mostrar", - "huge": "El repositorio Git '{0}' contiene muchos cambios activos, solamente un subconjunto de las caracterĆ­sticas de Git serĆ”n habilitadas." + "no repositories": "No hay repositorios disponibles", + "pick repo": "Elija un repositorio" } \ No newline at end of file diff --git a/i18n/esn/extensions/git/out/repository.i18n.json b/i18n/esn/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..fc557b451ea --- /dev/null +++ b/i18n/esn/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "Abrir", + "index modified": "ƍndice modificado", + "modified": "Modificado", + "index added": "ƍndice agregado", + "index deleted": "ƍndice Eliminado", + "deleted": "Eliminado", + "index renamed": "Nombre de ƍndice Cambiado", + "index copied": "ƍndice copiado", + "untracked": "Sin seguimiento", + "ignored": "Omitido", + "both deleted": "Ambos eliminados", + "added by us": "Agregado por nosotros", + "deleted by them": "Eliminado por ellos", + "added by them": "Agregado por ellos", + "deleted by us": "Borrado por nosotros", + "both added": "Ambos aƱadidos", + "both modified": "Ambos modificados", + "commit": "Confirmar", + "merge changes": "Fusionar cambios mediante combinación", + "staged changes": "Cambios almacenados provisionalmente", + "changes": "Cambios", + "ok": "Aceptar", + "neveragain": "No volver a mostrar", + "huge": "El repositorio Git '{0}' contiene muchos cambios activos, solamente un subconjunto de las caracterĆ­sticas de Git serĆ”n habilitadas." +} \ No newline at end of file diff --git a/i18n/esn/extensions/git/package.i18n.json b/i18n/esn/extensions/git/package.i18n.json index 859497d9753..928a2b6629e 100644 --- a/i18n/esn/extensions/git/package.i18n.json +++ b/i18n/esn/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "Clonar", "command.init": "Inicializar el repositorio", + "command.close": "Cerrar repositorio", "command.refresh": "Actualizar", "command.openChange": "Abrir cambios", "command.openFile": "Abrir archivo", @@ -14,6 +15,8 @@ "command.stageAll": "Almacenar todos los cambios", "command.stageSelectedRanges": "Realizar copia intermedia de los intervalos seleccionados", "command.revertSelectedRanges": "Revertir los intervalos seleccionados", + "command.stageChange": "Cambio de la etapa", + "command.revertChange": "Revertir el cambio", "command.unstage": "Cancelar almacenamiento provisional de los cambios", "command.unstageAll": "Cancelar almacenamiento provisional de todos los cambios", "command.unstageSelectedRanges": "Cancelar almacenamiento provisional de los intervalos seleccionados", @@ -22,22 +25,29 @@ "command.commit": "Confirmar", "command.commitStaged": "Confirmar almacenados provisionalmente", "command.commitStagedSigned": "Confirmar por etapas (Aprobado)", + "command.commitStagedAmend": "Confirmar almacenados provisionalmente (modificar)", "command.commitAll": "Confirmar todo", "command.commitAllSigned": "Confirmar todo (aprobado)", + "command.commitAllAmend": "Confirmar todo (modificar)", "command.undoCommit": "Deshacer Ćŗltima confirmación", "command.checkout": "Desproteger en...", "command.branch": "Crear rama...", "command.deleteBranch": "Borrar rama...", "command.merge": "Fusionar rama...", + "command.createTag": "Crear etiqueta", "command.pull": "Incorporación de cambios", "command.pullRebase": "Incorporación de cambios (fusionar mediante cambio de base)", "command.pullFrom": "Extraer de...", "command.push": "Insertar", "command.pushTo": "Insertar en...", + "command.pushWithTags": "Insertar con etiquetas", "command.sync": "Sincronizar", "command.publish": "Publicar rama", "command.showOutput": "Mostrar salida de GIT", "command.ignore": "Agregar archivo a .gitignore", + "command.stash": "Guardar provisionalmente", + "command.stashPop": "Aplicar y quitar cambios guardados provisionalmente...", + "command.stashPopLatest": "Aplicar y quitar Ćŗltimos cambios guardados provisionalmente...", "config.enabled": "Si GIT estĆ” habilitado", "config.path": "Ruta de acceso del ejecutable de GIT", "config.autorefresh": "Indica si la actualización automĆ”tica estĆ” habilitada", @@ -49,5 +59,12 @@ "config.ignoreLegacyWarning": "Ignora las advertencias hereradas de Git", "config.ignoreLimitWarning": "\nIgnora advertencias cuando se encuentran muchos cambios en un repositorio.", "config.defaultCloneDirectory": "La ubicación predeterminada en la que se clona un repositorio git", - "config.enableSmartCommit": "Confirmar todos los cambios cuando no hay elementos almacenados provisionalmente." + "config.enableSmartCommit": "Confirmar todos los cambios cuando no hay elementos almacenados provisionalmente.", + "config.enableCommitSigning": "Habilitar confirmar firma con GPG.", + "config.discardAllScope": "Controla quĆ© cambios son descartados por el comando 'Descartar todos los cambios'. 'all' descarta todos los cambios. 'tracked' descarta sólo los ficheros en seguimiento. 'prompt' muestra un cuadro de diĆ”logo para confirmar cada vez la acción ejecutada.", + "config.decorations.enabled": "Controla si Git contribuye los colores y distintivos al explorador y a los editores abiertos.", + "colors.modified": "Color para recursos modificados.", + "colors.untracked": "Color para los recursos a los que no se les hace seguimiento.", + "colors.ignored": "Color para los recursos ignorados.", + "colors.conflict": "Color para los recursos con conflictos." } \ No newline at end of file diff --git a/i18n/esn/extensions/grunt/out/main.i18n.json b/i18n/esn/extensions/grunt/out/main.i18n.json index fe2555e3d9a..a7fba536c38 100644 --- a/i18n/esn/extensions/grunt/out/main.i18n.json +++ b/i18n/esn/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "La autodetección de Grunt falló con el error: {0}" + "execFailed": "La detección automĆ”tica de Grunt para la carpeta {0} falló con el error: {1}" } \ No newline at end of file diff --git a/i18n/esn/extensions/gulp/out/main.i18n.json b/i18n/esn/extensions/gulp/out/main.i18n.json index 619a5f5a553..88f0fd24af4 100644 --- a/i18n/esn/extensions/gulp/out/main.i18n.json +++ b/i18n/esn/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Detección automĆ”tica gulp Error {0}" + "execFailed": "La detección automĆ”tica de gulp para la carpeta {0} falló con el error: {1}" } \ No newline at end of file diff --git a/i18n/esn/extensions/html/package.i18n.json b/i18n/esn/extensions/html/package.i18n.json index ef2f1f348b3..cdb66142db9 100644 --- a/i18n/esn/extensions/html/package.i18n.json +++ b/i18n/esn/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "Habilitar/deshabilitar formateador HTML predeterminado (requiere reiniciar)", + "html.format.enable.desc": "Habilitar o deshabilitar el formateador HTML predeterminado", "html.format.wrapLineLength.desc": "Cantidad mĆ”xima de caracteres por lĆ­nea (0 = deshabilitar).", "html.format.unformatted.desc": "Lista de etiquetas, separadas por comas, a las que no se debe volver a aplicar formato. El valor predeterminado de \"null\" son todas las etiquetas mostradas en https://www.w3.org/TR/html5/dom.html#phrasing-content.", "html.format.contentUnformatted.desc": "Lista de etiquetas, separadas por comas, en las que el contenido no debe volver a formatearse. \"null\" se establece de manera predeterminada en la etiqueta \"pre\".", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "Configura si la compatibilidad con el lenguaje HTML integrada sugiere etiquetas y propiedades de Angular V1.", "html.suggest.ionic.desc": "Configura si la compatibilidad con el lenguaje HTML integrada sugiere etiquetas, propiedades y valores de Ionic.", "html.suggest.html5.desc": "Configura si la compatibilidad con el lenguaje HTML integrada sugiere etiquetas, propiedades y valores de HTML5.", + "html.trace.server.desc": "Hace un seguimiento de la comunicación entre VSCode y el servidor de lenguaje HTML.", "html.validate.scripts": "Configura si la compatibilidad con el lenguaje HTML incorporado valida los scripts insertados.", - "html.validate.styles": "Configura si la compatibilidad con el lenguaje HTML incorporado valida los estilos insertados." + "html.validate.styles": "Configura si la compatibilidad con el lenguaje HTML incorporado valida los estilos insertados.", + "html.autoClosingTags": "Habilita o deshabilita el cierre automĆ”tico de las etiquetas HTML." } \ No newline at end of file diff --git a/i18n/esn/extensions/jake/out/main.i18n.json b/i18n/esn/extensions/jake/out/main.i18n.json index 1b387f27070..923e70b5173 100644 --- a/i18n/esn/extensions/jake/out/main.i18n.json +++ b/i18n/esn/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "La detección automĆ”tica de Jake falló con el error: {0}" + "execFailed": "La detección automĆ”tica de Jake para la carpeta {0} falló con el error: {1}" } \ No newline at end of file diff --git a/i18n/esn/extensions/json/package.i18n.json b/i18n/esn/extensions/json/package.i18n.json index e0edef4c42c..f73d2ce5578 100644 --- a/i18n/esn/extensions/json/package.i18n.json +++ b/i18n/esn/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "La definición de esquema de la dirección URL determinada. Solo se necesita proporcionar el esquema para evitar los accesos a la dirección URL del esquema.", "json.format.enable.desc": "Habilitar/deshabilitar formateador JSON predeterminado (requiere reiniciar)", "json.tracing.desc": "Seguimiento de comunicación entre VS Code y el servidor de lenguaje JSON", - "json.colorDecorators.enable.desc": "Habilita o deshabilita decoradores de color" + "json.colorDecorators.enable.desc": "Habilita o deshabilita decoradores de color", + "json.colorDecorators.enable.deprecationMessage": "El valor \"json.colorDecorators.enable\" estĆ” en desuso en favor de \"editor.colorDecorators\"." } \ No newline at end of file diff --git a/i18n/esn/extensions/markdown/out/extension.i18n.json b/i18n/esn/extensions/markdown/out/extension.i18n.json index 360f0b974b7..68d14e083b9 100644 --- a/i18n/esn/extensions/markdown/out/extension.i18n.json +++ b/i18n/esn/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "No se pudo cargar 'markdown.styles': {0}" + "onPreviewStyleLoadError": "No se pudo cargar 'markdown.styles': {0}", + "previewTitle": "Vista Previa {0}" } \ No newline at end of file diff --git a/i18n/esn/extensions/markdown/out/previewContentProvider.i18n.json b/i18n/esn/extensions/markdown/out/previewContentProvider.i18n.json index b84626f5793..dc058764af6 100644 --- a/i18n/esn/extensions/markdown/out/previewContentProvider.i18n.json +++ b/i18n/esn/extensions/markdown/out/previewContentProvider.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.securityMessage.text": "Parte del contenido ha sido deshabilitado en este documento", + "preview.securityMessage.text": "Se ha deshabilitado parte del contenido de este documento", "preview.securityMessage.title": "Se ha deshabilitado el contenido potencialmente inseguro en la previsualización de Markdown. Para permitir el contenido inseguro o habilitar scripts cambie la configuración de la previsualización de Markdown", "preview.securityMessage.label": "Alerta de seguridad de contenido deshabilitado" } \ No newline at end of file diff --git a/i18n/esn/extensions/markdown/out/security.i18n.json b/i18n/esn/extensions/markdown/out/security.i18n.json index ad9405c75c5..ec5482bbbf2 100644 --- a/i18n/esn/extensions/markdown/out/security.i18n.json +++ b/i18n/esn/extensions/markdown/out/security.i18n.json @@ -4,9 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.strictTitle": "Estricto. Solamente cargar contenido seguro.", - "preview.showPreviewSecuritySelector.currentSelection": "Configuración actual", - "preview.showPreviewSecuritySelector.insecureContentTitle": "Permite la carga de contenido mediante http.", - "preview.showPreviewSecuritySelector.scriptsAndAllContent": "Permitir todo el contenido y la ejecución de scripts. No se recomienda.", + "strict.title": "Estricto", + "strict.description": "Cargar solo el contenido seguro", + "insecureContent.title": "Permitir contenido inseguro", + "insecureContent.description": "Habilitar la carga del contenido sobre http", + "disable.title": "Deshabilitar", + "disable.description": "Permitir todo el contenido y la ejecución de scripts. No se recomienda.", + "moreInfo.title": "MĆ”s información", "preview.showPreviewSecuritySelector.title": "Seleccione configuración de seguridad para las previsualizaciones de Markdown en esta Ć”rea de trabajo" } \ No newline at end of file diff --git a/i18n/esn/extensions/markdown/package.i18n.json b/i18n/esn/extensions/markdown/package.i18n.json index 79557625b6c..5038437a133 100644 --- a/i18n/esn/extensions/markdown/package.i18n.json +++ b/i18n/esn/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "Establece cómo los saltos de lĆ­nea son representados en la vista previa de markdown. Estableciendolo en 'true' crea un
para cada nueva lĆ­nea.", + "markdown.preview.linkify": "Habilitar o deshabilitar la conversión de texto de tipo URL a enlaces en la vista previa de markdown.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Haga doble clic en la vista previa de Markdown para cambiar al editor.", "markdown.preview.fontFamily.desc": "Controla la familia de la fuente utilizada en la previsualización del descuento.", "markdown.preview.fontSize.desc": "Controla el tamaƱo de la fuente en pĆ­xeles utilizado en la previsualización del descuento.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "Abrir vista previa en el lateral", "markdown.showSource.title": "Mostrar origen", "markdown.styles.dec": "Una lista de direcciones URL o rutas de acceso locales a hojas de estilo CSS que utilizar desde la vista previa del descuento. Las tutas de acceso relativas se interpretan en relación con la carpeta abierta en el explorador. Si no hay ninguna carpeta abierta, se interpretan en relación con la ubicación del archivo del descuento. Todos los '\\' deben escribirse como '\\\\'.", - "markdown.showPreviewSecuritySelector.title": "Cambiar configuración de seguridad de vista previa de Markdown", - "markdown.trace.desc": "Habilitar registro de depuración para las extensiones de Markdown. " + "markdown.showPreviewSecuritySelector.title": "Cambiar configuración de seguridad de vista previa", + "markdown.trace.desc": "Habilitar registro de depuración para las extensiones de Markdown. ", + "markdown.refreshPreview.title": "Actualizar vista previa" } \ No newline at end of file diff --git a/i18n/esn/extensions/npm/out/main.i18n.json b/i18n/esn/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..941f83360df --- /dev/null +++ b/i18n/esn/extensions/npm/out/main.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "npm.parseError": "Detección de tareas de nueva gestión pĆŗblica: no se pudo analizar el archivo {0}" +} \ No newline at end of file diff --git a/i18n/esn/extensions/npm/package.i18n.json b/i18n/esn/extensions/npm/package.i18n.json index 51014f04757..6e3ba74bee2 100644 --- a/i18n/esn/extensions/npm/package.i18n.json +++ b/i18n/esn/extensions/npm/package.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "config.npm.autoDetect": "Controla si la detección automĆ”tica de scripts npm estĆ” activada o desactivada. Por defecto estĆ” activada.", - "config.npm.runSilent": "Ejecutar comandos de npm con la opción '--silent' " + "config.npm.runSilent": "Ejecutar comandos de npm con la opción '--silent' ", + "npm.parseError": "Detección de tareas de nueva gestión pĆŗblica: no se pudo analizar el archivo {0}" } \ No newline at end of file diff --git a/i18n/esn/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/esn/extensions/typescript/out/features/taskProvider.i18n.json index d2bd585c5ca..8ea3d44c659 100644 --- a/i18n/esn/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/esn/extensions/typescript/out/features/taskProvider.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "buildAndWatchTscLabel": "seguir - {0}", - "buildTscLabel": "construir - {0}" + "buildTscLabel": "construir - {0}", + "buildAndWatchTscLabel": "seguir - {0}" } \ No newline at end of file diff --git a/i18n/esn/extensions/typescript/out/utils/api.i18n.json b/i18n/esn/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..dbd035ca7a7 --- /dev/null +++ b/i18n/esn/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "versión invĆ”lida" +} \ No newline at end of file diff --git a/i18n/esn/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/esn/extensions/typescript/out/utils/versionPicker.i18n.json index d8a5be9b3bf..ad50dfc9605 100644 --- a/i18n/esn/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/esn/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "Usar versión de VSCode", + "useVSCodeVersionOption": "Utilizar la versión de VS Code", "useWorkspaceVersionOption": "Usar versión del Ć”rea de trabajo", "learnMore": "MĆ”s información", "selectTsVersion": "Seleccionar la versión de TypeScript usada para las caracterĆ­sticas del lenguaje de JavaScript y TypeScript" diff --git a/i18n/esn/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/esn/extensions/typescript/out/utils/versionProvider.i18n.json index 55bac23eb3c..1b370b81201 100644 --- a/i18n/esn/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/esn/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "Otra aplicación (por ejemplo, una herramienta de detección de virus con un comportamiento erróneo) eliminó el tsserver de VSCode. Debe reinstalar VS Code." + "couldNotLoadTsVersion": "No se pudo cargar la versión de TypeScript en esta ruta", + "noBundledServerFound": "Otra aplicación (por ejemplo, una herramienta de detección de virus con un comportamiento erróneo) eliminó el tsserver de VSCode. Debe reinstalar el VS Code." } \ No newline at end of file diff --git a/i18n/esn/extensions/typescript/package.i18n.json b/i18n/esn/extensions/typescript/package.i18n.json index 1201416614d..490b1f6de0d 100644 --- a/i18n/esn/extensions/typescript/package.i18n.json +++ b/i18n/esn/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Complete las funciones con la signatura de parĆ”metro.", "typescript.tsdk.desc": "Especifica la ruta de acceso de carpeta que contiene los archivos lib*.d.ts y tsserver que se van a usar.", - "typescript.disableAutomaticTypeAcquisition": "Deshabilita la adquisición automĆ”tica de tipos. Requiere TypeScript >= 2.0.6 y es necesario reiniciar despuĆ©s de cambiarlo.", + "typescript.disableAutomaticTypeAcquisition": "Desactiva la adquisición automĆ”tica de tipos. Requiere TypeScript >= 2.0.6.", "typescript.tsserver.log": "votes Habilita los registros del servidor TS a un archivo. Este registro se puede utilizar para diagnosticar problemas en el servidor TS. Este registro puede contener rutas de acceso, código fuente y posiblemente otra información sensitiva acerca del proyecto.", "typescript.tsserver.trace": "Habilita el seguimiento de mensajes al servidor TS. Este seguimiento se puede utilizar para diagnosticar problemas en el servidor TS. Este seguimiento puede contener rutas de acceso, código fuente y posiblemente otra información sensitiva acerca del proyecto.", "typescript.validate.enable": "Habilita o deshabilita la validación de TypeScript.", @@ -44,7 +44,10 @@ "typescript.npm": "Especifica la ruta de acceso al archivo ejecutable de NPM usada para la adquisición automĆ”tica de tipos. Requiere TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "Compruebe si NPM estĆ” instalado para la adquisición automĆ”tica de tipos.", "javascript.nameSuggestions": "Habilitar/deshabilitar nombres Ćŗnicos de la lista de sugerencias en los archivos de JavaScript. ", - "typescript.tsc.autoDetect": "Controla si la detección automĆ”tica de tareas TSC estĆ” activada o desactivada.", + "typescript.tsc.autoDetect": "Controla la auto detección de tareas del CAC. 'off' inhabilita esta función. 'build' crea una ejecución de compilación de tareas. 'watch' sólo crea compilación y 'watch tasks' 'on' crea tanto construir y ver tareas. Por defecto = 'on'. ", "typescript.problemMatchers.tsc.label": "Problemas de TypeScript", - "typescript.problemMatchers.tscWatch.label": "Problemas de TypeScript (modo de inspección)" + "typescript.problemMatchers.tscWatch.label": "Problemas de TypeScript (modo de inspección)", + "typescript.quickSuggestionsForPaths": "Activar o desactivar rĆ”pidas sugerencias al escribir una ruta de importación.", + "typescript.locale": "Establece la configuración regional para reportar errores de TypeScript. Requiere TypeScript > = 2.6.0. Por defecto, utiliza el valor 'null' de VS Code para errores de TypeScript.", + "javascript.implicitProjectConfig.experimentalDecorators": "Activar/desactivar 'experimentalDecorators' para los archivos JavaScript que no son parte de un proyecto. Los archivos jsconfig.json o tsconfig.json reemplazan esta configuración. Requiere inicio > = 2.3.1. " } \ No newline at end of file diff --git a/i18n/esn/src/vs/code/electron-main/menus.i18n.json b/i18n/esn/src/vs/code/electron-main/menus.i18n.json index 3a099ab9441..484face7717 100644 --- a/i18n/esn/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/esn/src/vs/code/electron-main/menus.i18n.json @@ -34,6 +34,7 @@ "miAutoSave": "Guardado automĆ”tico", "miRevert": "Revertir a&&rchivo", "miCloseWindow": "C&&errar ventana", + "miCloseWorkspace": "Cerrar &&Ć”rea de trabajo", "miCloseFolder": "Cerrar &&carpeta", "miCloseEditor": "&&Cerrar editor", "miExit": "Salir", @@ -46,6 +47,7 @@ "miPreferences": "&&Preferencias", "miReopenClosedEditor": "&&Volver a abrir el editor cerrado", "miMore": "&&MĆ”s...", + "miClearRecentOpen": "&&Borrar abiertos recientemente", "miUndo": "&&Deshacer", "miRedo": "&&Rehacer", "miCut": "Cortar", @@ -100,6 +102,7 @@ "miHideActivityBar": "Ocultar &&barra de actividades", "miShowActivityBar": "Mostrar &&barra de actividades", "miToggleWordWrap": "Alternar &&ajuste automĆ”tico de lĆ­nea", + "miToggleMinimap": "Alternar &&minimapa", "miToggleRenderWhitespace": "Alternar &&representación de espacio en blanco", "miToggleRenderControlCharacters": "Alternar caracteres de control &&", "miZoomIn": "&&Ampliar", @@ -148,6 +151,10 @@ "mZoom": "Zoom", "mBringToFront": "Traer todo al frente", "miSwitchWindow": "Cambiar &&Ventana...", + "mShowPreviousTab": "Mostrar pestaƱa anterior", + "mShowNextTab": "Mostrar siguiente pestaƱa", + "mMoveTabToNewWindow": "Mover pestaƱa a una nueva ventana", + "mMergeAllWindows": "Fusionar todas las ventanas", "miToggleDevTools": "&&Alternar herramientas de desarrollo", "miAccessibilityOptions": "&&Opciones de accesibilidad", "miReportIssues": "&&Notificar problemas", @@ -168,8 +175,8 @@ "miRunningTask": "Mostrar las &&tareas en ejecución", "miRestartTask": "R&&einiciar tarea en ejecución...", "miTerminateTask": "&&Finalizar tarea...", - "miConfigureTask": "&&Configurar tarea", - "miConfigureBuildTask": "Configurar tarea de compilación predeterminada", + "miConfigureTask": "&&Configurar Tareas...", + "miConfigureBuildTask": "Configurar Tarea de Compilación &&Predeterminada...", "accessibilityOptionsWindowTitle": "Opciones de accesibilidad", "miRestartToUpdate": "Reiniciar para actualizar...", "miCheckingForUpdates": "Buscando actualizaciones...", @@ -177,5 +184,6 @@ "miDownloadingUpdate": "Descargando actualización...", "miInstallingUpdate": "Instalando actualización...", "miCheckForUpdates": "Buscar actualizaciones...", + "aboutDetail": "\nVersión: {0}\nConfirmación: {1}\nFecha: {2}\nShell: {3}\nRepresentador: {4}\nNodo {5}\nArquitectura {6}", "okButton": "Aceptar" } \ No newline at end of file diff --git a/i18n/esn/src/vs/code/electron-main/windows.i18n.json b/i18n/esn/src/vs/code/electron-main/windows.i18n.json index f6ded97afe1..d28e7934772 100644 --- a/i18n/esn/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/esn/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,24 @@ "ok": "Aceptar", "pathNotExistTitle": "La ruta no existe", "pathNotExistDetail": "Parece que la ruta '{0}' ya no existe en el disco.", - "reopen": "Volver a abrir", - "wait": "Siga esperando", - "close": "Cerrar", + "reopen": "&& Abrir", + "wait": "&& Mantener la espera", + "close": "&& Cerrar", "appStalled": "La ventana ha dejado de responder.", "appStalledDetail": "Puede volver a abrir la ventana, cerrarla o seguir esperando.", "appCrashed": "La ventana se bloqueó", "appCrashedDetail": "Sentimos las molestias. Puede volver a abrir la ventana para continuar donde se detuvo.", + "open": "Abrir", + "openFolder": "Abrir carpeta", "openFile": "Abrir archivo", - "openFolder": "Abrir carpeta" + "workspaceOpenedMessage": "No se puede guardar el espacio de trabajo '{0}'", + "workspaceOpenedDetail": "El espacio de trabajo ya estĆ” abierto en otra ventana. Por favor, cierre primero la ventana y vuelta a intentarlo de nuevo.", + "openWorkspace": "&&Abrir...", + "openWorkspaceTitle": "Abrir Ć”rea de trabajo", + "save": "&&Guardar", + "doNotSave": "&&No guardar", + "cancel": "Cancelar", + "saveWorkspaceMessage": "ĀæQuiere guardar la configuración del Ć”rea de trabajo como un archivo?", + "saveWorkspaceDetail": "Guarde el Ć”rea de trabajo si tiene pensado volverla a abrir.", + "saveWorkspace": "Guardar Ć”rea de trabajo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json index 4fbc97c7e58..67e2a10947c 100644 --- a/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "Controla la altura de lĆ­nea. Utilice 0 para calcular el valor de lineHeight a partir de fontSize.", "letterSpacing": "Controla el espacio entre letras en pixels.", "lineNumbers": "Controla la presentación de los nĆŗmeros de lĆ­nea. Los valores posibles son \"on\", \"off\" y \"relative\". \"relative\" muestra el nĆŗmero de lĆ­neas desde la posición actual del cursor.", - "rulers": "Columnas en las que mostrar reglas verticales", + "rulers": "Representar reglas verticales despuĆ©s de un cierto nĆŗmero de caracteres monoespacio. Usar multiples valores para multiples reglas. No se dibuja ninguna regla si la matriz esta vacĆ­a.", "wordSeparators": "Caracteres que se usarĆ”n como separadores de palabras al realizar operaciones o navegaciones relacionadas con palabras.", "tabSize": "El nĆŗmero de espacios a los que equivale una tabulación. Este valor se invalida segĆŗn el contenido del archivo cuando `editor.detectIndentation` estĆ” activado.", "tabSize.errorMessage": "Se esperaba \"number\". Tenga en cuenta que el ajuste \"editor.detectIndentation\" ha reemplazado al valor \"auto\".", @@ -20,8 +20,9 @@ "detectIndentation": "Al abrir un archivo, se detectarĆ”n `editor.tabSize` y `editor.insertSpaces` en función del contenido del archivo.", "roundedSelection": "Controla si las selecciones tienen esquinas redondeadas", "scrollBeyondLastLine": "Controla si el editor se seguirĆ” desplazando despuĆ©s de la Ćŗltima lĆ­nea", + "smoothScrolling": "Controla si el editor se desplaza con una animación", "minimap.enabled": "Controla si se muestra el minimapa", - "minimap.showSlider": "Controla si el control deslizante del minimapa es ocultado automĆ”ticamente.", + "minimap.showSlider": "Controla si se oculta automĆ”ticamente el control deslizante del minimapa. Los valores posibles son \"always\" y \"mouseover\".", "minimap.renderCharacters": "Presentar los caracteres reales en una lĆ­nea (por oposición a bloques de color)", "minimap.maxColumn": "Limitar el ancho del minimapa para presentar como mucho un nĆŗmero de columnas determinado", "find.seedSearchStringFromSelection": "Controla si se inicializa la cadena de bĆŗsqueda en Buscar widget en la selección del editor", @@ -46,7 +47,7 @@ "autoClosingBrackets": "Controla si el editor debe cerrar automĆ”ticamente los corchetes despuĆ©s de abrirlos", "formatOnType": "Controla si el editor debe dar formato automĆ”ticamente a la lĆ­nea despuĆ©s de escribirla", "formatOnPaste": "Controla si el editor debe formatear automĆ”ticamente el contenido pegado. Debe haber disponible un formateador capaz de aplicar formato a un intervalo dentro de un documento.", - "autoIndent": "Controla si el editor deberĆ­a ajustar automĆ”ticamente la sangrĆ­a cuando los usuarios escriben, pegan o mueven lĆ­neas. Las reglas de sangrĆ­a del idioma deben estar disponibles.", + "autoIndent": "Controla si el editor deberĆ­a ajustar automĆ”ticamente la sangrĆ­a cuando los usuarios escriben, pegan o mueven lĆ­neas. Las reglas de sangrĆ­a del idioma deben estar disponibles", "suggestOnTriggerCharacters": "Controla si las sugerencias deben aparecer de forma automĆ”tica al escribir caracteres desencadenadores", "acceptSuggestionOnEnter": "Controla si las sugerencias deben aceptarse en \"Entrar\" (ademĆ”s de \"TAB\"). Ayuda a evitar la ambigüedad entre insertar nuevas lĆ­neas o aceptar sugerencias. El valor \"smart\" significa que solo se acepta una sugerencia con Entrar cuando se realiza un cambio textual.", "acceptSuggestionOnCommitCharacter": "Controla si se deben aceptar sugerencias en los caracteres de confirmación. Por ejemplo, en Javascript, el punto y coma (\";\") puede ser un carĆ”cter de confirmación que acepta una sugerencia y escribe ese carĆ”cter.", @@ -86,6 +87,8 @@ "accessibilitySupport.off": "El editor nunca se optimizarĆ” para su uso con un lector de pantalla.", "accessibilitySupport": "Controla si el editor se debe ejecutar en un modo optimizado para lectores de pantalla.", "links": "Controla si el editor debe detectar enlaces y hacerlos cliqueables", + "colorDecorators": "Controla si el editor debe representar el Selector de colores y los elementos Decorator de color en lĆ­nea.", + "codeActions": "Permite que el foco de acción del código", "sideBySide": "Controla si el editor de diferencias muestra las diferencias en paralelo o alineadas.", "ignoreTrimWhitespace": "Controla si el editor de diferencias muestra los cambios de espacio inicial o espacio final como diferencias.", "renderIndicators": "Controla si el editor de diff muestra indicadores +/- para cambios agregados/quitados", diff --git a/i18n/esn/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/esn/src/vs/editor/common/view/editorColorRegistry.i18n.json index 153aeca3e8b..9cd43302e16 100644 --- a/i18n/esn/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/esn/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "Color de primer plano de squigglies de error en el editor.", "errorBorder": "Color de borde de squigglies de error en el editor.", "warningForeground": "Color de primer plano de squigglies de advertencia en el editor.", - "warningBorder": "Color de borde de squigglies de advertencia en el editor." + "warningBorder": "Color de borde de squigglies de advertencia en el editor.", + "infoForeground": "Color de primer plano de los subrayados ondulados informativos en el editor.", + "infoBorder": "Color del borde de los subrayados ondulados informativos en el editor.", + "overviewRulerRangeHighlight": "Color de marcador de regla de información general para intervalos resaltados.", + "overviewRuleError": "Color de marcador de regla de información general para errores. ", + "overviewRuleWarning": "Color de marcador de regla de información general para advertencias.", + "overviewRuleInfo": "Color de marcador de regla de información general para mensajes informativos. " } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 6ffe5c01c29..a2385b5b922 100644 --- a/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "Reemplazar", "label.replaceAllButton": "Reemplazar todo", "label.toggleReplaceButton": "Alternar modo de reemplazar", - "title.matchesCountLimit": "Solo se resaltan los primeros 999 resultados, pero todas las operaciones de bĆŗsqueda trabajan en todo el texto.", + "title.matchesCountLimit": "Sólo los primeros {0} resultados son resaltados, pero todas las operaciones de bĆŗsqueda trabajan en todo el texto.", "label.matchesLocation": "{0} de {1}", "label.noResults": "Sin resultados" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json index d7f7577857c..27d384a1b68 100644 --- a/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,11 +10,6 @@ "nextSelectionMatchFindAction": "Buscar selección siguiente", "previousSelectionMatchFindAction": "Buscar selección anterior", "startReplace": "Reemplazar", - "addSelectionToNextFindMatch": "Agregar selección hasta la siguiente coincidencia de bĆŗsqueda", - "addSelectionToPreviousFindMatch": "Agregar selección hasta la anterior coincidencia de bĆŗsqueda", - "moveSelectionToNextFindMatch": "Mover Ćŗltima selección hasta la siguiente coincidencia de bĆŗsqueda", - "moveSelectionToPreviousFindMatch": "Mover Ćŗltima selección hasta la anterior coincidencia de bĆŗsqueda", - "selectAllOccurrencesOfFindMatch": "Seleccionar todas las repeticiones de coincidencia de bĆŗsqueda", - "changeAll.label": "Cambiar todas las ocurrencias", - "showNextFindTermAction": "Mostrar el siguiente tĆ©rmino de bĆŗsqueda" + "showNextFindTermAction": "Mostrar el siguiente tĆ©rmino de bĆŗsqueda", + "showPreviousFindTermAction": "Mostrar tĆ©rmino de bĆŗsqueda anterior" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/esn/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 5415844b0f8..6260d665365 100644 --- a/i18n/esn/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "{0} ediciones de formato en la lĆ­nea {1}", "hint1n": "1 edición de formato entre las lĆ­neas {0} y {1}", "hintnn": "{0} ediciones de formato entre las lĆ­neas {1} y {2}", + "no.provider": "Lo sentimos, pero no hay ningĆŗn formateador para los '{0}' archivos instalados.", "formatDocument.label": "Dar formato al documento", "formatSelection.label": "Dar formato a la selección" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/esn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 56027bb9936..a46ce2aad76 100644 --- a/i18n/esn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "Ir al error o la advertencia anterior", "editorMarkerNavigationError": "Color de los errores del widget de navegación de marcadores del editor.", "editorMarkerNavigationWarning": "Color de las advertencias del widget de navegación de marcadores del editor.", + "editorMarkerNavigationInfo": "Color del widget informativo marcador de navegación en el editor.", "editorMarkerNavigationBackground": "Fondo del widget de navegación de marcadores del editor." } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 13f4bac636a..d5994146753 100644 --- a/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Agregar cursor arriba", "mutlicursor.insertBelow": "Agregar cursor debajo", - "mutlicursor.insertAtEndOfEachLineSelected": "AƱadir cursores a finales de lĆ­nea" + "mutlicursor.insertAtEndOfEachLineSelected": "AƱadir cursores a finales de lĆ­nea", + "addSelectionToNextFindMatch": "Agregar selección hasta la siguiente coincidencia de bĆŗsqueda", + "addSelectionToPreviousFindMatch": "Agregar selección hasta la anterior coincidencia de bĆŗsqueda", + "moveSelectionToNextFindMatch": "Mover Ćŗltima selección hasta la siguiente coincidencia de bĆŗsqueda", + "moveSelectionToPreviousFindMatch": "Mover Ćŗltima selección hasta la anterior coincidencia de bĆŗsqueda", + "selectAllOccurrencesOfFindMatch": "Seleccionar todas las repeticiones de coincidencia de bĆŗsqueda", + "changeAll.label": "Cambiar todas las ocurrencias" } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/esn/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..067249df5b1 --- /dev/null +++ b/i18n/esn/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "Cerrar" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/esn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index b91a9fcb702..ce1db0c57f2 100644 --- a/i18n/esn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Color de fondo de un sĆ­mbolo durante el acceso de lectura; por ejemplo, cuando se lee una variable.", - "wordHighlightStrong": "Color de fondo de un sĆ­mbolo durante el acceso de escritura; por ejemplo, cuando se escribe una variable." + "wordHighlightStrong": "Color de fondo de un sĆ­mbolo durante el acceso de escritura; por ejemplo, cuando se escribe una variable.", + "overviewRulerWordHighlightForeground": "Color de marcador de regla de información general para sĆ­mbolos resaltados.", + "overviewRulerWordHighlightStrongForeground": "Color de marcador de regla de información general para sĆ­mbolos de acceso de escritura resaltados. ", + "wordHighlight.next.label": "Ir al siguiente sĆ­mbolo destacado", + "wordHighlight.previous.label": "Ir al sĆ­mbolo destacado anterior" } \ No newline at end of file diff --git a/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 253f50641c3..fc4e80ef3e4 100644 --- a/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "Grupo al que pertenece este comando", "vscode.extension.contributes.menus": "Contribuye con elementos de menĆŗ al editor", "menus.commandPalette": "La paleta de comandos", + "menus.touchBar": "Barra tĆ”ctil (sólo macOS)", "menus.editorTitle": "El menĆŗ de tĆ­tulo del editor", "menus.editorContext": "El menĆŗ contextual del editor", "menus.explorerContext": "El menĆŗ contextual del explorador de archivos", "menus.editorTabContext": "El menĆŗ contextual de pestaƱas del editor", "menus.debugCallstackContext": "El menĆŗ contextual de la pila de llamadas de depuración", "menus.scmTitle": "El menĆŗ del tĆ­tulo Control de código fuente", + "menus.scmSourceControl": "El menĆŗ de Control de código fuente", "menus.resourceGroupContext": "El menĆŗ contextual del grupo de recursos de Control de código fuente", "menus.resourceStateContext": "El menĆŗ contextual de estado de recursos de Control de código fuente", "view.viewTitle": "El menĆŗ de tĆ­tulo de vista contribuida", diff --git a/i18n/esn/src/vs/platform/environment/node/argv.i18n.json b/i18n/esn/src/vs/platform/environment/node/argv.i18n.json index 1a1f18154df..26e8b791489 100644 --- a/i18n/esn/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/esn/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "Los argumentos del modo \"--goto\" deben tener el formato \"ARCHIVO(:LƍNEA(:CARƁCTER))\".", - "diff": "Abra un editor de diferencias. Necesita pasar dos rutas de acceso a archivos como argumentos.", - "goto": "Abra el archivo en la ruta de acceso en la lĆ­nea y el carĆ”cter (agregue :lĆ­nea[:carĆ”cter] a la ruta de acceso).", + "diff": "Comparar dos archivos entre sĆ­.", + "add": "Agregar carpetas a la Ćŗltima ventana activa.", + "goto": "Abrir un archivo en la ruta de acceso de la lĆ­nea y posición de carĆ”cter especificadas.", "locale": "La configuración regional que se usarĆ” (por ejemplo, en-US o zh-TW).", "newWindow": "Fuerce una nueva instancia de Code.", "performance": "Comience con el comando 'Developer: Startup Performance' habilitado.", @@ -14,7 +15,7 @@ "reuseWindow": "Fuerce la apertura de un archivo o carpeta en la Ćŗltima ventana activa.", "userDataDir": "Especifica el directorio en que se conservan los datos de usuario; es Ćŗtil cuando se ejecuta como raĆ­z.", "verbose": "Imprima salidas detalladas (implica --wait).", - "wait": "Espere que se cierre la ventana antes de volver.", + "wait": "Espere a que los archivos sean cerrados antes de volver.", "extensionHomePath": "Establezca la ruta de acceso raĆ­z para las extensiones.", "listExtensions": "Enumere las extensiones instaladas.", "showVersions": "Muestra las versiones de las extensiones instaladas cuando se usa --list-extension.", diff --git a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 89b2efaccfe..d12f2822486 100644 --- a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Extensión no vĆ”lida: package.json no es un archivo JSON.", - "restartCode": "Reinicie Code antes de volver a instalar {0}.", - "installDependeciesConfirmation": "Al instalar '{0}', se instalan tambiĆ©n sus dependencias. ĀæQuiere continuar?", - "install": "SĆ­", - "doNotInstall": "No", + "restartCodeLocal": "Reinicie Code antes de volver a instalar {0}.", + "restartCodeGallery": "Por favor reinicie Code antes de reinstalar.", "uninstallDependeciesConfirmation": "ĀæQuiere desinstalar solo '{0}' o tambiĆ©n sus dependencias?", "uninstallOnly": "Solo", "uninstallAll": "Todo", diff --git a/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index b7b9d3c4f35..5568bf78176 100644 --- a/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "Eventos de activación de la extensión VS Code.", "vscode.extension.activationEvents.onLanguage": "Un evento de activación emitido cada vez que se abre un archivo que se resuelve en el idioma especificado.", "vscode.extension.activationEvents.onCommand": "Un evento de activación emitido cada vez que se invoca el comando especificado.", - "vscode.extension.activationEvents.onDebug": "Un evento de activación emitido cada vez que se inicia una sesión de depuración del tipo especificado.", + "vscode.extension.activationEvents.onDebug": "Un evento de activación emitido cada vez que un usuario estĆ” a punto de iniciar la depuración o cada vez que estĆ” a punto de configurar las opciones de depuración.", "vscode.extension.activationEvents.workspaceContains": "Un evento de activación emitido cada vez que se abre una carpeta que contiene al menos un archivo que coincide con el patrón global especificado.", "vscode.extension.activationEvents.onView": "Un evento de activación emitido cada vez que se expande la vista especificada.", "vscode.extension.activationEvents.star": "Un evento de activación emitido al inicio de VS Code. Para garantizar una buena experiencia para el usuario final, use este evento de activación en su extensión solo cuando no le sirva ninguna otra combinación de eventos de activación en su caso.", diff --git a/i18n/esn/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/esn/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..fb0c9175a49 --- /dev/null +++ b/i18n/esn/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "Contribuye a la extensión definida para los colores de los temas", + "contributes.color.id": "El identificador de los colores de los temas", + "contributes.color.id.format": "Los identificadores deben estar en la forma aa [.bb] *", + "contributes.color.description": "La descripción de los colores de los temas", + "contributes.defaults.light": "El color predeterminado para los temas claros. Un valor de color en hexadecimal (#RRGGBB [AA]) o el identificador de un color para los temas que proporciona el valor predeterminado.", + "contributes.defaults.dark": "El color predeterminado para los temas oscuros. Un valor de color en hexadecimal (#RRGGBB [AA]) o el identificador de un color para los temas que proporciona el valor predeterminado.", + "contributes.defaults.highContrast": "El color predeterminado para los temas con constraste. Un valor de color en hexadecimal (#RRGGBB [AA]) o el identificador de un color para los temas que proporciona el valor predeterminado.", + "invalid.colorConfiguration": "'configuration.colors' debe ser una matriz", + "invalid.default.colorType": "{0} debe ser un valor de color en hexadecimal (#RRGGBB [AA] o #RGB [A]) o el identificador de un color para los temas que puede ser el valor predeterminado.", + "invalid.id": "'configuration.colors.id' debe definirse y no puede estar vacĆ­o", + "invalid.id.format": "'configuration.colors.id' debe seguir la palabra [.word]*", + "invalid.description": "'configuration.colors.description' debe definirse y no puede estar vacĆ­o", + "invalid.defaults": "'configuration.colors.defaults' debe ser definida y contener 'light', 'dark' y 'highContrast'" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json index ea1252e6e2f..9f8669717f0 100644 --- a/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/esn/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Formato de color no vĆ”lido. Use #TGB, #RBGA, #RRGGBB o #RRGGBBAA", "schema.colors": "Colores usados en el Ć”rea de trabajo.", "foreground": "Color de primer plano general. Este color solo se usa si un componente no lo invalida.", "errorForeground": "Color de primer plano general para los mensajes de erroe. Este color solo se usa si un componente no lo invalida.", @@ -45,6 +44,7 @@ "listHoverForeground": "Color de primer plano de la lista o el Ć”rbol al pasar por encima de los elementos con el ratón.", "listDropBackground": "Fondo de arrastrar y colocar la lista o el Ć”rbol al mover los elementos con el mouse.", "highlight": "Color de primer plano de la lista o el Ć”rbol de las coincidencias resaltadas al buscar dentro de la lista o el Ć”bol.", + "invalidItemForeground": "Color de primer plano de una lista o Ć”rbol para los elementos invĆ”lidos, por ejemplo una raiz sin resolver en el explorador.", "pickerGroupForeground": "Selector de color rĆ”pido para la agrupación de etiquetas.", "pickerGroupBorder": "Selector de color rĆ”pido para la agrupación de bordes.", "buttonForeground": "Color de primer plano del botón.", @@ -85,5 +85,7 @@ "mergeBorder": "Color del borde en los encabezados y el divisor en conflictos de combinación alineados.", "overviewRulerCurrentContentForeground": "Primer plano de la regla de visión general actual para conflictos de combinación alineados.", "overviewRulerIncomingContentForeground": "Primer plano de regla de visión general de entrada para conflictos de combinación alineados.", - "overviewRulerCommonContentForeground": "Primer plano de la regla de visión general de ancestros comunes para conflictos de combinación alineados." + "overviewRulerCommonContentForeground": "Primer plano de la regla de visión general de ancestros comunes para conflictos de combinación alineados.", + "overviewRulerFindMatchForeground": "Color de marcador de regla de información general para coincidencias encontradas.", + "overviewRulerSelectionHighlightForeground": "Color de marcador de regla de información general para elementos seleccionados resaltados." } \ No newline at end of file diff --git a/i18n/esn/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/esn/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..bdb0c0100dd --- /dev/null +++ b/i18n/esn/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Espacio de trabajo de código", + "untitledWorkspace": "Sin tĆ­tulo (Espacio de trabajo)", + "workspaceNameVerbose": "{0} (espacio de trabajo)", + "workspaceName": "{0} (espacio de trabajo)" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/esn/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..71dc1648d7c --- /dev/null +++ b/i18n/esn/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "views debe ser una mariz", + "requirestring": "la propiedad `{0}` es obligatoria y debe ser de tipo \"string\"", + "optstring": "la propiedad `{0}` se puede omitir o debe ser de tipo \"string\"", + "vscode.extension.contributes.view.id": "Identificador de la vista. Úselo para registrar un proveedor de datos mediante la API \"vscode.window.registerTreeDataProviderForView\". TambiĆ©n para desencadenar la activación de su extensión al registrar el evento \"onView:${id}\" en \"activationEvents\".", + "vscode.extension.contributes.view.name": "Nombre de la vista en lenguaje natural. SerĆ” mostrado", + "vscode.extension.contributes.view.when": "Condición que se debe cumplir para mostrar esta vista", + "vscode.extension.contributes.views": "Aporta vistas al editor", + "views.explorer": "Vista del explorador", + "views.debug": "Vista de depuración", + "locationId.invalid": "`{0}` no es una ubicación de vista vĆ”lida", + "duplicateView1": "No se pueden registrar mĆŗltiples vistas con el mismo identificador '{0}' en la ubicación '{1}'", + "duplicateView2": "Una vista con el identificador '{0}' ya estĆ” registrada en la ubicación '{1}'" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/esn/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..2f9d0b3805c --- /dev/null +++ b/i18n/esn/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "La extensión `{1}` no se pudo activar. Motivo: dependencia `{0}` desconocida.", + "failedDep1": "La extensión `{1}` no se pudo activar. Motivo: La dependencia `{0}` no se pudo activar.", + "failedDep2": "La extensión `{0}` no se pudo activar. Motivo: mĆ”s de 10 niveles de dependencias (probablemente sea un bucle de dependencias).", + "activationError": "Error al activar la extensión `{0}`: {1}." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 0c23382bea4..1e2b99a1870 100644 --- a/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,11 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "Abrir archivo...", "openFolder": "Abrir carpeta...", "openFileFolder": "Abrir...", - "cancel": "Cancelar", "addFolderToWorkspace": "Agregar carpeta al Ć”rea de trabajo...", + "add": "&& Agregar", "addFolderToWorkspaceTitle": "Agregar carpeta al Ć”rea de trabajo", + "globalRemoveFolderFromWorkspace": "Quitar carpeta del Ɓrea de trabajo...", "removeFolderFromWorkspace": "Quitar carpeta del Ć”rea de trabajo", - "save": "&&Guardar" + "openFolderSettings": "Abrir Configuración de carpeta", + "saveWorkspaceAsAction": "Guardar Ć”rea de trabajo como...", + "save": "&&Guardar", + "saveWorkspace": "Guardar Ć”rea de trabajo", + "openWorkspaceAction": "Abrir Ć”rea de trabajo...", + "openWorkspaceConfigFile": "Abrir archivo de configuración del Ć”rea de trabajo", + "openFolderAsWorkspaceInNewWindow": "Abrir carpeta como Ɓrea de trabajo en una Nueva Ventana", + "workspaceFolderPickerPlaceholder": "Seleccionar la carpeta del Ć”rea de trabajo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index debc8854e48..7b9e720af09 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "Quitar de la barra de actividades", - "keepInActivityBar": "Guardar en la barra de la actividad", + "badgeTitle": "{0} - {1} ", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Ocultar de la barra de la actividad", + "keepInActivityBar": "Guardar en la barra de la actividad", "additionalViews": "Vistas adicionales", "numberBadge": "{0} ({1})", "manageExtension": "Administrar extensión", diff --git a/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index bfe695f895b..66f040cada4 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Ocultar barra de actividades", - "activityBarAriaLabel": "Modificador de vista activa", "globalActions": "Acciones globales" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..bbaa4095de7 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "Modificador de vista activa" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..5cf2aa986a5 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1} ", + "additionalViews": "Vistas adicionales", + "numberBadge": "{0} ({1})", + "manageExtension": "Administrar extensión", + "titleKeybinding": "{0} ({1})", + "hide": "Ocultar", + "keep": "Mantener", + "toggle": "Alternar vista fijada" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index c5c13f08096..ae6d0079e4c 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Mostrar editores del segundo grupo", "groupThreePicker": "Mostrar editores del tercer grupo", "allEditorsPicker": "Mostrar todos los editores abiertos", - "view": "Ver" + "view": "Ver", + "file": "Archivo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index f155f261fa1..5f8d21bad14 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,7 +35,9 @@ "openPreviousEditorInGroup": "Abrir el editor anterior en el grupo", "navigateNext": "Hacia delante", "navigatePrevious": "Hacia atrĆ”s", + "navigateLast": "Vaya al Ćŗltimo", "reopenClosedEditor": "Volver a abrir el editor cerrado", + "clearRecentFiles": "Borrar abiertos recientemente", "showEditorsInFirstGroup": "Mostrar editores del primer grupo", "showEditorsInSecondGroup": "Mostrar editores del segundo grupo", "showEditorsInThirdGroup": "Mostrar editores del tercer grupo", diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 7aae7a06e05..d3bb899fc07 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "Tabulación Mueve el Foco", - "screenReaderDetected": "Lector de Pantalla Detectado", + "screenReaderDetected": "Lector de pantalla optimizado", "screenReaderDetectedExtra": "Si no va a usar un lector de pantalla, cambie el valor de configuración \"editor.accessibilitySupport\" a \"desactivado\".", "disableTabMode": "Deshabilitar modo de accesibilidad", "gotoLine": "Ir a la lĆ­nea", @@ -47,5 +47,11 @@ "reopenWithEncoding": "Volver a abrir con Encoding", "guessedEncoding": "Adivinado por el contenido", "pickEncodingForReopen": "Seleccionar codificación de archivo para reabrir archivo", - "pickEncodingForSave": "Seleccionar codificación de archivo para guardar" + "pickEncodingForSave": "Seleccionar codificación de archivo para guardar", + "screenReaderDetectedExplanation.title": "Lector de pantalla optimizado", + "screenReaderDetectedExplanation.question": "ĀæEstĆ” usando un lector de pantalla con VS Code?", + "screenReaderDetectedExplanation.answerYes": "SĆ­", + "screenReaderDetectedExplanation.answerNo": "No", + "screenReaderDetectedExplanation.body1": "VS Code se ha optimizado para ser utilizado con un lector de pantalla", + "screenReaderDetectedExplanation.body2": "Algunas caracterĆ­sticas del editor tendrĆ”n comportamientos diferentes: por ejemplo, los ajustes de lĆ­nea, plegamiento, cierre automĆ”tico de llaves, etc." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 37917effd9c..08efb4d3ca8 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Cerrar panel", "togglePanel": "Alternar panel", "focusPanel": "Centrarse en el panel", + "toggledPanelPosition": "Posición de la palanca", + "moveToRight": "Mover a la derecha", + "moveToBottom": "Mover hacia abajo", "toggleMaximizedPanel": "Alternar el panel maximizado", "maximizePanel": "Maximizar el tamaƱo del panel", "minimizePanel": "Restaurar el tamaƱo del panel", diff --git a/i18n/esn/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json index 8791cdb4ffb..19146d91eec 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "compositePart.hideSideBarLabel": "Ocultar barra lateral", "focusSideBar": "Enfocar la barra lateral", "viewCategory": "Ver" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 7dd9c672cbe..4f9bdabe15e 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "El comando \"{0}\" no estĆ” habilitado actualmente y no se puede ejecutar.", "manageExtension": "Administrar extensión" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..62933f6b509 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} acciones" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..f2487840d97 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} acciones", + "hideView": "Ocultar en la barra lateral" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..f22e31a7e45 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "Ya existe una vista registrada con el identificador '{0}' en la ubicación '{1}'" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..e4776f8c605 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "Ocultar en la barra lateral" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/common/theme.i18n.json b/i18n/esn/src/vs/workbench/common/theme.i18n.json index 42525c6192b..323cb6d934f 100644 --- a/i18n/esn/src/vs/workbench/common/theme.i18n.json +++ b/i18n/esn/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "Color de fondo de la pestaƱa activa. Las pestaƱas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias pestaƱas en un grupo de editores. Puede haber varios grupos de editores.", "tabInactiveBackground": "Color de fondo de la pestaƱa inactiva. Las pestaƱas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias pestaƱas en un grupo de editores. Puede haber varios grupos de editores.", "tabBorder": "Borde para separar las pestaƱas entre sĆ­. Las pestaƱas son contenedores de editores en el Ć”rea de editores. Se pueden abrir varias pestaƱas en un grupo de editores. Puede haber varios grupos de editores.", + "tabActiveBorder": "Borde para resaltar las fichas activas. Las fichas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias fichas en un grupo de editores. Puede haber varios grupos de editores.", + "tabActiveUnfocusedBorder": "Borde para resaltar las fichas activas en un grupo que no tiene el foco. Las fichas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias fichas en un grupo de editores. Puede haber varios grupos de editores. ", "tabActiveForeground": "Color de primer plano de la pestaƱa activa en un grupo activo. Las pestaƱas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias pestaƱas en un grupo de editores. Puede haber varios grupos de editores.", "tabInactiveForeground": "Color de primer plano de la pestaƱa inactiva en un grupo activo. Las pestaƱas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias pestaƱas en un grupo de editores. Puede haber varios grupos de editores.", - "tabUnfocusedActiveForeground": "Color de primer plano de la pestaƱa activa en un grupo inactivo. Las pestaƱas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias pestaƱas en un grupo de editores. Puede haber varios grupos de editores.", - "tabUnfocusedInactiveForeground": "Color de primer plano de la pestaƱa inactiva en un grupo inactivo. Las pestaƱas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias pestaƱas en un grupo de editores. Puede haber varios grupos de editores.", + "tabUnfocusedActiveForeground": "Color de primer plano de la ficha activa en un grupo que no tiene el foco. Las fichas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias fichas en un grupo de editores. Puede haber varios grupos de editores. ", + "tabUnfocusedInactiveForeground": "Color de primer plano de las fichas inactivas en un grupo que no tiene el foco. Las fichas son los contenedores de los editores en el Ć”rea de editores. Se pueden abrir varias fichas en un grupo de editores. Puede haber varios grupos de editores. ", "editorGroupBackground": "Color de fondo de un grupo de editores. Los grupos de editores son los contenedores de los editores. El color de fondo se ve cuando se mueven arrastrando los grupos de editores.", "tabsContainerBackground": "Color de fondo del encabezado del tĆ­tulo del grupo de editores cuando las fichas estĆ”n habilitadas. Los grupos de editores son contenedores de editores.", "tabsContainerBorder": "Color de borde del encabezado del tĆ­tulo del grupo de editores cuando las fichas estĆ”n habilitadas. Los grupos de editores son contenedores de editores.", @@ -18,15 +20,17 @@ "editorGroupBorder": "Color para separar varios grupos de editores entre sĆ­. Los grupos de editores son los contenedores de los editores.", "editorDragAndDropBackground": "Color de fondo cuando se arrastran los editores. El color deberĆ­a tener transparencia para que el contenido del editor pueda brillar a su travĆ©s.", "panelBackground": "Color de fondo del panel. Los paneles se muestran debajo del Ć”rea de editores y contienen vistas, como Salida y Terminal integrado.", - "panelBorder": "Color del borde superior del panel que lo separa del editor. Los paneles se muestran debajo del Ć”rea de editores y contienen vistas, como Salida y Terminal integrado.", + "panelBorder": "El color del borde superior del panel que lo separa del editor. Los paneles se muestran debajo del Ć”rea de editores y contienen vistas, como la salida y la terminal integrada.", "panelActiveTitleForeground": "Color del tĆ­tulo del panel activo. Los paneles se muestran debajo del Ć”rea del editor y contienen vistas como Salida y Terminal integrado.", "panelInactiveTitleForeground": "Color del tĆ­tulo del panel inactivo. Los paneles se muestran debajo del Ć”rea del editor y contienen vistas como Salida y Terminal integrado.", "panelActiveTitleBorder": "Color de borde del tĆ­tulo del panel activo. Los paneles se muestran debajo del Ć”rea del editor y contienen vistas como Salida y Terminal integrado.", - "statusBarForeground": "Color de primer plano de la barra de estado, que se muestra en la parte inferior de la ventana.", + "panelDragAndDropBackground": "Arrastre y suelte color comentarios para los artĆ­culos de tĆ­tulo del panel. El color debe tener transparencia para que las entradas del panel todavĆ­a pueden brillar a travĆ©s. Los paneles se muestran debajo de la zona de editor y contienen vistas como salida y el terminal integrado.", + "statusBarForeground": "Color de primer plano de la barra de estado cuando se abre un espacio de trabajo. La barra de estado se muestra en la parte inferior de la ventana.", "statusBarNoFolderForeground": "Color de primer plano de la barra de estado cuando no hay ninguna carpeta abierta. La barra de estado se muestra en la parte inferior de la ventana.", - "statusBarBackground": "Color de fondo de la barra de estado estĆ”ndar, que se muestra en la parte inferior de la ventana.", + "statusBarBackground": "Color de fondo de la barra de estado cuando se abre un espacio de trabajo. La barra de estado se muestra en la parte inferior de la ventana.", "statusBarNoFolderBackground": "Color de fondo de la barra de estado cuando no hay ninguna carpeta abierta. La barra de estado se muestra en la parte inferior de la ventana.", "statusBarBorder": "Color de borde de la barra de estado que separa la barra lateral y el editor. La barra de estado se muestra en la parte inferior de la ventana.", + "statusBarNoFolderBorder": "Color de borde de la barra de estado que separa la barra lateral y el editor cuando no hay ninguna carpeta abierta. La barra de estado se muestra en la parte inferior de la ventana.", "statusBarItemActiveBackground": "Color de fondo de un elemento de la barra de estado al hacer clic. La barra de estado se muestra en la parte inferior de la ventana.", "statusBarItemHoverBackground": "Color de fondo de un elemento de la barra de estado al mantener el puntero. La barra de estado se muestra en la parte inferior de la ventana.", "statusBarProminentItemBackground": "Color de fondo de los elementos destacados en la barra de estado. Estos elementos sobresalen para indicar importancia. La barra de estado estĆ” ubicada en la parte inferior de la ventana.", @@ -41,12 +45,14 @@ "sideBarForeground": "Color de primer plano de la barra lateral, que es el contenedor de vistas como Explorador y BĆŗsqueda.", "sideBarBorder": "Color de borde de la barra lateral en el lado que separa el editor. La barra lateral es el contenedor de vistas como Explorador y BĆŗsqueda.", "sideBarTitleForeground": "Color de primer plano del tĆ­tulo de la barra lateral, que es el contenedor de vistas como Explorador y BĆŗsqueda.", + "sideBarDragAndDropBackground": "Color de arrastrar y colocar comentarios para las secciones de la barra lateral. El color debe tener transparencia para permitir que se vean las secciones de la barra lateral, que es el contenedor para vistas como la del explorador o la de bĆŗsqueda.", "sideBarSectionHeaderBackground": "Color de fondo del encabezado de sección de la barra lateral, que es el contenedor de vistas como Explorador y BĆŗsqueda.", "sideBarSectionHeaderForeground": "Color de primer plano del encabezado de sección de la barra lateral, que es el contenedor de vistas como Explorador y BĆŗsqueda.", "titleBarActiveForeground": "Color de primer plano de la barra de tĆ­tulo cuando la ventana estĆ” activa. Tenga en cuenta que, actualmente, este clor solo se admite en macOS.", "titleBarInactiveForeground": "Color de primer plano de la barra de tĆ­tulo cuando la ventana estĆ” inactiva. Tenga en cuenta que, actualmente, este color solo se admite en macOS.", "titleBarActiveBackground": "Fondo de la barra de tĆ­tulo cuando la ventana estĆ” activa. Tenga en cuenta que, actualmente, este color solo se admite en macOS.", "titleBarInactiveBackground": "Color de fondo de la barra de tĆ­tulo cuando la ventana estĆ” inactiva. Tenga en cuenta que, actualmente, este color solo se admite en macOS.", + "titleBarBorder": "Color de borde de la barra de tĆ­tulo. Tenga en cuenta que, actualmente, este color se admite solo en macOS.", "notificationsForeground": "Color de primer plano de las notificaciones. Estas se deslizan en la parte superior de la ventana. ", "notificationsBackground": "Color de fondo de las notificaciones. Estas se deslizan en la parte superior de la ventana. ", "notificationsButtonBackground": "Color de fondo del botón de notificaciones. Estas se deslizan en la parte superior de la ventana.", diff --git a/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json index d8ddeb3fcda..a404f8a1152 100644 --- a/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/esn/src/vs/workbench/electron-browser/actions.i18n.json @@ -6,6 +6,8 @@ { "closeActiveEditor": "Cerrar editor", "closeWindow": "Cerrar ventana", + "closeWorkspace": "Cerrar Ć”rea de trabajo", + "noWorkspaceOpened": "No hay ninguna Ć”rea de trabajo abierta en esta instancia para cerrarla.", "newWindow": "Nueva ventana", "toggleFullScreen": "Alternar pantalla completa", "toggleMenuBar": "Alternar barra de menĆŗs", @@ -20,7 +22,11 @@ "close": "Cerrar ventana", "switchWindow": "Cambiar de Ventana...", "quickSwitchWindow": "Cambio RĆ”pido de Ventana...", + "workspaces": "Ć”reas de trabajo", "files": "archivos", + "openRecentPlaceHolderMac": "Seleccione para abrir (mantenga presionada la tecla Comando para abrir en una ventana nueva)", + "openRecentPlaceHolder": "Seleccione para abrir (mantenga presionada la tecla Ctrl para abrir en una ventana nueva)", + "remove": "Quitar de abiertos recientemente", "openRecent": "Abrir Reciente...", "quickOpenRecent": "Abrir Reciente Rapidamente...", "closeMessages": "Cerrar mensajes de notificación", @@ -36,5 +42,10 @@ "navigateUp": "Navegar a la Vista Superior", "navigateDown": "Navegar a la Vista Inferior", "increaseViewSize": "Aumentar tamaƱo de vista actual", - "decreaseViewSize": "Reducir tamaƱo de vista actual" + "decreaseViewSize": "Reducir tamaƱo de vista actual", + "showPreviousTab": "Mostrar pestaƱa de ventana anterior", + "showNextWindowTab": "Mostrar siguiente pestaƱa de ventana", + "moveWindowTabToNewWindow": "Mover pestaƱa de ventana a una nueva ventana", + "mergeAllWindowTabs": "Fusionar todas las ventanas", + "toggleWindowTabsBar": "Alternar barra de pestaƱas de ventana" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..949ae20646f --- /dev/null +++ b/i18n/esn/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "Configurar idioma", + "displayLanguage": "Define el lenguaje para mostrar de VSCode.", + "doc": "Consulte {0} para obtener una lista de idiomas compatibles.", + "restart": "Al cambiar el valor se requiere reiniciar VSCode.", + "fail.createSettings": "No se puede crear '{0}' ({1}).", + "JsonSchema.locale": "Idioma de la interfaz de usuario que debe usarse." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json index dc8d19d2e3a..f6ea30df3b7 100644 --- a/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,20 +10,32 @@ "workspaces": "Ɓreas de trabajo", "developer": "Desarrollador", "showEditorTabs": "Controla si los editores abiertos se deben mostrar o no en pestaƱas.", + "workbench.editor.labelFormat.default": "Mostrar el nombre del archivo. Cuando estĆ”n habilitadas las pestaƱas y dos archivos tienen el mismo nombre en un grupo se agregan las secciones de distinguinshing de ruta de cada archivo. Cuando se desactivan las pestaƱas, se muestra la ruta de acceso relativa a la carpeta de trabajo si el editor estĆ” activo.", + "workbench.editor.labelFormat.short": "Mostrar el nombre del archivo seguido de su nombre de directorio.", + "workbench.editor.labelFormat.medium": "Mostrar el nombre del archivo seguido de la ruta de acceso relativa a la carpeta de espacio de trabajo.", + "workbench.editor.labelFormat.long": "Mostrar el nombre del archivo seguido de la ruta de acceso absoluta.", + "tabDescription": "Controla el formato de la etiqueta para un editor. Modificar este ajuste puede hacer, por ejemplo, que sea mĆ”s fĆ”cil entender la ubicación de un archivo: - corta: 'parent' - media: 'workspace/src/parent' - larga: '/home/user/workspace/src/parect' - por defecto: '.../parent', cuando otra pestaƱa comparte el mismo tĆ­tulo, o la ruta de acceso relativa del espacio de trabajo si las pestaƱas estĆ”n deshabilitadas", "editorTabCloseButton": "Controla la posición de los botones de cierre de pestaƱas del editor o los deshabilita si se establece en \"off\".", "showIcons": "Controla si los editores abiertos deben mostrarse o no con un icono. Requiere que tambiĆ©n se habilite un tema de icono.", - "enablePreview": "Controla si los editores abiertos se muestran en vista previa. Los editores en vista previa se reutilizan hasta que se guardan (por ejemplo, mediante doble clic o editĆ”ndolos).", + "enablePreview": "Controla si los editores abiertos se muestran en vista previa. Los editores en vista previa se reutilizan hasta que se guardan (por ejemplo, mediante doble clic o editĆ”ndolos) y se muestran en cursiva.", "enablePreviewFromQuickOpen": "Controla si los editores abiertos mediante Quick Open se muestran en modo de vista previa. Los editores en modo de vista previa se reutilizan hasta que se conservan (por ejemplo, mediante doble clic o editĆ”ndolos).", - "editorOpenPositioning": "Controla dónde se abren los editores. Seleccione 'izquierda' o 'derecha' para abrir los editores situados a la izquierda o la derecha del que estĆ” actualmente activo. Seleccione 'primero' o 'Ćŗltimo' para abrir los editores con independencia del que estĆ© actualmente activo.", + "editorOpenPositioning": "Controla dónde se abren los editores. Seleccione 'izquierda' o 'derecha' para abrir los editores situados a la izquierda o la derecha del que estĆ” actualmente activo. Seleccione 'primero' o 'Ćŗltimo' para abrir los editores con independencia del que estĆ© actualmente activo. ", "revealIfOpen": "Controla si un editor se muestra en alguno de los grupos visibles cuando se abre. Si se deshabilita esta opción, un editor preferirĆ” abrirse en el grupo de editores activo en ese momento. Si se habilita, un editor ya abierto se mostrarĆ” en lugar de volver a abrirse en el grupo de editores activo. Tenga en cuenta que hay casos en los que esta opción se omite; por ejemplo, cuando se fuerza la apertura de un editor en un grupo especĆ­fico o junto al grupo activo actual.", - "commandHistory": "Controla el nĆŗmero de comandos usados recientemente a almacenar en el historial para la paleta de comandos. Establezca a 0 para deshabilitar el historial de comandos.", + "commandHistory": "Controla el nĆŗmero de comandos utilizados recientemente que se mantendrĆ”n en el historial de la paleta de comandos. Establezca el valor a 0 para desactivar el historial de comandos.", "preserveInput": "Controla si la Ćŗltima entrada introducida en la paleta de comandos deberĆ­a ser restaurada cuando sea abierta la próxima vez.", "closeOnFocusLost": "Controla si Quick Open debe cerrarse automĆ”ticamente cuando pierde el foco.", "openDefaultSettings": "Controla si la configuración de apertura tambiĆ©n abre un editor que muestra todos los valores predeterminados.", + "experimentalFuzzySearchEndpoint": "Indica el punto final para la bĆŗsqueda de configuraciones experimentales.", + "experimentalFuzzySearchKey": "Indica la clave a utilizar para la bĆŗsqueda de configuraciones experimentales.", "sideBarLocation": "Controla la ubicación de la barra lateral. Puede mostrarse a la izquierda o a la derecha del Ć”rea de trabajo.", + "panelLocation": "Controla la ubicación de la barra lateral. Puede mostrarse a la izquierda o a la derecha del Ć”rea de trabajo.", "statusBarVisibility": "Controla la visibilidad de la barra de estado en la parte inferior del Ć”rea de trabajo.", "activityBarVisibility": "Controla la visibilidad de la barra de actividades en el Ć”rea de trabajo.", "closeOnFileDelete": "Controla si los editores que muestran un archivo deben cerrarse automĆ”ticamente cuando otro proceso elimina el archivo o le cambia el nombre. Si se deshabilita esta opción y se da alguna de estas circunstancias, se mantiene el editor abierto con modificaciones. Tenga en cuenta que, cuando se eliminan archivos desde la aplicación, siempre se cierra el editor y que los archivos con modificaciones no se cierran nunca para preservar los datos.", + "fontAliasing": "Controla el mĆ©todo de suavizado de fuentes en el Ć”rea de trabajo.\n- default: suavizado de fuentes en subpĆ­xeles. En la mayorĆ­a de las pantallas que no son Retina, esta opción muestra el texto mĆ”s nĆ­tido.\n- antialiased: suaviza las fuentes en pĆ­xeles, en lugar de subpĆ­xeles. Puede hacer que las fuentes se vean mĆ”s claras en general\n- none: deshabilita el suavizado de fuentes. El texto se muestra con bordes nĆ­tidos irregulares.", + "workbench.fontAliasing.default": "Suavizado de fuentes en subpĆ­xeles. En la mayorĆ­a de las pantallas que no son Retina, esta opción muestra el texto mĆ”s nĆ­tido.", + "workbench.fontAliasing.antialiased": "Suaviza las fuentes en pĆ­xeles, en lugar de subpĆ­xeles. Puede hacer que las fuentes se vean mĆ”s claras en general.", + "workbench.fontAliasing.none": "Deshabilita el suavizado de fuentes. El texto se muestra con bordes nĆ­tidos irregulares.", "swipeToNavigate": "Navegar entre achivos abiertos utlizando la pulsación de tres dedos para deslizar horizontalmante.", "workbenchConfigurationTitle": "Ɓrea de trabajo", "window.openFilesInNewWindow.on": "Los archivos se abrirĆ”n en una nueva ventana", @@ -35,16 +47,19 @@ "window.openFoldersInNewWindow.default": "Las carpetas se abrirĆ”n en una nueva ventana a menos que se seleccione una carpeta desde la aplicación (p. ej. mediante el menĆŗ Archivo)", "openFoldersInNewWindow": "Controla si las carpetas deben abrirse en una ventana nueva o reemplazar la Ćŗltima ventana activa.\n- default: las carpetas se abrirĆ”n en una ventana nueva, a menos que se seleccione una carpeta desde la aplicación (por ejemplo, desde el menĆŗ Archivo)\n- on: las carpetas se abrirĆ”n en una ventana nueva\n- off: las carpetas reemplazarĆ”n la Ćŗltima ventana activa\nTenga en cuenta que aĆŗn puede haber casos en los que este parĆ”metro se ignore (por ejemplo, al usar la opción de la lĆ­nea de comandos -new-window o -reuse-window).", "window.reopenFolders.all": "Reabrir todas las ventanas.", + "window.reopenFolders.folders": "Reabrir todas las carpetas. Las Ć”reas de trabajo vacĆ­as no se restaurarĆ”n.", "window.reopenFolders.one": "Reabrir la Ćŗltima ventana activa.", "window.reopenFolders.none": "Nunca reabrir una ventana. Empezar siempre con una vacĆ­a.", + "restoreWindows": "Controla cómo se vuelven a abrir las ventanas tras un reinicio. Seleccione \"none\" para comenzar siempre con un Ć”rea de trabajo vacĆ­a, \"one\" para volver a abrir la Ćŗltima ventana en la que trabajó, \"folders\" para volver a abrir todas las ventanas que tenĆ­an carpetas abiertas o \"all\" para volver a abrir todas las ventanas de la Ćŗltima sesión.", "restoreFullscreen": "Controla si una ventana se debe restaurar al modo de pantalla completa si se salió de ella en dicho modo.", "zoomLevel": "Ajuste el nivel de zoom de la ventana. El tamaƱo original es 0 y cada incremento (por ejemplo, 1) o disminución (por ejemplo, -1) representa una aplicación de zoom un 20Ā % mĆ”s grande o mĆ”s pequeƱo. TambiĆ©n puede especificar decimales para ajustar el nivel de zoom con una granularidad mĆ”s precisa.", - "title": "Controla el tĆ­tulo de la ventana segĆŗn el editor activo. Las variables se sustituyen segĆŗn el contexto:\n${activeEditorShort}: e.g. myFile.txt\n${activeEditorMedium}: e.g. myFolder/myFile.txt\n${activeEditorLong}: por ejemplo, /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: por ejemplo, myFolder\n${folderPath}: por ejemplo, /Users/Development/myFolder\n${rootName}: por ejemplo, myFolder1, myFolder2, myFolder3\n${rootPath}: por ejemplo, /Users/Development/myWorkspace\n${appName}: por ejemplo, VS Code\n${dirty}: un indicador con modificaciones si el editor activo estĆ” desfasado\n${separator}: separador condicional (\" - \") que solo se muestra cuando estĆ” rodeado de variables con valores", + "title": "Controla el tĆ­tulo de ventana basado en el editor activo. Las variables se sustituyen segĆŗn el contexto: ${activeEditorShort}: el archivo nombre (e.g. miarchivo.txt) ${activeEditorMedium}: la ruta del archivo en relación con el Ć”rea de trabajo carpeta (por ejemplo, myFolder/myFile.txt) ${activeEditorLong}: la ruta de acceso completa del archivo (p. ej. / Users/Development/myProject/myFolder/myFile.txt) ${nombre de carpeta}: nombre de la carpeta el archivo del espacio de trabajo estĆ” contenida en (e.g. myFolder) ${folderPath}: ruta del archivo de la carpeta el archivo del espacio de trabajo estĆ” contenida en (por ejemplo, /Users/Development/myFolder) {} $ rootName}: nombre de la Ć”rea de trabajo (por ejemplo myFolder o myWorkspace) ${Ruta_raĆ­z}: ruta del archivo del espacio de trabajo (por ejemplo, /Users/Development/myWorkspace) ${appName}: por ejemplo VS código ${sucio}: un indicador sucio si el editor activo es sucio ${separador}: condicional separador (\"-\") que sólo muestra cuando rodeada de variables con valores", "window.newWindowDimensions.default": "Abrir las nuevas ventanas en el centro de la pantalla.", "window.newWindowDimensions.inherit": "Abrir las nuevas ventanas con la misma dimensión que la Ćŗltima activa.", "window.newWindowDimensions.maximized": "Abrir las nuevas ventanas maximizadas.", "window.newWindowDimensions.fullscreen": "Abrir las nuevas ventanas en modo de pantalla completa.", "newWindowDimensions": "Controla las dimensiones de la nueva ventana cuando ya existe alguna ventana abierta. Por defecto, una nueva ventana se abrirĆ” en el centro de la pantalla con dimensiones pequeƱas. Cuando se establece como 'heredar', la ventana tomarĆ” las dimensiones de la Ćŗltima ventana activa. Cuando se establece a 'maximizar', la ventana se abrirĆ” maximizada, y a pantalla completa si fue configurada como 'pantalla completa'. Tenga en cuenta que esta configuración no afecta a la primera ventana abierta. La primera ventana siempre restaurarĆ” el tamaƱo y posición en la que quedó antes de ser cerrada.", + "closeWhenEmpty": "Controla si, al cerrar el Ćŗltimo editor, debe cerrarse tambiĆ©n la ventana. Esta configuración se aplica solo a ventanas que no muestran carpetas.", "window.menuBarVisibility.default": "El menĆŗ solo estĆ” oculto en modo de pantalla completa.", "window.menuBarVisibility.visible": "El menĆŗ estĆ” siempre visible incluso en modo de pantalla completa.", "window.menuBarVisibility.toggle": "El menĆŗ estĆ” oculto pero se puede mostrar mediante la tecla Alt.", diff --git a/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json index ff93659c0b4..5ceee829d26 100644 --- a/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/esn/src/vs/workbench/electron-browser/window.i18n.json @@ -9,6 +9,5 @@ "cut": "Cortar", "copy": "Copiar", "paste": "Pegar", - "selectAll": "Seleccionar todo", - "confirmOpenButton": "&&Abrir..." + "selectAll": "Seleccionar todo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 42304193db2..ebf04db12c2 100644 --- a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Si una lĆ­nea coincide con este patrón, su sangrĆ­a no se debe cambiar y no se debe evaluar utilizando las otras reglas.", "schema.indentationRules.unIndentedLinePattern.pattern": "El patrón de RegExp para unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Las marcas de RegExp para unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Debe coincidir con el patrón `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Debe coincidir con el patrón `/^([gimuy]+)$/`.", + "schema.folding": "Configuración del plegamiento de idioma.", + "schema.folding.offSide": "Un idioma se adhiere a la regla del fuera de juego si los bloques en ese idioma se expresan por su sangrĆ­a. Si se establece, las lĆ­neas vacĆ­as pertenecen al bloque posterior.", + "schema.folding.markers": "Marcadores de plegado especĆ­ficos de un idioma, como \"'#region\" o \"#endregion\". Se probarĆ”n los valores regex en relación con el contenido de todas las lĆ­neas, y deben estar diseƱados de manera eficiente.", + "schema.folding.markers.start": "El patrón de expresión regular para el marcador de inicio. La expresión regular debe comenzar con '^'.", + "schema.folding.markers.end": "El patrón de expresión regular para el marcador de fin. La expresión regular debe comenzar con '^'." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..72b8a580d23 --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "Ver: Alternar minimapa" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index 2bb51d7bf48..ae024682e37 100644 --- a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "Alternar caracteres de control" + "toggleRenderControlCharacters": "Ver: Alternar caracteres de control" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 621ee31ec25..b46420bf784 100644 --- a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "Alternar representación de espacio en blanco" + "toggleRenderWhitespace": "Ver: Alternar representación de espacio en blanco" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index 83815d8f8b2..a4c0a9b282f 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "No hay configuraciones", + "addConfigTo": "Agregar configuración ({0})...", "addConfiguration": "Agregar configuración..." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index be6974deb6b..e9a982317e2 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, depurar", "debugAriaLabel": "Escriba un nombre de una configuración de inicio para ejecutar.", + "addConfigTo": "Agregar configuración ({0})...", + "addConfiguration": "Agregar configuración...", "noConfigurationsMatching": "No hay ninguna configuración de depuración coincidente", "noConfigurationsFound": "No se encontró ninguna configuración de inicio. Cree un archivo \"launch.json\"." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..2419cd6ec9c --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "Variables de EnfoqueĀ ", + "debugFocusWatchView": "Reloj de enfoque", + "debugFocusCallStackView": "Pila de EnfoqueĀ ", + "debugFocusBreakpointsView": "Puntos de interrupción de enfoque" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index f4d25015e28..28c7690312b 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Configuraciones para generar el archivo \"launch.json\" inicial.", "vscode.extension.contributes.debuggers.languages": "Lista de lenguajes para los que la extensión de depuración podrĆ­a considerarse el \"depurador predeterminado\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Si se especifica, VS Code llamarĆ” a este comando para determinar la ruta de acceso ejecutable del adaptador de depuración y los argumentos que se deben pasar.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Si se especifica, VS Code llamarĆ” a este comando para las acciones de \"depuración\" o \"ejecución\" destinadas para esta extensión.", "vscode.extension.contributes.debuggers.configurationSnippets": "Fragmentos de código para agregar nuevas configuraciones a \"launch.json\".", "vscode.extension.contributes.debuggers.configurationAttributes": "Configuraciones de esquema JSON para validar \"launch.json\".", "vscode.extension.contributes.debuggers.windows": "Configuración especĆ­fica de Windows.", diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 254f1162351..97fb5eae642 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,14 +12,15 @@ "breakpointRemoved": "Punto de interrupción quitado, lĆ­nea {0}, archivo {1}", "compoundMustHaveConfigurations": "El compuesto debe tener configurado el atributo \"configurations\" a fin de iniciar varias configuraciones.", "configMissing": "La configuración \"{0}\" falta en \"launch.json\".", + "debugRequestNotSupported": "El atributo '{0}' tiene un valor no admitido '{1}' en la configuración de depuración seleccionada.", + "debugRequesMissing": "El atributo '{0}' estĆ” ausente en la configuración de depuración elegida. ", "debugTypeNotSupported": "El tipo de depuración '{0}' configurado no es compatible.", - "debugTypeMissing": "Falta la propiedad \"type\" en la configuración de inicio seleccionada.", + "debugTypeMissing": "Falta la propiedad \"type\" en la configuración de inicio seleccionada. ", + "debugAnyway": "Depurar de todos modos", "preLaunchTaskErrors": "Errores de compilación durante la tarea preLaunchTask '{0}'.", "preLaunchTaskError": "Error de compilación durante la tarea preLaunchTask '{0}'.", "preLaunchTaskExitCode": "La tarea preLaunchTask '{0}' finalizó con el código de salida {1}.", - "debugAnyway": "Depurar de todos modos", "noFolderWorkspaceDebugError": "El archivo activo no se puede depurar. Compruebe que se ha guardado en el disco y que tiene una extensión de depuración instalada para ese tipo de archivo.", "NewLaunchConfig": "Defina los valores del archivo de configuración de inicio para la aplicación. {0}", - "DebugTaskNotFound": "No se encontró el elemento preLaunchTask '{0}'.", - "differentTaskRunning": "Ya se estĆ” ejecutando la tarea '{0}'. No se puede ejecutar tareas de pre-lanzamiento '{1}'." + "DebugTaskNotFound": "No se encontró el elemento preLaunchTask '{0}'." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index c71edc9f51f..94c3c4bbf33 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "La variable {0} tiene el valor {1}, read–eval–print loop, depuración", "replExpressionAriaLabel": "La expresión {0} tiene el valor {1}, read–eval–print loop, depuración", "replValueOutputAriaLabel": "{0}, read–eval–print loop, depuración", - "replKeyValueOutputAriaLabel": "La variable de salida {0} tiene el valor {1}, read–eval–print loop, depuración" + "replRawObjectAriaLabel": "La variable {0} tiene el valor {1}, read–eval–print loop, debug" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index ff677b59a60..ca947a2308c 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "Color de fondo de la barra de estado cuando se estĆ” depurando un programa. La barra de estado se muestra en la parte inferior de la ventana", - "statusBarDebuggingForeground": "Color de primer plano de la barra de estado cuando se estĆ” depurando un programa. La barra de estado se muestra en la parte inferior de la ventana" + "statusBarDebuggingForeground": "Color de primer plano de la barra de estado cuando se estĆ” depurando un programa. La barra de estado se muestra en la parte inferior de la ventana", + "statusBarDebuggingBorder": "Color de borde de la barra de estado que separa la barra lateral y el editor cuando se estĆ” depurando un programa. La barra de estado se muestra en la parte inferior de la ventana." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 00a55728fff..2ad5121b38e 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "El ejecutable del adaptador de depuración \"{0}\" no existe.", "debugAdapterCannotDetermineExecutable": "No se puede determinar el ejecutable para el adaptador de depuración \"{0}\".", + "launch.config.comment1": "Utilizar IntelliSense para aprender acerca de los posibles atributos.", + "launch.config.comment2": "Mantenga el puntero para ver las descripciones de los existentes atributos ", + "launch.config.comment3": "Para mĆ”s información, visite: {0}", "debugType": "Tipo de configuración.", "debugTypeNotRecognised": "Este tipo de depuración no se reconoce. Compruebe que tiene instalada la correspondiente extensión de depuración y que estĆ” habilitada.", "node2NotSupported": "\"node2\" ya no se admite; use \"node\" en su lugar y establezca el atributo \"protocol\" en \"inspector\".", diff --git a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index a425ccfbeef..9c360797a3c 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "Id.", "view name": "Nombre", "view location": "Donde", - "themes": "Temas ({0})", + "colorThemes": "Temas de color ({0})", + "iconThemes": "Temas del icono ({0})", + "colors": "Colores ({0})", + "colorId": "ID", + "defaultDark": "Oscuro por defecto", + "defaultLight": "Claro por defecto", + "defaultHC": "Contraste alto por defecto", "JSON Validation": "Validación JSON ({0})", "commands": "Comandos ({0})", "command name": "Nombre", diff --git a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 5e236865193..148988a3afc 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,23 +34,28 @@ "postDisableMessage": "ĀæQuiere recargar esta ventana para desactivar la extensión '{0}'?", "postUninstallTooltip": "Recargar para desactivar", "postUninstallMessage": "ĀæQuiere recargar esta ventana para desactivar la extensión desinstalada '{0}'?", - "reload": "&&Volver a cargar Window", "toggleExtensionsViewlet": "Mostrar extensiones", "installExtensions": "Instalar extensiones", + "showEnabledExtensions": "Mostrar extensiones habilitadas", "showInstalledExtensions": "Mostrar extensiones instaladas", "showDisabledExtensions": "Mostrar extensiones deshabilitadas", "clearExtensionsInput": "Borrar entrada de extensiones", "showOutdatedExtensions": "Mostrar extensiones obsoletas", "showPopularExtensions": "Mostrar extensiones conocidas", "showRecommendedExtensions": "Mostrar extensiones recomendadas", - "showWorkspaceRecommendedExtensions": "Mostrar extensiones recomendadas del Ć”rea de trabajo", + "installWorkspaceRecommendedExtensions": "Instalar todo trabajo recomienda extensiones", + "allExtensionsInstalled": "Ya se han instalado todas las extensiones recomendadas para esta Ć”rea de trabajo", + "installRecommendedExtension": "Instalar extensión recomendada", + "extensionInstalled": "La extensión recomendada ya ha sido instalada", "showRecommendedKeymapExtensions": "Mostrar asignaciones de teclado recomendadas", "showRecommendedKeymapExtensionsShort": "Asignaciones de teclado", "showLanguageExtensions": "Mostrar extensiones del lenguaje", "showLanguageExtensionsShort": "Extensiones del lenguaje", - "configureWorkspaceRecommendedExtensions": "Configurar extensiones recomendadas (Ć”rea de trabajo)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Las recomendaciones solo estĆ”n disponibles en una carpeta de Ć”rea de trabajo.", + "showAzureExtensions": "Mostrar extensiones de Azure", + "showAzureExtensionsShort": "Extensiones de Azure", "OpenExtensionsFile.failed": "No se puede crear el archivo \"extensions.json\" dentro de la carpeta \".vscode\" ({0}).", + "configureWorkspaceRecommendedExtensions": "Configurar extensiones recomendadas (Ć”rea de trabajo)", + "configureWorkspaceFolderRecommendedExtensions": "Configurar extensiones recomendadas (Carpeta del Ć”rea de trabajo)", "builtin": "Integrada", "disableAll": "Deshabilitar todas las extensiones instaladas", "disableAllWorkspace": "Deshabilitar todas las extensiones instaladas para esta Ć”rea de trabajo", diff --git a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..eb6f8e39a71 --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "Recomendado" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index 20d11ae5ad9..11e9f1883d3 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "Presione ENTRAR para administrar sus extensiones.", + "notfound": "No se encontró '{0}' en Marketplace. ", + "install": "Presione Intro para instalar '{0}' desde el Marketplace. ", "searchFor": "Presione ENTRAR para buscar '{0}' en el catĆ”logo de soluciones.", "noExtensionsToInstall": "Escriba un nombre de extensión" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 845e8de1c17..6e56df786fd 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -4,12 +4,17 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "fileBasedRecommendation": "Esta extensión se recomienda basado en los archivos que abrió recientemente.", + "workspaceRecommendation": "Esta extensión es recomendada por los usuarios del espacio de trabajo actual.", "reallyRecommended2": "Para este tipo de archivo, se recomineda la extensión '{0}'.", + "reallyRecommendedExtensionPack": "Para este tipo de fichero, se recomienda el paquete de extensión '{0}'.", "showRecommendations": "Mostrar recomendaciones", + "install": "Instalar", "neverShowAgain": "No volver a mostrar", "close": "Cerrar", "workspaceRecommended": "Esta Ć”rea de trabajo tiene recomendaciones de extensión.", - "ignoreExtensionRecommendations": "ĀæDesea despreciar todas las recomendaciones de extensión?", + "installAll": "Instalar todo", + "ignoreExtensionRecommendations": "ĀæDesea ignorar todas las recomendaciones de la extensión?", "ignoreAll": "SĆ­, despreciar todas.", "no": "No", "cancel": "Cancelar" diff --git a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index d93e053a7d5..36cf35cad15 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,6 +6,8 @@ { "openExtensionsFolder": "Abrir carpeta de extensiones", "installVSIX": "Instalar desde VSIX...", + "installFromVSIX": "Instalar de VSIX", + "installButton": "&& Instalar", "InstallVSIXAction.success": "La extensión se instaló correctamente. Reinicie para habilitarla.", "InstallVSIXAction.reloadNow": "Recargar ahora" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json index a6e21a80ec7..cac04389f2e 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json @@ -8,6 +8,8 @@ "installedExtensions": "Instalado", "searchInstalledExtensions": "Instalado", "recommendedExtensions": "Recomendado", + "otherRecommendedExtensions": "Otras recomendaciones", + "workspaceRecommendedExtensions": "Recomendaciones de espacio de trabajo", "searchExtensions": "Buscar extensiones en Marketplace", "sort by installs": "Criterio de ordenación: NĆŗmero de instalaciones", "sort by rating": "Criterio de ordenación: Clasificación", diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index a58136aa89f..5b4f1d9a867 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Archivos", - "revealInSideBar": "Mostrar en barra lateral" + "filesCategory": "Archivo", + "revealInSideBar": "Mostrar en barra lateral", + "acceptLocalChanges": "Usar los cambios y sobrescribir el contenido del disco", + "revertLocalChanges": "Descartar los cambios y volver al contenido del disco" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json index c3a2ac37c7e..5c6f151c353 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "ĀæEstĆ” seguro de que desea eliminar '{0}'?", "undoBin": "Puede restaurar desde la papelera de reciclaje.", "undoTrash": "Puede restaurar desde la papelera.", + "doNotAskAgain": "No volver a preguntarme", "confirmDeleteMessageFolder": "ĀæEstĆ” seguro de que desea eliminar '{0}' y su contenido de forma permanente?", "confirmDeleteMessageFile": "ĀæEstĆ” seguro de que desea eliminar '{0}' de forma permanente?", "irreversible": "Esta acción es irreversible.", @@ -37,17 +38,15 @@ "openToSide": "Abrir en el lateral", "compareSource": "Seleccionar para comparar", "globalCompareFile": "Comparar archivo activo con...", - "pickHistory": "Seleccione un archivo abierto anteriormente para comparar", - "unableToFileToCompare": "El archivo seleccionado no se puede comparar con '{0}'.", "openFileToCompare": "Abrir un archivo antes para compararlo con otro archivo.", - "compareWith": "Comparar con '{0}'", + "compareWith": "Comparar \"{0}\" con \"{1}\"", "compareFiles": "Comparar archivos", "refresh": "Actualizar", "save": "Guardar", "saveAs": "Guardar como...", "saveAll": "Guardar todos", "saveAllInGroup": "Guardar todo en el grupo", - "saveFiles": "Guardar archivos con modificaciones", + "saveFiles": "Guardar todos los archivos", "revert": "Revertir archivo", "focusOpenEditors": "Foco sobre la vista de editores abiertos", "focusFilesExplorer": "Enfocar Explorador de archivos", @@ -55,7 +54,6 @@ "openFileToShow": "Abra primero un archivo para mostrarlo en el explorador.", "collapseExplorerFolders": "Contraer carpetas en el Explorador", "refreshExplorer": "Actualizar Explorador", - "openFile": "Abrir archivo...", "openFileInNewWindow": "Abrir archivo activo en nueva ventana", "openFileToShowInNewWindow": "Abrir un archivo antes para abrirlo en una nueva ventana", "revealInWindows": "Mostrar en el Explorador", @@ -69,5 +67,7 @@ "emptyFileNameError": "Debe especificarse un nombre de archivo o carpeta.", "fileNameExistsError": "Ya existe el archivo o carpeta **{0}** en esta ubicación. Elija un nombre diferente.", "invalidFileNameError": "El nombre **{0}** no es vĆ”lido para el archivo o la carpeta. Elija un nombre diferente.", - "filePathTooLongError": "El nombre **{0}** da como resultado una ruta de acceso demasiado larga. Elija un nombre mĆ”s corto." + "filePathTooLongError": "El nombre **{0}** da como resultado una ruta de acceso demasiado larga. Elija un nombre mĆ”s corto.", + "compareWithSaved": "Comparar el archivo activo con el guardado", + "modifiedLabel": "{0} (en disco) ↔ {1}" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index ad4eeb2b731..6b7926d2bf7 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "Editor de archivos de texto", "binaryFileEditor": "Editor de archivos binarios", "filesConfigurationTitle": "Archivos", - "exclude": "Configurar patrones globales para excluir archivos y carpetas.", + "exclude": "Configurar los patrones globales para excluir archivos y carpetas. Por ejemplo, el explorador de archivos decide que archivos y carpetas mostrar u ocultar segĆŗn esta configuración.", "files.exclude.boolean": "El patrón global con el que se harĆ”n coincidir las rutas de acceso de los archivos. EstablĆ©zcalo en true o false para habilitarlo o deshabilitarlo.", "files.exclude.when": "Comprobación adicional de los elementos del mismo nivel de un archivo coincidente. Use $(nombreBase) como variable para el nombre de archivo que coincide.", "associations": "Configure asociaciones de archivo para los lenguajes (por ejemplo, \"*.extension\": \"html\"). Estas asociaciones tienen prioridad sobre las asociaciones predeterminadas de los lenguajes instalados.", - "encoding": "La codificación del juego de caracteres predeterminada que debe utilizarse al leer y escribir archivos.", - "autoGuessEncoding": "Si estĆ” opción estĆ” habilitada, se intentarĆ” adivinar la codificación del juego de caracteres al abrir los archivos", + "encoding": "La codificación del juego de caracteres predeterminada que debe utilizarse al leer y escribir archivos. Este ajuste puede configurarse tambiĆ©n por idioma.", + "autoGuessEncoding": "Cuando estĆ” activada, intentarĆ” adivinar la codificación del juego de caracteres al abrir archivos. Este ajuste puede configurarse tambiĆ©n por idioma.", "eol": "CarĆ”cter predeterminado de final de lĆ­nea. Utilice \\n para LF y \\r\\n para CRLF.", "trimTrailingWhitespace": "Si se habilita, se recortarĆ” el espacio final cuando se guarde un archivo.", "insertFinalNewline": "Si se habilita, inserte una nueva lĆ­nea final al final del archivo cuando lo guarde.", + "trimFinalNewlines": "Cuando se habilita, recorta todas las nuevas lĆ­neas despuĆ©s de la Ćŗltima nueva lĆ­nea al final del archivo al guardarlo", "files.autoSave.off": "Un archivo con modificaciones no se guarda nunca automĆ”ticamente.", "files.autoSave.afterDelay": "Un archivo con modificaciones se guarda automĆ”ticamente tras la propiedad \"files.autoSaveDelay\" configurada.", "files.autoSave.onFocusChange": "Un archivo con modificaciones se guarda automĆ”ticamente cuando el editor deja de fijarse en Ć©l.", @@ -38,5 +39,15 @@ "openEditorsVisible": "NĆŗmero de editores mostrados en el panel Editores abiertos. Establezca este valor en 0 para ocultar el panel.", "dynamicHeight": "Controla si la altura de la sección de editores abiertos deberĆ­a adaptarse o no de forma dinĆ”mica al nĆŗmero de elementos.", "autoReveal": "Controla si el explorador debe mostrar y seleccionar automĆ”ticamente los archivos al abrirlos.", - "enableDragAndDrop": "Controla si el explorador debe permitir mover archivos y carpetas mediante la función arrastrar y colocar." + "enableDragAndDrop": "Controla si el explorador debe permitir mover archivos y carpetas mediante la función arrastrar y colocar.", + "confirmDragAndDrop": "Controla si el explorador debe pedir la confirmación al reubicar archivos o carpetas a travĆ©s de arrastrar y soltar.", + "confirmDelete": "Controla si el explorador debe pedir la confirmación al borrar un archivo utilizando la papelera.", + "sortOrder.default": "Los archivos y las carpetas se ordenan por nombre alfabĆ©ticamente. Las carpetas se muestran antes que los archivos.", + "sortOrder.mixed": "Los archivos y las carpetas se ordenan por nombre alfabĆ©ticamente. Los archivos se entrelazan con las carpetas.", + "sortOrder.filesFirst": "Los archivos y las carpetas se ordenan por nombre alfabĆ©ticamente. Los archivos se muestran antes que las carpetas.", + "sortOrder.type": "Los archivos y las carpetas se ordenan por extensión. Las carpetas se muestran antes que los archivos.", + "sortOrder.modified": "Los archivos y las carpetas se ordenan por fecha de Ćŗltima modificación. Las carpetas se muestran antes que los archivos.", + "sortOrder": "Controla el criterio de ordenación de los archivos y las carpetas en el explorador. AdemĆ”s del orden \"default\", puede establecer el orden en \"mixed\" (los archivos y las carpetas se ordenan combinados), \"type\" (por tipo de archivo), \"modified\" (por fecha de Ćŗltima modificación) o \"filesFirst\" (los archivos se colocan antes que las carpetas).", + "explorer.decorations.colors": "Controla si las decoraciones de archivo deben utilizar colores. ", + "explorer.decorations.badges": "Controla si las decoraciones de archivo deben utilizar insignias" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index e5705ac4c78..186f5cdaa42 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "Use las acciones de la barra de herramientas del editor situada a la derecha para **deshacer** los cambios o **sobrescribir** el contenido del disco con sus cambios", "discard": "Descartar", "overwrite": "Sobrescribir", "retry": "Reintentar", diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index ed00449cce3..bed30ddc028 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "No hay ninguna carpeta abierta", "explorerSection": "Sección del Explorador de archivos", - "noWorkspaceHelp": "TodavĆ­a no ha abierto ninguna carpeta.", + "noWorkspaceHelp": "TodavĆ­a no ha agregado una carpeta al espacio de trabajo.", + "addFolder": "Agregar Carpeta", + "noFolderHelp": "TodavĆ­a no ha abierto ninguna carpeta.", "openFolder": "Abrir carpeta" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..e05ecb0ff0e --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Explorador", + "canNotResolve": "No se puede resolver la carpeta de trabajo" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 6dd654390f1..f1bacff5d9e 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,13 @@ { "fileInputAriaLabel": "Escriba el nombre de archivo. Presione ENTRAR para confirmar o Esc para cancelar", "filesExplorerViewerAriaLabel": "{0}, Explorador de archivos", + "dropFolders": "ĀæQuiere agregar las carpetas al Ć”rea de trabajo?", + "dropFolder": "ĀæQuiere agregar la carpeta al Ć”rea de trabajo?", + "addFolders": "&&Agregar carpetas", + "addFolder": "&&Agregar carpeta", + "confirmMove": "ĀæEstĆ” seguro de que desea mover '{0}'?", + "doNotAskAgain": "No volver a preguntarme", + "moveButtonLabel": "&&Mover", "confirmOverwriteMessage": "'{0}' ya existe en la carpeta de destino. ĀæDesea reemplazarlo?", "irreversible": "Esta acción es irreversible.", "replaceButtonLabel": "Reemplazar" diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json index f3bd7912e40..f43443fbdd0 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json @@ -9,6 +9,7 @@ "saveAll": "Guardar todos", "closeAllUnmodified": "Cerrar los que no se han modificado", "closeAll": "Cerrar todo", + "compareWithSaved": "Comparar con el guardado", "close": "Cerrar", "closeOthers": "Cerrar otros" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/esn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 2f30ba5cf14..11009de442e 100644 --- a/i18n/esn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 archivo no guardado", "dirtyFiles": "{0} archivos no guardados" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/esn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..710f5b027a0 --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Problemas", + "tooltip.1": "1 problema en este fichero", + "tooltip.N": "{0} problemas en este fichero", + "markers.showOnFile": "Mostrar Errores y Advertencias en la carpeta y ficheros." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/esn/src/vs/workbench/parts/markers/common/messages.i18n.json index 699e66d3665..967a2c1221b 100644 --- a/i18n/esn/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "Ver", + "problems.view.toggle.label": "Alternar ProblemasĀ ", "problems.view.show.label": "Mostrar problemas", + "problems.view.hide.label": "Ocultar problemas", "problems.panel.configuration.title": "Vista Problemas", "problems.panel.configuration.autoreveal": "Controla si la vista Problemas debe revelar automĆ”ticamente los archivos cuando los abre", "markers.panel.title.problems": "Problemas", diff --git a/i18n/esn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/esn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index 027c80cca30..2b8d1b482f6 100644 --- a/i18n/esn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "Copiar" + "copyMarker": "Copiar", + "copyMarkerMessage": "Copiar mensaje" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index 81f5a667ca8..8aa6eb775be 100644 --- a/i18n/esn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "Inicio lento detectado", - "slow.detail": "Lamentamos que haya tenido un inicio lento. Reinicie \"{0}\" con la generación de perfiles habilitada, comparta los perfiles con nosotros y trabajaremos a fondo para que vuelva a disfrutar de un inicio increĆ­ble.", "prof.message": "Los perfiles se crearon correctamente.", "prof.detail": "Cree un problema y asóciele manualmente los siguientes archivos: {0}", "prof.restartAndFileIssue": "Crear problema y reiniciar", diff --git a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 31318057630..402cc5d581e 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -8,6 +8,7 @@ "openGlobalKeybindings": "Abrir mĆ©todos abreviados de teclado", "openGlobalKeybindingsFile": "Abrir el archivo de mĆ©todos abreviados de teclado", "openWorkspaceSettings": "Abrir configuración del Ć”rea de trabajo", + "openFolderSettings": "Abrir Configuración de carpeta", "configureLanguageBasedSettings": "Configurar opciones especĆ­ficas del lenguaje...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Seleccionar lenguaje" diff --git a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index e23a93a70a0..35264ae0434 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -13,5 +13,6 @@ "settingsFound": "{0} configuraciones coincidentes", "fileEditorWithInputAriaLabel": "{0}. Editor de archivos de texto.", "fileEditorAriaLabel": "Editor de archivos de texto.", + "defaultEditorReadonly": "Editar en el editor de lado de mano derecha para reemplazar valores predeterminados.", "preferencesAriaLabel": "Preferencias predeterminadas. Editor de texto de solo lectura." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index e2e21899134..c1606c5e1a9 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,12 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "No se puede escribir la configuración. Corrija los errores o advertencias del archivo y vuelva a intentarlo.", + "emptyUserSettingsHeader": "Coloque aquĆ­ su configuración para sobrescribir la configuración predeterminada.", + "emptyWorkspaceSettingsHeader": "Coloque aquĆ­ su configuración para sobrescribir la configuración de usuario.", + "emptyFolderSettingsHeader": "Coloque aquĆ­ su configuración de carpeta para sobrescribir la que se especifica en la configuración de Ć”rea de trabajo.", + "defaultFolderSettingsTitle": "Configuración de carpeta predeterminada", "defaultSettingsTitle": "Configuración predeterminada", - "noSettingsFound": "No se encontró ninguna configuración.", "editTtile": "Editar", "replaceDefaultValue": "Reemplazar en Configuración", "copyDefaultValue": "Copiar en Configuración", "unsupportedPHPExecutablePathSetting": "Este valor debe estar en la configuración de usuario. Si quiere configurar PHP para el Ć”rea de trabajo, abra un archivo PHP y haga clic en \"Ruta de acceso PHP\" en la barra de estado.", - "unsupportedWorkspaceSetting": "Este valor debe estar en Configuración de usuario." + "unsupportedWorkspaceSetting": "Este valor debe estar en Configuración de usuario.", + "unsupportedWorkbenchSetting": "Esta configuración no se puede aplicar ahora. Se aplicarĆ” al abrir esta carpeta directamente.", + "unsupportedWorkbenchSettingDevMode": "Esta configuración no se puede aplicar ahora. Se aplicarĆ” si se define su alcance como 'recurso' o al abrir esta carpeta directamente. " } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json index 7edb56fa420..d53ba6ae07b 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json @@ -7,5 +7,6 @@ "openFolderFirst": "Abrir una carpeta antes de crear la configuración del Ć”rea de trabajo", "emptyKeybindingsHeader": "Coloque sus enlaces de teclado en este archivo para sobrescribir los valores predeterminados.", "defaultKeybindings": "Enlaces de teclado predeterminados", + "folderSettingsName": "{0} (Configuración de carpeta)", "fail.createSettings": "No se puede crear '{0}' ({1})." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 8b6ad71cd4e..41053cf2b5e 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "defaultSettingsFuzzyPrompt": "Pruebe la bĆŗsqueda parcial", + "defaultSettings": "Colocar la configuración en el editor de lado de mano derecha para anular.", + "noSettingsFound": "No se encontró ninguna configuración.", + "folderSettingsDetails": "Configuración de carpeta", + "enableFuzzySearch": "Habilitar bĆŗsqueda parcial experimental" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index a88bc4a6285..575bc61fdb4 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "MĆ”s utilizada", - "noSettings": "No hay configuración", + "mostRelevant": "MĆ”s relevante", "defaultKeybindingsHeader": "Coloque los enlaces de teclado en el archivo de enlaces de teclado para sobrescribirlos." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 5b11b46879d..e0012dd14f7 100644 --- a/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "El comando '{0}' no estĆ” habilitado en el contexto actual.", "recentlyUsed": "usado recientemente", "morecCommands": "otros comandos", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "No hay comandos coincidentes" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 498d20e2ecd..2535a2c82d0 100644 --- a/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,6 +6,5 @@ { "relaunchSettingMessage": "Ha cambiado un ajuste que requiere un reinicio para ser efectivo.", "relaunchSettingDetail": "Pulse el botón de reinicio para reiniciar {0} y habilitar el ajuste.", - "restart": "Reiniciar", - "reload": "Recargar" + "restart": "&& Reiniciar" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 5fe13ab86c4..b5e6ea1e405 100644 --- a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} de {1} cambios", + "change": "{0} de {1} cambio", + "show previous change": "Mostrar el cambio anterior", + "show next change": "Mostrar el cambio siguiente", "editorGutterModifiedBackground": "Color de fondo del medianil del editor para las lĆ­neas modificadas.", "editorGutterAddedBackground": "Color de fondo del medianil del editor para las lĆ­neas agregadas.", - "editorGutterDeletedBackground": "Color de fondo del medianil del editor para las lĆ­neas eliminadas." + "editorGutterDeletedBackground": "Color de fondo del medianil del editor para las lĆ­neas eliminadas.", + "overviewRulerModifiedForeground": "Color de marcador de regla de información general para contenido modificado.", + "overviewRulerAddedForeground": "Color de marcador de regla de información general para contenido agregado.", + "overviewRulerDeletedForeground": "Color de marcador de regla de información general para contenido eliminado." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index a77a2211780..2d44f58d514 100644 --- a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Mostrar GIT", - "installAdditionalSCMProviders": "Instalar proveedores adicionales de SCM...", "source control": "Control de código fuente", "toggleSCMViewlet": "Mostrar SCM", "view": "Ver" diff --git a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 745b72f2319..6b08e43a291 100644 --- a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Proveedores de Control de Código fuente", + "hideRepository": "Ocultar", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "Instalar proveedores adicionales de SCM...", + "no open repo": "No hay proveedores de control de código fuente activos.", "source control": "Control de código fuente", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index a5577a453c9..1a0bd6edd0f 100644 --- a/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "Ir al sĆ­mbolo en el Ć”rea de trabajo...", "name": "Buscar", - "showSearchViewlet": "Mostrar bĆŗsqueda", + "search": "Buscar", "view": "Ver", - "findInFiles": "Buscar en archivos", "openAnythingHandlerDescription": "Ir al archivo", "openSymbolDescriptionNormal": "Ir al sĆ­mbolo en el Ć”rea de trabajo", "searchOutputChannelTitle": "Buscar", @@ -16,7 +15,9 @@ "exclude": "Configure patrones globales para excluir archivos y carpetas de las bĆŗsquedas. Hereda todos los patrones globales de la configuración files.exclude.", "exclude.boolean": "El patrón global con el que se harĆ”n coincidir las rutas de acceso de los archivos. EstablĆ©zcalo en true o false para habilitarlo o deshabilitarlo.", "exclude.when": "Comprobación adicional de los elementos del mismo nivel de un archivo coincidente. Use $(nombreBase) como variable para el nombre de archivo que coincide.", - "useRipgrep": "Controla si debe utilizarse ripgrep en la bĆŗsqueda de texto", - "useIgnoreFilesByDefault": "Controla si usar los archivos .gitignore y .ignore de forma predeterminada al buscar en una nueva Ć”rea de trabajo.", - "search.quickOpen.includeSymbols": "Configurar para incluir los resultados de una bĆŗsqueda global de sĆ­mbolos en los resultados de archivos de Quick Open." + "useRipgrep": "Controla si se utiliza ripgrep en la bĆŗsqueda de texto y ficheros", + "useIgnoreFilesByDefault": "Controla si se utilizan los archivos .gitignore e .ignore de forma predeterminada al buscar en una nueva Ć”rea de trabajo.", + "useIgnoreFiles": "Controla si se utilizan los archivos .gitignore e .ignore al buscar archivos.", + "search.quickOpen.includeSymbols": "Configurar para incluir los resultados de una bĆŗsqueda global de sĆ­mbolos en los resultados de archivos de Quick Open.", + "search.followSymlinks": "Controla si va a seguir enlaces simbólicos durante la bĆŗsqueda." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 676bea02e78..7d28af93190 100644 --- a/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,16 +4,26 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "Mostrar siguiente bĆŗsqueda de patrón include", + "previousSearchIncludePattern": "Mostrar bĆŗsqueda anterior de patrón include ", + "nextSearchExcludePattern": "Mostrar siguiente bĆŗsqueda de patrón exclude ", + "previousSearchExcludePattern": "Mostrar bĆŗsqueda anterior de patrón exclude ", "nextSearchTerm": "Mostrar siguiente tĆ©rmino de bĆŗsqueda", "previousSearchTerm": "Mostrar anterior tĆ©rmino de bĆŗsqueda", "focusNextInputBox": "Centrarse en el siguiente cuadro de entrada", "focusPreviousInputBox": "Centrarse en el anterior cuadro de entrada", + "showSearchViewlet": "Mostrar bĆŗsqueda", + "findInFiles": "Buscar en archivos", + "findInFilesWithSelectedText": "Buscar en ficheros de texto seleccionado", "replaceInFiles": "Reemplazar en archivos", + "replaceInFilesWithSelectedText": "Reemplazar en archivos con el texto seleccionado", + "findInWorkspace": "Buscar en Ć”rea de trabajo...", + "findInFolder": "Buscar en carpeta...", "RefreshAction.label": "Actualizar", "ClearSearchResultsAction.label": "Borrar resultados de la bĆŗsqueda", "FocusNextSearchResult.label": "Centrarse en el siguiente resultado de la bĆŗsqueda", "FocusPreviousSearchResult.label": "Centrarse en el anterior resultado de la bĆŗsqueda", - "RemoveAction.label": "Quitar", + "RemoveAction.label": "Despedir", "file.replaceAll.label": "Reemplazar todo", "match.replace.label": "Reemplazar" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json b/i18n/esn/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json index 06b841c9cab..97148bc69de 100644 --- a/i18n/esn/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "searchFolderMatch.other.label": "Otros archivos", + "searchFileMatches": "{0} archivos encontrados", + "searchFileMatch": "{0} archivo encontrado", "searchMatches": "{0} coincidencias encontradas", "searchMatch": "{0} coincidencia encontrada", + "folderMatchAriaLabel": "{0} coincidencias en la carpeta raĆ­z {1}, resultados de la bĆŗsqueda", "fileMatchAriaLabel": "{0} coincidencias en el archivo {1} de la carpeta {2}, resultados de la bĆŗsqueda", "replacePreviewResultAria": "Reemplazar el termino {0} con {1} en la columna con posición {2} en la lĆ­nea de texto {3}", "searchResultAria": "Encontró el tĆ©rmino {0} en la columna de posición {1} en la lĆ­nea con el texto {2}." diff --git a/i18n/esn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/esn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 9dce8d0622c..a8d279eeb38 100644 --- a/i18n/esn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "archivos para excluir", "label.excludes": "Buscar patrones de exclusión", "replaceAll.confirmation.title": "Reemplazar todo", - "replaceAll.confirm.button": "Reemplazar", + "replaceAll.confirm.button": "&&Reemplazar", "replaceAll.occurrence.file.message": "{0} aparición reemplazada en {1} archivo por \"{2}\".", "removeAll.occurrence.file.message": "{0} aparición reemplazada en {1} archivo.", "replaceAll.occurrence.files.message": "{0} aparición reemplazada en {1} archivos por \"{2}\".", @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "ĀæReemplazar {0} apariciones en {1} archivos por \"{2}\"?", "replaceAll.occurrences.files.confirmation.message": "ĀæReemplazar {0} apariciones en {1} archivos?", "treeAriaLabel": "Resultados de la bĆŗsqueda", + "searchPathNotFoundError": "No se encuentra la ruta de bĆŗsqueda: {0}", "searchMaxResultsWarning": "El conjunto de resultados solo contiene un subconjunto de todas las coincidencias. Sea mĆ”s especĆ­fico en la bĆŗsqueda para acotar los resultados.", "searchCanceled": "La bĆŗsqueda se canceló antes de poder encontrar resultados - ", "noResultsIncludesExcludes": "No se encontraron resultados en '{0}' con exclusión de '{1}' - ", "noResultsIncludes": "No se encontraron resultados en '{0}' - ", "noResultsExcludes": "No se encontraron resultados con exclusión de '{0}' - ", - "noResultsFound": "No se encontraron resultados. Revise los ajustes de las exclusiones configuradas - ", + "noResultsFound": "No se encontraron resultados. Revise la configuración de exclusiones y archivos omitidos - ", "rerunSearch.message": "Buscar de nuevo", "rerunSearchInAll.message": "Buscar de nuevo en todos los archivos", "openSettings.message": "Abrir configuración", + "openSettings.learnMore": "MĆ”s información", "ariaSearchResultsStatus": "La bĆŗsqueda devolvió {0} resultados en {1} archivos", "search.file.result": "{0} resultado en {1} archivo", "search.files.result": "{0} resultado en {1} archivos", diff --git a/i18n/esn/src/vs/workbench/parts/search/browser/searchWidget.i18n.json b/i18n/esn/src/vs/workbench/parts/search/browser/searchWidget.i18n.json index d054ec1c07a..867b4c76388 100644 --- a/i18n/esn/src/vs/workbench/parts/search/browser/searchWidget.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/search/browser/searchWidget.i18n.json @@ -11,5 +11,6 @@ "search.placeHolder": "Buscar", "label.Replace": "Reemplazar: Escriba el tĆ©rmino de reemplazo y presione Intro para obtener una vista previa o Escape para cancelar la acción", "search.replace.placeHolder": "Reemplazar", - "regexp.validationFailure": "La expresión coincide con todo" + "regexp.validationFailure": "La expresión coincide con todo", + "regexp.backreferenceValidationFailure": "No se admiten referencias inversas" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/esn/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..de65c6ed796 --- /dev/null +++ b/i18n/esn/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Ninguna carpeta en el espacio de trabajo tiene el nombre: {0}" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index ef56f7f84bd..34a3208c841 100644 --- a/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "Insertar fragmento de código" + "snippet.suggestions.label": "Insertar fragmento de código", + "sep.userSnippet": "Fragmentos de código de usuario", + "sep.extSnippet": "Fragmentos de código de extensión" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index e8dde5bc0ce..ecf3b81fb81 100644 --- a/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "Lenguaje desconocido en \"contributes.{0}.language\". Valor proporcionado: {1}", + "invalid.path.0": "Se esperaba una cadena en \"contributes.{0}.path\". Valor proporcionado: {1}", + "invalid.path.1": "Se esperaba que \"contributes.{0}.path\" ({1}) se incluyera en la carpeta de la extensión ({2}). Esto puede hacer que la extensión no sea portĆ”til.", + "vscode.extension.contributes.snippets": "Aporta fragmentos de código.", + "vscode.extension.contributes.snippets-language": "Identificador del lenguaje al que se aporta este fragmento de código.", + "vscode.extension.contributes.snippets-path": "Ruta de acceso del archivo de fragmentos de código. La ruta es relativa a la carpeta de extensión y normalmente empieza por \"./snippets/\".", + "badVariableUse": "Uno o mĆ”s fragmentos de la extensión '{0}' muy probable confunden variables de fragmento y fragmento-marcadores de posición (vĆ©ase https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax para mĆ”s detalles)", + "badFile": "No se pudo leer el archivo del fragmento \"{0}\".", "source.snippet": "Fragmento de código del usuario", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 021fb81ebaa..5a1d231ed58 100644 --- a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "Configura el panel que se utiliza para presentar las salidas de la tarea y lee sus entradas.", "JsonSchema.tasks.presentation.echo": "Controla si se presenta en el panel un eco del comando ejecutado. El valor predeterminado es verdadero.", "JsonSchema.tasks.presentation.focus": "Controla si el panel recibe el foco. El valor predeterminado es falso. Si se establece a verdadero, el panel ademĆ”s se revela.", + "JsonSchema.tasks.presentation.reveal.always": "Revela siempre el terminal cuando se ejecuta esta tarea.", + "JsonSchema.tasks.presentation.reveal.silent": "Solo revela el terminal si no hay ningĆŗn buscador de coincidencias de problemas asociado con la tarea y se producen errores al ejecutarla.", + "JsonSchema.tasks.presentation.reveal.never": "No revela nunca el teminal cuando se ejecuta la tarea.", "JsonSchema.tasks.presentation.reveals": "Controla si el panel que ejecuta la tarea se revela o no. El valor predeterminado es \"siempre\".", "JsonSchema.tasks.presentation.instance": "Controla si el panel se comparte entre tareas, estĆ” dedicado a esta tarea, o se crea uno nuevo por cada ejecución.", "JsonSchema.tasks.terminal": "La propiedad terminal estĆ” en desuso. En su lugar, utilice presentation.", @@ -22,7 +25,8 @@ "JsonSchema.tasks.group.test": "Marca las tareas como tarea de prueba accesible a travĆ©s del comando \"Ejecutar tarea de compilación\". ", "JsonSchema.tasks.group.none": "No asigna la tarea a ningĆŗn grupo", "JsonSchema.tasks.group": "Define a quĆ© grupo de ejecución pertenece esta tarea. Admite \"compilación\" para agregarla al grupo de compilación y \"prueba\" para agregarla al grupo de prueba.", - "JsonSchema.tasks.type": "Define si la tarea se ejecuta como un proceso o como un comando dentro de un shell. El valor predeterminado es proceso.", + "JsonSchema.tasks.type": "Define si la tarea se ejecuta como un proceso o como un comando dentro de in shell. ", + "JsonSchema.tasks.label": "Etiqueta de interfaz de usuario de la tarea", "JsonSchema.version": "El nĆŗmero de versión de la configuración.", "JsonSchema.tasks.identifier": "Un identificador definido por el usuario para hacer referencia a la tarea en launch.json o una clĆ”usula dependsOn.", "JsonSchema.tasks.taskLabel": "La etiqueta de la tarea", @@ -35,8 +39,10 @@ "JsonSchema.tasks.customize.deprecated": "La propiedad customize estĆ” en desuso. Consulte las notas de la versión 1.14 sobre cómo migrar al nuevo enfoque de personalización de tareas.", "JsonSchema.tasks.showOputput.deprecated": "La propiedad showOutput estĆ” en desuso. Utilice la propiedad reveal dentro de la propiedad presentation en su lugar. Vea tambiĆ©n las notas de la versión 1.14.", "JsonSchema.tasks.echoCommand.deprecated": "La propiedad echoCommand estĆ” en desuso. Utilice la propiedad echo dentro de la propiedad presentation en su lugar. Vea tambiĆ©n las notas de la versión 1.14.", + "JsonSchema.tasks.suppressTaskName.deprecated": "La propiedad suppressTaskName estĆ” en desuso. En lugar de usar esta propiedad, inserte el comando con los argumentos en la tarea. Vea tambiĆ©n las notas de la versión 1.14.", "JsonSchema.tasks.isBuildCommand.deprecated": "La propiedad isBuildCommand estĆ” en desuso. Utilice la propiedad group en su lugar. Vea tambiĆ©n las notas de la versión 1.14.", "JsonSchema.tasks.isTestCommand.deprecated": "La propiedad isTestCommand estĆ” en desuso. Utilice la propiedad group en su lugar. Vea tambiĆ©n las notas de la versión 1.14.", + "JsonSchema.tasks.taskSelector.deprecated": "La propiedad taskSelector estĆ” en desuso. En lugar de usar esta propiedad, inserte el comando con los argumentos en la tarea. Vea tambiĆ©n las notas de la versión 1.14.", "JsonSchema.windows": "Configuración de comando especĆ­fico de Windows", "JsonSchema.mac": "Configuración de comando especĆ­fico de Mac", "JsonSchema.linux": "Configuración de comando especĆ­fico de Linux" diff --git a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 048794026a3..26d019052c5 100644 --- a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,30 +5,35 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Tareas", - "ConfigureTaskRunnerAction.noWorkspace": "Las tareas solo estĆ”n disponibles en una carpeta del Ć”rea de trabajo.", - "ConfigureTaskRunnerAction.quickPick.template": "Seleccionar un ejecutador de tareas", - "ConfigureTaskRunnerAction.autoDetecting": "Detectando tareas automĆ”ticamente para {0}", - "ConfigureTaskRunnerAction.autoDetect": "Error de detección automĆ”tica del sistema de tareas. Se usa la plantilla predeterminada. Consulte el resultado de la tarea para obtener mĆ”s detalles", - "ConfigureTaskRunnerAction.autoDetectError": "Error de detección automĆ”tica del sistema de tareas. Consulte el resultado de la tarea para obtener mĆ”s detalles", - "ConfigureTaskRunnerAction.failed": "No se puede crear el archivo \"tasks.json\" dentro de la carpeta \".vscode\". Consulte el resultado de la tarea para obtener mĆ”s detalles.", - "ConfigureTaskRunnerAction.label": "Configurar ejecutor de tareas", + "ConfigureTaskRunnerAction.label": "Configurar tarea", "ConfigureBuildTaskAction.label": "Configurar tarea de compilación", "CloseMessageAction.label": "Cerrar", "ShowTerminalAction.label": "Ver terminal", "problems": "Problemas", "manyMarkers": "MĆ”s de 99", + "runningTasks": "Mostrar tareas en ejecución", "tasks": "Tareas", - "TaskSystem.noHotSwap": "El cambio del motor de ejecución de tareas requiere reiniciar VS Code. Se omite el cambio.", + "TaskSystem.noHotSwap": "Cambiar el motor de ejecución de tareas con una tarea activa ejecutandose, requiere recargar la ventana", + "TaskServer.folderIgnored": "La carpeta {0} se pasa por alto puesto que utiliza la versión 0.1.0 de las tareas", "TaskService.noBuildTask1": "No se ha definido ninguna tarea de compilación. Marque una tarea con \"isBuildCommand\" en el archivo tasks.json.", "TaskService.noBuildTask2": "No se ha definido ninguna tarea de compilación. Marque una tarea con un grupo \"build\" en el archivo tasks.json. ", "TaskService.noTestTask1": "No se ha definido ninguna tarea de prueba. Marque una tarea con \"isTestCommand\" en el archivo tasks.json.", "TaskService.noTestTask2": "No se ha definido ninguna tarea de prueba. Marque una tarea con \"test\" en el archivo tasks.json.", "TaskServer.noTask": "No se encuentra la tarea {0} que se ha solicitado para ejecutarla.", + "TaskService.associate": "asociar", + "TaskService.attachProblemMatcher.continueWithout": "Continuar sin examinar la salida de la tarea", + "TaskService.attachProblemMatcher.never": "No examinar nunca la salida de la tarea", + "TaskService.attachProblemMatcher.learnMoreAbout": "MĆ”s información acerca del examen de la salida de la tarea", + "selectProblemMatcher": "Seleccione quĆ© tipo de errores y advertencias deben buscarse durante el examen de la salida de la tarea", "customizeParseErrors": "La configuración actual de tareas contiene errores. Antes de personalizar una tarea, corrija los errores.", "moreThanOneBuildTask": "Hay muchas tareas de compilación definidas en el archivo tasks.json. Se ejecutarĆ” la primera.\n", + "TaskSystem.activeSame.background": "La tarea \"{0}\" ya estĆ” activa en segundo plano. Para terminarla, use la opción \"Terminar tarea\" del menĆŗ Tareas.", + "TaskSystem.activeSame.noBackground": "La tarea \"{0}\" ya estĆ” activa. Para terminarla, use la opción \"Terminar tarea\" del menĆŗ Tareas.", "TaskSystem.active": "Ya hay una tarea en ejecución. FinalĆ­cela antes de ejecutar otra tarea.", "TaskSystem.restartFailed": "No se pudo terminar y reiniciar la tarea {0}", + "TaskService.noConfiguration": "Error: La detección de tarea {0} no encontró una tarea para la siguiente configuración:\n{1}\nLa tarea serĆ” omitida.\n", "TaskSystem.configurationErrors": "Error: La configuración de la tarea proporcionada tiene errores de validación y no se puede usar. Corrija los errores primero.", + "taskService.ignoreingFolder": "Ignorando las configuraciones de tarea para la carpeta del area de trabajo {0}. El soporte de tarea de area de trabajo multi carpeta requiere que todas las carpetas usen la versión de tarea 2.0.0 ", "TaskSystem.invalidTaskJson": "Error: El contenido del archivo tasks.json tiene errores de sintaxis. CorrĆ­jalos antes de ejecutar una tarea.", "TaskSystem.runningTask": "Hay una tarea en ejecución. ĀæQuiere finalizarla?", "TaskSystem.terminateTask": "&&Finalizar tarea", @@ -40,25 +45,37 @@ "recentlyUsed": "Tareas usadas recientemente", "configured": "tareas configuradas", "detected": "tareas detectadas", + "TaskService.ignoredFolder": "Las siguientes carpetas del espacio de trabajo se omiten ya que utilizan la versión 0.1.0 de tarea: ", + "TaskService.notAgain": "No volver a mostrar", + "TaskService.ok": "Aceptar", + "TaskService.pickRunTask": "Seleccione la tarea a ejecutar", + "TaslService.noEntryToRun": "No se encontraron tareas para ejecutar. Configurar tareas...", "TaskService.fetchingBuildTasks": "Obteniendo tareas de compilación...", - "TaskService.noBuildTaskTerminal": "No se encontraron Tareas de Compilación. Pulse 'Configurar Tarea de Compilación' para definir una.", "TaskService.pickBuildTask": "Seleccione la tarea de compilación para ejecutar", + "TaskService.noBuildTask": "No se encontraron tareas de compilación para ejecutar. Configurar tareas...", "TaskService.fetchingTestTasks": "Capturando tareas de prueba...", - "TaskService.noTestTaskTerminal": "No se encontraron tareas de prueba. Presione \"Configurar ejecutor de tareas\" para definir una.", "TaskService.pickTestTask": "Seleccione la tarea de prueba para ejecutar", - "TaskService.noTaskRunning": "Ninguna tarea se estĆ” ejecutando actualmente.", + "TaskService.noTestTaskTerminal": "No se encontraron tareas de prueba para ejecutar. Configurar tareas...", "TaskService.tastToTerminate": "Seleccione la tarea para finalizar", + "TaskService.noTaskRunning": "Ninguna tarea se estĆ” ejecutando actualmente", "TerminateAction.noProcess": "El proceso iniciado ya no existe. Si la tarea generó procesos en segundo plano al salir de VS Code, puede dar lugar a procesos huĆ©rfanos.", "TerminateAction.failed": "No se pudo finalizar la tarea en ejecución", - "TaskService.noTaskToRestart": "No hay tareas para reiniciar.", "TaskService.tastToRestart": "Seleccione la tarea para reiniciar", - "TaskService.defaultBuildTaskExists": "{0} ya se ha marcado como la tarea de compilación predeterminada.", + "TaskService.noTaskToRestart": "No hay tareas para reiniciar", + "TaskService.template": "Seleccione una plantilla de tarea", + "TaskService.createJsonFile": "Crear archivo tasks.json desde plantilla", + "TaskService.openJsonFile": "Abrir archivo tasks.json", + "TaskService.pickTask": "Seleccione una tarea para configurar", + "TaskService.defaultBuildTaskExists": "{0} estĆ” marcado ya como la tarea de compilación predeterminada", "TaskService.pickDefaultBuildTask": "Seleccione la tarea que se va a utilizar como tarea de compilación predeterminada", "TaskService.defaultTestTaskExists": "{0} ya se ha marcado como la tarea de prueba predeterminada.", "TaskService.pickDefaultTestTask": "Seleccione la tarea que se va a usar como la tarea de prueba predeterminada ", + "TaskService.pickShowTask": "Seleccione la tarea de la que desea ver la salida", + "TaskService.noTaskIsRunning": "Ninguna tarea se estĆ” ejecutando", "ShowLogAction.label": "Mostrar registro de tareas", "RunTaskAction.label": "Ejecutar tarea", "RestartTaskAction.label": "Reiniciar la tarea en ejecución", + "ShowTasksAction.label": "Mostrar tareas en ejecución", "BuildAction.label": "Ejecutar tarea de compilación", "TestAction.label": "Ejecutar tarea de prueba", "ConfigureDefaultBuildTask.label": "Configurar tarea de compilación predeterminada", diff --git a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 99a6eef0566..a3bf48c132e 100644 --- a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Error desconocido durante la ejecución de una tarea. Vea el registro de resultados de la tarea para obtener mĆ”s detalles.", + "dependencyFailed": "No se pudo resolver la tarea dependiente '{0}' en la carpeta del Ć”rea de trabajo '{1}'", "TerminalTaskSystem.terminalName": "Tarea - {0}", "reuseTerminal": "Las tareas reutilizarĆ”n el terminal, presione cualquier tecla para cerrarlo.", "TerminalTaskSystem": "No se puede ejecutar un comando shell en una unidad UNC.", diff --git a/i18n/esn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/esn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index bb2599901ca..f6279ef6605 100644 --- a/i18n/esn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,9 +11,12 @@ "ConfigurationParser.unknownMatcherKind": "Advertencia: El buscador de coincidencias de problemas definido se desconoce. Los tipos admitidos son string | ProblemMatcher | (string | ProblemMatcher). {0}", "ConfigurationParser.invalidVaraibleReference": "Error: Referencia a problemMatcher no vĆ”lida: {0}", "ConfigurationParser.noTaskType": "Error: Las tareas deben tener una propiedad type. La configuración se omitirĆ”.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "Error: No hay ningĆŗn tipo de tarea \"{0}\" registrado. ĀæOmitió la instalación de una extensión que proporciona un proveedor de tareas correspondiente?", + "ConfigurationParser.missingRequiredProperty": "Error: la configuración de la tarea '{0}' no contiene la propiedad requerida '{1}'. Se omitirĆ” la configuración de la tarea.", "ConfigurationParser.notCustom": "Error: Las tareas no se declaran como una tarea personalizada. La configuración se omitirĆ”.\n{0}\n", "ConfigurationParser.noTaskName": "Error: Las tareas deben proporcionar una propiedad taskName. La tarea se ignorarĆ”. {0}", "taskConfiguration.shellArgs": "Advertencia: La tarea \"{0}\" es un comando de shell y su nombre de comando o uno de sus argumentos tiene espacios sin escape. Para asegurarse de que la lĆ­nea de comandos se cite correctamente, combine mediante fusión los argumentos en el comando.", "taskConfiguration.noCommandOrDependsOn": "Error: La tarea \"{0}\" no especifica un comando ni una propiedad dependsOn. La tarea se ignorarĆ”. Su definición es: \n{1}", - "taskConfiguration.noCommand": "Error: La tarea \"{0}\" no define un comando. La tarea se ignorarĆ”. Su definición es: {1}" + "taskConfiguration.noCommand": "Error: La tarea \"{0}\" no define un comando. La tarea se ignorarĆ”. Su definición es: {1}", + "TaskParse.noOsSpecificGlobalTasks": "La versión de tarea 2.0.0 no admite tareas especĆ­ficas de SO globales. ConviĆ©rtalas en una tarea con un comando especĆ­fico de SO. Estas son las tareas afectadas:\n{0}" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 8b6ad71cd4e..34f865d0af2 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "termEntryAriaLabel": "{0}, selector de terminal", + "termCreateEntryAriaLabel": "{0}, crear nueva terminal", + "'workbench.action.terminal.newplus": "$(plus) crear nueva Terminal integrada", + "noTerminalsMatching": "No hay terminales coincidentes", + "noTerminalsFound": "No hay terminales abiertos" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 120d6ffbb3d..5de633af6fd 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -4,18 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "quickOpen.terminal": "Mostrar todos los terminales abiertos", + "terminal": "Terminal", "terminalIntegratedConfigurationTitle": "Terminal integrado", "terminal.integrated.shell.linux": "La ruta de acceso del shell que el terminal usa en Linux.", "terminal.integrated.shellArgs.linux": "Los argumentos de la lĆ­nea de comandos que se usarĆ”n en el terminal de Linux.", "terminal.integrated.shell.osx": "La ruta de acceso del shell que el terminal usa en OS X.", "terminal.integrated.shellArgs.osx": "Los argumentos de la lĆ­nea de comandos que se usarĆ”n en el terminal de OS X.", + "terminal.integrated.shell.windows": "Ruta de acceso del shell que el terminal utiliza en Windows. Cuando se usan shells distribuidos con Windows (cmd, PowerShell o Bash en Ubuntu).", "terminal.integrated.shellArgs.windows": "Argumentos de la lĆ­nea de comandos que se usan cuando se utiliza el terminal Windows.", "terminal.integrated.rightClickCopyPaste": "Si estĆ” configurado, impedirĆ” que el menĆŗ contextual aparezca al hacer clic con el botón derecho dentro del terminal; en su lugar, copiarĆ” si hay una selección y pegarĆ” si no hay ninguna selección.", "terminal.integrated.fontFamily": "Controla la familia de fuentes del terminal, que estĆ” establecida de manera predeterminada en el valor de editor.fontFamily.", - "terminal.integrated.fontLigatures": "Controla si las ligaduras tipogrĆ”ficas estĆ”n habilitadas en el terminal.", "terminal.integrated.fontSize": "Controla el tamaƱo de la fuente en pĆ­xeles del terminal.", "terminal.integrated.lineHeight": "Controla el alto de lĆ­nea del terminal. Este nĆŗmero se multiplica por el tamaƱo de fuente del terminal para obtener el alto de lĆ­nea real en pĆ­xeles.", - "terminal.integrated.enableBold": "Indica si debe habilitarse el texto en negrita en el terminal. Requiere soporte del terminal Shell.", + "terminal.integrated.enableBold": "Indica si debe habilitar el texto en negrita en el terminal. Requiere soporte del terminal Shell. ", "terminal.integrated.cursorBlinking": "Controla si el cursor del terminal parpadea.", "terminal.integrated.cursorStyle": "Controla el estilo de cursor del terminal.", "terminal.integrated.scrollback": "Controla la cantidad mĆ”xima de lĆ­neas que mantiene el terminal en su bĆŗfer.", @@ -23,7 +25,9 @@ "terminal.integrated.cwd": "Una ruta de acceso de inicio explĆ­cita en la que se iniciarĆ” el terminal; se utiliza como el directorio de trabajo actual (cwd) para el proceso de shell. Puede resultar especialmente Ćŗtil en una configuración de Ć”rea de trabajo si la raĆ­z de directorio no es un cwd prĆ”ctico.", "terminal.integrated.confirmOnExit": "Indica si debe confirmarse a la salida si hay sesiones de terminal activas.", "terminal.integrated.commandsToSkipShell": "Conjunto de identificadores de comando cuyos enlaces de teclado no se enviarĆ”n al shell, sino que siempre se controlarĆ”n con Code. Esto permite el uso de enlaces de teclado que normalmente consumirĆ­a el shell para funcionar igual que cuando el terminal no tiene el foco; por ejemplo, Ctrl+P para iniciar Quick Open.", - "terminal": "Terminal", + "terminal.integrated.env.osx": "Objeto con variables de entorno que se agregarĆ”n al proceso de VS Code para que las use el terminal en OS X", + "terminal.integrated.env.linux": "Objeto con variables de entorno que se agregarĆ”n al proceso de VS Code para que las use el terminal en Linux", + "terminal.integrated.env.windows": "Objeto con variables de entorno que se agregarĆ”n al proceso de VS Code para que las use el terminal en Windows", "terminalCategory": "Terminal", "viewCategory": "Ver" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index a2abb93e39c..c3d0cfd1e37 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "Alternar terminal integrado", "workbench.action.terminal.kill": "Terminar la instancia del terminal activo", "workbench.action.terminal.kill.short": "Terminar el terminal", + "workbench.action.terminal.quickKill": "Terminar la instancia del terminal", "workbench.action.terminal.copySelection": "Copiar selección", "workbench.action.terminal.selectAll": "Seleccionar todo", + "workbench.action.terminal.deleteWordLeft": "Eliminar una palabra a la izquierda", + "workbench.action.terminal.deleteWordRight": "Eliminar una palabra a la derecha", "workbench.action.terminal.new": "Crear nuevo terminal integrado", "workbench.action.terminal.new.short": "Nuevo terminal", "workbench.action.terminal.focus": "Enfocar terminal", "workbench.action.terminal.focusNext": "Enfocar terminal siguiente", - "workbench.action.terminal.focusAtIndex": "Enfocar terminal {0}", "workbench.action.terminal.focusPrevious": "Enfocar terminal anterior", "workbench.action.terminal.paste": "Pegar en el terminal activo", "workbench.action.terminal.DefaultShell": "Seleccionar el shell predeterminado", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "Cambiar nombre", "workbench.action.terminal.rename.prompt": "Introducir nombre del terminal", "workbench.action.terminal.focusFindWidget": "Foco Encontrar Widget", - "workbench.action.terminal.hideFindWidget": "Ocultar Encontrar Widget" + "workbench.action.terminal.hideFindWidget": "Ocultar Encontrar Widget", + "nextTerminalFindTerm": "Mostrar siguiente tĆ©rmino de bĆŗsqueda", + "previousTerminalFindTerm": "Mostrar tĆ©rmino de bĆŗsqueda anterior", + "quickOpenTerm": "Cambiar terminal activo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index d371b1e3d8c..b41adfc8dd9 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -6,5 +6,8 @@ { "terminal.background": "El color de fondo del terminal, esto permite colorear el terminal de forma diferente al panel.", "terminal.foreground": "El color de primer plano del terminal.", + "terminalCursor.foreground": "Color de primer plano del cursor del terminal.", + "terminalCursor.background": "Color de fondo del cursor del terminal. Permite personalizar el color de un carĆ”cter solapado por un cursor de bloque.", + "terminal.selectionBackground": "Color de fondo de selección del terminal.", "terminal.ansiColor": "Color ANSI \"{0}\" en el terminal." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 1b04639ccd5..a2ea49d47f1 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copiar", - "createNewTerminal": "Nuevo terminal", "paste": "Pegar", "selectAll": "Seleccionar todo", "clear": "Borrar" diff --git a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 6b1dbc4c66a..1a5374df014 100644 --- a/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "De acuerdo, no volver a mostrar este mensaje", "terminal.integrated.chooseWindowsShell": "Seleccione el shell de terminal que desee, puede cambiarlo mĆ”s adelante en la configuración", "terminalService.terminalCloseConfirmationSingular": "Hay una sesión de terminal activa, Āæquiere terminarla?", - "terminalService.terminalCloseConfirmationPlural": "Hay {0} sesiones de terminal activas, Āæquiere terminarlas?", - "yes": "SĆ­" + "terminalService.terminalCloseConfirmationPlural": "Hay {0} sesiones de terminal activas, Āæquiere terminarlas?" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json index e99da0524bc..788665ef84b 100644 --- a/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,9 @@ "licenseChanged": "Los tĆ©rminos de licencia han cambiado, revĆ­selos.", "license": "Leer licencia", "neveragain": "No volver a mostrar", + "64bitisavailable": "Ya estĆ” disponible {0} para Windows de 64 bits.", "learn more": "MĆ”s información", + "updateIsReady": "Nueva actualización de {0} disponible.", "thereIsUpdateAvailable": "Hay una actualización disponible.", "updateAvailable": "{0} se actualizarĆ” despuĆ©s de reiniciarse.", "noUpdatesAvailable": "Actualmente no hay actualizaciones disponibles.", diff --git a/i18n/esn/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/esn/src/vs/workbench/parts/views/browser/views.i18n.json index 62933f6b509..f2487840d97 100644 --- a/i18n/esn/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/views/browser/views.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "viewToolbarAriaLabel": "{0} acciones" + "viewToolbarAriaLabel": "{0} acciones", + "hideView": "Ocultar en la barra lateral" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json b/i18n/esn/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json index 9088eb82605..e0975190eb1 100644 --- a/i18n/esn/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json @@ -12,5 +12,6 @@ "vscode.extension.contributes.view.when": "Condición que se debe cumplir para mostrar esta vista", "vscode.extension.contributes.views": "Aporta vistas al editor", "views.explorer": "Vista del explorador", + "views.debug": "Vista de depuración", "locationId.invalid": "`{0}` no es una ubicación de vista vĆ”lida" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 2085fc57b44..ce34af0dd56 100644 --- a/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "Iniciar", "welcomePage.newFile": "Nuevo archivo", "welcomePage.openFolder": "Abrir carpeta...", - "welcomePage.cloneGitRepository": "Clonar el repositorio GIT...", + "welcomePage.addWorkspaceFolder": "Agregar carpeta de espacio de trabajo...", "welcomePage.recent": "Reciente", "welcomePage.moreRecent": "MĆ”s...", "welcomePage.noRecentFolders": "No hay ninguna carpeta reciente", diff --git a/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json index c8a34873f9d..f768bb7f558 100644 --- a/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json @@ -8,5 +8,6 @@ "workbench.startupEditor.none": "Iniciar sin un editor.", "workbench.startupEditor.welcomePage": "Abra la pĆ”gina de bienvenida (predeterminado).", "workbench.startupEditor.newUntitledFile": "Abrir un nuevo archivo sin tĆ­tulo.", + "workbench.startupEditor": "Controla quĆ© editor se muestra al inicio, si no se restaura ninguno de la sesión anterior. Seleccione \"none\" para iniciar sin editor, \"welcomePage\" para abrir la pĆ”gina principal (opción predeterminada), \"newUntitledFile\" para abrir un archivo nuevo sin tĆ­tulo (solo cuando se abre un Ć”rea de trabajo vacĆ­a).", "help": "Ayuda" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index b1be3bd2206..14443a64a66 100644 --- a/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Mostrar extensiones de Azure", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/esn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/esn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 70bde8b3e76..dba5932269b 100644 --- a/i18n/esn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "Ɓrea de juegos interactiva", - "editorWalkThrough.title": "Ɓrea de juegos interactiva" + "editorWalkThrough.title": "Ɓrea de juegos interactiva", + "editorWalkThrough": "Ɓrea de juegos interactiva" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/esn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..9461c69f688 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Resumen de la configuración. Esta etiqueta se usarĆ” en el archivo de configuración como comentario divisor.", + "vscode.extension.contributes.configuration.properties": "Descripción de las propiedades de configuración.", + "scope.window.description": "Configuración especĆ­fica para ventanas, que se puede definir en la configuración de usuario o de Ć”rea de trabajo.", + "scope.resource.description": "Configuración especĆ­fica para recursos, que se puede definir en la configuración de usuario, de Ć”rea de trabajo o de carpeta.", + "scope.description": "Ɓmbito donde es aplicable la configuración. Los Ć”mbitos disponibles son \"window\" y \"resource\".", + "vscode.extension.contributes.configuration": "Aporta opciones de configuración.", + "invalid.title": "configuration.title debe ser una cadena", + "vscode.extension.contributes.defaultConfiguration": "Contribuye a la configuración de los parĆ”metros del editor predeterminados por lenguaje.", + "invalid.properties": "configuration.properties debe ser un objeto", + "invalid.allOf": "'configuration.allOf' estĆ” en desuso y ya no debe ser utilizado. En cambio, pase varias secciones de configuración como un arreglo al punto de contribución 'configuration'.", + "workspaceConfig.folders.description": "Lista de carpetas para cargar en el Ć”rea de trabajo. ", + "workspaceConfig.path.description": "Ruta de acceso de archivo; por ejemplo, \"/raĆ­z/carpetaA\" o \"./carpetaA\" para una ruta de acceso de archivo que se resolverĆ” respecto a la ubicación del archivo del Ć”rea de trabajo.", + "workspaceConfig.name.description": "Un nombre opcional para la carpeta. ", + "workspaceConfig.uri.description": "URI de la carpeta", + "workspaceConfig.settings.description": "Configuración de Ć”rea de trabajo", + "workspaceConfig.extensions.description": "Extensiones del Ć”rea de trabajo", + "unknownWorkspaceProperty": "Propiedad de configuración de espacio de trabajo desconocida" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json index 05e79aa04fc..7393d607455 100644 --- a/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,11 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "Aporta opciones de configuración.", "vscode.extension.contributes.configuration.title": "Resumen de la configuración. Esta etiqueta se usarĆ” en el archivo de configuración como comentario divisor.", "vscode.extension.contributes.configuration.properties": "Descripción de las propiedades de configuración.", - "invalid.type": "si se establece, \"configuration.type\" debe establecerse en \"object\"", + "scope.window.description": "Configuración especĆ­fica para ventanas, que se puede definir en la configuración de usuario o de Ć”rea de trabajo.", + "scope.resource.description": "Configuración especĆ­fica para recursos, que se puede definir en la configuración de usuario, de Ć”rea de trabajo o de carpeta.", + "scope.description": "Ɓmbito donde es aplicable la configuración. Los Ć”mbitos disponibles son \"window\" y \"resource\".", + "vscode.extension.contributes.configuration": "Aporta opciones de configuración.", "invalid.title": "configuration.title debe ser una cadena", "vscode.extension.contributes.defaultConfiguration": "Contribuye a la configuración de los parĆ”metros del editor predeterminados por lenguaje.", - "invalid.properties": "configuration.properties debe ser un objeto" + "invalid.properties": "configuration.properties debe ser un objeto", + "invalid.allOf": "'configuration.allOf' estĆ” en desuso y ya no debe ser utilizado. En cambio, pasar varias secciones de configuración como una matriz al punto de contribución de 'configuración'.", + "workspaceConfig.folders.description": "Lista de carpetas para cargar en el Ć”rea de trabajo. ", + "workspaceConfig.path.description": "Ruta de acceso de archivo; por ejemplo, \"/raĆ­z/carpetaA\" o \"./carpetaA\" para una ruta de acceso de archivo que se resolverĆ” respecto a la ubicación del archivo del Ć”rea de trabajo.", + "workspaceConfig.name.description": "Un nombre opcional para la carpeta. ", + "workspaceConfig.uri.description": "URI de la carpeta", + "workspaceConfig.settings.description": "Configuración de Ć”rea de trabajo", + "workspaceConfig.extensions.description": "Extensiones del Ć”rea de trabajo", + "unknownWorkspaceProperty": "Propiedad de configuración de espacio de trabajo desconocida" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/esn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index c750b75802e..a984f12ff42 100644 --- a/i18n/esn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/esn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,28 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Abrir configuración", + "openTasksConfiguration": "Abrir configuración de tareas", + "openLaunchConfiguration": "Abrir configuración de inicio", "close": "Cerrar", - "saveAndRetry": "Guardar la configuración y reintentar. ", - "errorInvalidConfiguration": "No se pudo guardar la configuración. Abra el archivo **Configuración de usuario** para corregir los errores o advertencias del archivo y vuelva a intentarlo.", - "errorInvalidConfigurationWorkspace": "No se pudo guardar la configuración. Abra **Configuración de Ć”rea de trabajo** para corregir los errores o advertencias del archivo y vuelva a intentarlo.", - "errorConfigurationFileDirty": "No se pudo guardar la configuración porque el archivo se ha modificado. Guarde el archivo **Configuración de usuario** y vuelva a intentarlo.", - "errorConfigurationFileDirtyWorkspace": "No se pudo guardar la configuración porque el archivo se ha modificado. Guarde el archivo **Configuración de Ć”rea de trabajo** y vuelva a intentarlo.", + "open": "Abrir configuración", + "saveAndRetry": "Guardar y reintentar", + "errorUnknownKey": "No se puede escribir en {0} porque {1} no es una configuración registrada.", + "errorInvalidFolderConfiguration": "No se puede escribir en Configuración de carpeta porque {0} no admite el Ć”mbito del recurso de carpeta.", + "errorInvalidUserTarget": "No se puede escribir en Configuración de usuario porque {0} no admite el Ć”mbito global.", + "errorInvalidWorkspaceTarget": "No se puede escribir a la configuración del espacio de trabajo porque {0} no soporta a un espacio de trabajo con multi carpetas.", + "errorInvalidFolderTarget": "No se puede escribir en Configuración de carpeta porque no se ha proporcionado ningĆŗn recurso.", + "errorNoWorkspaceOpened": "No se puede escribir en {0} porque no hay ninguna Ć”rea de trabajo abierta. Abra un Ć”rea de trabajo y vuelva a intentarlo.", + "errorInvalidTaskConfiguration": "No se puede escribir en el archivo de tareas. Por favor, abra el archivo de ** Tareas ** para corregir los errores/advertencias en Ć©l e intĆ©ntelo de nuevo.", + "errorInvalidLaunchConfiguration": "No se puede escribir en el archivo de inicio. Por favor, abra el archivo de ** Inicio** para corregir los errores/advertencias en Ć©l e intĆ©ntelo de nuevo.", + "errorInvalidConfiguration": "No se puede escribir en la configuración de usuario. Por favor, abra el archivo de **Configuración de usuario** para corregir los errores/advertencias en Ć©l e intĆ©ntelo de nuevo.", + "errorInvalidConfigurationWorkspace": "No se puede escribir en la configuración del Ć”rea de trabajo. Por favor, abra el archivo de **Configuración de Ć”rea de trabajo** para corregir los errores/advertencias en Ć©l e intĆ©ntelo de nuevo.", + "errorInvalidConfigurationFolder": "No se puede escribir en la configuración de carpeta. Por favor, abra el archivo de **Configuración de carpeta** para corregir los errores/advertencias en Ć©l e intĆ©ntelo de nuevo.", + "errorTasksConfigurationFileDirty": "No se puede escribir en el archivo de tareas porque el archivo se ha modificado. Por favor, guarde el archivo de **Configuración de Tareas** e intĆ©ntelo de nuevo.", + "errorLaunchConfigurationFileDirty": "No se puede escribir en el archivo de inicio porque el archivo se ha modificado. Por favor, guarde el archivo de **Configuración de inicio** e intĆ©ntelo de nuevo.", + "errorConfigurationFileDirty": "No se puede escribir en la configuración de usuario porque el archivo se ha modificado. Por favor, guarde el archivo de **Configuración de usuario** e intĆ©ntelo de nuevo.", + "errorConfigurationFileDirtyWorkspace": "No se puede escribir en la configuración del Ć”rea de trabajo porque el archivo se ha modificado. Por favor, guarde el archivo de **Configuración del Ć”rea de trabajo** e intĆ©ntelo de nuevo.", + "errorConfigurationFileDirtyFolder": "No se puede escribir en la configuración de carpeta porque el archivo se ha modificado. Por favor, guarde el archivo de **Configuración de carpeta** en la carpeta ** {0} ** e intĆ©ntelo de nuevo.", "userTarget": "Configuración de usuario", - "workspaceTarget": "Configuración de Ć”rea de trabajo" + "workspaceTarget": "Configuración de Ć”rea de trabajo", + "folderTarget": "Configuración de carpeta" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json b/i18n/esn/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json index 8b6ad71cd4e..081d0764166 100644 --- a/i18n/esn/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json +++ b/i18n/esn/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "errorInvalidFile": "No se puede escribir en el archivo. Abra el archivo para corregir los errores o advertencias y vuelva a intentarlo.", + "errorFileDirty": "No se puede escribir en el archivo porque se ha modificado. Guarde el archivo y vuelva a intentarlo." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/esn/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..74a0358730f --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "bubbleTitle": "contiene elementos resaltados" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/esn/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..0d456319334 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "El host de extensiones no se inició en 10 segundos, puede que se detenga en la primera lĆ­nea y necesita un depurador para continuar.", + "extensionHostProcess.startupFail": "El host de extensiones no se inició en 10 segundos, lo cual puede ser un problema.", + "extensionHostProcess.error": "Error del host de extensiones: {0}" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..7204a4d9d39 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "No se pudo analizar {0}: {1}.", + "fileReadFail": "No se puede leer el archivo {0}: {1}.", + "jsonsParseFail": "No se pudo analizar {0} o {1}: {2}.", + "missingNLSKey": "No se encontró un mensaje para la clave {0}." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..0e9ec06b1bf --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "Herramientas de desarrollo", + "restart": "Reiniciar el host de extensiones", + "extensionHostProcess.crash": "El host de extensiones finalizó inesperadamente.", + "extensionHostProcess.unresponsiveCrash": "Se terminó el host de extensiones porque no respondĆ­a.", + "overwritingExtension": "Sobrescribiendo la extensión {0} con {1}.", + "extensionUnderDevelopment": "Cargando la extensión de desarrollo en {0}" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/esn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..1d8632efe35 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "El archivo parece ser binario y no se puede abrir como texto" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json index fc60db843fa..32802572ad8 100644 --- a/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "Recurso de archivo no vĆ”lido ({0})", - "fileIsDirectoryError": "El archivo es un directorio ({0})", + "fileIsDirectoryError": "Archivo es el directorio", "fileNotModifiedError": "Archivo no modificado desde", "fileTooLargeError": "Archivo demasiado grande para abrirlo", "fileBinaryError": "El archivo parece ser binario y no se puede abrir como texto", "fileNotFoundError": "Archivo no encontrado ({0})", + "fileExists": "El archivo a crear ya existe ({0})", "fileMoveConflict": "No se puede mover o copiar. El archivo ya existe en la ubicación de destino. ", "unableToMoveCopyError": "No se puede mover o copiar. El archivo reemplazarĆ­a a la carpeta que lo contiene.", "foldersCopyError": "No se pueden copiar carpetas en el Ć”rea de trabajo. Seleccione archivos individuales para copiarlos.", diff --git a/i18n/esn/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/esn/src/vs/workbench/services/progress/browser/progressService2.i18n.json index ee9bbb9d071..d810290ae9d 100644 --- a/i18n/esn/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/esn/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1} ", + "progress.subtitle": "{0} - {1} ", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/esn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index b64b20cb44d..2c851d60838 100644 --- a/i18n/esn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/esn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "Estilo de fuente de la regla: una opción de \"italic\", \"bold\" y \"underline\", o una combinación de ellas.", - "schema.colors": "Colores para resaltado de sintaxis", - "schema.properties.name": "Descripción de la regla", - "schema.tokenColors.path": "Ruta de acceso de la archivo de tema (relativa al archivo actual)" + "schema.token.settings": "Colores y estilos para el token.", + "schema.token.foreground": "Color de primer plano para el token.", + "schema.token.background.warning": "En este momento los colores de fondo para Token no estĆ”n soportados.", + "schema.token.fontStyle": "Estilo de fuente de la regla: una opción de \"italic\", \"bold\" y \"underline\", o una combinación de ellas.", + "schema.fontStyle.error": "Estilo de fuente debe ser una combinación de 'cursiva', 'negrita' y 'subrayado'", + "schema.properties.name": "Descripción de la regla.", + "schema.properties.scope": "Selector de Ć”mbito con el que se compara esta regla.", + "schema.tokenColors.path": "Ruta a un archivo tmTheme (relativa al archivo actual).", + "schema.colors": "Colores para resaltado de sintaxis" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/esn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 247bf82cb60..870dfc044d0 100644 --- a/i18n/esn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/esn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Cuando se usa una fuente: porcentaje del tamaƱo de fuente para la fuente del texto. Si no se ha establecido, el valor predeterminado es el tamaƱo de la definición de fuente.", "schema.fontId": "Cuando se usa una fuente: el identificador de la fuente. Si no se ha establecido, el valor predeterminado es la primera definición de fuente.", "schema.light": "Asociaciones opcionales para iconos de archivo en temas de colores claros.", - "schema.highContrast": "Asociaciones opcionales para iconos de archivo en temas de color de contraste alto." + "schema.highContrast": "Asociaciones opcionales para iconos de archivo en temas de color de contraste alto.", + "schema.hidesExplorerArrows": "Configura si las flechas del explorador deben quedar ocultas cuando este tema estĆ© activo." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 464fd1a886e..1ef0ff3dbea 100644 --- a/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "Problemas al analizar el archivo de tema JSON: {0}", "error.invalidformat.colors": "Problema al analizar el archivo de tema: {0}. La propiedad \"colors\" no es tipo \"object\".", - "error.invalidformat.tokenColors": "Problema al analizar el archivo de tema: {0}. La propiedad 'tokenColors' deberĆ­a ser una matriz de colores o una ruta de acceso a un archivo texto de tema.", + "error.invalidformat.tokenColors": "Problema al analizar el archivo de tema de color: {0}. La propiedad 'tokenColors' debe ser un array especificando colores o una ruta a un archivo de tema de TextMate", "error.plist.invalidformat": "Problema al analizar el archivo de tema: {0}. \"settings\" no es una matriz.", "error.cannotparse": "Problemas al analizar el archivo de tema: {0}", "error.cannotload": "Problemas al analizar el archivo de tema: {0}:{1}" diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..5be27841f5b --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", + "vscode.extension.contributes.themes.label": "Etiqueta del tema de color tal como se muestra en la interfaz de usuario.", + "vscode.extension.contributes.themes.uiTheme": "Tema base que define los colores que se usan en el editor: 'vs' es el tema de color claro, 'vs-dark' es el tema de color oscuro, 'hc-black' es el tema oscuro de alto contraste.", + "vscode.extension.contributes.themes.path": "Ruta de acceso del archivo tmTheme. La ruta de acceso es relativa a la carpeta de extensión y suele ser './themes/themeFile.tmTheme'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Se esperaba una cadena en \"contributes.{0}.path\". Valor proporcionado: {1}", + "invalid.path.1": "Se esperaba que \"contributes.{0}.path\" ({1}) se incluyera en la carpeta de la extensión ({2}). Esto puede hacer que la extensión no sea portĆ”til." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..541e0ac3d8b --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", + "vscode.extension.contributes.iconThemes.label": "Etiqueta del tema de icono como se muestra en la interfaz de usuario.", + "vscode.extension.contributes.iconThemes.path": "Ruta de acceso del archivo de definición de temas de icono. La ruta de acceso es relativa a la carpeta de extensión y suele ser './icons/awesome-icon-theme.json'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Se esperaba una cadena en \"contributes.{0}.path\". Valor proporcionado: {1}", + "reqid": "Se esperaba una cadena en `contributes.{0}.id`. Valor proporcionado: {1}", + "invalid.path.1": "Se esperaba que \"contributes.{0}.path\" ({1}) se incluyera en la carpeta de la extensión ({2}). Esto puede hacer que la extensión no sea portĆ”til." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index e9c42972e4e..cb85af9d3cd 100644 --- a/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/esn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,29 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", - "vscode.extension.contributes.themes.label": "Etiqueta del tema de color tal como se muestra en la interfaz de usuario.", - "vscode.extension.contributes.themes.uiTheme": "Tema base que define los colores que se usan en el editor: 'vs' es el tema de color claro, 'vs-dark' es el tema de color oscuro, 'hc-black' es el tema oscuro de alto contraste.", - "vscode.extension.contributes.themes.path": "Ruta de acceso del archivo tmTheme. La ruta de acceso es relativa a la carpeta de extensión y suele ser './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "Identificador del tema de icono como se usa en la configuración de usuario.", - "vscode.extension.contributes.iconThemes.label": "Etiqueta del tema de icono como se muestra en la interfaz de usuario.", - "vscode.extension.contributes.iconThemes.path": "Ruta de acceso del archivo de definición de temas de icono. La ruta de acceso es relativa a la carpeta de extensión y suele ser './icons/awesome-icon-theme.json'.", "migration.completed": "Se han agregado nuevos valores de tema a la configuración de usuario. Hay una copia de seguridad disponible en {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "Se esperaba una cadena en \"contributes.{0}.path\". Valor proporcionado: {1}", - "invalid.path.1": "Se esperaba que \"contributes.{0}.path\" ({1}) se incluyera en la carpeta de la extensión ({2}). Esto puede hacer que la extensión no sea portĆ”til.", - "reqid": "Se esperaba una cadena en `contributes.{0}.id`. Valor proporcionado: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Especifica el tema de icono utilizado en el Ć”rea de trabajo o \"null\" para no mostrar ningĆŗn icono de archivo.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Reemplaza los colores del tema de color actual", - "workbenchColors.deprecated": "Esta configuracion no es experimental y se ha cambiado de nombre a 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Utilice 'workbench.colorCustomizations' en su lugar" + "editorColors": "Reemplaza los colores y el estilo de fuente del editor del tema de color seleccionado.", + "editorColors.comments": "Establece los colores y estilos para los comentarios", + "editorColors.strings": "Establece los colores y estilos para los literales de cadena.", + "editorColors.keywords": "Establece los colores y estilos para las palabras clave.", + "editorColors.numbers": "Establece los colores y estilos para nĆŗmeros literales.", + "editorColors.types": "Establece los colores y estilos para las declaraciones y referencias de tipos.", + "editorColors.functions": "Establece los colores y estilos para las declaraciones y referencias de funciones.", + "editorColors.variables": "Establece los colores y estilos para las declaraciones y referencias de variables.", + "editorColors.textMateRules": "Establece colores y estilos utilizando las reglas de la tematización de textmate (avanzadas)." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/esn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..83604230ec4 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "No se puede escribir en el archivo de configuración del espacio de trabajo. Por favor, abra el archivo para corregir sus errores/advertencias e intĆ©ntelo de nuevo.", + "errorWorkspaceConfigurationFileDirty": "No se puede escribir en el archivo de configuración de espacio de trabajo porque el archivo ha sido modificado. Por favor, guĆ”rdelo y vuelva a intentarlo.", + "openWorkspaceConfigurationFile": "Abrir archivo de configuración del Ć”rea de trabajo", + "close": "Cerrar", + "enterWorkspace.close": "Cerrar", + "enterWorkspace.dontShowAgain": "No volver a mostrar", + "enterWorkspace.moreInfo": "MĆ”s información", + "enterWorkspace.prompt": "Obtenga mĆ”s información acerca de cómo trabajar con varias carpetas en VS Code. " +} \ No newline at end of file diff --git a/i18n/fra/extensions/azure-account/out/azure-account.i18n.json b/i18n/fra/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..7ee7c75a5ab --- /dev/null +++ b/i18n/fra/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "Copier & Ouvrir", + "azure-account.close": "Fermer", + "azure-account.login": "Connexion", + "azure-account.loginFirst": "Non connectĆ©, se connecter d'abord.", + "azure-account.userCodeFailed": "L'acquisition de code utilisateur a Ć©chouĆ©", + "azure-account.tokenFailed": "Acquisition du jeton avec le code de l’appareil", + "azure-account.tokenFromRefreshTokenFailed": "Acquisition de jeton avec le jeton d'actualisation" +} \ No newline at end of file diff --git a/i18n/fra/extensions/azure-account/out/extension.i18n.json b/i18n/fra/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..c9ceccea29e --- /dev/null +++ b/i18n/fra/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "AzureĀ : Connexion en cours...", + "azure-account.loggedIn": "AzureĀ : {0}" +} \ No newline at end of file diff --git a/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index fcedce53b3c..c8334701a65 100644 --- a/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/fra/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "exempleĀ : myFile.txt", - "activeEditorMedium": "exempleĀ : myFolder/myFile.txt", - "activeEditorLong": "exempleĀ : /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "par ex., myFolder1, myFolder2, myFolder3", - "rootPath": "exempleĀ : /Users/Development/myProject", - "folderName": "par ex., myFolder", - "folderPath": "par ex., /Users/Development/myFolder", + "activeEditorShort": "le nom du fichier (ex: monfichier.txt)", + "activeEditorMedium": "le chemin d’accĆØs du fichier relatif au dossier de l’espace de travail (ex: myFolder/myFile.txt)", + "activeEditorLong": "le chemin d’accĆØs complet du fichier (ex: /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nom de l’espace de travail (ex: monDossier ou monEspaceDeTravail)", + "rootPath": "chemin d’accĆØs de l’espace de travail (ex: /Users/Development/myWorkspace)", + "folderName": "nom du dossier de l'espace de travail auquel le fichier appartient (ex: monDossier)", + "folderPath": "chemin d’accĆØs du dossier de l'espace de travail auquel le fichier appartient (ex: /Users/Development/myFolder)", "appName": "exempleĀ : VS Code", "dirty": "indicateur d'intĆ©gritĆ© si l'intĆ©gritĆ© de l'Ć©diteur actif est compromise", "separator": "sĆ©parateur conditionnel (' - ') qui s'affiche uniquement quand il est entourĆ© de variables avec des valeurs", diff --git a/i18n/fra/extensions/css/package.i18n.json b/i18n/fra/extensions/css/package.i18n.json index 96dff648d69..a6f0b6d471f 100644 --- a/i18n/fra/extensions/css/package.i18n.json +++ b/i18n/fra/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "Nombre de paramĆØtres non valide", "css.lint.boxModel.desc": "Ne pas utiliser la largeur ou la hauteur avec une marge intĆ©rieure ou une bordure", "css.lint.compatibleVendorPrefixes.desc": "Lors de l'utilisation d'un prĆ©fixe spĆ©cifique Ć  un fabricant, toujours inclure Ć©galement toutes les propriĆ©tĆ©s spĆ©cifiques au fabricant", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "PropriĆ©tĆ© spĆ©cifique Ć  un fournisseur inconnue.", "css.lint.vendorPrefix.desc": "Lors de l'utilisation d'un prĆ©fixe spĆ©cifique Ć  un fournisseur, ajouter Ć©galement la propriĆ©tĆ© standard", "css.lint.zeroUnits.desc": "Aucune unitĆ© nĆ©cessaire pour zĆ©ro", + "css.trace.server.desc": "Trace la communication entre VS Code et le serveur de langage CSS.", + "css.validate.title": "ContrĆ“le la validation CSS et la gravitĆ© des problĆØmes.", "css.validate.desc": "Active ou dĆ©sactive toutes les validations", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "Nombre de paramĆØtres non valide", "less.lint.boxModel.desc": "Ne pas utiliser la largeur ou la hauteur avec une marge intĆ©rieure ou une bordure", "less.lint.compatibleVendorPrefixes.desc": "Lors de l'utilisation d'un prĆ©fixe spĆ©cifique Ć  un fabricant, toujours inclure Ć©galement toutes les propriĆ©tĆ©s spĆ©cifiques au fabricant", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "PropriĆ©tĆ© spĆ©cifique Ć  un fournisseur inconnue.", "less.lint.vendorPrefix.desc": "Lors de l'utilisation d'un prĆ©fixe spĆ©cifique Ć  un fournisseur, ajouter Ć©galement la propriĆ©tĆ© standard", "less.lint.zeroUnits.desc": "Aucune unitĆ© nĆ©cessaire pour zĆ©ro", + "less.validate.title": "ContrĆ“le la validation LESS et la gravitĆ© des problĆØmes.", "less.validate.desc": "Active ou dĆ©sactive toutes les validations", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "Nombre de paramĆØtres non valide", "scss.lint.boxModel.desc": "Ne pas utiliser la largeur ou la hauteur avec une marge intĆ©rieure ou une bordure", "scss.lint.compatibleVendorPrefixes.desc": "Lors de l'utilisation d'un prĆ©fixe spĆ©cifique Ć  un fabricant, toujours inclure Ć©galement toutes les propriĆ©tĆ©s spĆ©cifiques au fabricant", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "PropriĆ©tĆ© spĆ©cifique Ć  un fournisseur inconnue.", "scss.lint.vendorPrefix.desc": "Lors de l'utilisation d'un prĆ©fixe spĆ©cifique Ć  un fournisseur, ajouter Ć©galement la propriĆ©tĆ© standard", "scss.lint.zeroUnits.desc": "Aucune unitĆ© nĆ©cessaire pour zĆ©ro", + "scss.validate.title": "ContrĆ“le la validation SCSS et la gravitĆ© des problĆØmes.", "scss.validate.desc": "Active ou dĆ©sactive toutes les validations", "less.colorDecorators.enable.desc": "Active ou dĆ©sactive les Ć©lĆ©ments dĆ©coratifs de couleurs", "scss.colorDecorators.enable.desc": "Active ou dĆ©sactive les Ć©lĆ©ments dĆ©coratifs de couleurs", - "css.colorDecorators.enable.desc": "Active ou dĆ©sactive les Ć©lĆ©ments dĆ©coratifs de couleurs" + "css.colorDecorators.enable.desc": "Active ou dĆ©sactive les Ć©lĆ©ments dĆ©coratifs de couleurs", + "css.colorDecorators.enable.deprecationMessage": "Le paramĆØtre 'css.colorDecorators.enable' a Ć©tĆ© dĆ©prĆ©ciĆ© en faveur de 'editor.colorDecorators'.", + "scss.colorDecorators.enable.deprecationMessage": "Le paramĆØtre 'scss.colorDecorators.enable' a Ć©tĆ© dĆ©prĆ©ciĆ© en faveur de 'editor.colorDecorators'.", + "less.colorDecorators.enable.deprecationMessage": "Le paramĆØtre 'less.colorDecorators.enable' a Ć©tĆ© dĆ©prĆ©ciĆ© en faveur de 'editor.colorDecorators'." } \ No newline at end of file diff --git a/i18n/fra/extensions/emmet/package.i18n.json b/i18n/fra/extensions/emmet/package.i18n.json index 8b6ad71cd4e..175d70aeb65 100644 --- a/i18n/fra/extensions/emmet/package.i18n.json +++ b/i18n/fra/extensions/emmet/package.i18n.json @@ -3,4 +3,51 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "command.wrapWithAbbreviation": "Envelopper avec une abrĆ©viation", + "command.wrapIndividualLinesWithAbbreviation": "Envelopper les lignes individuelles avec une abrĆ©viation", + "command.removeTag": "Supprimer le Tag", + "command.updateTag": "Mettre Ć  jour le Tag", + "command.matchTag": "Aller Ć  la paire correspondante", + "command.balanceIn": "Equilibrer (vers l'intĆ©rieur)", + "command.balanceOut": "Equilibrer (vers l'extĆ©rieur)", + "command.prevEditPoint": "Aller au Point d'Ć©dition prĆ©cĆ©dent", + "command.nextEditPoint": "Aller au Point d’édition suivant", + "command.mergeLines": "Fusionner les lignes", + "command.selectPrevItem": "SĆ©lectionner l’élĆ©ment prĆ©cĆ©dent", + "command.selectNextItem": "SĆ©lectionner l’élĆ©ment suivant", + "command.splitJoinTag": "SĆ©parer / Joindre le Tag", + "command.toggleComment": "Activer/dĆ©sactiver le commentaire", + "command.evaluateMathExpression": "Ɖvaluer l’Expression mathĆ©matique", + "command.updateImageSize": "Mettre Ć  jour la taille de l’image", + "command.reflectCSSValue": "ReflĆØter la valeur CSS", + "command.incrementNumberByOne": "IncrĆ©menter de 1", + "command.decrementNumberByOne": "DĆ©crĆ©menter de 1", + "command.incrementNumberByOneTenth": "IncrĆ©menter de 0,1", + "command.decrementNumberByOneTenth": "DĆ©crĆ©menter de 0,1", + "command.incrementNumberByTen": "IncrĆ©menter de 10", + "command.decrementNumberByTen": "DĆ©crĆ©menter de 10", + "emmetSyntaxProfiles": "DĆ©finissez le profil pour la syntaxe spĆ©cifiĆ©e ou utilisez votre propre profil avec des rĆØgles spĆ©cifiques.", + "emmetExclude": "Un tableau des langages pour lesquels les abrĆ©viations Emmet ne devraient pas ĆŖtre dĆ©veloppĆ©es.", + "emmetExtensionsPath": "Chemin d’accĆØs au dossier contenant les profils Emmet et les extraits.", + "emmetShowExpandedAbbreviation": "Affiche les abrĆ©viations Emmet dĆ©veloppĆ©es sous forme de suggestions.\nL’option \"inMarkupAndStylesheetFilesOnly\" s’applique Ć  haml, jade, slim, xml, xsl, css, html, scss, sass, less et stylus.\nL’option\"always\" s’applique Ć  toutes les parties du fichier indĆ©pendamment du balisage/css.", + "emmetShowAbbreviationSuggestions": "Affiche les abrĆ©viations Emmet possibles sous forme de suggestions. Non applicable dans les feuilles de style ou lorsque emmet.showExpandedAbbreviation est dĆ©fini Ć  \"never\".", + "emmetIncludeLanguages": "Activer les abrĆ©viations Emmet dans les langages qui ne sont pas pris en charge par dĆ©faut. Ajouter ici un mappage entre le langage et le langage Emmet pris en charge.\n Par exempleĀ : {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "Variables Ć  utiliser dans les extraits de Emmet", + "emmetTriggerExpansionOnTab": "Lorsqu’activĆ©, les abrĆ©viations Emmet sont dĆ©veloppĆ©es lorsque vous appuyez sur TAB.", + "emmetPreferences": "PrĆ©fĆ©rences utilisĆ©es pour modifier le comportement de certaines actions et rĆ©solveurs d'Emmet.", + "emmetPreferencesIntUnit": "UnitĆ© par dĆ©faut pour les valeurs entiĆØres", + "emmetPreferencesFloatUnit": "UnitĆ© par dĆ©faut pour les valeurs float", + "emmetPreferencesCssAfter": "Symbole Ć  placer Ć  la fin de la propriĆ©tĆ© CSS pendant le dĆ©veloppement des abrĆ©viations CSS", + "emmetPreferencesSassAfter": "Symbole Ć  placer Ć  la fin de la propriĆ©tĆ© CSS pendant le dĆ©veloppement des abrĆ©viations CSS dans les fichiers Sass", + "emmetPreferencesStylusAfter": "Symbole Ć  placer Ć  la fin de la propriĆ©tĆ© CSS pendant le dĆ©veloppement des abrĆ©viations CSS dans les fichiers Stylus", + "emmetPreferencesCssBetween": "Symbole Ć  placer entre la propriĆ©tĆ© CSS et la valeur pendant le dĆ©veloppement des abrĆ©viations CSS", + "emmetPreferencesSassBetween": "Symbole Ć  placer entre la propriĆ©tĆ© CSS et la valeur pendant le dĆ©veloppement des abrĆ©viations CSS dans les fichiers Sass", + "emmetPreferencesStylusBetween": "Symbole Ć  placer entre la propriĆ©tĆ© CSS et la valeur pendant le dĆ©veloppement des abrĆ©viations CSS dans les fichiers Stylus", + "emmetShowSuggestionsAsSnippets": "Si true, alors les suggestions Emmet apparaĆ®tront en tant qu’extraits vous permettant de les commander selon le paramĆØtre editor.snippetSuggestions.", + "emmetPreferencesBemElementSeparator": "SĆ©parateur d’élĆ©ments utilisĆ© pour les classes lorsque le filtre BEM est utilisĆ©", + "emmetPreferencesBemModifierSeparator": "SĆ©parateur de modificateur utilisĆ© pour les classes lorsque le filtre BEM est utilisĆ©", + "emmetPreferencesFilterCommentBefore": "Une dĆ©finition de commentaire qui doit ĆŖtre placĆ©e avant l’élĆ©ment correspondant quand le filtre de commentaire est appliquĆ©.", + "emmetPreferencesFilterCommentAfter": "Une dĆ©finition de commentaire qui doit ĆŖtre placĆ©e aprĆØs l’élĆ©ment correspondant quand un filtre de commentaire est appliquĆ©.", + "emmetPreferencesFilterCommentTrigger": "Une liste sĆ©parĆ©e par des virgules de noms d’attributs qui devraient exister en abrĆ©gĆ© pour que le filtre de commentaire soit appliquĆ©" +} \ No newline at end of file diff --git a/i18n/fra/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/fra/extensions/extension-editing/out/extensionLinter.i18n.json index 7f69cac4fb4..c64c3a6f862 100644 --- a/i18n/fra/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/fra/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "Les images doivent utiliser le protocole HTTPS.", "svgsNotValid": "Les SVG ne sont pas une source d'images valide.", "embeddedSvgsNotValid": "Les SVG incorporĆ©s ne sont pas une source d'images valide.", - "dataUrlsNotValid": "Les URL de donnĆ©es ne sont pas une source d'images valide." + "dataUrlsNotValid": "Les URL de donnĆ©es ne sont pas une source d'images valide.", + "relativeUrlRequiresHttpsRepository": "Les URL d'image relatives nĆ©cessitent un dĆ©pĆ“t avec le protocole HTTPS dans package.json.", + "relativeIconUrlRequiresHttpsRepository": "Une icĆ“ne nĆ©cessite un rĆ©fĆ©rentiel avec le protocole HTTPS spĆ©cifiĆ© dans ce package.json.", + "relativeBadgeUrlRequiresHttpsRepository": "Les URL d'image relatives nĆ©cessitent un dĆ©pĆ“t avec le protocole HTTPS dans package.json." } \ No newline at end of file diff --git a/i18n/fra/extensions/git/out/commands.i18n.json b/i18n/fra/extensions/git/out/commands.i18n.json index ee6ed2d988c..e0dab3e5a12 100644 --- a/i18n/fra/extensions/git/out/commands.i18n.json +++ b/i18n/fra/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "Clonage du dĆ©pĆ“t git...", "openrepo": "Ouvrir le dĆ©pĆ“t", "proposeopen": "Voulez-vous ouvrir le dĆ©pĆ“t cloné ?", + "init repo": "Initialiser le dĆ©pĆ“t", + "create repo": "Initialiser le dĆ©pĆ“t", + "are you sure": "Ceci va crĆ©er un dĆ©pĆ“t Git dans '{0}'. Êtes-vous sĆ»r de vouloir continuerĀ ?", "HEAD not available": "La version HEAD de '{0}' n'est pas disponible.", + "confirm stage files with merge conflicts": "Voulez-vous vraiment crĆ©er {0} fichiers avec des conflits de fusion ?", + "confirm stage file with merge conflicts": "Voulez-vous vraiment crĆ©er {0} avec des conflits de fusion ?", + "yes": "Oui", "confirm revert": "Voulez-vous vraiment restaurer les changements sĆ©lectionnĆ©s dans {0}Ā ?", "revert": "Restaurer les modifications", + "discard": "Ignorer les modifications", + "confirm delete": "Êtes-vous sĆ»r de vouloir SUPPRIMER {0}Ā ?", + "delete file": "Supprimer le fichier", "confirm discard": "Voulez-vous vraiment abandonner les changements apportĆ©s Ć  {0}Ā ?", "confirm discard multiple": "Voulez-vous vraiment abandonner les changements apportĆ©s Ć  {0} fichiersĀ ?", - "discard": "Ignorer les modifications", - "confirm discard all": "Voulez-vous vraiment ignorer TOUTES les modificationsĀ ? Cette action est IRRƉVERSIBLE.", - "discardAll": "Ignorer TOUTES les modifications", + "warn untracked": "Ceci effacera les fichiers {0} non suivis !", + "confirm discard all single": "Voulez-vous vraiment abandonner les changements apportĆ©s Ć  {0}Ā ?", + "confirm discard all": "Voulez-vous vraiment ignorer TOUTES les modifications dans {0} fichiers ?\nCette opĆ©ration est IRRƉVERSIBLE.\nVotre plage de travail actuelle sera DƉFINITIVEMENT PERDUE.", + "discardAll multiple": "Ignorer 1 fichier", + "discardAll": "Ignorer les {0} fichiers", + "confirm delete multiple": "Voulez-vous vraiment SUPPRIMER {0} fichiersĀ ?", + "delete files": "Supprimer des fichiers", + "there are untracked files single": "Le fichier non suivi suivant sera SUPPRIMƉ DU DISQUE s'il est ignorĆ© : {0}.", + "there are untracked files": "{0} fichiers non suivis seront SUPPRIMƉS DU DISQUE s'ils sont ignorĆ©s.", + "confirm discard all 2": "{0}\n\nCette opĆ©ration est IRRƉVERSIBLE, votre plage de travail actuelle sera DƉFINITIVEMENT PERDUE.", + "yes discard tracked": "Ignorer 1 fichier suivi", + "yes discard tracked multiple": "Ignorer {0} fichiers suivis", "no staged changes": "Aucune modification en attente Ć  valider.\n\nVoulez-vous automatiquement mettre en attente toutes vos modifications et les valider directement ?", - "yes": "Oui", "always": "Toujours", "no changes": "Il n'existe aucun changement Ć  valider.", "commit message": "Message de validation", @@ -34,16 +51,25 @@ "delete branch": "Supprimer la branche", "select a branch to merge from": "SĆ©lectionner une branche Ć  fusionner", "merge conflicts": "Il existe des conflits de fusion. Corrigez-les avant la validation.", + "tag name": "Nom de la balise", + "provide tag name": "SpĆ©cifiez un nom de balise", + "tag message": "Message", + "provide tag message": "SpĆ©cifiez un message pour annoter la balise", "no remotes to pull": "Votre dĆ©pĆ“t n'a aucun dĆ©pĆ“t distant configurĆ© pour un Pull.", "pick remote pull repo": "Choisir un dĆ©pĆ“t distant duquel extraire la branche", "no remotes to push": "Votre dĆ©pĆ“t n'a aucun dĆ©pĆ“t distant configurĆ© pour un Push.", + "push with tags success": "EnvoyĆ© (push) avec des balises.", "nobranch": "Vous devez extraire une branche dont vous souhaitez effectuer le Push vers un emplacement distant.", "pick remote": "Choisissez un dĆ©pĆ“t distant où publier la branche '{0}'Ā :", "sync is unpredictable": "Cette action effectue un transfert (Push) et un tirage (Pull) des validations Ć  destination et en provenance de '{0}'.", "ok": "OK", "never again": "OK, ne plus afficher", "no remotes to publish": "Votre dĆ©pĆ“t n'a aucun dĆ©pĆ“t distant configurĆ© pour une publication.", - "disabled": "Git est dĆ©sactivĆ© ou non pris en charge dans cet espace de travail", + "no changes stash": "Aucune modification Ć  remiser (stash).", + "provide stash message": "SpĆ©cifier Ć©ventuellement un message pour la remise (stash)", + "stash message": "Message pour la remise (stash)", + "no stashes": "Aucune remise (stash) Ć  restaurer.", + "pick stash to pop": "Choisir une remise (stash) Ć  appliquer et supprimer", "clean repo": "Nettoyez l'arborescence de travail de votre dĆ©pĆ“t avant l'extraction.", "cant push": "Push impossible des rĆ©fĆ©rences vers la branche distante. ExĆ©cutez d'abord 'Extraire' pour intĆ©grer vos modifications.", "git error details": "GitĀ : {0}", diff --git a/i18n/fra/extensions/git/out/model.i18n.json b/i18n/fra/extensions/git/out/model.i18n.json index 70565ab6248..6b72576dc57 100644 --- a/i18n/fra/extensions/git/out/model.i18n.json +++ b/i18n/fra/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Ouvrir", - "merge changes": "Fusionner les modifications", - "staged changes": "Modifications en zone de transit", - "changes": "Modifications", - "ok": "OK", - "neveragain": "Ne plus afficher", - "huge": "Le dĆ©pĆ“t Git dans '{0}' a trop de modifications actives, seul un sous-ensemble de fonctionnalitĆ©s Git sera activĆ©." + "no repositories": "Aucun dĆ©pĆ“t disponible", + "pick repo": "Choisir un dĆ©pĆ“t" } \ No newline at end of file diff --git a/i18n/fra/extensions/git/out/repository.i18n.json b/i18n/fra/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..75b81935d06 --- /dev/null +++ b/i18n/fra/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "Ouvrir", + "index modified": "Index modifiĆ©", + "modified": "ModifiĆ©", + "index added": "Index ajoutĆ©", + "index deleted": "Index supprimĆ©", + "deleted": "SupprimĆ©", + "index renamed": "Index renommĆ©", + "index copied": "Index copiĆ©", + "untracked": "Non suivi", + "ignored": "IgnorĆ©", + "both deleted": "Tous deux supprimĆ©s", + "added by us": "AjoutĆ© par nos soins", + "deleted by them": "SupprimĆ© par eux", + "added by them": "AjoutĆ© par eux", + "deleted by us": "SupprimĆ© par nos soins", + "both added": "Tous deux ajoutĆ©s", + "both modified": "Tous deux modifiĆ©s", + "commit": "Commit", + "merge changes": "Fusionner les modifications", + "staged changes": "Modifications en zone de transit", + "changes": "Modifications", + "ok": "OK", + "neveragain": "Ne plus afficher", + "huge": "Le dĆ©pĆ“t Git dans '{0}' a trop de modifications actives, seul un sous-ensemble de fonctionnalitĆ©s Git sera activĆ©." +} \ No newline at end of file diff --git a/i18n/fra/extensions/git/package.i18n.json b/i18n/fra/extensions/git/package.i18n.json index b3affbab952..e5008fa48da 100644 --- a/i18n/fra/extensions/git/package.i18n.json +++ b/i18n/fra/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "Cloner", "command.init": "Initialiser le dĆ©pĆ“t", + "command.close": "Fermer le dĆ©pĆ“t", "command.refresh": "Actualiser", "command.openChange": "Ouvrir les modifications", "command.openFile": "Ouvrir le fichier", @@ -14,6 +15,8 @@ "command.stageAll": "Mettre en attente toutes les modifications", "command.stageSelectedRanges": "Mettre en attente les plages sĆ©lectionnĆ©es", "command.revertSelectedRanges": "Restaurer les portĆ©es sĆ©lectionnĆ©es", + "command.stageChange": "Mettre en attente la modification", + "command.revertChange": "Restaurer la modification", "command.unstage": "Annuler la mise en attente des modifications", "command.unstageAll": "Annuler la mise en attente de toutes les modifications", "command.unstageSelectedRanges": "Annuler la mise en attente des plages sĆ©lectionnĆ©es", @@ -22,22 +25,29 @@ "command.commit": "Commit", "command.commitStaged": "Valider le contenu en zone de transit", "command.commitStagedSigned": "Valider les modifications en attente (signĆ©)", + "command.commitStagedAmend": "Valider les modifications en attente (modifier)", "command.commitAll": "Valider tout", "command.commitAllSigned": "Valider tout (signĆ©)", + "command.commitAllAmend": "Tout Valider (Modifier)", "command.undoCommit": "Annuler la derniĆØre validation", "command.checkout": "Extraire vers...", "command.branch": "CrĆ©er une branche...", "command.deleteBranch": "Supprimer la branche...", "command.merge": "Fusionner la branche...", + "command.createTag": "CrĆ©er une Ć©tiquette", "command.pull": "Pull", "command.pullRebase": "Pull (rebaser)", "command.pullFrom": "Extraire de...", "command.push": "Push", "command.pushTo": "Transfert (Push) vers...", + "command.pushWithTags": "TransfĆ©rer (Push) avec les Ć©tiquettes", "command.sync": "Synchroniser", "command.publish": "Publier la branche", "command.showOutput": "Afficher la sortie Git", "command.ignore": "Ajouter un fichier Ć  .gitignore", + "command.stash": "Remiser (stash)", + "command.stashPop": "Appliquer et supprimer la remise...", + "command.stashPopLatest": "Appliquer et supprimer la derniĆØre remise", "config.enabled": "Indique si git est activĆ©", "config.path": "Chemin d'accĆØs Ć  l'exĆ©cutable git", "config.autorefresh": "Indique si l'actualisation automatique est activĆ©e", @@ -49,5 +59,7 @@ "config.ignoreLegacyWarning": "Ignore l'avertissement Git hĆ©ritĆ©", "config.ignoreLimitWarning": "Ignore l'avertissement quand il y a trop de modifications dans un dĆ©pĆ“t", "config.defaultCloneDirectory": "Emplacement par dĆ©faut où cloner un dĆ©pĆ“t git", - "config.enableSmartCommit": "Validez toutes les modifications en l'absence de modifications en attente." + "config.enableSmartCommit": "Validez toutes les modifications en l'absence de modifications en attente.", + "config.enableCommitSigning": "Permet de valider en signant avec GPG.", + "config.discardAllScope": "ContrĆ“le les modifications ignorĆ©es par la commande 'Ignorer toutes les modifications'. 'all' ignore toutes les modifications. 'tracked' ignore uniquement les fichiers suivis. 'prompt' affiche un message d'invite chaque fois que l’action est exĆ©cutĆ©e." } \ No newline at end of file diff --git a/i18n/fra/extensions/grunt/out/main.i18n.json b/i18n/fra/extensions/grunt/out/main.i18n.json index 831ac201fd9..90ccce143b1 100644 --- a/i18n/fra/extensions/grunt/out/main.i18n.json +++ b/i18n/fra/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Ɖchec de la dĆ©tection automatique des tĆ¢ches Grunt avec l'erreur : {0}" + "execFailed": "L'auto dĆ©tection de Grunt pour le dossier {0} a Ć©chouĆ© avec l’erreurĀ : {1}" } \ No newline at end of file diff --git a/i18n/fra/extensions/gulp/out/main.i18n.json b/i18n/fra/extensions/gulp/out/main.i18n.json index 5baf80d099d..ebb7531e60e 100644 --- a/i18n/fra/extensions/gulp/out/main.i18n.json +++ b/i18n/fra/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Ɖchec de la dĆ©tection automatique des tĆ¢ches Gulp avec l'erreur : {0}" + "execFailed": "L'auto dĆ©tection de gulp pour le dossier {0} a Ć©chouĆ© avec l’erreurĀ : {1}" } \ No newline at end of file diff --git a/i18n/fra/extensions/html/package.i18n.json b/i18n/fra/extensions/html/package.i18n.json index bbd11b9a02f..40f7639359f 100644 --- a/i18n/fra/extensions/html/package.i18n.json +++ b/i18n/fra/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "Activer/dĆ©sactiver le formateur HTML par dĆ©faut (nĆ©cessite un redĆ©marrage)", + "html.format.enable.desc": "Activer/dĆ©sactiver le formateur HTML par dĆ©faut.", "html.format.wrapLineLength.desc": "Nombre maximal de caractĆØres par ligne (0 = dĆ©sactiver).", "html.format.unformatted.desc": "Liste des balises, sĆ©parĆ©es par des virgules, qui ne doivent pas ĆŖtre remises en forme. 'null' correspond par dĆ©faut Ć  toutes les balises rĆ©pertoriĆ©es Ć  l'adresse https://www.w3.org/TR/html5/dom.html#phrasing-content.", "html.format.contentUnformatted.desc": "Liste des balises, sĆ©parĆ©es par des virgules, dont le contenu ne doit pas ĆŖtre remis en forme. 'null' correspond par dĆ©faut Ć  toutes les balises 'pre'.", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "Permet de configurer la prise en charge intĆ©grĆ©e du langage HTML pour suggĆ©rer des balises et propriĆ©tĆ©s AngularĀ V1.", "html.suggest.ionic.desc": "Permet de configurer la prise en charge intĆ©grĆ©e du langage HTML pour suggĆ©rer des balises, des propriĆ©tĆ©s et des valeurs Ionic.", "html.suggest.html5.desc": "Permet de configurer la prise en charge intĆ©grĆ©e du langage HTML pour suggĆ©rer des balises, des propriĆ©tĆ©s et des valeurs HTML5.", + "html.trace.server.desc": "Trace la communication entre VS Code et le serveur de langage HTML.", "html.validate.scripts": "Configure la validation des scripts incorporĆ©s par la prise en charge du langage HTML intĆ©grĆ©.", - "html.validate.styles": "Configure la validation des styles incorporĆ©s par la prise en charge du langage HTML intĆ©grĆ©." + "html.validate.styles": "Configure la validation des styles incorporĆ©s par la prise en charge du langage HTML intĆ©grĆ©.", + "html.autoClosingTags": "Activez/dĆ©sactivez la fermeture automatique des balises HTML." } \ No newline at end of file diff --git a/i18n/fra/extensions/jake/out/main.i18n.json b/i18n/fra/extensions/jake/out/main.i18n.json index 4811debb9a3..00ae9b76cb8 100644 --- a/i18n/fra/extensions/jake/out/main.i18n.json +++ b/i18n/fra/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Ɖchec de la dĆ©tection automatique des tĆ¢ches Jake avec l'erreur : {0}" + "execFailed": "L'auto dĆ©tection de Jake pour le dossier {0} a Ć©chouĆ© avec l’erreurĀ : {1}" } \ No newline at end of file diff --git a/i18n/fra/extensions/json/package.i18n.json b/i18n/fra/extensions/json/package.i18n.json index 6285b48329c..b236be267b2 100644 --- a/i18n/fra/extensions/json/package.i18n.json +++ b/i18n/fra/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "DĆ©finition de schĆ©ma pour l'URL indiquĆ©e. Le schĆ©ma doit ĆŖtre fourni uniquement pour Ć©viter les accĆØs Ć  l'URL du schĆ©ma.", "json.format.enable.desc": "Activer/dĆ©sactiver le formateur JSON par dĆ©faut (nĆ©cessite un redĆ©marrage)", "json.tracing.desc": "Trace la communication entre VS Code et le serveur de langage JSON.", - "json.colorDecorators.enable.desc": "Active ou dĆ©sactive les Ć©lĆ©ments dĆ©coratifs de couleurs" + "json.colorDecorators.enable.desc": "Active ou dĆ©sactive les Ć©lĆ©ments dĆ©coratifs de couleurs", + "json.colorDecorators.enable.deprecationMessage": "Le paramĆØtre 'json.colorDecorators.enable' a Ć©tĆ© dĆ©prĆ©ciĆ© en faveur de 'editor.colorDecorators'." } \ No newline at end of file diff --git a/i18n/fra/extensions/markdown/out/extension.i18n.json b/i18n/fra/extensions/markdown/out/extension.i18n.json index 34001f88bb7..a5db2a445e3 100644 --- a/i18n/fra/extensions/markdown/out/extension.i18n.json +++ b/i18n/fra/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "Impossible de charger 'markdown.styles' : {0}" + "onPreviewStyleLoadError": "Impossible de charger 'markdown.styles' : {0}", + "previewTitle": "PrĆ©visualiser {0}" } \ No newline at end of file diff --git a/i18n/fra/extensions/markdown/out/previewContentProvider.i18n.json b/i18n/fra/extensions/markdown/out/previewContentProvider.i18n.json index 8b6ad71cd4e..2eb7c81389d 100644 --- a/i18n/fra/extensions/markdown/out/previewContentProvider.i18n.json +++ b/i18n/fra/extensions/markdown/out/previewContentProvider.i18n.json @@ -3,4 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "preview.securityMessage.text": "Du contenu a Ć©tĆ© dĆ©sactivĆ© dans ce document", + "preview.securityMessage.title": "Le contenu potentiellement dangereux ou prĆ©caire a Ć©tĆ© dĆ©sactivĆ© dans l’aperƧu du format markdown. Modifier le paramĆØtre de sĆ©curitĆ© AperƧu Markdown afin d’autoriser les contenus non sĆ©curisĆ©s ou activer les scripts", + "preview.securityMessage.label": "Avertissement de sĆ©curitĆ© de contenu dĆ©sactivĆ©" +} \ No newline at end of file diff --git a/i18n/fra/extensions/markdown/out/security.i18n.json b/i18n/fra/extensions/markdown/out/security.i18n.json index b6ec4bbef7d..3dbb7ee43fd 100644 --- a/i18n/fra/extensions/markdown/out/security.i18n.json +++ b/i18n/fra/extensions/markdown/out/security.i18n.json @@ -4,5 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.currentSelection": "ParamĆØtre actuel" + "strict.title": "Strict", + "strict.description": "Charger uniquement le contenu sĆ©curisĆ©", + "insecureContent.title": "Autoriser le contenu non sĆ©curisĆ©", + "insecureContent.description": "Activer le chargement de contenu sur http", + "disable.title": "DĆ©sactiver", + "disable.description": "Autorisez tout le contenu et l’exĆ©cution des scripts. Non recommandĆ©", + "moreInfo.title": "Informations", + "preview.showPreviewSecuritySelector.title": "SĆ©lectionner les paramĆØtres de sĆ©curitĆ© pour les aperƧus Markdown dans cet espace de travail" } \ No newline at end of file diff --git a/i18n/fra/extensions/markdown/package.i18n.json b/i18n/fra/extensions/markdown/package.i18n.json index 4be64275645..d6a8fb4e51e 100644 --- a/i18n/fra/extensions/markdown/package.i18n.json +++ b/i18n/fra/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "DĆ©finit l'affichage des sauts de ligne dans l'aperƧu Markdown. Si la valeur est 'true', crĆ©e un
pour chaque nouvelle ligne.", + "markdown.preview.linkify": "Activez ou dĆ©sactivez la conversion de texte de type URL en liens dans l’aperƧu Markdown.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Double-cliquez dans l'aperƧu Markdown pour passer Ć  l'Ć©diteur.", "markdown.preview.fontFamily.desc": "ContrĆ“le la famille de polices utilisĆ©e dans l'aperƧu Markdown.", "markdown.preview.fontSize.desc": "ContrĆ“le la taille de police en pixels utilisĆ©e dans l'aperƧu Markdown.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "Ouvrir l'aperƧu sur le cĆ“tĆ©", "markdown.showSource.title": "Afficher la source", "markdown.styles.dec": "Liste d'URL ou de chemins locaux de feuilles de style CSS Ć  utiliser dans l'aperƧu Markdown. Les chemins relatifs sont interprĆ©tĆ©s par rapport au dossier ouvert dans l'explorateur. S'il n'y a aucun dossier ouvert, ils sont interprĆ©tĆ©s par rapport Ć  l'emplacement du fichier Markdown. Tous les signes '\\' doivent ĆŖtre Ć©crits sous la forme '\\\\'.", - "markdown.showPreviewSecuritySelector.title": "Changer les paramĆØtres de sĆ©curitĆ© de l'aperƧu Markdown", - "markdown.trace.desc": "Active la journalisation du dĆ©bogage pour l'extension Markdown." + "markdown.showPreviewSecuritySelector.title": "Changer les paramĆØtres de sĆ©curitĆ© de l'aperƧu", + "markdown.trace.desc": "Active la journalisation du dĆ©bogage pour l'extension Markdown.", + "markdown.refreshPreview.title": "Actualiser l’aperƧu" } \ No newline at end of file diff --git a/i18n/fra/extensions/npm/out/main.i18n.json b/i18n/fra/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..1bdcbfa7fe3 --- /dev/null +++ b/i18n/fra/extensions/npm/out/main.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "npm.parseError": "DĆ©tection de tĆ¢che NpmĀ : impossible d’analyser le fichier {0}" +} \ No newline at end of file diff --git a/i18n/fra/extensions/npm/package.i18n.json b/i18n/fra/extensions/npm/package.i18n.json index 7028d1f9162..05ec75a219e 100644 --- a/i18n/fra/extensions/npm/package.i18n.json +++ b/i18n/fra/extensions/npm/package.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "config.npm.autoDetect": "ContrĆ“le si la dĆ©tection automatique des scripts npm est activĆ©e ou dĆ©sactivĆ©e. La valeur par dĆ©faut est activĆ©e.", - "config.npm.runSilent": "ExĆ©cuter les commandes npm avec l'option `--silent`" + "config.npm.runSilent": "ExĆ©cuter les commandes npm avec l'option `--silent`", + "npm.parseError": "DĆ©tection de tĆ¢che NpmĀ : impossible d’analyser le fichier {0}" } \ No newline at end of file diff --git a/i18n/fra/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/fra/extensions/typescript/out/features/taskProvider.i18n.json index 8b6ad71cd4e..e2466a7782b 100644 --- a/i18n/fra/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/fra/extensions/typescript/out/features/taskProvider.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "buildTscLabel": "build - {0}", + "buildAndWatchTscLabel": "watch - {0}" +} \ No newline at end of file diff --git a/i18n/fra/extensions/typescript/out/utils/api.i18n.json b/i18n/fra/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..96e054255c0 --- /dev/null +++ b/i18n/fra/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "version non valide" +} \ No newline at end of file diff --git a/i18n/fra/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/fra/extensions/typescript/out/utils/versionPicker.i18n.json index ea5f08fdab2..718528e4059 100644 --- a/i18n/fra/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/fra/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "Utiliser la version de VSCode", + "useVSCodeVersionOption": "Utiliser la version de VS Code", "useWorkspaceVersionOption": "Utiliser la version de l'espace de travail", "learnMore": "En savoir plus", "selectTsVersion": "SĆ©lectionner la version TypeScript utilisĆ©e pour les fonctionnalitĆ©s de langage JavaScript et TypeScript" diff --git a/i18n/fra/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/fra/extensions/typescript/out/utils/versionProvider.i18n.json index 9663a805143..eb6b0ab41a7 100644 --- a/i18n/fra/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/fra/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "Le tsserver de VSCode a Ć©tĆ© supprimĆ© par une autre application, par exemple un outil de dĆ©tection de virus mal configurĆ©. RĆ©installez VS Code." + "couldNotLoadTsVersion": "Impossible de charger la version TypeScript dans ce chemin", + "noBundledServerFound": "Le tsserver de VSCode a Ć©tĆ© supprimĆ© par une autre application, par exemple, un outil de dĆ©tection de virus mal configurĆ©. RĆ©installez VS Code." } \ No newline at end of file diff --git a/i18n/fra/extensions/typescript/package.i18n.json b/i18n/fra/extensions/typescript/package.i18n.json index 38e7c99e409..48b0d5d17dc 100644 --- a/i18n/fra/extensions/typescript/package.i18n.json +++ b/i18n/fra/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Fonctions complĆØtes avec leur signature de paramĆØtre.", "typescript.tsdk.desc": "SpĆ©cifie le chemin de dossier contenant les fichiers tsserver et lib*.d.ts Ć  utiliser.", - "typescript.disableAutomaticTypeAcquisition": "DĆ©sactive l'acquisition de type automatique. NĆ©cessite TypeScript >=Ā 2.0.6 et un redĆ©marrage, une fois le changement effectuĆ©.", + "typescript.disableAutomaticTypeAcquisition": "DĆ©sactive l'acquisition de type automatique. NĆ©cessite TypeScript >=Ā 2.0.6.", "typescript.tsserver.log": "Active la journalisation du serveur TS dans un fichier. Ce journal peut ĆŖtre utilisĆ© pour diagnostiquer les problĆØmes du serveur TS. Il peut contenir des chemins de fichier, du code source et d'autres informations potentiellement sensibles de votre projet.", "typescript.tsserver.trace": "Active le traƧage des messages envoyĆ©s au serveur TS. Cette trace peut ĆŖtre utilisĆ©e pour diagnostiquer les problĆØmes du serveur TS. Elle peut contenir des chemins de fichier, du code source et d'autres informations potentiellement sensibles de votre projet.", "typescript.validate.enable": "Activez/dĆ©sactivez la validation TypeScript.", @@ -44,7 +44,11 @@ "typescript.npm": "SpĆ©cifie le chemin de l'exĆ©cutable NPM utilisĆ© pour l'acquisition de type automatique. NĆ©cessite TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "VĆ©rifie si NPM est installĆ© pour l'acquisition de type automatique.", "javascript.nameSuggestions": "Activez/dĆ©sactivez l'inclusion de noms uniques Ć  partir du fichier dans les listes de suggestions JavaScript.", - "typescript.tsc.autoDetect": "ContrĆ“le si la dĆ©tection automatique des tĆ¢ches tsc est activĆ©e ou dĆ©sactivĆ©e.", + "typescript.tsc.autoDetect": "ContrĆ“le la dĆ©tection automatique des tĆ¢ches tsc. 'off' dĆ©sactive cette fonctionnalitĆ©. 'build' crĆ©e uniquement des tĆ¢ches de compilation Ć  exĆ©cution unique. 'watch' crĆ©e uniquement des tĆ¢ches de compilation et de watch. 'on' crĆ©e les deux les tĆ¢ches build et watch. La valeur par dĆ©faut est 'on'.", "typescript.problemMatchers.tsc.label": "ProblĆØmes liĆ©s Ć  TypeScript", - "typescript.problemMatchers.tscWatch.label": "ProblĆØmes liĆ©s Ć  TypeScript (mode espion)" + "typescript.problemMatchers.tscWatch.label": "ProblĆØmes liĆ©s Ć  TypeScript (mode espion)", + "typescript.quickSuggestionsForPaths": "Activer/dĆ©sactiver les suggestions rapides lorsque vous saisissez un chemin d’import.", + "typescript.locale": "DĆ©finit les paramĆØtres locaux utilisĆ©s pour signaler les erreurs TypeScript . NĆ©cessite TypeScript >= 2.6.0. Par dĆ©faut 'null' utilise les paramĆØtres locaux de VS Code pour les erreurs TypeScript.", + "javascript.implicitProjectConfig.experimentalDecorators": "Activer/dĆ©sactiver 'experimentalDecorators' pour les fichiers JavaScript qui ne font pas partie d'un projet. Les fichiers jsconfig.json ou tsconfig.json existants remplacent ce paramĆØtre. NĆ©cessite TypeScript >=2.3.1.", + "typescript.autoImportSuggestions.enabled": "Activer/dĆ©sactiver les suggestions d'import automatiques. NĆ©cessite TypeScript >= 2.6.1." } \ No newline at end of file diff --git a/i18n/fra/src/vs/code/electron-main/menus.i18n.json b/i18n/fra/src/vs/code/electron-main/menus.i18n.json index c4301b43c67..58e75c2db36 100644 --- a/i18n/fra/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/fra/src/vs/code/electron-main/menus.i18n.json @@ -22,9 +22,11 @@ "miQuit": "Quitter {0}", "miNewFile": "&&Nouveau fichier", "miOpen": "&&Ouvrir...", + "miOpenWorkspace": "&&Ouvrir un espace de travail...", "miOpenFolder": "Ouvrir le &&dossier", "miOpenFile": "&&Ouvrir un fichier...", "miOpenRecent": "Ouvrir les Ć©lĆ©ments &&rĆ©cents", + "miSaveWorkspaceAs": "&&Enregistrer l’espace de travail sous...", "miAddFolderToWorkspace": "&&Ajouter un dossier Ć  l'espace de travail...", "miSave": "&&Enregistrer", "miSaveAs": "Enregistrer &&sous...", @@ -32,6 +34,7 @@ "miAutoSave": "Enregistrement automatique", "miRevert": "RĆ©ta&&blir le fichier", "miCloseWindow": "Ferm&&er la fenĆŖtre", + "miCloseWorkspace": "&&Fermer l'espace de travail", "miCloseFolder": "&&Fermer le dossier", "miCloseEditor": "Fermer l'Ć©dit&&eur", "miExit": "Q&&uitter", @@ -44,6 +47,7 @@ "miPreferences": "&&PrĆ©fĆ©rences", "miReopenClosedEditor": "&&Rouvrir l'Ć©diteur fermĆ©", "miMore": "&&Plus...", + "miClearRecentOpen": "Effacer les fichiers &&rĆ©cents", "miUndo": "&&Annuler", "miRedo": "&&RĆ©tablir", "miCut": "Coupe&&r", @@ -98,6 +102,7 @@ "miHideActivityBar": "Masquer la &&Barre d'activitĆ©s", "miShowActivityBar": "Afficher la &&Barre d'activitĆ©s", "miToggleWordWrap": "Activer/dĆ©sactiver le retour automatique Ć  la &&ligne", + "miToggleMinimap": "Activer/dĆ©sactiver la &&minicarte", "miToggleRenderWhitespace": "Activer/dĆ©sactiver &&Restituer l'espace", "miToggleRenderControlCharacters": "Activer/dĆ©sactiver les &&caractĆØres de contrĆ“le", "miZoomIn": "&&Zoom avant", @@ -146,6 +151,10 @@ "mZoom": "Zoom", "mBringToFront": "Mettre tout au premier plan", "miSwitchWindow": "Changer de &&fenĆŖtre...", + "mShowPreviousTab": "Afficher l’onglet prĆ©cĆ©dent", + "mShowNextTab": "Afficher l’onglet suivant", + "mMoveTabToNewWindow": "DĆ©placer l’onglet vers une nouvelle fenĆŖtre", + "mMergeAllWindows": "Fusionner toutes les fenĆŖtres", "miToggleDevTools": "Activer/dĆ©sactiver les ou&&tils de dĆ©veloppement", "miAccessibilityOptions": "&&Options d'accessibilitĆ©", "miReportIssues": "S&&ignaler les problĆØmes", @@ -163,9 +172,10 @@ "miAbout": "ƀ pr&&opos de", "miRunTask": "&&ExĆ©cuter la tĆ¢che...", "miBuildTask": "ExĆ©cuter la &&tĆ¢che de gĆ©nĆ©ration...", + "miRunningTask": "Afficher les &&tĆ¢ches en cours...", "miRestartTask": "R&&edĆ©marrer la tĆ¢che en cours d'exĆ©cution...", "miTerminateTask": "&&Terminer la tĆ¢che...", - "miConfigureTask": "&&Configurer les tĆ¢ches", + "miConfigureTask": "&&Configurer les tĆ¢ches...", "miConfigureBuildTask": "Configurer la tĆ¢che de gĆ©nĆ©ration par dĆ©&&faut", "accessibilityOptionsWindowTitle": "Options d'accessibilitĆ©", "miRestartToUpdate": "RedĆ©marrer pour mettre Ć  jour...", @@ -174,5 +184,6 @@ "miDownloadingUpdate": "TĆ©lĆ©chargement de la mise Ć  jour...", "miInstallingUpdate": "Installation de la mise Ć  jour...", "miCheckForUpdates": "Rechercher les mises Ć  jour...", + "aboutDetail": "\nVersion {0}\nCommit {1}\nDate {2}\nShell {3}\nRenderer {4}\nNode {5}\nArchitecture {6}", "okButton": "OK" } \ No newline at end of file diff --git a/i18n/fra/src/vs/code/electron-main/windows.i18n.json b/i18n/fra/src/vs/code/electron-main/windows.i18n.json index d1f659dfa20..9ef71356aa9 100644 --- a/i18n/fra/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/fra/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,24 @@ "ok": "OK", "pathNotExistTitle": "Le chemin d'accĆØs n'existe pas", "pathNotExistDetail": "Le chemin d'accĆØs '{0}' ne semble plus exister sur le disque.", - "reopen": "Rouvrir", - "wait": "Continuer Ć  attendre", - "close": "Fermer", + "reopen": "&&Rouvrir", + "wait": "&&Continuer Ć  attendre", + "close": "&&Fermer", "appStalled": "La fenĆŖtre ne rĆ©pond plus", "appStalledDetail": "Vous pouvez rouvrir ou fermer la fenĆŖtre, ou continuer Ć  patienter.", "appCrashed": "La fenĆŖtre s'est bloquĆ©e", "appCrashedDetail": "Nous vous prions de nous excuser pour ce dĆ©sagrĆ©ment. Vous pouvez rouvrir la fenĆŖtre pour reprendre l'action au moment où elle a Ć©tĆ© interrompue.", + "open": "Ouvrir", + "openFolder": "Ouvrir le dossier", "openFile": "Ouvrir le fichier", - "openFolder": "Ouvrir le dossier" + "workspaceOpenedMessage": "Impossible d’enregistrer l’espace de travail '{0}'", + "workspaceOpenedDetail": "L’espace de travail est dĆ©jĆ  ouvert dans une autre fenĆŖtre. Veuillez s’il vous plaĆ®t d’abord fermer cette fenĆŖtre et puis essayez Ć  nouveau.", + "openWorkspace": "&&Ouvrir...", + "openWorkspaceTitle": "Ouvrir un espace de travail", + "save": "&&Enregistrer", + "doNotSave": "&&Ne pas enregistrer", + "cancel": "Annuler", + "saveWorkspaceMessage": "Voulez-vous enregistrer la configuration de votre espace de travail dans un fichierĀ ?", + "saveWorkspaceDetail": "Enregistrez votre espace de travail si vous avez l’intention de le rouvrir.", + "saveWorkspace": "Enregistrer l’espace de travail" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json index 7df44172608..27e0dbdef63 100644 --- a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "ContrĆ“le la hauteur de ligne. UtilisezĀ 0 pour calculer lineHeight Ć  partir de fontSize.", "letterSpacing": "DĆ©finit l'espacement des caractĆØres en pixels.", "lineNumbers": "ContrĆ“le l'affichage des numĆ©ros de ligne. Les valeurs possibles sont 'activĆ©', 'dĆ©sactivĆ©' et 'relatif'. La valeur 'relatif' indique le numĆ©ro de ligne Ć  partir de la position actuelle du curseur.", - "rulers": "Colonnes où afficher les rĆØgles verticales", + "rulers": "Afficher les rĆØgles verticales aprĆØs un certain nombre de caractĆØres Ć  espacement fixe. Utiliser plusieurs valeurs pour plusieurs rĆØgles. Aucune rĆØgle n'est dessinĆ©e si le tableau est vide", "wordSeparators": "CaractĆØres utilisĆ©s comme sĆ©parateurs de mots durant la navigation ou les opĆ©rations basĆ©es sur les mots", "tabSize": "Nombre d'espaces correspondant Ć  une tabulation. Ce paramĆØtre est remplacĆ© en fonction du contenu du fichier quand 'editor.detectIndentation' est activĆ©.", "tabSize.errorMessage": "'number' attendu. Notez que la valeur \"auto\" a Ć©tĆ© remplacĆ©e par le paramĆØtre 'editor.detectIndentation'.", @@ -20,8 +20,9 @@ "detectIndentation": "Quand vous ouvrez un fichier, 'editor.tabSize' et 'editor.insertSpaces' sont dĆ©tectĆ©s en fonction du contenu du fichier.", "roundedSelection": "ContrĆ“le si les sĆ©lections ont des angles arrondis", "scrollBeyondLastLine": "ContrĆ“le si l'Ć©diteur dĆ©file au-delĆ  de la derniĆØre ligne", + "smoothScrolling": "ContrĆ“le si l'Ć©diteur dĆ©filera en utilisant une animation", "minimap.enabled": "ContrĆ“le si la minicarte est affichĆ©e", - "minimap.showSlider": "ContrĆ“le si le curseur de la minicarte est automatiquement masquĆ©", + "minimap.showSlider": "ContrĆ“le si le curseur de la minicarte est automatiquement masquĆ©. Les valeurs possibles sont 'always' et 'mouseover'", "minimap.renderCharacters": "Afficher les caractĆØres rĆ©els sur une ligne (par opposition aux blocs de couleurs)", "minimap.maxColumn": "Limiter la largeur de la minicarte pour afficher au maximum un certain nombre de colonnes", "find.seedSearchStringFromSelection": "ContrĆ“le si nous remplissons la chaĆ®ne Ć  rechercher dans le Widget Recherche Ć  partir de la sĆ©lection de l'Ć©diteur", @@ -46,7 +47,7 @@ "autoClosingBrackets": "ContrĆ“le si l'Ć©diteur doit automatiquement fermer les crochets aprĆØs les avoir ouverts", "formatOnType": "ContrĆ“le si l'Ć©diteur doit automatiquement mettre en forme la ligne aprĆØs la saisie", "formatOnPaste": "ContrĆ“le si l'Ć©diteur doit automatiquement mettre en forme le contenu collĆ©. Un formateur doit ĆŖtre disponible et doit pouvoir mettre en forme une plage dans un document.", - "autoIndent": "ContrĆ“le si l'Ć©diteur doit automatiquement ajuster l'indentation quand les utilisateurs Ć©crivent, collent ou dĆ©placent des lignes. Les rĆØgles d'indentationĀ du langage doivent ĆŖtre disponibles.", + "autoIndent": "ContrĆ“le si l’éditeur doit ajuster automatiquement la mise en retrait lorsque les utilisateurs tapent, collent ou dĆ©placent des lignes. Les rĆØgles de mise en retrait du language doivent ĆŖtre disponibles.", "suggestOnTriggerCharacters": "ContrĆ“le si les suggestions doivent s'afficher automatiquement durant la saisie de caractĆØres de dĆ©clenchement", "acceptSuggestionOnEnter": "ContrĆ“le si les suggestions doivent ĆŖtre acceptĆ©es avec 'EntrĆ©e', en plus de 'Tab'. Cela permet d'Ć©viter toute ambiguĆÆtĆ© entre l'insertion de nouvelles lignes et l'acceptation de suggestions. La valeur 'smart' signifie que vous acceptez uniquement une suggestion avec EntrĆ©e quand elle applique une modification de texte", "acceptSuggestionOnCommitCharacter": "ContrĆ“le si les suggestions doivent ĆŖtre acceptĆ©es avec des caractĆØres de validation. Par exemple, en JavaScript, le point-virgule (';') peut ĆŖtre un caractĆØre de validation qui permet d'accepter une suggestion et de taper ce caractĆØre.", @@ -86,6 +87,8 @@ "accessibilitySupport.off": "L'Ć©diteur n'est jamais optimisĆ© pour une utilisation avec un lecteur d'Ć©cran.", "accessibilitySupport": "ContrĆ“le si l'Ć©diteur doit s'exĆ©cuter dans un mode optimisĆ© pour les lecteurs d'Ć©cran.", "links": "ContrĆ“le si l'Ć©diteur doit dĆ©tecter les liens et les rendre cliquables", + "colorDecorators": "ContrĆ“le si l'Ć©diteur doit afficher les Ć©lĆ©ments dĆ©coratifs de couleurs inline et le sĆ©lecteur de couleurs.", + "codeActions": "Active l'ampoule d'action de code", "sideBySide": "ContrĆ“le si l'Ć©diteur de diffĆ©rences affiche les diffĆ©rences en mode cĆ“te Ć  cĆ“te ou inline", "ignoreTrimWhitespace": "ContrĆ“le si l'Ć©diteur de diffĆ©rences affiche les changements liĆ©s aux espaces blancs de dĆ©but ou de fin comme des diffĆ©rences", "renderIndicators": "ContrĆ“le si l'Ć©diteur de diffĆ©rences affiche les indicateurs +/- pour les modifications ajoutĆ©es/supprimĆ©es", diff --git a/i18n/fra/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/fra/src/vs/editor/common/view/editorColorRegistry.i18n.json index 73727b48419..4bea17a181e 100644 --- a/i18n/fra/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/fra/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "Couleur de premier plan de la ligne ondulĆ©e marquant les erreurs dans l'Ć©diteur.", "errorBorder": "Couleur de bordure de la ligne ondulĆ©e marquant les erreurs dans l'Ć©diteur.", "warningForeground": "Couleur de premier plan de la ligne ondulĆ©e marquant les avertissements dans l'Ć©diteur.", - "warningBorder": "Couleur de bordure de la ligne ondulĆ©e marquant les avertissements dans l'Ć©diteur." + "warningBorder": "Couleur de bordure de la ligne ondulĆ©e marquant les avertissements dans l'Ć©diteur.", + "infoForeground": "Couleur de premier plan de la ligne ondulĆ©e marquant les informations dans l'Ć©diteur.", + "infoBorder": "Couleur de bordure de la ligne ondulĆ©e marquant les informations dans l'Ć©diteur.", + "overviewRulerRangeHighlight": "Couleur du marqueur de la rĆØgle d'aperƧu pour la mise en Ć©vidence de plage.", + "overviewRuleError": "Couleur du marqueur de la rĆØgle d'aperƧu pour les erreurs.", + "overviewRuleWarning": "Couleur du marqueur de la rĆØgle d'aperƧu pour les avertissements.", + "overviewRuleInfo": "Couleur du marqueur de la rĆØgle d'aperƧu pour les informations." } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json index e6ecb5ce261..b38c8823721 100644 --- a/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "Remplacer", "label.replaceAllButton": "Tout remplacer", "label.toggleReplaceButton": "Changer le mode de remplacement", - "title.matchesCountLimit": "Seuls les 999Ā premiers rĆ©sultats sont mis en surbrillance. Cependant, toutes les opĆ©rations de recherche sont appliquĆ©es Ć  l'ensemble du texte.", + "title.matchesCountLimit": "Seuls les {0} premiers rĆ©sultats sont mis en Ć©vidence, mais toutes les opĆ©rations de recherche fonctionnent sur l’ensemble du texte.", "label.matchesLocation": "{0} sur {1}", "label.noResults": "Aucun rĆ©sultat" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json index 7517a404783..21889b4123e 100644 --- a/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,10 +10,6 @@ "nextSelectionMatchFindAction": "SĆ©lection suivante", "previousSelectionMatchFindAction": "SĆ©lection prĆ©cĆ©dente", "startReplace": "Remplacer", - "addSelectionToNextFindMatch": "Ajouter la sĆ©lection Ć  la correspondance de recherche suivante", - "addSelectionToPreviousFindMatch": "Ajouter la sĆ©lection Ć  la correspondance de recherche prĆ©cĆ©dente", - "moveSelectionToNextFindMatch": "DĆ©placer la derniĆØre sĆ©lection vers la correspondance de recherche suivante", - "moveSelectionToPreviousFindMatch": "DĆ©placer la derniĆØre sĆ©lection Ć  la correspondance de recherche prĆ©cĆ©dente", - "selectAllOccurrencesOfFindMatch": "SĆ©lectionner toutes les occurrences des correspondances de la recherche", - "changeAll.label": "Modifier toutes les occurrences" + "showNextFindTermAction": "Afficher le terme de recherche suivant", + "showPreviousFindTermAction": "Afficher le terme de recherche prĆ©cĆ©dent" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/fra/src/vs/editor/contrib/format/browser/formatActions.i18n.json index b684a5befec..5d10d9569e4 100644 --- a/i18n/fra/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "{0} modifications de format effectuĆ©es Ć  la ligne {1}", "hint1n": "1Ā modification de format effectuĆ©e entre les lignes {0} et {1}", "hintnn": "{0} modifications de format effectuĆ©es entre les lignes {1} et {2}", + "no.provider": "DĆ©solĆ©, mais il n’y a aucun formateur installĆ© pour les fichiers '{0}'.", "formatDocument.label": "Mettre en forme le document", "formatSelection.label": "Mettre en forme la sĆ©lection" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/fra/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index bfa85d51156..2e7dbc5e1ee 100644 --- a/i18n/fra/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "AccĆ©der Ć  l'erreur ou l'avertissement prĆ©cĆ©dent", "editorMarkerNavigationError": "Couleur d'erreur du widget de navigation dans les marqueurs de l'Ć©diteur.", "editorMarkerNavigationWarning": "Couleur d'avertissement du widget de navigation dans les marqueurs de l'Ć©diteur.", + "editorMarkerNavigationInfo": "Couleur d’information du widget de navigation du marqueur de l'Ć©diteur.", "editorMarkerNavigationBackground": "ArriĆØre-plan du widget de navigation dans les marqueurs de l'Ć©diteur." } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 081fbcf0bec..04e943155da 100644 --- a/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Ajouter un curseur au-dessus", "mutlicursor.insertBelow": "Ajouter un curseur en dessous", - "mutlicursor.insertAtEndOfEachLineSelected": "Ajouter des curseurs Ć  la fin des lignes" + "mutlicursor.insertAtEndOfEachLineSelected": "Ajouter des curseurs Ć  la fin des lignes", + "addSelectionToNextFindMatch": "Ajouter la sĆ©lection Ć  la correspondance de recherche suivante", + "addSelectionToPreviousFindMatch": "Ajouter la sĆ©lection Ć  la correspondance de recherche prĆ©cĆ©dente", + "moveSelectionToNextFindMatch": "DĆ©placer la derniĆØre sĆ©lection vers la correspondance de recherche suivante", + "moveSelectionToPreviousFindMatch": "DĆ©placer la derniĆØre sĆ©lection Ć  la correspondance de recherche prĆ©cĆ©dente", + "selectAllOccurrencesOfFindMatch": "SĆ©lectionner toutes les occurrences des correspondances de la recherche", + "changeAll.label": "Modifier toutes les occurrences" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/fra/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..e7284c958c2 --- /dev/null +++ b/i18n/fra/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "Fermer" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/fra/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index 1b5900cc0db..45974daea0a 100644 --- a/i18n/fra/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Couleur d'arriĆØre-plan d'un symbole durant l'accĆØs en lecture, par exemple la lecture d'une variable.", - "wordHighlightStrong": "Couleur d'arriĆØre-plan d'un symbole durant l'accĆØs en Ć©criture, par exemple l'Ć©criture dans une variable." + "wordHighlightStrong": "Couleur d'arriĆØre-plan d'un symbole durant l'accĆØs en Ć©criture, par exemple l'Ć©criture dans une variable.", + "overviewRulerWordHighlightForeground": "Couleur du marqueur de la rĆØgle d'aperƧu pour la mise en Ć©vidence de symbole.", + "overviewRulerWordHighlightStrongForeground": "Couleur du marqueur de la rĆØgle d'aperƧu la mise en Ć©vidence de symbole d’accĆØs en Ć©criture.", + "wordHighlight.next.label": "Aller Ć  la prochaine mise en Ć©vidence de symbole", + "wordHighlight.previous.label": "Aller Ć  la mise en Ć©vidence de symbole prĆ©cĆ©dente" } \ No newline at end of file diff --git a/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 4ec0caa12c1..ed0024d2710 100644 --- a/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "Groupe auquel cette commande appartient", "vscode.extension.contributes.menus": "Contribue Ć  fournir des Ć©lĆ©ments de menu Ć  l'Ć©diteur", "menus.commandPalette": "Palette de commandes", + "menus.touchBar": "La touch bar (macOS uniquement)", "menus.editorTitle": "Menu de titre de l'Ć©diteur", "menus.editorContext": "Menu contextuel de l'Ć©diteur", "menus.explorerContext": "Menu contextuel de l'Explorateur de fichiers", "menus.editorTabContext": "Menu contextuel des onglets de l'Ć©diteur", "menus.debugCallstackContext": "Menu contextuel de la pile d'appels de dĆ©bogage", "menus.scmTitle": "Menu du titre du contrĆ“le de code source", + "menus.scmSourceControl": "Le menu de contrĆ“le de code source", "menus.resourceGroupContext": "Menu contextuel du groupe de ressources du contrĆ“le de code source", "menus.resourceStateContext": "Menu contextuel de l'Ć©tat des ressources du contrĆ“le de code source", "view.viewTitle": "Menu de titre de la vue ajoutĆ©e", diff --git a/i18n/fra/src/vs/platform/environment/node/argv.i18n.json b/i18n/fra/src/vs/platform/environment/node/argv.i18n.json index b4a7b53c42b..2f3ab904009 100644 --- a/i18n/fra/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/fra/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "Les arguments en mode '--goto' doivent ĆŖtre au format 'FILE(:LINE(:CHARACTER))'.", - "diff": "Ouvrez un Ć©diteur de diffĆ©rences. NĆ©cessite de passer deux chemins de fichiers comme arguments.", - "goto": "Ouvrez le fichier sur le chemin, Ć  la ligne et au caractĆØre indiquĆ©s (ajoutezĀ :line[:character] au chemin).", + "diff": "Comparez deux fichiers entre eux.", + "add": "Ajoutez un ou plusieurs dossiers Ć  la derniĆØre fenĆŖtre active.", + "goto": "Ouvrez un fichier dans le chemin, Ć  la ligne et la position de caractĆØre spĆ©cifiĆ©es.", "locale": "ParamĆØtres rĆ©gionaux Ć  utiliser (exempleĀ : fr-FR ou en-US).", "newWindow": "Forcez l'utilisation d'une nouvelle instance de Code.", "performance": "DĆ©marrez avec la commande 'DĆ©veloppeurĀ : performance de dĆ©marrage' activĆ©e.", @@ -14,7 +15,7 @@ "reuseWindow": "Forcez l'ouverture d'un fichier ou dossier dans la derniĆØre fenĆŖtre active.", "userDataDir": "SpĆ©cifie le rĆ©pertoire où sont conservĆ©es les donnĆ©es des utilisateurs. S'avĆØre utile pour une exĆ©cution en tant que root.", "verbose": "Affichez la sortie dĆ©taillĆ©e (implique --wait).", - "wait": "Attendez la fermeture de la fenĆŖtre avant un retour.", + "wait": "Attendre que les fichiers soient fermĆ©s avant de retourner.", "extensionHomePath": "DĆ©finissez le chemin racine des extensions.", "listExtensions": "Listez les extensions installĆ©es.", "showVersions": "Affichez les versions des extensions installĆ©es, quand --list-extension est utilisĆ©.", diff --git a/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 38f12473526..e6693aebb79 100644 --- a/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Extension non valideĀ : package.json n'est pas un fichier JSON.", - "restartCode": "RedĆ©marrez Code avant de rĆ©installer {0}.", - "installDependeciesConfirmation": "L'installation de '{0}' entraĆ®ne Ć©galement l'installation de ses dĆ©pendances. Voulez-vous continuerĀ ?", - "install": "Oui", - "doNotInstall": "Non", + "restartCodeLocal": "RedĆ©marrez Code avant de rĆ©installer {0}.", + "restartCodeGallery": "Veuillez s’il vous plaĆ®t redĆ©marrer Code avant la rĆ©installation.", "uninstallDependeciesConfirmation": "Voulez-vous dĆ©sinstaller uniquement '{0}' ou Ć©galement ses dĆ©pendancesĀ ?", "uninstallOnly": "Uniquement", "uninstallAll": "Tout", diff --git a/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 1b99c644dbb..77c19000246 100644 --- a/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "ƉvĆ©nements d'activation pour l'extension VS Code.", "vscode.extension.activationEvents.onLanguage": "ƉvĆ©nement d'activation envoyĆ© quand un fichier rĆ©solu dans le langage spĆ©cifiĆ© est ouvert.", "vscode.extension.activationEvents.onCommand": "ƉvĆ©nement d'activation envoyĆ© quand la commande spĆ©cifiĆ©e est appelĆ©e.", - "vscode.extension.activationEvents.onDebug": "ƉvĆ©nement d'activation envoyĆ© quand une session de dĆ©bogage du type spĆ©cifiĆ© est dĆ©marrĆ©e.", + "vscode.extension.activationEvents.onDebug": "Un Ć©vĆ©nement d’activation Ć©mis chaque fois qu’un utilisateur est sur le point de dĆ©marrer le dĆ©bogage ou sur le point de la dĆ©boguer des configurations.", "vscode.extension.activationEvents.workspaceContains": "ƉvĆ©nement d'activation envoyĆ© quand un dossier ouvert contient au moins un fichier correspondant au modĆØle glob spĆ©cifiĆ©.", "vscode.extension.activationEvents.onView": "ƉvĆ©nement d'activation envoyĆ© quand la vue spĆ©cifiĆ©e est dĆ©veloppĆ©e.", "vscode.extension.activationEvents.star": "ƉvĆ©nement d'activation envoyĆ© au dĆ©marrage de VS Code. Pour garantir la qualitĆ© de l'expĆ©rience utilisateur, utilisez cet Ć©vĆ©nement d'activation dans votre extension uniquement quand aucune autre combinaison d'Ć©vĆ©nements d'activation ne fonctionne dans votre cas d'utilisation.", diff --git a/i18n/fra/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/fra/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..9bf03d39312 --- /dev/null +++ b/i18n/fra/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "Contribue Ć  des couleurs dĆ©finies pour des extensions dont le thĆØme peut ĆŖtre changĆ©", + "contributes.color.id": "L’identifiant de la couleur dont le thĆØme peut ĆŖtre changĆ©", + "contributes.color.id.format": "Les identifiants doivent ĆŖtre sous la forme aa[.bb]*", + "contributes.color.description": "La description de la couleur dont le thĆØme peut ĆŖtre changĆ©", + "contributes.defaults.light": "La couleur par dĆ©faut pour les thĆØmes clairs. Soit une valeur de couleur en hexadĆ©cimal (#RRGGBB[AA]) ou l’identifiant d’une couleur dont le thĆØme peut ĆŖtre changĆ© qui fournit la valeur par dĆ©faut.", + "contributes.defaults.dark": "La couleur par dĆ©faut pour les thĆØmes sombres. Soit une valeur de couleur en hexadĆ©cimal (#RRGGBB[AA]) ou l’identifiant d’une couleur dont le thĆØme peut ĆŖtre changĆ© qui fournit la valeur par dĆ©faut.", + "contributes.defaults.highContrast": "La couleur par dĆ©faut pour les thĆØmes de contraste Ć©levĆ©. Soit une valeur de couleur en hexadĆ©cimal (#RRGGBB[AA]) ou l’identifiant d’une couleur dont le thĆØme peut ĆŖtre changĆ© qui fournit la valeur par dĆ©faut.", + "invalid.colorConfiguration": "'configuration.colors' doit ĆŖtre un tableau", + "invalid.default.colorType": "{0} doit ĆŖtre soit une valeur de couleur en hexadĆ©cimal (#RRGGBB[AA] ou #RGB[A]) ou l’identifiant d’une couleur dont le thĆØme peut ĆŖtre changĆ© qui fournit la valeur par dĆ©faut.", + "invalid.id": "'configuration.colors.id' doit ĆŖtre dĆ©fini et ne peut pas ĆŖtre vide", + "invalid.id.format": "'configuration.colors.id' doit suivre le word[.word]*", + "invalid.description": "'configuration.colors.description' doit ĆŖtre dĆ©fini et ne peut pas ĆŖtre vide", + "invalid.defaults": "'configuration.colors.defaults' doit ĆŖtre dĆ©fini et doit contenir 'light', 'dark' et 'highContrast'" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json index e92560f342a..64fc37335ec 100644 --- a/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/fra/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Format de couleur non valide. Utilisez #RGB, #RGBA, #RRGGBB ou #RRGGBBAA", "schema.colors": "Couleurs utilisĆ©es dans le banc d'essai.", "foreground": "Couleur de premier plan globale. Cette couleur est utilisĆ©e si elle n'est pas remplacĆ©e par un composant.", "errorForeground": "Couleur principale de premier plan pour les messages d'erreur. Cette couleur est utilisĆ©e uniquement si elle n'est pas redĆ©finie par un composant.", @@ -45,6 +44,7 @@ "listHoverForeground": "Premier plan de la liste/l'arborescence pendant le pointage sur des Ć©lĆ©ments avec la souris.", "listDropBackground": "ArriĆØre-plan de l'opĆ©ration de glisser-dĆ©placer dans une liste/arborescence pendant le dĆ©placement d'Ć©lĆ©ments avec la souris.", "highlight": "Couleur de premier plan dans la liste/l'arborescence pour la surbrillance des correspondances pendant la recherche dans une liste/arborescence.", + "invalidItemForeground": "Couleur de premier plan de liste/arbre pour les Ć©lĆ©ments non valides, par exemple une racine non rĆ©solue dans l’Explorateur.", "pickerGroupForeground": "Couleur du sĆ©lecteur rapide pour les Ć©tiquettes de regroupement.", "pickerGroupBorder": "Couleur du sĆ©lecteur rapide pour les bordures de regroupement.", "buttonForeground": "Couleur de premier plan du bouton.", @@ -85,5 +85,7 @@ "mergeBorder": "Couleur de bordure des en-tĆŖtes et du sĆ©parateur dans les conflits de fusion inline.", "overviewRulerCurrentContentForeground": "Premier plan de la rĆØgle d'aperƧu actuelle pour les conflits de fusion inline.", "overviewRulerIncomingContentForeground": "Premier plan de la rĆØgle d'aperƧu entrante pour les conflits de fusion inline.", - "overviewRulerCommonContentForeground": "ArriĆØre-plan de la rĆØgle d'aperƧu de l'ancĆŖtre commun dans les conflits de fusion inline." + "overviewRulerCommonContentForeground": "ArriĆØre-plan de la rĆØgle d'aperƧu de l'ancĆŖtre commun dans les conflits de fusion inline.", + "overviewRulerFindMatchForeground": "Couleur du marqueur de la rĆØgle d'aperƧu pour rechercher des correspondances.", + "overviewRulerSelectionHighlightForeground": "Couleur du marqueur de la rĆØgle d'aperƧu pour la mise en Ć©vidence de la sĆ©lection." } \ No newline at end of file diff --git a/i18n/fra/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/fra/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..decedacdeb2 --- /dev/null +++ b/i18n/fra/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Espace de travail de code", + "untitledWorkspace": "Sans titre(Espace de travail)", + "workspaceNameVerbose": "{0} (Espace de travail)", + "workspaceName": "{0} (Espace de travail)" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/fra/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..74930c2a09d --- /dev/null +++ b/i18n/fra/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "les vues doivent figurer dans un tableau", + "requirestring": "la propriĆ©tĆ© '{0}' est obligatoire et doit ĆŖtre de type 'string'", + "optstring": "La propriĆ©tĆ© '{0}' peut ĆŖtre omise ou doit ĆŖtre de type 'string'", + "vscode.extension.contributes.view.id": "Identificateur de la vue. Utilisez-le pour inscrire un fournisseur de donnĆ©es au moyen de l'API 'vscode.window.registerTreeDataProviderForView', ainsi que pour dĆ©clencher l'activation de votre extension en inscrivant l'Ć©vĆ©nement 'onView:${id}' dans 'activationEvents'.", + "vscode.extension.contributes.view.name": "Nom de la vue, contrĆ“lable de visu. AffichĆ©", + "vscode.extension.contributes.view.when": "Condition qui doit ĆŖtre vraie pour afficher cette vue", + "vscode.extension.contributes.views": "Ajoute des vues Ć  l'Ć©diteur", + "views.explorer": "Mode Explorateur", + "views.debug": "Debug View", + "locationId.invalid": "'{0}' n'est pas un emplacement de vue valide", + "duplicateView1": "Impossible d’enregistrer des vues multiples avec le mĆŖme id '{0}'Ā» dans l’emplacement '{1}'", + "duplicateView2": "Une vue avec l’id `{0}` est dĆ©jĆ  enregistrĆ©e Ć  l’emplacement `{1}`" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/fra/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..7c0c741150f --- /dev/null +++ b/i18n/fra/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "Ɖchec de l'activation de l'extension '{1}'. RaisonĀ : dĆ©pendance '{0}' inconnue.", + "failedDep1": "Ɖchec de l'activation de l'extension '{1}'. RaisonĀ : Ć©chec de l'activation de la dĆ©pendance '{0}'.", + "failedDep2": "Ɖchec de l'activation de l'extension '{0}'. RaisonĀ : plus de 10Ā niveaux de dĆ©pendances (probablement une boucle de dĆ©pendance).", + "activationError": "Ɖchec de l'activation de l'extension '{0}'Ā : {1}." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json index bdfc2772c39..6158fd5950f 100644 --- a/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,11 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "Ouvrir un fichier...", "openFolder": "Ouvrir un dossier...", "openFileFolder": "Ouvrir...", - "cancel": "Annuler", "addFolderToWorkspace": "Ajouter un dossier Ć  l'espace de travail...", + "add": "&&Ajouter", "addFolderToWorkspaceTitle": "Ajouter un dossier Ć  l'espace de travail", + "globalRemoveFolderFromWorkspace": "Supprimer le dossier d’espace de travail...", "removeFolderFromWorkspace": "Supprimer le dossier de l'espace de travail", - "save": "&&Enregistrer" + "openFolderSettings": "Ouvrir le dossier ParamĆØtres", + "saveWorkspaceAsAction": "Enregistrer l’espace de travail sous...", + "save": "&&Enregistrer", + "saveWorkspace": "Enregistrer l’espace de travail", + "openWorkspaceAction": "Ouvrir un espace de travail...", + "openWorkspaceConfigFile": "Ouvrir le Fichier de Configuration d’espace de travail", + "openFolderAsWorkspaceInNewWindow": "Ouvrir le dossier en tant qu'espace de travail dans une nouvelle fenĆŖtre", + "workspaceFolderPickerPlaceholder": "SĆ©lectionner le dossier de l’espace de travail" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index b512a195332..1bd02d3dbad 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "Supprimer de la barre d'activitĆ©s", - "keepInActivityBar": "Conserver dans la barre d'activitĆ©s", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Masquer de la barre d’activitĆ©s", + "keepInActivityBar": "Conserver dans la barre d'activitĆ©s", "additionalViews": "Vues supplĆ©mentaires", "numberBadge": "{0} ({1})", "manageExtension": "GĆ©rer l'extension", diff --git a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index a04b897abfe..affef8547e2 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Masquer la barre d'activitĆ©s", - "activityBarAriaLabel": "SĆ©lecteur d'affichage actif", "globalActions": "Actions globales" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..ed052dd9d9c --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "SĆ©lecteur d'affichage actif" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..ee22c640dbd --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Vues supplĆ©mentaires", + "numberBadge": "{0} ({1})", + "manageExtension": "GĆ©rer l'extension", + "titleKeybinding": "{0} ({1})", + "hide": "Masquer", + "keep": "Garder", + "toggle": "Afficher/masquer la vue Ć©pinglĆ©e" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index dc32ce2159e..4326e29e9e4 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Afficher les Ć©diteurs du deuxiĆØme groupe", "groupThreePicker": "Afficher les Ć©diteurs du troisiĆØme groupe", "allEditorsPicker": "Afficher tous les Ć©diteurs ouverts", - "view": "Affichage" + "view": "Affichage", + "file": "Fichier" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 9927a31f58e..a7e57354829 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,7 +35,9 @@ "openPreviousEditorInGroup": "Ouvrir l'Ć©diteur prĆ©cĆ©dent du groupe", "navigateNext": "Suivant", "navigatePrevious": "PrĆ©cĆ©dent", + "navigateLast": "Aller au dernier", "reopenClosedEditor": "Rouvrir l'Ć©diteur fermĆ©", + "clearRecentFiles": "Effacer les fichiers rĆ©cemment ouverts", "showEditorsInFirstGroup": "Afficher les Ć©diteurs du premier groupe", "showEditorsInSecondGroup": "Afficher les Ć©diteurs du deuxiĆØme groupe", "showEditorsInThirdGroup": "Afficher les Ć©diteurs du troisiĆØme groupe", diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 4bda3973ff4..dc585654a46 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "La touche Tab dĆ©place le focus", - "screenReaderDetected": "Lecteur d'Ć©cran dĆ©tectĆ©", + "screenReaderDetected": "OptimisĆ© pour un lecteur d’écran ", "screenReaderDetectedExtra": "Si vous n'utilisez pas de lecteur d'Ć©cran, dĆ©finissez le paramĆØtre 'editor.accessibilitySupport' sur \"dĆ©sactivĆ©\".", "disableTabMode": "DĆ©sactiver le mode d'accessibilitĆ©", "gotoLine": "Atteindre la ligne", @@ -47,5 +47,11 @@ "reopenWithEncoding": "Rouvrir avec l'encodage", "guessedEncoding": "DevinĆ© Ć  partir du contenu", "pickEncodingForReopen": "SĆ©lectionner l'encodage du fichier pour rouvrir le fichier", - "pickEncodingForSave": "SĆ©lectionner l'encodage du fichier Ć  utiliser pour l'enregistrement" + "pickEncodingForSave": "SĆ©lectionner l'encodage du fichier Ć  utiliser pour l'enregistrement", + "screenReaderDetectedExplanation.title": "OptimisĆ© pour un lecteur d’écran ", + "screenReaderDetectedExplanation.question": "Est-ce que vous utilisez un lecteur d’écran pour faire fonctionner VS Code ?", + "screenReaderDetectedExplanation.answerYes": "Oui", + "screenReaderDetectedExplanation.answerNo": "Non", + "screenReaderDetectedExplanation.body1": "VS Code est maintenant optimisĆ© pour une utilisation avec un lecteur d’écran.", + "screenReaderDetectedExplanation.body2": "Certaines fonctionnalitĆ©s de l’éditeur auront des comportements diffĆ©rentsĀ : par exemple l'encapsulation, le repliage, l'auto-fermeture des parenthĆØses, etc..." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 7acd01eb2f3..1ff4e23202d 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Fermer le panneau", "togglePanel": "Activer/dĆ©sactiver le panneau", "focusPanel": "Focus dans le panneau", + "toggledPanelPosition": "Basculer la position du panneau", + "moveToRight": "DĆ©placer Ć  droite", + "moveToBottom": "DĆ©placer en bas", "toggleMaximizedPanel": "Activer/dĆ©sactiver le panneau agrandi", "maximizePanel": "Agrandir la taille du panneau", "minimizePanel": "Restaurer la taille du panneau", diff --git a/i18n/fra/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json index ab3e54a798d..7a0ea73a96a 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "compositePart.hideSideBarLabel": "Masquer la barre latĆ©rale", "focusSideBar": "Focus sur la barre latĆ©rale", "viewCategory": "Affichage" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 6e9f1b4185b..d4a3eda558a 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "La commande '{0}' n'est pas activĆ©e et ne peut pas ĆŖtre exĆ©cutĆ©e.", "manageExtension": "GĆ©rer l'extension" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..4868e0b0e11 --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} actions" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..fcd571da926 --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} actions", + "hideView": "Masquer dans la barre latĆ©rale" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..e7ba8e9e54b --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "Une vue avec l’id `{0}` est dĆ©jĆ  enregistrĆ©e Ć  l’emplacement `{1}`" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..3ed5e9fc685 --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "Masquer dans la barre latĆ©rale" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/common/theme.i18n.json b/i18n/fra/src/vs/workbench/common/theme.i18n.json index 2c777584371..af5be6b5265 100644 --- a/i18n/fra/src/vs/workbench/common/theme.i18n.json +++ b/i18n/fra/src/vs/workbench/common/theme.i18n.json @@ -7,6 +7,8 @@ "tabActiveBackground": "Couleur d'arriĆØre-plan de l'onglet actif. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©diteurs. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", "tabInactiveBackground": "Couleur d'arriĆØre-plan de l'onglet inactif. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©diteurs. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", "tabBorder": "Bordure sĆ©parant les onglets les uns des autres. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©diteurs. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", + "tabActiveBorder": "Bordure pour mettre en Ć©vidence les onglets actifs. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©dition. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", + "tabActiveUnfocusedBorder": "Bordure pour mettre en Ć©vidence les onglets actifs dans un groupe inactif. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©dition. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", "tabActiveForeground": "Couleur de premier plan de l'onglet actif dans un groupe actif. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©diteurs. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", "tabInactiveForeground": "Couleur de premier plan de l'onglet inactif dans un groupe actif. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©diteurs. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", "tabUnfocusedActiveForeground": "Couleur de premier plan de l'onglet actif dans un groupe inactif. Les onglets sont les conteneurs des Ć©diteurs dans la zone d'Ć©diteurs. Vous pouvez ouvrir plusieurs onglets dans un groupe d'Ć©diteurs. Il peut exister plusieurs groupes d'Ć©diteurs.", @@ -18,15 +20,16 @@ "editorGroupBorder": "Couleur sĆ©parant plusieurs groupes d'Ć©diteurs les uns des autres. Les groupes d'Ć©diteurs sont les conteneurs des Ć©diteurs.", "editorDragAndDropBackground": "Couleur d'arriĆØre-plan lors du dĆ©placement des Ć©diteurs par glissement. La couleur doit avoir une transparence pour que le contenu de l'Ć©diteur soit visible Ć  travers.", "panelBackground": "Couleur d'arriĆØre-plan du panneau. Les panneaux s'affichent sous la zone d'Ć©diteurs et contiennent des affichages tels que la sortie et le terminal intĆ©grĆ©.", - "panelBorder": "Couleur de bordure de panneau dans la partie supĆ©rieure de sĆ©paration de l'Ć©diteur. Les panneaux s'affichent sous la zone d'Ć©diteurs et contiennent des affichages tels que la sortie et le terminal intĆ©grĆ©.", "panelActiveTitleForeground": "Couleur du titre du panneau actif. Les panneaux se situent sous la zone de l'Ć©diteur et contiennent des affichages comme la sortie et le terminal intĆ©grĆ©.", "panelInactiveTitleForeground": "Couleur du titre du panneau inactif. Les panneaux se situent sous la zone de l'Ć©diteur et contiennent des affichages comme la sortie et le terminal intĆ©grĆ©.", "panelActiveTitleBorder": "Couleur de la bordure du titre du panneau actif. Les panneaux se situent sous la zone de l'Ć©diteur et contiennent des affichages comme la sortie et le terminal intĆ©grĆ©.", - "statusBarForeground": "Couleur de premier plan de la barre d'Ć©tat. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", + "panelDragAndDropBackground": "Glissez et dĆ©posez la couleur de vos commentaires pour les Ć©lĆ©ments de titre du panneau. La couleur devrait avoir de la transparence afin que les entrĆ©es du panneau puissent encore briller Ć  travers. Les panneaux apparaissent sous la zone de l’éditeur et contiennent des vues comme la sortie et le terminal intĆ©grĆ©.", + "statusBarForeground": "Couleur de premier plan de la barre d'Ć©tat quand l'espace de travail est ouvert. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", "statusBarNoFolderForeground": "Couleur de premier plan de la barre d'Ć©tat quand aucun dossier n'est ouvert. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", - "statusBarBackground": "Couleur d'arriĆØre-plan de la barre d'Ć©tat standard. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", + "statusBarBackground": "Couleur d'arriĆØre-plan de la barre d'Ć©tat quand l'espace de travail est ouvert. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", "statusBarNoFolderBackground": "Couleur d'arriĆØre-plan de la barre d'Ć©tat quand aucun dossier n'est ouvert. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", "statusBarBorder": "Couleur de bordure de la barre d'Ć©tat faisant la sĆ©paration avec la barre latĆ©rale et l'Ć©diteur. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", + "statusBarNoFolderBorder": "Couleur de la bordure qui sĆ©pare la barre latĆ©rale et l’éditeur lorsque aucun dossier ne s’ouvre la barre d’état. La barre d’état s’affiche en bas de la fenĆŖtre.", "statusBarItemActiveBackground": "Couleur d'arriĆØre-plan de l'Ć©lĆ©ment de la barre d'Ć©tat durant un clic. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", "statusBarItemHoverBackground": "Couleur d'arriĆØre-plan de l'Ć©lĆ©ment de la barre d'Ć©tat durant un pointage. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", "statusBarProminentItemBackground": "Couleur d'arriĆØre-plan des Ć©lĆ©ments importants de la barre d'Ć©tat. Les Ć©lĆ©ments importants se diffĆ©rencient des autres entrĆ©es de la barre d'Ć©tat pour indiquer l'importance. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre.", @@ -41,12 +44,14 @@ "sideBarForeground": "Couleur de premier plan de la barre latĆ©rale. La barre latĆ©rale est le conteneur des vues comme celles de l'explorateur et de la recherche.", "sideBarBorder": "Couleur de bordure de la barre latĆ©rale faisant la sĆ©paration avec l'Ć©diteur. La barre latĆ©rale est le conteneur des vues comme celles de l'explorateur et de la recherche.", "sideBarTitleForeground": "Couleur de premier plan du titre de la barre latĆ©rale. La barre latĆ©rale est le conteneur des affichages tels que ceux de l'exploration et la recherche.", + "sideBarDragAndDropBackground": "Glisser-dĆ©poser la couleur pour les sections de barre latĆ©rale. La couleur devrait avoir de la transparence afin que les sections de barre latĆ©rale puissent encore briller Ć  travers. La barre latĆ©rale est le conteneur des vues comme l'explorateur et la recherche.", "sideBarSectionHeaderBackground": "Couleur d'arriĆØre-plan de l'en-tĆŖte de section de la barre latĆ©rale. La barre latĆ©rale est le conteneur des vues comme celles de l'explorateur et la recherche.", "sideBarSectionHeaderForeground": "Couleur de premier plan de l'en-tĆŖte de section de la barre latĆ©rale. La barre latĆ©rale est le conteneur des vues comme celles de l'explorateur et de la recherche.", "titleBarActiveForeground": "Premier plan de la barre de titre quand la fenĆŖtre est active. Notez que cette couleur est uniquement prise en charge sur macOS.", "titleBarInactiveForeground": "Premier plan de la barre de titre quand la fenĆŖtre est inactive. Notez que cette couleur est uniquement prise en charge sur macOS.", "titleBarActiveBackground": "ArriĆØre-plan de la barre de titre quand la fenĆŖtre est active. Notez que cette couleur est uniquement prise en charge sur macOS.", "titleBarInactiveBackground": "ArriĆØre-plan de la barre de titre quand la fenĆŖtre est inactive. Notez que cette couleur est uniquement prise en charge sur macOS.", + "titleBarBorder": "Couleur de bordure de la barre titre. Notez que cette couleur est actuellement uniquement pris en charge sur macOS.", "notificationsForeground": "Couleur de premier plan des notifications. Les notifications dĆ©filent Ć  partir du haut de la fenĆŖtre.", "notificationsBackground": "Couleur d'arriĆØre-plan des notifications. Les notifications dĆ©filent Ć  paritr du haut de la fenĆŖtre.", "notificationsButtonBackground": "Couleur d'arriĆØre-plan du bouton des notifications. Les notifications dĆ©filent Ć  partir du haut de la fenĆŖtre.", diff --git a/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json index a082ef906e1..fc7be7db920 100644 --- a/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json @@ -6,6 +6,8 @@ { "closeActiveEditor": "Fermer l'Ć©diteur", "closeWindow": "Fermer la fenĆŖtre", + "closeWorkspace": "Fermer l’espace de travail", + "noWorkspaceOpened": "Il n’y a actuellement aucun espace de travail ouvert dans cette instance Ć  fermer.", "newWindow": "Nouvelle fenĆŖtre", "toggleFullScreen": "Plein Ć©cran", "toggleMenuBar": "Activer/dĆ©sactiver la barre de menus", @@ -20,7 +22,11 @@ "close": "Fermer la fenĆŖtre", "switchWindow": "Changer de fenĆŖtre...", "quickSwitchWindow": "Changement rapide de fenĆŖtre...", + "workspaces": "espaces de travail", "files": "fichiers", + "openRecentPlaceHolderMac": "SĆ©lectionner pour ouvrir (maintenir Cmd-key pour ouvrir dans une nouvelle fenĆŖtre)", + "openRecentPlaceHolder": "SĆ©lectionner pour ouvrir (maintenir Ctrl-key pour ouvrir dans une nouvelle fenĆŖtre)", + "remove": "Supprimer des rĆ©cemment ouverts", "openRecent": "Ouvrir les Ć©lĆ©ments rĆ©cents...", "quickOpenRecent": "Ouverture rapide des Ć©lĆ©ments rĆ©cents...", "closeMessages": "Fermer les messages de notification", @@ -36,5 +42,10 @@ "navigateUp": "Naviguer vers l'affichage au-dessus", "navigateDown": "Naviguer vers l'affichage en dessous", "increaseViewSize": "Augmenter la taille de l'affichage actuel", - "decreaseViewSize": "Diminuer la taille de l'affichage actuel" + "decreaseViewSize": "Diminuer la taille de l'affichage actuel", + "showPreviousTab": "Afficher l’onglet de la fenĆŖtre prĆ©cĆ©dente", + "showNextWindowTab": "Afficher l’onglet de la fenĆŖtre suivante", + "moveWindowTabToNewWindow": "DĆ©placer l’onglet de la fenĆŖtre vers la nouvelle fenĆŖtre", + "mergeAllWindowTabs": "Fusionner toutes les fenĆŖtres", + "toggleWindowTabsBar": "Activer/dĆ©sactiver la barre de fenĆŖtres d’onglets" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/fra/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..a8e6e2e5147 --- /dev/null +++ b/i18n/fra/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "Configurer la langue", + "displayLanguage": "DĆ©finit le langage affichĆ© par VSCode.", + "doc": "Consultez {0} pour connaĆ®tre la liste des langues prises en charge.", + "restart": "Le changement de la valeur nĆ©cessite le redĆ©marrage de VS Code.", + "fail.createSettings": "Impossible de crĆ©er '{0}' ({1}).", + "JsonSchema.locale": "Langue d'interface utilisateur (IU) Ć  utiliser." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json index 4753f90d9c4..4827be6525f 100644 --- a/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -7,22 +7,35 @@ "view": "Affichage", "help": "Aide", "file": "Fichier", + "workspaces": "Espaces de travail", "developer": "DĆ©veloppeur", "showEditorTabs": "ContrĆ“le si les Ć©diteurs ouverts doivent s'afficher ou non sous des onglets.", + "workbench.editor.labelFormat.default": "Afficher le nom du fichier. Lorsque les onglets sont activĆ©s et que deux fichiers portent le mĆŖme nom dans un groupe, les sections distinctes du chemin de chaque fichier sont ajoutĆ©es. Lorsque les onglets sont dĆ©sactivĆ©es, le chemin d’accĆØs relatif au dossier de l'espace de travail est affichĆ© si l’éditeur est actif.", + "workbench.editor.labelFormat.short": "Indiquer le nom du fichier suivi de son nom de rĆ©pertoire.", + "workbench.editor.labelFormat.medium": "Afficher le nom du fichier suivi de son chemin d’accĆØs relatif au dossier de l'espace de travail.", + "workbench.editor.labelFormat.long": "Indiquer le nom du fichier suivi de son chemin d’accĆØs absolu.", + "tabDescription": "ContrĆ“le le format de l’étiquette d’un Ć©diteur. La modification de ce paramĆØtre peut par exemple rendre plus facile la comprĆ©hension de l’emplacement d’un fichier :\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', quand un autre onglet partage le mĆŖme titre, ou la chemin d’accĆØs relatif Ć  l'espace de travail si les onglets sont dĆ©sactivĆ©s", "editorTabCloseButton": "ContrĆ“le la position des boutons de fermeture des onglets de l'Ć©diteur, ou les dĆ©sactive quand le paramĆØtre a la valeur 'off'.", "showIcons": "ContrĆ“le si les Ć©diteurs ouverts doivent s'afficher ou non avec une icĆ“ne. Cela implique notamment l'activation d'un thĆØme d'icĆ“ne.", - "enablePreview": "ContrĆ“le si les Ć©diteurs ouverts s'affichent en mode aperƧu. Les Ć©diteurs en mode aperƧu sont rĆ©utilisĆ©s jusqu'Ć  ce qu'ils soient conservĆ©s (par exemple, aprĆØs un double-clic ou une modification).", + "enablePreview": "ContrĆ“le si les Ć©diteurs ouverts s'affichent en mode aperƧu. Les Ć©diteurs en mode aperƧu sont rĆ©utilisĆ©s jusqu'Ć  ce qu'ils soient conservĆ©s (par exemple, aprĆØs un double-clic ou une modification) et apparaissent avec un style de police en italique.", "enablePreviewFromQuickOpen": "ContrĆ“le si les Ć©diteurs de Quick Open s'affichent en mode aperƧu. Les Ć©diteurs en mode aperƧu sont rĆ©utilisĆ©s jusqu'Ć  ce qu'ils soient conservĆ©s (par exemple, aprĆØs un double-clic ou une modification).", - "editorOpenPositioning": "ContrĆ“le l'emplacement de l'ouverture des Ć©diteurs. SĆ©lectionnez 'left' ou 'right' pour ouvrir les Ć©diteurs Ć  gauche ou Ć  droite de l'Ć©diteur actuellement actif. SĆ©lectionnez 'first' ou 'last' pour ouvrir les Ć©diteurs indĆ©pendamment de l'Ć©diteur actuellement actif.", + "editorOpenPositioning": "Permet de dĆ©finir Ć  quel endroit les Ć©diteurs s'ouvrent. SĆ©lectionnez 'left' ou 'right' pour ouvrir les Ć©diteurs Ć  gauche ou Ć  droite de celui actuellement actif. SĆ©lectionnez 'first' ou 'last' pour ouvrir les Ć©diteurs indĆ©pendamment de celui actuellement actif.", "revealIfOpen": "ContrĆ“le si un Ć©diteur est affichĆ© dans l'un des groupes visibles, s'il est ouvert. Si cette option est dĆ©sactivĆ©e, l'Ć©diteur s'ouvre de prĆ©fĆ©rence dans le groupe d'Ć©diteurs actif. Si cette option est activĆ©e, tout Ć©diteur dĆ©jĆ  ouvert est affichĆ© au lieu d'ĆŖtre rouvert dans le groupe d'Ć©diteurs actif. Notez que dans certains cas, ce paramĆØtre est ignorĆ©, par exemple quand vous forcez un Ć©diteur Ć  s'ouvrir dans un groupe spĆ©cifique ou Ć  cĆ“tĆ© du groupe actif.", - "commandHistory": "ContrĆ“le le nombre de commandes rĆ©cemment utilisĆ©es Ć  conserver dans l'historique de la palette de commandes. DĆ©finissez cette valeur sur 0 pour dĆ©sactiver l'historique de commandes.", + "commandHistory": "ContrĆ“le le nombre de commandes rĆ©cemment utilisĆ©es Ć  retenir dans l’historique de la palette de commande. SpĆ©cifier la valeur 0 pour dĆ©sactiver l’historique des commandes.", "preserveInput": "ContrĆ“le si la derniĆØre entrĆ©e tapĆ©e dans la palette de commandes doit ĆŖtre restaurĆ©e Ć  la prochaine ouverture.", "closeOnFocusLost": "ContrĆ“le si Quick Open doit se fermer automatiquement, une fois qu'il a perdu le focus.", "openDefaultSettings": "ContrĆ“le si l'ouverture des paramĆØtres entraĆ®ne Ć©galement l'ouverture d'un Ć©diteur qui affiche tous les paramĆØtres par dĆ©faut.", + "experimentalFuzzySearchEndpoint": "Indique le point de terminaison Ć  utiliser pour la recherche des paramĆØtres expĆ©rimentaux.", + "experimentalFuzzySearchKey": "Indique la clĆ© Ć  utiliser pour la recherche des paramĆØtres expĆ©rimentaux.", "sideBarLocation": "ContrĆ“le l'emplacement de la barre latĆ©rale. Elle peut s'afficher Ć  gauche ou Ć  droite du banc d'essai.", + "panelLocation": "ContrĆ“le l’emplacement du panneau. Il peut soit ĆŖtre affichĆ© en bas ou Ć  droite du banc d'essai.", "statusBarVisibility": "ContrĆ“le la visibilitĆ© de la barre d'Ć©tat au bas du banc d'essai.", "activityBarVisibility": "ContrĆ“le la visibilitĆ© de la barre d'activitĆ©s dans le banc d'essai.", "closeOnFileDelete": "ContrĆ“le si les Ć©diteurs qui affichent un fichier doivent se fermer automatiquement quand ce fichier est supprimĆ© ou renommĆ© par un autre processus. Si vous dĆ©sactivez cette option, l'Ć©diteur reste ouvert dans un Ć©tat indiquant une intĆ©gritĆ© compromise. Notez que la suppression de fichiers Ć  partir de l'application entraĆ®ne toujours la fermeture de l'Ć©diteur, et que les fichiers Ć  l'intĆ©gritĆ© compromise ne sont jamais fermĆ©s pour permettre la conservation de vos donnĆ©es.", + "fontAliasing": "ContrĆ“le la mĆ©thode de font aliasing dans le workbench.\n- par dĆ©fautĀ : Lissage des polices de sous-pixel. Sur la plupart des affichages non-ratina, cela vous donnera le texte le plus vif\n- crĆ©nelĆ©esĀ : Lisse les polices au niveau du pixel, plutĆ“t que les sous-pixels. Peut faire en sorte que la police apparaisse plus lĆ©gĆØre dans l’ensemble \n- noneĀ : dĆ©sactive le lissage des polices. Le texte s'affichera avec des bordures dentelĆ©es", + "workbench.fontAliasing.default": "Lissage de sous-pixel des polices. Sur la plupart des affichages non-retina, cela vous donnera le texte le plus vif.", + "workbench.fontAliasing.antialiased": "Lisser les polices au niveau du pixel, plutĆ“t que les sous-pixels. Peut faire en sorte que la police apparaisse plus lĆ©gĆØre dans l’ensemble.", + "workbench.fontAliasing.none": "DĆ©sactive le lissage des polices. Le texte s'affichera avec des bordures dentelĆ©es.", "swipeToNavigate": "Parcourez les fichiers ouverts en faisant glisser trois doigts horizontalement. ", "workbenchConfigurationTitle": "Banc d'essai", "window.openFilesInNewWindow.on": "Les fichiers s'ouvrent dans une nouvelle fenĆŖtre", @@ -34,16 +47,19 @@ "window.openFoldersInNewWindow.default": "Les dossiers s'ouvrent dans une nouvelle fenĆŖtre, sauf si un dossier est sĆ©lectionnĆ© depuis l'application (par exemple, via le menu Fichier)", "openFoldersInNewWindow": "ContrĆ“le si les dossiers doivent s'ouvrir dans une nouvelle fenĆŖtre ou remplacer la derniĆØre fenĆŖtre active.\n- defaultĀ : les dossiers s'ouvrent dans une nouvelle fenĆŖtre, sauf si un dossier est sĆ©lectionnĆ© depuis l'application (par exemple, via le menu Fichier)\n- onĀ : les dossiers s'ouvrent dans une nouvelle fenĆŖtre\n- offĀ : les dossiers remplacent la derniĆØre fenĆŖtre active\nNotez que dans certains cas, ce paramĆØtre est ignorĆ© (par exemple, quand vous utilisez l'option de ligne de commande -new-window ou -reuse-window).", "window.reopenFolders.all": "Rouvre toutes les fenĆŖtres.", + "window.reopenFolders.folders": "Rouvrir tous les dossiers. Les espaces de travail vides ne seront pas restaurĆ©es.", "window.reopenFolders.one": "Rouvre la derniĆØre fenĆŖtre active.", "window.reopenFolders.none": "Ne jamais rouvrir de fenĆŖtre. Toujours dĆ©marrer avec une fenĆŖtre vide.", + "restoreWindows": "ContrĆ“le comment les fenĆŖtres seront rouvertes aprĆØs un redĆ©marrage. SĆ©lectionner 'none' pour toujours dĆ©marrer avec un espace de travail vide, 'one' pour rouvrir la derniĆØre fenĆŖtre avec laquelle vous avez travaillĆ©, 'folders' pour rouvrir toutes les fenĆŖtres qui avaient des dossiers ouverts ou 'all' pour rouvrir toutes les fenĆŖtres de votre derniĆØre session.", "restoreFullscreen": "ContrĆ“le si une fenĆŖtre doit ĆŖtre restaurĆ©e en mode plein Ć©cran si elle a Ć©tĆ© fermĆ©e dans ce mode.", "zoomLevel": "Modifiez le niveau de zoom de la fenĆŖtre. La taille d'origine est 0. Chaque incrĆ©ment supĆ©rieur (exempleĀ : 1) ou infĆ©rieur (exempleĀ : -1) reprĆ©sente un zoom 20Ā % plus gros ou plus petit. Vous pouvez Ć©galement entrer des dĆ©cimales pour changer le niveau de zoom avec une granularitĆ© plus fine.", - "title": "ContrĆ“le le titre de la fenĆŖtre en fonction de l'Ć©diteur actif. Les variables sont remplacĆ©es selon le contexte :\n${activeEditorShort} : par ex., myFile.txt\n${activeEditorMedium} : par ex., myFolder/myFile.txt\n${activeEditorLong} : par ex., /Users/Development/myProject/myFolder/myFile.txt\n${folderName} : par ex., myFolder\n${folderPath} : par ex., /Users/Development/myFolder\n${rootName} : par ex., myFolder1, myFolder2, myFolder3\n${rootPath} : par ex., /Users/Development/myWorkspace\n${appName} : par ex., VS Code\n${dirty} : indicateur d'intĆ©gritĆ© si l'intĆ©gritĆ© de l'Ć©diteur actif est compromise\n${separator} : sĆ©parateur conditionnel (\" - \") qui s'affiche uniquement quand il est entourĆ© de variables avec des valeurs", + "title": "ContrĆ“le le titre de la fenĆŖtre en fonction sur l’éditeur actif. Les variables sont remplacĆ©s selon le contexteĀ : ${activeEditorShort}Ā : le nom du fichier (ex: monFichier.txt) ${activeEditorMedium}Ā : le chemin d’accĆØs au fichier par rapport au dossier de l’espace de travail (ex: monDossier/monFichier.txt) ${activeEditorLong}Ā : le chemin d’accĆØs complet du fichier (par exemple / Users/Developpement/monDossier/monFichier.txt) ${folderName}Ā : nom du dossier de l’espace de travail auquel le fichier appartient (ex: mondossier) ${folderPath}Ā : chemin d’accĆØs du dossier de l'espace de travail auquel le fichier appartient (ex: /Users/Developpement/monDossier) {$ rootName}Ā : nom de l’espace de travail (:. monDossier ou monEspaceDeTravail) ${rootPath}Ā : chemin d’accĆØs de l’espace de travail (ex: /Users/Developpement/monEspaceDeTravail) ${appName}Ā : ex. VS Code ${dirty}Ā : un indicateur si l’éditeur actif est modifiĆ© ${separator}Ā : un sĆ©parateur conditionnel (\" - \") qui ne s'affiche que quand ils sont entourĆ©s par des variables avec des valeurs", "window.newWindowDimensions.default": "Permet d'ouvrir les nouvelles fenĆŖtres au centre de l'Ć©cran.", "window.newWindowDimensions.inherit": "Permet d'ouvrir les nouvelles fenĆŖtres avec la mĆŖme dimension que la derniĆØre fenĆŖtre active.", "window.newWindowDimensions.maximized": "Permet d'ouvrir les nouvelles fenĆŖtres de maniĆØre agrandie.", "window.newWindowDimensions.fullscreen": "Permet d'ouvrir les nouvelles fenĆŖtres en mode plein Ć©cran.", "newWindowDimensions": "ContrĆ“le les dimensions d'ouverture d'une nouvelle fenĆŖtre quand au moins une fenĆŖtre est dĆ©jĆ  ouverte. Par dĆ©faut, une nouvelle fenĆŖtre s'ouvre au centre de l'Ć©cran avec des dimensions rĆ©duites. Quand la valeur est 'inherit', la fenĆŖtre a les mĆŖmes dimensions que la derniĆØre fenĆŖtre active. Quand la valeur est 'maximized', la fenĆŖtre s'ouvre dans sa taille maximale et quand la valeur est 'fullscreen', elle s'ouvre en mode plein Ć©cran. Notez que ce paramĆØtre n'a aucun impact sur la premiĆØre fenĆŖtre ouverte, laquelle est toujours restaurĆ©e Ć  la taille et l'emplacement dĆ©finis au moment de sa fermeture.", + "closeWhenEmpty": "ContrĆ“le si le dernier Ć©diteur de clĆ“ture devrait Ć©galement fermer la fenĆŖtre. Ce paramĆØtre s’applique uniquement pour les fenĆŖtres qui ne prĆ©sentent pas de dossiers.", "window.menuBarVisibility.default": "Le menu n'est masquĆ© qu'en mode plein Ć©cran.", "window.menuBarVisibility.visible": "Le menu est toujours visible mĆŖme en mode plein Ć©cran.", "window.menuBarVisibility.toggle": "Le menu est masquĆ© mais il peut ĆŖtre affichĆ© via la touche Alt.", diff --git a/i18n/fra/src/vs/workbench/electron-browser/window.i18n.json b/i18n/fra/src/vs/workbench/electron-browser/window.i18n.json index 52e6b8d12ff..96dc00191af 100644 --- a/i18n/fra/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/fra/src/vs/workbench/electron-browser/window.i18n.json @@ -9,6 +9,5 @@ "cut": "Couper", "copy": "Copier", "paste": "Coller", - "selectAll": "Tout SĆ©lectionner", - "confirmOpenButton": "&&Ouvrir..." + "selectAll": "Tout SĆ©lectionner" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 7e1c234e5c3..07ecb08aee3 100644 --- a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Si une ligne correspond Ć  ce modĆØle, sa mise en retrait ne doit pas ĆŖtre changĆ©e et la ligne ne doit pas ĆŖtre Ć©valuĆ©e par rapport aux autres rĆØgles.", "schema.indentationRules.unIndentedLinePattern.pattern": "ModĆØle RegExp pour unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Indicateurs RegExp pour unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Doit valider l'expression rĆ©guliĆØre `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Doit valider l'expression rĆ©guliĆØre `/^([gimuy]+)$/`.", + "schema.folding": "ParamĆØtres de repliage de la langue.", + "schema.folding.offSide": "Un langage adhĆØre Ć  la rĆØgle du hors-champ si les blocs dans ce langage sont exprimĆ©es par leur indentation. Si spĆ©cifiĆ©, les lignes vides appartiennent au bloc suivant.", + "schema.folding.markers": "Les marqueurs de langage spĆ©cifiques de repliage tels que '#region' et '#endregion'. Les regex de dĆ©but et la fin seront testĆ©s sur le contenu de toutes les lignes et doivent ĆŖtre conƧues de maniĆØre efficace.", + "schema.folding.markers.start": "Le modĆØle de RegExp pour le marqueur de dĆ©but. L’expression rĆ©guliĆØre doit commencer par '^'.", + "schema.folding.markers.end": "Le modĆØle de RegExp pour le marqueur de fin. L’expression rĆ©guliĆØre doit commencer par '^'." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..56dc21af001 --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "AffichageĀ : Activer/dĆ©sactiver la minicarte" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index 6555dbee125..064c359bfc7 100644 --- a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "Activer/dĆ©sactiver les caractĆØres de contrĆ“le" + "toggleRenderControlCharacters": "Affichage : Activer/dĆ©sactiver les caractĆØres de contrĆ“le" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 0bdd59aa9bd..878f453bdeb 100644 --- a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "Activer/dĆ©sactiver Restituer l'espace" + "toggleRenderWhitespace": "Affichage : Activer/dĆ©sactiver l'affichage des espaces" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index fdf0d48085c..207f6a482dd 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "Aucune configuration", + "addConfigTo": "Ajouter une configuration ({0})...", "addConfiguration": "Ajouter une configuration..." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 30c636b7769..914334d0401 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, dĆ©bogage", "debugAriaLabel": "Tapez le nom d'une configuration de lancement Ć  exĆ©cuter.", + "addConfigTo": "Ajouter une configuration ({0})...", + "addConfiguration": "Ajouter une configuration...", "noConfigurationsMatching": "Aucune configuration de dĆ©bogage correspondante", "noConfigurationsFound": "Configurations de dĆ©bogage introuvables. CrĆ©ez un fichier 'launch.json'." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..9782a892c46 --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "Focus sur les Variables", + "debugFocusWatchView": "Focus sur Watch", + "debugFocusCallStackView": "Focus sur CallStack", + "debugFocusBreakpointsView": "Focus sur les points d'arrĆŖts" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 8a1e2b50d5f..5a3987eaa76 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Configurations pour la gĆ©nĆ©ration du fichier 'launch.json' initial.", "vscode.extension.contributes.debuggers.languages": "Liste de langages pour lesquels l'extension de dĆ©bogage peut ĆŖtre considĆ©rĆ©e comme \"dĆ©bogueur par dĆ©faut\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Si l'extension VS Code spĆ©cifiĆ©e appelle cette commande pour dĆ©terminer le chemin de l'exĆ©cutable de l'adaptateur de dĆ©bogage et les arguments Ć  passer.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Si l'extension VS Code spĆ©cifiĆ©e appelle cette commande pour les actions \"debug\" ou \"run\" ciblĆ©es pour cette extension.", "vscode.extension.contributes.debuggers.configurationSnippets": "Extraits pour l'ajout de nouvelles configurations Ć  'launch.json'.", "vscode.extension.contributes.debuggers.configurationAttributes": "Configurations de schĆ©ma JSON pour la validation de 'launch.json'.", "vscode.extension.contributes.debuggers.windows": "ParamĆØtres spĆ©cifiques Ć  Windows.", diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index d60a025a1a0..1dae12e425f 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,12 +12,13 @@ "breakpointRemoved": "Point d'arrĆŖt supprimĆ©, ligne {0}, fichier {1}", "compoundMustHaveConfigurations": "L'attribut \"configurations\" du composĆ© doit ĆŖtre dĆ©fini pour permettre le dĆ©marrage de plusieurs configurations.", "configMissing": "Il manque la configuration '{0}' dans 'launch.json'.", + "debugRequestNotSupported": "L’attribut '{0}' a une valeur '{1}' non prise en charge dans la configuration de dĆ©bogage sĆ©lectionnĆ©e.", "debugTypeNotSupported": "Le type de dĆ©bogage '{0}' configurĆ© n'est pas pris en charge.", - "debugTypeMissing": "PropriĆ©tĆ© 'type' manquante pour la configuration de lancement choisie.", + "debugTypeMissing": "La propriĆ©tĆ© 'type' est manquante pour la configuration de lancement sĆ©lectionnĆ©e.", + "debugAnyway": "DĆ©boguer quand mĆŖme", "preLaunchTaskErrors": "Des erreurs de build ont Ć©tĆ© dĆ©tectĆ©es durant le preLaunchTask '{0}'.", "preLaunchTaskError": "Une erreur de build a Ć©tĆ© dĆ©tectĆ©e durant le preLaunchTask '{0}'.", "preLaunchTaskExitCode": "Le preLaunchTask '{0}' s'est terminĆ© avec le code de sortie {1}.", - "debugAnyway": "DĆ©boguer quand mĆŖme", "noFolderWorkspaceDebugError": "Impossible de dĆ©boguer le fichier actif. VĆ©rifiez qu'il est enregistrĆ© sur le disque et qu'une extension de dĆ©bogage est installĆ©e pour ce type de fichier.", "NewLaunchConfig": "Configurez le fichier config de lancement de votre application. {0}", "DebugTaskNotFound": "preLaunchTask '{0}' introuvable." diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 9fa5e84fe4a..93c9076aca7 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "La variable {0} a la valeur {1}, boucle REPL (Read Eval Print Loop), dĆ©bogage", "replExpressionAriaLabel": "L'expression {0} a la valeur {1}, boucle REPL (Read Eval Print Loop), dĆ©bogage", "replValueOutputAriaLabel": "{0}, boucle REPL (Read Eval Print Loop), dĆ©bogage", - "replKeyValueOutputAriaLabel": "La variable de sortie {0} a la valeur {1}, boucle REPL (Read Eval Print Loop), dĆ©bogage" + "replRawObjectAriaLabel": "La variable Repl {0} a la valeur {1}, read eval print loop, dĆ©bogage" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index b4fa3eab636..76fb8ce3e72 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "Couleur d'arriĆØre-plan de la barre d'Ć©tat quand un programme est en cours de dĆ©bogage. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre", - "statusBarDebuggingForeground": "Couleur de premier plan de la barre d'Ć©tat quand un programme est en cours de dĆ©bogage. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre" + "statusBarDebuggingForeground": "Couleur de premier plan de la barre d'Ć©tat quand un programme est en cours de dĆ©bogage. La barre d'Ć©tat est affichĆ©e en bas de la fenĆŖtre", + "statusBarDebuggingBorder": "Couleur de la bordure qui sĆ©pare Ć  l’éditeur et la barre latĆ©rale quand un programme est en cours de dĆ©bogage. La barre d’état s’affiche en bas de la fenĆŖtre" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 8b0cfe2f540..f3922c0c45a 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "L'exĆ©cutable d'adaptateur de dĆ©bogage '{0}' n'existe pas.", "debugAdapterCannotDetermineExecutable": "Impossible de dĆ©terminer l'exĆ©cutable pour l'adaptateur de dĆ©bogage '{0}'.", + "launch.config.comment1": "Utilisez IntelliSense pour en savoir plus sur les attributs possibles.", + "launch.config.comment2": "Pointez pour afficher la description des attributs existants.", + "launch.config.comment3": "Pour plus d'informations, visitez : {0}", "debugType": "Type de configuration.", "debugTypeNotRecognised": "Le type de dĆ©bogage n'est pas reconnu. VĆ©rifiez que vous avez installĆ© l'extension de dĆ©bogage correspondante et qu'elle est activĆ©e.", "node2NotSupported": "\"node2\" n'est plus pris en charge. Utilisez \"node\" Ć  la place, et affectez la valeur \"inspector\" Ć  l'attribut \"protocol\".", diff --git a/i18n/fra/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json index 552e6f9f400..8fadf8b958b 100644 --- a/i18n/fra/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "terminalConfigurationTitle": "Terminal externe", + "explorer.openInTerminalKind": "Personnalise le type de terminal Ć  lancer.", "terminal.external.windowsExec": "Personnalise le terminal Ć  exĆ©cuter sur Windows.", "terminal.external.osxExec": "Personnalise l'application de terminal Ć  exĆ©cuter sur OSĀ X.", "terminal.external.linuxExec": "Personnalise le terminal Ć  exĆ©cuter sur Linux.", diff --git a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index c8681a6e261..d2552c4f0ca 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "Nom", "view location": "Emplacement", - "themes": "ThĆØmes ({0})", + "colorThemes": "ThĆØmes de couleurs ({0})", + "iconThemes": "ThĆØmes d’icĆ“nes ({0})", + "colors": "Couleurs ({0})", + "colorId": "Id", + "defaultDark": "DĆ©faut pour le thĆØme sombre", + "defaultLight": "DĆ©faut pour le thĆØme clair", + "defaultHC": "DĆ©faut pour le thĆØme de contraste Ć©levĆ©", "JSON Validation": "Validation JSON ({0})", "commands": "Commandes ({0})", "command name": "Nom", diff --git a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 0112a21db36..2320626a88f 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,23 +34,28 @@ "postDisableMessage": "Recharger cette fenĆŖtre pour dĆ©sactiver l'extension '{0}'Ā ?", "postUninstallTooltip": "Recharger pour dĆ©sactiver", "postUninstallMessage": "Recharger cette fenĆŖtre pour dĆ©sactiver l'extension dĆ©sinstallĆ©e '{0}'Ā ?", - "reload": "&&Recharger la fenĆŖtre", "toggleExtensionsViewlet": "Afficher les extensions", "installExtensions": "Installer les extensions", + "showEnabledExtensions": "Afficher les Extensions activĆ©es", "showInstalledExtensions": "Afficher les extensions installĆ©es", "showDisabledExtensions": "Afficher les extensions dĆ©sactivĆ©es", "clearExtensionsInput": "Effacer l'entrĆ©e des extensions", "showOutdatedExtensions": "Afficher les extensions obsolĆØtes", "showPopularExtensions": "Afficher les extensions les plus demandĆ©es", "showRecommendedExtensions": "Afficher les extensions recommandĆ©es", - "showWorkspaceRecommendedExtensions": "Afficher les extensions recommandĆ©es pour l'espace de travail", + "installWorkspaceRecommendedExtensions": "Installer toutes les Extensions recommandĆ©es pour l'espace de travail", + "allExtensionsInstalled": "Toutes les extensions recommandĆ©es pour cet espace de travail ont dĆ©jĆ  Ć©tĆ© installĆ©es", + "installRecommendedExtension": "Installer l'Extension RecommandĆ©e", + "extensionInstalled": "L’extension recommandĆ©e est dĆ©jĆ  installĆ©e", "showRecommendedKeymapExtensions": "Afficher les mappages de touches recommandĆ©s", "showRecommendedKeymapExtensionsShort": "Mappages de touches", "showLanguageExtensions": "Afficher les extensions de langage", "showLanguageExtensionsShort": "Extensions de langage", - "configureWorkspaceRecommendedExtensions": "Configurer les extensions recommandĆ©es (espace de travail)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Les recommandations ne sont disponibles que pour un dossier d'espace de travail.", + "showAzureExtensions": "Afficher les Extensions Azure", + "showAzureExtensionsShort": "Extensions Azure", "OpenExtensionsFile.failed": "Impossible de crĆ©er le fichier 'extensions.json' dans le dossier '.vscode' ({0}).", + "configureWorkspaceRecommendedExtensions": "Configurer les extensions recommandĆ©es (espace de travail)", + "configureWorkspaceFolderRecommendedExtensions": "Configurer les extensions recommandĆ©es (Dossier d'espace de travail)", "builtin": "IntĆ©grĆ©e", "disableAll": "DĆ©sactiver toutes les extensions installĆ©es", "disableAllWorkspace": "DĆ©sactiver toutes les extensions installĆ©es pour cet espace de travail", diff --git a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..c2bf78ba750 --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "RecommandĆ©es" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index da896dab794..9b8daa4bbea 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "Appuyez sur EntrĆ©e pour gĆ©rer vos extensions.", + "notfound": "Extension '{0}' introuvable dans le Marketplace.", + "install": "Appuyez sur entrĆ©e pour installer '{0}' depuis le Marketplace.", "searchFor": "Appuyez sur EntrĆ©e pour rechercher '{0}' dans le Marketplace.", "noExtensionsToInstall": "Tapez un nom d'extension" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index ba4825598d4..c0c7657681f 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -4,12 +4,17 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "fileBasedRecommendation": "Cette extension est recommandĆ©e basĆ© sur les fichiers que vous avez ouverts rĆ©cemment.", + "workspaceRecommendation": "Cette extension est recommandĆ©e par les utilisateurs de l’espace de travail actuel.", "reallyRecommended2": "L'extension '{0}' est recommandĆ©e pour ce type de fichier.", + "reallyRecommendedExtensionPack": "Le pack d’extensions '{0}' est recommandĆ© pour ce type de fichier.", "showRecommendations": "Afficher les recommandations", + "install": "Installer", "neverShowAgain": "Ne plus afficher", "close": "Fermer", "workspaceRecommended": "Cet espace de travail a des recommandations d'extension.", - "ignoreExtensionRecommendations": "Voulez-vous ignorer toutes les recommandations d'extension ?", + "installAll": "Tout installer", + "ignoreExtensionRecommendations": "Voulez-vous ignorer toutes les recommandations d’extensionsĀ ?", "ignoreAll": "Oui, ignorer tout", "no": "Non", "cancel": "Annuler" diff --git a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 7cd892fba92..c9965ba9318 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,6 +6,8 @@ { "openExtensionsFolder": "Ouvrir le dossier d'extensions", "installVSIX": "Installer depuis un VSIX...", + "installFromVSIX": "Installer Ć  partir d'un VSIX", + "installButton": "&&Installer", "InstallVSIXAction.success": "Installation rĆ©ussie de l'extension. Effectuez un redĆ©marrage pour l'activer.", "InstallVSIXAction.reloadNow": "Recharger maintenant" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json index 4a3247cd7a9..bd14c18316c 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json @@ -8,6 +8,8 @@ "installedExtensions": "InstallĆ©es", "searchInstalledExtensions": "InstallĆ©es", "recommendedExtensions": "RecommandĆ©es", + "otherRecommendedExtensions": "Autres recommandations", + "workspaceRecommendedExtensions": "Recommandations de l’espace de travail", "searchExtensions": "Rechercher des extensions dans Marketplace", "sort by installs": "Trier parĀ : nombre d'installations", "sort by rating": "Trier parĀ : Ć©valuation", diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index fdf890d05ee..c0057e5215c 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Fichiers", - "revealInSideBar": "Afficher dans la barre latĆ©rale" + "filesCategory": "Fichier", + "revealInSideBar": "Afficher dans la barre latĆ©rale", + "acceptLocalChanges": "Utiliser vos modifications et Ć©craser les contenus du disque", + "revertLocalChanges": "Ignorer les modifications et revenir au contenu sur le disque" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json index c3b09b18594..3aa8d0485de 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Voulez-vous vraiment supprimer '{0}'Ā ?", "undoBin": "Vous pouvez effectuer une restauration Ć  partir de la Corbeille.", "undoTrash": "Vous pouvez effectuer une restauration Ć  partir de la Poubelle.", + "doNotAskAgain": "Ne plus me demander", "confirmDeleteMessageFolder": "Voulez-vous vraiment supprimer dĆ©finitivement '{0}' et son contenuĀ ?", "confirmDeleteMessageFile": "Voulez-vous vraiment supprimer dĆ©finitivement '{0}'Ā ?", "irreversible": "Cette action est irrĆ©versibleĀ !", @@ -37,17 +38,15 @@ "openToSide": "Ouvrir sur le cĆ“tĆ©", "compareSource": "SĆ©lectionner pour comparer", "globalCompareFile": "Comparer le fichier actif Ć ...", - "pickHistory": "SĆ©lectionnez un fichier ouvert Ć  comparer", - "unableToFileToCompare": "Impossible de comparer le fichier sĆ©lectionnĆ© Ć  '{0}'.", "openFileToCompare": "Ouvrez d'abord un fichier pour le comparer Ć  un autre fichier.", - "compareWith": "Comparer Ć  '{0}'", + "compareWith": "Comparer '{0}' Ć  '{1}'", "compareFiles": "Comparer des fichiers", "refresh": "Actualiser", "save": "Enregistrer", "saveAs": "Enregistrer sous...", "saveAll": "Enregistrer tout", "saveAllInGroup": "Enregistrer tout dans le groupe", - "saveFiles": "Enregistrer les fichiers Ć  l'intĆ©gritĆ© compromise", + "saveFiles": "Enregistrer tous les fichiers", "revert": "RĆ©tablir le fichier", "focusOpenEditors": "Mettre le focus sur la vue des Ć©diteurs ouverts", "focusFilesExplorer": "Focus sur l'Explorateur de fichiers", @@ -55,7 +54,6 @@ "openFileToShow": "Ouvrir d'abord un fichier pour l'afficher dans l'Explorateur", "collapseExplorerFolders": "RĆ©duire les dossiers dans l'explorateur", "refreshExplorer": "Actualiser l'explorateur", - "openFile": "Ouvrir un fichier...", "openFileInNewWindow": "Ouvrir le fichier actif dans une nouvelle fenĆŖtre", "openFileToShowInNewWindow": "Ouvrir d'abord un fichier Ć  ouvrir dans une nouvelle fenĆŖtre", "revealInWindows": "RĆ©vĆ©ler dans l'Explorateur", diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 9439ba9fff7..7b048fa2388 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "Ɖditeur de fichier texte", "binaryFileEditor": "Ɖditeur de fichier binaire", "filesConfigurationTitle": "Fichiers", - "exclude": "Configurez les modĆØles Glob pour l'exclusion des fichiers et des dossiers.", + "exclude": "Configurer des modĆØles glob pour exclure des fichiers et dossiers. Par exemple, l’explorateur de fichiers dĆ©cide quels fichiers et dossiers afficher ou masquer en fonction de ce paramĆØtre.", "files.exclude.boolean": "ModĆØle Glob auquel les chemins de fichiers doivent correspondre. Affectez la valeur true ou false pour activer ou dĆ©sactiver le modĆØle.", "files.exclude.when": "VĆ©rification supplĆ©mentaire des frĆØres d'un fichier correspondant. Utilisez $(basename) comme variable pour le nom de fichier correspondant.", "associations": "Configurez les associations entre les fichiers et les langages (par exemple, \"*.extension\": \"html\"). Celles-ci ont prioritĆ© sur les associations par dĆ©faut des langages installĆ©s.", - "encoding": "Encodage du jeu de caractĆØres par dĆ©faut Ć  utiliser durant la lecture et l'Ć©criture des fichiers.", - "autoGuessEncoding": "Quand cette option est activĆ©e, tente de deviner l'encodage du jeu de caractĆØres Ć  l'ouverture des fichiers", + "encoding": "L'encodage du jeu de caractĆØres par dĆ©faut Ć  utiliser durant la lecture et l'Ć©criture des fichiers. Ce paramĆØtre peut Ć©galement ĆŖtre configurĆ© par langage.", + "autoGuessEncoding": "Quand cette option est activĆ©e, tente de deviner l'encodage du jeu de caractĆØres Ć  l'ouverture des fichiers. Ce paramĆØtre peut Ć©galement ĆŖtre configurĆ© par langage.", "eol": "CaractĆØre de fin de ligne par dĆ©faut. Utilisez \\n pour LF et \\r\\n pour CRLF.", "trimTrailingWhitespace": "Si l'option est activĆ©e, l'espace blanc de fin est supprimĆ© au moment de l'enregistrement d'un fichier.", "insertFinalNewline": "Quand l'option est activĆ©e, une nouvelle ligne finale est insĆ©rĆ©e Ć  la fin du fichier au moment de son enregistrement.", + "trimFinalNewlines": "Si l'option est activĆ©e, va supprimer toutes les nouvelles lignes aprĆØs la derniĆØre ligne Ć  la fin du fichier lors de l’enregistrement.", "files.autoSave.off": "Un fichier dont l'intĆ©gritĆ© est compromise n'est jamais enregistrĆ© automatiquement.", "files.autoSave.afterDelay": "Un fichier dont l'intĆ©gritĆ© est compromise est automatiquement enregistrĆ© aprĆØs la configuration de 'files.autoSaveDelay'.", "files.autoSave.onFocusChange": "Un fichier dont l'intĆ©gritĆ© est compromise est automatiquement enregistrĆ© quand l'Ć©diteur perd le focus.", @@ -39,9 +40,13 @@ "dynamicHeight": "ContrĆ“le si la hauteur de la section des Ć©diteurs ouverts doit s'adapter dynamiquement ou non au nombre d'Ć©lĆ©ments.", "autoReveal": "ContrĆ“le si l'Explorateur doit automatiquement afficher et sĆ©lectionner les fichiers Ć  l'ouverture.", "enableDragAndDrop": "ContrĆ“le si l'explorateur doit autoriser le dĆ©placement de fichiers et de dossiers par glisser-dĆ©placer.", - "sortOrder.default": "Fichiers et rĆ©pertoires sont triĆ©s par leur nom, dans l’ordre alphabĆ©tique. Les rĆ©pertoires sont affichĆ©s avant les fichiers.", - "sortOrder.mixed": "Fichiers et rĆ©pertoires sont triĆ©s par leur nom, dans l’ordre alphabĆ©tique. Les fichiers sont imbriquĆ©es dans des rĆ©pertoires.", - "sortOrder.filesFirst": "Fichiers et rĆ©pertoires sont triĆ©s par leur nom, dans l’ordre alphabĆ©tique. Les fichiers sont affichĆ©s avant les rĆ©pertoires.", - "sortOrder.type": "Fichiers et rĆ©pertoires sont triĆ©s par leurs extensions, dans l’ordre alphabĆ©tique. Les rĆ©pertoires sont affichĆ©s avant les fichiers.", - "sortOrder.modified": "Fichiers et rĆ©pertoires sont triĆ©s par date de derniĆØre modification, dans l’ordre dĆ©croissant. Les rĆ©pertoires sont affichĆ©s avant les fichiers." + "confirmDelete": "ContrĆ“le si l’explorateur doit demander confirmation lorsque vous supprimez un fichier via la corbeille.", + "sortOrder.default": "Les fichiers et dossiers sont triĆ©s par nom, dans l’ordre alphabĆ©tique. Les dossiers sont affichĆ©s avant les fichiers.", + "sortOrder.mixed": "Les fichiers et dossiers sont triĆ©s par nom, dans l’ordre alphabĆ©tique. Les fichiers sont imbriquĆ©s dans les dossiers.", + "sortOrder.filesFirst": "Les fichiers et dossiers sont triĆ©s par nom, dans l’ordre alphabĆ©tique. Les fichiers sont affichĆ©s avant les dossiers.", + "sortOrder.type": "Les fichiers et dossiers sont triĆ©s par extension, dans l’ordre alphabĆ©tique. Les dossiers sont affichĆ©s avant les fichiers.", + "sortOrder.modified": "Les fichiers et dossiers sont triĆ©s par date de derniĆØre modification, dans l’ordre dĆ©croissant. Les dossiers sont affichĆ©s avant les fichiers.", + "sortOrder": "ContrĆ“le l'ordre de tri des fichiers et dossiers dans l'explorateur. En plus du tri par dĆ©faut, vous pouvez dĆ©finir l'ordre sur 'mixed' (fichiers et dossiers triĆ©s combinĆ©s), 'type' (par type de fichier), 'modified' (par date de derniĆØre modification) ou 'fileFirst' (trier les fichiers avant les dossiers).", + "explorer.decorations.colors": "ContrĆ“le si les dĆ©corations de fichier doivent utiliser des couleurs.", + "explorer.decorations.badges": "ContrĆ“le si les dĆ©corations de fichier doivent utiliser des badges." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 2ecf7ac060d..f944e7fc14f 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "Utiliser les actions dans la barre d’outils de l’éditeur vers la droite pour soit **annuler** vos modifications ou **Ć©craser** le contenu sur le disque avec vos modifications", "discard": "Abandonner", "overwrite": "Remplacer", "retry": "RĆ©essayer", diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 8d920cf85ed..a44dd00649c 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Aucun dossier ouvert", "explorerSection": "Section de l'Explorateur de fichiers", - "noWorkspaceHelp": "Vous n'avez pas encore ouvert de dossier.", + "noWorkspaceHelp": "Vous n’avez pas encore ajoutĆ© un dossier Ć  l’espace de travail.", + "addFolder": "Ajouter un dossier", + "noFolderHelp": "Vous n'avez pas encore ouvert de dossier.", "openFolder": "Ouvrir le dossier" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..1dccba91e43 --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Explorateur" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 503c32add40..631a14a1cef 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,13 @@ { "fileInputAriaLabel": "Tapez le nom du fichier. Appuyez sur EntrĆ©e pour confirmer ou sur Ɖchap pour annuler.", "filesExplorerViewerAriaLabel": "{0}, Explorateur de fichiers", + "dropFolders": "Voulez-vous ajouter les dossiers Ć  l’espace de travailĀ ?", + "dropFolder": "Voulez-vous ajouter le dossier Ć  l’espace de travailĀ ?", + "addFolders": "&&Ajouter les dossiers", + "addFolder": "&&Ajouter le dossier", + "confirmMove": "Êtes-vous certain de vouloir dĆ©placer '{0}'Ā ?", + "doNotAskAgain": "Ne plus me demander", + "moveButtonLabel": "&&DĆ©placer", "confirmOverwriteMessage": "{0}' existe dĆ©jĆ  dans le dossier de destination. Voulez-vous le remplacerĀ ?", "irreversible": "Cette action est irrĆ©versibleĀ !", "replaceButtonLabel": "&&Remplacer" diff --git a/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 0a89ce8a7c8..457666ad7bb 100644 --- a/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 fichier non enregistrĆ©", "dirtyFiles": "{0} fichiers non enregistrĆ©s" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/fra/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..72ea24da7b8 --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "ProblĆØmes", + "tooltip.1": "1 problĆØme dans ce fichier", + "tooltip.N": "{0} problĆØmes dans ce fichier", + "markers.showOnFile": "Afficher les erreurs & les avertissements sur les fichiers et dossiers." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/fra/src/vs/workbench/parts/markers/common/messages.i18n.json index e57b4d06ecc..3e60b2ce7d8 100644 --- a/i18n/fra/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "Affichage", + "problems.view.toggle.label": "Activer/dĆ©sactiver les problĆØmes", "problems.view.show.label": "Afficher les problĆØmes", + "problems.view.hide.label": "Masquer les problĆØmes", "problems.panel.configuration.title": "Affichage des problĆØmes", "problems.panel.configuration.autoreveal": "ContrĆ“le si l'affichage des problĆØmes doit automatiquement montrer les fichiers quand il les ouvre", "markers.panel.title.problems": "ProblĆØmes", diff --git a/i18n/fra/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/fra/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index d31d43bede3..841d6e3c3c9 100644 --- a/i18n/fra/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "Copier" + "copyMarker": "Copier", + "copyMarkerMessage": "Copier le Message" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index 13b60d7dd5c..0a6aa85c9e2 100644 --- a/i18n/fra/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "DĆ©marrage lent dĆ©tectĆ©", - "slow.detail": "Le dĆ©marrage a Ć©tĆ© trĆØs lent. RedĆ©marrez '{0}' en ayant activĆ© le profilage, partagez les profils avec nous, et nous ferons en sorte que le dĆ©marrage retrouve sa rapiditĆ© d'exĆ©cution.", "prof.message": "CrĆ©ation rĆ©ussie des profils.", "prof.detail": "CrĆ©ez un problĆØme et joignez manuellement les fichiers suivantsĀ :\n{0}", "prof.restartAndFileIssue": "CrĆ©er le problĆØme et redĆ©marrer", diff --git a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 61742507b36..740f133866c 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -8,6 +8,7 @@ "openGlobalKeybindings": "Ouvrir les raccourcis clavier", "openGlobalKeybindingsFile": "Ouvrir le fichier des raccourcis clavier", "openWorkspaceSettings": "Ouvrir les paramĆØtres d'espace de travail", + "openFolderSettings": "Ouvrir le dossier ParamĆØtres", "configureLanguageBasedSettings": "Configurer les paramĆØtres spĆ©cifiques au langage...", "languageDescriptionConfigured": "({0})", "pickLanguage": "SĆ©lectionner un langage" diff --git a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index ae14ef7dcdc..627070bf270 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -13,5 +13,6 @@ "settingsFound": "{0} paramĆØtres correspondants", "fileEditorWithInputAriaLabel": "{0}. Ɖditeur de fichier texte.", "fileEditorAriaLabel": "Ɖditeur de fichier texte.", + "defaultEditorReadonly": "Modifier dans l’éditeur du cĆ“tĆ© droit pour substituer les valeurs par dĆ©faut.", "preferencesAriaLabel": "PrĆ©fĆ©rences par dĆ©faut. Ɖditeur de texte en lecture seule." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 990d1f6a9a9..12d172be7b1 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,12 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "Impossible d'Ć©crire les paramĆØtres. Corrigez les erreurs/avertissements prĆ©sents dans le fichier, puis rĆ©essayez.", + "emptyUserSettingsHeader": "Placer vos paramĆØtres ici pour remplacer les paramĆØtres par dĆ©faut.", + "emptyWorkspaceSettingsHeader": "Placer vos paramĆØtres ici pour remplacer les paramĆØtres utilisateur.", + "emptyFolderSettingsHeader": "Placer les paramĆØtres de votre dossier ici pour remplacer ceux des paramĆØtres de l’espace de travail.", + "defaultFolderSettingsTitle": "ParamĆØtres de dossier par dĆ©faut", "defaultSettingsTitle": "ParamĆØtres par dĆ©faut", - "noSettingsFound": "Aucun paramĆØtre.", "editTtile": "Modifier", "replaceDefaultValue": "Remplacer dans les paramĆØtres", "copyDefaultValue": "Copier dans ParamĆØtres", "unsupportedPHPExecutablePathSetting": "Ce paramĆØtre doit ĆŖtre un paramĆØtre utilisateur. Pour configurer PHP pour l'espace de travail, ouvrez un fichier PHP, puis cliquez sur 'Chemin PHP' dans la barre d'Ć©tat.", - "unsupportedWorkspaceSetting": "Ce paramĆØtre doit ĆŖtre un paramĆØtre utilisateur." + "unsupportedWorkspaceSetting": "Ce paramĆØtre doit ĆŖtre un paramĆØtre utilisateur.", + "unsupportedWorkbenchSetting": "Ce paramĆØtre ne peut pas ĆŖtre appliquĆ© maintenant. Il est appliquĆ© quand vous ouvrez ce dossier directement.", + "unsupportedWorkbenchSettingDevMode": "Ce paramĆØtre ne peut pas s’appliquer maintenant. Il s’appliquera si vous dĆ©finissez la portĆ©e Ć  'ressource' lors de son inscription, ou lorsque vous ouvrez ce dossier directement." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json index a71763915a8..3f323a43275 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json @@ -7,5 +7,6 @@ "openFolderFirst": "Ouvrir d'abord un dossier pour crĆ©er les paramĆØtres d'espace de travail", "emptyKeybindingsHeader": "Placez vos combinaisons de touches dans ce fichier pour remplacer les valeurs par dĆ©faut", "defaultKeybindings": "Combinaisons de touches par dĆ©faut", + "folderSettingsName": "{0} (ParamĆØtres du dossier)", "fail.createSettings": "Impossible de crĆ©er '{0}' ({1})." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 8b6ad71cd4e..b35025c24ae 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "defaultSettingsFuzzyPrompt": "Essayez la recherche vague (fuzzy)Ā !", + "defaultSettings": "Placez vos paramĆØtres dans l’éditeur du cĆ“tĆ© droit pour substituer.", + "noSettingsFound": "Aucun paramĆØtre.", + "folderSettingsDetails": "ParamĆØtres de dossier", + "enableFuzzySearch": "Activer la recherche vague (fuzzy) expĆ©rimentale" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index b9e13e04400..42c1698dcd3 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "UtilisĆ©s le plus souvent", - "noSettings": "Aucun paramĆØtre", + "mostRelevant": "Plus pertinent", "defaultKeybindingsHeader": "Remplacez les combinaisons de touches dans votre fichier de combinaisons de touches." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 1c20cdc1e83..9806bbb1795 100644 --- a/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "La commande '{0}' n'est pas activĆ©e dans le contexte actuel.", "recentlyUsed": "rĆ©cemment utilisĆ©es", "morecCommands": "autres commandes", - "commandLabel": "{0}Ā : {1}", "cat.title": "{0}Ā : {1}", "noCommandsMatching": "Aucune commande correspondante" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 7507a7f217a..d2b78f7e8eb 100644 --- a/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,6 +6,5 @@ { "relaunchSettingMessage": "Un paramĆØtre a changĆ© et nĆ©cessite un redĆ©marrage pour ĆŖtre appliquĆ©.", "relaunchSettingDetail": "Appuyez sur le bouton de redĆ©marrage pour redĆ©marrer {0} et activer le paramĆØtre.", - "restart": "RedĆ©marrer", - "reload": "Recharger" + "restart": "&&RedĆ©marrer" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 3fe2c3e213d..9e292a57bbd 100644 --- a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} sur {1} modifications", + "change": "{0} sur {1} modification", + "show previous change": "Voir la modification prĆ©cĆ©dente", + "show next change": "Voir la modification suivante", "editorGutterModifiedBackground": "Couleur d'arriĆØre-plan de la reliure de l'Ć©diteur pour les lignes modifiĆ©es.", "editorGutterAddedBackground": "Couleur d'arriĆØre-plan de la reliure de l'Ć©diteur pour les lignes ajoutĆ©es.", - "editorGutterDeletedBackground": "Couleur d'arriĆØre-plan de la reliure de l'Ć©diteur pour les lignes supprimĆ©es." + "editorGutterDeletedBackground": "Couleur d'arriĆØre-plan de la reliure de l'Ć©diteur pour les lignes supprimĆ©es.", + "overviewRulerModifiedForeground": "Couleur du marqueur de la rĆØgle d'aperƧu pour le contenu modifiĆ©.", + "overviewRulerAddedForeground": "Couleur du marqueur de la rĆØgle d'aperƧu pour le contenu ajoutĆ©.", + "overviewRulerDeletedForeground": "Couleur du marqueur de la rĆØgle d'aperƧu pour le contenu supprimĆ©." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index 50606f11e00..015c5898f64 100644 --- a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Afficher Git", - "installAdditionalSCMProviders": "Installer des fournisseurs SCM supplĆ©mentaires...", "source control": "ContrĆ“le de code source", "toggleSCMViewlet": "Afficher SCM", "view": "Afficher" diff --git a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index af8d3a6de12..81a1f808023 100644 --- a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Fournisseurs de contrĆ“le de code source", + "hideRepository": "Masquer", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "Installer des fournisseurs SCM supplĆ©mentaires...", + "no open repo": "Il n’y a aucun fournisseur de contrĆ“le de code source actif.", "source control": "ContrĆ“le de code source", "viewletTitle": "{0}Ā : {1}" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 0412e7f268a..2ab53a48942 100644 --- a/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "Atteindre le symbole dans l'espace de travail...", "name": "Rechercher", - "showSearchViewlet": "Afficher la zone de recherche", + "search": "Rechercher", "view": "Affichage", - "findInFiles": "Chercher dans les fichiers", "openAnythingHandlerDescription": "AccĆ©der au fichier", "openSymbolDescriptionNormal": "Atteindre le symbole dans l'espace de travail", "searchOutputChannelTitle": "Rechercher", @@ -16,7 +15,7 @@ "exclude": "Configurez les modĆØles Glob pour exclure les fichiers et les dossiers des recherches. HĆ©rite de tous les modĆØles Glob Ć  partir du paramĆØtre files.exclude.", "exclude.boolean": "ModĆØle Glob auquel les chemins de fichiers doivent correspondre. Affectez la valeur true ou false pour activer ou dĆ©sactiver le modĆØle.", "exclude.when": "VĆ©rification supplĆ©mentaire des frĆØres d'un fichier correspondant. Utilisez $(basename) comme variable pour le nom de fichier correspondant.", - "useRipgrep": "ContrĆ“le si ripgrep doit ĆŖtre utilisĆ© dans la recherche de texte", - "useIgnoreFilesByDefault": "Indique s'il faut utiliser les fichiers .gitignore et .ignore par dĆ©faut en cas de recherche dans un nouvel espace de travail.", - "search.quickOpen.includeSymbols": "Configurez l'ajout des rĆ©sultats d'une recherche de symboles globale dans le fichier de rĆ©sultats pour Quick Open." + "useRipgrep": "ContrĆ“le si ripgrep doit ĆŖtre utilisĆ© dans la recherche de texte et de fichier", + "search.quickOpen.includeSymbols": "Configurez l'ajout des rĆ©sultats d'une recherche de symboles globale dans le fichier de rĆ©sultats pour Quick Open.", + "search.followSymlinks": "DĆ©termine s’il faut suivre les liens symboliques lors de la recherche." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json index dd5b8b24dd7..e723b18fb05 100644 --- a/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,16 +4,26 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "Afficher le prochain Include Pattern de recherche", + "previousSearchIncludePattern": "Afficher le prĆ©cĆ©dent Include Pattern de recherche", + "nextSearchExcludePattern": "Afficher le prochain Exclude Pattern de recherche", + "previousSearchExcludePattern": "Afficher le prĆ©cĆ©dent Exclude Pattern de recherche", "nextSearchTerm": "Afficher le terme de recherche suivant", "previousSearchTerm": "Afficher le terme de recherche prĆ©cĆ©dent", "focusNextInputBox": "Focus sur la zone d'entrĆ©e suivante", "focusPreviousInputBox": "Focus sur la zone d'entrĆ©e prĆ©cĆ©dente", + "showSearchViewlet": "Afficher la zone de recherche", + "findInFiles": "Chercher dans les fichiers", + "findInFilesWithSelectedText": "Rechercher dans les fichiers avec le texte sĆ©lectionnĆ©", "replaceInFiles": "Remplacer dans les fichiers", + "replaceInFilesWithSelectedText": "Remplacer dans les fichiers avec le texte sĆ©lectionnĆ©", + "findInWorkspace": "Trouver dans l’espace de travail...", + "findInFolder": "Trouver dans le dossier...", "RefreshAction.label": "Actualiser", "ClearSearchResultsAction.label": "Effacer les rĆ©sultats de la recherche", "FocusNextSearchResult.label": "Focus sur le rĆ©sultat de la recherche suivant", "FocusPreviousSearchResult.label": "Focus sur le rĆ©sultat de la recherche prĆ©cĆ©dent", - "RemoveAction.label": "Supprimer", + "RemoveAction.label": "Rejeter", "file.replaceAll.label": "Tout remplacer", "match.replace.label": "Remplacer" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json b/i18n/fra/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json index 052e41c13ac..9038b91202e 100644 --- a/i18n/fra/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "searchFolderMatch.other.label": "Autres fichiers", + "searchFileMatches": "{0} fichiers trouvĆ©s", + "searchFileMatch": "{0} fichier trouvĆ©", "searchMatches": "{0} correspondances trouvĆ©es", "searchMatch": "{0} correspondance trouvĆ©e", + "folderMatchAriaLabel": "{0} correspondances dans le dossier racine {1}, RĆ©sultat de la recherche", "fileMatchAriaLabel": "{0} correspondances dans le fichier {1} du dossier {2}, RĆ©sultat de la recherche", "replacePreviewResultAria": "Remplacer le terme {0} par {1} Ć  la position de colonne {2} dans la ligne avec le texte {3}", "searchResultAria": "Terme {0} trouvĆ© Ć  la position de colonne {1} dans la ligne avec le texte {2}" diff --git a/i18n/fra/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/fra/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index ee2441931b5..8ed40e4b151 100644 --- a/i18n/fra/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "fichiers Ć  exclure", "label.excludes": "ModĆØles d'exclusion de recherche", "replaceAll.confirmation.title": "Tout remplacer", - "replaceAll.confirm.button": "Remplacer", + "replaceAll.confirm.button": "&&Remplacer", "replaceAll.occurrence.file.message": "{0} occurrence remplacĆ©e dans {1} fichier par '{2}'.", "removeAll.occurrence.file.message": "{0} occurrence remplacĆ©e dans {1} fichier.", "replaceAll.occurrence.files.message": "{0} occurrence remplacĆ©e dans {1} fichiers par '{2}'.", @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "Remplacer {0} occurrences dans {1} fichiers par '{2}'Ā ?", "replaceAll.occurrences.files.confirmation.message": "Remplacer {0} occurrences dans {1} fichiersĀ ?", "treeAriaLabel": "RĆ©sultats de la recherche", + "searchPathNotFoundError": "Chemin de recherche introuvableĀ : {0}", "searchMaxResultsWarning": "Le jeu de rĆ©sultats contient uniquement un sous-ensemble de toutes les correspondances. Soyez plus prĆ©cis dans votre recherche de faƧon Ć  limiter les rĆ©sultats retournĆ©s.", "searchCanceled": "La recherche a Ć©tĆ© annulĆ©e avant l'obtention de rĆ©sultats - ", "noResultsIncludesExcludes": "RĆ©sultats introuvables pour '{0}' excluant '{1}' - ", "noResultsIncludes": "RĆ©sultats introuvables dans '{0}' - ", "noResultsExcludes": "RĆ©sultats introuvables avec l'exclusion de '{0}' - ", - "noResultsFound": "RĆ©sultats introuvables. VĆ©rifiez les paramĆØtres d'exclusion configurĆ©s - ", + "noResultsFound": "Aucun rĆ©sultat trouvĆ©. VĆ©rifiez vos paramĆØtres pour les exclusions configurĆ©es et les fichiers ignorĆ©s - ", "rerunSearch.message": "Rechercher Ć  nouveau", "rerunSearchInAll.message": "Rechercher Ć  nouveau dans tous les fichiers", "openSettings.message": "Ouvrir les paramĆØtres", + "openSettings.learnMore": "En savoir plus", "ariaSearchResultsStatus": "La recherche a retournĆ© {0} rĆ©sultats dans {1} fichiers", "search.file.result": "{0} rĆ©sultat dans {1} fichier", "search.files.result": "{0} rĆ©sultat dans {1} fichiers", diff --git a/i18n/fra/src/vs/workbench/parts/search/browser/searchWidget.i18n.json b/i18n/fra/src/vs/workbench/parts/search/browser/searchWidget.i18n.json index a2c4ab2c790..834cc74665d 100644 --- a/i18n/fra/src/vs/workbench/parts/search/browser/searchWidget.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/search/browser/searchWidget.i18n.json @@ -11,5 +11,6 @@ "search.placeHolder": "Rechercher", "label.Replace": "RemplacerĀ : tapez le terme de remplacement, puis appuyez sur EntrĆ©e pour avoir un aperƧu, ou sur Ɖchap pour l'annuler", "search.replace.placeHolder": "Remplacer", - "regexp.validationFailure": "L'expression correspond Ć  tout" + "regexp.validationFailure": "L'expression correspond Ć  tout", + "regexp.backreferenceValidationFailure": "Les rĆ©fĆ©rences arriĆØres (Backreferences) ne sont pas prises en charge" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/fra/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..f01c8d3071d --- /dev/null +++ b/i18n/fra/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Aucun dossier dans l’espace de travail avec le nomĀ {0}" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 27c0397de03..b8f73f7acad 100644 --- a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "InsĆ©rer un extrait de code" + "snippet.suggestions.label": "InsĆ©rer un extrait de code", + "sep.userSnippet": "Extraits de code de l'utilisateur", + "sep.extSnippet": "Extraits de code d’extension" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 94092e12ea5..0c67783e02a 100644 --- a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "Langage inconnu dans 'contributes.{0}.language'. Valeur fournieĀ : {1}", + "invalid.path.0": "ChaĆ®ne attendue dans 'contributes.{0}.path'. Valeur fournieĀ : {1}", + "invalid.path.1": "'contributes.{0}.path' ({1}) est censĆ© ĆŖtre inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable.", + "vscode.extension.contributes.snippets": "Ajoute des extraits de code.", + "vscode.extension.contributes.snippets-language": "Identificateur de langage pour lequel cet extrait de code est ajoutĆ©.", + "vscode.extension.contributes.snippets-path": "Chemin du fichier d'extraits de code. Le chemin est relatif au dossier d'extensions et commence gĆ©nĆ©ralement par './snippets/'.", + "badVariableUse": "Un ou plusieurs extraits de l’extension '{0}' confondent trĆØs probablement des snippet-variables et des snippet-placeholders (Voir https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax pour plus de dĆ©tails)", + "badFile": "Le fichier d’extrait \"{0}\" n’a pas pu ĆŖtre lu.", "source.snippet": "Extrait de code utilisateur", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 880bf493d01..5dbc6753aa3 100644 --- a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "Configure le panneau utilisĆ© pour prĆ©senter la sortie de la tĆ¢che et lit son entrĆ©e.", "JsonSchema.tasks.presentation.echo": "ContrĆ“le si la commande exĆ©cutĆ©e est rĆ©percutĆ©e dans le panneau. La valeur par dĆ©faut est true.", "JsonSchema.tasks.presentation.focus": "ContrĆ“le si le panneau reƧoit le focus. La valeur par dĆ©faut est false. Si la valeur est true, le panneau est Ć©galement affichĆ©.", + "JsonSchema.tasks.presentation.reveal.always": "Toujours afficher le terminal quand cette tĆ¢che est exĆ©cutĆ©e.", + "JsonSchema.tasks.presentation.reveal.silent": "Afficher uniquement le terminal si aucun dĆ©tecteur de problĆØmes de correspondance n’est associĆ© Ć  la tĆ¢che et qu'une erreur se produit pendant son exĆ©cution.", + "JsonSchema.tasks.presentation.reveal.never": "Ne jamais afficher le terminal quand cette tĆ¢che est exĆ©cutĆ©e.", "JsonSchema.tasks.presentation.reveals": "ContrĆ“le si le panneau qui exĆ©cute la tĆ¢che est affichĆ© ou non. La valeur par dĆ©faut est \"always\".", "JsonSchema.tasks.presentation.instance": "ContrĆ“le si le panneau est partagĆ© entre les tĆ¢ches, dĆ©diĆ© Ć  cette tĆ¢che ou si un panneau est crƩƩ Ć  chaque exĆ©cution.", "JsonSchema.tasks.terminal": "La propriĆ©tĆ© de terminal est dĆ©prĆ©ciĆ©e. Utilisez la prĆ©sentation Ć  la place", @@ -22,7 +25,8 @@ "JsonSchema.tasks.group.test": "Marque la tĆ¢che comme tĆ¢che de test accessible par la commande 'ExĆ©cuter la tĆ¢che de test'.", "JsonSchema.tasks.group.none": "N'assigne la tĆ¢che Ć  aucun groupe", "JsonSchema.tasks.group": "DĆ©finit le groupe d'exĆ©cution auquel la tĆ¢che appartient. Prend en charge \"build\" pour l'ajouter au groupe de gĆ©nĆ©ration et \"test\" pour l'ajouter au groupe de test.", - "JsonSchema.tasks.type": "DĆ©finit si la tĆ¢che est exĆ©cutĆ©e sous forme de processus ou d'une commande d'un interprĆ©teur de commandes. La valeur par dĆ©faut est un processus.", + "JsonSchema.tasks.type": "DĆ©finit si la tĆ¢che est exĆ©cutĆ©e comme un processus ou comme une commande Ć  l’intĆ©rieur d’un shell.", + "JsonSchema.tasks.label": "L'Ć©tiquette de l’interface utilisateur de la tĆ¢che", "JsonSchema.version": "NumĆ©ro de version de la configuration.", "JsonSchema.tasks.identifier": "Identificateur dĆ©fini par l'utilisateur pour rĆ©fĆ©rencer la tĆ¢che dans launch.json ou une clause dependsOn.", "JsonSchema.tasks.taskLabel": "Ɖtiquette de la tĆ¢che", @@ -35,8 +39,10 @@ "JsonSchema.tasks.customize.deprecated": "La propriĆ©tĆ© de personnalisation est dĆ©prĆ©ciĆ©e. Consultez les notes de publication 1.14 pour savoir comment migrer vers la nouvelle approche de personnalisation des tĆ¢ches", "JsonSchema.tasks.showOputput.deprecated": "La propriĆ©tĆ© showOutput est dĆ©prĆ©ciĆ©e. Utilisez Ć  la place la propriĆ©tĆ© d'affichage au sein de la propriĆ©tĆ© de prĆ©sentation. Consultez Ć©galement les notes de publication 1.14.", "JsonSchema.tasks.echoCommand.deprecated": "La propriĆ©tĆ© echoCommand est dĆ©prĆ©ciĆ©e. Utilisez Ć  la place la propriĆ©tĆ© d'Ć©cho au sein de la propriĆ©tĆ© de prĆ©sentation. Consultez Ć©galement les notes de publication 1.14.", + "JsonSchema.tasks.suppressTaskName.deprecated": "La propriĆ©tĆ© suppressTaskName est obsolĆØte. Utiliser la ligne de commande avec ses arguments dans la tĆ¢che Ć  la place. Voir aussi les notes de version 1.14.", "JsonSchema.tasks.isBuildCommand.deprecated": "La propriĆ©tĆ© isBuildCommand est dĆ©prĆ©ciĆ©e. Utilisez la propriĆ©tĆ© de groupe Ć  la place. Consultez Ć©galement les notes de publication 1.14.", "JsonSchema.tasks.isTestCommand.deprecated": "La propriĆ©tĆ© isTestCommand est dĆ©prĆ©ciĆ©e. Utilisez la propriĆ©tĆ© de groupe Ć  la place. Consultez Ć©galement les notes de publication 1.14.", + "JsonSchema.tasks.taskSelector.deprecated": "La propriĆ©tĆ© taskSelector est obsolĆØte. Utiliser la ligne de commande avec ses arguments dans la tĆ¢che Ć  la place. Voir aussi les notes de version 1.14.", "JsonSchema.windows": "Configuration de commande spĆ©cifique Ć  Windows", "JsonSchema.mac": "Configuration de commande spĆ©cifique Ć  Mac", "JsonSchema.linux": "Configuration de commande spĆ©cifique Ć  Linux" diff --git a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 3681aebcf34..abe24c7ec4d 100644 --- a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,30 +5,35 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "TĆ¢ches", - "ConfigureTaskRunnerAction.noWorkspace": "Les tĆ¢ches ne sont disponibles que dans un dossier d'espace de travail.", - "ConfigureTaskRunnerAction.quickPick.template": "SĆ©lectionner un exĆ©cuteur de tĆ¢ches", - "ConfigureTaskRunnerAction.autoDetecting": "DĆ©tection automatique des tĆ¢ches pour {0}", - "ConfigureTaskRunnerAction.autoDetect": "En raison de l'Ć©chec de la dĆ©tection automatique du systĆØme de tĆ¢che, le modĆØle par dĆ©faut va ĆŖtre utilisĆ©. Pour plus d'informations, consultez la sortie de la tĆ¢che.", - "ConfigureTaskRunnerAction.autoDetectError": "La dĆ©tection automatique du systĆØme de tĆ¢che a produit des erreurs. Consultez la sortie de la tĆ¢che pour plus d'informations.", - "ConfigureTaskRunnerAction.failed": "Impossible de crĆ©er le fichier 'tasks.json' dans le dossier '.vscode'. Pour plus d'informations, consultez la sortie de la tĆ¢che.", - "ConfigureTaskRunnerAction.label": "Configurer l'exĆ©cuteur de tĆ¢ches", + "ConfigureTaskRunnerAction.label": "Configurer une tĆ¢che", "ConfigureBuildTaskAction.label": "Configurer une tĆ¢che de build", "CloseMessageAction.label": "Fermer", "ShowTerminalAction.label": "Afficher le terminal", "problems": "ProblĆØmes", "manyMarkers": "99", + "runningTasks": "Afficher les tĆ¢ches en cours d'exĆ©cution", "tasks": "TĆ¢ches", - "TaskSystem.noHotSwap": "Le changement du moteur d'exĆ©cution de tĆ¢ches nĆ©cessite le redĆ©marrage de VS Code. Changement ignorĆ©.", + "TaskSystem.noHotSwap": "Changer le moteur d’exĆ©cution de tĆ¢ches avec une tĆ¢che active en cours d’exĆ©cution nĆ©cessite de recharger la fenĆŖtre", + "TaskServer.folderIgnored": "Le dossier {0} est ignorĆ© car il utilise la version 0.1.0 de task", "TaskService.noBuildTask1": "Aucune tĆ¢che de build dĆ©finie. Marquez une tĆ¢che avec 'isBuildCommand' dans le fichier tasks.json.", "TaskService.noBuildTask2": "Aucune tĆ¢che de gĆ©nĆ©ration dĆ©finie. Marquez une tĆ¢che comme groupe 'build' dans le fichier tasks.json.", "TaskService.noTestTask1": "Aucune tĆ¢che de test dĆ©finie. Marquez une tĆ¢che avec 'isTestCommand' dans le fichier tasks.json.", "TaskService.noTestTask2": "Aucune tĆ¢che de test dĆ©finie. Marquez une tĆ¢che comme groupe 'test' dans le fichier tasks.json.", "TaskServer.noTask": "La tĆ¢che {0} Ć  exĆ©cuter est introuvable.", + "TaskService.associate": "associer", + "TaskService.attachProblemMatcher.continueWithout": "Continuer sans analyser la sortie de la tĆ¢che", + "TaskService.attachProblemMatcher.never": "Ne jamais vĆ©rifier la sortie de la tĆ¢che", + "TaskService.attachProblemMatcher.learnMoreAbout": "En savoir plus sur la sortie de la tĆ¢che de numĆ©risation", + "selectProblemMatcher": "SĆ©lectionner pour quel type d’erreurs et d’avertissements analyser la sortie de la tĆ¢che", "customizeParseErrors": "La configuration de tĆ¢che actuelle contient des erreurs. Corrigez-les avant de personnaliser une tĆ¢che. ", "moreThanOneBuildTask": "De nombreuses tĆ¢ches de gĆ©nĆ©ration sont dĆ©finies dans le fichier tasks.json. ExĆ©cution de la premiĆØre.\n", + "TaskSystem.activeSame.background": "La tĆ¢che '{0}' est dĆ©jĆ  active et en mode arriĆØre-plan. Pour la terminer, utiliser `Terminer la TĆ¢che...`Ā Ā» dans le menu TĆ¢ches.", + "TaskSystem.activeSame.noBackground": "La tĆ¢che '{0}' est dĆ©jĆ  active. Pour la terminer, il utilise `Terminer la TĆ¢che...` dans le menu TĆ¢ches.", "TaskSystem.active": "Une tĆ¢che est dĆ©jĆ  en cours d'exĆ©cution. Terminez-la avant d'exĆ©cuter une autre tĆ¢che.", "TaskSystem.restartFailed": "Ɖchec de la fin de l'exĆ©cution de la tĆ¢che {0}", + "TaskService.noConfiguration": "ErreurĀ : La dĆ©tection de la tĆ¢che {0} n’a pas contribuĆ© Ć  une tĆ¢che pour la configuration suivanteĀ : {1}, la tĆ¢che sera ignorĆ©e.\n", "TaskSystem.configurationErrors": "ErreurĀ : la configuration de tĆ¢che fournie comporte des erreurs de validation et ne peut pas ĆŖtre utilisĆ©e. Corrigez d'abord les erreurs.", + "taskService.ignoreingFolder": "Les configurations de tĆ¢che seront ignorĆ©es pour le dossier de l’espace de travail {0}. Le support de la tĆ¢che d'espace de travail multi-dossier requiert que tous les dossiers utilisent task version 2.0.0\n", "TaskSystem.invalidTaskJson": "ErreurĀ : le fichier tasks.json contient des erreurs de syntaxe. Corrigez-les avant d'exĆ©cuter une tĆ¢che.\n", "TaskSystem.runningTask": "Une tĆ¢che est en cours d'exĆ©cution. Voulez-vous la terminerĀ ?", "TaskSystem.terminateTask": "&&Terminer la tĆ¢che", @@ -40,25 +45,37 @@ "recentlyUsed": "tĆ¢ches rĆ©cemment utilisĆ©es", "configured": "tĆ¢ches configurĆ©es", "detected": "tĆ¢ches dĆ©tectĆ©es", + "TaskService.ignoredFolder": "Les dossiers d’espace de travail suivants sont ignorĆ©s car ils utilisent task version 0.1.0Ā : ", + "TaskService.notAgain": "Ne plus afficher", + "TaskService.ok": "OK", + "TaskService.pickRunTask": "SĆ©lectionner la tĆ¢che Ć  exĆ©cuter", + "TaslService.noEntryToRun": "Aucune tĆ¢che Ć  exĆ©cuter n'a Ć©tĆ© trouvĆ©e. Configurer les tĆ¢ches...", "TaskService.fetchingBuildTasks": "RĆ©cupĆ©ration des tĆ¢ches de gĆ©nĆ©ration...", - "TaskService.noBuildTaskTerminal": "Aucune tĆ¢che de gĆ©nĆ©ration. Appuyez sur 'Configurer une tĆ¢che de gĆ©nĆ©ration' pour en dĆ©finir une.", "TaskService.pickBuildTask": "SĆ©lectionner la tĆ¢che de gĆ©nĆ©ration Ć  exĆ©cuter", + "TaskService.noBuildTask": "Aucune tĆ¢che de gĆ©nĆ©ration Ć  exĆ©cuter n'a Ć©tĆ© trouvĆ©e. Configurer les tĆ¢ches...", "TaskService.fetchingTestTasks": "RĆ©cupĆ©ration des tĆ¢ches de test...", - "TaskService.noTestTaskTerminal": "Aucune tĆ¢che de test. Appuyez sur 'Configurer un exĆ©cuteur de tĆ¢ches' pour en dĆ©finir un.", "TaskService.pickTestTask": "SĆ©lectionner la tĆ¢che de test Ć  exĆ©cuter", - "TaskService.noTaskRunning": "Aucune tĆ¢che en cours d'exĆ©cution.", + "TaskService.noTestTaskTerminal": "Aucune tĆ¢che de test Ć  exĆ©cuter n'a Ć©tĆ© trouvĆ©e. Configurer les tĆ¢ches...", "TaskService.tastToTerminate": "SĆ©lectionner une tĆ¢che Ć  terminer", + "TaskService.noTaskRunning": "Aucune tĆ¢che en cours d’exĆ©cution", "TerminateAction.noProcess": "Le processus lancĆ© n'existe plus. Si la tĆ¢che a engendrĆ© des tĆ¢ches en arriĆØre-plan, la sortie de VS Code risque de donner lieu Ć  des processus orphelins.", "TerminateAction.failed": "Ɖchec de la fin de l'exĆ©cution de la tĆ¢che", - "TaskService.noTaskToRestart": "Aucune tĆ¢che Ć  redĆ©marrer.", "TaskService.tastToRestart": "SĆ©lectionner la tĆ¢che Ć  redĆ©marrer", - "TaskService.defaultBuildTaskExists": "{0} est dĆ©jĆ  marquĆ©e comme tĆ¢che de gĆ©nĆ©ration par dĆ©faut.", + "TaskService.noTaskToRestart": "Aucune tĆ¢che Ć  redĆ©marrer.", + "TaskService.template": "SĆ©lectionner un modĆØle de tĆ¢che", + "TaskService.createJsonFile": "CrĆ©er le fichier tasks.json Ć  partir d'un modĆØle", + "TaskService.openJsonFile": "Ouvrir le fichier tasks.json", + "TaskService.pickTask": "SĆ©lectionner une tĆ¢che Ć  configurer", + "TaskService.defaultBuildTaskExists": "{0} est dĆ©jĆ  marquĆ©e comme la tĆ¢che de gĆ©nĆ©ration par dĆ©faut", "TaskService.pickDefaultBuildTask": "SĆ©lectionner la tĆ¢che Ć  utiliser comme tĆ¢che de gĆ©nĆ©ration par dĆ©faut", "TaskService.defaultTestTaskExists": "{0} est dĆ©jĆ  marquĆ©e comme tĆ¢che de test par dĆ©faut.", "TaskService.pickDefaultTestTask": "SĆ©lectionner la tĆ¢che Ć  utiliser comme tĆ¢che de test par dĆ©faut", + "TaskService.pickShowTask": "SĆ©lectionner la tĆ¢che pour montrer sa sortie", + "TaskService.noTaskIsRunning": "Aucune tĆ¢che n’est en cours d’exĆ©cution", "ShowLogAction.label": "Afficher le journal des tĆ¢ches", "RunTaskAction.label": "ExĆ©cuter la tĆ¢che", "RestartTaskAction.label": "RedĆ©marrer la tĆ¢che en cours d'exĆ©cution", + "ShowTasksAction.label": "Afficher les tĆ¢ches en cours d'exĆ©cution", "BuildAction.label": "ExĆ©cuter la tĆ¢che de gĆ©nĆ©ration", "TestAction.label": "ExĆ©cuter la tĆ¢che de test", "ConfigureDefaultBuildTask.label": "Configurer la tĆ¢che de gĆ©nĆ©ration par dĆ©faut", diff --git a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 413680671bf..2265e06f9f3 100644 --- a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Une erreur inconnue s'est produite durant l'exĆ©cution d'une tĆ¢che. Pour plus d'informations, consultez le journal de sortie des tĆ¢ches.", + "dependencyFailed": "Impossible de rĆ©soudre la tĆ¢che dĆ©pendante '{0}' dans le dossier de l’espace de travail '{1}'", "TerminalTaskSystem.terminalName": "TĆ¢cheĀ -Ā {0}", "reuseTerminal": "Le terminal sera rĆ©utilisĆ© par les tĆ¢ches, appuyez sur une touche pour le fermer.", "TerminalTaskSystem": "Impossible d'exĆ©cuter une commande d'interprĆ©teur de commandes sur un lecteur UNC.", diff --git a/i18n/fra/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/fra/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index 9b94ea39874..14d05c09fde 100644 --- a/i18n/fra/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,9 +11,12 @@ "ConfigurationParser.unknownMatcherKind": "AvertissementĀ : le dĆ©tecteur de problĆØmes de correspondance dĆ©fini est inconnu. Les types pris en charge sont string | ProblemMatcher | (string | ProblemMatcher)[].\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "ErreurĀ : rĆ©fĆ©rence Ć  problemMatcher non valideĀ : {0}\n", "ConfigurationParser.noTaskType": "ErreurĀ : la configuration des tĆ¢ches doit avoir une propriĆ©tĆ© de type. La configuration est ignorĆ©e.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "ErreurĀ : aucun type de tĆ¢che '{0}' enregistrĆ©. Avez-vous oubliĆ© d'installer une extension incluant le fournisseur de tĆ¢ches correspondant ?", + "ConfigurationParser.missingRequiredProperty": "ErreurĀ : la configuration de la tĆ¢che '{0}' a besoin de la propriĆ©tĆ© '{1}'. La configuration de la tĆ¢che sera ignorĆ©e.", "ConfigurationParser.notCustom": "Erreur : la tĆ¢che n'est pas dĆ©clarĆ©e comme une tĆ¢che personnalisĆ©e. La configuration est ignorĆ©e.\n{0}\n", "ConfigurationParser.noTaskName": "ErreurĀ : les tĆ¢ches doivent fournir une propriĆ©tĆ© taskName. La tĆ¢che va ĆŖtre ignorĆ©e.\n{0}\n", "taskConfiguration.shellArgs": "AvertissementĀ : La tĆ¢che '{0}' est une commande d'interprĆ©teur de commandes, et le nom de la commande ou l'un de ses arguments contient des espaces non prĆ©cĆ©dĆ©s d'un caractĆØre d'Ć©chappement. Pour garantir une ligne de commande correcte, fusionnez les arguments dans la commande.", "taskConfiguration.noCommandOrDependsOn": "ErreurĀ : La tĆ¢che '{0}' ne spĆ©cifie ni une commande, ni une propriĆ©tĆ© dependsOn. La tĆ¢che est ignorĆ©e. Sa dĆ©finition estĀ :\n{1}", - "taskConfiguration.noCommand": "ErreurĀ : La tĆ¢che '{0}' ne dĆ©finit aucune commande. La tĆ¢che va ĆŖtre ignorĆ©e. Sa dĆ©finition estĀ :\n{1}" + "taskConfiguration.noCommand": "ErreurĀ : La tĆ¢che '{0}' ne dĆ©finit aucune commande. La tĆ¢che va ĆŖtre ignorĆ©e. Sa dĆ©finition estĀ :\n{1}", + "TaskParse.noOsSpecificGlobalTasks": "Task Version 2.0.0 ne supporte pas les tĆ¢ches spĆ©cifiques globales du systĆØme d'exploitation. Convertissez-les en une tĆ¢che en une commande spĆ©cifique du systĆØme d'exploitation. Les tĆ¢ches concernĆ©es sontĀ : {0}" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 8b6ad71cd4e..f680d69a958 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "termEntryAriaLabel": "{0}, sĆ©lecteur de terminaux", + "termCreateEntryAriaLabel": "{0}, crĆ©er un terminal", + "'workbench.action.terminal.newplus": "$(plus) CrĆ©er un terminal intĆ©grĆ©", + "noTerminalsMatching": "Aucun terminal correspondant", + "noTerminalsFound": "Aucun terminal ouvert" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 4eb70b27e65..8e54d84198f 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -4,18 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "quickOpen.terminal": "Afficher tous les terminaux ouverts", + "terminal": "Terminal", "terminalIntegratedConfigurationTitle": "Terminal intĆ©grĆ©", "terminal.integrated.shell.linux": "Chemin de l'interprĆ©teur de commandes utilisĆ© par le terminal sur Linux.", "terminal.integrated.shellArgs.linux": "Arguments de ligne de commande Ć  utiliser sur le terminal Linux.", "terminal.integrated.shell.osx": "Chemin de l'interprĆ©teur de commandes utilisĆ© par le terminal sur OSĀ X.", "terminal.integrated.shellArgs.osx": "Arguments de ligne de commande Ć  utiliser sur le terminal OSĀ X.", + "terminal.integrated.shell.windows": "Le chemin du shell que le terminal utilise sous Windows. Lors de l’utilisation de shells fournies avec Windows (cmd, PowerShell ou Bash sur Ubuntu).", "terminal.integrated.shellArgs.windows": "Arguments de ligne de commande Ć  utiliser sur le terminal Windows.", "terminal.integrated.rightClickCopyPaste": "Une fois le paramĆØtre dĆ©fini, le menu contextuel cesse de s'afficher quand l'utilisateur clique avec le bouton droit dans le terminal. ƀ la place, une opĆ©ration de copie est effectuĆ©e quand il existe une sĆ©lection, et une opĆ©ration de collage est effectuĆ©e en l'absence de sĆ©lection.", "terminal.integrated.fontFamily": "ContrĆ“le la famille de polices du terminal. La valeur par dĆ©faut est la valeur associĆ©e Ć  editor.fontFamily.", - "terminal.integrated.fontLigatures": "ContrĆ“le si les ligatures de police sont activĆ©es sur le terminal.", "terminal.integrated.fontSize": "ContrĆ“le la taille de police en pixels du terminal.", "terminal.integrated.lineHeight": "ContrĆ“le la hauteur de ligne du terminal. La multiplication de ce nombre par la taille de police du terminal permet d'obtenir la hauteur de ligne rĆ©elle en pixels.", - "terminal.integrated.enableBold": "Indique s'il faut activer ou non le texte en gras dans le terminal, ce qui nĆ©cessite une prise en charge de l'interprĆ©teur de commandes du terminal.", + "terminal.integrated.enableBold": "Indique s'il faut activer le texte en gras dans le terminal, notez que cela nĆ©cessite la prise en charge du terminal Shell.", "terminal.integrated.cursorBlinking": "ContrĆ“le si le curseur du terminal clignote.", "terminal.integrated.cursorStyle": "ContrĆ“le le style du curseur du terminal.", "terminal.integrated.scrollback": "ContrĆ“le la quantitĆ© maximale de lignes que le terminal conserve dans sa mĆ©moire tampon.", @@ -23,7 +25,9 @@ "terminal.integrated.cwd": "Chemin explicite de lancement du terminal. Il est utilisĆ© comme rĆ©pertoire de travail actif du processus d'interprĆ©teur de commandes. Cela peut ĆŖtre particuliĆØrement utile dans les paramĆØtres d'espace de travail, si le rĆ©pertoire racine n'est pas un rĆ©pertoire de travail actif adĆ©quat.", "terminal.integrated.confirmOnExit": "Indique s'il est nĆ©cessaire de confirmer l'existence de sessions de terminal actives au moment de quitter.", "terminal.integrated.commandsToSkipShell": "Ensemble d'ID de commandes dont les combinaisons de touches sont gĆ©rĆ©es par Code au lieu d'ĆŖtre envoyĆ©es Ć  l'interprĆ©teur de commandes. Cela permet d'utiliser des combinaisons de touches qui sont normalement consommĆ©es par l'interprĆ©teur de commandes et d'obtenir le mĆŖme rĆ©sultat quand le terminal n'a pas le focus, par exemple Ctrl+P pour lancer Quick Open.", - "terminal": "Terminal", + "terminal.integrated.env.osx": "Objet avec les variables d’environnement qui seront ajoutĆ©es au processus VS Code pour ĆŖtre utilisĆ©es par le terminal sous OS X", + "terminal.integrated.env.linux": "Objet avec les variables d’environnement qui seront ajoutĆ©es au processus VS Code pour ĆŖtre utilisĆ©es par le terminal sous Linux", + "terminal.integrated.env.windows": "Objet avec les variables d’environnement qui seront ajoutĆ©es au processus VS Code pour ĆŖtre utilisĆ©es par le terminal sous Windows", "terminalCategory": "Terminal", "viewCategory": "Affichage" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index e0a29182e95..b1d65f3e2d3 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "Activer/dĆ©sactiver le terminal intĆ©grĆ©", "workbench.action.terminal.kill": "Tuer l'instance active du terminal", "workbench.action.terminal.kill.short": "Tuer le terminal", + "workbench.action.terminal.quickKill": "Tuer l'instance de terminal", "workbench.action.terminal.copySelection": "Copier la sĆ©lection", "workbench.action.terminal.selectAll": "Tout SĆ©lectionner", + "workbench.action.terminal.deleteWordLeft": "Supprimer le mot Ć  gauche", + "workbench.action.terminal.deleteWordRight": "Supprimer le mot Ć  droite", "workbench.action.terminal.new": "CrĆ©er un terminal intĆ©grĆ©", "workbench.action.terminal.new.short": "Nouveau terminal", "workbench.action.terminal.focus": "Focus sur le terminal", "workbench.action.terminal.focusNext": "Focus sur le terminal suivant", - "workbench.action.terminal.focusAtIndex": "Focus sur le terminal {0}", "workbench.action.terminal.focusPrevious": "Focus sur le terminal prĆ©cĆ©dent", "workbench.action.terminal.paste": "Coller dans le terminal actif", "workbench.action.terminal.DefaultShell": "SĆ©lectionner l'interprĆ©teur de commandes par dĆ©faut", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "Renommer", "workbench.action.terminal.rename.prompt": "Entrer le nom du terminal", "workbench.action.terminal.focusFindWidget": "Focus sur le widget de recherche", - "workbench.action.terminal.hideFindWidget": "Masquer le widget de recherche" + "workbench.action.terminal.hideFindWidget": "Masquer le widget de recherche", + "nextTerminalFindTerm": "Afficher le terme de recherche suivant", + "previousTerminalFindTerm": "Afficher le terme de recherche prĆ©cĆ©dent", + "quickOpenTerm": "Changer de terminal actif" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 2a639927b49..89f1b826995 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -6,5 +6,8 @@ { "terminal.background": "Couleur d'arriĆØre-plan du terminal, permet d'appliquer au terminal une couleur diffĆ©rente de celle du panneau.", "terminal.foreground": "Couleur de premier plan du terminal.", + "terminalCursor.foreground": "La couleur de premier plan du curseur du terminal.", + "terminalCursor.background": "La couleur d’arriĆØre-plan du curseur terminal. Permet de personnaliser la couleur d’un caractĆØre recouvert par un curseur de bloc.", + "terminal.selectionBackground": "La couleur d’arriĆØre-plan de sĆ©lection du terminal.", "terminal.ansiColor": "Couleur ansi '{0}' dans le terminal." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 7aeb29b6337..aa7d60b35db 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copier", - "createNewTerminal": "Nouveau terminal", "paste": "Coller", "selectAll": "Tout SĆ©lectionner", "clear": "Effacer" diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 4692e6dfcd1..d636f6886f8 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OK, ne plus afficher", "terminal.integrated.chooseWindowsShell": "SĆ©lectionnez votre interprĆ©teur de commandes de terminal favori. Vous pouvez le changer plus tard dans vos paramĆØtres", "terminalService.terminalCloseConfirmationSingular": "Il existe une session de terminal active. Voulez-vous la tuerĀ ?", - "terminalService.terminalCloseConfirmationPlural": "Il existe {0} sessions de terminal actives. Voulez-vous les tuerĀ ?", - "yes": "Oui" + "terminalService.terminalCloseConfirmationPlural": "Il existe {0} sessions de terminal actives. Voulez-vous les tuerĀ ?" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 3b225062d91..12b4156b835 100644 --- a/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,9 @@ "licenseChanged": "Nos termes du contrat de licence ont changĆ©. Prenez un instant pour les consulter.", "license": "Lire la licence", "neveragain": "Ne plus afficher", + "64bitisavailable": "{0} pour Windows 64 bits est maintenant disponibleĀ !", "learn more": "En savoir plus", + "updateIsReady": "Nouvelle mise Ć  jour de {0} disponible.", "thereIsUpdateAvailable": "Une mise Ć  jour est disponible.", "updateAvailable": "{0} sera mis Ć  jour aprĆØs avoir redĆ©marrĆ©.", "noUpdatesAvailable": "Aucune mise Ć  jour n'est disponible actuellement.", diff --git a/i18n/fra/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/fra/src/vs/workbench/parts/views/browser/views.i18n.json index 4868e0b0e11..fcd571da926 100644 --- a/i18n/fra/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/views/browser/views.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "viewToolbarAriaLabel": "{0} actions" + "viewToolbarAriaLabel": "{0} actions", + "hideView": "Masquer dans la barre latĆ©rale" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json b/i18n/fra/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json index 4bf7b927181..f29fc92b3e6 100644 --- a/i18n/fra/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json @@ -12,5 +12,6 @@ "vscode.extension.contributes.view.when": "Condition qui doit ĆŖtre vraie pour afficher cette vue", "vscode.extension.contributes.views": "Ajoute des vues Ć  l'Ć©diteur", "views.explorer": "Mode Explorateur", + "views.debug": "Debug View", "locationId.invalid": "'{0}' n'est pas un emplacement de vue valide" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 8f490ebe701..0eb71eeba55 100644 --- a/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "DĆ©marrer", "welcomePage.newFile": "Nouveau fichier", "welcomePage.openFolder": "Ouvrir un dossier...", - "welcomePage.cloneGitRepository": "Cloner le dĆ©pĆ“t Git...", + "welcomePage.addWorkspaceFolder": "Ajouter un dossier d’espace de travail...", "welcomePage.recent": "RĆ©cent", "welcomePage.moreRecent": "Plus...", "welcomePage.noRecentFolders": "Aucun dossier rĆ©cent", diff --git a/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 7e1598eb347..8b2700e0374 100644 --- a/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Afficher les extensions Azure", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/fra/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/fra/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 3fb36dad027..5e7bc3ffbc2 100644 --- a/i18n/fra/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "Terrain de jeu interactif", - "editorWalkThrough.title": "Terrain de jeu interactif" + "editorWalkThrough.title": "Terrain de jeu interactif", + "editorWalkThrough": "Terrain de jeu interactif" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/fra/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..10bbc7a9e96 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "RĆ©sumĆ© des paramĆØtres. Cette Ć©tiquette va ĆŖtre utilisĆ©e dans le fichier de paramĆØtres en tant que commentaire de sĆ©paration.", + "vscode.extension.contributes.configuration.properties": "Description des propriĆ©tĆ©s de configuration.", + "scope.window.description": "Configuration spĆ©cifique de la fenĆŖtre, qui peut ĆŖtre configurĆ©e dans les paramĆØtres utilisateur ou de l'espace de travail.", + "scope.resource.description": "Configuration spĆ©cifique de la ressource, qui peut ĆŖtre configurĆ©e dans les paramĆØtres utilisateur, de l'espace de travail ou du dossier.", + "scope.description": "PortĆ©e dans laquelle la configuration s’applique. Les portĆ©es disponibles sont `window` et `resource`.", + "vscode.extension.contributes.configuration": "Ajoute des paramĆØtres de configuration.", + "invalid.title": "'configuration.title' doit ĆŖtre une chaĆ®ne", + "vscode.extension.contributes.defaultConfiguration": "Contribue aux paramĆØtres de configuration d'Ć©diteur par dĆ©faut en fonction du langage.", + "invalid.properties": "'configuration.properties' doit ĆŖtre un objet", + "invalid.allOf": "'configuration.allOf' est obsolĆØte et ne doit plus ĆŖtre utilisĆ©. Au lieu de cela, passez plusieurs sections de configuration sous forme de tableau au point de contribution 'configuration'.", + "workspaceConfig.folders.description": "Liste des dossiers Ć  ĆŖtre chargĆ©s dans l’espace de travail.", + "workspaceConfig.path.description": "Un chemin de fichier, par exemple, '/root/folderA' ou './folderA' pour un chemin relatif rĆ©solu selon l’emplacement du fichier d’espace de travail.", + "workspaceConfig.name.description": "Un nom facultatif pour le dossier. ", + "workspaceConfig.uri.description": "URI du dossier", + "workspaceConfig.settings.description": "ParamĆØtres de l’espace de travail", + "workspaceConfig.extensions.description": "Extensions de l’espace de travail", + "unknownWorkspaceProperty": "PropriĆ©tĆ© de configuration d’espace de travail inconnue" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json index 77c399f7d66..10bbc7a9e96 100644 --- a/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,11 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "Ajoute des paramĆØtres de configuration.", "vscode.extension.contributes.configuration.title": "RĆ©sumĆ© des paramĆØtres. Cette Ć©tiquette va ĆŖtre utilisĆ©e dans le fichier de paramĆØtres en tant que commentaire de sĆ©paration.", "vscode.extension.contributes.configuration.properties": "Description des propriĆ©tĆ©s de configuration.", - "invalid.type": "s'il est dĆ©fini, 'configuration.type' doit avoir la valeur 'object", + "scope.window.description": "Configuration spĆ©cifique de la fenĆŖtre, qui peut ĆŖtre configurĆ©e dans les paramĆØtres utilisateur ou de l'espace de travail.", + "scope.resource.description": "Configuration spĆ©cifique de la ressource, qui peut ĆŖtre configurĆ©e dans les paramĆØtres utilisateur, de l'espace de travail ou du dossier.", + "scope.description": "PortĆ©e dans laquelle la configuration s’applique. Les portĆ©es disponibles sont `window` et `resource`.", + "vscode.extension.contributes.configuration": "Ajoute des paramĆØtres de configuration.", "invalid.title": "'configuration.title' doit ĆŖtre une chaĆ®ne", "vscode.extension.contributes.defaultConfiguration": "Contribue aux paramĆØtres de configuration d'Ć©diteur par dĆ©faut en fonction du langage.", - "invalid.properties": "'configuration.properties' doit ĆŖtre un objet" + "invalid.properties": "'configuration.properties' doit ĆŖtre un objet", + "invalid.allOf": "'configuration.allOf' est obsolĆØte et ne doit plus ĆŖtre utilisĆ©. Au lieu de cela, passez plusieurs sections de configuration sous forme de tableau au point de contribution 'configuration'.", + "workspaceConfig.folders.description": "Liste des dossiers Ć  ĆŖtre chargĆ©s dans l’espace de travail.", + "workspaceConfig.path.description": "Un chemin de fichier, par exemple, '/root/folderA' ou './folderA' pour un chemin relatif rĆ©solu selon l’emplacement du fichier d’espace de travail.", + "workspaceConfig.name.description": "Un nom facultatif pour le dossier. ", + "workspaceConfig.uri.description": "URI du dossier", + "workspaceConfig.settings.description": "ParamĆØtres de l’espace de travail", + "workspaceConfig.extensions.description": "Extensions de l’espace de travail", + "unknownWorkspaceProperty": "PropriĆ©tĆ© de configuration d’espace de travail inconnue" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/fra/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index 059a4d89167..90ee69d1c1e 100644 --- a/i18n/fra/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/fra/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,28 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Ouvrir les paramĆØtres", + "openTasksConfiguration": "Ouvrir la configuration des tĆ¢ches", + "openLaunchConfiguration": "Ouvrir la configuration du lancement", "close": "Fermer", - "saveAndRetry": "Enregistrer les paramĆØtres et recommencer", - "errorInvalidConfiguration": "Impossible d'Ć©crire les paramĆØtres. Ouvrez les **ParamĆØtres utilisateur** pour corriger les erreurs/avertissements prĆ©sents dans le fichier, puis rĆ©essayez.", - "errorInvalidConfigurationWorkspace": "Impossible d'Ć©crire les paramĆØtres. Ouvrez les **ParamĆØtres d'espace de travail** pour corriger les erreurs/avertissements prĆ©sents dans le fichier, puis rĆ©essayez.", - "errorConfigurationFileDirty": "Impossible d'Ć©crire les paramĆØtres, car l'intĆ©gritĆ© du fichier est compromise. Enregistrez le fichier des **ParamĆØtres utilisateur**, puis rĆ©essayez.", - "errorConfigurationFileDirtyWorkspace": "Impossible d'Ć©crire les paramĆØtres, car l'intĆ©gritĆ© du fichier est compromise. Enregistrez le fichier des **ParamĆØtres d'espace de travail**, puis rĆ©essayez.", + "open": "Ouvrir les paramĆØtres", + "saveAndRetry": "Enregistrer et RĆ©essayer", + "errorUnknownKey": "Impossible d’écrire dans {0} car {1} n’est pas une configuration recommandĆ©e.", + "errorInvalidFolderConfiguration": "Impossible d’écrire dans les paramĆØtres de dossier parce que {0} ne supporte pas la portĆ©e de ressource de dossier.", + "errorInvalidUserTarget": "Impossible d’écrire dans les paramĆØtres utilisateur parce que {0} ne supporte pas de portĆ©e globale.", + "errorInvalidWorkspaceTarget": "Impossible d’écrire dans les paramĆØtres de l’espace de travail car {0} ne supporte pas de portĆ©e d’espace de travail dans un espace de travail multi dossiers.", + "errorInvalidFolderTarget": "Impossible d’écrire dans les paramĆØtres de dossier car aucune ressource n’est fournie.", + "errorNoWorkspaceOpened": "Impossible d’écrire dans {0} car aucun espace de travail n’est ouvert. Veuillez ouvrir un espace de travail et essayer Ć  nouveau.", + "errorInvalidTaskConfiguration": "Impossible d’écrire dans le fichier de tĆ¢ches. Veuillez s’il vous plaĆ®t ouvrir le fichier **Tasks** pour corriger les erreurs/avertissements Ć  l'intĆ©rieur et essayez Ć  nouveau.", + "errorInvalidLaunchConfiguration": "Impossible d’écrire dans le fichier de lancement. Veuillez s’il vous plaĆ®t ouvrir le fichier **Launch** pour corriger les erreurs/avertissements Ć  l'intĆ©rieur et essayez Ć  nouveau.", + "errorInvalidConfiguration": "Impossible d’écrire dans les paramĆØtres de l’utilisateur. Veuillez s’il vous plaĆ®t ouvrir le fichier **User Settings** pour corriger les erreurs/avertissements Ć  l'intĆ©rieur et essayez Ć  nouveau.", + "errorInvalidConfigurationWorkspace": "Impossible d’écrire dans les paramĆØtres de l’espace de travail. Veuillez s’il vous plaĆ®t ouvrir le fichier **Workspace Settings** pour corriger les erreurs/avertissements dans le fichier et rĆ©essayez.", + "errorInvalidConfigurationFolder": "Impossible d’écrire dans les paramĆØtres de dossier. Veuillez s’il vous plaĆ®t ouvrir le fichier **Folder Settings** sous le dossier **{0}** pour corriger les erreurs/avertissements Ć  l'intĆ©rieur et essayez Ć  nouveau.", + "errorTasksConfigurationFileDirty": "Impossible d’écrire dans le fichier de tĆ¢ches car le fichier est en attente de sauvegarde. Veuillez s’il vous plaĆ®t enregistrer le fichier **Tasks Configuration** et essayez Ć  nouveau.", + "errorLaunchConfigurationFileDirty": "Impossible d’écrire dans le fichier de lancement, car le fichier est en attente de sauvegarde. Veuillez s’il vous plaĆ®t enregistrer le fichier **Launch Configuration** et essayez Ć  nouveau.", + "errorConfigurationFileDirty": "Impossible d’écrire dans les paramĆØtres de l’utilisateur, car le fichier est en attente de sauvegarde. Veuillez s’il vous plaĆ®t enregistrer le fichier **User Settings** et essayez Ć  nouveau.", + "errorConfigurationFileDirtyWorkspace": "Impossible d’écrire dans les paramĆØtres de l’espace de travail, car le fichier est en attente de sauvegarde. Veuillez s’il vous plaĆ®t enregistrer le fichier **Workspace Settings** et essayez Ć  nouveau.", + "errorConfigurationFileDirtyFolder": "Impossible d’écrire dans les paramĆØtres de dossier parce que le fichier est attente de sauvegarde. Veuillez s’il vous plaĆ®t enregistrer le fichier **Folder Settings** sous le dossier **{0}** et essayez Ć  nouveau.", "userTarget": "ParamĆØtres utilisateur", - "workspaceTarget": "ParamĆØtres de l'espace de travail" + "workspaceTarget": "ParamĆØtres de l'espace de travail", + "folderTarget": "ParamĆØtres de dossier" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json b/i18n/fra/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json index 8b6ad71cd4e..c071f5c7c67 100644 --- a/i18n/fra/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json +++ b/i18n/fra/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "errorInvalidFile": "Impossible d’écrire dans le fichier. Veuillez ouvrir le fichier pour corriger les erreurs/avertissements dans le fichier et rĆ©essayer.", + "errorFileDirty": "Impossible d’écrire dans le fichier parce que le fichier a Ć©tĆ© modifiĆ©. Veuillez enregistrer le fichier et rĆ©essayer." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/fra/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/fra/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..a8972ed186e --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "L'hĆ“te d'extension n'a pas dĆ©marrĆ© en moins de 10Ā secondes. Il est peut-ĆŖtre arrĆŖtĆ© Ć  la premiĆØre ligne et a besoin d'un dĆ©bogueur pour continuer.", + "extensionHostProcess.startupFail": "L'hĆ“te d'extension n'a pas dĆ©marrĆ© en moins de 10Ā secondes. Il existe peut-ĆŖtre un problĆØme.", + "extensionHostProcess.error": "Erreur de l'hĆ“te d'extensionĀ : {0}" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..20c3f21a455 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "Ɖchec de l'analyse de {0}Ā : {1}.", + "fileReadFail": "Impossible de lire le fichier {0}Ā : {1}.", + "jsonsParseFail": "Ɖchec de l'analyse de {0} ou de {1}Ā : {2}.", + "missingNLSKey": "Le message est introuvable pour la clĆ© {0}." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..2056c501ce0 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "Outils de dĆ©veloppement", + "restart": "RedĆ©marrer l’hĆ“te d'extension", + "extensionHostProcess.crash": "L'hĆ“te d’extension s'est arrĆŖtĆ© de maniĆØre inattendue.", + "extensionHostProcess.unresponsiveCrash": "L'hĆ“te d'extension s'est arrĆŖtĆ©, car il ne rĆ©pondait pas.", + "overwritingExtension": "Remplacement de l'extension {0} par {1}.", + "extensionUnderDevelopment": "Chargement de l'extension de dĆ©veloppement sur {0}" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/fra/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..8ca568a2f40 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Il semble que le fichier soit binaire. Impossible de l'ouvrir en tant que texte" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json index 6a723324a19..e5bf54a3941 100644 --- a/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "Ressource de fichier non valide ({0})", - "fileIsDirectoryError": "Le fichier est un rĆ©pertoire ({0})", + "fileIsDirectoryError": "Le fichier est un rĆ©pertoire", "fileNotModifiedError": "Fichier non modifiĆ© depuis", "fileTooLargeError": "Fichier trop volumineux pour ĆŖtre ouvert", "fileBinaryError": "Il semble que le fichier soit binaire. Impossible de l'ouvrir en tant que texte", "fileNotFoundError": "Fichier introuvable ({0})", + "fileExists": "Le fichier Ć  crĆ©er existe dĆ©jĆ  ({0})", "fileMoveConflict": "DĆ©placement/copie impossible. Le fichier existe dĆ©jĆ  dans la destination.", "unableToMoveCopyError": "Impossible de dĆ©placer/copier. Le fichier remplace le dossier qui le contient.", "foldersCopyError": "Impossible de copier des dossiers dans l'espace de travail. SĆ©lectionnez les fichiers Ć  copier individuellement.", diff --git a/i18n/fra/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/fra/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 541b82ff55a..8488594cac5 100644 --- a/i18n/fra/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/fra/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}Ā : {1}" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 8d3e92e3005..72ed7866243 100644 --- a/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/fra/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "Style de police de la rĆØgleĀ : 'italique', 'gras' ou 'soulignĆ©', ou une combinaison de ces styles", - "schema.colors": "Couleurs de la coloration syntaxique", - "schema.properties.name": "Description de la rĆØgle", - "schema.tokenColors.path": "Chemin d'un fichier tmTheme (relatif au fichier actuel)" + "schema.token.settings": "Couleurs et styles du jeton.", + "schema.token.foreground": "Couleur de premier plan du jeton.", + "schema.token.background.warning": "Les couleurs d’arriĆØre-plan des tokens ne sont actuellement pas pris en charge.", + "schema.token.fontStyle": "Style de police de la rĆØgleĀ : 'italique', 'gras' ou 'soulignĆ©', ou une combinaison de ces styles", + "schema.fontStyle.error": "Le style de police doit ĆŖtre une combinaison de 'italic', 'bold' et 'underline'", + "schema.properties.name": "Description de la rĆØgle.", + "schema.properties.scope": "SĆ©lecteur de portĆ©e qui correspond Ć  cette rĆØgle.", + "schema.tokenColors.path": "Chemin d'un ficher tmTheme (relatif au fichier actuel).", + "schema.colors": "Couleurs de la coloration syntaxique" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 47c337cef4b..d920cb0bcb8 100644 --- a/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/fra/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Quand une police est utilisĆ©eĀ : taille de police en pourcentage par rapport Ć  la police du texte. En l'absence de dĆ©finition, la taille de la dĆ©finition de police est utilisĆ©e par dĆ©faut.", "schema.fontId": "Quand une police est employĆ©eĀ : ID de la police. En l'absence de dĆ©finition, la premiĆØre dĆ©finition de police est utilisĆ©e par dĆ©faut.", "schema.light": "Associations facultatives des icĆ“nes de fichiers dans les thĆØmes de couleur claire.", - "schema.highContrast": "Associations facultatives des icĆ“nes de fichiers dans les thĆØmes de couleur Ć  contraste Ć©levĆ©." + "schema.highContrast": "Associations facultatives des icĆ“nes de fichiers dans les thĆØmes de couleur Ć  contraste Ć©levĆ©.", + "schema.hidesExplorerArrows": "DĆ©termine si les flĆØches de l’Explorateur de fichier doivent ĆŖtre masquĆ©es lorsque ce thĆØme est actif." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..63c65b5f2e0 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "ID du thĆØme d'icĆ“ne utilisĆ© dans les paramĆØtres utilisateur.", + "vscode.extension.contributes.themes.label": "Ɖtiquette du thĆØme de couleur comme indiquĆ© dans l'interface utilisateur (IU).", + "vscode.extension.contributes.themes.uiTheme": "ThĆØme de base dĆ©finissant les couleurs autour de l'Ć©diteurĀ : 'vs' est le thĆØme de couleur clair, 'vs-dark' est le thĆØme de couleur sombre. 'hc-black' est le thĆØme sombre Ć  contraste Ć©levĆ©.", + "vscode.extension.contributes.themes.path": "Chemin du fichier tmTheme. Le chemin est relatif au dossier d'extensions et correspond gĆ©nĆ©ralement Ć  './themes/themeFile.tmTheme'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "ChaĆ®ne attendue dans 'contributes.{0}.path'. Valeur fournieĀ : {1}", + "invalid.path.1": "'contributes.{0}.path' ({1}) est censĆ© ĆŖtre inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..0c251843630 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "ID du thĆØme d'icĆ“ne utilisĆ© dans les paramĆØtres utilisateur.", + "vscode.extension.contributes.iconThemes.label": "Ɖtiquette du thĆØme d'icĆ“ne indiquĆ© dans l'IU (interface utilisateur).", + "vscode.extension.contributes.iconThemes.path": "Chemin du fichier de dĆ©finitions de thĆØmes d'icĆ“nes. Le chemin est relatif au dossier d'extensions et correspond gĆ©nĆ©ralement Ć  './icons/awesome-icon-theme.json'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "ChaĆ®ne attendue dans 'contributes.{0}.path'. Valeur fournieĀ : {1}", + "reqid": "ChaĆ®ne attendue dans 'contributes.{0}.id'. Valeur fournieĀ : {1}", + "invalid.path.1": "'contributes.{0}.path' ({1}) est censĆ© ĆŖtre inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable." +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index d541e53470b..234d5fb5a0e 100644 --- a/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/fra/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,29 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "ID du thĆØme d'icĆ“ne utilisĆ© dans les paramĆØtres utilisateur.", - "vscode.extension.contributes.themes.label": "Ɖtiquette du thĆØme de couleur comme indiquĆ© dans l'interface utilisateur (IU).", - "vscode.extension.contributes.themes.uiTheme": "ThĆØme de base dĆ©finissant les couleurs autour de l'Ć©diteurĀ : 'vs' est le thĆØme de couleur clair, 'vs-dark' est le thĆØme de couleur sombre. 'hc-black' est le thĆØme sombre Ć  contraste Ć©levĆ©.", - "vscode.extension.contributes.themes.path": "Chemin du fichier tmTheme. Le chemin est relatif au dossier d'extensions et correspond gĆ©nĆ©ralement Ć  './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ID du thĆØme d'icĆ“ne utilisĆ© dans les paramĆØtres utilisateur.", - "vscode.extension.contributes.iconThemes.label": "Ɖtiquette du thĆØme d'icĆ“ne indiquĆ© dans l'IU (interface utilisateur).", - "vscode.extension.contributes.iconThemes.path": "Chemin du fichier de dĆ©finitions de thĆØmes d'icĆ“nes. Le chemin est relatif au dossier d'extensions et correspond gĆ©nĆ©ralement Ć  './icons/awesome-icon-theme.json'.", "migration.completed": "De nouveaux paramĆØtres de thĆØme ont Ć©tĆ© ajoutĆ©s aux paramĆØtres utilisateur. Sauvegarde disponible sur {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "ChaĆ®ne attendue dans 'contributes.{0}.path'. Valeur fournieĀ : {1}", - "invalid.path.1": "'contributes.{0}.path' ({1}) est censĆ© ĆŖtre inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable.", - "reqid": "ChaĆ®ne attendue dans 'contributes.{0}.id'. Valeur fournieĀ : {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "SpĆ©cifie le thĆØme d'icĆ“ne utilisĆ© dans le banc d'essai ou 'null' pour n'afficher aucune icĆ“ne de fichier.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Remplace les couleurs du thĆØme de couleur sĆ©lectionnĆ©.", - "workbenchColors.deprecated": "Le paramĆØtre n'est plus expĆ©rimental et a Ć©tĆ© renommĆ© 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Utiliser 'workbench.colorCustomizations' Ć  la place" + "editorColors": "Remplace les couleurs et le style de la police de l’éditeur du thĆØme par la couleur actuellement sĆ©lectionnĆ©e.", + "editorColors.comments": "DĆ©finit les couleurs et les styles des commentaires", + "editorColors.strings": "DĆ©finit les couleurs et les styles des littĆ©raux de chaĆ®nes.", + "editorColors.keywords": "DĆ©finit les couleurs et les styles des mots clĆ©s.", + "editorColors.numbers": "DĆ©finit les couleurs et les styles des littĆ©raux de nombre.", + "editorColors.types": "DĆ©finit les couleurs et les styles des dĆ©clarations et rĆ©fĆ©rences de type.", + "editorColors.functions": "DĆ©finit les couleurs et les styles des dĆ©clarations et rĆ©fĆ©rences de fonctions.", + "editorColors.variables": "DĆ©finit les couleurs et les styles des dĆ©clarations et rĆ©fĆ©rences de variables.", + "editorColors.textMateRules": "DĆ©finit les couleurs et les styles Ć  l’aide de rĆØgles de thĆØme textmate (avancĆ©)." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/fra/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..079d530ab03 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "Impossible d’écrire dans le fichier de configuration de l’espace de travail. Veuillez ouvrir le fichier pour y corriger les erreurs/avertissements et essayez Ć  nouveau.", + "errorWorkspaceConfigurationFileDirty": "Impossible d’écrire dans le fichier de configuration de l’espace de travail, car le fichier a Ć©tĆ© modifiĆ©. Veuillez, s’il vous plaĆ®t, l'enregistrez et rĆ©essayez.", + "openWorkspaceConfigurationFile": "Ouvrir le Fichier de Configuration d’espace de travail", + "close": "Fermer", + "enterWorkspace.close": "Fermer", + "enterWorkspace.dontShowAgain": "Ne plus afficher", + "enterWorkspace.moreInfo": "Informations", + "enterWorkspace.prompt": "En savoir plus sur l’utilisation de dossiers multiples dans VS Code." +} \ No newline at end of file diff --git a/i18n/hun/extensions/azure-account/out/azure-account.i18n.json b/i18n/hun/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..fce78b4ff62 --- /dev/null +++ b/i18n/hun/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "MĆ”solĆ”s Ć©s megnyitĆ”s", + "azure-account.close": "BezĆ”rĆ”s", + "azure-account.login": "BejelentkezĆ©s", + "azure-account.loginFirst": "Nincs bejelentkezve. Előszƶr jelentkezzen be.", + "azure-account.userCodeFailed": "FelhasznĆ”lói kód lekĆ©rĆ©se nem sikerült", + "azure-account.tokenFailed": "Token lekĆ©rĆ©se eszkƶzkóddal", + "azure-account.tokenFromRefreshTokenFailed": "Token lekĆ©rĆ©se frissĆ­tĆ©si tokennel" +} \ No newline at end of file diff --git a/i18n/hun/extensions/azure-account/out/extension.i18n.json b/i18n/hun/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..3b2b1940bb6 --- /dev/null +++ b/i18n/hun/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: BejelentkezĆ©s...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 73e2b227f47..b0baf1f7552 100644 --- a/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/hun/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "pl.: myFile.txt", - "activeEditorMedium": "pl.: myFolder/myFile.txt", - "activeEditorLong": "pl.: /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "pl.: myFolder1, myFolder2, myFolder3", - "rootPath": "pl.: /Users/Development/myProject", - "folderName": "pl.: myFolder", - "folderPath": "pl.: /Users/Development/myProject", + "activeEditorShort": "a fĆ”jl neve (pl. myFile.txt)", + "activeEditorMedium": "a fĆ”jl relatĆ­v elĆ©rĆ©si Ćŗtja a munkaterület mappĆ”jĆ”hoz kĆ©pest (pl. myFolder/myFile.txt)", + "activeEditorLong": "a fĆ”jl teljes elĆ©rĆ©si Ćŗtja (pl. /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "a munkaterület neve (pl. myFolder vagy myWorkspace)", + "rootPath": "a munkaterület elĆ©rĆ©si Ćŗtja (pl. /Users/Development/myWorkspace)", + "folderName": "azon munkaterületi mappa a neve, amelyben a fĆ”jl talĆ”lható (pl. myFolder)", + "folderPath": "azon munkaterületi mappa elĆ©rĆ©si Ćŗtja, amelyben a fĆ”jl talĆ”lható (pl. /Users/Development/myFolder)", "appName": "pl.: VS Code", "dirty": "módosĆ­tĆ”sjelző, ami akkor jelenik meg, ha az aktĆ­v szerkesztőablak tartalma módosĆ­tva lett", "separator": "egy feltĆ©teles elvĆ”lasztó (' - '), ami akkor jelenik meg, ha olyan vĆ”ltozókkal van kƶrülvĆ©ve, amelyeknek van Ć©rtĆ©ke", diff --git a/i18n/hun/extensions/css/package.i18n.json b/i18n/hun/extensions/css/package.i18n.json index 5f6b8a4014b..5b083d46503 100644 --- a/i18n/hun/extensions/css/package.i18n.json +++ b/i18n/hun/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "Nem megfelelő szĆ”mĆŗ paramĆ©ter", "css.lint.boxModel.desc": "A width Ć©s a height tulajdonsĆ”g kerülĆ©se a padding Ć©s a border tulajdonsĆ”g hasznĆ”lata esetĆ©n", "css.lint.compatibleVendorPrefixes.desc": "GyĆ”rtóspecifikus előtag hasznĆ”lata esetĆ©n minden mĆ”s gyĆ”rtóspecifikus tulajdonsĆ”got is meg kell adni", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "Ismeretlen gyĆ”rtóspecifikus tulajdonsĆ”g.", "css.lint.vendorPrefix.desc": "GyĆ”rtóspecifikus előtagok hasznĆ”lata esetĆ©n az adott tulajdonsĆ”g szabvĆ”nyos vĆ”ltozatĆ”t is meg kell adni", "css.lint.zeroUnits.desc": "A 0 Ć©rtĆ©khez nem szüksĆ©ges mĆ©rtĆ©kegysĆ©g", + "css.trace.server.desc": "A VS Code Ć©s a CSS nyelvi szerver kƶzƶtti kommunikĆ”ció naplózĆ”sa.", + "css.validate.title": "MeghatĆ”rozza a CSS-validĆ”ció műkƶdĆ©sĆ©t Ć©s a problĆ©mĆ”k sĆŗlyossĆ”gĆ”t.", "css.validate.desc": "Ɩsszes validĆ”lĆ”s engedĆ©lyezĆ©se vagy letiltĆ”sa", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "Nem megfelelő szĆ”mĆŗ paramĆ©ter", "less.lint.boxModel.desc": "A width Ć©s a height tulajdonsĆ”g kerülĆ©se a padding Ć©s a border tulajdonsĆ”g hasznĆ”lata esetĆ©n", "less.lint.compatibleVendorPrefixes.desc": "GyĆ”rtóspecifikus előtag hasznĆ”lata esetĆ©n minden mĆ”s gyĆ”rtóspecifikus tulajdonsĆ”got is meg kell adni", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "Ismeretlen gyĆ”rtóspecifikus tulajdonsĆ”g.", "less.lint.vendorPrefix.desc": "GyĆ”rtóspecifikus előtagok hasznĆ”lata esetĆ©n az adott tulajdonsĆ”g szabvĆ”nyos vĆ”ltozatĆ”t is meg kell adni", "less.lint.zeroUnits.desc": "A 0 Ć©rtĆ©khez nem szüksĆ©ges mĆ©rtĆ©kegysĆ©g", + "less.validate.title": "MeghatĆ”rozza a LESS-validĆ”ció műkƶdĆ©sĆ©t Ć©s a problĆ©mĆ”k sĆŗlyossĆ”gĆ”t.", "less.validate.desc": "Ɩsszes validĆ”lĆ”s engedĆ©lyezĆ©se vagy letiltĆ”sa", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "Nem megfelelő szĆ”mĆŗ paramĆ©ter", "scss.lint.boxModel.desc": "A width Ć©s a height tulajdonsĆ”g kerülĆ©se a padding Ć©s a border tulajdonsĆ”g hasznĆ”lata esetĆ©n", "scss.lint.compatibleVendorPrefixes.desc": "GyĆ”rtóspecifikus előtag hasznĆ”lata esetĆ©n minden mĆ”s gyĆ”rtóspecifikus tulajdonsĆ”got is meg kell adni", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "Ismeretlen gyĆ”rtóspecifikus tulajdonsĆ”g.", "scss.lint.vendorPrefix.desc": "GyĆ”rtóspecifikus előtagok hasznĆ”lata esetĆ©n az adott tulajdonsĆ”g szabvĆ”nyos vĆ”ltozatĆ”t is meg kell adni", "scss.lint.zeroUnits.desc": "A 0 Ć©rtĆ©khez nem szüksĆ©ges mĆ©rtĆ©kegysĆ©g", + "scss.validate.title": "MeghatĆ”rozza az SCSS-validĆ”ció műkƶdĆ©sĆ©t Ć©s a problĆ©mĆ”k sĆŗlyossĆ”gĆ”t.", "scss.validate.desc": "Ɩsszes validĆ”lĆ”s engedĆ©lyezĆ©se vagy letiltĆ”sa", "less.colorDecorators.enable.desc": "SzĆ­ndekorĆ”torok engedĆ©lyezĆ©se vagy letiltĆ”sa", "scss.colorDecorators.enable.desc": "SzĆ­ndekorĆ”torok engedĆ©lyezĆ©se vagy letiltĆ”sa", - "css.colorDecorators.enable.desc": "SzĆ­ndekorĆ”torok engedĆ©lyezĆ©se vagy letiltĆ”sa" + "css.colorDecorators.enable.desc": "SzĆ­ndekorĆ”torok engedĆ©lyezĆ©se vagy letiltĆ”sa", + "css.colorDecorators.enable.deprecationMessage": "Az `css.colorDecorators.enable` beĆ”llĆ­tĆ”s elavult az `editor.colorDecorators` bevezetĆ©se miatt.", + "scss.colorDecorators.enable.deprecationMessage": "Az `scss.colorDecorators.enable` beĆ”llĆ­tĆ”s elavult az `editor.colorDecorators` bevezetĆ©se miatt.", + "less.colorDecorators.enable.deprecationMessage": "A `less.colorDecorators.enable` beĆ”llĆ­tĆ”s elavult az `editor.colorDecorators` bevezetĆ©se miatt." } \ No newline at end of file diff --git a/i18n/hun/extensions/emmet/package.i18n.json b/i18n/hun/extensions/emmet/package.i18n.json index e5c10b00cae..99db67d814e 100644 --- a/i18n/hun/extensions/emmet/package.i18n.json +++ b/i18n/hun/extensions/emmet/package.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "BecsomagolĆ”s rƶvidĆ­tĆ©ssel", + "command.wrapIndividualLinesWithAbbreviation": "Egyedi sorok becsomagolĆ”sa rƶvidĆ­tĆ©ssel", "command.removeTag": "Elem eltĆ”volĆ­tĆ”sa", "command.updateTag": "Elem módosĆ­tĆ”sa", "command.matchTag": "UgrĆ”s az illeszkedő pĆ”rra", @@ -24,5 +26,28 @@ "command.incrementNumberByOneTenth": "NƶvelĆ©s 0,1-gyel", "command.decrementNumberByOneTenth": "CsƶkkentĆ©s 0,1-gyel", "command.incrementNumberByTen": "NƶvelĆ©s 10-zel", - "command.decrementNumberByTen": "CsƶkkentĆ©s 10-zel" + "command.decrementNumberByTen": "CsƶkkentĆ©s 10-zel", + "emmetSyntaxProfiles": "KonkrĆ©t szintaktika profiljĆ”nak meghatĆ”rozĆ”sa vagy sajĆ”t profil hasznĆ”lata adott szabĆ”lyokkal.", + "emmetExclude": "Azon nyelvek listĆ”ja, ahol az Emmet-rƶvidĆ­tĆ©sek ne legyenek kibontva.", + "emmetExtensionsPath": "Emmet-profilokat Ć©s -kódtƶredĆ©keket tartalmazó mappa elĆ©rĆ©si Ćŗtja.", + "emmetShowExpandedAbbreviation": "Kibontott Emmet-rƶvidĆ­tĆ©sek megjelenĆ­tĆ©se javaslatkĆ©nt. Az \"inMarkupAndStylesheetFilesOnly\" beĆ”llĆ­tĆ”s csak a html, haml, jade, slim, xml, xsl, css, scss, sass, less Ć©s stylus tĆ­pusĆŗ tartalmat jelenti. Az \"always\" beĆ”llĆ­tĆ”s a fĆ”jl ƶsszes rĆ©szĆ©re vonatkozik a jelƶlőnyelvtől/css-től függetlenül.", + "emmetShowAbbreviationSuggestions": "LehetsĆ©ges Emmet-rƶvidĆ­tĆ©sek megjelenĆ­tĆ©se javaslatkĆ©nt. Nem hasznĆ”lható a stĆ­luslapokon vagy ha az emmet.showExpandedAbbreviation Ć©rtĆ©ke \"never\".", + "emmetIncludeLanguages": "Emmet-rƶvidĆ­tĆ©sek engedĆ©lyezĆ©se olyan nyelvek esetĆ©ben, amelyek alapĆ©rtelmezĆ©s szerint nem tĆ”mogatottak. Egy megfeleltetĆ©st kell felvenni a nyelv Ć©s egy emmet Ć”ltal tĆ”mogatott nyelv kƶzƶtt.\nPl.: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "Az Emmet-kódrĆ©szletekben hasznĆ”lt vĆ”ltozók", + "emmetTriggerExpansionOnTab": "Ha engedĆ©lyezve van, akkor az Emmet-rƶvidĆ­tĆ©sek a Tab billentyű lenyomĆ”sĆ”val bonthatók ki.", + "emmetPreferences": "BeĆ”llĆ­tĆ”sok, melyek módosĆ­tjĆ”k az Emmet műveleteinek Ć©s feloldó algoritmusainak viselkedĆ©sĆ©t.", + "emmetPreferencesIntUnit": "Az egĆ©sz szĆ”mok alapĆ©rtelmezett mĆ©rtĆ©kegysĆ©ge", + "emmetPreferencesFloatUnit": "A lebegőpontos szĆ”mok alapĆ©rtelmezett mĆ©rtĆ©kegysĆ©ge", + "emmetPreferencesCssAfter": "A CSS-tulajdonsĆ”g vĆ©gĆ©re helyezett szimbólum CSS-rƶvidĆ­tĆ©sek kibontĆ”sĆ”nĆ”l", + "emmetPreferencesSassAfter": "A CSS-tulajdonsĆ”g vĆ©gĆ©re helyezett szimbólum CSS-rƶvidĆ­tĆ©sek kibontĆ”sĆ”nĆ”l Sass-fĆ”jlokban", + "emmetPreferencesStylusAfter": "A CSS-tulajdonsĆ”g vĆ©gĆ©re helyezett szimbólum CSS-rƶvidĆ­tĆ©sek kibontĆ”sĆ”nĆ”l Stylus-fĆ”jlokban", + "emmetPreferencesCssBetween": "A CSS-tulajdonsĆ”g Ć©s az Ć©rtĆ©k kƶzĆ© helyezett szimbólum CSS-rƶvidĆ­tĆ©sek kibontĆ”sĆ”nĆ”l", + "emmetPreferencesSassBetween": "A CSS-tulajdonsĆ”g Ć©s az Ć©rtĆ©k kƶzĆ© helyezett szimbólum CSS-rƶvidĆ­tĆ©sek kibontĆ”sĆ”nĆ”l Sass-fĆ”jlokban", + "emmetPreferencesStylusBetween": "A CSS-tulajdonsĆ”g Ć©s az Ć©rtĆ©k kƶzĆ© helyezett szimbólum CSS-rƶvidĆ­tĆ©sek kibontĆ”sĆ”nĆ”l Stylus-fĆ”jlokban", + "emmetShowSuggestionsAsSnippets": "Ha ez igaz, majd Emmet-javaslatok jelenik meg mint tƶredĆ©k, amely lehetővĆ© teszi, annak Ć©rdekĆ©ben, őket egy editor.snippetSuggestions beĆ”llĆ­tĆ”st.", + "emmetPreferencesBemElementSeparator": "ElemelvĆ”lasztó osztĆ”lyok megadĆ”sĆ”nĆ”l BEM-szűrő hasznĆ”lata esetĆ©n", + "emmetPreferencesBemModifierSeparator": "MódosĆ­tó elvĆ”lasztó osztĆ”lyok megadĆ”sĆ”nĆ”l BEM-szűrő hasznĆ”lata esetĆ©n", + "emmetPreferencesFilterCommentBefore": "Annak a megjegyzĆ©snek a definĆ­ciója, ami az illeszkedő elem elĆ© kerül a megjegyzĆ©sszűrő alkalmazĆ”sa esetĆ©n.", + "emmetPreferencesFilterCommentAfter": "Annak a megjegyzĆ©snek a definĆ­ciója, ami az illeszkedő elem mƶgĆ© kerül a megjegyzĆ©sszűrő alkalmazĆ”sa esetĆ©n.", + "emmetPreferencesFilterCommentTrigger": "AttribĆŗtumnevek vesszővel elvĆ”lasztott listĆ”ja, amelyeknek lĆ©teznie kell a megjegyzĆ©sszűrő alkalmazĆ”sĆ”hoz." } \ No newline at end of file diff --git a/i18n/hun/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/hun/extensions/extension-editing/out/extensionLinter.i18n.json index 3e085fae59a..e3c13b9c6a9 100644 --- a/i18n/hun/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/hun/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "A kĆ©pek csak HTTPS-protokollt hasznĆ”lhatnak.", "svgsNotValid": "Az SVG-k nem Ć©rvĆ©nyes kĆ©pforrĆ”sok.", "embeddedSvgsNotValid": "A beĆ”gyazott SVG-k nem Ć©rvĆ©nyes kĆ©pforrĆ”sok.", - "dataUrlsNotValid": "A data URL-ek nem Ć©rvĆ©nyes kĆ©pforrĆ”sok." + "dataUrlsNotValid": "A data URL-ek nem Ć©rvĆ©nyes kĆ©pforrĆ”sok.", + "relativeUrlRequiresHttpsRepository": "A relatĆ­v kĆ©p URL-ekhez egy HTTPS-protokollal rendelkező forrĆ”skódtĆ”rat kell megadni a package.json-ban.", + "relativeIconUrlRequiresHttpsRepository": "Az ikonhoz egy HTTPS-protokollal rendelkező forrĆ”skódtĆ”rat kell megadni a package.json-ban.", + "relativeBadgeUrlRequiresHttpsRepository": "A relatĆ­v jelvĆ©ny URL-ekhez egy HTTPS-protokollal rendelkező forrĆ”skódtĆ”rat kell megadni a package.json-ban." } \ No newline at end of file diff --git a/i18n/hun/extensions/git/out/commands.i18n.json b/i18n/hun/extensions/git/out/commands.i18n.json index cefdc21b643..ed82f751b7f 100644 --- a/i18n/hun/extensions/git/out/commands.i18n.json +++ b/i18n/hun/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "Git-forrĆ”skódtĆ”r klónozĆ”sa...", "openrepo": "ForrĆ”skódtĆ”r megnyitĆ”sa", "proposeopen": "SzeretnĆ© megnyitni a klónozott forrĆ”skódtĆ”rat?", + "init repo": "ForrĆ”skódtĆ”r előkĆ©szĆ­tĆ©se", + "create repo": "ForrĆ”skódtĆ”r előkĆ©szĆ­tĆ©se", + "are you sure": "A művelet egy Git forrĆ”skódtĆ”rat hoz lĆ©tre a kƶvetkező helyen: '{0}. Biztosan szeretnĆ© folytatni?", "HEAD not available": "A(z) '{0}' HEAD-verziója nem elĆ©rhető.", + "confirm stage files with merge conflicts": "Biztosan elő szeretne jegyezni {0} ütkƶzĆ©si konfliktussal rendelkező fĆ”jlt?", + "confirm stage file with merge conflicts": "Biztosan elő szeretne jegyezni a kƶvetkező, ütkƶzĆ©si konfliktussal rendelkező fĆ”jlt: {0}?", + "yes": "Igen", "confirm revert": "VisszaĆ”llĆ­tja a kijelƶlt módosĆ­tĆ”sokat a kƶvetkező helyen: {0}?", "revert": "MódosĆ­tĆ”sok visszaĆ”llĆ­tĆ”sa", + "discard": "MódosĆ­tĆ”sok elvetĆ©se", + "confirm delete": "Biztosan TƖRLI a kƶvetkezőt: {0}?", + "delete file": "FĆ”jl tƶrlĆ©se", "confirm discard": "Elveti a módosĆ­tĆ”sokat a kƶvetkező helyen: {0}?", "confirm discard multiple": "Elveti {0} fĆ”jl módosĆ­tĆ”sait?", - "discard": "MódosĆ­tĆ”sok elvetĆ©se", - "confirm discard all": "Elveti az ƖSSZES módosĆ­tĆ”st? A művelet NEM VONHATƓ VISSZA!", - "discardAll": "ƖSSZES módosĆ­tĆ”s elvetĆ©se", + "warn untracked": "A művelet {0} nem kƶvetett fĆ”jl TƖRLƉSƉT fogja eredmĆ©nyezni!", + "confirm discard all single": "Elveti a módosĆ­tĆ”sokat a kƶvetkező helyen: {0}?", + "confirm discard all": "Elveti az ƖSSZES módosĆ­tĆ”st {0} fĆ”jlban?\nA művelet NEM VONHATƓ VISSZA!\nAz aktuĆ”lis munka ƖRƖKRE EL FOG VESZNI.", + "discardAll multiple": "Egy fĆ”jl elvetĆ©se", + "discardAll": "Mind a(z) {0} fĆ”jl elvetĆ©se", + "confirm delete multiple": "Biztosan TƖRƖLNI akar {0} fĆ”jlt?", + "delete files": "FĆ”jlok tƶrlĆ©se", + "there are untracked files single": "A kƶvetkező, nem kƶvetett fĆ”jl TƖRƖLVE LESZ A LEMEZRŐL, ha elvetĆ©sre kerül: {0}.", + "there are untracked files": "{0} nem kƶvetett fĆ”jl TƖRƖLVE LESZ A LEMEZRŐL, ha elvetĆ©sre kerülnek. ", + "confirm discard all 2": "{0}\n\nA művelet NEM VONHATƓ VISSZA, az aktuĆ”lis munka ƖRƖKRE EL FOG VESZNI.", + "yes discard tracked": "Egy kƶvetett fĆ”jl elvetĆ©se", + "yes discard tracked multiple": "{0} kƶvetett fĆ”jl elvetĆ©se", "no staged changes": "Nincs beadĆ”shoz (commithoz) előjegyzett módosĆ­tĆ”s. SzeretnĆ© automatikusan előjegyeztetni a módosĆ­tĆ”sokat Ć©s kƶzvetlenül beadni őket?", - "yes": "Igen", "always": "Mindig", "no changes": "Nincs beadandó módosĆ­tĆ”s.", "commit message": "BeadĆ”si (commit) üzenet", @@ -34,16 +51,25 @@ "delete branch": "Ɓg tƶrlĆ©se", "select a branch to merge from": "VĆ”lassza ki az Ć”gat, amit olvasztani szeretne", "merge conflicts": "ƖsszeolvasztĆ”si konfliktusok keletkeztek. Oldja fel őket a beadĆ”s (commit) előtt!", + "tag name": "CĆ­mke neve", + "provide tag name": "Adja meg a cĆ­mke nevĆ©t", + "tag message": "Üzenet", + "provide tag message": "Adja meg a cĆ­mke leĆ­rĆ”sĆ”t tartalmazó üzenetet", "no remotes to pull": "A forrĆ”skódtĆ”rhoz nincsenek tĆ”voli szerverek konfigurĆ”lva, ahonnan pullozni lehetne.", "pick remote pull repo": "VĆ”lassza ki a tĆ”voli szervert, ahonnan pullozni szeretnĆ© az Ć”gat", "no remotes to push": "A forrĆ”skódtĆ”rhoz nincsenek tĆ”voli szerverek konfigurĆ”lva, ahovĆ” pusholni lehetne.", + "push with tags success": "A cĆ­mkĆ©kkel együtt tƶrtĆ©nő pusholĆ”s sikeresen befejeződƶtt.", "nobranch": "VĆ”lasszon egy Ć”gat a tĆ”voli szerverre való pusholĆ”shot!", "pick remote": "VĆ”lassza ki a tĆ”voli szervert, ahovĆ” publikĆ”lni szeretnĆ© a(z) '{0}' Ć”gat:", "sync is unpredictable": "Ez a művelet pusholja Ć©s pullozza a commitokat a kƶvetkező helyről: '{0}'.", "ok": "OK", "never again": "Rendben, ne jelenĆ­tse meg Ćŗjra", "no remotes to publish": "A forrĆ”skódtĆ”rhoz nincsenek tĆ”voli szerverek konfigurĆ”lva, ahovĆ” publikĆ”lni lehetne.", - "disabled": "A git le van tiltva vagy nem tĆ”mogatott ezen a munkaterületen", + "no changes stash": "Nincs elrakandó módosĆ­tĆ”s.", + "provide stash message": "Adja meg a stash-hez tartozó üzenet (nem kƶtelező)", + "stash message": "Stash-üzenet", + "no stashes": "Nincs visszaĆ”llĆ­tható stash.", + "pick stash to pop": "VĆ”lassza ki a visszaĆ”llĆ­tandó stash-t", "clean repo": "TakarĆ­tsa ki a forrĆ”skódtĆ”r munkafĆ”jĆ”t, mielőtt checkoutolna!", "cant push": "Nem lehet pusholni a tĆ”voli szerverre. Futtassa a 'Pull' parancsot a módosĆ­tĆ”sai integrĆ”lĆ”sĆ”hoz!", "git error details": "Git: {0}", diff --git a/i18n/hun/extensions/git/out/model.i18n.json b/i18n/hun/extensions/git/out/model.i18n.json index 3744b7c2b59..b48df0faf59 100644 --- a/i18n/hun/extensions/git/out/model.i18n.json +++ b/i18n/hun/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "MegnyitĆ”s", - "merge changes": "MódosĆ­tĆ”sok ƶsszeolvasztĆ”sa", - "staged changes": "BeadĆ”sra előjegyzett módosĆ­tĆ”sok", - "changes": "MódosĆ­tĆ”sok", - "ok": "OK", - "neveragain": "Soha ne jelenĆ­tse meg Ćŗjra", - "huge": "A(z) '{0}' forrĆ”skódtĆ”rban tĆŗl sok aktĆ­v módosĆ­tĆ”s van. A Git-funkciók csak egy rĆ©sze lesz engedĆ©lyezve." + "no repositories": "Nem talĆ”lható forrĆ”skódtĆ”r.", + "pick repo": "VĆ”lasszon forrĆ”skódtĆ”rat!" } \ No newline at end of file diff --git a/i18n/hun/extensions/git/out/repository.i18n.json b/i18n/hun/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..360a4435ac6 --- /dev/null +++ b/i18n/hun/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "MegnyitĆ”s", + "index modified": "Index, módosĆ­tva", + "modified": "MódosĆ­tva", + "index added": "Index, hozzĆ”adva", + "index deleted": "Index, tƶrƶlve", + "deleted": "Tƶrƶlve", + "index renamed": "Index, Ć”tnevezve", + "index copied": "Index, mĆ”solva", + "untracked": "Nem kƶvetett", + "ignored": "Figyelmen kĆ­vül hagyva", + "both deleted": "Mindkettő tƶrƶlte", + "added by us": "Ɓltalunk hozzĆ”adott", + "deleted by them": "Ɓltaluk tƶrƶlt", + "added by them": "Ɓltaluk hozzĆ”adott", + "deleted by us": "Ɓltalunk tƶrƶlt", + "both added": "Mindkettő hozzĆ”adta", + "both modified": "Mindkettő módosĆ­totta", + "commit": "Commit", + "merge changes": "MódosĆ­tĆ”sok ƶsszeolvasztĆ”sa", + "staged changes": "BeadĆ”sra előjegyzett módosĆ­tĆ”sok", + "changes": "MódosĆ­tĆ”sok", + "ok": "OK", + "neveragain": "Soha ne jelenĆ­tse meg Ćŗjra", + "huge": "A(z) '{0}' forrĆ”skódtĆ”rban tĆŗl sok aktĆ­v módosĆ­tĆ”s van. A Git-funkciók csak egy rĆ©sze lesz engedĆ©lyezve." +} \ No newline at end of file diff --git a/i18n/hun/extensions/git/package.i18n.json b/i18n/hun/extensions/git/package.i18n.json index 94959981606..d0c5339fa18 100644 --- a/i18n/hun/extensions/git/package.i18n.json +++ b/i18n/hun/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "KlónozĆ”s", "command.init": "ForrĆ”skódtĆ”r előkĆ©szĆ­tĆ©se", + "command.close": "ForrĆ”skódtĆ”r bezĆ”rĆ”sa", "command.refresh": "FrissĆ­tĆ©s", "command.openChange": "MódosĆ­tĆ”sok megnyitĆ”sa", "command.openFile": "FĆ”jl megnyitĆ”sa", @@ -14,6 +15,8 @@ "command.stageAll": "Ɩsszes módosĆ­tĆ”s előjegyzĆ©se beadĆ”sra", "command.stageSelectedRanges": "Kijelƶlt területek előjegyzĆ©se beadĆ”sra", "command.revertSelectedRanges": "Kijelƶlt területek visszaĆ”llĆ­tĆ”sa", + "command.stageChange": "VĆ”ltozĆ”s előjegyzĆ©se beadĆ”sra", + "command.revertChange": "VĆ”ltoztatĆ”s visszavonĆ”sa", "command.unstage": "MódosĆ­tĆ”sok előjegyzĆ©sĆ©nek tƶrlĆ©se", "command.unstageAll": "Minden módosĆ­tĆ”s előjegyzĆ©sĆ©nek tƶrlĆ©se", "command.unstageSelectedRanges": "Kijelƶlt területek előjegyzĆ©sĆ©nek tƶrlĆ©se", @@ -22,22 +25,29 @@ "command.commit": "Commit", "command.commitStaged": "Előjegyzettek beadĆ”sa (commit)", "command.commitStagedSigned": "Előjegyzettek beadĆ”sa (commit) alƔƭrĆ”ssal", + "command.commitStagedAmend": "Előjegyzettek beadĆ”sa (commit) javĆ­tĆ”ssal (amend)", "command.commitAll": "Ɩsszes beadĆ”sa (commit)", "command.commitAllSigned": "Ɩsszes beadĆ”sa (commit) alƔƭrĆ”ssal", + "command.commitAllAmend": "Ɩsszes beadĆ”sa (commint) javĆ­tĆ”ssal", "command.undoCommit": "Legutolsó beadĆ”s (commit) visszavonĆ”sa", "command.checkout": "Checkout adott helyre...", "command.branch": "Ɓg lĆ©trehozĆ”sa...", "command.deleteBranch": "Új Ć”g lĆ©trehozĆ”sa", "command.merge": "Ɓg beolvasztĆ”sa...", + "command.createTag": "CĆ­mke lĆ©trehozĆ”sa", "command.pull": "Pull", "command.pullRebase": "Pull (Rebase)", "command.pullFrom": "PullozĆ”s...", "command.push": "Push", "command.pushTo": "Push adott helyre...", + "command.pushWithTags": "Push cĆ­mkĆ©kkel", "command.sync": "SzinkronizĆ”lĆ”s", "command.publish": "Ɓg publikĆ”lĆ”sa", "command.showOutput": "Git-kimenet megjelenĆ­tĆ©se", "command.ignore": "FĆ”jl hozzĆ”adĆ”sa a .gitignore-hoz", + "command.stash": "Stash", + "command.stashPop": "Stash visszaĆ”llĆ­tĆ”sa...", + "command.stashPopLatest": "Legutóbbi stash visszaĆ”llĆ­tĆ”sa", "config.enabled": "MeghatĆ”rozza, hogy a git engedĆ©lyezve van-e", "config.path": "A git vĆ©grehajtható fĆ”jl elĆ©rĆ©si Ćŗtja", "config.autorefresh": "MeghatĆ”rozza, hogy engedĆ©lyezve van-e az automatikus frissĆ­tĆ©s", @@ -49,5 +59,13 @@ "config.ignoreLegacyWarning": "RĆ©gi gittel kapcsolatos figyelmeztetĆ©s figyelmen kĆ­vül hagyĆ”sa", "config.ignoreLimitWarning": "TĆŗl sok módosĆ­tĆ”s esetĆ©n megjelenő figyelmeztetĆ©s figyelmen kĆ­vül hagyĆ”sa", "config.defaultCloneDirectory": "Git-forrĆ”skódtĆ”rak klónozĆ”sĆ”nak alapĆ©rtelmezett helye.", - "config.enableSmartCommit": "Ɩsszes módosĆ­tĆ”s beadĆ”sa (commit), ha nincsenek előjegyzett módosĆ­tĆ”sok." + "config.enableSmartCommit": "Ɩsszes módosĆ­tĆ”s beadĆ”sa (commit), ha nincsenek előjegyzett módosĆ­tĆ”sok.", + "config.enableCommitSigning": "Commit GPG-vel tƶrtĆ©nő alƔƭrĆ”sĆ”nak engedĆ©lyezĆ©se.", + "config.discardAllScope": "MeghatĆ”rozza, hogy milyen módosĆ­tĆ”sok kerülnek elvetĆ©sre az \"Ɩsszes módosĆ­tĆ”s elvetĆ©se\" parancs kiadĆ”sa esetĆ©n. `all` esetĆ©n minden módosĆ­tĆ”s elvetődik. `tracked` esetĆ©n csak a kƶvetett fĆ”jlok módosĆ­tĆ”sai vetődnek el. `prompt` esetĆ©n a parancs minden futtatĆ”sĆ”nĆ”l felugrik egy pĆ”rbeszĆ©dablak.", + "config.decorations.enabled": "MeghatĆ”rozza, hogy a Git megjelƶlje-e szĆ­nnel Ć©s jelvĆ©nnyekkel a fĆ”jlokat a fĆ”jlkezelőben Ć©s a nyitott szerkesztőablakok nĆ©zetben.", + "colors.modified": "A módosĆ­tott erőforrĆ”sok szĆ­ne.", + "colors.deleted": "A tƶrƶlt erőforrĆ”sok szĆ­ne.", + "colors.untracked": "A nem kƶvetett erőforrĆ”sok szĆ­ne.", + "colors.ignored": "A figyelmen kĆ­vül hagyott erőforrĆ”sok szĆ­ne.", + "colors.conflict": "A konfliktusos erőforrĆ”sok szĆ­ne." } \ No newline at end of file diff --git a/i18n/hun/extensions/grunt/out/main.i18n.json b/i18n/hun/extensions/grunt/out/main.i18n.json index 9c974666315..343486514df 100644 --- a/i18n/hun/extensions/grunt/out/main.i18n.json +++ b/i18n/hun/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "A Grunt automatikus felderĆ­tĆ©se nem sikerült a kƶvetkező hiba miatt: {0}" + "execFailed": "A Grunt automatikus felderĆ­tĆ©se a(z) {0} mappĆ”hoz nem sikerült a kƶvetkező hiba miatt: {1}" } \ No newline at end of file diff --git a/i18n/hun/extensions/gulp/out/main.i18n.json b/i18n/hun/extensions/gulp/out/main.i18n.json index 8c8ac9db031..9a22c2ad9b3 100644 --- a/i18n/hun/extensions/gulp/out/main.i18n.json +++ b/i18n/hun/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "A gulp automatikus felderĆ­tĆ©se nem sikerült a kƶvetkező hiba miatt: {0}" + "execFailed": "A gulp automatikus felderĆ­tĆ©se a(z) {0} mappĆ”hoz nem sikerült a kƶvetkező hiba miatt: {1}" } \ No newline at end of file diff --git a/i18n/hun/extensions/html/package.i18n.json b/i18n/hun/extensions/html/package.i18n.json index 1eea9c9eee6..292aa40864b 100644 --- a/i18n/hun/extensions/html/package.i18n.json +++ b/i18n/hun/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "AlapĆ©rtelmezett HTML-formĆ”zó engedĆ©lyezĆ©se vagy letiltĆ”sa (ĆŗjraindĆ­tĆ”st igĆ©nyel)", + "html.format.enable.desc": "AlapĆ©rtelmezett HTML-formĆ”zó engedĆ©lyezĆ©se vagy letiltĆ”sa.", "html.format.wrapLineLength.desc": "MaximĆ”lis karakterszĆ”m soronkĆ©nt (0 = letiltĆ”s)", "html.format.unformatted.desc": "Azon elemek vesszővel elvĆ”lasztott listĆ”ja, melyek ne legyenek ĆŗjraformĆ”zva. 'null' Ć©rtĆ©k esetĆ©n a https://www.w3.org/TR/html5/dom.html#phrasing-content oldalon listĆ”zott elemek lesznek hasznĆ”lva.", "html.format.contentUnformatted.desc": "Azon elemek vesszővel elvĆ”lasztott listĆ”ja, melyek ne legyenek ĆŗjraformĆ”zva. 'null' Ć©rtĆ©k esetĆ©n a 'pre' tag lesz hasznĆ”lva.", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "MeghatĆ”rozza, hogy a beĆ©pĆ­tett HTML nyelvi tĆ”mogatĆ”s ajĆ”nl-e Angular V1 elemeket Ć©s tulajdonsĆ”gokat.", "html.suggest.ionic.desc": "MeghatĆ”rozza, hogy a beĆ©pĆ­tett HTML nyelvi tĆ”mogatĆ”s ajĆ”nl-e Ionic elemeket, tulajdonsĆ”gokat Ć©s Ć©rtĆ©keket.", "html.suggest.html5.desc": "MeghatĆ”rozza, hogy a beĆ©pĆ­tett HTML nyelvi tĆ”mogatĆ”s ajĆ”nl-e HTML5-ƶs elemeket, tulajdonsĆ”gokat Ć©s Ć©rtĆ©keket.", + "html.trace.server.desc": "A VS Code Ć©s a HTML nyelvi szerver kƶzƶtti kommunikĆ”ció naplózĆ”sa.", "html.validate.scripts": "MeghatĆ”rozza, hogy a beĆ©pĆ­tett HTML nyelvi tĆ”mogatĆ”s validĆ”lja-e a beĆ”gyazott parancsafĆ”jlokat.", - "html.validate.styles": "MeghatĆ”rozza, hogy a beĆ©pĆ­tett HTML nyelvi tĆ”mogatĆ”s validĆ”lja-e a beĆ”gyazott stĆ­lusfĆ”jlokat." + "html.validate.styles": "MeghatĆ”rozza, hogy a beĆ©pĆ­tett HTML nyelvi tĆ”mogatĆ”s validĆ”lja-e a beĆ”gyazott stĆ­lusfĆ”jlokat.", + "html.autoClosingTags": "HTML-elemek automatikus lezĆ”rĆ”sĆ”nak engedĆ©lyezĆ©se vagy tetiltĆ”sa." } \ No newline at end of file diff --git a/i18n/hun/extensions/jake/out/main.i18n.json b/i18n/hun/extensions/jake/out/main.i18n.json index c73ae9cac7e..3dd479da8bb 100644 --- a/i18n/hun/extensions/jake/out/main.i18n.json +++ b/i18n/hun/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "A Jake automatikus felderĆ­tĆ©se nem sikerült a kƶvetkező hiba miatt: {0}" + "execFailed": "A Jake automatikus felderĆ­tĆ©se a(z) {0} mappĆ”hoz nem sikerült a kƶvetkező hiba miatt: {1}" } \ No newline at end of file diff --git a/i18n/hun/extensions/json/package.i18n.json b/i18n/hun/extensions/json/package.i18n.json index 9357a63ffaf..9738d213584 100644 --- a/i18n/hun/extensions/json/package.i18n.json +++ b/i18n/hun/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "Az adott URL-cĆ­m sĆ©madefinĆ­ciója. A sĆ©mĆ”t csak a sĆ©ma URL-cĆ­mĆ©hez való fƶlƶsleges lekĆ©rdezĆ©sek megakadĆ”lyozĆ”sa Ć©rdekĆ©ben kell megadni.", "json.format.enable.desc": "AlapĆ©rtelmezett JSON-formĆ”zó engedĆ©lyezĆ©se vagy letiltĆ”sa (ĆŗjraindĆ­tĆ”st igĆ©nyel)", "json.tracing.desc": "A VS Code Ć©s a JSON nyelvi szerver kƶzƶtti kommunikĆ”ció naplózĆ”sa.", - "json.colorDecorators.enable.desc": "SzĆ­ndekorĆ”torok engedĆ©lyezĆ©se vagy letiltĆ”sa" + "json.colorDecorators.enable.desc": "SzĆ­ndekorĆ”torok engedĆ©lyezĆ©se vagy letiltĆ”sa", + "json.colorDecorators.enable.deprecationMessage": "A `json.colorDecorators.enable` beĆ”llĆ­tĆ”s elavult az `editor.colorDecorators` bevezetĆ©se miatt." } \ No newline at end of file diff --git a/i18n/hun/extensions/markdown/out/extension.i18n.json b/i18n/hun/extensions/markdown/out/extension.i18n.json index 5f2c5343afb..8f10082f96b 100644 --- a/i18n/hun/extensions/markdown/out/extension.i18n.json +++ b/i18n/hun/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "A 'markdown.styles' nem tƶlthető be: {0}" + "onPreviewStyleLoadError": "A 'markdown.styles' nem tƶlthető be: {0}", + "previewTitle": "{0} előnĆ©zete" } \ No newline at end of file diff --git a/i18n/hun/extensions/markdown/out/security.i18n.json b/i18n/hun/extensions/markdown/out/security.i18n.json index cafe0123ba2..17e3cdb8d75 100644 --- a/i18n/hun/extensions/markdown/out/security.i18n.json +++ b/i18n/hun/extensions/markdown/out/security.i18n.json @@ -4,9 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.strictTitle": "SzigorĆŗ. Csak a biztonsĆ”gos tartalom tƶltődik be.", - "preview.showPreviewSecuritySelector.currentSelection": "AktuĆ”lis beĆ”llĆ­tĆ”s", - "preview.showPreviewSecuritySelector.insecureContentTitle": "Tartalom betƶltĆ©sĆ©nek engedĆ©lyezĆ©se HTTP-n keresztül.", - "preview.showPreviewSecuritySelector.scriptsAndAllContent": "Minden tartalom Ć©s parancsfĆ”jl futtatĆ”sĆ”nak engedĆ©lyezĆ©se. Nem ajĆ”nlott.", + "strict.title": "SzigorĆŗ", + "strict.description": "Csak biztonsĆ”gos tartalmak betƶltĆ©se", + "insecureContent.title": "Nem biztonsĆ”gos tartalom engedĆ©lyezĆ©se", + "insecureContent.description": "Tartalom betƶltĆ©sĆ©nek engedĆ©lyezĆ©se HTTP-n keresztül.", + "disable.title": "LetiltĆ”s", + "disable.description": "Minden tartalom Ć©s parancsfĆ”jl futtatĆ”sĆ”nak engedĆ©lyezĆ©se. Nem ajĆ”nlott.", + "moreInfo.title": "TovĆ”bbi informĆ”ció", "preview.showPreviewSecuritySelector.title": "VĆ”lassza ki a munkaterület Markdown-előnĆ©zeteinek biztonsĆ”gi beĆ”llĆ­tĆ”sĆ”t!" } \ No newline at end of file diff --git a/i18n/hun/extensions/markdown/package.i18n.json b/i18n/hun/extensions/markdown/package.i18n.json index 75c0b114f2e..beadc8533dc 100644 --- a/i18n/hun/extensions/markdown/package.i18n.json +++ b/i18n/hun/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "MeghatĆ”rozza, hogy a sortƶrĆ©sek hogyan vannak megjelenĆ­tve a markdown-előnĆ©zetben. Ha az Ć©rtĆ©ke 'true', akkor minden egyes Ćŗjsor esetĆ©n
jƶn lĆ©tre.", + "markdown.preview.linkify": "URL-szerű szƶvegek hivatkozĆ”ssĆ” alakĆ­tĆ”sĆ”nak engedĆ©lyezĆ©se vagy letiltĆ”sa a markdown-előnĆ©zetben.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Kattintson duplĆ”n a markdown-előnĆ©zetre a szerkesztőre való Ć”tvĆ”ltĆ”shoz.", "markdown.preview.fontFamily.desc": "MeghatĆ”rozza a markdown-előnĆ©zeten hasznĆ”lt betűkĆ©szletet.", "markdown.preview.fontSize.desc": "MeghatĆ”rozza a markdown-előnĆ©zet betűmĆ©retĆ©t, pixelekben.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "ElőnĆ©zet megnyitĆ”sa oldalt", "markdown.showSource.title": "ForrĆ”s megjelenĆ­tĆ©se", "markdown.styles.dec": "CSS-stĆ­luslapok URL-cĆ­meinek vagy helyi elĆ©rĆ©si Ćŗtjainak listĆ”ja, amelyek a markdown-előnĆ©zeten hasznĆ”lva vannak. A relatĆ­v elĆ©rĆ©si utak az intĆ©zőben megnyitott mappĆ”hoz kĆ©pest vannak relatĆ­van Ć©rtelmezve. Ha nincs mappa megnyitva, akkor a markdown-fĆ”jl elrĆ©sĆ©i ĆŗtjĆ”hoz kĆ©pest. Minden '\\' karaktert '\\\\' formĆ”ban kell megadni.", - "markdown.showPreviewSecuritySelector.title": "A markdown-előnĆ©zet biztonsĆ”gi beĆ”llĆ­tĆ”sainak módosĆ­tĆ”sa", - "markdown.trace.desc": "HibakeresĆ©si napló engedĆ©lyezĆ©se a markdown kiterjesztĆ©sben." + "markdown.showPreviewSecuritySelector.title": "Az előnĆ©zet biztonsĆ”gi beĆ”llĆ­tĆ”sainak módosĆ­tĆ”sa", + "markdown.trace.desc": "HibakeresĆ©si napló engedĆ©lyezĆ©se a markdown kiterjesztĆ©sben.", + "markdown.refreshPreview.title": "ElőnĆ©zet frissĆ­tĆ©se" } \ No newline at end of file diff --git a/i18n/hun/extensions/npm/out/main.i18n.json b/i18n/hun/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..3ce6ffea152 --- /dev/null +++ b/i18n/hun/extensions/npm/out/main.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "npm.parseError": "Npm-feladatok felderĆ­tĆ©se: nem sikerült beolvasni a kƶvetkező fĆ”jlt: {0}" +} \ No newline at end of file diff --git a/i18n/hun/extensions/npm/package.i18n.json b/i18n/hun/extensions/npm/package.i18n.json index 4eeff32c6d3..7903815d420 100644 --- a/i18n/hun/extensions/npm/package.i18n.json +++ b/i18n/hun/extensions/npm/package.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "config.npm.autoDetect": "MeghatĆ”rozza, hogy az npm-parancsfĆ”jlok automatikus felderĆ­tĆ”se be van-e kapcsolva. A beĆ”llĆ­tĆ”s alapĆ©rtelmezetten aktĆ­v.", - "config.npm.runSilent": "Npm parancsok futtatĆ”sa a `--silent` kapcsolóval" + "config.npm.runSilent": "Npm parancsok futtatĆ”sa a `--silent` kapcsolóval", + "npm.parseError": "Npm-feladatok felderĆ­tĆ©se: nem sikerült beolvasni a kƶvetkező fĆ”jlt: {0}" } \ No newline at end of file diff --git a/i18n/hun/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/hun/extensions/typescript/out/features/taskProvider.i18n.json index bdb20530028..baa7372a5a2 100644 --- a/i18n/hun/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/hun/extensions/typescript/out/features/taskProvider.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "buildAndWatchTscLabel": "figyelĆ©s – {0}", - "buildTscLabel": "buildelĆ©s – {0}" + "buildTscLabel": "buildelĆ©s – {0}", + "buildAndWatchTscLabel": "figyelĆ©s – {0}" } \ No newline at end of file diff --git a/i18n/hun/extensions/typescript/out/utils/api.i18n.json b/i18n/hun/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..1fdc4062874 --- /dev/null +++ b/i18n/hun/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "Ć©rvĆ©nytelen verzió" +} \ No newline at end of file diff --git a/i18n/hun/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/hun/extensions/typescript/out/utils/versionProvider.i18n.json index e7e49293c5e..62faa5fc547 100644 --- a/i18n/hun/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/hun/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "A VSCode beĆ©pĆ­tett TS-szerverĆ©t tƶrƶlte egy mĆ”sik alkalmazĆ”s, pĆ©ldĆ”ul egy hibĆ”san viselkedő vĆ­ruskereső eszkƶz. TelepĆ­tse Ćŗjra a VSCode-ot! " + "couldNotLoadTsVersion": "Nem sikerült meghatĆ”rozni a TypeScript-verziót ezen az elĆ©rĆ©si Ćŗton", + "noBundledServerFound": "A VSCode beĆ©pĆ­tett tsserverĆ©t tƶrƶlte egy mĆ”sik alkalmazĆ”s, pĆ©ldĆ”ul egy hibĆ”san viselkedő vĆ­ruskereső eszkƶz. TelepĆ­tse Ćŗjra a VSCode-ot!" } \ No newline at end of file diff --git a/i18n/hun/extensions/typescript/package.i18n.json b/i18n/hun/extensions/typescript/package.i18n.json index c840556f299..e6fbadc2798 100644 --- a/i18n/hun/extensions/typescript/package.i18n.json +++ b/i18n/hun/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "FüggvĆ©nyek kiegĆ©szĆ­tĆ©se paramĆ©terdefinĆ­ciójukkal.", "typescript.tsdk.desc": "A tsservert Ć©s a lib*.d.ts fĆ”jlokat tartalmazó mappa elĆ©rĆ©si Ćŗtja.", - "typescript.disableAutomaticTypeAcquisition": "Automatikus tĆ­pusdefinĆ­ció-letƶltĆ©s letiltĆ”sa. LegalĆ”bb 2.0.6-os TypeScriptet igĆ©nyel, Ć©s a módosĆ­tĆ”s utĆ”n ĆŗjraindĆ­tĆ”s szüksĆ©ges.", + "typescript.disableAutomaticTypeAcquisition": "Automatikus tĆ­pusdefinĆ­ció-letƶltĆ©s letiltĆ”sa. LegalĆ”bb 2.0.6-os TypeScriptet igĆ©nyel.", "typescript.tsserver.log": "EngedĆ©lyezi a TS-szerver naplózĆ”sĆ”t egy fĆ”jlba. Ez a napló a TS-szerverrel kapcsolatos problĆ©mĆ”k diagnosztizĆ”lĆ”sĆ”ra hasznĆ”lható. A napló tartalmazhat elĆ©rĆ©si utakat, forrĆ”skódot Ć©s mĆ”s potenciĆ”lisan Ć©rzĆ©keny, projekttel kapcsolatos adatot.", "typescript.tsserver.trace": "EngedĆ©lyezi a TS-szervernek küldƶtt üzenetek naplózĆ”sĆ”t. Ez a napló a TS-szerverrel kapcsolatos problĆ©mĆ”k diagnosztizĆ”lĆ”sĆ”ra hasznĆ”lható. A napló tartalmazhat elĆ©rĆ©si utakat, forrĆ”skódot Ć©s mĆ”s potenciĆ”lisan Ć©rzĆ©keny, projekttel kapcsolatos adatot. ", "typescript.validate.enable": "TypeScript-validĆ”lĆ”s engedĆ©lyezĆ©se vagy letiltĆ”sa.", @@ -44,7 +44,11 @@ "typescript.npm": "Az automatikus tĆ­pusdefinĆ­ció-letƶltĆ©shez hasznĆ”lt NPM vĆ©grehajtható fĆ”jl elĆ©rĆ©si Ćŗtja. TypeScript 2.3.4-et igĆ©nyel.", "typescript.check.npmIsInstalled": "Ellenőrizze, hogy az NPM telepĆ­tve van-e az automatikus tĆ­pusdefinĆ­ció-letƶltĆ©shez.", "javascript.nameSuggestions": "Egyedi nevek listĆ”zĆ”sĆ”nak engedĆ©lyezĆ©se a javascriptes javaslati listĆ”kban.", - "typescript.tsc.autoDetect": "MeghatĆ”rozza, hogy a tsc-feladatok automatikus felderĆ­tĆ©se be van-e kapcsolva.", + "typescript.tsc.autoDetect": "MeghatĆ”rozza a tsc-s feladatok automatikus felderĆ­tĆ©sĆ©nek műkƶdĆ©sĆ©t. 'off' Ć©rtĆ©k esetĆ©n a funkció ki van kapcsolva. 'build' esetĆ©n egyszer lefutó, fordĆ­tĆ”st vĆ©gző feladatok jƶnnek lĆ©tre. 'watch' esetĆ©n csak fordĆ­tĆ”st Ć©s figyelĆ©st vĆ©gző feladatok jƶnnek lĆ©tre. 'on' esetĆ©n buildelĆ©si Ć©s figyelĆ©si feladatok is keletkeznek. Az alapĆ©rtelmezett Ć©rtĆ©k: 'on'.", "typescript.problemMatchers.tsc.label": "TypeScript-problĆ©mĆ”k", - "typescript.problemMatchers.tscWatch.label": "TypeScript-problĆ©mĆ”k (figyelő módban)" + "typescript.problemMatchers.tscWatch.label": "TypeScript-problĆ©mĆ”k (figyelő módban)", + "typescript.quickSuggestionsForPaths": "KiegĆ©szĆ­tĆ©si javaslatok engedĆ©lyezĆ©se importĆ”lt elĆ©rĆ©si utak beĆ­rĆ”sakor.", + "typescript.locale": "MeghatĆ”rozza a TypeScript-hibĆ”k jelentĆ©sĆ©nĆ©l hasznĆ”lt lokalizĆ”ciót. TypeScript >= 2.6.0-t igĆ©nyel. Az alapĆ©rtelmezett 'null' Ć©rtĆ©k esetĆ©n a VS Code-ban beĆ”llĆ­tott nyelven jelennek meg a TypeScript-hibĆ”k.", + "javascript.implicitProjectConfig.experimentalDecorators": "Ā 'experimentalDecorators' beĆ”llĆ­tĆ”s engedĆ©lyezĆ©se azon JavaScript-fĆ”jlok esetĆ©ben, amelyek nem rĆ©szei a projektnek. A meglĆ©vő jsconfig.json vagy tsconfig.json fĆ”jlok felülĆ­rjĆ”k ezt a beĆ”llĆ­tĆ”st. TypeScript >= 2.3.1-et igĆ©nyel.", + "typescript.autoImportSuggestions.enabled": "Automatikus importĆ”lĆ”si ajĆ”nlatok engedĆ©lyezĆ©se vagy letiltĆ”sa. TypeScript >= 2.6.1-t igĆ©nyel." } \ No newline at end of file diff --git a/i18n/hun/src/vs/code/electron-main/menus.i18n.json b/i18n/hun/src/vs/code/electron-main/menus.i18n.json index 1c2baf9517c..62fae0da197 100644 --- a/i18n/hun/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/hun/src/vs/code/electron-main/menus.i18n.json @@ -102,6 +102,7 @@ "miHideActivityBar": "&&TevĆ©kenysĆ©gsĆ”v elrejtĆ©se", "miShowActivityBar": "&&TevĆ©kenysĆ©gsĆ”v megjelenĆ­tĆ©se", "miToggleWordWrap": "&&SortƶrĆ©s be- Ć©s kikapcsolĆ”sa", + "miToggleMinimap": "&&KódtĆ©rkĆ©p be- Ć©s kikapcsolĆ”sa", "miToggleRenderWhitespace": "S&&zókƶzƶk kirajzolĆ”sĆ”nak be- Ć©s kikapcsolĆ”sa", "miToggleRenderControlCharacters": "&&VezĆ©rlőkarakterek kirajzolĆ”sĆ”nak be- Ć©s kikapcsolĆ”sa", "miZoomIn": "&&NagyĆ­tĆ”s", @@ -150,6 +151,10 @@ "mZoom": "NagyĆ­tĆ”s", "mBringToFront": "Legyen az ƶsszes előtĆ©rben", "miSwitchWindow": "&&Ablak vĆ”ltĆ”sa...", + "mShowPreviousTab": "Előző fül megjelenĆ­tĆ©se", + "mShowNextTab": "Kƶvetkező fül megjelenĆ­tĆ©se", + "mMoveTabToNewWindow": "Fül Ć”tmozgatĆ”sa Ćŗj ablakba", + "mMergeAllWindows": "Ɩsszes ablak ƶsszeolvasztĆ”sa", "miToggleDevTools": "&&Fejlesztői eszkƶzƶk be- Ć©s kikapcsolĆ”sa", "miAccessibilityOptions": "&&KisegĆ­tő lehetősĆ©gek", "miReportIssues": "&&ProblĆ©mĆ”k jelentĆ©se", @@ -170,8 +175,8 @@ "miRunningTask": "&&Futó feladatok megjelenĆ­tĆ©se...", "miRestartTask": "Futó f&&eladat ĆŗjraindĆ­tĆ”sa...", "miTerminateTask": "Felada&&t megszakĆ­tĆ”sa...", - "miConfigureTask": "Feladatok &&konfigurĆ”lĆ”sa", - "miConfigureBuildTask": "AlapĆ©rtelmezett buildelĆ©si &&feladat beĆ”llĆ­tĆ”sa", + "miConfigureTask": "Feladatok &&konfigurĆ”lĆ”sa...", + "miConfigureBuildTask": "AlapĆ©rtelmezett buildelĆ©si &&feladat beĆ”llĆ­tĆ”sa...", "accessibilityOptionsWindowTitle": "KisegĆ­tő lehetősĆ©gek beĆ”llĆ­tĆ”sai", "miRestartToUpdate": "ÚjraindĆ­tĆ”s a frissĆ­tĆ©shez...", "miCheckingForUpdates": "FrissĆ­tĆ©sek keresĆ©se...", diff --git a/i18n/hun/src/vs/code/electron-main/windows.i18n.json b/i18n/hun/src/vs/code/electron-main/windows.i18n.json index 035c87c63bf..cf2d6c1723a 100644 --- a/i18n/hun/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/hun/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,24 @@ "ok": "OK", "pathNotExistTitle": "Az elĆ©rĆ©si Ćŗt nem lĆ©tezik", "pathNotExistDetail": "Úgy tűnik, hogy a(z) ā€ž{0}ā€ elĆ©rĆ©si Ćŗt mĆ”r nem lĆ©tezik a lemezen.", - "reopen": "ÚjranyitĆ”s", - "wait": "VĆ”rakozĆ”s tovĆ”bb", - "close": "BezĆ”rĆ”s", + "reopen": "MegnyitĆ”s Ćŗj&&ra", + "wait": "VĆ”rakozĆ”s &&tovĆ”bb", + "close": "&&BezĆ”rĆ”s", "appStalled": "Az ablak nem vĆ”laszol", "appStalledDetail": "BezĆ”rhatja vagy Ćŗjranyithatja az ablakot vagy vĆ”rakozhat tovĆ”bb.", "appCrashed": "Az ablak ƶsszeomlott", "appCrashedDetail": "ElnĆ©zĆ©st kĆ©rünk az okozott kellemetlensĆ©gĆ©rt. Nyissa Ćŗjra az ablakot, ha onnan szeretnĆ© folytatni a munkĆ”t, ahol abbahagyta.", + "open": "MegnyitĆ”s", + "openFolder": "Mappa megnyitĆ”sa", "openFile": "FĆ”jl megnyitĆ”sa", - "openFolder": "Mappa megnyitĆ”sa" + "workspaceOpenedMessage": "Nem sikerült menteni a(z) '{0}' munkaterületet", + "workspaceOpenedDetail": "A munkaterület mĆ”r meg van nyitva egy mĆ”sik ablakban. ZĆ”rja be azt az ablakot, majd próbĆ”lja Ćŗjra!", + "openWorkspace": "&&MegnyitĆ”s", + "openWorkspaceTitle": "Munkaterület megnyitĆ”sa", + "save": "MentĆ©&&s", + "doNotSave": "&&Ne mentse", + "cancel": "MĆ©gse", + "saveWorkspaceMessage": "SzeretnĆ© menteni a munkaterület konfigurĆ”ciójĆ”t egy fĆ”jlba?", + "saveWorkspaceDetail": "Mentse el a munkaterületet, ha meg szeretnĆ© nyitni Ćŗjra!", + "saveWorkspace": "Munkaterület mentĆ©se" } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json index 9a872bf8d12..a441d84a33a 100644 --- a/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/hun/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "MeghatĆ”rozza a sormagassĆ”got. A 0 Ć©rtĆ©k hasznĆ”lata esetĆ©n a sormagassĆ”g a fontSize Ć©rtĆ©kĆ©ből van szĆ”molva.", "letterSpacing": "MeghatĆ”rozza a betűkƶzt, pixelekben.", "lineNumbers": "MeghatĆ”rozza, hogy megjelenjenek-e a sorszĆ”mok. A lehetsĆ©ges Ć©rtĆ©kek 'on', 'off' Ć©s 'relative'. A 'relative' Ć©rtĆ©k hasznĆ”lata esetĆ©n a kurzor aktuĆ”lis pozĆ­ciójĆ”hoz kĆ©pest szĆ”mĆ­tott sorszĆ”m jelenik meg.", - "rulers": "Azon oszlopok listĆ”ja, ahol függőleges segĆ©dvonal jelenjen meg.", + "rulers": "Függőleges vonalzók kirajzolĆ”sa bizonyos szĆ”mĆŗ fix szĆ©lessĆ©gű karakter utĆ”n. Tƶbb vonalzó hasznĆ”latĆ”hoz adjon meg tƶbb Ć©rtĆ©ket. Nincs kirajzolva semmi, ha a tƶmb üres.", "wordSeparators": "Azon karakterek listĆ”ja, amelyek szóelvĆ”lasztónak vannak tekintve szavakkal kapcsolatos navigĆ”ció vagy műveletek sorĆ”n.", "tabSize": "Egy tabulĆ”tor hĆ”ny szókƶznek felel meg. Ez a beĆ”llĆ­tĆ”s felülĆ­rĆ”sra kerül a fĆ”jl tartalma alapjĆ”n, ha az 'editor.detectIndentation' beĆ”llĆ­tĆ”s aktĆ­v.", "tabSize.errorMessage": "A vĆ”rt Ć©rtĆ©k 'number' tĆ­pusĆŗ. MegjegyzĆ©s: az \"auto\" Ć©rtĆ©ket az 'editor.detectIndentation' beĆ”llĆ­tĆ”s helyettesĆ­ti.", @@ -20,8 +20,9 @@ "detectIndentation": "FĆ”jl megnyitĆ”sakor az `editor.tabSize` Ć©s az `editor.insertSpaces` Ć©rtĆ©ke a fĆ”jl tartalma alapjĆ”n lesz meghatĆ”rozva.", "roundedSelection": "Itt adható meg, hogy a kijelƶlt elemek sarkai lekerekĆ­tettek legyenek-e", "scrollBeyondLastLine": "MeghatĆ”rozza, hogy a szerkesztőablak gƶrgethető-e az utolsó sor utĆ”n.", + "smoothScrolling": "MeghatĆ”rozza, hogy a szerkesztőablak animĆ”lva van-e gƶrgetve.", "minimap.enabled": "MeghatĆ”rozza, hogy megjelenjen-e a kódtĆ©rkĆ©p.", - "minimap.showSlider": "MeghatĆ”rozza, hogy automatikusan el legyen-e rejtve a kódtĆ©rkĆ©pes gƶrgetősĆ”v.", + "minimap.showSlider": "MeghatĆ”rozza, hogy automatikusan el legyen-e rejtve a kódtĆ©rkĆ©pes gƶrgetősĆ”v. LehetsĆ©ges Ć©rtĆ©kek: 'always' Ć©s 'mouseover'.", "minimap.renderCharacters": "MeghatĆ”rozza, hogy a tĆ©nyleges karakterek legyenek-e megjelenĆ­tve (szĆ­nes tĆ©glalapok helyett)", "minimap.maxColumn": "MeghatĆ”rozza, hogy a kódtĆ©rkĆ©pen legfeljebb hĆ”ny oszlop legyen kirajzolva.", "find.seedSearchStringFromSelection": "MeghatĆ”rozza, hogy a keresĆ©s modulba automatikusan bekerüljƶn-e a szerkesztőablakban kivĆ”lasztott szƶveg.", @@ -86,6 +87,8 @@ "accessibilitySupport.off": "A szerkesztő soha nincs kĆ©pernyőolvasó hasznĆ”latĆ”ra optimalizĆ”lva.", "accessibilitySupport": "MeghatĆ”rozza, hogy a szerkesztő olyan módban fusson-e, ami optimalizĆ”lva van kĆ©pernyőolvasóval való hasznĆ”lathoz.", "links": "MeghatĆ”rozza, hogy a szerkesztőablak Ć©rzĆ©kelje-e a hivatkozĆ”sokat, Ć©s kattinthatóvĆ” tegye-e őket.", + "colorDecorators": "MeghatĆ”rozza, hogy a szerkesztőablakban ki legyenek-e rajzolva a szĆ­ndekorĆ”torok Ć©s szĆ­nvĆ”lasztók.", + "codeActions": "EngedĆ©lyezi a kódműveletek vĆ©grehajtĆ”sĆ”hoz hasznĆ”lható villanykƶrtĆ©t", "sideBySide": "MeghatĆ”rozza, hogy a differenciaszerkesztő ablakban egymĆ”s mellett vagy a sorban jelenjenek meg az eltĆ©rĆ©sek", "ignoreTrimWhitespace": "MeghatĆ”rozza, hogy a differenciaszerkesztő ablakban megjelenjenek-e a sor elejĆ©n vagy vĆ©gĆ©n a szókƶzƶkben talĆ”lt külƶnbsĆ©gek", "renderIndicators": "MeghatĆ”rozza, hogy a differenciaszerkesztő ablakban megjelenjenek-e a +/- jelzők az hozzĆ”adott/eltĆ”volĆ­tott vĆ”ltozĆ”soknĆ”l", diff --git a/i18n/hun/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/hun/src/vs/editor/common/view/editorColorRegistry.i18n.json index 313187f032a..ca5c75eaa93 100644 --- a/i18n/hun/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/hun/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "A hibĆ”kat jelző hullĆ”mvonal előtĆ©rszĆ­ne a szerkesztőablakban.", "errorBorder": "A hibĆ”kat jelző hullĆ”mvonal keretszĆ­ne a szerkesztőablakban.", "warningForeground": "A figyelmeztetĆ©seket jelző hullĆ”mvonal előtĆ©rszĆ­ne a szerkesztőablakban.", - "warningBorder": "A figyelmeztetĆ©seket jelző hullĆ”mvonal keretszĆ­ne a szerkesztőablakban." + "warningBorder": "A figyelmeztetĆ©seket jelző hullĆ”mvonal keretszĆ­ne a szerkesztőablakban.", + "infoForeground": "Az informĆ”ciókat jelző hullĆ”mvonal előtĆ©rszĆ­ne a szerkesztőablakban.", + "infoBorder": "Az informĆ”ciókat jelző hullĆ”mvonal keretszĆ­ne a szerkesztőablakban. ", + "overviewRulerRangeHighlight": "A kiemelt tartomĆ”nyokat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "overviewRuleError": "A hibĆ”kat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "overviewRuleWarning": "A figyelmeztetĆ©seket jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "overviewRuleInfo": "Az informĆ”ciókat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von." } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 2e445d0ec2e..02c1e20d0be 100644 --- a/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "Csere", "label.replaceAllButton": "Az ƶsszes előfordulĆ”s cserĆ©je", "label.toggleReplaceButton": "VĆ”ltĆ”s csere módra", - "title.matchesCountLimit": "Csak az első 999 talĆ”lat van kiemelve, de minden keresĆ©si művelet a teljes szƶveggel dolgozik.", + "title.matchesCountLimit": "Csak az első {0} talĆ”lat van kiemelve, de minden keresĆ©si művelet a teljes szƶveggel dolgozik.", "label.matchesLocation": "{0} (ƶsszesen {1})", "label.noResults": "Nincs eredmĆ©ny" } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json index b502771aa98..6e1f33bceda 100644 --- a/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Kƶvetkező kijelƶlĆ©s", "previousSelectionMatchFindAction": "Előző kijelƶlĆ©s", "startReplace": "Csere", - "addSelectionToNextFindMatch": "KijelƶlĆ©s hozzĆ”adĆ”sa a kƶvetkező keresĆ©si talĆ”lathoz", - "addSelectionToPreviousFindMatch": "KijelƶlĆ©s hozzĆ”adĆ”sa az előző keresĆ©si talĆ”lathoz", - "moveSelectionToNextFindMatch": "Utolsó kijelƶlĆ©s Ć”thelyezĆ©se a kƶvetkező keresĆ©si talĆ”latra", - "moveSelectionToPreviousFindMatch": "Utolsó kijelƶlĆ©s Ć”thelyezĆ©se az előző keresĆ©si talĆ”latra", - "selectAllOccurrencesOfFindMatch": "Az ƶsszes keresĆ©si talĆ”lat kijelƶlĆ©se", - "changeAll.label": "Minden előfordulĆ”s módosĆ­tĆ”sa", "showNextFindTermAction": "Kƶvetkező keresĆ©si kifejezĆ©s megjelenĆ­tĆ©se", "showPreviousFindTermAction": "Előző keresĆ©si kifejezĆ©s megjelenĆ­tĆ©se" } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/hun/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 6ef4ffd2eed..7b8c9186b0f 100644 --- a/i18n/hun/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "{0} formĆ”zĆ”st vĆ©gzett a(z) {1}. sorban", "hint1n": "Egy formĆ”zĆ”st vĆ©gzett a(z) {0}. Ć©s {1}. sorok kƶzƶtt", "hintnn": "{0} formĆ”zĆ”st vĆ©gzett a(z) {1}. Ć©s {2}. sorok kƶzƶtt", + "no.provider": "SajnĆ”ljuk, de nincs formĆ”zó telepĆ­tve a(z) '{0}' tĆ­pusĆŗ fĆ”jlokhoz.", "formatDocument.label": "Dokumentum formĆ”zĆ”sa", "formatSelection.label": "Kijelƶlt tartalom formĆ”zĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/hun/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index ce65a365e45..e3ec625549e 100644 --- a/i18n/hun/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "Előző hiba vagy figyelmeztetĆ©s", "editorMarkerNavigationError": "A szerkesztőablak jelzőnavigĆ”ciós moduljĆ”nak szĆ­ne hiba esetĆ©n.", "editorMarkerNavigationWarning": "A szerkesztőablak jelzőnavigĆ”ciós moduljĆ”nak szĆ­ne figyelmeztetĆ©s esetĆ©n.", + "editorMarkerNavigationInfo": "A szerkesztőablak jelzőnavigĆ”ciós moduljĆ”nak szĆ­ne informĆ”ció esetĆ©n.", "editorMarkerNavigationBackground": "A szerkesztőablak jelzőnavigĆ”ciós moduljĆ”nak hĆ”ttĆ©rszĆ­ne." } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 8aa3dbca9ff..f50dc975843 100644 --- a/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Kurzor beszĆŗrĆ”sa egy sorral feljebb", "mutlicursor.insertBelow": "Kurzor beszĆŗrĆ”sa egy sorral lejjebb", - "mutlicursor.insertAtEndOfEachLineSelected": "Kurzor beszĆŗrĆ”sa a sorok vĆ©gĆ©re" + "mutlicursor.insertAtEndOfEachLineSelected": "Kurzor beszĆŗrĆ”sa a sorok vĆ©gĆ©re", + "addSelectionToNextFindMatch": "KijelƶlĆ©s hozzĆ”adĆ”sa a kƶvetkező keresĆ©si talĆ”lathoz", + "addSelectionToPreviousFindMatch": "KijelƶlĆ©s hozzĆ”adĆ”sa az előző keresĆ©si talĆ”lathoz", + "moveSelectionToNextFindMatch": "Utolsó kijelƶlĆ©s Ć”thelyezĆ©se a kƶvetkező keresĆ©si talĆ”latra", + "moveSelectionToPreviousFindMatch": "Utolsó kijelƶlĆ©s Ć”thelyezĆ©se az előző keresĆ©si talĆ”latra", + "selectAllOccurrencesOfFindMatch": "Az ƶsszes keresĆ©si talĆ”lat kijelƶlĆ©se", + "changeAll.label": "Minden előfordulĆ”s módosĆ­tĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/hun/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..a40829f1ae6 --- /dev/null +++ b/i18n/hun/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "BezĆ”rĆ”s" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/hun/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index 6192eaea44a..fa7c3359075 100644 --- a/i18n/hun/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/hun/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Szimbólumok hĆ”ttĆ©rszĆ­ne olvasĆ”si hozzĆ”fĆ©rĆ©s, pĆ”ldĆ”ul vĆ”ltozó olvasĆ”sa esetĆ©n.", - "wordHighlightStrong": "Szimbólumok hĆ”ttĆ©rszĆ­ne Ć­rĆ”si hozzĆ”fĆ©rĆ©s, pĆ”ldĆ”ul vĆ”ltozó Ć­rĆ”sa esetĆ©n." + "wordHighlightStrong": "Szimbólumok hĆ”ttĆ©rszĆ­ne Ć­rĆ”si hozzĆ”fĆ©rĆ©s, pĆ”ldĆ”ul vĆ”ltozó Ć­rĆ”sa esetĆ©n.", + "overviewRulerWordHighlightForeground": "A kiemelt szimbólumokat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "overviewRulerWordHighlightStrongForeground": "A kiemelt, Ć­rĆ”si hozzĆ”fĆ©rĆ©sű szimbólumokat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "wordHighlight.next.label": "UgrĆ”s a kƶvetkező kiemelt szimbólumhoz", + "wordHighlight.previous.label": "UgrĆ”s az előző kiemelt szimbólumhoz" } \ No newline at end of file diff --git a/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index e935364b995..27181140f4b 100644 --- a/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "A csoport, amibe a parancs tartozik", "vscode.extension.contributes.menus": "Menüket szolgĆ”ltat a szerkesztőhƶz", "menus.commandPalette": "A parancskatalógus", + "menus.touchBar": "A Touch Bar (csak macOS-en)", "menus.editorTitle": "A szerkesztőablak cĆ­msora menüje", "menus.editorContext": "A szerkesztőablak helyi menüje", "menus.explorerContext": "A fĆ”jlkezelő helyi menüje", "menus.editorTabContext": "A szerkesztőablak füleinek helyi menüje", "menus.debugCallstackContext": "A hibakeresĆ©si hĆ­vĆ”si verem helyi menüje", - "menus.scmTitle": "A verziókezelő cĆ­msora menüje", + "menus.scmTitle": "A verziókezelő cĆ­msorĆ”nak menüje", + "menus.scmSourceControl": "A verziókezelő menüje", "menus.resourceGroupContext": "A verziókezelő erőforrĆ”scsoportja helyi menüje", "menus.resourceStateContext": "A verziókzeleő erőforrĆ”sĆ”llapot helyi menüje", "view.viewTitle": "A szolgĆ”ltatott nĆ©zet cĆ­msorĆ”nak menüje", diff --git a/i18n/hun/src/vs/platform/environment/node/argv.i18n.json b/i18n/hun/src/vs/platform/environment/node/argv.i18n.json index e6ca14e40be..bce6090ca24 100644 --- a/i18n/hun/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/hun/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "`--goto` mód esetĆ©n az argumentumokat a kƶvetkező formĆ”ban kell megadni: `FƁJL(:SOR(:OSZLOP))`.", - "diff": "Megnyit egy diffszerkesztőt. ArgumentumkĆ©nt kĆ©t fĆ”jl elĆ©rĆ©si ĆŗtjĆ”t kell Ć”tadni.", - "goto": "Megnyitja a megadott elĆ©rĆ©si Ćŗton talĆ”lható fĆ”jlt a megadott sornĆ”l Ć©s oszlopnĆ”l (a :sor[:oszlop] informĆ”ciót az elĆ©rĆ©si Ćŗt vĆ©gĆ©re kell fűzni)", + "diff": "KĆ©t fĆ”jl ƶsszehasonlĆ­tĆ”sa egymĆ”ssal.", + "add": "MappĆ”(k) hozzĆ”adĆ”sa a legutolsó aktĆ­v ablakhoz.", + "goto": "Megnyitja a megadott elĆ©rĆ©si Ćŗton talĆ”lható fĆ”jlt a megadott sornĆ”l Ć©s oszlopnĆ”l.", "locale": "A hasznĆ”lt lokalizĆ”ció (pl. en-US vagy zh-TW)", "newWindow": "MindenkĆ©pp induljon Ćŗj pĆ©ldĆ”ny a Code-ból.", "performance": "IndĆ­tĆ”s a 'Developer: Startup Performance' parancs engedĆ©lyezĆ©sĆ©vel.", @@ -14,7 +15,7 @@ "reuseWindow": "FĆ”jl vagy mappa megnyitĆ”sa a legutoljĆ”ra aktĆ­v ablakban.", "userDataDir": "MeghatĆ”rozza a kƶnyvtĆ”rat, ahol a felhasznĆ”lói adatok vannak tĆ”rolva. HasznĆ”s, ha rootkĆ©nt van futtatva.", "verbose": "RĆ©szletes kimenet kiĆ­rĆ”sa (magĆ”ba foglalja a --wait kapcsolót)", - "wait": "VĆ”rjon az ablak bezĆ”rĆ”sĆ”ra a visszatĆ©rĆ©s előtt.", + "wait": "VĆ”rjon a fĆ”jlok bezĆ”rĆ”sĆ”ra a visszatĆ©rĆ©s előtt.", "extensionHomePath": "A kiegĆ©szĆ­tők gyƶkĆ©rkƶnyvtĆ”rĆ”nak beĆ”llĆ­tĆ”sa.", "listExtensions": "TelepĆ­tett kiegĆ©szĆ­tők listĆ”zĆ”sa.", "showVersions": "TelepĆ­tett kiegĆ©szĆ­tők verziójĆ”nak megjelenĆ­tĆ©se a --list-extension kapcsoló hasznĆ”lata esetĆ©n.", diff --git a/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 9a21167685a..339d7b60e78 100644 --- a/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "A kiegĆ©szĆ­tő Ć©rvĆ©nytelen: a package.json nem egy JSON-fĆ”jl.", - "restartCode": "IndĆ­tsa Ćŗjra a Code-ot a(z) {0} ĆŗjratelepĆ­tĆ©se előtt.", - "installDependeciesConfirmation": "A(z) '{0}' teleĆ­tĆ©se sorĆ”n annak függősĆ©gei is telepĆ­tve lesznek. SzeretnĆ© folytatni?", - "install": "Igen", - "doNotInstall": "Nem", + "restartCodeLocal": "IndĆ­tsa Ćŗjra a Code-ot a(z) {0} ĆŗjratelepĆ­tĆ©se előtt.", + "restartCodeGallery": "IndĆ­tsa Ćŗjra a Code-ot az ĆŗjratelepĆ­tĆ©s előtt!", "uninstallDependeciesConfirmation": "Csak a(z) '{0}' kiegĆ©szĆ­tőt szeretnĆ© eltĆ”volĆ­tani vagy annak függősĆ©geit is?", "uninstallOnly": "Csak ezt", "uninstallAll": "Mindent", diff --git a/i18n/hun/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/hun/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index d7c85757ebd..5b5fef0ea32 100644 --- a/i18n/hun/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/hun/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "A VS Code kiegĆ©szĆ­tő aktivĆ”lĆ”si esemĆ©nyei.", "vscode.extension.activationEvents.onLanguage": "AktivĆ”ló esemĆ©ny, ami akkor fut le, ha az adott nyelvhez tĆ”rsĆ­tott fĆ”jl kerül megnyitĆ”sra.", "vscode.extension.activationEvents.onCommand": "AktivĆ”ló esemĆ©ny, ami akkor fut le, amikor a megadott parancsot meghĆ­vjĆ”k.", - "vscode.extension.activationEvents.onDebug": "AktivĆ”ló esemĆ©ny, ami akkor fut le, amikor elindul az adott tĆ­pusĆŗ hibakeresĆ©si folyamat.", + "vscode.extension.activationEvents.onDebug": "AktivĆ”ló esemĆ©ny, ami akkor fut le, ha a felhasznĆ”ló hibakeresĆ©st indĆ­t el vagy beĆ”llĆ­tani kĆ©szül a hibakeresĆ©si konfigurĆ”ciót.", "vscode.extension.activationEvents.workspaceContains": "AktivĆ”ló esemĆ©ny, ami akkor fut le, ha egy olyan mappa kerül megnyitĆ”sra, amiben legalĆ”bb egy olyan fĆ”jl van, amely illeszkedik a megadott globĆ”lis mintĆ”ra.", "vscode.extension.activationEvents.onView": "AktivĆ”ló esemĆ©ny, ami akkor fut le, amikor a megadott nĆ©zetet kiterjesztik.", "vscode.extension.activationEvents.star": "AktivĆ”ló esemĆ©ny, ami a VS Code indĆ­tĆ”sakor fut le. A jó felhasznĆ”lói Ć©lmĆ©ny Ć©rdekĆ©ben csak akkor hasznĆ”lja ezt az esemĆ©nyt, ha mĆ”s aktivĆ”ló esemĆ©nyek nem alkalmasak az adott kiegĆ©szĆ­tő esetĆ©ben.", diff --git a/i18n/hun/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/hun/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..7be8f29fde8 --- /dev/null +++ b/i18n/hun/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "KiegĆ©szĆ­tők Ć”ltal definiĆ”lt, tĆ©mĆ”zható szĆ­neket szolgĆ”ltat.", + "contributes.color.id": "A tĆ©mĆ”zható szĆ­n azonosĆ­tója.", + "contributes.color.id.format": "Az azonosĆ­tókat az aa[.bb]* formĆ”ban kell megadni.", + "contributes.color.description": "A tĆ©mĆ”zható szĆ­n leĆ­rĆ”sa.", + "contributes.defaults.light": "Az alapĆ©rtelmezett szĆ­n vilĆ”gos tĆ©mĆ”k esetĆ©n. Vagy egy szĆ­n hex formĆ”tumban (#RRGGBB[AA]) vagy egy tĆ©mĆ”zható szĆ­n azonosĆ­tója, ami meghatĆ”rozza az alapĆ©rtelmezett Ć©rtĆ©ket.", + "contributes.defaults.dark": "Az alapĆ©rtelmezett szĆ­n sƶtĆ©t tĆ©mĆ”k esetĆ©n. Vagy egy szĆ­n hex formĆ”tumban (#RRGGBB[AA]) vagy egy tĆ©mĆ”zható szĆ­n azonosĆ­tója, ami meghatĆ”rozza az alapĆ©rtelmezett Ć©rtĆ©ket.", + "contributes.defaults.highContrast": "Az alapĆ©rtelmezett szĆ­n nagy kontrasztĆŗ tĆ©mĆ”k esetĆ©n. Vagy egy szĆ­n hex formĆ”tumban (#RRGGBB[AA]) vagy egy tĆ©mĆ”zható szĆ­n azonosĆ­tója, ami meghatĆ”rozza az alapĆ©rtelmezett Ć©rtĆ©ket.", + "invalid.colorConfiguration": "a 'configuration.colors' Ć©rtĆ©kĆ©t tƶmbkĆ©nt kell megadni", + "invalid.default.colorType": "A(z) {0} Ć©rtĆ©ke egy szĆ­n hex formĆ”tumban (#RRGGBB[AA]) vagy egy tĆ©mĆ”zható szĆ­n azonosĆ­tója, ami meghatĆ”rozza az alapĆ©rtelmezett Ć©rtĆ©ket.", + "invalid.id": "A 'configuration.colors.id' Ć©rtĆ©kĆ©t meg kell adni, Ć©s nem lehet üres", + "invalid.id.format": "A 'configuration.colors.id' Ć©rtĆ©kĆ©t a word[.word]* formĆ”tumban kell megadni.", + "invalid.description": "A 'configuration.colors.description' Ć©rtĆ©kĆ©t meg kell adni, Ć©s nem lehet üres", + "invalid.defaults": "A 'configuration.colors.defaults' Ć©rtĆ©kĆ©t meg kell adni, Ć©s tartalmaznia kell 'light', 'dark' Ć©s 'highContrast' tulajdonsĆ”gokat" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json index b106cb3adab..a024837c583 100644 --- a/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/hun/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "ƉrvĆ©nytelen szĆ­nformĆ”tum. Az #RGB, #RGBA, #RRGGBB vagy #RRGGBBAA formĆ”tum hasznĆ”lható.", "schema.colors": "A munkaterületen hasznĆ”lt szĆ­nek.", "foreground": "ƁltalĆ”nos előtĆ©rszĆ­n. Csak akkor van hasznĆ”lva, ha nem Ć­rja felül az adott komponens.", "errorForeground": "A hibaüzenetek Ć”ltalĆ”nos előtĆ©rszĆ­ne. Csak akkor van hasznĆ”lva, ha nem Ć­rja felül az adott komponens.", @@ -45,6 +44,7 @@ "listHoverForeground": "A lista/fa előtĆ©rszĆ­ne, amikor az egĆ©rkurzor egy adott elem fƶlĆ© kerül.", "listDropBackground": "A lista/fa hĆ”ttĆ©rszĆ­ne, amikor az elemek az egĆ©rkurzorral vannak mozgatva egyik helyről a mĆ”sikra.", "highlight": "Kiemelt talĆ”latok előtĆ©rszĆ­ne a listĆ”ban/fĆ”ban való keresĆ©s esetĆ©n.", + "invalidItemForeground": "A lista/fa előtĆ©rszĆ­ne Ć©rvĆ©nytelen elemek esetĆ©n, pĆ©ldĆ”ul mĆ©g nem feloldott gyƶkĆ©relemek esetĆ©ben a fĆ”jlkezelőben.", "pickerGroupForeground": "CsoportcĆ­mkĆ©k szĆ­ne a gyorsvĆ”lasztóban.", "pickerGroupBorder": "Csoportok keretszĆ­ne a gyorsvĆ”lasztóban.", "buttonForeground": "A gombok előtĆ©rszĆ­ne.", @@ -85,5 +85,7 @@ "mergeBorder": "A fejlĆ©cek Ć©s az elvĆ”lasztó sĆ”v keretszĆ­ne a sorok kƶzƶtt megjelenĆ­tett ƶsszeolvasztĆ”si konfliktusok esetĆ©n.", "overviewRulerCurrentContentForeground": "A helyi tartalom előtĆ©rszĆ­ne az Ć”ttekintő sĆ”von ƶsszeolvasztĆ”si konfliktusok esetĆ©n.", "overviewRulerIncomingContentForeground": "A beĆ©rkező tartalom előtĆ©rszĆ­ne az Ć”ttekintő sĆ”von ƶsszeolvasztĆ”si konfliktusok esetĆ©n.", - "overviewRulerCommonContentForeground": "A kƶzƶs ős tartalom előtĆ©rszĆ­ne az Ć”ttekintő sĆ”von ƶsszeolvasztĆ”si konfliktusok esetĆ©n. " + "overviewRulerCommonContentForeground": "A kƶzƶs ős tartalom előtĆ©rszĆ­ne az Ć”ttekintő sĆ”von ƶsszeolvasztĆ”si konfliktusok esetĆ©n. ", + "overviewRulerFindMatchForeground": "A keresĆ©si talĆ”latokat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "overviewRulerSelectionHighlightForeground": "A kiemelt kijelƶlĆ©seket jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von." } \ No newline at end of file diff --git a/i18n/hun/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/hun/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..cfef075a083 --- /dev/null +++ b/i18n/hun/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Code-munkaterület", + "untitledWorkspace": "NĆ©vtelen (munkaterület)", + "workspaceNameVerbose": "{0} (munkaterület)", + "workspaceName": "{0} (munkaterület)" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/hun/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..3b99b32d619 --- /dev/null +++ b/i18n/hun/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "a nĆ©zeteket tƶmbkĆ©nt kell megadni", + "requirestring": "a(z) `{0}` tulajdonsĆ”g kƶtelező Ć©s `string` tĆ­pusĆŗnak kell lennie", + "optstring": "a(z) `{0}` tulajdonsĆ”g elhagyható vagy `string` tĆ­pusĆŗnak kell lennie", + "vscode.extension.contributes.view.id": "A nĆ©zet azonosĆ­tója. Ez hasznĆ”lható az adatszolgĆ”ltató regisztrĆ”lĆ”sĆ”hoz a `vscode.window.registerTreeDataProviderForView` API-n keresztül. Ezen tĆŗl a kiegĆ©szĆ­tő aktivĆ”lĆ”sĆ”hoz regisztrĆ”lni kell az `onView:${id}` esemĆ©nyt az `activationEvents`-nĆ©l.", + "vscode.extension.contributes.view.name": "A nĆ©zet emberek szĆ”mĆ”ra olvasható neve. Meg fog jelenni", + "vscode.extension.contributes.view.when": "A nĆ©zet megjelenĆ­tĆ©sĆ©nek feltĆ©tele", + "vscode.extension.contributes.views": "NĆ©zeteket szolgĆ”ltat a szerkesztőhƶz", + "views.explorer": "FĆ”jlkezelő-nĆ©zet", + "views.debug": "HibakeresĆ©si nĆ©zet", + "locationId.invalid": "A(z) `{0}` nem Ć©rvĆ©nyes nĆ©zethelyszĆ­n", + "duplicateView1": "Nem regisztrĆ”lható tƶbb nĆ©zet `{0}` azonosĆ­tóval a kƶvetkező helyen: `{1}`", + "duplicateView2": "MĆ”r van `{0}` azonosĆ­tójĆŗ nĆ©zet regisztrĆ”lva a kƶvetkező helyen: `{1}`" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/hun/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..a4e5d9f9437 --- /dev/null +++ b/i18n/hun/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "A(z) `{1}` kiegĆ©szĆ­tőt nem sikerült aktivĆ”lni. Oka: ismeretlen függősĆ©g: `{0}`.", + "failedDep1": "A(z) `{1}` kiegĆ©szĆ­tőt nem sikerült aktivĆ”lni. Oka: a(z) `{0}` függősĆ©get nem sikerült aktivĆ”lni.", + "failedDep2": "A(z) `{0}` kiegĆ©szĆ­tőt nem sikerült aktivĆ”lni. Oka: tƶbb, mint 10 szintnyi függősĆ©g van (nagy valószĆ­nűsĆ©ggel egy függősĆ©gi hurok miatt).", + "activationError": "A(z) `{0}` kiegĆ©szĆ­tő aktivĆ”lĆ”sa nem sikerült: {1}." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 4a577b24d46..586bbb9d5a1 100644 --- a/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,24 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "FĆ”jl megnyitĆ”sa...", "openFolder": "Mappa megnyitĆ”sa...", "openFileFolder": "MegnyitĆ”s...", - "reload": "Új&&ratƶltĆ©s", - "cancel": "MĆ©gse", - "newWorkspaceFormExisting": "Új munkaterület meglĆ©vőből...", - "select": "&&KivĆ”lasztĆ”s", - "selectWorkspace": "VĆ”lassza ki a munkaterület mappĆ”it!", - "addSupported": "Tƶbb mappa megnyitĆ”sĆ”hoz az ablak ĆŗjratƶltĆ©se szüksĆ©ges.", "addFolderToWorkspace": "Mappa hozzĆ”adĆ”sa a munkaterülethez...", "add": "&&HozzĆ”adĆ”s", "addFolderToWorkspaceTitle": "Mappa hozzĆ”adĆ”sa a munkaterülethez", + "globalRemoveFolderFromWorkspace": "Mappa eltĆ”volĆ­tĆ”sa a munkaterületről...", "removeFolderFromWorkspace": "Mappa eltĆ”volĆ­tĆ”sa a munkaterületről", + "openFolderSettings": "Mappa beĆ”llĆ­tĆ”sainak megnyitĆ”sa", "saveWorkspaceAsAction": "Munkaterület mentĆ©se mĆ”skĆ©nt...", - "saveEmptyWorkspaceNotSupported": "A mentĆ©shez előszƶr nyisson meg egy munkaterületet.", - "saveNotSupported": "Munkaterület mentĆ©sĆ©hez az ablak ĆŗjratƶltĆ©se szüksĆ©ges.", "save": "MentĆ©&&s", "saveWorkspace": "Munkaterület mentĆ©se", "openWorkspaceAction": "Munkaterület megnyitĆ”sa...", - "newWorkspace": "Új munkaterület...", - "openWorkspaceConfigFile": "Munkaterület konfigurĆ”ciós fĆ”jljĆ”nak megnyitĆ”sa" + "openWorkspaceConfigFile": "Munkaterület konfigurĆ”ciós fĆ”jljĆ”nak megnyitĆ”sa", + "openFolderAsWorkspaceInNewWindow": "Mappa megnyitĆ”sa munkaterületkĆ©nt egy Ćŗj ablakban", + "workspaceFolderPickerPlaceholder": "VĆ”lasszon munkaterület-mappĆ”t!" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 38f496cc0ee..21034f249a0 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "EltĆ”volĆ­tĆ”s a tevĆ©kenysĆ©gsĆ”vról", - "keepInActivityBar": "MegtartĆ”s a tevĆ©kenysĆ©gsĆ”von", + "badgeTitle": "{0} – {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "ElrejtĆ©s a tevĆ©kenysĆ©gsĆ”vról", + "keepInActivityBar": "MegtartĆ”s a tevĆ©kenysĆ©gsĆ”von", "additionalViews": "TovĆ”bbi nĆ©zetek", "numberBadge": "{0} ({1})", "manageExtension": "KiegĆ©szĆ­tő kezelĆ©se", diff --git a/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 266ac56433e..3c81d54bd07 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "TevĆ©kenysĆ©gsĆ”v elrejtĆ©se", - "activityBarAriaLabel": "Az aktĆ­v nĆ©zet vĆ”ltĆ”sa", "globalActions": "GlobĆ”lis műveletek" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..4fe5826df65 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "Az aktĆ­v nĆ©zet vĆ”ltĆ”sa" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..215e7d12e87 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} – {1}", + "additionalViews": "TovĆ”bbi nĆ©zetek", + "numberBadge": "{0} ({1})", + "manageExtension": "KiegĆ©szĆ­tő kezelĆ©se", + "titleKeybinding": "{0} ({1})", + "hide": "ElrejtĆ©s", + "keep": "MegtartĆ”s", + "toggle": "NĆ©zet rƶgzĆ­tĆ©sĆ©nek be- Ć©s kikapcsolĆ”sa" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 186c2e66b64..05a3be82161 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "A mĆ”sodik csoportban talĆ”lható szerkesztőablakok megjelenĆ­tĆ©se", "groupThreePicker": "A harmadik csoportban talĆ”lható szerkesztőablakok megjelenĆ­tĆ©se", "allEditorsPicker": "Ɩsszes megnyitott szerkesztőablak megjelenĆ­tĆ©se", - "view": "NĆ©zet" + "view": "NĆ©zet", + "file": "FĆ”jl" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index a7c8a9b8eeb..505c556c227 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "A csoport előző szerkesztőablakĆ”nak megnyitĆ”sa", "navigateNext": "UgrĆ”s előre", "navigatePrevious": "UgrĆ”s vissza", + "navigateLast": "UgrĆ”s az utolsóra", "reopenClosedEditor": "BezĆ”rt szerkesztőablak ĆŗjranyitĆ”sa", "clearRecentFiles": "Legutóbb megnyitottak listĆ”jĆ”nak ürĆ­tĆ©se", "showEditorsInFirstGroup": "Az első csoportban talĆ”lható szerkesztőablakok megjelenĆ­tĆ©se", diff --git a/i18n/hun/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index cf37b615cda..7f3902b99cf 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "Tab fókuszt vĆ”lt", - "screenReaderDetected": "KĆ©pernyőolvasó Ć©rzĆ©kelve", + "screenReaderDetected": "KĆ©pernyőolvasóra optimalizĆ”lva", "screenReaderDetectedExtra": "Ha nem hasznĆ”l kĆ©pernyőolvasót, Ć”llĆ­tsa az `editor.accessibilitySupport` Ć©rtĆ©kĆ©t \"off\"-ra.", "disableTabMode": "KisegĆ­tő mód letiltĆ”sa", "gotoLine": "Sor megkeresĆ©se", @@ -47,5 +47,11 @@ "reopenWithEncoding": "ÚjranyitĆ”s adott kódolĆ”ssal", "guessedEncoding": "KitalĆ”lva a tartalomból", "pickEncodingForReopen": "VĆ”lassza ki a kódolĆ”st a fĆ”jl ĆŗjranyitĆ”sĆ”hoz", - "pickEncodingForSave": "VĆ”lassza ki a mentĆ©shez hasznĆ”landó kódolĆ”st" + "pickEncodingForSave": "VĆ”lassza ki a mentĆ©shez hasznĆ”landó kódolĆ”st", + "screenReaderDetectedExplanation.title": "KĆ©pernyőolvasóra optimalizĆ”lva", + "screenReaderDetectedExplanation.question": "KĆ©pernyőolvasót hasznĆ”l a VS Code vezĆ©rlĆ©sĆ©hez?", + "screenReaderDetectedExplanation.answerYes": "Igen", + "screenReaderDetectedExplanation.answerNo": "Nem", + "screenReaderDetectedExplanation.body1": "A VS Code most mĆ”r optimalizĆ”lva van kĆ©pernyőolvasóval való hasznĆ”lathoz.", + "screenReaderDetectedExplanation.body2": "NĆ©hĆ”ny funkció mĆ”skĆ©pp műkƶdik. PĆ©ldĆ”ul a sortƶrĆ©s, kódrĆ©szletek bezĆ”rĆ”sa, automatikus zĆ”ró zĆ”rójelek beszĆŗrĆ”sa stb." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 79a37ed7da4..572b8317269 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Panel bezĆ”rĆ”sa", "togglePanel": "Panel be- Ć©s kikapcsolĆ”sa", "focusPanel": "VĆ”ltĆ”s a panelra", + "toggledPanelPosition": "Panel helyzetĆ©nek vĆ”ltĆ”sa", + "moveToRight": "ƁthelyezĆ©s jobbra", + "moveToBottom": "ƁthelyezĆ©s lentre", "toggleMaximizedPanel": "Teljes mĆ©retű panel be- Ć©s kikapcsolĆ”sa", "maximizePanel": "Panel teljes mĆ©retűvĆ© tĆ©tele", "minimizePanel": "Panel mĆ©retĆ©nek visszaĆ”llĆ­tĆ”sa", diff --git a/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 3cc19480b62..dfd63a785b3 100644 --- a/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "A(z) '{0}' parancs jelenleg nem engedĆ©lyezett Ć©s nem futtatható.", "manageExtension": "KiegĆ©szĆ­tő kezelĆ©se" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..30ba124e291 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} művelet" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..f00a5e742b6 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} művelet", + "hideView": "ElrejtĆ©s az oldalsĆ”vról" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..52cc050953f --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "MĆ”r van `{0}` azonosĆ­tójĆŗ nĆ©zet regisztrĆ”lva a kƶvetkező helyen: `{1}`" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..b21a79bc546 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "ElrejtĆ©s az oldalsĆ”vról" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/common/theme.i18n.json b/i18n/hun/src/vs/workbench/common/theme.i18n.json index e127840392f..b30bec0d245 100644 --- a/i18n/hun/src/vs/workbench/common/theme.i18n.json +++ b/i18n/hun/src/vs/workbench/common/theme.i18n.json @@ -4,27 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "tabActiveBackground": "Az aktĆ­v fül hĆ”ttĆ©rszĆ­ne. A fülek tartalmazzĆ”k a szerkesztőablakoket a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", - "tabInactiveBackground": "Az inaktĆ­v fülek hĆ”ttĆ©rszĆ­ne. A fülek tartalmazzĆ”k a szerkesztőablakoket a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", - "tabBorder": "A füleket egymĆ”stól elvĆ”lasztó keret szĆ­ne. A fülek tartalmazzĆ”k a szerkesztőablakoket a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", - "tabActiveForeground": "Az aktĆ­v fül előtĆ©rszĆ­ne az aktĆ­v csoportban. A fülek tartalmazzĆ”k a szerkesztőablakoket a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", - "tabInactiveForeground": "Az inaktĆ­v fülek előtĆ©rszĆ­ne az aktĆ­v csoportban. A fülek tartalmazzĆ”k a szerkesztőablakoket a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", - "tabUnfocusedActiveForeground": "Az aktĆ­v fül előtĆ©rszĆ­ne az inaktĆ­v csoportokban. A fülek tartalmazzĆ”k a szerkesztőablakoket a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", - "tabUnfocusedInactiveForeground": "Az inaktĆ­v fülek előtĆ©rszĆ­ne inaktĆ­v csoportokban. A fülek tartalmazzĆ”k a szerkesztőablakoket a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabActiveBackground": "Az aktĆ­v fül hĆ”ttĆ©rszĆ­ne. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabInactiveBackground": "Az inaktĆ­v fülek hĆ”ttĆ©rszĆ­ne. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabBorder": "A füleket egymĆ”stól elvĆ”lasztó keret szĆ­ne. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabActiveBorder": "Az aktĆ­v fülek kiemelĆ©sĆ©re hasznĆ”lt keretszĆ­n. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabActiveUnfocusedBorder": "Az aktĆ­v fülek kiemelĆ©sĆ©re hasznĆ”lt keretszĆ­n egy fókusz nĆ©lküli csoportban. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni. ", + "tabActiveForeground": "Az aktĆ­v fül előtĆ©rszĆ­ne az aktĆ­v csoportban. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabInactiveForeground": "Az inaktĆ­v fülek előtĆ©rszĆ­ne az aktĆ­v csoportban. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabUnfocusedActiveForeground": "Az aktĆ­v fül előtĆ©rszĆ­ne egy fókusz nĆ©lküli csoportban. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", + "tabUnfocusedInactiveForeground": "Az inaktĆ­v fülek előtĆ©rszĆ­ne egy fókusz nĆ©lküli csoportban. A fülek tartalmazzĆ”k a szerkesztőablakokat a szerkesztőterületen. Egy szerkesztőablak-csoportban tƶbb fül is megnyitható. Tƶbb szerkesztőablak-csoportot is lĆ©tre lehet hozni.", "editorGroupBackground": "A szerkesztőcsoportok hĆ”ttĆ©rszĆ­ne. A szerkesztőcsoportok szerkesztőablakokat tartalmaznak. A hĆ”ttĆ©rszĆ­n akkor jelenik meg, ha a szerkesztőcsoportok mozgatva vannak.", "tabsContainerBackground": "A szerkesztőcsoport cĆ­msorĆ”nak hĆ”ttĆ©rszĆ­ne, ha a fülek engedĆ©lyezve vannak. A szerkesztőcsoportok szerkesztőablakokat tartalmaznak.", "tabsContainerBorder": "A szerkesztőcsoport cĆ­msorĆ”nak keretszĆ­ne, ha a fülek engedĆ©lyezve vannak. A szerkesztőcsoportok szerkesztőablakokat tartalmaznak.", "editorGroupHeaderBackground": "A szerkesztőcsoport cĆ­msorĆ”nak keretszĆ­ne, ha a fülek le vannak tiltva. A szerkesztőcsoportok szerkesztőablakokat tartalmaznak.", "editorGroupBorder": "A szerkesztőcsoportokat elvĆ”lasztó vonal szĆ­ne. A szerkesztőcsoportok szerkesztőablakokat tartalmaznak.", "editorDragAndDropBackground": "A szerkesztőablakok mozgatĆ”sĆ”nĆ”l hasznĆ”lt hĆ”ttĆ©rszĆ­n. Ɖrdemes Ć”tlĆ”tszó szĆ­nt vĆ”lasztani, hogy a szerkesztőablak tartalma tovĆ”bbra is lĆ”tszódjon.", - "panelBackground": "A panelek hĆ”ttĆ©rszĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenetet Ć©s az integrĆ”lt terminĆ”l.", + "panelBackground": "A panelek hĆ”ttĆ©rszĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenet Ć©s az integrĆ”lt terminĆ”l.", "panelBorder": "A panelek keretszĆ­ne, ami elvĆ”lasztja őket a szerkesztőablakoktól. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenetet Ć©s az integrĆ”lt terminĆ”l.", - "panelActiveTitleForeground": "Az aktĆ­v panel cĆ­msorĆ”nak szĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenetet Ć©s az integrĆ”lt terminĆ”l.", - "panelInactiveTitleForeground": "Az inaktĆ­v panelek cĆ­msorĆ”nak szĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenetet Ć©s az integrĆ”lt terminĆ”l.", - "panelActiveTitleBorder": "Az aktĆ­v panel cĆ­msorĆ”nak keretszĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenetet Ć©s az integrĆ”lt terminĆ”l.", - "statusBarForeground": "Az Ć”llapotsor előtĆ©rszĆ­ne. Az Ć”llapotsor az ablak aljĆ”n jelenik meg.", + "panelActiveTitleForeground": "Az aktĆ­v panel cĆ­msorĆ”nak szĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenet Ć©s az integrĆ”lt terminĆ”l.", + "panelInactiveTitleForeground": "Az inaktĆ­v panelek cĆ­msorĆ”nak szĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenet Ć©s az integrĆ”lt terminĆ”l.", + "panelActiveTitleBorder": "Az aktĆ­v panel cĆ­msorĆ”nak keretszĆ­ne. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenet Ć©s az integrĆ”lt terminĆ”l.", + "panelDragAndDropBackground": "A panel cĆ­msorĆ”ban talĆ”lható elemek mozgatĆ”sĆ”nĆ”l hasznĆ”lt visszajelzĆ©si szĆ­n. Ɖrdemes Ć”tlĆ”tszó szĆ­nt vĆ”lasztani, hogy a panel elemei lĆ”thatóak maradjanak. A panelek a szerkesztőterület alatt jelennek meg, Ć©s pl. itt talĆ”lható a kimenet Ć©s az integrĆ”lt terminĆ”l.", + "statusBarForeground": "Az Ć”llapotsor előtĆ©rszĆ­ne, ha egy munkaterület van megnyitva. Az Ć”llapotsor az ablak aljĆ”n jelenik meg.", "statusBarNoFolderForeground": "Az Ć”llapotsor előtĆ©rszĆ­ne, ha nincs mappa megnyitva. Az Ć”llapotsor az ablak aljĆ”n jelenik meg.", - "statusBarBackground": "Az Ć”llapotsor alapĆ©rtelmezett hĆ”ttĆ©rszĆ­ne. Az Ć”llapotsor az ablak aljĆ”n jelenik meg.", + "statusBarBackground": "Az Ć”llapotsor hĆ”ttĆ©rszĆ­ne, ha egy munkaterület van megnyitva. Az Ć”llapotsor az ablak aljĆ”n jelenik meg.", "statusBarNoFolderBackground": "Az Ć”llapotsor hĆ”ttĆ©rszĆ­ne, ha nincs mappa megnyitva. Az Ć”llapotsor az ablak aljĆ”n jelenik meg.", "statusBarBorder": "Az Ć”llapotsort az oldalsĆ”vtól Ć©s a szerkesztőablakoktól elvĆ”lasztó keret szĆ­ne. Az Ć”llapotsor az ablak aljĆ”n jelenik meg.", "statusBarNoFolderBorder": "Az Ć”llapotsort az oldalsĆ”vtól Ć©s a szerkesztőablakoktól elvĆ”lasztó keret szĆ­ne, ha nincs mappa megnyitva. Az Ć”llapotsor az ablak aljĆ”n jelenik meg. ", diff --git a/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json index 07e209f9fa9..b81dfc62fd3 100644 --- a/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/hun/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "NavigĆ”lĆ”s a felül lĆ©vő nĆ©zetre", "navigateDown": "NavigĆ”lĆ”s az alul lĆ©vő nĆ©zetre", "increaseViewSize": "Jelenlegi nĆ©zet mĆ©retĆ©nek nƶvelĆ©se", - "decreaseViewSize": "Jelenlegi nĆ©zet mĆ©retĆ©nek csƶkkentĆ©se" + "decreaseViewSize": "Jelenlegi nĆ©zet mĆ©retĆ©nek csƶkkentĆ©se", + "showPreviousTab": "Előző ablakfül megjelenĆ­tĆ©se", + "showNextWindowTab": "Kƶvetkező ablakfül megjelenĆ­tĆ©se", + "moveWindowTabToNewWindow": "Ablakfül Ć”tmozgatĆ”sa Ćŗj ablakba", + "mergeAllWindowTabs": "Ɩsszes ablak ƶsszeolvasztĆ”sa", + "toggleWindowTabsBar": "AblakfülsĆ”v be- Ć©s kikapcsolĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/hun/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..deafef14508 --- /dev/null +++ b/i18n/hun/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "Nyelv beĆ”llĆ­tĆ”sa", + "displayLanguage": "MeghatĆ”rozza a VSCode felületĆ©nek nyelvĆ©t.", + "doc": "Az elĆ©rhető nyelvek listĆ”ja a kƶvetkező cĆ­men tekinthető meg: {0}", + "restart": "Az Ć©rtĆ©k módosĆ­tĆ”sa utĆ”n Ćŗjra kell indĆ­tani a VSCode-ot.", + "fail.createSettings": "Nem sikerült a(z) '{0}' lĆ©trehozĆ”s ({1}).", + "JsonSchema.locale": "A felhasznĆ”lói felületen hasznĆ”lt nyelv." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json index 12a7eedd3e9..471b064ae29 100644 --- a/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,17 +10,25 @@ "workspaces": "Munkaterületek", "developer": "Fejlesztői", "showEditorTabs": "MeghatĆ”rozza, hogy a megnyitott szerkesztőablakok telejĆ©n megjelenjenek-e a fülek", + "workbench.editor.labelFormat.default": "FĆ”jl nevĆ©nek megjelenĆ­tĆ©se. Ha a fülek engedĆ©lyezve vannak, Ć©s kĆ©t egyező nevű fĆ”jl van egy csoportban, az elĆ©rĆ©si Ćŗtjuk eltĆ©rő rĆ©sze lesz hozzĆ”fűzve a nĆ©vhez. Ha a fülek le vannak tiltva, a fĆ”jl munkaterület kƶnyvtĆ”rĆ”hoz kĆ©pest relatĆ­v elĆ©rĆ©si Ćŗtja jelenik meg, ha a szerkesztőablak aktĆ­v.", + "workbench.editor.labelFormat.short": "A fĆ”jl nevĆ©nek megjelenĆ­tĆ©se a kƶnyvtĆ”r nevĆ©vel együtt.", + "workbench.editor.labelFormat.medium": "FĆ”jl nevĆ©nek megjelenĆ­tĆ©se a fĆ”jl munkaterület kƶnyvtĆ”rĆ”hoz kĆ©pest relatĆ­v elĆ©rĆ©si ĆŗtjĆ”val együtt.", + "workbench.editor.labelFormat.long": "FĆ”jl nevĆ©nek megjelenĆ­tĆ©se a fĆ”jl abszolĆŗt elĆ©rĆ©si ĆŗtjĆ”val együtt.", + "tabDescription": "MeghatĆ”rozza a szerkesztőablakok cĆ­mkĆ©je formĆ”jĆ”t. A beĆ”llĆ­tĆ”s módosĆ­tĆ”sa kƶnnyebbĆ© teheti a fĆ”jl helyĆ©nek kiderĆ­tĆ©sĆ©t:\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', ha egy mĆ”sik fülnek ugyanaz a cĆ­me, vagy a relatĆ­v elĆ©rĆ©si Ćŗt, ha a fülek le vannak tiltva", "editorTabCloseButton": "MeghatĆ”rozza a szerkesztőablakok fülein talĆ”lható bezĆ”rógomb pozĆ­ciójĆ”t vagy eltĆ”volĆ­tja őket, ha a beĆ”llĆ­tĆ”s Ć©rtĆ©ke 'off'.", "showIcons": "MeghatĆ”rozza, hogy a megnyitott szerkesztőablakok ikonnal együtt jelenjenek-e meg. A műkƶdĆ©shez szüksĆ©ges egy ikontĆ©ma engedĆ©lyezĆ©se is.", - "enablePreview": "MeghatĆ”rozza, hogy a megnyitott szerkesztőablakok előnĆ©zetkĆ©nt jelenjenek-e meg. Az előnĆ©zetkĆ©nt hasznĆ”lt szerkesztőablakok Ćŗjra vannak hasznosĆ­tva, amĆ­g meg nem tartja őket a felhasznĆ”ló (pl. dupla kattintĆ”s vagy szerkesztĆ©s esetĆ©n).", + "enablePreview": "MeghatĆ”rozza, hogy a megnyitott szerkesztőablakok előnĆ©zetkĆ©nt jelenjenek-e meg. Az előnĆ©zetkĆ©nt hasznĆ”lt szerkesztőablakok Ćŗjra vannak hasznosĆ­tva, amĆ­g meg nem tartja őket a felhasznĆ”ló (pl. dupla kattintĆ”s vagy szerkesztĆ©s esetĆ©n), Ć©s dőlt betűvel jelenik meg a cĆ­msoruk.", "enablePreviewFromQuickOpen": "MeghatĆ”rozza, hogy a gyors megnyitĆ”s sorĆ”n megnyitott szerkesztőablakok előnĆ©zetkĆ©nt jelenjenek-e meg. Az előnĆ©zetkĆ©nt hasznĆ”lt szerkesztőablakok Ćŗjra vannak hasznosĆ­tva, amĆ­g meg nem tartja őket a felhasznĆ”ló (pl. dupla kattintĆ”s vagy szerkesztĆ©s esetĆ©n).", - "editorOpenPositioning": "MeghatĆ”rozza, hogy hol nyĆ­ljanak meg a szerkesztőablakok. A 'left' vagy 'right' hasznĆ”lata esetĆ©n az aktĆ­v szerkesztőablaktól jobbra vagy balra nyĆ­lnak meg az Ćŗjak. A 'first' vagy 'last' esetĆ©n a szerkesztőablakok a jelenleg aktĆ­v ablaktól függetlenül nyĆ­lnak meg.", + "editorOpenPositioning": "MeghatĆ”rozza, hogy hol nyĆ­ljanak meg a szerkesztőablakok. A 'left' vagy 'right' hasznĆ”lata esetĆ©n az aktĆ­v szerkesztőablaktól jobbra vagy balra nyĆ­lnak meg az Ćŗjak. 'first' vagy 'last' esetĆ©n a szerkesztőablakok a jelenleg aktĆ­v ablaktól függetlenül nyĆ­lnak meg.", "revealIfOpen": "MeghatĆ”rozza, hogy egy szerkesztőablak fel legyen-e fedve, ha mĆ”r meg van nyitva a lĆ”tható csoportok bĆ”rmelyikĆ©pben. Ha le van tiltva, akkor egy Ćŗj szerkesztőablak nyĆ­lik az aktĆ­v szerkesztőablak-csoportban. Ha engedĆ©lyezve van, akkor a mĆ”r megnyitott szerkesztőablak lesz felfedve egy Ćŗj megnyitĆ”sa helyett. MegjegyzĆ©s: vannak esetek, amikor ez a beĆ”llĆ­tĆ”s figyelmen kĆ­vül van hagyva, pl. ha egy adott szerkesztőablak egy konkrĆ©t csoportban vagy a jelenleg aktĆ­v csoport mellett van menyitva.", - "commandHistory": "MeghatĆ”rozza, hogy mennyi legutóbb hasznĆ”lt parancs jelenjen meg a parancskatalógus előzmĆ©nyeinek listĆ”jĆ”ban. Az előzmĆ©nyek kikapcsolĆ”sĆ”hoz Ć”llĆ­tsa az Ć©rtĆ©ket 0-ra.", + "commandHistory": "MeghatĆ”rozza, hogy hĆ”ny legutóbb hasznĆ”lt parancs jelenjen meg a parancskatalógus előzmĆ©nyeinek listĆ”jĆ”ban. Az előzmĆ©nyek kikapcsolĆ”sĆ”hoz Ć”llĆ­tsa az Ć©rtĆ©ket nullĆ”ra.", "preserveInput": "MeghatĆ”rozza, hogy a legutóbb beĆ­rt parancs automatikusan helyre legyen-e Ć”llĆ­tva a parancskatalógus kƶvetkező megnyitĆ”sa sorĆ”n.", "closeOnFocusLost": "MeghatĆ”rozza, hogy a gyors megnyitĆ”s automatikusan bezĆ”ródjon-e amint elveszĆ­ti a fókuszt.", "openDefaultSettings": "MeghatĆ”rozza, hogy a beĆ”llĆ­tĆ”sok megnyitĆ”sakor megnyĆ­ljon-e egy szerkesztő az ƶsszes alapĆ©rtelmezett beĆ”llĆ­tĆ”ssal.", + "experimentalFuzzySearchEndpoint": "MeghatĆ”rozza a kĆ­sĆ©rleti beĆ”llĆ­tĆ”skeresőben hasznĆ”lt vĆ©gpontot.", + "experimentalFuzzySearchKey": "MeghatĆ”rozza a kĆ­sĆ©rleti beĆ”llĆ­tĆ”skeresőben hasznĆ”lt kulcsot.", "sideBarLocation": "MeghatĆ”rozza az oldalsĆ”v helyĆ©t. Az oldalsĆ”v megjelenhet a munkaterület bal vagy jobb oldalĆ”n.", + "panelLocation": "MeghatĆ”rozza a panel pozĆ­ciójĆ”t. Megjelenhet a munkaterület aljĆ”n vagy jobb oldalon.", "statusBarVisibility": "MeghatĆ”rozza, hogy megjelenjen-e az Ć”llapotsor a munkaterület aljĆ”n.", "activityBarVisibility": "MeghatĆ”rozza, hogy megjelenjen-e a tevĆ©kenysĆ©gsĆ”v a munkaterületen.", "closeOnFileDelete": "MeghatĆ”rozza, hogy bezĆ”ródjanak-e azok a szerkesztőablakok, melyekben olyan fĆ”jl van megnyitva, amelyet tƶrƶl vagy Ć”tnevez egy mĆ”sik folyamat. A beĆ”llĆ­tĆ”s letiltĆ”sa esetĆ©n a szerkesztőablak nyitva marad módosĆ­tott Ć”llapotban ilyen esemĆ©ny utĆ”n. MegjegyzĆ©s: az alkalmazĆ”son belüli tƶrlĆ©sek esetĆ©n mindig bezĆ”ródik a szerkesztőablakok, a módosĆ­tott fĆ”jlok pedig soha nem zĆ”ródnak be, hogy az adatok megmaradjanak.", @@ -45,7 +53,7 @@ "restoreWindows": "MeghatĆ”rozza, hogy ĆŗjraindĆ­tĆ”s utĆ”n hogyan vannak ismĆ©t megnyitva az ablakok. A 'none' vĆ”lasztĆ”sa esetĆ©n mindig üres munkaterület indul, 'one' esetĆ©n a legutóbb hasznĆ”lt ablak nyĆ­lik meg Ćŗjra, a 'folders' megnyitja az ƶsszes megnyitott mappĆ”t, mĆ­g az 'all' Ćŗjranyitja az ƶsszes ablakot az előző munkamenetből.", "restoreFullscreen": "MeghatĆ”rozza, hogy az ablak teljeskĆ©pernyős módban nyĆ­ljon-e meg, ha kilĆ©pĆ©skor teljes kĆ©pernyős módban volt.", "zoomLevel": "MeghatĆ”rozza az ablak nagyĆ­tĆ”si szintjĆ©t. Az eredei mĆ©ret 0, Ć©s minden egyes plusz (pl. 1) vagy mĆ­nusz (pl. -1) 20%-kal nagyobb vagy kisebb nagyĆ­tĆ”si szintet jelent. Tizedestƶrt megadĆ”sa esetĆ©n a nagyĆ­tĆ”si szint finomabban Ć”llĆ­tható.", - "title": "MeghatĆ”rozza az ablak cĆ­mĆ©t az aktĆ­v szerkesztőablak alapjĆ”n. A vĆ”ltozók a kƶrnyezet alapjĆ”n vannak behelyettesĆ­tve:\n${activeEditorShort}: pl. myFile.txt\n${activeEditorMedium}: pl. myFolder/myFile.txt\n${activeEditorLong}: pl. /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: pl. myFolder\n${folderPath}: pl. /Users/Development/myFolder\n${rootName}: pl. myFolder1, myFolder2, myFolder3\n${rootPath}: pl. /Users/Development/myWorkspace\n${appName}: pl. VS Code\n${dirty}: módosĆ­tĆ”sjelző, ami jelzi, ha az aktĆ­v szerkesztőablak tartalma módosĆ­tva lett\n${separator}: feltĆ©teles elvĆ”lasztó (\" - \"), ami akkor jelenik meg, ha olyan vĆ”ltozókkal van kƶrülvĆ©ve, amelyeknek van Ć©rtĆ©ke\n", + "title": "MeghatĆ”rozza az ablak cĆ­mĆ©t az aktĆ­v szerkesztőablak alapjĆ”n. A vĆ”ltozók a kƶrnyezet alapjĆ”n vannak behelyettesĆ­tve:\n${activeEditorShort}: a fĆ”jl neve (pl. myFile.txt)\n${activeEditorMedium}: a fĆ”jl relatĆ­v elĆ©rĆ©si Ćŗtja a munkaterület mappĆ”jĆ”hoz kĆ©pest (pl. myFolder/myFile.txt)\n${activeEditorLong}: a fĆ”jl teljes elĆ©rĆ©si Ćŗtja (pl. /Users/Development/myProject/myFolder/myFile.txt)\n${folderName}: azon munkaterületi mappa a neve, amelyben a fĆ”jl talĆ”lható (pl. myFolder)\n${folderPath}: azon munkaterületi mappa elĆ©rĆ©si Ćŗtja, amelyben a fĆ”jl talĆ”lható (pl. /Users/Development/myFolder)\n${rootName}: a munkaterület neve (pl. myFolder vagy myWorkspace)\n${rootPath}: a munkaterület elĆ©rĆ©si Ćŗtja (pl. /Users/Development/myWorkspace)\n${appName}: pl. VS Code\n${dirty}: módosĆ­tĆ”sjelző, ami jelzi, ha az aktĆ­v szerkesztőablak tartalma módosĆ­tva lett\n${separator}: feltĆ©teles elvĆ”lasztó (\" - \"), ami akkor jelenik meg, ha olyan vĆ”ltozókkal van kƶrülvĆ©ve, amelyeknek van Ć©rtĆ©ke", "window.newWindowDimensions.default": "Az Ćŗj ablakok a kĆ©pernyő kƶzepĆ©n nyĆ­lnak meg.", "window.newWindowDimensions.inherit": "Az Ćŗj ablakok ugyanolyan mĆ©retben Ć©s ugyanazon a helyen jelennek meg, mint a legutoljĆ”ra aktĆ­v ablak.", "window.newWindowDimensions.maximized": "Az Ćŗj ablakok teljes mĆ©retben nyĆ­lnak meg.", diff --git a/i18n/hun/src/vs/workbench/electron-browser/window.i18n.json b/i18n/hun/src/vs/workbench/electron-browser/window.i18n.json index 345a003f2e5..3f8ae5cf9dd 100644 --- a/i18n/hun/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/hun/src/vs/workbench/electron-browser/window.i18n.json @@ -9,7 +9,5 @@ "cut": "KivĆ”gĆ”s", "copy": "MĆ”solĆ”s", "paste": "BeillesztĆ©s", - "selectAll": "Ɩsszes kijelƶlĆ©se", - "confirmOpen": "Biztosan meg szeretne nyitni {0} munkaterületet?", - "confirmOpenButton": "&&MegnyitĆ”s" + "selectAll": "Ɩsszes kijelƶlĆ©se" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 92cdf300946..96fdaf66ac8 100644 --- a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Ha egy sor illeszkedik erre a mintĆ”ra, akkor az indentĆ”lĆ”sa nem vĆ”ltozik, Ć©s nem lesz kiĆ©rtĆ©kelve mĆ”s szabĆ”lyok alapjĆ”n.", "schema.indentationRules.unIndentedLinePattern.pattern": "Az unIndentedLinePatternhƶz tartozó regulĆ”ris kifejezĆ©s.", "schema.indentationRules.unIndentedLinePattern.flags": "Az unIndentedLinePatternhƶz tartozó regulĆ”ris kifejezĆ©s beĆ”llĆ­tĆ”sai.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Illeszkednie kell a kƶvetkező mintĆ”ra: `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Illeszkednie kell a kƶvetkező mintĆ”ra: `/^([gimuy]+)$/`.", + "schema.folding": "A nyelv kódrĆ©szek bezĆ”rĆ”sĆ”val kapcsolatos beĆ”llĆ­tĆ”sai.", + "schema.folding.offSide": "Egy nyelv kƶveti az ā€žoff-sideā€-szabĆ”lyt, ha a blokkokat az adott nyelvben az indentĆ”ciójuk fejezi ki. Ha be van Ć”llĆ­tva, akkor az üres sorok a rĆ”kƶvetkező blokkhoz tartoznak.", + "schema.folding.markers": "Nyelvspecifikus, becsukható kódrĆ©szleteket hatĆ”roló kifejezĆ©sek. PĆ©ldĆ”ul: '#region' Ć©s '#endregion'. A kezdő Ć©s zĆ”ró regulĆ”ris kifejezĆ©sek az ƶsszes soron tesztelve vannak, Ć­gy hatĆ©konyan kell őket megtervezni.", + "schema.folding.markers.start": "A kezdő hatĆ”rjelzőt leĆ­ró regulĆ”ris kifejezĆ©s. A regulĆ”ris kifejezĆ©snek '^' karakterrel kell kezdődnie.", + "schema.folding.markers.end": "A zĆ”ró hatĆ”rjelzőt leĆ­ró regulĆ”ris kifejezĆ©s. A regulĆ”ris kifejezĆ©snek '^' karakterrel kell kezdődnie." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..bae20c58d0d --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "NĆ©zet: KódtĆ©rkĆ©p be- Ć©s kikapcsolĆ”sa" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index 79c5e7716ee..ebffddce9a7 100644 --- a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "VezĆ©rlőkarakterek be- Ć©s kikapcsolĆ”sa" + "toggleRenderControlCharacters": "NĆ©zet: VezĆ©rlőkarakterek be- Ć©s kikapcsolĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index e496d62b102..eea8c1ed6d1 100644 --- a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "Szókƶzƶk kirajzolĆ”sĆ”nak be- Ć©s kikapcsolĆ”sa" + "toggleRenderWhitespace": "NĆ©zet: Szókƶzƶk kirajzolĆ”sĆ”nak be- Ć©s kikapcsolĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 4020242c40c..7c16965748a 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, hibakeresĆ©s", "debugAriaLabel": "ƍrja be a futtatandó konfigurĆ”ció nevĆ©t.", + "addConfigTo": "KonfigurĆ”ció hozzĆ”adĆ”sa ({0})...", + "addConfiguration": "KonfigurĆ”ció hozzĆ”adĆ”sa...", "noConfigurationsMatching": "Nincs illeszkedő hibakeresĆ©si konfigurĆ”ció", "noConfigurationsFound": "Nem talĆ”lható hibakeresĆ©si konfigurĆ”ció. KĆ©szĆ­tsen egy 'launch.json' fĆ”jlt." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..2a303e57010 --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "selectAndStartDebug": "HibakeresĆ©si konfigurĆ”ció kivĆ”lasztĆ”sa Ć©s indĆ­tĆ”sa" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..72630bc8424 --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "VĆ”ltĆ”s a vĆ”ltozókra", + "debugFocusWatchView": "VĆ”ltĆ”s a figyelőlistĆ”ra", + "debugFocusCallStackView": "VĆ”ltĆ”s a hĆ­vĆ”si veremre", + "debugFocusBreakpointsView": "VĆ”ltĆ”s a tƶrĆ©spontokra" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index fffc1aad27f..a54b3a8b776 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "KonfigurĆ”ciók a 'launch.json' első vĆ”ltozatĆ”nak elkĆ©szĆ­tĆ©sĆ©hez.", "vscode.extension.contributes.debuggers.languages": "Azon nyelvek listĆ”ja, amelyeknĆ©l ez a hibakeresĆ©si kiegĆ©szĆ­tő alapĆ©rtelmezett hibakeresőnek tekinthető.", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Ha meg van adva, a VS Code ezt a parancsot fogja hĆ­vni a hibakeresĆ©si illesztő futtatható Ć”llomĆ”nya elĆ©rĆ©si ĆŗtjĆ”nak Ć©s az Ć”tadandó argumentumok meghatĆ”rozĆ”sĆ”hoz.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Ha meg van hatĆ”rozva, a VS Code ezt a parancsot fogja hĆ­vni az ennek a kiegĆ©szĆ­tőnek küldƶtt \"debug\" vagy \"run\" parancsok esetĆ©n.", "vscode.extension.contributes.debuggers.configurationSnippets": "KódtƶredĆ©kek Ćŗj 'launch.json'-konfigurĆ”ciók hozzĆ”adĆ”sĆ”hoz.", "vscode.extension.contributes.debuggers.configurationAttributes": "JSON-sĆ©makonfigurĆ”ciók a 'launch.json' validĆ”lĆ”sĆ”hoz.", "vscode.extension.contributes.debuggers.windows": "Windows-specifikus beĆ”llĆ­tĆ”sok.", diff --git a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 80975da2ce4..e3d15de5db5 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,14 +12,16 @@ "breakpointRemoved": "TƶrĆ©spont eltĆ”voĆ­ltva, {0}. sor, fĆ”jl: {1}", "compoundMustHaveConfigurations": "A kombinĆ”ciók \"configurations\" tulajdonsĆ”gĆ”t be kell Ć”llĆ­tani tƶbb konfigurĆ”ció elindĆ­tĆ”sĆ”hoz.", "configMissing": "A(z) '{0}' konfigurĆ”ció hiĆ”nyzik a 'launch.json'-ból.", + "debugRequestNotSupported": "A(z) `{0}` attribĆŗtumnak nem tĆ”mogatott Ć©rtĆ©ke van ('{1}') a kivĆ”lasztott hibakeresĆ©si konfigurĆ”cióban.", + "debugRequesMissing": "A(z) '{0}' attribĆŗtum hiĆ”nyzik a kivĆ”lasztott hibakeresĆ©si konfigurĆ”cióból.", "debugTypeNotSupported": "A megadott hibakeresĆ©si tĆ­pus ('{0}') nem tĆ”mogatott.", - "debugTypeMissing": "A kivĆ”lasztott indĆ­tĆ”si konfigurĆ”ciónak hiĆ”nyzik a 'type' tulajdonsĆ”ga.", + "debugTypeMissing": "A kivĆ”lasztott indĆ­tĆ”si konfigurĆ”ciónak hiĆ”nyzik a `type` tulajdonsĆ”ga.", + "debugAnyway": "HibakeresĆ©s indĆ­tĆ”sa mindenkĆ©pp", "preLaunchTaskErrors": "BuildelĆ©si hibĆ”k lĆ©ptek fel a(z) '{0}' preLaunchTask futĆ”sa kƶzben.", "preLaunchTaskError": "BuildelĆ©si hiba lĆ©pett fel a(z) '{0}' preLaunchTask futĆ”sa kƶzben.", "preLaunchTaskExitCode": "A(z) '{0}' preLaunchTask a kƶvetkező hibakóddal fejeződƶtt be: {1}.", - "debugAnyway": "HibakeresĆ©s indĆ­tĆ”sa mindenkĆ©pp", "noFolderWorkspaceDebugError": "Az aktĆ­v fĆ”jlon nem lehet hibakeresĆ©st vĆ©gezni. Bizonyosodjon meg róla, hogy el van mentve a lemezre, Ć©s hogy az adott fĆ”jltĆ­pushoz telepĆ­tve van a megfelelő hibakeresĆ©si kiegĆ©szĆ­tő.", "NewLaunchConfig": "ƁllĆ­tson be egy indĆ­tĆ”si konfigurĆ”ciót az alkalmazĆ”sa szĆ”mĆ”ra. {0}", "DebugTaskNotFound": "A(z) '{0}' preLaunchTask nem talĆ”lható.", - "differentTaskRunning": "A(z) '{0}' feladat mĆ”r fut. Nem futtatható a(z) '{1}' indĆ­tĆ”s előtti feladat." + "taskNotTracked": "A(z) ${0} preLaunchTaskot nem lehet kƶvetni." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 929096a6c43..9c979492ec3 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "A(z) {0} vĆ”ltozó Ć©rtĆ©ke: {1}, REPL, hibakeresĆ©s", "replExpressionAriaLabel": "A(z) {0} kifejezĆ©s Ć©rtĆ©ke: {1}, REPL, hibakeresĆ©s", "replValueOutputAriaLabel": "{0}, REPL, hibakeresĆ©s", - "replKeyValueOutputAriaLabel": "A(z) {0} kimeneti vĆ”ltozó Ć©rtĆ©ke: {1}, REPL, hibakeresĆ©s" + "replRawObjectAriaLabel": "{0} repl-vĆ”ltozó Ć©rtĆ©ke: {1}, REPL, hibakeresĆ©s" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/hun/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 6b2154af74d..0efffacb2ab 100644 --- a/i18n/hun/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "A hibakeresĆ©si illesztő futtatható Ć”llomĆ”nya ('{0}') nem lĆ©tezik.", "debugAdapterCannotDetermineExecutable": "Nem hatĆ”rozható meg a(z) '{0}' hibakeresĆ©si illesztő futtatható Ć”llomĆ”nya.", + "launch.config.comment1": "IntelliSense hasznĆ”lata a lehetsĆ©ges attribĆŗtumok listĆ”zĆ”sĆ”hoz", + "launch.config.comment2": "HĆŗzza fƶlĆ© az egeret a lĆ©tező attribĆŗtumok leĆ­rĆ”sĆ”nak megtekintĆ©sĆ©hez!", + "launch.config.comment3": "TovĆ”bbi informĆ”cióért lĆ”togassa meg a kƶvetkezőt: {0}", "debugType": "A konfigurĆ”ció tĆ­pusa.", "debugTypeNotRecognised": "Ez a hibakeresĆ©si tĆ­pus nem ismert. Bizonyosodjon meg róla, hogy telepĆ­tve Ć©s engedĆ©lyezve van a megfelelő hibakeresĆ©si kiegĆ©szĆ­tő.", "node2NotSupported": "A \"node2\" mĆ”r nem tĆ”mogatott. HasznĆ”lja helyette a \"node\"-ot, Ć©s Ć”llĆ­tsa a \"protocol\" attribĆŗtum Ć©rtĆ©kĆ©t \"inspector\"-ra.", diff --git a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index b3bbb32e886..806ae8197d4 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "AzonosĆ­tó", "view name": "NĆ©v", "view location": "Hol?", - "themes": "TĆ©mĆ”k ({0})", + "colorThemes": "SzĆ­ntĆ©mĆ”k ({0})", + "iconThemes": "IkontĆ©mĆ”k ({0})", + "colors": "SzĆ­nek ({0})", + "colorId": "AzonosĆ­tó", + "defaultDark": "AlapĆ©rtelmezett sƶtĆ©t", + "defaultLight": "AlapĆ©rtelmezett vilĆ”gos", + "defaultHC": "AlapĆ©rtelmezett nagy kontrasztĆŗ", "JSON Validation": "JSON-validĆ”ciók ({0})", "commands": "Parancsok ({0})", "command name": "NĆ©v", diff --git a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 650d879840d..831e0dd3d1d 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,7 +34,6 @@ "postDisableMessage": "Újratƶlti az ablakot a kiegĆ©szĆ­tő ('{0}') kikapcsolĆ”sĆ”hoz?", "postUninstallTooltip": "ÚjratƶltĆ©s a kikapcsolĆ”shoz", "postUninstallMessage": "Újratƶlti az ablakot az eltĆ”volĆ­tott kiegĆ©szĆ­tő ('{0}') kikapcsolĆ”sĆ”hoz?", - "reload": "Ablak Ćŗj&&ratƶltĆ©se", "toggleExtensionsViewlet": "KiegĆ©szĆ­tők megjelenĆ­tĆ©se", "installExtensions": "KiegĆ©szĆ­tők telepĆ­tĆ©se", "showEnabledExtensions": "EngedĆ©lyezett kiegĆ©szĆ­tők megjelenĆ­tĆ©se", @@ -44,14 +43,19 @@ "showOutdatedExtensions": "Elavult kiegĆ©szĆ­tők megjelenĆ­tĆ©se", "showPopularExtensions": "NĆ©pszerű kiegĆ©szĆ­tők megjelenĆ­tĆ©se", "showRecommendedExtensions": "AjĆ”nlott kiegĆ©szĆ­tők megjelenĆ­tĆ©se", - "showWorkspaceRecommendedExtensions": "Munkaterülethez ajĆ”nlott kiegĆ©szĆ­tők megjelenĆ­tĆ©se", + "installWorkspaceRecommendedExtensions": "Minden munkaterülethez ajĆ”nlott kiegĆ©szĆ­tő telepĆ­tĆ©se", + "allExtensionsInstalled": "MĆ”r az ƶsszes, munkaterülethez ajĆ”nlott kiegĆ©szĆ­tő telepĆ­tve van", + "installRecommendedExtension": "AjĆ”nlott kiegĆ©szĆ­tő telepĆ­tĆ©se", + "extensionInstalled": "Ez az ajĆ”nlott kiegĆ©szĆ­tő mĆ”r telepĆ­tve van.", "showRecommendedKeymapExtensions": "AjĆ”nlott billentyűkonfigurĆ”ciók megjelenĆ­tĆ©se", "showRecommendedKeymapExtensionsShort": "BillentyűkonfigurĆ”ciók", "showLanguageExtensions": "Nyelvi kiegĆ©szĆ­tők megjelenĆ­tĆ©se", "showLanguageExtensionsShort": "Nyelvi kiegĆ©szĆ­tők", - "configureWorkspaceRecommendedExtensions": "AjĆ”nlott kiegĆ©szĆ­tők konfigurĆ”lĆ”sa (munkaterületre vonatkozóan)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Az ajĆ”nlatok csak egy munkaterület mappĆ”jĆ”ra vonatkozóan Ć©rhetők el.", + "showAzureExtensions": "Azure-kiegĆ©szĆ­tők megjelenĆ­tĆ©se", + "showAzureExtensionsShort": "Azure-kiegĆ©szĆ­tők", "OpenExtensionsFile.failed": "Nem sikerült lĆ©trehozni az 'extensions.json' fĆ”jlt a '.vscode' mappĆ”nan ({0}).", + "configureWorkspaceRecommendedExtensions": "AjĆ”nlott kiegĆ©szĆ­tők konfigurĆ”lĆ”sa (munkaterületre vonatkozóan)", + "configureWorkspaceFolderRecommendedExtensions": "AjĆ”nlott kiegĆ©szĆ­tők konfigurĆ”lĆ”sa (munkaterület-mappĆ”ra vonatkozóan)", "builtin": "BeĆ©pĆ­tett", "disableAll": "Ɩsszes telepĆ­tett kiegĆ©szĆ­tő letiltĆ”sa", "disableAllWorkspace": "Ɩsszes telepĆ­tett kiegĆ©szĆ­tő letiltĆ”sa a munkaterületre vonatkozóan", diff --git a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..8c7fafc8b58 --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "AjĆ”nlott" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index 85d01b9b53e..eb59571b41c 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "Nyomjon Entert a kiegĆ©szĆ­tők kezelĆ©sĆ©hez.", + "notfound": "A(z) '{0}' kiegĆ©szĆ­tő nem talĆ”lható a piactĆ©ren.", + "install": "Nyomja meg az Enter gombot a(z) '{0}' kiegĆ©szĆ­tő telepĆ­tĆ©sĆ©hez a piactĆ©rről!", "searchFor": "Nyomja meg az Enter gombot a(z) '{0}' kiegĆ©szĆ­tő keresĆ©sĆ©hez a piactĆ©ren.", "noExtensionsToInstall": "Adja meg a kiegĆ©szĆ­tő nevĆ©t" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 09c306397f4..21f3a85d014 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -4,11 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "reallyRecommended2": "Ehhez a fĆ”jltĆ­pushoz a(z) '{0}' kiegĆ©szĆ­tő ajĆ”nlott", + "fileBasedRecommendation": "Ez a kiegĆ©szĆ­tő a kƶzelmĆŗltban megnyitott fĆ”jlok alapjĆ”n ajĆ”nlott.", + "workspaceRecommendation": "Ez a kiegĆ©szĆ­tő az aktuĆ”lis munkaterület felhasznĆ”lói Ć”ltal ajĆ”nlott.", + "reallyRecommended2": "Ehhez a fĆ”jltĆ­pushoz ajĆ”nlott a(z) '{0}' kiegĆ©szĆ­tő.", + "reallyRecommendedExtensionPack": "Ehhez a fĆ”jltĆ­pushoz ajĆ”nlott a(z) '{0}' kiegĆ©szĆ­tőcsomag.", "showRecommendations": "AjĆ”nlatok megjelenĆ­tĆ©se", + "install": "TelepĆ­tĆ©s", "neverShowAgain": "Ne jelenĆ­tse meg Ćŗjra", "close": "BezĆ”rĆ”s", "workspaceRecommended": "A munkaterülethez vannak javasolt kiegĆ©szĆ­tők", + "installAll": "Ɩsszes telepĆ­tĆ©se", "ignoreExtensionRecommendations": "Figyelmen kĆ­vül akarja hagyni az ƶsszes javasolt kiegĆ©szĆ­tőt?", "ignoreAll": "Igen, az ƶsszes figyelmen kĆ­vül hagyĆ”sa", "no": "Nem", diff --git a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index aa157cfb84a..b3695897cf7 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,6 +6,8 @@ { "openExtensionsFolder": "KiegĆ©szĆ­tők mappĆ”jĆ”nak megnyitĆ”sa", "installVSIX": "TelepĆ­tĆ©s VSIX-ből...", + "installFromVSIX": "TelepĆ­tĆ©s VSIX-ből", + "installButton": "&&TelepĆ­tĆ©s", "InstallVSIXAction.success": "A kiegĆ©szĆ­tő sikeresen fel lett telepĆ­tve. IndĆ­tsa Ćŗjra az engedĆ©lyezĆ©shez.", "InstallVSIXAction.reloadNow": "ÚjratƶltĆ©s most" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json index 1cfc5763aeb..1002198259b 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json @@ -8,6 +8,8 @@ "installedExtensions": "TelepĆ­tve", "searchInstalledExtensions": "TelepĆ­tve", "recommendedExtensions": "AjĆ”nlott", + "otherRecommendedExtensions": "TovĆ”bbi ajĆ”nlatok", + "workspaceRecommendedExtensions": "AjĆ”nlott a munkaterülethez", "searchExtensions": "KiegĆ©szĆ­tők keresĆ©se a piactĆ©ren", "sort by installs": "RendezĆ©s a telepĆ­tĆ©sek szĆ”ma szerint", "sort by rating": "RendezĆ©s Ć©rtĆ©kelĆ©s szerint", diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 0992f340c4a..d032a29e684 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "FĆ”jlok", + "filesCategory": "FĆ”jl", "revealInSideBar": "MegjelenĆ­tĆ©s az oldalsĆ”von", "acceptLocalChanges": "A lemezen lĆ©vő tartalom felülĆ­rĆ”sa a sajĆ”t módosĆ­tĆ”sokkal", "revertLocalChanges": "SajĆ”t módosĆ­tĆ”sok elvetĆ©se Ć©s a lemezen lĆ©vő tartalom visszaĆ”llĆ­tĆ”sa" diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 4e50a349a2f..89393542705 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Tƶrli a(z) '{0}' nevű fĆ”jlt?", "undoBin": "HelyreĆ”llĆ­thatja a lomtĆ”rból.", "undoTrash": "HelyreĆ”llĆ­thatja a kukĆ”ból.", + "doNotAskAgain": "Ne kĆ©rdezze meg Ćŗjra", "confirmDeleteMessageFolder": "Tƶrli a(z) {0} mappĆ”t Ć©s a teljes tartalmĆ”t?", "confirmDeleteMessageFile": "VĆ©glegesen tƶrli a kƶvetkezőt: {0}?", "irreversible": "A művelet nem vonható vissza!", @@ -37,17 +38,15 @@ "openToSide": "MegnyitĆ”s oldalt", "compareSource": "KijelƶlĆ©s ƶsszehasonlĆ­tĆ”shoz", "globalCompareFile": "AktĆ­v fĆ”jl ƶsszehasonlĆ­tĆ”sa...", - "pickHistory": "VĆ”lasszon egy korĆ”bban megnyitott fĆ”jlt az ƶsszehasonlĆ­tĆ”shoz", - "unableToFileToCompare": "A kivĆ”lasztott fĆ”jl nem hasonlĆ­tható ƶssze a kƶvetkezővel: '{0}'.", "openFileToCompare": "FĆ”jlok ƶsszehasonlĆ­tĆ”sĆ”hoz elősszƶr nyisson meg egy fĆ”jlt.", - "compareWith": "ƖsszehasonlĆ­tĆ”s a kƶvetkezővel: '{0}'", + "compareWith": "'{0}' ƶsszehasonlĆ­tĆ”sa a kƶvetkezővel: '{1}'", "compareFiles": "FĆ”jlok ƶsszehasonlĆ­tĆ”sa", "refresh": "FrissĆ­tĆ©s", "save": "MentĆ©s", "saveAs": "MentĆ©s mĆ”skĆ©nt...", "saveAll": "Ɩsszes mentĆ©se", "saveAllInGroup": "Ɩsszes mentĆ©se a csoportban", - "saveFiles": "MódosĆ­tott fĆ”jlok mentĆ©se", + "saveFiles": "Ɩsszes fĆ”jl mentĆ©se", "revert": "FĆ”jl visszaĆ”llĆ­tĆ”sa", "focusOpenEditors": "VĆ”ltĆ”s a megnyitott szerkesztőablakok nĆ©zetre", "focusFilesExplorer": "VĆ”ltĆ”s a fĆ”jlkezelőre", @@ -55,7 +54,6 @@ "openFileToShow": "FĆ”jl fĆ”jlkezelőben tƶrtĆ©nő megjelenĆ­tĆ©sĆ©hez előszƶr nyisson meg egy fĆ”jlt", "collapseExplorerFolders": "MappĆ”k ƶsszecsukĆ”sa a fĆ”jlkezelőben", "refreshExplorer": "FĆ”jlkezelő frissĆ­tĆ©se", - "openFile": "FĆ”jl megnyitĆ”sa...", "openFileInNewWindow": "AktĆ­v fĆ”jl megnyitĆ”sa Ćŗj ablakban", "openFileToShowInNewWindow": "FĆ”jl Ćŗj ablakban tƶrtĆ©nő megnyitĆ”sĆ”hoz előszƶr nyisson meg egy fĆ”jlt", "revealInWindows": "MegjelenĆ­tĆ©s a fĆ”jlkezelőben", diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 0bb1717ba95..a6c7fe4eaef 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "SzƶvegfĆ”jlszerkesztő", "binaryFileEditor": "BinĆ”ris fĆ”jlszerkesztő", "filesConfigurationTitle": "FĆ”jlok", - "exclude": "GlobĆ”lis mintĆ”k konfigurĆ”lĆ”sa fĆ”jlok Ć©s mappĆ”k kiszűrĆ©sĆ©hez.", + "exclude": "GlobĆ”lis mintĆ”k konfigurĆ”lĆ”sa fĆ”jlok Ć©s mappĆ”k kizĆ”rĆ”sĆ”hoz. A fĆ”jlkezelő pĆ©ldĆ”ul ezen beĆ”llĆ­tĆ”s alapjĆ”n dƶnti el, hogy mely fĆ”jlokat Ć©s mappĆ”kat jelenĆ­tsen meg vagy rejtsen el.", "files.exclude.boolean": "A globĆ”lis minta, amire illesztve lesznek a fĆ”jlok elĆ©rĆ©si Ćŗtjai. A minta engedĆ©lyezĆ©sĆ©hez vagy letiltĆ”sĆ”hoz Ć”llĆ­tsa igaz vagy hamis Ć©rtĆ©kre.", "files.exclude.when": "TovĆ”bbi ellenőrzĆ©s elvĆ©gzĆ©se egy egyező fĆ”jl testvĆ©rein. Az egyező fĆ”jlnĆ©vhez hasznĆ”lja a $(basename) vĆ”ltozót.", "associations": "Rendeljen nyelveket a fĆ”jlokhoz (pl: \"*.kiterjesztĆ©s\": \"html\"). Ezek a hozzĆ”rendelĆ©sek elsőbbsĆ©get Ć©lveznek a telepĆ­tett nyelvek Ć”ltal definiĆ”lt alapĆ©rtelmezett beĆ”llĆ­tĆ”sokkal szemben.", - "encoding": "A fĆ”jlok olvasĆ”sakor Ć©s Ć­rĆ”sakor hasznĆ”lt alapĆ©rtelmezett karakterkódolĆ”s.", - "autoGuessEncoding": "Ha engedĆ©lyezve van, az alkalmazĆ”s automatikusan megpróbĆ”lja kitalĆ”lni a fĆ”jlok kódolĆ”sĆ”t megnyitĆ”skor", + "encoding": "A fĆ”jlok Ć­rĆ”sĆ”nĆ”l Ć©s olvasĆ”sĆ”nĆ”l hasznĆ”lt alapĆ©rtelmezett karakterkĆ©szlet. A beĆ”llĆ­tĆ”s nyelvenkĆ©nt is konfigurĆ”lható.", + "autoGuessEncoding": "Ha engedĆ©lyezve van, fĆ”jlok megnyitĆ”sakor megpróbĆ”lja kitalĆ”lni a karakterkĆ©szletüket. A beĆ”llĆ­tĆ”s nyelvenkĆ©nt is konfigurĆ”lható.", "eol": "Az alapĆ©rtelmezett sorvĆ©gjel. LF-hez hasznĆ”ljon \\n-t, CRLF-hez pedig \\r\\n-t.", "trimTrailingWhitespace": "Ha engedĆ©lyezve van, a fĆ”jl mentĆ©sekor levĆ”gja a sor vĆ©gĆ©n talĆ”lható szókƶzƶket.", "insertFinalNewline": "Ha engedĆ©lyezve van, mentĆ©skor beszĆŗr egy zĆ”ró Ćŗjsort a fĆ”jl vĆ©gĆ©re.", + "trimFinalNewlines": "Ha engedĆ©lyezve van, mentĆ©skor levĆ”gja a fĆ”jl vĆ©gĆ©rő az ƶsszes Ćŗjsort az utolsó Ćŗjsor utĆ”n.", "files.autoSave.off": "A módosĆ­tott fĆ”jlok soha nincsenek automatikusan mentve.", "files.autoSave.afterDelay": "A módosĆ­tott fĆ”jlok automatikusan mentĆ©sre kerülnek a 'files.autoSaveDelay' beĆ”llĆ­tĆ”sban meghatĆ”rozott időkƶzƶnkĆ©nt.", "files.autoSave.onFocusChange": "A módosĆ­tott fĆ”jlok automatikusan mentĆ©sre kerülnek, ha a szerkesztőablak elveszĆ­ti a fókuszt.", @@ -39,10 +40,14 @@ "dynamicHeight": "MeghatĆ”rozza, hogy a megnyitott szerkesztőablakok szakasz magassĆ”ga automatikusan illeszkedjen a megnyitott elemek szĆ”mĆ”hoz vagy sem.", "autoReveal": "MeghatĆ”rozza, hogy a fĆ”jlkezelőben automatikusan fel legyenek fedve Ć©s ki legyenek jelƶlve a fĆ”jlok, amikor megnyitjĆ”k őket.", "enableDragAndDrop": "MeghatĆ”rozza, hogy a fĆ”jlkezelőben Ć”thelyezhetők-e a fĆ”jlok Ć©s mappĆ”k hĆŗzĆ”ssal.", - "sortOrder.default": "A fĆ”jlok Ć©s kƶnyvtĆ”rak nĆ©v szerint vannak rendezve, ABC-sorrendben. A kƶnyvtĆ”rak a fĆ”jlok előtt vannak listĆ”zva.", - "sortOrder.mixed": "A fĆ”jlok Ć©s kƶnyvtĆ”rak nĆ©v szerint vannak rendezve, ABC-sorrendben. A fĆ”jlok Ć©s a kƶnyvtĆ”rak kƶzƶsen vannak rendezve.", - "sortOrder.filesFirst": "A fĆ”jlok Ć©s kƶnyvtĆ”rak nĆ©v szerint vannak rendezve, ABC-sorrendben. A fĆ”jlok a kƶnyvtĆ”rak előtt vannak listĆ”zva.", - "sortOrder.type": "A fĆ”jlok Ć©s kƶnyvtĆ”rak a kiterjesztĆ©sük szerint vannak rendezve, ABC-sorrendben. A kƶnyvtĆ”rak a fĆ”jlok előtt vannak listĆ”zva.", - "sortOrder.modified": "A fĆ”jlok Ć©s kƶnyvtĆ”rak a legutolsó módosĆ­tĆ”s dĆ”tuma szerint vannak rendezve, csƶkkenő sorrendben. A kƶnyvtĆ”rak a fĆ”jlok előtt vannak listĆ”zva.", - "sortOrder": "MeghatĆ”rozza a fĆ”jlok Ć©s kƶnyvtĆ”rak rendezĆ©si módjĆ”t a fĆ”jlkezelőben." + "confirmDragAndDrop": "MeghatĆ”rozza, hogy a fĆ”jlkezelő kĆ©rjen-e megerősĆ­tĆ©st fĆ”jlok Ć©s mappĆ”k hĆŗzĆ”ssal tƶrtĆ©nő Ć”thelyezĆ©se esetĆ©n.", + "confirmDelete": "MeghatĆ”rozza, hogy a fĆ”jlkezelő kĆ©rjen-e megerősĆ­tĆ©st a fĆ”jlok lomtĆ”rba tƶrtĆ©nő helyezĆ©se esetĆ©n.", + "sortOrder.default": "A fĆ”jlok Ć©s mappĆ”k nĆ©v szerint vannak rendezve, ABC-sorrendben. A mappĆ”k a fĆ”jlok előtt vannak listĆ”zva.", + "sortOrder.mixed": "A fĆ”jlok Ć©s mappĆ”k nĆ©v szerint vannak rendezve, ABC-sorrendben. A fĆ”jlok Ć©s a mappĆ”k kƶzƶsen vannak rendezve.", + "sortOrder.filesFirst": "A fĆ”jlok Ć©s mappĆ”k nĆ©v szerint vannak rendezve, ABC-sorrendben. A fĆ”jlok a mappĆ”k előtt vannak listĆ”zva.", + "sortOrder.type": "A fĆ”jlok Ć©s mappĆ”k a kiterjesztĆ©sük szerint vannak rendezve, ABC-sorrendben. A mappĆ”k a fĆ”jlok előtt vannak listĆ”zva.", + "sortOrder.modified": "A fĆ”jlok Ć©s mappĆ”k a legutolsó módosĆ­tĆ”s dĆ”tuma szerint vannak rendezve, csƶkkenő sorrendben. A mappĆ”k a fĆ”jlok előtt vannak listĆ”zva.", + "sortOrder": "MeghatĆ”rozza a fĆ”jlok Ć©s mappĆ”k rendezĆ©si módjĆ”t a fĆ”jlkezelőben. Az alapĆ©rtelmezett rendezĆ©sen tĆŗl beĆ”llĆ­tható 'mixed' (a fĆ”jlok Ć©s mappĆ”k kƶzƶsen vannak rendezve), 'type' (rendezĆ©s fĆ”jltĆ­pus szerint), 'modified' (rendezĆ©s utolsó módosĆ­tĆ”si dĆ”tum szerint) vagy 'filesFirst' (fĆ”jlok a mappĆ”k elĆ© vannak rendezve) is.", + "explorer.decorations.colors": "MeghatĆ”rozza, hogy a fĆ”jldekorĆ”ciók hasznĆ”ljanak-e szĆ­neket.", + "explorer.decorations.badges": "MeghatĆ”rozza, hogy a fĆ”jldekorĆ”ciók hasznĆ”ljanak-e jelvĆ©nyeket." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 1e6952cc6a7..0bb33fdc628 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "HasznĆ”lja a jobbra lĆ©vő szerkesztői eszkƶztĆ”ron talĆ”lható műveleteket a sajĆ”t módosĆ­tĆ”sok **visszavonĆ”sĆ”ra** vagy **Ć­rja felül** a lemezen lĆ©vő tartalmat a vĆ”ltoztatĆ”sokkal", "discard": "ElvetĆ©s", "overwrite": "FelülĆ­rĆ”s", "retry": "ÚjrapróbĆ”lkozĆ”s", @@ -11,6 +12,5 @@ "genericSaveError": "Hiba a(z) '{0}' mentĆ©se kƶzben: {1}", "staleSaveError": "Nem sikerült menteni a(z) '{0}' fĆ”jlt: a lemezen lĆ©vő tartalom Ćŗjabb. Kattintson az **ƖsszehasonlĆ­tĆ”s*** gombra a helyi Ć©s a lemezen lĆ©vő vĆ”ltozat ƶsszehasonlĆ­tĆ”sĆ”hoz.", "compareChanges": "ƖsszehasonlĆ­tĆ”s", - "saveConflictDiffLabel": "{0} (a lemezen) ↔ {1} ({2}) – MentĆ©si konfliktus feloldĆ”sa", - "userGuide": "HasznĆ”lja a jobbra lĆ©vő szerkesztői eszkƶztĆ”ron talĆ”lható műveleteket a sajĆ”t módosĆ­tĆ”sok **visszavonĆ”sĆ”ra** vagy **Ć­rja felül** a lemezen lĆ©vő tartalmat a vĆ”ltoztatĆ”sokkal" + "saveConflictDiffLabel": "{0} (a lemezen) ↔ {1} ({2}) – MentĆ©si konfliktus feloldĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 924c7ac5593..30d6d309142 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Nincs mappa megnyitva", "explorerSection": "FĆ”jlkezelő szakasz", - "noWorkspaceHelp": "MĆ©g nem nyitott meg mappĆ”t", + "noWorkspaceHelp": "MĆ©g nem adott mappĆ”t a munkaterülethez.", + "addFolder": "Mappa hozzĆ”adĆ”sa", + "noFolderHelp": "MĆ©g nem nyitott meg mappĆ”t", "openFolder": "Mappa megnyitĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..e8e887279e8 --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "FĆ”jlkezelő", + "canNotResolve": "Nem sikerült feloldani a munkaterület-mappĆ”t" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index d2f6b36195d..e00a7141ecf 100644 --- a/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,13 @@ { "fileInputAriaLabel": "Adja meg a fĆ”jl nevĆ©t. Nyomjon 'Enter'-t a megerősĆ­tĆ©shez vagy 'Escape'-et a megszakĆ­tĆ”shoz.", "filesExplorerViewerAriaLabel": "{0}, FĆ”jlkezelő", + "dropFolders": "SzeretnĆ© hozzĆ”adni a mappĆ”kat a munkaterülethez?", + "dropFolder": "SzeretnĆ© hozzĆ”adni a mappĆ”t a munkaterülethez?", + "addFolders": "MappĆ”k hozzĆ”&&adĆ”sa", + "addFolder": "Mappa hozzĆ”&&adĆ”sa", + "confirmMove": "Biztosan Ć”t szeretnĆ© helyezni a kƶvetkezőt: '{0}'?", + "doNotAskAgain": "Ne kĆ©rdezze meg Ćŗjra", + "moveButtonLabel": "&&ƁthelyezĆ©s", "confirmOverwriteMessage": "A cĆ©lmappĆ”ban mĆ”r lĆ©tezik '{0}' nevű elem. Le szeretnĆ© cserĆ©lni?", "irreversible": "A művelet nem vonható vissza!", "replaceButtonLabel": "&&Csere" diff --git a/i18n/hun/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/hun/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 24ed237c8fe..757e243c9a7 100644 --- a/i18n/hun/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 nem mentett fĆ”jl", "dirtyFiles": "{0} nem mentett fĆ”jl" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/hun/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..c9127f9169b --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "ProblĆ©mĆ”k", + "tooltip.1": "A fĆ”jlban 1 problĆ©ma talĆ”lható", + "tooltip.N": "A fĆ”jlban {0} problĆ©ma talĆ”lható", + "markers.showOnFile": "FĆ”jlokban Ć©s mappĆ”kban talĆ”lható hibĆ”k Ć©s figyelmeztetĆ©sek megjelenĆ­tĆ©se" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/hun/src/vs/workbench/parts/markers/common/messages.i18n.json index f17c3b300c4..5600d4626b5 100644 --- a/i18n/hun/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "NĆ©zet", + "problems.view.toggle.label": "ProblĆ©mĆ”k be- Ć©s kikapcsolĆ”sa", "problems.view.show.label": "ProblĆ©mĆ”k megjelenĆ­tĆ©se", + "problems.view.hide.label": "ProblĆ©mĆ”k elrejtĆ©se", "problems.panel.configuration.title": "ProblĆ©mĆ”k-nĆ©zet", "problems.panel.configuration.autoreveal": "MeghatĆ”rozza, hogy a problĆ©mĆ”k nĆ©zet automatikusan felfedje-e a fĆ”jlokat, amikor megnyitja őket.", "markers.panel.title.problems": "ProblĆ©mĆ”k", diff --git a/i18n/hun/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/hun/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index ef6d4a9d7db..9023227fb65 100644 --- a/i18n/hun/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "MĆ”solĆ”s" + "copyMarker": "MĆ”solĆ”s", + "copyMarkerMessage": "Üzenet mĆ”solĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index 497bbff0b89..bf91ad5e3b5 100644 --- a/i18n/hun/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "LassĆŗ indulĆ”s Ć©rzĆ©kelve", - "slow.detail": "SajnĆ”ljuk, hogy lassĆŗ volt az alkalmazĆ”s indulĆ”sa. IndĆ­tsa Ćŗjra a(z) '{0}' alkalmazĆ”st bekapcsolt profilozĆ”ssal, ossza meg a profilt velünk, Ć©s kemĆ©nyen fogunk dolgozni azon, hogy az indulĆ”s ismĆ©t gyors legyen.", "prof.message": "Profil sikeresen elkĆ©szĆ­tve.", "prof.detail": "KĆ©szĆ­tsen egy hibajelentĆ©st, Ć©s manuĆ”lisan csatolja a kƶvetkező fĆ”jlokat:\n{0}", "prof.restartAndFileIssue": "HibajelentĆ©s lĆ©trehozĆ”sa Ć©s ĆŗjraindĆ­tĆ”s", diff --git a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index d7bd56c34cc..4d1cfca9683 100644 --- a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "BillentyűparancsfĆ”jl megnyitĆ”sa", "openWorkspaceSettings": "Munkaterület beĆ”llĆ­tĆ”sainak megnyitĆ”sa", "openFolderSettings": "Mappa beĆ”llĆ­tĆ”sainak megnyitĆ”sa", - "pickFolder": "VĆ”lasszon mappĆ”t!", "configureLanguageBasedSettings": "Nyelvspecifikus beĆ”llĆ­tĆ”sok konfigurĆ”lĆ”sa...", "languageDescriptionConfigured": "(({0})", "pickLanguage": "Nyelv kivĆ”lasztĆ”sa" diff --git a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index fa8da3a82cf..c61dba726c1 100644 --- a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -13,5 +13,6 @@ "settingsFound": "{0} illeszkedő beĆ”llĆ­tĆ”s", "fileEditorWithInputAriaLabel": "{0}. SzƶvegfĆ”jlszerkesztő.", "fileEditorAriaLabel": "SzƶvegfĆ”jlszerkesztő", + "defaultEditorReadonly": "A jobb oldalon lĆ©vő szerkesztőablak tartalmĆ”nak módosĆ­tĆ”sĆ”val Ć­rhatja felül az alapĆ©rtelmezett beĆ”llĆ­tĆ”sokat.", "preferencesAriaLabel": "Az alapĆ©rtelmezett beĆ”llĆ­tĆ”sok. ƍrĆ”svĆ©dett szerkesztőablak." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 7fbc7fb1516..856d458a709 100644 --- a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,15 +5,15 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Az ebben a fĆ”jlban elhelyezett beĆ”llĆ­tĆ”sok felülĆ­rjĆ”k az alapĆ©rtelmezett beĆ”llĆ­tĆ”sokat.", - "errorInvalidConfiguration": "Nem sikerült Ć­rni a beĆ”llĆ­tĆ”sokba. JavĆ­tsa a fĆ”jlban talĆ”lható hibĆ”kat/figyelmeztetĆ©seket, majd próbĆ”lja Ćŗjra!", "emptyWorkspaceSettingsHeader": "Az ebben a fĆ”jlban elhelyezett beĆ”llĆ­tĆ”sok felülĆ­rjĆ”k a felhasznĆ”lói beĆ”llĆ­tĆ”sokat.", "emptyFolderSettingsHeader": "Az ebben a fĆ”jlban elhelyezett beĆ”llĆ­tĆ”sok felülĆ­rjĆ”k a munkaterületre vonatkozó beĆ”llĆ­tĆ”sokat.", "defaultFolderSettingsTitle": "AlapĆ©rtelmezett mappabeĆ”llĆ­tĆ”sok", "defaultSettingsTitle": "AlapĆ©rtelmezett beĆ”llĆ­tĆ”sok", - "noSettingsFound": "BeĆ”llĆ­tĆ”s nem talĆ”lható.", "editTtile": "SzerkesztĆ©s", "replaceDefaultValue": "Csere a beĆ”llĆ­tĆ”sokban", "copyDefaultValue": "MĆ”solĆ”s a beĆ”llĆ­tĆ”sokba", "unsupportedPHPExecutablePathSetting": "Ez a beĆ”llĆ­tĆ”s csak a felhasznĆ”lói beĆ”llĆ­tĆ”sokban szerepelhet. A PHP munkaterülethez tƶrtĆ©nő konfigurĆ”lĆ”sĆ”hoz nyisson meg egy PHP-fĆ”jlt, majd kattintson a PHP-elĆ©rĆ©si Ćŗtra az Ć”llapotsoron!", - "unsupportedWorkspaceSetting": "Ez a beĆ”llĆ­tĆ”s csak a felhasznĆ”lói beĆ”llĆ­tĆ”sokban szerepelhet." + "unsupportedWorkspaceSetting": "Ez a beĆ”llĆ­tĆ”s csak a felhasznĆ”lói beĆ”llĆ­tĆ”sokban szerepelhet.", + "unsupportedWorkbenchSetting": "Ez a beĆ”llĆ­tĆ”s jelenleg nem alkalmazható. Akkor van hasznĆ”latban, ha kƶzvetlenül nyitja meg ezt a mappĆ”t.", + "unsupportedWorkbenchSettingDevMode": "Ez a beĆ”llĆ­tĆ”s jelenleg nem alkalmazható. Akkor van hasznĆ”latban, ha a hatókƶre 'resource'-kĆ©nt van megadva a regisztrĆ”ció sorĆ”n vagy kƶzvetlenül nyitja meg ezt a mappĆ”t." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 20651a37e87..1da42b0222a 100644 --- a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "folderSettingsDetails": "MappabeĆ”llĆ­tĆ”sok" + "defaultSettingsFuzzyPrompt": "PróbĆ”lja ki a fuzzy keresĆ©st!", + "defaultSettings": "A jobb oldalon lĆ©vő szerkesztőablakban elhelyezett beĆ”llĆ­tĆ”sok felülĆ­rjĆ”k az alapĆ©rtelmezett beĆ”llĆ­tĆ”sokat.", + "noSettingsFound": "BeĆ”llĆ­tĆ”s nem talĆ”lható.", + "folderSettingsDetails": "MappabeĆ”llĆ­tĆ”sok", + "enableFuzzySearch": "KĆ­sĆ©rleti fuzzy keresĆ©s engedĆ©lyezĆ©se" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/hun/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index f246587a26b..1fd4f23c9d2 100644 --- a/i18n/hun/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "Gyakran hasznĆ”lt", - "noSettings": "Nincsenek beĆ”llĆ­tĆ”sok.", + "mostRelevant": "Legfontosabb", "defaultKeybindingsHeader": "A billentyűparancsok fĆ”jlban elhelyezett billentyűparancsok felülĆ­rjĆ”k az alapĆ©rtelmezett beĆ”llĆ­tĆ”sokat" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 41ec82c33f7..949b0eb4dcf 100644 --- a/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "Ebben a kontextusban nem engedĆ©lyezett a(z) {0} parancs futtatĆ”sa.", "recentlyUsed": "legutóbb hasznĆ”lt", "morecCommands": "tovĆ”bbi parancsok", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Parancs nem talĆ”lható" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 2100b3de8db..40810934d63 100644 --- a/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Egy olyan beĆ”llĆ­tĆ”s vĆ”ltozott, melynek hatĆ”lyba lĆ©pĆ©sĆ©hez ĆŗjraindĆ­tĆ”s szüksĆ©ges.", "relaunchSettingDetail": "A beĆ”llĆ­tĆ”s engedĆ©lyezĆ©sĆ©hez nyomja meg az ĆŗjraindĆ­tĆ”s gombot a {0} ĆŗjraindĆ­tĆ”sĆ”hoz.", - "restart": "ÚjraindĆ­tĆ”s", - "relaunchWorkspaceMessage": "A munkaterület módosĆ­tĆ”sa miatt a kiegĆ©szĆ­tőrendszer ĆŗjratƶltĆ©sĆ©re van szüksĆ©g.", - "reload": "ÚjratƶltĆ©s" + "restart": "Új&&raindĆ­tĆ”s" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 088f4ecdf17..165c4dd23c2 100644 --- a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0}. módosĆ­tĆ”s (ƶsszesen: {1})", + "change": "{0}. módosĆ­tĆ”s (ƶsszesen: {1})", + "show previous change": "Előző módosĆ­tĆ”s megjelenĆ­tĆ©se", + "show next change": "Kƶvetkező módosĆ­tĆ”s megjelenĆ­tĆ©se", "editorGutterModifiedBackground": "A szerkesztőablak margójĆ”nak hĆ”ttĆ©rszĆ­ne a módosĆ­tott soroknĆ”l.", "editorGutterAddedBackground": "A szerkesztőablak margójĆ”nak hĆ”ttĆ©rszĆ­ne a hozzĆ”adott soroknĆ”l.", - "editorGutterDeletedBackground": "A szerkesztőablak margójĆ”nak hĆ”ttĆ©rszĆ­ne a tƶrƶlt soroknĆ”l." + "editorGutterDeletedBackground": "A szerkesztőablak margójĆ”nak hĆ”ttĆ©rszĆ­ne a tƶrƶlt soroknĆ”l.", + "overviewRulerModifiedForeground": "A módosĆ­tott tartalmat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "overviewRulerAddedForeground": "A hozzĆ”adott tartalmat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von.", + "overviewRulerDeletedForeground": "A tƶrƶlt tartalmat jelƶlő jelzĆ©sek szĆ­ne az Ć”ttekintősĆ”von." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index fd2863510af..4f8b481dc00 100644 --- a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Git megjelenĆ­tĆ©se", - "installAdditionalSCMProviders": "TovĆ”bbi verziókezelő rendszerek telepĆ­tĆ©se...", "source control": "Verziókezelő rendszer", "toggleSCMViewlet": "Verziókezelő megjelenĆ­tĆ©se", "view": "NĆ©zet" diff --git a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 529d2491ca2..023886324b7 100644 --- a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Verziókezelő rendszerek", + "hideRepository": "ElrejtĆ©s", "commitMessage": "Üzenet (nyomja meg a kƶvetkezőt a commithoz: {0})", + "installAdditionalSCMProviders": "TovĆ”bbi verziókezelő rendszerek telepĆ­tĆ©se...", + "no open repo": "Nincs aktĆ­v verziókezelő rendszer.", "source control": "Verziókezelő rendszer", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 47387e215d8..4d6c563c176 100644 --- a/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "Szimbólum megkeresĆ©se a munkaterületen...", "name": "KeresĆ©s", - "showSearchViewlet": "KeresĆ©s megjelenĆ­tĆ©se", + "search": "KeresĆ©s", "view": "NĆ©zet", - "findInFiles": "KeresĆ©s a fĆ”jlokban", "openAnythingHandlerDescription": "FĆ”jl megkeresĆ©se", "openSymbolDescriptionNormal": "Szimbólum megkeresĆ©se a munkaterületen", "searchOutputChannelTitle": "KeresĆ©s", @@ -16,7 +15,9 @@ "exclude": "GlobĆ”lis mintĆ”k konfigurĆ”lĆ”sa fĆ”jlok Ć©s mappĆ”k keresĆ©sből való kizĆ”rĆ”sĆ”hoz. Ɩrƶkli az ƶsszes globĆ”lis mintĆ”t a fliex.exclude beĆ”llĆ­tĆ”sból.", "exclude.boolean": "A globĆ”lis minta, amire illesztve lesznek a fĆ”jlok elĆ©rĆ©si Ćŗtjai. A minta engedĆ©lyezĆ©sĆ©hez vagy letiltĆ”sĆ”hoz Ć”llĆ­tsa igaz vagy hamis Ć©rtĆ©kre.", "exclude.when": "TovĆ”bbi ellenőrzĆ©s elvĆ©gzĆ©se az illeszkedő fĆ”jlok testvĆ©rein. Az illeszkedő fĆ”jl nevĆ©hez hasznĆ”lja a $(basename) vĆ”ltozót!", - "useRipgrep": "MeghatĆ”rozza, hogy a szƶvegben való keresĆ©shez a ripgrep van-e hasznĆ”lva.", - "useIgnoreFilesByDefault": "MeghatĆ”rozza, hogy a .gitignore Ć©s .ignore fĆ”jlok hasznĆ”lva vannak-e az Ćŗj munkaterületeken a keresĆ©shez.", - "search.quickOpen.includeSymbols": "MeghatĆ”rozza, hogy a fĆ”jlok gyors megnyitĆ”sĆ”nĆ”l megjelenjenek-e a globĆ”lis szimbólumkereső talĆ”latai." + "useRipgrep": "MeghatĆ”rozza, hogy a szƶvegben Ć©s fĆ”jlokban való keresĆ©shez a ripgrep van-e hasznĆ”lva.", + "useIgnoreFilesByDefault": "MeghatĆ”rozza, hogy a .gitignore Ć©s .ignore fĆ”jlok alapĆ©rtelmezĆ©s szerint hasznĆ”lva legyenek-e egy Ćŗj munkaterületen a keresĆ©shez.", + "useIgnoreFiles": "MeghatĆ”rozza, hogy a .gitignore Ć©s .ignore fĆ”jlok hasznĆ”lva legyenek-e a keresĆ©shez.", + "search.quickOpen.includeSymbols": "MeghatĆ”rozza, hogy a fĆ”jlok gyors megnyitĆ”sĆ”nĆ”l megjelenjenek-e a globĆ”lis szimbólumkereső talĆ”latai.", + "search.followSymlinks": "MeghatĆ”rozza, hogy keresĆ©s sorĆ”n kƶvetve legyenek-e a szimbolikus linkek." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 81ca25b06ea..a98705779e9 100644 --- a/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -12,14 +12,18 @@ "previousSearchTerm": "Előző keresőkifejezĆ©s megjelenĆ­tĆ©se", "focusNextInputBox": "VĆ”ltĆ”s a kƶvetkező beviteli mezőre", "focusPreviousInputBox": "VĆ”ltĆ”s az előző beviteli mezőre", + "showSearchViewlet": "KeresĆ©s megjelenĆ­tĆ©se", + "findInFiles": "KeresĆ©s a fĆ”jlokban", + "findInFilesWithSelectedText": "KeresĆ©s a fĆ”jlokban a kijelƶlt szƶveg alapjĆ”n", "replaceInFiles": "Csere a fĆ”jlokban", + "replaceInFilesWithSelectedText": "Csere a fĆ”jlokban a kijelƶlt szƶveg alapjĆ”n", "findInWorkspace": "KeresĆ©s a munkaterületen...", "findInFolder": "KeresĆ©s mappĆ”ban...", "RefreshAction.label": "FrissĆ­tĆ©s", "ClearSearchResultsAction.label": "KeresĆ©si eredmĆ©nyek tƶrlĆ©se", "FocusNextSearchResult.label": "VĆ”ltĆ”s a kƶvetkező keresĆ©si eredmĆ©nyre", "FocusPreviousSearchResult.label": "VĆ”ltĆ”s az előző keresĆ©si eredmĆ©nyre", - "RemoveAction.label": "EltĆ”volĆ­tĆ”s", + "RemoveAction.label": "ElvetĆ©s", "file.replaceAll.label": "Ɩsszes cserĆ©je", "match.replace.label": "Csere" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/hun/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 557a3b1f1b3..73b5cb21652 100644 --- a/i18n/hun/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "kizĆ”rt fĆ”jlok", "label.excludes": "KeresĆ©sből kizĆ”rt fĆ”jlok", "replaceAll.confirmation.title": "Minden előfordulĆ”s cserĆ©je", - "replaceAll.confirm.button": "Csere", + "replaceAll.confirm.button": "&&Csere", "replaceAll.occurrence.file.message": "{0} előfordulĆ”s cserĆ©lve {1} fĆ”jlban a kƶvetkezőre: '{2}'.", "removeAll.occurrence.file.message": "{0} előfordulĆ”s cserĆ©lve {1} fĆ”jlban.", "replaceAll.occurrence.files.message": "{0} előfordulĆ”s cserĆ©lve {1} fĆ”jlban a kƶvetkezőre: '{2}'.", @@ -28,28 +28,22 @@ "removeAll.occurrences.files.confirmation.message": "CserĆ©l {0} előfordulĆ”s {1} fĆ”jlban a kƶvetkezőre: '{2}'?", "replaceAll.occurrences.files.confirmation.message": "CserĆ©l {0} előfordulĆ”st {1} fĆ”jlban?", "treeAriaLabel": "KeresĆ©si eredmĆ©nyek", + "searchPathNotFoundError": "KeresĆ©si elĆ©rĆ©si Ćŗt nem talĆ”lható: {0}", "searchMaxResultsWarning": "Az eredmĆ©nyhalmaz csak a talĆ”latok egy rĆ©szĆ©t tartalmazza. PontosĆ­tsa a keresĆ©st a keresĆ©si eredmĆ©nyek halmazĆ”nak szűkĆ­tĆ©sĆ©hez!", "searchCanceled": "A keresĆ©s meg lett szakĆ­tva, mielőtt eredmĆ©nyt hozott volna –", "noResultsIncludesExcludes": "Nincs talĆ”lat a kƶvetkező helyen: '{0}', '{1}' kivĆ©telĆ©vel –", "noResultsIncludes": "Nincs talĆ”lat a kƶvetkező helyen: '{0}' –", "noResultsExcludes": "Nincs talĆ”lat '{1}' kivĆ©telĆ©vel –", - "noResultsFound": "Nincs talĆ”lat. Ellenőrizze a kizĆ”rĆ”si beĆ”llĆ­tĆ”sokat –", + "noResultsFound": "Nincs talĆ”lat. Ellenőrizze a kizĆ”rĆ”si beĆ”llĆ­tĆ”sokat Ć©s az ignore-fĆ”jlokat –", "rerunSearch.message": "KeresĆ©s megismĆ©tlĆ©se", "rerunSearchInAll.message": "KeresĆ©s megismĆ©tlĆ©se az ƶsszes fĆ”jlban", "openSettings.message": "BeĆ”llĆ­tĆ”sok megnyitĆ”sa", + "openSettings.learnMore": "TovĆ”bbi informĆ”ció", "ariaSearchResultsStatus": "A keresĆ©s {0} talĆ”latot eredmĆ©nyezett {1} fĆ”jlban", "search.file.result": "{0} talĆ”lat {1} fĆ”jlban", "search.files.result": "{0} talĆ”lat {1} fĆ”jlban", "search.file.results": "{0} talĆ”lat {1} fĆ”jlban", "search.files.results": "{0} talĆ”lat {1} fĆ”jlban", - "search.folder.file.result": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", - "search.folder.files.result": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", - "search.folder.file.results": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", - "search.folder.files.results": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", - "search.folders.file.result": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", - "search.folders.files.result": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", - "search.folders.file.results": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", - "search.folders.files.results": "{0} talĆ”lat {1} fĆ”jlban, {2} mappĆ”ban", "searchWithoutFolder": "MĆ©g nincs mappa megnyitva. Jelenleg csak a nyitott fĆ”jlokban tƶrtĆ©nik keresĆ©s –", "openFolder": "Mappa megnyitĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/search/browser/searchWidget.i18n.json b/i18n/hun/src/vs/workbench/parts/search/browser/searchWidget.i18n.json index 1bc0f722bcd..f9f0ca59cc0 100644 --- a/i18n/hun/src/vs/workbench/parts/search/browser/searchWidget.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/search/browser/searchWidget.i18n.json @@ -11,5 +11,6 @@ "search.placeHolder": "KeresĆ©s", "label.Replace": "Csere: adja meg a cerekifejezĆ©st, majd nyomjon Entert a keresĆ©shez vagy Escape-et a megszakĆ­tĆ”shoz", "search.replace.placeHolder": "Csere", - "regexp.validationFailure": "A kifejezĆ©s mindenre illeszkedik" + "regexp.validationFailure": "A kifejezĆ©s mindenre illeszkedik", + "regexp.backreferenceValidationFailure": "A visszahivatkozĆ”s nem tĆ”mogatott" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/hun/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..dcb26c8240f --- /dev/null +++ b/i18n/hun/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Nincs {0} nevű mappa a munkaterületen" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 8a772b44962..7c0eceed2d8 100644 --- a/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "KódrĆ©szlet beszĆŗrĆ”sa" + "snippet.suggestions.label": "KódrĆ©szlet beszĆŗrĆ”sa", + "sep.userSnippet": "FelhasznĆ”lói kódrĆ©szletek", + "sep.extSnippet": "KiegĆ©szĆ­tők kódrĆ©szletei" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index f8980547dd7..b86aeaf6994 100644 --- a/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "Ismeretlen nyelv talĆ”lható a kƶvetkezőben: `contributes.{0}.language`. A megadott Ć©rtĆ©k: {1}", + "invalid.path.0": "HiĆ”nyzó karakterlĆ”nc a `contributes.{0}.path`-ban. A megadott Ć©rtĆ©k: {1}", + "invalid.path.1": "A `contributes.{0}.path` ({1}) nem a kiegĆ©szĆ­tő mappĆ”jĆ”n belül talĆ”lható ({2}). Emiatt előfordulhat, hogy a kiegĆ©szĆ­tő nem lesz hordozható.", + "vscode.extension.contributes.snippets": "KódrĆ©szleteket szolgĆ”ltat.", + "vscode.extension.contributes.snippets-language": "Azon nyelv azonosĆ­tója, amely szĆ”mĆ”ra szolgĆ”ltatva van ez a kódrĆ©szlet.", + "vscode.extension.contributes.snippets-path": "A kódrĆ©szlet-fĆ”jl elĆ©rĆ©si Ćŗtja. Az elĆ©rĆ©si Ćŗt relatĆ­v a kiegĆ©szĆ­tő mappĆ”jĆ”hoz, Ć©s Ć”ltalĆ”ban a kƶvetkezővel kezdődik: './snippets/',", + "badVariableUse": "A(z) '{0}' kiegĆ©szĆ­tőben egy vagy tƶbb kódrĆ©szlet nagy valószĆ­nűsĆ©ggel keveri a kódrĆ©szletvĆ”ltozók Ć©s a kódrĆ©szlet-helyjelƶlők fogalmĆ”t (tovĆ”bbi informĆ”ció a kƶvetkező oldalon talĆ”lható: https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax)", + "badFile": "A(z) \"{0}\" kódrĆ©szletet tartalmazó fĆ”jlt nem sikerült beolvasni.", "source.snippet": "FelhasznĆ”lói kódrĆ©szlet", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 0af66d78b7a..96726818200 100644 --- a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "A feladat kimenetĆ©nek megjelenĆ­tĆ©sĆ©re Ć©s adatbevitelĆ©re hasznĆ”lt panelt konfigurĆ”lja.", "JsonSchema.tasks.presentation.echo": "MeghatĆ”rozza, hogy a vĆ©grehajtott parancs ki van-e Ć­rva a terminĆ”lban. AlapĆ©rtelmezett Ć©rtĆ©ke true.", "JsonSchema.tasks.presentation.focus": "MeghatĆ”rozza, hogy a panel fókuszt kap-e. Az alapĆ©rtelmezett Ć©rtĆ©ke true. Ha true-ra van Ć”llĆ­tva, akkor a panel fel is lesz fedve.", + "JsonSchema.tasks.presentation.reveal.always": "A feladat vĆ©grehajtĆ”sakor mindig legyen felfedve a terminĆ”l.", + "JsonSchema.tasks.presentation.reveal.silent": "Csak akkor legyen felfedve a terminĆ”l, ha nincs problĆ©maillesztő tĆ”rsĆ­tva a feladathoz, Ć©s problĆ©ma tƶrtĆ©nik a vĆ©grehajtĆ”s sorĆ”n.", + "JsonSchema.tasks.presentation.reveal.never": "Soha ne legyen felfedve a terminĆ”l a feladat vĆ©grehajtĆ”sa sorĆ”n.", "JsonSchema.tasks.presentation.reveals": "MeghatĆ”rozza, hogy a feladatot futtató panel fel van-e fedve vagy sem. AlapĆ©rtelmezett Ć©rtĆ©ke \"always\".", "JsonSchema.tasks.presentation.instance": "MeghatĆ”rozza, hogy a panel meg van-e osztva a feladatok kƶzƶtt, ennek a feladatnak van-e dedikĆ”lva, vagy Ćŗj kĆ©szül minden egyes futtatĆ”s sorĆ”n.", "JsonSchema.tasks.terminal": "A terminal tulajdonsĆ”g elavult. HasznĆ”lja helyette a presentation tulajdonsĆ”got!", @@ -22,7 +25,8 @@ "JsonSchema.tasks.group.test": "A feladatot a 'TesztelĆ©si feladat futtatĆ”sa' parancson keresztül elĆ©rhető tesztelĆ©si feladatnak jelƶli meg.", "JsonSchema.tasks.group.none": "A feladatot egyetlen csoporthoz sem rendeli", "JsonSchema.tasks.group": "MeghatĆ”rozza a feladat vĆ©grehajtĆ”si csoportjĆ”t. A \"build\" esetĆ©n a buildelĆ©si csoportba, a \"test\" esetĆ©n a tesztelĆ©si csoportba kerül bele a feladat.", - "JsonSchema.tasks.type": "MeghatĆ”rozza, hogy a feladat folyamatkĆ©nt van-e vĆ©grehajtva vagy egy parancskĆ©nt a shellben. AlapĆ©rtelmetten folyamatkĆ©nt vannak vĆ©grehajtva.", + "JsonSchema.tasks.type": "MeghatĆ”rozza, hogy a feladat folyamatkĆ©nt van-e vĆ©grehajtva vagy egy parancskĆ©nt a shellben.", + "JsonSchema.tasks.label": "A feladat felhasznĆ”lói felületen megjelenő neve", "JsonSchema.version": "A konfigurĆ”ció verziószĆ”ma", "JsonSchema.tasks.identifier": "A feladat felhasznĆ”ló Ć”ltal definiĆ”lt azonosĆ­tója, amivel hivatkozni lehet a feladatra a lauch.json-ban vagy egy dependsOn-utasĆ­tĆ”sban.", "JsonSchema.tasks.taskLabel": "A feladat cĆ­mkĆ©je", diff --git a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 08f91f72770..ad07b544ef3 100644 --- a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Feladatok", - "ConfigureTaskRunnerAction.noWorkspace": "A feladatok csak egy munkaterület mappĆ”jĆ”ra vonatkozóan Ć©rhetők el.", - "ConfigureTaskRunnerAction.quickPick.template": "Feladatfuttató rendszer vĆ”lasztĆ”sa", - "ConfigureTaskRunnerAction.autoDetecting": "Feladatok automatikus felderĆ­tĆ©se a kƶvetkezőhƶz: {0}", - "ConfigureTaskRunnerAction.autoDetect": "A feladatfuttató rendszer automatikus felderĆ­tĆ©se nem sikerült. Az alapĆ©rtelmezett sablon hasznĆ”lata. Tekintse meg a feladatkimenetet a rĆ©szletekĆ©rt.", - "ConfigureTaskRunnerAction.autoDetectError": "A feladatfuttató rendszer automatikus felderĆ­tĆ©se hibĆ”kat eredmĆ©nyezett. Tekintse meg a feladatkimenetet a rĆ©szletekĆ©rt.", - "ConfigureTaskRunnerAction.failed": "Nem sikerült lĆ©trehozni a 'tasks.json' fĆ”jlt a '.vscode' mappĆ”ban. Tekintse meg a feladatkimenetet a rĆ©szletekĆ©rt.", - "ConfigureTaskRunnerAction.label": "Feladatfuttató rendszer beĆ”llĆ­tĆ”sa", + "ConfigureTaskRunnerAction.label": "Feladat beĆ”llĆ­tĆ”sa", "ConfigureBuildTaskAction.label": "BuildelĆ©si feladat beĆ”llĆ­tĆ”sa", "CloseMessageAction.label": "BezĆ”rĆ”s", "ShowTerminalAction.label": "TerminĆ”l megtekintĆ©se", @@ -19,12 +13,14 @@ "manyMarkers": "99+", "runningTasks": "Futó feladatok megjelenĆ­tĆ©se", "tasks": "Feladatok", - "TaskSystem.noHotSwap": "A feladatvĆ©grehajtó motor megvĆ”ltoztatĆ”sa a VS Code ĆŗjraindĆ­tĆ”sĆ”t igĆ©nyli. A módosĆ­tĆ”s figyelmen kĆ­vül van hagyva.", + "TaskSystem.noHotSwap": "A feladatvĆ©grehajtó motor megvĆ”ltoztatĆ”sa egy futó, aktĆ­v feladat esetĆ©n az ablak ĆŗjraindĆ­tĆ”sĆ”t igĆ©nyli.", + "TaskServer.folderIgnored": "A(z) {0} mappa figyelmen kĆ­vül van hagyva, mert 0.1.0-s verziójĆŗ feladatkonfigurĆ”ciót hasznĆ”l.", "TaskService.noBuildTask1": "Nincs buildelĆ©si feladat definiĆ”lva. Jelƶljƶn meg egy feladatot az 'isBuildCommand' tulajdonsĆ”ggal a tasks.json fĆ”jlban!", "TaskService.noBuildTask2": "Nincs buildelĆ©si feladat definiĆ”lva. Jelƶljƶn meg egy feladatot a 'build' csoporttal a tasks.json fĆ”jlban!", "TaskService.noTestTask1": "Nincs tesztelĆ©si feladat definiĆ”lva. Jelƶljƶn meg egy feladatot az 'isTestCommand' tulajdonsĆ”ggal a tasks.json fĆ”jlban!", "TaskService.noTestTask2": "Nincs tesztelĆ©si feladat definiĆ”lva. Jelƶljƶn meg egy feladatot a 'test' csoporttal a tasks.json fĆ”jlban!", "TaskServer.noTask": "A futtatni kĆ­vĆ”nt feladat ({0}) nem talĆ”lható.", + "TaskService.associate": "tĆ”rsĆ­tĆ”s", "TaskService.attachProblemMatcher.continueWithout": "FolytatĆ”s a feladat kimenetĆ©nek Ć”tkutatĆ”sa nĆ©lkül", "TaskService.attachProblemMatcher.never": "Soha ne kutassa Ć”t a feladat kimenetĆ©t", "TaskService.attachProblemMatcher.learnMoreAbout": "TovĆ”bbi informĆ”ciók a feladat kimenetĆ©nek Ć”tkutatĆ”sĆ”ról", @@ -35,7 +31,9 @@ "TaskSystem.activeSame.noBackground": "A(z) '{0}' feladat mĆ”r aktĆ­v. A feladat befejezĆ©sĆ©hez hasznĆ”lja `Feladat megszakĆ­tĆ”sa` parancsot a Feladatok menüből!", "TaskSystem.active": "MĆ”r fut egy feladat. SzakĆ­tsa meg, mielőtt egy mĆ”sik feladatot futtatna.", "TaskSystem.restartFailed": "Nem sikerült a(z) {0} feladat befejezĆ©se Ć©s ĆŗjraindĆ­tĆ”sa.", + "TaskService.noConfiguration": "Hiba: a(z) {0} feladatok felderĆ­tĆ©se nem szolgĆ”ltatott feladatot a kƶvetkező konfigurĆ”cióhoz:\n{1}\nA feladat figyelmen kĆ­vül lesz hagyva.\n", "TaskSystem.configurationErrors": "Hiba: a megadott feladatkonfigurĆ”cióban validĆ”ciós hibĆ”k vannak, Ć©s nem hasznĆ”lható. Előszƶr javĆ­tsa ezeket a hibĆ”kat!", + "taskService.ignoreingFolder": "FeladatkonfigurĆ”ció figyelmen kĆ­vül hagyva a munkaterület {0} nevű mappĆ”ja esetĆ©ben. Tƶbb mappĆ”s munkaterületen a feladatok tĆ”mogatĆ”sĆ”hoz az ƶsszes mappĆ”nak a 2.0-s verziójĆŗ feladatkonfigurĆ”ciót kell hasznĆ”lni.\n", "TaskSystem.invalidTaskJson": "Hiba. A tasks.json fĆ”jlban szintaktikai hibĆ”k talĆ”lhatók. JavĆ­tsa ezeket a hibĆ”kat feladatvĆ©grehajtĆ”s előtt.\n", "TaskSystem.runningTask": "MĆ”r fut egy feladat. SzeretnĆ© megszakĆ­tani?", "TaskSystem.terminateTask": "Felada&&t megszakĆ­tĆ”sa", @@ -47,24 +45,33 @@ "recentlyUsed": "legutóbb futtatott feladatok", "configured": "konfigurĆ”lt feladatok", "detected": "talĆ”lt feladatok", + "TaskService.ignoredFolder": "A kƶvetkező munkaterületi mappĆ”k figyelmen kĆ­vül vannak hagyva, mert 0.1.0-s verziójĆŗ feladatkonfigurĆ”ciót hasznĆ”lnak:", + "TaskService.notAgain": "Ne jelenĆ­tse meg Ćŗjra", + "TaskService.ok": "OK", + "TaskService.pickRunTask": "VĆ”lassza ki a futtatandó feladatot!", + "TaslService.noEntryToRun": "Nincs futtatandó feladat. Feladatok konfigurĆ”lĆ”sa...", "TaskService.fetchingBuildTasks": "BuildelĆ©si feladatok lekĆ©rĆ©se...", - "TaskService.noBuildTaskTerminal": "BuildelĆ©si feladat nem talĆ”lható. Futtassa a 'BuildelĆ©si feladat beĆ”llĆ­tĆ”sa' parancsot a lĆ©trehozĆ”shoz!", "TaskService.pickBuildTask": "VĆ”lassza ki a futtatandó buildelĆ©si feladatot!", + "TaskService.noBuildTask": "Nincs futtatandó buildelĆ©si feladat. Feladatok konfigurĆ”lĆ”sa...", "TaskService.fetchingTestTasks": "TesztelĆ©si feladatok lekĆ©rĆ©se...", - "TaskService.noTestTaskTerminal": "BuildelĆ©si feladat nem talĆ”lható. Futtassa a 'Feladatfuttató rendszer beĆ”llĆ­tĆ”sa' parancsot a lĆ©trehozĆ”shoz!", "TaskService.pickTestTask": "VĆ”lassza ki a futtatandó tesztelĆ©si feladatot", - "TaskService.noTaskRunning": "Jelenleg nem fut feladat.", + "TaskService.noTestTaskTerminal": "Nincs futtatandó tesztelĆ©si feladat. Feladatok konfigurĆ”lĆ”sa...", "TaskService.tastToTerminate": "VĆ”lassza ki a megszakĆ­tandó feladatot!", + "TaskService.noTaskRunning": "Jelenleg nem fut feladat", "TerminateAction.noProcess": "Az elindĆ­tott folyamat mĆ”r nem lĆ©tezik. Ha a feladat hĆ”ttĆ©rfeladatokat indĆ­tott, a VS Code-ból való kilĆ©pĆ©s Ć”rva folyamatokat eredmĆ©nyezhet. ", "TerminateAction.failed": "Nem sikerült megszakĆ­tani a futó feladatot", - "TaskService.noTaskToRestart": "Nincs ĆŗjraindĆ­tható feladat.", "TaskService.tastToRestart": "VĆ”lassza ki az ĆŗjraindĆ­tandó feladatot!", - "TaskService.defaultBuildTaskExists": "A(z) {0} mĆ”r meg van jelƶlve alapĆ©rtelmezett buildelĆ©si feladatkĆ©nt.", + "TaskService.noTaskToRestart": "Nincs ĆŗjraindĆ­tható feladat", + "TaskService.template": "VĆ”lasszon feladatsablont!", + "TaskService.createJsonFile": "Tasks.json fĆ”jl lĆ©trehozĆ”sa sablon alapjĆ”n", + "TaskService.openJsonFile": "Tasks.json-fĆ”jl megnyitĆ”sa", + "TaskService.pickTask": "VĆ”lassza ki a konfigurĆ”landó feladatot!", + "TaskService.defaultBuildTaskExists": "A(z) {0} mĆ”r meg van jelƶlve alapĆ©rtelmezett buildelĆ©si feladatnak", "TaskService.pickDefaultBuildTask": "VĆ”lassza ki az alpĆ©rtelmezett buildelĆ©si feladatkĆ©nt hasznĆ”lt feladatot!", "TaskService.defaultTestTaskExists": "A(z) {0} mĆ”r meg van jelƶlve alapĆ©rtelmezett tesztelĆ©si feladatkĆ©nt.", "TaskService.pickDefaultTestTask": "VĆ”lassza ki az alpĆ©rtelmezett tesztelĆ©si feladatkĆ©nt hasznĆ”lt feladatot!", - "TaskService.noTaskIsRunning": "Nem fut feladat.", "TaskService.pickShowTask": "VĆ”lassza ki a feladatot a kimenet megjelenĆ­tĆ©sĆ©hez!", + "TaskService.noTaskIsRunning": "Nem fut feladat", "ShowLogAction.label": "Feladatnapló megtekintĆ©se", "RunTaskAction.label": "Feladat futtatĆ”sa", "RestartTaskAction.label": "Futó feladat ĆŗjraindĆ­tĆ”sa...", diff --git a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index cbc547d3e4a..496170af36e 100644 --- a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Ismeretlen hiba tƶrtĆ©nt a feladat vĆ©grehajtĆ”sa kƶzben. RĆ©szletek a feladat kimeneti naplójĆ”ban talĆ”lhatók.", + "dependencyFailed": "Nem sikerült feloldani a(z) '{0}' függő feladatot a(z) '{1}' munkaterületi mappĆ”ban", "TerminalTaskSystem.terminalName": "Feladat – {0}", "reuseTerminal": "A terminĆ”l Ćŗjra lesz hasznosĆ­tva a feladatok Ć”ltal. Nyomjon meg egy billentyűt a bezĆ”rĆ”shoz.", "TerminalTaskSystem": "Rendszerparancsok nem hajthatók vĆ©gre UNC-meghajtókon.", diff --git a/i18n/hun/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/hun/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index cec5de6d410..45e04c9c1fc 100644 --- a/i18n/hun/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,6 +11,8 @@ "ConfigurationParser.unknownMatcherKind": "Figyelem: a megadott problĆ©maillesztő ismeretlen. A tĆ”mogatott tĆ­pusok: string | ProblemMatcher | (string | ProblemMatcher)[].\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "Hiba: Ć©rvĆ©nytelen problemMatcher-referencia: {0}\n", "ConfigurationParser.noTaskType": "Hiba: a feladatkonfigurĆ”ciónak rendelkeznie kell type tulajdonsĆ”ggal. A konfigurĆ”ció figyelmen kĆ­vül lesz hagyva.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "Hiba: nincs '{0}' azonosĆ­tójĆŗ feladattĆ­pus regisztrĆ”lva. Elfelejtett telepĆ­teni egy kiegĆ©szĆ­tőt, ami a feladat szolgĆ”ltatĆ”sƔƩrt felelős?", + "ConfigurationParser.missingRequiredProperty": "Hiba: a(z) '{0}' feladatkonfigurĆ”cióból hiĆ”nyzik a kƶtelező '{1}' tulajdonsĆ”g. A feladatkonfigurĆ”ció figyelmen kĆ­vül lesz hagyva.", "ConfigurationParser.notCustom": "Hiba: a feladat nem egyedi feladatkĆ©nt van definiĆ”lva. A konfigurĆ”ció figyelmen kĆ­vül lesz hagyva.\n{0}\n", "ConfigurationParser.noTaskName": "Hiba: a feladathoz meg kell adni a taskName tulajdonsĆ”got. A feladat figyelmen kĆ­vül lesz hagyva.\n{0}\n", "taskConfiguration.shellArgs": "FigyelmeztetĆ©s: a(z) '{0}' feladat egy rendszerparancs, Ć©s vagy a parancs nevĆ©ben vagy az argumentumok egyikĆ©ben escape nĆ©lküli szókƶz talĆ”lható. A megfelelő idĆ©zőjelezĆ©s Ć©rdekĆ©ben olvassza bele az argumentumokat a parancsba.", diff --git a/i18n/hun/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index ce7074ecb90..d2b84accaac 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "entryAriaLabel": "{0}, terminĆ”lvĆ”lasztó", + "termEntryAriaLabel": "{0}, terminĆ”lvĆ”lasztó", + "termCreateEntryAriaLabel": "{0}, Ćŗj terminĆ”l lĆ©trehozĆ”sa", + "'workbench.action.terminal.newplus": "$(plus) Új integrĆ”lt terminĆ”l lĆ©trehozĆ”sa", "noTerminalsMatching": "Nincs ilyen terminĆ”l", "noTerminalsFound": "Nincs megnyitott terminĆ”l" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 30ac3bd3127..9abe5fcaf6f 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -5,18 +5,19 @@ // Do not edit this file. It is machine generated. { "quickOpen.terminal": "Ɩsszes megnyitott terminĆ”l megjelenĆ­tĆ©se", + "terminal": "TerminĆ”l", "terminalIntegratedConfigurationTitle": "BeĆ©pĆ­tett terminĆ”l", "terminal.integrated.shell.linux": "A terminĆ”l Ć”ltal hasznĆ”lt shell elĆ©rĆ©si Ćŗtja Linuxon.", "terminal.integrated.shellArgs.linux": "Linux-terminĆ”l esetĆ©n hasznĆ”lt parancssori argumentumok.", "terminal.integrated.shell.osx": "A terminĆ”l Ć”ltal hasznĆ”lt shell elĆ©rĆ©si Ćŗtja OS X-en.", "terminal.integrated.shellArgs.osx": "OS X-terminĆ”l esetĆ©n hasznĆ”lt parancssori argumentumok.", + "terminal.integrated.shell.windows": "A terminĆ”l Ć”ltal hasznĆ”lt shell elĆ©rĆ©si Ćŗtja Windowson. A Windows beĆ©pĆ­tett shelljei (cmd, PowerShell vagy Bash on Ubuntu) hasznĆ”lata esetĆ©n kell megadni.", "terminal.integrated.shellArgs.windows": "Windows-terminĆ”l esetĆ©n hasznĆ”lt parancssori argumentumok.", "terminal.integrated.rightClickCopyPaste": "Ha be van Ć”llĆ­tva, megakadĆ”lyozza a helyi menü megjelenĆ©sĆ©t a terminĆ”lon tƶrtĆ©nő jobb kattintĆ”s esetĆ©n. Helyette mĆ”sol, ha van kijelƶlĆ©s, Ć©s beilleszt, ha nincs.", "terminal.integrated.fontFamily": "MeghatĆ”rozza a terminĆ”l betűtĆ­pusĆ”t. AlapĆ©rtelmezett Ć©rtĆ©ke az editor.fontFamily Ć©rtĆ©ke.", - "terminal.integrated.fontLigatures": "MeghatĆ”rozza, hogy a terminĆ”lban engedĆ©lyezve vannak-e a betűtĆ­pus-ligatĆŗrĆ”k.", "terminal.integrated.fontSize": "MeghatĆ”rozza a terminĆ”lban hasznĆ”lt betű mĆ©retĆ©t, pixelekben.", "terminal.integrated.lineHeight": "MeghatĆ”rozza a sormagassĆ”got a terminĆ”lban. A tĆ©nyleges mĆ©ret a megadott szĆ”m Ć©s a terminĆ”l betűmĆ©retĆ©nek szorzatĆ”ból jƶn ki.", - "terminal.integrated.enableBold": "EngedĆ©lyezve van-e a fĆ©lkƶvĆ©r szƶveg a terminĆ”lban. A műkƶdĆ©shez szüksĆ©ges, hogy a terminĆ”l shellje tĆ”mogassa a fĆ©lkƶvĆ©r betűket.", + "terminal.integrated.enableBold": "EngedĆ©lyezve van-e a fĆ©lkƶvĆ©r szƶveg a terminĆ”lban. A műkƶdĆ©shez szüksĆ©ges, hogy a terminĆ”l shell tĆ”mogassa a fĆ©lkƶvĆ©r betűket.", "terminal.integrated.cursorBlinking": "MeghatĆ”rozza, hogy a terminĆ”l kurzora villog-e.", "terminal.integrated.cursorStyle": "MeghatĆ”rozza a terminĆ”l kurzorĆ”nak stĆ­lusĆ”t.", "terminal.integrated.scrollback": "MeghatĆ”rozza, hogy a terminĆ”l legfeljebb hĆ”ny sort tĆ”rol a pufferben.", @@ -27,7 +28,6 @@ "terminal.integrated.env.osx": "A VS Code folyamatĆ”hoz hozzĆ”adott kƶrnyezeti vĆ”ltozókat tartalmazó objektum, amit az OS X-es terminĆ”l hasznĆ”l.", "terminal.integrated.env.linux": "A VS Code folyamatĆ”hoz hozzĆ”adott kƶrnyezeti vĆ”ltozókat tartalmazó objektum, amit a linuxos terminĆ”l hasznĆ”l.", "terminal.integrated.env.windows": "A VS Code folyamatĆ”hoz hozzĆ”adott kƶrnyezeti vĆ”ltozókat tartalmazó objektum, amit a windowsos terminĆ”l hasznĆ”l.", - "terminal": "TerminĆ”l", "terminalCategory": "TerminĆ”l", "viewCategory": "NĆ©zet" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 3abe72be506..c671a91c989 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,6 +7,7 @@ "workbench.action.terminal.toggleTerminal": "IntegrĆ”lt terminĆ”l be- Ć©s kikapcsolĆ”sa", "workbench.action.terminal.kill": "Az aktĆ­v terminĆ”lpĆ©ldĆ”ny leĆ”llĆ­tĆ”sa", "workbench.action.terminal.kill.short": "TerminĆ”l leĆ”llĆ­tĆ”sa", + "workbench.action.terminal.quickKill": "TerminĆ”lpĆ©ldĆ”ny leĆ”llĆ­tĆ”sa", "workbench.action.terminal.copySelection": "KijelƶlĆ©s mĆ”solĆ”sa", "workbench.action.terminal.selectAll": "Ɩsszes kijelƶlĆ©se", "workbench.action.terminal.deleteWordLeft": "Balra lĆ©vő szó tƶrlĆ©se", @@ -15,7 +16,6 @@ "workbench.action.terminal.new.short": "Új terminĆ”l", "workbench.action.terminal.focus": "VĆ”ltĆ”s a terminĆ”lra", "workbench.action.terminal.focusNext": "VĆ”ltĆ”s a kƶvetkező terminĆ”lra", - "workbench.action.terminal.focusAtIndex": "VĆ”ltĆ”s a(z) {0}. terminĆ”lra", "workbench.action.terminal.focusPrevious": "VĆ”ltĆ”s az előző terminĆ”lra", "workbench.action.terminal.paste": "BeillesztĆ©s az aktĆ­v terminĆ”lba", "workbench.action.terminal.DefaultShell": "AlapĆ©rtelmezett shell kivĆ”lasztĆ”sa", @@ -35,5 +35,8 @@ "workbench.action.terminal.rename": "ƁtnevezĆ©s", "workbench.action.terminal.rename.prompt": "Adja meg a terminĆ”l nevĆ©t!", "workbench.action.terminal.focusFindWidget": "VĆ”ltĆ”s a keresőmodulra", - "workbench.action.terminal.hideFindWidget": "Keresőmodul elrejtĆ©se" + "workbench.action.terminal.hideFindWidget": "Keresőmodul elrejtĆ©se", + "nextTerminalFindTerm": "Kƶvetkező keresĆ©si kifejezĆ©s megjelenĆ­tĆ©se", + "previousTerminalFindTerm": "Előző keresĆ©si kifejezĆ©s megjelenĆ­tĆ©se", + "quickOpenTerm": "AktĆ­v terminĆ”l vĆ”ltĆ”sa" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 62724fd2402..3471cfec5dc 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "A terminĆ”l előtĆ©rszĆ­ne.", "terminalCursor.foreground": "A terminĆ”l kurzorĆ”nak előtĆ©rszĆ­ne.", "terminalCursor.background": "A terminĆ”l kurzorĆ”nak hĆ”ttĆ©rszĆ­ne. LehetővĆ© teszik az olyan karakterek szĆ­nĆ©nek módosĆ­tĆ”sĆ”t, amelyek fƶlƶtt egy blokk-tĆ­pusĆŗ kurzor Ć”ll.", + "terminal.selectionBackground": "A terminĆ”lban kijelƶlt tartalom hĆ”ttĆ©rszĆ­ne.", "terminal.ansiColor": "A(z) '{0}' ANSI-szĆ­n a terminĆ”lban." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 15f0f130a04..1f792eaa3ac 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "MĆ”solĆ”s", - "createNewTerminal": "Új terminĆ”l", "paste": "BeillesztĆ©s", "selectAll": "Ɩsszes kijelƶlĆ©se", "clear": "TƶrlĆ©s" diff --git a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index babb2962c46..45f5c16180a 100644 --- a/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "Rendben, ne jelenĆ­tse meg Ćŗjra", "terminal.integrated.chooseWindowsShell": "VĆ”lassza ki a preferĆ”lt terminĆ”l shellt! Ez kĆ©sőbb módosĆ­tható a beĆ”llĆ­tĆ”sokban.", "terminalService.terminalCloseConfirmationSingular": "Van egy aktĆ­v terminĆ”lmunkamenet. SzeretnĆ© megszakĆ­tani?", - "terminalService.terminalCloseConfirmationPlural": "{0} aktĆ­v terminĆ”lmunkamenet van. SzeretnĆ© megszakĆ­tani?", - "yes": "Igen" + "terminalService.terminalCloseConfirmationPlural": "{0} aktĆ­v terminĆ”lmunkamenet van. SzeretnĆ© megszakĆ­tani?" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/hun/src/vs/workbench/parts/views/browser/views.i18n.json index 84a5f0798ce..f00a5e742b6 100644 --- a/i18n/hun/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/views/browser/views.i18n.json @@ -5,5 +5,5 @@ // Do not edit this file. It is machine generated. { "viewToolbarAriaLabel": "{0} művelet", - "removeView": "EltĆ”volĆ­tĆ”s az oldalsĆ”vról" + "hideView": "ElrejtĆ©s az oldalsĆ”vról" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 8c2f2f7b249..56418a5e967 100644 --- a/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "Start", "welcomePage.newFile": "Új fĆ”jl", "welcomePage.openFolder": "Mappa megnyitĆ”sa...", - "welcomePage.cloneGitRepository": "Git forrĆ”skódtĆ”r klónozĆ”sa...", + "welcomePage.addWorkspaceFolder": "Mappa hozzĆ”adĆ”sa a munkaterülethez...", "welcomePage.recent": "Legutóbbi", "welcomePage.moreRecent": "TovĆ”bb...", "welcomePage.noRecentFolders": "Nincsenek megnyitott mappĆ”k", diff --git a/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 7b98229452c..0ea6480ec65 100644 --- a/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Azure-kiegĆ©szĆ­tők megjelenĆ­tĆ©se", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/hun/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/hun/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 0120c6821a0..d6da0ebd901 100644 --- a/i18n/hun/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "InteraktĆ­v jĆ”tszótĆ©r", - "editorWalkThrough.title": "InteraktĆ­v jĆ”tszótĆ©r" + "editorWalkThrough.title": "InteraktĆ­v jĆ”tszótĆ©r", + "editorWalkThrough": "InteraktĆ­v jĆ”tszótĆ©r" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/hun/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..209303272b7 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "A beĆ”llĆ­tĆ”sok ƶsszefoglaló leĆ­rĆ”sa. Ez a cĆ­mke jelenik meg a beĆ”llĆ­tĆ”sok fĆ”jlban egy külƶnĆ”lló megjegyzĆ©skĆ©nt.", + "vscode.extension.contributes.configuration.properties": "A konfigurĆ”ciós tulajdonsĆ”gok leĆ­rĆ”sa.", + "scope.window.description": "Ablakspecifikus beĆ”llĆ­tĆ”s, ami konfigurĆ”lható a felhasznĆ”lói vagy munkaterületi beĆ”llĆ­tĆ”sokban.", + "scope.resource.description": "ErőforrĆ”sspecifikus beĆ”llĆ­tĆ”s, ami beĆ”llĆ­tható a felhasznĆ”lói, munkaterületi Ć©s mappaszintű beĆ”llĆ­tĆ”sokban.", + "scope.description": "A hatókƶr, amire a beĆ”llĆ­tĆ”s vonatkozik. Az elĆ©rhető hatókƶrƶk: `window` Ć©s `resource`.", + "vscode.extension.contributes.configuration": "KonfigurĆ”ciós beĆ”llĆ­tĆ”sokat szolgĆ”ltat.", + "invalid.title": "a 'configuration.title' Ć©rtĆ©kĆ©t karakterlĆ”nckĆ©nt kell megadni", + "vscode.extension.contributes.defaultConfiguration": "Adott nyelvre vonatkozóan szerkesztőbeĆ”llĆ­tĆ”sokat szolgĆ”ltat.", + "invalid.properties": "A 'configuration.properties' Ć©rtĆ©kĆ©t egy objektumkĆ©nt kell megadni", + "invalid.allOf": "A 'configuration.allOf' elavult, Ć©s hasznĆ”lata nem javasolt. Helyette tƶbb konfigurĆ”ciós szakaszt kell Ć”tadni tƶmbkĆ©nt a 'configuration' Ć©rtĆ©kekĆ©nt.", + "workspaceConfig.folders.description": "A munkaterületre betƶltƶtt mappĆ”k listĆ”ja.", + "workspaceConfig.path.description": "Egy fĆ”jl elĆ©rĆ©si Ćŗtja, pl. `/root/folderA` vagy `./folderA` relatĆ­v elĆ©rĆ©si Ćŗt esetĆ©n, ami a munkaterületfĆ”jl helye alapjĆ”n lesz feloldva.", + "workspaceConfig.name.description": "A mappa neve. Nem kƶtelező megadni.", + "workspaceConfig.uri.description": "A mappa URI-ja", + "workspaceConfig.settings.description": "Munkaterület-beĆ”llĆ­tĆ”sok", + "workspaceConfig.extensions.description": "Munkaterület-kiegĆ©szĆ­tők", + "unknownWorkspaceProperty": "Ismeretlen munkaterület-konfigurĆ”ciós tulajdonsĆ”g" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json index 300fc7b40dc..209303272b7 100644 --- a/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,14 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "KonfigurĆ”ciós beĆ”llĆ­tĆ”sokat szolgĆ”ltat.", "vscode.extension.contributes.configuration.title": "A beĆ”llĆ­tĆ”sok ƶsszefoglaló leĆ­rĆ”sa. Ez a cĆ­mke jelenik meg a beĆ”llĆ­tĆ”sok fĆ”jlban egy külƶnĆ”lló megjegyzĆ©skĆ©nt.", "vscode.extension.contributes.configuration.properties": "A konfigurĆ”ciós tulajdonsĆ”gok leĆ­rĆ”sa.", - "invalid.type": "ha meg van adva, a 'configuration.type' Ć©rtĆ©kĆ©t egy objektumkĆ©nt kell megadnii", + "scope.window.description": "Ablakspecifikus beĆ”llĆ­tĆ”s, ami konfigurĆ”lható a felhasznĆ”lói vagy munkaterületi beĆ”llĆ­tĆ”sokban.", + "scope.resource.description": "ErőforrĆ”sspecifikus beĆ”llĆ­tĆ”s, ami beĆ”llĆ­tható a felhasznĆ”lói, munkaterületi Ć©s mappaszintű beĆ”llĆ­tĆ”sokban.", + "scope.description": "A hatókƶr, amire a beĆ”llĆ­tĆ”s vonatkozik. Az elĆ©rhető hatókƶrƶk: `window` Ć©s `resource`.", + "vscode.extension.contributes.configuration": "KonfigurĆ”ciós beĆ”llĆ­tĆ”sokat szolgĆ”ltat.", "invalid.title": "a 'configuration.title' Ć©rtĆ©kĆ©t karakterlĆ”nckĆ©nt kell megadni", "vscode.extension.contributes.defaultConfiguration": "Adott nyelvre vonatkozóan szerkesztőbeĆ”llĆ­tĆ”sokat szolgĆ”ltat.", "invalid.properties": "A 'configuration.properties' Ć©rtĆ©kĆ©t egy objektumkĆ©nt kell megadni", - "workspaceConfig.id.description": "A munkaterület azonosĆ­tója. A munkaterület belső Ć”llapotĆ”nak tĆ”rolĆ”sĆ”ra van hasznĆ”lva, ami elveszhet módosĆ­tĆ”s esetĆ©n.", - "workspaceConfig.folders.description": "A munkaterületre betƶltƶtt mappĆ”k listĆ”ja. ElĆ©rĆ©si Ćŗtnak kell lennie, pl. `file:///root/folderA`.", - "workspaceConfig.settings.description": "Munkaterület-beĆ”llĆ­tĆ”sok" + "invalid.allOf": "A 'configuration.allOf' elavult, Ć©s hasznĆ”lata nem javasolt. Helyette tƶbb konfigurĆ”ciós szakaszt kell Ć”tadni tƶmbkĆ©nt a 'configuration' Ć©rtĆ©kekĆ©nt.", + "workspaceConfig.folders.description": "A munkaterületre betƶltƶtt mappĆ”k listĆ”ja.", + "workspaceConfig.path.description": "Egy fĆ”jl elĆ©rĆ©si Ćŗtja, pl. `/root/folderA` vagy `./folderA` relatĆ­v elĆ©rĆ©si Ćŗt esetĆ©n, ami a munkaterületfĆ”jl helye alapjĆ”n lesz feloldva.", + "workspaceConfig.name.description": "A mappa neve. Nem kƶtelező megadni.", + "workspaceConfig.uri.description": "A mappa URI-ja", + "workspaceConfig.settings.description": "Munkaterület-beĆ”llĆ­tĆ”sok", + "workspaceConfig.extensions.description": "Munkaterület-kiegĆ©szĆ­tők", + "unknownWorkspaceProperty": "Ismeretlen munkaterület-konfigurĆ”ciós tulajdonsĆ”g" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/hun/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index 459dfe9d8c1..138b32aacb8 100644 --- a/i18n/hun/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/hun/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "BeĆ”llĆ­tĆ”sok megnyitĆ”sa", + "openTasksConfiguration": "FeladatkonfigurĆ”ció megnyitĆ”sa", + "openLaunchConfiguration": "IndĆ­tĆ”si konfigurĆ”ció megnyitĆ”sa", "close": "BezĆ”rĆ”s", - "saveAndRetry": "BeĆ”llĆ­tĆ”sok mentĆ©se Ć©s ĆŗjrapróbĆ”lkozĆ”s", - "errorInvalidConfiguration": "Nem sikerült Ć­rni a beĆ”llĆ­tĆ”sokba. Nyissa meg a **FelhasznĆ”lói beĆ”llĆ­tĆ”sokat**, javĆ­tsa a hibĆ”kat Ć©s figyelmeztetĆ©seket a fĆ”jlban, majd próbĆ”lja Ćŗjra!", - "errorInvalidConfigurationWorkspace": "Nem sikerült Ć­rni a beĆ”llĆ­tĆ”sokba. Nyissa meg a **Munkaterült beĆ”llĆ­tĆ”sait**, javĆ­tsa a hibĆ”kat Ć©s figyelmeztetĆ©seket a fĆ”jlban, majd próbĆ”lja Ćŗjra!", - "errorConfigurationFileDirty": "Nem sikerült Ć­rni a beĆ”llĆ­tĆ”sokba, mert a fĆ”jl módosĆ­tva lett. Mentse a **FelhasznĆ”lói beĆ”llĆ­tĆ”sok** fĆ”jlt, majd próbĆ”lja Ćŗjra!", - "errorConfigurationFileDirtyWorkspace": "Nem sikerült Ć­rni a beĆ”llĆ­tĆ”sokba, mert a fĆ”jl módosĆ­tva lett. Mentse a **Munkaterület beĆ”llĆ­tĆ”sai** fĆ”jlt, majd próbĆ”lja Ćŗjra!", + "open": "BeĆ”llĆ­tĆ”sok megnyitĆ”sa", + "saveAndRetry": "MentĆ©s Ć©s ĆŗjrapróbĆ”lkozĆ”s", + "errorUnknownKey": "Nem sikerült Ć­rni a kƶvetkezőbe: {0}. A(z) {1} nem regisztrĆ”lt beĆ”llĆ­tĆ”s.", + "errorInvalidFolderConfiguration": "Nem sikerült Ć­rni a mappa beĆ”llĆ­tĆ”saiba, mert a(z) {0} nem tĆ”mogatott mappa tĆ­pusĆŗ erőforrĆ”sok hatókƶrĆ©ben.", + "errorInvalidUserTarget": "Nem sikerült Ć­rni a felhasznĆ”lói beĆ”llĆ­tĆ”sokba, mert a(z) {0} nem tĆ”mogatott globĆ”lis hatókƶrben.", + "errorInvalidWorkspaceTarget": "Nem sikerült Ć­rni a munkaterület beĆ”llĆ­tĆ”saiba, mert a(z) {0} nem tĆ”mogatott munkaterületi hatókƶrben egy tƶbb mappĆ”t tartalmazó munkaterületen.", + "errorInvalidFolderTarget": "Nem sikerült Ć­rni a mappa beĆ”llĆ­tĆ”saiba, mert nincs erőforrĆ”s megadva.", + "errorNoWorkspaceOpened": "Nem sikerült Ć­rni a kƶvetkezőbe: {0}. Nincs munkaterület megnyitva. Nyisson meg egy munkaterületet, majd próbĆ”lja Ćŗjra!", + "errorInvalidTaskConfiguration": "Nem sikerült Ć­rni a feladatkonfigurĆ”ciós fĆ”jlba. Nyissa meg az **FeladatkonfigurĆ”ciós** fĆ”jlt, javĆ­tsa a hibĆ”kat Ć©s figyelmeztetĆ©seket a fĆ”jlban, majd próbĆ”lja Ćŗjra!", + "errorInvalidLaunchConfiguration": "Nem sikerült Ć­rni az indĆ­tĆ”si fĆ”jlba. Nyissa meg az **IndĆ­tĆ”si** fĆ”jlt, javĆ­tsa a hibĆ”kat Ć©s figyelmeztetĆ©seket a fĆ”jlban, majd próbĆ”lja Ćŗjra!", + "errorInvalidConfiguration": "Nem sikerült Ć­rni a felhasznĆ”lói beĆ”llĆ­tĆ”sokba. Nyissa meg a **FelhasznĆ”lói beĆ”llĆ­tĆ”sokat**, javĆ­tsa a hibĆ”kat Ć©s figyelmeztetĆ©seket a fĆ”jlban, majd próbĆ”lja Ćŗjra!", + "errorInvalidConfigurationWorkspace": "Nem sikerült Ć­rni a munkaterület beĆ”llĆ­tĆ”saiba. Nyissa meg a **Munkaterület beĆ”llĆ­tĆ”sait**, javĆ­tsa a hibĆ”kat Ć©s figyelmeztetĆ©seket a fĆ”jlban, majd próbĆ”lja Ćŗjra!", + "errorInvalidConfigurationFolder": "Nem sikerült Ć­rni a mappa beĆ”llĆ­tĆ”saiba. Nyissa meg a **Mappa beĆ”llĆ­tĆ”sait**, javĆ­tsa a hibĆ”kat Ć©s figyelmeztetĆ©seket a fĆ”jlban, majd próbĆ”lja Ćŗjra!", + "errorTasksConfigurationFileDirty": "Nem sikerült Ć­rni a feladatkonfigurĆ”ciós fĆ”jlba, mert a fĆ”jl módosĆ­tva lett. Mentse a **FeladatkonfigurĆ”ciós** fĆ”jlt, majd próbĆ”lja Ćŗjra!", + "errorLaunchConfigurationFileDirty": "Nem sikerült Ć­rni az indĆ­tĆ”si fĆ”jlba, mert a fĆ”jl módosĆ­tva lett. Mentse az **IndĆ­tĆ”si konfigurĆ”ció** fĆ”jlt, majd próbĆ”lja Ćŗjra!", + "errorConfigurationFileDirty": "Nem sikerült Ć­rni a felhasznĆ”lói beĆ”llĆ­tĆ”sokba, mert a fĆ”jl módosĆ­tva lett. Mentse a **FelhasznĆ”lói beĆ”llĆ­tĆ”sok** fĆ”jlt, majd próbĆ”lja Ćŗjra!", + "errorConfigurationFileDirtyWorkspace": "Nem sikerült Ć­rni a munkaterületi beĆ”llĆ­tĆ”sokba, mert a fĆ”jl módosĆ­tva lett. Mentse a **Munkaterület beĆ”llĆ­tĆ”sai** fĆ”jlt, majd próbĆ”lja Ćŗjra!", + "errorConfigurationFileDirtyFolder": "Nem sikerült Ć­rni a mappa beĆ”llĆ­tĆ”saiba, mert a fĆ”jl módosĆ­tva lett. Mentse a **Mappa beĆ”llĆ­tĆ”sai** fĆ”jlt a(z) **{0}** mappĆ”ban, majd próbĆ”lja Ćŗjra!", "userTarget": "FelhasznĆ”lói beĆ”llĆ­tĆ”sok", "workspaceTarget": "Munkaterület-beĆ”llĆ­tĆ”sok", "folderTarget": "MappabeĆ”lĆ­ltĆ”sok" diff --git a/i18n/hun/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/hun/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..55c4947973b --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "bubbleTitle": "kiemelt elemeket tartalmaz" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/hun/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..4ffc18c313c --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "A kiegĆ©szĆ­tő gazdafolyamata nem idult el 10 mĆ”sodperben belül. ElkĆ©pzelhető, hogy megĆ”llt az első soron, Ć©s szüksĆ©ge van a hibakeresőre a folytatĆ”shoz.", + "extensionHostProcess.startupFail": "A kiegĆ©szĆ­tő gazdafolyamata nem idult el 10 mĆ”sodperben belül. Ez problĆ©ma lehet.", + "extensionHostProcess.error": "A kiegĆ©szĆ­tő gazdafolyamatĆ”tól hiba Ć©rkezett: {0}" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..e9cae50ed45 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "Hiba a(z) {0} feldolgozĆ”sa kƶzben: {1}.", + "fileReadFail": "A(z) ({0}) fĆ”jl nem olvasható: {1}.", + "jsonsParseFail": "Hiba a(z) {0} vagy {1} feldolgozĆ”sa kƶzben: {2}.", + "missingNLSKey": "A(z) {0} kulcshoz tartozó üzenet nem talĆ”lható." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..dd506bf2042 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "Fejlesztői eszkƶzƶk", + "restart": "KiegĆ©szĆ­tő gazdafolyamatĆ”nak ĆŗjraindĆ­tĆ”sa", + "extensionHostProcess.crash": "A kiegĆ©szĆ­tő gazdafolyamata vĆ”ratlanul leĆ”llt.", + "extensionHostProcess.unresponsiveCrash": "A kiegĆ©szĆ­tő gazdafolyamata le lett Ć”llĆ­tva, mert nem vĆ”laszolt.", + "overwritingExtension": "A(z) {0} kiegĆ©szĆ­tő felülĆ­rĆ”sa a kƶvetkezővel: {1}.", + "extensionUnderDevelopment": "A(z) {0} elĆ©rĆ©si Ćŗton talĆ”lható fejlesztői kiegĆ©szĆ­tő betƶltĆ©se" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/hun/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..f77948f5276 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "A fĆ”jl binĆ”risnak tűnik Ć©s nem nyitható meg szƶvegkĆ©nt" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json index f303a5e38e2..5dbccfabb8d 100644 --- a/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "ƉrvĆ©nytelen fĆ”jlerőforrĆ”s ({0})", - "fileIsDirectoryError": "A fĆ”jl egy kƶvtĆ”r ({0})", + "fileIsDirectoryError": "A fĆ”jl egy kƶnyvtĆ”r", "fileNotModifiedError": "A fĆ”jl azóta nem módosult", "fileTooLargeError": "A fĆ”jl tĆŗl nagy a megnyitĆ”shoz", "fileBinaryError": "A fĆ”jl binĆ”risnak tűnik Ć©s nem nyitható meg szƶvegkĆ©nt", "fileNotFoundError": "FĆ”jl nem talĆ”lható ({0})", + "fileExists": "A lĆ©trehozandó fĆ”jl mĆ”r lĆ©tezik ({0})", "fileMoveConflict": "Nem lehet Ć”thelyezni vagy mĆ”solni. A fĆ”jl mĆ”r lĆ©tezik a cĆ©lhelyen.", "unableToMoveCopyError": "Nem lehet Ć”thelyezni vagy mĆ”solni. A fĆ”jl felülĆ­rnĆ” a mappĆ”t, amiben talĆ”lható.", "foldersCopyError": "A munkaterületre nem mĆ”solhatók mappĆ”k. VĆ”lasszon ki egyedi fĆ”jlokat a mĆ”solĆ”shoz.", diff --git a/i18n/hun/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/hun/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 1618012de89..483d1f717cc 100644 --- a/i18n/hun/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/hun/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} – {1}", + "progress.subtitle": "{0} – {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index eba34a8381d..c5c7acc39f4 100644 --- a/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/hun/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "A szabĆ”ly betűtĆ­pusĆ”nak stĆ­lusa: 'italic', 'bold', 'underline', vagy ezek kombinĆ”ciója", - "schema.colors": "A szintaktikai kiemelĆ©shez hasznĆ”lt szĆ­nek", - "schema.properties.name": "A szabĆ”ly leĆ­rĆ”sa", - "schema.tokenColors.path": "A tmTheme-fĆ”jl elĆ©rĆ©si Ćŗtja (az aktuĆ”lis fĆ”jlhoz kĆ©pest relatĆ­van)" + "schema.token.settings": "A token szĆ­ne Ć©s stĆ­lusa.", + "schema.token.foreground": "A token előtĆ©rszĆ­ne.", + "schema.token.background.warning": "A tokenek hĆ”ttĆ©rszĆ­ne jelenleg nem tĆ”mogatott.", + "schema.token.fontStyle": "A szabĆ”ly betűtĆ­pusĆ”nak stĆ­lusa: 'italic', 'bold', 'underline', vagy ezek kombinĆ”ciója", + "schema.fontStyle.error": "A betűtĆ­pus stĆ­lusa 'italic', 'bold', 'underline', vagy ezek kombinĆ”ciója lehet.", + "schema.properties.name": "A szabĆ”ly leĆ­rĆ”sa.", + "schema.properties.scope": "Hatókƶrszelektor, amire ez a szabĆ”ly illeszkedik.", + "schema.tokenColors.path": "Egy tmTheme-fĆ”jl elĆ©rĆ©si Ćŗtja (az aktuĆ”lis fĆ”jlhoz kĆ©pest relatĆ­van).", + "schema.colors": "A szintaktikai kiemelĆ©shez hasznĆ”lt szĆ­nek" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index b93f26958fa..1a824863bdd 100644 --- a/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/hun/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "BetűkĆ©szlet hasznĆ”lata esetĆ©n a betűkĆ©szlet mĆ©rete a szƶveg betűkĆ©szletĆ©nek mĆ©retĆ©hez kĆ©pest, szĆ”zalĆ©kban. Ha nincs megadva, akkor a betűkĆ©szlet-definĆ­cióban megadott Ć©rtĆ©k van hasznĆ”lva.", "schema.fontId": "BetűkĆ©szlet hasznĆ”lata esetĆ©n a betűkĆ©szlet azonosĆ­tója. Ha nincs megadva, akkor az első betűkĆ©szlet-definĆ­ció van hasznĆ”lva.", "schema.light": "FĆ”jlikon-tĆ”rsĆ­tĆ”sok vilĆ”gos tĆ©mĆ”k hasznĆ”lata esetĆ©n. Nem kƶtelező megadni.", - "schema.highContrast": "FĆ”jlikon-tĆ”rsĆ­tĆ”sok nagy kontrasztĆŗ tĆ©mĆ”k hasznĆ”lata esetĆ©n. Nem kƶtelező megadni." + "schema.highContrast": "FĆ”jlikon-tĆ”rsĆ­tĆ”sok nagy kontrasztĆŗ tĆ©mĆ”k hasznĆ”lata esetĆ©n. Nem kƶtelező megadni.", + "schema.hidesExplorerArrows": "MeghatĆ”rozza, hogy a fĆ”jlkezelőben megjelenő nyilak el legyenek-e rejtve, amikor ez a tĆ©ma aktĆ­v." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 88c2c741155..d3d8dca1d71 100644 --- a/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "Hiba a JSON tĆ©mafĆ”jl feldolgozĆ”sa kƶzben: {0}", "error.invalidformat.colors": "Hiba a szĆ­ntĆ©mafĆ”jl feldolgozĆ”sa kƶzben: {0}. A 'colors' Ć©rtĆ©ke nem 'object' tĆ­pusĆŗ.", - "error.invalidformat.tokenColors": "Hiba a szĆ­ntĆ©mafĆ”jl feldolgozĆ”sa kƶzben: {0}. A 'tokenColors' tulajdonsĆ”g vagy egy szĆ­neket tartalmazó tƶmb legyen vagy egy TextMate tĆ©mafĆ”jl elĆ©rĆ©si Ćŗtja", + "error.invalidformat.tokenColors": "Hiba a szĆ­ntĆ©mafĆ”jl feldolgozĆ”sa kƶzben: {0}. A 'tokenColors' tulajdonsĆ”g vagy egy szĆ­neket tartalmazó tƶmb legyen vagy egy TextMate tĆ©mafĆ”jl elĆ©rĆ©si Ćŗtja.", "error.plist.invalidformat": "Hiba a tmTheme-fĆ”jl feldolgozĆ”sa kƶzben: {0}. A 'settings' nem egy tƶmb.", "error.cannotparse": "Hiba a tmTheme-fĆ”jl feldolgozĆ”sa kƶzben: {0}", "error.cannotload": "Hiba a(z) {0} tmTheme fĆ”jl betƶltĆ©se kƶzben: {1}" diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..4dace3f126c --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "TextMate-szĆ­ntĆ©mĆ”kat szolgĆ”ltat.", + "vscode.extension.contributes.themes.id": "Az ikontĆ©ma felhasznĆ”lói beĆ”llĆ­tĆ”sokban hasznĆ”lt azonosĆ­tója.", + "vscode.extension.contributes.themes.label": "A szĆ­ntĆ©ma felhasznĆ”lói felületen megjelenő neve.", + "vscode.extension.contributes.themes.uiTheme": "A szerkesztőablak kƶrül megjelenő elemek alaptĆ©mĆ”ja. A 'vs' a vilĆ”gos, a 'vs-dark' a sƶtĆ©t szĆ­ntĆ©ma, a 'hc-black' pedig a sƶtĆ©t, nagy kontrasztĆŗ tĆ©ma.", + "vscode.extension.contributes.themes.path": "A tmTheme-fĆ”jl elĆ©rĆ©si Ćŗtja. Az elĆ©rĆ©si Ćŗt relatĆ­v a kiegĆ©szĆ­tő mappĆ”jĆ”hoz kĆ©pest, Ć©s Ć”ltalĆ”ban './themes/themeFile.tmTheme'.", + "reqarray": "a(z) `{0}` kiegszĆ­tĆ©si pontot tƶmbkĆ©nt kell megadni", + "reqpath": "HiĆ”nyzó karakterlĆ”nc a `contributes.{0}.path`-ban. A megadott Ć©rtĆ©k: {1}", + "invalid.path.1": "A `contributes.{0}.path` ({1}) nem a kiegĆ©szĆ­tő mappĆ”jĆ”n belül talĆ”lható ({2}). Emiatt előfordulhat, hogy a kiegĆ©szĆ­tő nem lesz hordozható." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..91291d589e7 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Hiba a fĆ”jlikonokat leĆ­ró fĆ”jl feldolgozĆ”sa kƶzben: {0}" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..bdbe180864e --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "FĆ”jlikontĆ©mĆ”kat szolgĆ”ltat.", + "vscode.extension.contributes.iconThemes.id": "Az ikontĆ©ma felhasznĆ”lói beĆ”llĆ­tĆ”sokban hasznĆ”lt azonosĆ­tója.", + "vscode.extension.contributes.iconThemes.label": "Az ikontĆ©ma felhasznĆ”lói felületen megjelenő neve.", + "vscode.extension.contributes.iconThemes.path": "A tĆ©madefinĆ­ciós fĆ”jl elĆ©rĆ©si Ćŗtja. Az elĆ©rĆ©si Ćŗt relatĆ­v a kiegĆ©szĆ­tő mappĆ”jĆ”hoz kĆ©pest, Ć©s Ć”ltalĆ”ban ./icons/awesome-icon-theme.json'.", + "reqarray": "a(z) `{0}` kiegszĆ­tĆ©si pontot tƶmbkĆ©nt kell megadni", + "reqpath": "HiĆ”nyzó karakterlĆ”nc a `contributes.{0}.path`-ban. A megadott Ć©rtĆ©k: {1}", + "reqid": "HiĆ”nyzó karakterlĆ”nc a `contributes.{0}.id`-ben. A megadott Ć©rtĆ©k: {1}", + "invalid.path.1": "A `contributes.{0}.path` ({1}) nem a kiegĆ©szĆ­tő mappĆ”jĆ”n belül talĆ”lható ({2}). Emiatt előfordulhat, hogy a kiegĆ©szĆ­tő nem lesz hordozható." +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 46c356d2f23..f65a2da76bc 100644 --- a/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/hun/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,30 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "TextMate-szĆ­ntĆ©mĆ”kat szolgĆ”ltat.", - "vscode.extension.contributes.themes.id": "A tĆ©ma felhasznĆ”lói beĆ”llĆ­tĆ”sokban hasznĆ”lt azonosĆ­tója.", - "vscode.extension.contributes.themes.label": "A szĆ­ntĆ©ma felhasznĆ”lói felületen megjelenő neve.", - "vscode.extension.contributes.themes.uiTheme": "A szerkesztőablak kƶrül megjelenő elemek alaptĆ©mĆ”ja. A 'vs' a vilĆ”gos, a 'vs-dark' a sƶtĆ©t szĆ­ntĆ©ma, a 'hc-black' pedig a sƶtĆ©t, nagy kontrasztĆŗ tĆ©ma.", - "vscode.extension.contributes.themes.path": "A tmTheme-fĆ”jl elĆ©rĆ©si Ćŗtja. Az elĆ©rĆ©si Ćŗt relatĆ­v a kiegĆ©szĆ­tő mappĆ”jĆ”hoz kĆ©pest, Ć©s Ć”ltalĆ”ban './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "FĆ”jlikontĆ©mĆ”kat szolgĆ”ltat.", - "vscode.extension.contributes.iconThemes.id": "Az ikontĆ©ma felhasznĆ”lói beĆ”llĆ­tĆ”sokban hasznĆ”lt azonosĆ­tója.", - "vscode.extension.contributes.iconThemes.label": "Az ikontĆ©ma felhasznĆ”lói felületen megjelenő neve.", - "vscode.extension.contributes.iconThemes.path": "A tĆ©madefinĆ­ciós fĆ”jl elĆ©rĆ©si Ćŗtja. Az elĆ©rĆ©si Ćŗt relatĆ­v a kiegĆ©szĆ­tő mappĆ”jĆ”hoz kĆ©pest, Ć©s Ć”ltalĆ”ban ./icons/awesome-icon-theme.json'.", "migration.completed": "Új tĆ©mabeĆ”llĆ­tĆ”sok lettek hozzĆ”adva a felhasznĆ”lói beĆ”llĆ­tĆ”sokhoz. BiztonsĆ”gi mentĆ©s a kƶvetkező helyen Ć©rhető el: {0}.", "error.cannotloadtheme": "Nem sikerült betƶlteni a(z) '{0}' tĆ©mĆ”t: {1}.", - "reqarray": "a(z) `{0}` kiegszĆ­tĆ©si pontot tƶmbkĆ©nt kell megadni", - "reqpath": "HiĆ”nyzó karakterlĆ”nc a `contributes.{0}.path`-ban. A megadott Ć©rtĆ©k: {1}", - "invalid.path.1": "A `contributes.{0}.path` ({1}) nem a kiegĆ©szĆ­tő mappĆ”jĆ”n belül talĆ”lható ({2}). Emiatt előfordulhat, hogy a kiegĆ©szĆ­tő nem lesz hordozható.", - "reqid": "HiĆ”nyzó karakterlĆ”nc a `contributes.{0}.id`-ben. A megadott Ć©rtĆ©k: {1}", "error.cannotloadicontheme": "Nem sikerült megnyitni a(z) '{0}' tĆ©mĆ”t", - "error.cannotparseicontheme": "Hiba a fĆ”jlikonokat leĆ­ró fĆ”jl feldolgozĆ”sa kƶzben: {0}", "colorTheme": "MeghatĆ”rozza a munkaterületen hasznĆ”lt szĆ­ntĆ©mĆ”t.", "colorThemeError": "A tĆ©ma ismeretlen vagy nincs telepĆ­tve.", "iconTheme": "MeghatĆ”rozza a munkaterületen hasznĆ”lt ikontĆ©mĆ”t. 'null' Ć©rtĆ©k esetĆ©n nem jelenik meg egyetlen fĆ”jlikon sem.", "noIconThemeDesc": "Nincsenek fĆ”jlikonok", "iconThemeError": "A fĆ”jlikontĆ©ma ismeretlen vagy nincs telepĆ­tve.", "workbenchColors": "FelülĆ­rja az aktuĆ”lis szĆ­ntĆ©mĆ”ban definiĆ”lt szĆ­neket.", - "workbenchColors.deprecated": "A beĆ”llĆ­tĆ”s mĆ”r nem kĆ­sĆ©rleti, Ć©s Ć”t lett nevezve 'workbench.colorCustomizations'-re.", - "workbenchColors.deprecatedDescription": "HasznĆ”lja a 'workbench.colorCustomizations' tulajdonsĆ”got helyette.", - "editorColors": "FelülĆ­rja az aktuĆ”lis szĆ­ntĆ©mĆ”ban definiĆ”lt, szerkesztőablakhoz kapcsolódó szĆ­neket Ć©s betűstĆ­lusokat." + "editorColors": "FelülĆ­rja az aktuĆ”lis szĆ­ntĆ©mĆ”ban definiĆ”lt, szerkesztőablakhoz kapcsolódó szĆ­neket Ć©s betűstĆ­lusokat.", + "editorColors.comments": "MeghatĆ”rozza a megjegyzĆ©sek szĆ­nĆ©t Ć©s stĆ­lusĆ”t.", + "editorColors.strings": "MeghatĆ”rozza a sztringliterĆ”lok szĆ­nĆ©t Ć©s stĆ­lusĆ”t.", + "editorColors.keywords": "MeghatĆ”rozza a kulcsszavak szĆ­nĆ©t Ć©s stĆ­lusĆ”t.", + "editorColors.numbers": "MeghatĆ”rozza a szĆ”mliterĆ”lok szĆ­nĆ©t Ć©s stĆ­lusĆ”t.", + "editorColors.types": "MeghatĆ”rozza a tĆ­pusdeklarĆ”ciók Ć©s -referenciĆ”k szĆ­nĆ©t Ć©s stĆ­lusĆ”t.", + "editorColors.functions": "MeghatĆ”rozza a függvĆ©nydeklarĆ”ciók Ć©s -referenciĆ”k szĆ­nĆ©t Ć©s stĆ­lusĆ”t.", + "editorColors.variables": "MeghatĆ”rozza a vĆ”ltozódeklarĆ”ciók Ć©s -referenciĆ”k szĆ­nĆ©t Ć©s stĆ­lusĆ”t.", + "editorColors.textMateRules": "SzĆ­nek Ć©s stĆ­lusok beĆ”llĆ­tĆ”sa textmate tĆ©mĆ”zĆ”si szabĆ”lyok alapjĆ”n (haladó)." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/hun/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..068445ae82b --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "Nem sikerült Ć­rni a munkaterület konfigurĆ”ciós fĆ”jljĆ”ba. Nyissa meg a fĆ”jlt, javĆ­tsa a benne talĆ”lható hibĆ”kat Ć©s figyelmeztetĆ©seket, majd próbĆ”lja Ćŗjra!", + "errorWorkspaceConfigurationFileDirty": "Nem sikerült Ć­rni a munkaterület konfigurĆ”ciós fĆ”jljĆ”ba, mert módosĆ­tva lett. Mentse, majd próbĆ”lja Ćŗjra!", + "openWorkspaceConfigurationFile": "Munkaterület konfigurĆ”ciós fĆ”jljĆ”nak megnyitĆ”sa", + "close": "BezĆ”rĆ”s", + "enterWorkspace.close": "BezĆ”rĆ”s", + "enterWorkspace.dontShowAgain": "Ne jelenĆ­tse meg Ćŗjra", + "enterWorkspace.moreInfo": "TovĆ”bbi informĆ”ció", + "enterWorkspace.prompt": "Tudjon meg tƶbbet arról, hogyan dolgozhat egyszerre tƶbb mappĆ”val a VS Code-ban!" +} \ No newline at end of file diff --git a/i18n/ita/extensions/azure-account/out/azure-account.i18n.json b/i18n/ita/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..7417dd475b9 --- /dev/null +++ b/i18n/ita/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "Copia e apri", + "azure-account.close": "Chiudi", + "azure-account.login": "Accedi", + "azure-account.loginFirst": "Non ĆØ stato eseguito l'accesso. Eseguirlo.", + "azure-account.userCodeFailed": "L'acquisizione del codice utente non ĆØ riuscita", + "azure-account.tokenFailed": "Acquisizione del token con il codice dispositivo", + "azure-account.tokenFromRefreshTokenFailed": "Acquisizione del token con il token di aggiornamento" +} \ No newline at end of file diff --git a/i18n/ita/extensions/azure-account/out/extension.i18n.json b/i18n/ita/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..a89b7f23c89 --- /dev/null +++ b/i18n/ita/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: accesso...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index da8de5ed00e..f99b5799775 100644 --- a/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/ita/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "ad esempio myFile.txt", - "activeEditorMedium": "ad esempio myFolder/myFile.txt", - "activeEditorLong": "ad esempio /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "ad es. myFolder1, myFolder2, myFolder3", - "rootPath": "ad esempio /Users/Development/myProject", - "folderName": "ad es. myFolder", - "folderPath": "ad es. /Users/Development/myFolder", + "activeEditorShort": "il nome del file (ad esempio MyFile.txt)", + "activeEditorMedium": "il percorso del file relativo alla cartella dell'area di lavoro (ad es. myFolder/myFile.txt)", + "activeEditorLong": "il percorso completo del file (ad es. /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nome dell'area di lavoro (ad es. myFolder o myWorkspace)", + "rootPath": "percorso dell'area di lavoro (ad es. /Users/Development/myWorkspace)", + "folderName": "nome della cartella dell'area di lavoro in cui ĆØ contenuto il file (ad es. myFolder)", + "folderPath": "percorso della cartella dell'area di lavoro in cui ĆØ contenuto il file (ad es. /Users/Development/myFolder)", "appName": "ad esempio VS Code", "dirty": "un indicatore dirty se l'editor attivo ĆØ dirty", "separator": "un separatore condizionale (' - ') visualizzato solo se circondato da variabili con valori", diff --git a/i18n/ita/extensions/css/package.i18n.json b/i18n/ita/extensions/css/package.i18n.json index 5c004d473e5..f3beed19120 100644 --- a/i18n/ita/extensions/css/package.i18n.json +++ b/i18n/ita/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "Numero di parametri non valido", "css.lint.boxModel.desc": "Non usare width o height con padding o border", "css.lint.compatibleVendorPrefixes.desc": "Quando si usa un prefisso specifico del fornitore, assicurarsi di includere anche tutte le altre proprietĆ  specifiche del fornitore", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "ProprietĆ  specifica del fornitore sconosciuta.", "css.lint.vendorPrefix.desc": "Quando si usa un prefisso specifico del fornitore, includere anche la proprietĆ  standard", "css.lint.zeroUnits.desc": "Non ĆØ necessaria alcuna unitĆ  per lo zero", + "css.trace.server.desc": "Traccia la comunicazione tra VS Code e il server del linguaggio CSS.", + "css.validate.title": "Controlla la convalida CSS e le gravitĆ  dei problemi.", "css.validate.desc": "Abilita o disabilita tutte le convalide", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "Numero di parametri non valido", "less.lint.boxModel.desc": "Non usare width o height con padding o border", "less.lint.compatibleVendorPrefixes.desc": "Quando si usa un prefisso specifico del fornitore, assicurarsi di includere anche tutte le altre proprietĆ  specifiche del fornitore", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "ProprietĆ  specifica del fornitore sconosciuta.", "less.lint.vendorPrefix.desc": "Quando si usa un prefisso specifico del fornitore, includere anche la proprietĆ  standard", "less.lint.zeroUnits.desc": "Non ĆØ necessaria alcuna unitĆ  per lo zero", + "less.validate.title": "Controlla la convalida LESS e le gravitĆ  dei problemi.", "less.validate.desc": "Abilita o disabilita tutte le convalide", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "Numero di parametri non valido", "scss.lint.boxModel.desc": "Non usare width o height con padding o border", "scss.lint.compatibleVendorPrefixes.desc": "Quando si usa un prefisso specifico del fornitore, assicurarsi di includere anche tutte le altre proprietĆ  specifiche del fornitore", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "ProprietĆ  specifica del fornitore sconosciuta.", "scss.lint.vendorPrefix.desc": "Quando si usa un prefisso specifico del fornitore, includere anche la proprietĆ  standard", "scss.lint.zeroUnits.desc": "Non ĆØ necessaria alcuna unitĆ  per lo zero", + "scss.validate.title": "Controlla la convalida SCSS e le gravitĆ  dei problemi.", "scss.validate.desc": "Abilita o disabilita tutte le convalide", "less.colorDecorators.enable.desc": "Abilita o disabilita gli elementi Decorator di tipo colore", "scss.colorDecorators.enable.desc": "Abilita o disabilita gli elementi Decorator di tipo colore", - "css.colorDecorators.enable.desc": "Abilita o disabilita gli elementi Decorator di tipo colore" + "css.colorDecorators.enable.desc": "Abilita o disabilita gli elementi Decorator di tipo colore", + "css.colorDecorators.enable.deprecationMessage": "L'impostazione `css.colorDecorators.enable` ĆØ stata deprecata e sostituita da `editor.colorDecorators`.", + "scss.colorDecorators.enable.deprecationMessage": "L'impostazione `scss.colorDecorators.enable` ĆØ stata deprecata e sostituita da `editor.colorDecorators`.", + "less.colorDecorators.enable.deprecationMessage": "L'impostazione `less.colorDecorators.enable` ĆØ stata deprecata e sostituita da `editor.colorDecorators`." } \ No newline at end of file diff --git a/i18n/ita/extensions/emmet/package.i18n.json b/i18n/ita/extensions/emmet/package.i18n.json index 702045560ca..d4e654204c0 100644 --- a/i18n/ita/extensions/emmet/package.i18n.json +++ b/i18n/ita/extensions/emmet/package.i18n.json @@ -4,9 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "Esegui il wrapping con l'abbreviazione", + "command.wrapIndividualLinesWithAbbreviation": "Esegui il wrapping di singole righe con l'abbreviazione", "command.removeTag": "Rimuovi Tag", "command.updateTag": "Aggiorna tag", "command.matchTag": "Vai alla coppia corrispondente", + "command.balanceIn": "Corrispondenza (interna)", + "command.balanceOut": "Corrispondenza (esterna)", "command.prevEditPoint": "Vai al punto di modifica precedente", "command.nextEditPoint": "Vai al punto di modifica successivo", "command.mergeLines": "Esegui merge delle righe", @@ -16,10 +20,34 @@ "command.toggleComment": "Attiva/Disattiva commento", "command.evaluateMathExpression": "Valuta espressione matematica", "command.updateImageSize": "Aggiorna dimensioni immagine", + "command.reflectCSSValue": "Ricopia il valore CSS", "command.incrementNumberByOne": "Aumenta di 1", "command.decrementNumberByOne": "Riduci di 1", "command.incrementNumberByOneTenth": "Aumenta di 0,1", "command.decrementNumberByOneTenth": "Riduci di 0,1", "command.incrementNumberByTen": "Aumenta di 10", - "command.decrementNumberByTen": "Riduci di 10" + "command.decrementNumberByTen": "Riduci di 10", + "emmetSyntaxProfiles": "Consente di definire il profilo per la sintassi specificata oppure di usare un profilo personalizzato con regole specifiche.", + "emmetExclude": "Una matrice di linguaggi dove le abbreviazioni Emmet non dovrebbero essere espanse.", + "emmetExtensionsPath": "Percorso di una cartella contenente profili e snippet Emmet.'", + "emmetShowExpandedAbbreviation": "Mostra le abbreviazioni Emmet espanse come suggerimenti.\nL'opzione \"inMarkupAndStylesheetFilesOnly\" si applica a html, haml, jade, slim, xml, xsl, css, scss, sass, less e stylus.\nL'opzione \"sempre\" (always) si applica a tutte le parti del file indipendentemente dal markup/css.", + "emmetShowAbbreviationSuggestions": "Mostra possibili abbreviazioni Emmet come suggerimenti. Non si applica a fogli di stile o quando emmet.showExpandedAbbreviation ĆØ impostata a \"mai\" (never).", + "emmetIncludeLanguages": "Abilita le abbreviazioni Emmet in linguaggi che non sono normalmente supportati. Qui si può aggiungere un mapping tra il linguaggio ed il linguaggio supportato da Emmet.\n Ad esempio: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "Variabili da utilizzare negli snippet Emmet", + "emmetTriggerExpansionOnTab": "Se abilitate, le abbreviazioni Emmet vengono espanse quando si preme TAB.", + "emmetPreferences": "Preferenze usate per modificare il comportamento di alcune azioni e i resolver di Emmet.", + "emmetPreferencesIntUnit": "UnitĆ  di misura predefinita per i valori integer", + "emmetPreferencesFloatUnit": "UnitĆ  di misura predefinita per i valori float", + "emmetPreferencesCssAfter": "Simbolo da inserire alla fine della proprietĆ  CSS quando si espandono le abbreviazioni CSS", + "emmetPreferencesSassAfter": "Simbolo da inserire alla fine della proprietĆ  CSS quando si espandono le abbreviazioni CSS nei file Sass", + "emmetPreferencesStylusAfter": "Simbolo da inserire alla fine della proprietĆ  CSS quando si espandono le abbreviazioni CSS nei file Stylus", + "emmetPreferencesCssBetween": "Simbolo da inserire tra la proprietĆ  CSS e il valore quando si espandono le abbreviazioni CSS", + "emmetPreferencesSassBetween": "Simbolo da inserire tra la proprietĆ  CSS e il valore quando si espandono le abbreviazioni CSS nei file Sass", + "emmetPreferencesStylusBetween": "Simbolo da inserire tra la proprietĆ  CSS e il valore quando si espandono le abbreviazioni CSS nei file Stylus", + "emmetShowSuggestionsAsSnippets": "Se ĆØ true, i suggerimenti Emmet verranno visualizzati come frammenti consentendo di ordinarli in base all'impostazione editor.snippetSuggestions.", + "emmetPreferencesBemElementSeparator": "Separatore di elementi utilizzati per le classi quando si utilizza il filtro BEM", + "emmetPreferencesBemModifierSeparator": "Separatore di modificatore utilizzato per le classi quando si utilizza il filtro BEM", + "emmetPreferencesFilterCommentBefore": "Una definizione di commento che deve essere inserita prima dell'elemento corrispondente quando viene applicato il filtro commenti.", + "emmetPreferencesFilterCommentAfter": "Una definizione di commento che deve essere posizionato dopo l'elemento corrispondente quando viene applicato il filtro commenti.", + "emmetPreferencesFilterCommentTrigger": "Un elenco delimitato da virgole di nomi di attributi che dovrebbero esistere come abbreviazione per il filtro commenti da applicare" } \ No newline at end of file diff --git a/i18n/ita/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/ita/extensions/extension-editing/out/extensionLinter.i18n.json index 4fb28078ec9..a8b4072cafe 100644 --- a/i18n/ita/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/ita/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "Le immagini devono utilizzare il protocollo HTTPS.", "svgsNotValid": "Immagini di tipo SVG non sono una fonte valida.", "embeddedSvgsNotValid": "Immagini SVG incorporate non sono una fonte valida.", - "dataUrlsNotValid": "URL di dati non sono una fonte valida per le immagini." + "dataUrlsNotValid": "URL di dati non sono una fonte valida per le immagini.", + "relativeUrlRequiresHttpsRepository": "Immagini con URL relative richiedono di specificare un repository con protocollo HTTPS in package.json.", + "relativeIconUrlRequiresHttpsRepository": "Un'icona richiede di specificare un repository con protocollo HTTPS in questo package.json.", + "relativeBadgeUrlRequiresHttpsRepository": "Notifiche con URL relativo richiedono di specificare un repository con protocollo HTTPS in questo package.json." } \ No newline at end of file diff --git a/i18n/ita/extensions/git/out/commands.i18n.json b/i18n/ita/extensions/git/out/commands.i18n.json index 26d0cd57ac2..09e5850f8cd 100644 --- a/i18n/ita/extensions/git/out/commands.i18n.json +++ b/i18n/ita/extensions/git/out/commands.i18n.json @@ -6,21 +6,39 @@ { "tag at": "Tag in {0}", "remote branch at": "Ramo remoto in {0}", + "create branch": "$(plus) Crea nuovo branch", "repourl": "URL del repository", "parent": "Directory padre", "cloning": "Clonazione del repository GIT...", "openrepo": "Apri repository", "proposeopen": "Aprire il repository clonato?", + "init repo": "Inizializza repository", + "create repo": "Inizializza repository", + "are you sure": "Questo creerĆ  un repository Git in '{0}'. Sei sicuro di voler continuare?", "HEAD not available": "La versione HEAD di '{0}' non ĆØ disponibile.", + "confirm stage files with merge conflicts": "Preparare per il commit {0} file con conflitti di merge?", + "confirm stage file with merge conflicts": "Preparare per il commit {0} con conflitti di merge?", + "yes": "SƬ", "confirm revert": "Ripristinare le modifiche selezionate in {0}?", "revert": "Annulla modifiche", + "discard": "Rimuovi modifiche", + "confirm delete": "ELIMINARE {0}?", + "delete file": "Elimina file", "confirm discard": "Rimuovere le modifiche in {0}?", "confirm discard multiple": "Rimuovere le modifiche in {0} file?", - "discard": "Rimuovi modifiche", - "confirm discard all": "Sei sicuro di voler annullare TUTTE le modifiche? Quest'azione ĆØ IRREVERSIBILE!", - "discardAll": "Rimuovi TUTTE le modifiche", + "warn untracked": "Verranno ELIMINATI {0} file di cui non viene tenuta traccia.", + "confirm discard all single": "Rimuovere le modifiche in {0}?", + "confirm discard all": "Rimuovere TUTTE le modifiche apportate in {0} file?\nQuesta operazione ĆØ IRREVERSIBILE.\nIl working set corrente andrĆ  PERSO PER SEMPRE.", + "discardAll multiple": "Rimuovi 1 file", + "discardAll": "Rimuovi tutti i {0} file", + "confirm delete multiple": "ELIMINARE {0} file?", + "delete files": "Elimina file", + "there are untracked files single": "Se rimosso, il file seguente di cui non viene tenuta traccia verrĆ  ELIMINATO DAL DISCO: {0}.", + "there are untracked files": "Se rimossi, {0} file di cui non viene tenuta traccia verranno ELIMINATI DAL DISCO.", + "confirm discard all 2": "{0}\n\nQuesta operazione ĆØ IRREVERSIBILE. Il working set corrente andrĆ  PERSO PER SEMPRE.", + "yes discard tracked": "Rimuovi 1 file di cui viene tenuta traccia", + "yes discard tracked multiple": "Rimuovi {0} file di cui viene tenuta traccia", "no staged changes": "Non ci sono modifiche in stage di cui eseguire il commit.\n\nSI desidera mettere in stage automaticamente tutte le modifiche ed eseguirne il commit direttamente?", - "yes": "SƬ", "always": "Sempre", "no changes": "Non ci sono modifiche di cui eseguire il commit.", "commit message": "Messaggio di commit", @@ -33,16 +51,25 @@ "delete branch": "Elimina ramo", "select a branch to merge from": "Selezionare un ramo da cui eseguire il merge", "merge conflicts": "Ci sono conflitti di merge. Risolverli prima di eseguire commit.", + "tag name": "Nome del tag", + "provide tag name": "Specificare un nome di tag", + "tag message": "Messaggio", + "provide tag message": "Specificare un messaggio per aggiungere un'annotazione per il tag", "no remotes to pull": "Il repository non contiene elementi remoti configurati come origini del pull.", "pick remote pull repo": "Selezionare un repository remoto da cui effettuare il pull del ramo", "no remotes to push": "Il repository non contiene elementi remoti configurati come destinazione del push.", + "push with tags success": "Il push con tag ĆØ riuscito.", "nobranch": "Estrarre un ramo per eseguire il push in un elemento remoto.", "pick remote": "Selezionare un repository remoto in cui pubblicare il ramo '{0}':", "sync is unpredictable": "Questa azione consentirĆ  di effettuare il push e il pull di commit da e verso '{0}'.", "ok": "OK", "never again": "OK, non visualizzare più", "no remotes to publish": "Il repository non contiene elementi remoti configurati come destinazione della pubblicazione.", - "disabled": "GIT ĆØ disabilitato oppure non supportato in quest'area di lavoro", + "no changes stash": "Non ci sono modifiche da accantonare.", + "provide stash message": "Specificare un messaggio di accantonamento (facoltativo)", + "stash message": "Messaggio di accantonamento", + "no stashes": "Non ci sono accantonamenti da ripristinare.", + "pick stash to pop": "Scegli un accantonamento da prelevare", "clean repo": "Pulire l'albero di lavoro del repository prima dell'estrazione.", "cant push": "Impossibile effettuare il push in remoto. Effettua prima un 'pull' per integrare le tue modifiche.", "git error details": "GIT: {0}", diff --git a/i18n/ita/extensions/git/out/model.i18n.json b/i18n/ita/extensions/git/out/model.i18n.json index 5cfce3e0844..22eb58052df 100644 --- a/i18n/ita/extensions/git/out/model.i18n.json +++ b/i18n/ita/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Apri", - "merge changes": "Esegui merge delle modifiche", - "staged changes": "Modifiche preparate per il commit", - "changes": "Modifiche", - "ok": "OK", - "neveragain": "Non visualizzare più questo messaggio", - "huge": "Il repository git '{0}' ha troppe modifiche attive - verrĆ  attivato solo un sottoinsieme delle funzionalitĆ  di Git." + "no repositories": "Non ci sono repository disponibili", + "pick repo": "Scegli un repository" } \ No newline at end of file diff --git a/i18n/ita/extensions/git/out/repository.i18n.json b/i18n/ita/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..0b2210016a0 --- /dev/null +++ b/i18n/ita/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "Apri", + "index modified": "Indice modificato", + "modified": "Modificato", + "index added": "Indice aggiunto", + "index deleted": "Indice eliminato", + "deleted": "Eliminato", + "index renamed": "Indice rinominato", + "index copied": "Indice copiato", + "untracked": "Non registrato", + "ignored": "Ignorato", + "both deleted": "Entrambi eliminati", + "added by us": "Aggiunto da noi", + "deleted by them": "Eliminato da loro", + "added by them": "Aggiunto da loro", + "deleted by us": "Eliminato da noi", + "both added": "Entrambi aggiunti", + "both modified": "Entrambi modificati", + "commit": "Esegui commit", + "merge changes": "Esegui merge delle modifiche", + "staged changes": "Modifiche preparate per il commit", + "changes": "Modifiche", + "ok": "OK", + "neveragain": "Non visualizzare più questo messaggio", + "huge": "Il repository git '{0}' ha troppe modifiche attive - verrĆ  attivato solo un sottoinsieme delle funzionalitĆ  di Git." +} \ No newline at end of file diff --git a/i18n/ita/extensions/git/package.i18n.json b/i18n/ita/extensions/git/package.i18n.json index 6333c529dcd..7fe36b9539a 100644 --- a/i18n/ita/extensions/git/package.i18n.json +++ b/i18n/ita/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "Clona", "command.init": "Inizializza repository", + "command.close": "Chiudi repository", "command.refresh": "Aggiorna", "command.openChange": "Apri modifiche", "command.openFile": "Apri file", @@ -14,6 +15,8 @@ "command.stageAll": "Prepara tutte le modifiche per commit", "command.stageSelectedRanges": "Prepara per il commit intervalli selezionati", "command.revertSelectedRanges": "Ripristina intervalli selezionati", + "command.stageChange": "Prepara modifica per commit", + "command.revertChange": "Annulla modifica", "command.unstage": "Annulla preparazione modifiche per commit", "command.unstageAll": "Annulla preparazione di tutte le modifiche per commit", "command.unstageSelectedRanges": "Annulla preparazione per il commit di intervalli selezionati", @@ -22,22 +25,29 @@ "command.commit": "Commit", "command.commitStaged": "Esegui commit dei file preparati", "command.commitStagedSigned": "Esegui commit dei file preparati (approvazione)", + "command.commitStagedAmend": "Esegui commit dei file preparati (modifica)", "command.commitAll": "Esegui commit di tutto", "command.commitAllSigned": "Esegui commit di tutto (approvazione)", + "command.commitAllAmend": "Esegui commit di tutto (modifica)", "command.undoCommit": "Annulla ultimo commit", "command.checkout": "Estrai in...", "command.branch": "Crea ramo...", "command.deleteBranch": "Elimina ramo...", "command.merge": "Merge ramo...", + "command.createTag": "Crea tag", "command.pull": "Esegui pull", "command.pullRebase": "Esegui pull (Riassegna)", "command.pullFrom": "Pull da...", "command.push": "Esegui push", "command.pushTo": "Esegui push in...", + "command.pushWithTags": "Esegui push con tag", "command.sync": "Sincronizza", "command.publish": "Pubblica ramo", "command.showOutput": "Mostra output GIT", "command.ignore": "Aggiungi file a .gitignore", + "command.stash": "Accantona", + "command.stashPop": "Preleva accantonamento...", + "command.stashPopLatest": "Preleva accantonamento più recente", "config.enabled": "Indica se GIT ĆØ abilitato", "config.path": "Percorso dell'eseguibile di GIT", "config.autorefresh": "Indica se l'aggiornamento automatico ĆØ abilitato", @@ -49,5 +59,13 @@ "config.ignoreLegacyWarning": "Ignora l'avvertimento legacy di Git", "config.ignoreLimitWarning": "Ignora il messaggio di avviso quando ci sono troppi cambiamenti in un repository", "config.defaultCloneDirectory": "Il percorso predefinito dove clonare un repository GIT", - "config.enableSmartCommit": "Eseguire il commit di tutte le modifiche quando non ci sono modifiche preparate." + "config.enableSmartCommit": "Eseguire il commit di tutte le modifiche quando non ci sono modifiche preparate.", + "config.enableCommitSigning": "Abilita la firma del commit con GPG.", + "config.discardAllScope": "Controlla quali modifiche vengono rimosse tramite il comando `Rimuovi tutte le modifiche`. Con `all` vengono rimosse tutte le modifiche. Con `tracked` vengono rimossi solo i file di cui viene tenuta traccia. Con `prompt` viene visualizzata una finestra di dialogo ogni volta che si esegue l'azione.", + "config.decorations.enabled": "Controlla se Git fornisce colori e distintivi alle visualizzazioni Esplora risorse e Editor aperti.", + "colors.modified": "Colore delle risorse modificate.", + "colors.deleted": "Colore delle risorse eliminate.", + "colors.untracked": "Colore delle risorse non tracciate.", + "colors.ignored": "Colore delle risorse ignorate.", + "colors.conflict": "Colore delle risorse con conflitti." } \ No newline at end of file diff --git a/i18n/ita/extensions/grunt/out/main.i18n.json b/i18n/ita/extensions/grunt/out/main.i18n.json index 8defb3ed923..b0acbd01bca 100644 --- a/i18n/ita/extensions/grunt/out/main.i18n.json +++ b/i18n/ita/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Rilevamento automatico di Grunt non riuscito - errore: {0}" + "execFailed": "Rilevamento automatico di Grunt per la cartella {0} non riuscito - errore: {1}" } \ No newline at end of file diff --git a/i18n/ita/extensions/gulp/out/main.i18n.json b/i18n/ita/extensions/gulp/out/main.i18n.json index 3c12bf6e402..e6e18f9d518 100644 --- a/i18n/ita/extensions/gulp/out/main.i18n.json +++ b/i18n/ita/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Rilevamento automatico di gulp non riuscito - errore: {0}" + "execFailed": "Rilevamento automatico di Gulp per la cartella {0} non riuscito - errore: {1}" } \ No newline at end of file diff --git a/i18n/ita/extensions/html/package.i18n.json b/i18n/ita/extensions/html/package.i18n.json index 6e77b2e1cb1..6aa0272c4c3 100644 --- a/i18n/ita/extensions/html/package.i18n.json +++ b/i18n/ita/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "Abilita/Disabilita il formattatore HTML predefinito (richiede il riavvio)", + "html.format.enable.desc": "Abilita/Disabilita il formattatore HTML predefinito", "html.format.wrapLineLength.desc": "Numero massimo di caratteri per riga (0 = disabilita).", "html.format.unformatted.desc": "Elenco di tag, separati da virgole, che non devono essere riformattati. Con 'null' viene usata l'impostazione predefinita che prevede l'uso di tutti i tag elencati in https://www.w3.org/TR/html5/dom.html#phrasing-content.", "html.format.contentUnformatted.desc": "Elenco di tag, separati da virgole, in cui il contenuto non deve essere riformattato. Per impostazione predefinita, con 'null' viene usato il tag 'pre'.", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "Consente di configurare se il supporto del linguaggio HTML predefinito suggerisce tag e proprietĆ  di Angular V1.", "html.suggest.ionic.desc": "Consente di configurare se il supporto del linguaggio HTML predefinito suggerisce tag, proprietĆ  e valori di Ionic.", "html.suggest.html5.desc": "Consente di configurare se il supporto del linguaggio HTML predefinito suggerisce tag, proprietĆ  e valori di HTML5.", + "html.trace.server.desc": "Traccia la comunicazione tra VS Code e il server del linguaggio HTML.", "html.validate.scripts": "Consente di configurare se il supporto del linguaggio HTML predefinito convalida gli script incorporati.", - "html.validate.styles": "Consente di configurare se il supporto del linguaggio HTML predefinito convalida gli stili incorporati." + "html.validate.styles": "Consente di configurare se il supporto del linguaggio HTML predefinito convalida gli stili incorporati.", + "html.autoClosingTags": "Abilita/Disabilita la chiusura automatica dei tag HTML." } \ No newline at end of file diff --git a/i18n/ita/extensions/jake/out/main.i18n.json b/i18n/ita/extensions/jake/out/main.i18n.json index be50361d378..0a83577e4d6 100644 --- a/i18n/ita/extensions/jake/out/main.i18n.json +++ b/i18n/ita/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Rilevamento automatico di Jake non riuscito - errore: {0}" + "execFailed": "Rilevamento automatico di Jake per la cartella {0} non riuscito - errore: {1}" } \ No newline at end of file diff --git a/i18n/ita/extensions/json/package.i18n.json b/i18n/ita/extensions/json/package.i18n.json index f863ad2cb05..99b5edcf95b 100644 --- a/i18n/ita/extensions/json/package.i18n.json +++ b/i18n/ita/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "Definizione dello schema per l'URL specificato. ƈ necessario specificare lo schema per evitare accessi all'URL dello schema.", "json.format.enable.desc": "Abilita/Disabilita il formattatore JSON predefinito (richiede il riavvio)", "json.tracing.desc": "Traccia la comunicazione tra VS Code e il server del linguaggio JSON.", - "json.colorDecorators.enable.desc": "Abilita o disabilita gli elementi Decorator di tipo colore" + "json.colorDecorators.enable.desc": "Abilita o disabilita gli elementi Decorator di tipo colore", + "json.colorDecorators.enable.deprecationMessage": "L'impostazione `json.colorDecorators.enable` ĆØ stata deprecata e sostituita da `editor.colorDecorators`." } \ No newline at end of file diff --git a/i18n/ita/extensions/markdown/out/extension.i18n.json b/i18n/ita/extensions/markdown/out/extension.i18n.json index 2448cc1f0e0..d1d6e298825 100644 --- a/i18n/ita/extensions/markdown/out/extension.i18n.json +++ b/i18n/ita/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "Impossibile caricare 'markdown.styles': {0}" + "onPreviewStyleLoadError": "Impossibile caricare 'markdown.styles': {0}", + "previewTitle": "Anteprima {0}" } \ No newline at end of file diff --git a/i18n/ita/extensions/markdown/out/previewContentProvider.i18n.json b/i18n/ita/extensions/markdown/out/previewContentProvider.i18n.json index 81907bad2d4..9207358bc4d 100644 --- a/i18n/ita/extensions/markdown/out/previewContentProvider.i18n.json +++ b/i18n/ita/extensions/markdown/out/previewContentProvider.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.securityMessage.text": "Alcuni contenuti sono stati disattivati in questo documento", - "preview.securityMessage.title": "Contenuti potenzialmente non sicuri sono stati disattivati nell'anteprima del Markdown. Modificare l'impostazione di protezione dell'anteprima del Markdown per consentire la visualizzazione di contenuto insicuro o abilitare gli script" + "preview.securityMessage.text": "Alcuni contenuti sono stati disabilitati in questo documento", + "preview.securityMessage.title": "Contenuti potenzialmente non sicuri sono stati disattivati nell'anteprima del Markdown. Modificare l'impostazione di protezione dell'anteprima del Markdown per consentire la visualizzazione di contenuto insicuro o abilitare gli script", + "preview.securityMessage.label": "Avviso di sicurezza contenuto disabilitato" } \ No newline at end of file diff --git a/i18n/ita/extensions/markdown/out/security.i18n.json b/i18n/ita/extensions/markdown/out/security.i18n.json index 4b1b334651f..0b73b98c61c 100644 --- a/i18n/ita/extensions/markdown/out/security.i18n.json +++ b/i18n/ita/extensions/markdown/out/security.i18n.json @@ -4,5 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.currentSelection": "Impostazione corrente" + "strict.title": "Strict", + "strict.description": "Carica solo contenuto protetto", + "insecureContent.title": "Consenti contenuto non protetto", + "insecureContent.description": "Consente il caricamento di contenuti tramite HTTP", + "disable.title": "Disabilita", + "disable.description": "Consente l'esecuzione di tutti i contenuti e script. Scelta non consigliata", + "moreInfo.title": "Altre informazioni", + "preview.showPreviewSecuritySelector.title": "Seleziona impostazioni di protezione per le anteprime Markdown in questa area di lavoro" } \ No newline at end of file diff --git a/i18n/ita/extensions/markdown/package.i18n.json b/i18n/ita/extensions/markdown/package.i18n.json index 86ada41639d..6aca710a338 100644 --- a/i18n/ita/extensions/markdown/package.i18n.json +++ b/i18n/ita/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "Imposta come le interruzioni di riga vengono visualizzate nell'anteprima di markdown. Impostarlo a 'true' crea un
per ogni carattere di nuova riga.", + "markdown.preview.linkify": "Abilita o disabilita la conversione di testo simile a URL in collegamenti nell'anteprima markdown.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Fare doppio clic nell'anteprima markdown per passare all'editor.", "markdown.preview.fontFamily.desc": "Consente di controllare la famiglia di caratteri usata nell'anteprima markdown.", "markdown.preview.fontSize.desc": "Consente di controllare le dimensioni del carattere in pixel usate nell'anteprima markdown.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "Apri anteprima lateralmente", "markdown.showSource.title": "Mostra origine", "markdown.styles.dec": "Elenco di URL o percorsi locali dei fogli di stile CSS da usare dall'anteprima markdown. I percorsi relativi vengono interpretati come relativi alla cartella aperta nella finestra di esplorazione. Se non ĆØ presente alcuna cartella aperta, vengono interpretati come relativi al percorso del file markdown. Tutti i caratteri '\\' devono essere scritti come '\\\\'.", - "markdown.showPreviewSecuritySelector.title": "Modifica impostazioni di sicurezza anteprima markdown", - "markdown.trace.desc": "Abilitare la registrazione debug per l'estensione markdown." + "markdown.showPreviewSecuritySelector.title": "Modifica impostazioni di sicurezza anteprima", + "markdown.trace.desc": "Abilitare la registrazione debug per l'estensione markdown.", + "markdown.refreshPreview.title": "Aggiorna anteprima" } \ No newline at end of file diff --git a/i18n/ita/extensions/npm/out/main.i18n.json b/i18n/ita/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..a8e1865d452 --- /dev/null +++ b/i18n/ita/extensions/npm/out/main.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "npm.parseError": "Rilevamento attivitĆ  NPM: Impossibile analizzare il file {0}" +} \ No newline at end of file diff --git a/i18n/ita/extensions/npm/package.i18n.json b/i18n/ita/extensions/npm/package.i18n.json index 835b035d146..2b1bd514d59 100644 --- a/i18n/ita/extensions/npm/package.i18n.json +++ b/i18n/ita/extensions/npm/package.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "config.npm.autoDetect": "Controlla se la rilevazione automatica degli script npm ĆØ on/off. L'impostazione predefinita ĆØ 'on'.", - "config.npm.runSilent": "Esegue i comandi di npm con l'opzione `--silent`" + "config.npm.runSilent": "Esegue i comandi di npm con l'opzione `--silent`", + "npm.parseError": "Rilevamento attivitĆ  NPM: Impossibile analizzare il file {0}" } \ No newline at end of file diff --git a/i18n/ita/extensions/typescript/out/features/completionItemProvider.i18n.json b/i18n/ita/extensions/typescript/out/features/completionItemProvider.i18n.json index d27b41daf56..70df4761df5 100644 --- a/i18n/ita/extensions/typescript/out/features/completionItemProvider.i18n.json +++ b/i18n/ita/extensions/typescript/out/features/completionItemProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "acquiringTypingsLabel": "Acquisizione dei file typings...", - "acquiringTypingsDetail": "Acquisizione delle definizioni dei file typings per IntelliSense." + "acquiringTypingsDetail": "Acquisizione delle definizioni dei file typings per IntelliSense.", + "autoImportLabel": "Importazione automatica da {0}" } \ No newline at end of file diff --git a/i18n/ita/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/ita/extensions/typescript/out/features/taskProvider.i18n.json index 6d36978248d..413001392cc 100644 --- a/i18n/ita/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/ita/extensions/typescript/out/features/taskProvider.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "buildAndWatchTscLabel": "Osserva - {0}", - "buildTscLabel": "Compila - {0}" + "buildTscLabel": "Compila - {0}", + "buildAndWatchTscLabel": "Osserva - {0}" } \ No newline at end of file diff --git a/i18n/ita/extensions/typescript/out/utils/api.i18n.json b/i18n/ita/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..23e26f897b6 --- /dev/null +++ b/i18n/ita/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "versione non valida" +} \ No newline at end of file diff --git a/i18n/ita/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/ita/extensions/typescript/out/utils/versionPicker.i18n.json index 09c108e0ed3..d2d039e2256 100644 --- a/i18n/ita/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/ita/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "Usa versione di VSCode", + "useVSCodeVersionOption": "Usa versione di VS Code", "useWorkspaceVersionOption": "Usa versione dell'area di lavoro", "learnMore": "Altre informazioni", "selectTsVersion": "Selezionare la versione di TypeScript usata per le funzionalitĆ  del linguaggio JavaScript e TypeScript" diff --git a/i18n/ita/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/ita/extensions/typescript/out/utils/versionProvider.i18n.json index 68ad43be044..ce11b335eca 100644 --- a/i18n/ita/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/ita/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "Il file tsserver di VSCode ĆØ stato eliminato da un'altra applicazione, ad esempio uno strumento di rilevamento virus che non funziona correttamente. Reinstallare VSCode." + "couldNotLoadTsVersion": "Non ĆØ stato possibile caricare la versione di TypeScript in questo percorso", + "noBundledServerFound": "Il file tsserver di VS Code ĆØ stato eliminato da un'altra applicazione, ad esempio uno strumento di rilevamento virus che non funziona correttamente. Reinstallare VS Code." } \ No newline at end of file diff --git a/i18n/ita/extensions/typescript/package.i18n.json b/i18n/ita/extensions/typescript/package.i18n.json index ed2f1d326cf..54540ff71f9 100644 --- a/i18n/ita/extensions/typescript/package.i18n.json +++ b/i18n/ita/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Completare le funzioni con la relativa firma del parametro.", "typescript.tsdk.desc": "Specifica il percorso della cartella che contiene i file tsserver e lib*.d.ts da usare.", - "typescript.disableAutomaticTypeAcquisition": "Disabilita l'acquisizione automatica del tipo. Richiede TypeScript >= 2.0.6 e un riavvio dopo la modifica.", + "typescript.disableAutomaticTypeAcquisition": "Disabilita l'acquisizione automatica del tipo. Richiede TypeScript >= 2.0.6.", "typescript.tsserver.log": "Abilita la registrazione del server TypeScript in un file. Questo registro può essere utilizzato per diagnosticare problemi del server TypeScript. Il registro può contenere percorsi di file, codice sorgente e altre informazioni del progetto potenzialmente riservate. ", "typescript.tsserver.trace": "Abilita la traccia dei messaggi inviati al server TypeScript. Questa traccia può essere utilizzata per diagnosticare problemi del server TypeScript. La traccia può contenere percorsi di file, codice sorgente e altre informazioni del progetto potenzialmente riservate.", "typescript.validate.enable": "Abilita/Disabilita la convalida TypeScript.", @@ -44,7 +44,11 @@ "typescript.npm": "Specifica il percorso dell'eseguibile NPM utilizzato per l'acquisizione automatica delle definizioni di tipi. Richiede TypeScript >= 2.3.4.", "typescript.check.npmIsInstalled": "Controlla se NPM ĆØ installato per l'acquisizione automatica delle definizioni di tipi", "javascript.nameSuggestions": "Abilita/disabilita l'inclusione di nomi univoci dal file negli elenchi di suggerimento di JavaScript.", - "typescript.tsc.autoDetect": "Controlla se la rilevazione automatica di attivitĆ  tsc ĆØ on/off.", + "typescript.tsc.autoDetect": "Controlla l'auto-rilevazione di attivitĆ  di tsc. 'off' disabilita questa funzionalitĆ . 'build' crea solo attivitĆ  di singola compilazione esecuzione. 'watch' crea solo attivitĆ  di compilazione e controllo. 'on' crea attivitĆ  sia di tipo 'build' che 'watch'. Il valore predefinito ĆØ 'on'.", "typescript.problemMatchers.tsc.label": "Problemi TypeScript", - "typescript.problemMatchers.tscWatch.label": "Problemi TypeScript (modalitĆ  espressione di controllo)" + "typescript.problemMatchers.tscWatch.label": "Problemi TypeScript (modalitĆ  espressione di controllo)", + "typescript.quickSuggestionsForPaths": "Attiva/Disattiva suggerimenti rapidi quando si digita un percorso di importazione.", + "typescript.locale": "Assegna le impostazioni internazionali utilizzate per riportare errori TypeScript. Richiede TypeScript > = 2.6.0. Il valore predefinito 'null' utilizza le impostazioni internazionali di VS Code.", + "javascript.implicitProjectConfig.experimentalDecorators": "Abilita/disabilita 'experimentalDecorators' per i file JavaScript che non fanno parte di un progetto. File jsconfig.json o tsconfig.json esistenti ignorano questa impostazione. Richiede TypeScript >= 2.3.1.", + "typescript.autoImportSuggestions.enabled": "Abilita/Disabilita suggerimenti importazione automatica. Richiede una versione di TypeScript >= 2.6.1" } \ No newline at end of file diff --git a/i18n/ita/src/vs/code/electron-main/auth.i18n.json b/i18n/ita/src/vs/code/electron-main/auth.i18n.json index 8b6ad71cd4e..354aecd5ccb 100644 --- a/i18n/ita/src/vs/code/electron-main/auth.i18n.json +++ b/i18n/ita/src/vs/code/electron-main/auth.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "authRequire": "Autenticazione proxy necessaria", + "proxyauth": "Il proxy {0} richiede l'autenticazione." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/code/electron-main/menus.i18n.json b/i18n/ita/src/vs/code/electron-main/menus.i18n.json index ad8399e27f9..17fd875af6f 100644 --- a/i18n/ita/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/ita/src/vs/code/electron-main/menus.i18n.json @@ -22,9 +22,11 @@ "miQuit": "Chiudi {0}", "miNewFile": "&&Nuovo file", "miOpen": "&&Apri...", + "miOpenWorkspace": "&&Apri area di lavoro...", "miOpenFolder": "Apri &&cartella...", "miOpenFile": "&&Apri file...", "miOpenRecent": "Apri &&recenti", + "miSaveWorkspaceAs": "&&Salva area di lavoro con nome...", "miAddFolderToWorkspace": "&&Aggiungi cartella all'area di lavoro...", "miSave": "&&Salva", "miSaveAs": "Salva con nome...", @@ -32,6 +34,7 @@ "miAutoSave": "Salvataggio automatico", "miRevert": "Ripristina file", "miCloseWindow": "Chiudi finestra", + "miCloseWorkspace": "Chiudi &&area di lavoro", "miCloseFolder": "Chiudi &&cartella", "miCloseEditor": "Chiudi &&editor", "miExit": "&&Uscita", @@ -44,6 +47,7 @@ "miPreferences": "&&Preferenze", "miReopenClosedEditor": "&&Riapri editor chiuso", "miMore": "&&Altro...", + "miClearRecentOpen": "&&Cancella elementi aperti di recente", "miUndo": "Annulla", "miRedo": "Ripristina", "miCut": "Taglia (&&X)", @@ -98,6 +102,7 @@ "miHideActivityBar": "Nascondi &&barra attivitĆ ", "miShowActivityBar": "Mostra &&barra attivitĆ ", "miToggleWordWrap": "Attiva/Disattiva &&ritorno a capo automatico", + "miToggleMinimap": "Attiva/Disattiva &&mini mappa", "miToggleRenderWhitespace": "Attiva/Disattiva rendering &&spazi vuoti", "miToggleRenderControlCharacters": "Attiva/Disattiva &&caratteri di controllo", "miZoomIn": "&&Zoom avanti", @@ -146,6 +151,10 @@ "mZoom": "Zoom", "mBringToFront": "Porta tutto in primo piano", "miSwitchWindow": "Cambia &&finestra...", + "mShowPreviousTab": "Visualizza scheda precedente", + "mShowNextTab": "Visualizza scheda successiva", + "mMoveTabToNewWindow": "Sposta scheda in una nuova finestra", + "mMergeAllWindows": "Unisci tutte le finestre", "miToggleDevTools": "&&Attiva/Disattiva strumenti di sviluppo", "miAccessibilityOptions": "&&Opzioni accessibilitĆ ", "miReportIssues": "&&Segnala problemi", @@ -163,10 +172,11 @@ "miAbout": "&&Informazioni su", "miRunTask": "&&Esegui attivitĆ ...", "miBuildTask": "Esegui attivitĆ  di &&compilazione...", + "miRunningTask": "Mostra attivitĆ  in esec&&uzione...", "miRestartTask": "Ria&&vvia attivitĆ  in esecuzione...", "miTerminateTask": "&&Termina attivitĆ ...", - "miConfigureTask": "&&Configura attivitĆ ", - "miConfigureBuildTask": "Configura atti&&vitĆ  di compilazione predefinita", + "miConfigureTask": "&&Configura attivitĆ ...", + "miConfigureBuildTask": "Configura atti&&vitĆ  di compilazione predefinita...", "accessibilityOptionsWindowTitle": "Opzioni accessibilitĆ ", "miRestartToUpdate": "Riavvia per aggiornare...", "miCheckingForUpdates": "Verifica della disponibilitĆ  di aggiornamenti...", @@ -174,5 +184,6 @@ "miDownloadingUpdate": "Download dell'aggiornamento...", "miInstallingUpdate": "Installazione dell'aggiornamento...", "miCheckForUpdates": "Verifica disponibilitĆ  aggiornamenti...", + "aboutDetail": "\nVersione {0}\nCommit {1}\nData {2}\nShell {3}\nRenderer {4}\nNodo {5}\nArchitettura {6}", "okButton": "OK" } \ No newline at end of file diff --git a/i18n/ita/src/vs/code/electron-main/windows.i18n.json b/i18n/ita/src/vs/code/electron-main/windows.i18n.json index c16eee44314..afc4b6fc666 100644 --- a/i18n/ita/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/ita/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,23 @@ "ok": "OK", "pathNotExistTitle": "Il percorso non esiste", "pathNotExistDetail": "Il percorso '{0}' sembra non esistere più sul disco.", - "reopen": "Riapri", - "wait": "Continua ad attendere", - "close": "Chiudi", + "reopen": "&& Riaprire", + "wait": "&&Continua ad attendere", "appStalled": "La finestra non risponde", "appStalledDetail": "ƈ possibile riaprire la finestra, chiuderla oppure attendere.", "appCrashed": "Si ĆØ verificato un arresto anomalo della finestra", "appCrashedDetail": "Ci scusiamo per l'inconveniente. Per riprendere dal punto in cui si ĆØ verificata l'interruzione, riaprire la finestra.", + "open": "Apri", + "openFolder": "Apri cartella", "openFile": "Apri file", - "openFolder": "Apri cartella" + "workspaceOpenedMessage": "Non ĆØ possibile salvare l'area di lavoro '{0}'", + "workspaceOpenedDetail": "L'area di lavoro ĆØ giĆ  aperta in un'altra finestra. Chiudere tale finestra prima di riprovare.", + "openWorkspace": "&&Apri", + "openWorkspaceTitle": "Apri area di lavoro", + "save": "&&Salva", + "doNotSave": "&&Non salvare", + "cancel": "Annulla", + "saveWorkspaceMessage": "Salvare la configurazione dell'area di lavoro in un file?", + "saveWorkspaceDetail": "Salvare l'area di lavoro se si prevede di aprirla di nuovo.", + "saveWorkspace": "Salva area di lavoro" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json index ec56b9229e6..0b12d0bdf2d 100644 --- a/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "Controlla l'altezza della riga. Usare 0 per calcolare l'altezza della riga dalle dimensioni del carattere.", "letterSpacing": "Controlla la spaziatura tra le lettere in pixel.", "lineNumbers": "Consente di controllare la visualizzazione dei numeri di riga. I valori possibili sono 'on', 'off' e 'relative'. Con 'relative' viene visualizzato il conteggio delle righe a partire dalla posizione corrente del cursore.", - "rulers": "Colonne in corrispondenza delle quali visualizzare i righelli verticali", + "rulers": "Mostra righelli verticali dopo un certo numero di caratteri a spaziatura fissa. Utilizza più valori per più righelli. Nessun righello viene disegnati se la matrice ĆØ vuota", "wordSeparators": "Caratteri che verranno usati come separatori di parola quando si eseguono operazioni o spostamenti correlati a parole", "tabSize": "Numero di spazi a cui equivale una tabulazione. Quando `editor.detectIndentation` ĆØ attivo, questa impostazione viene sostituita in base al contenuto del file.", "tabSize.errorMessage": "ƈ previsto 'number'. Nota: il valore \"auto\" ĆØ stato sostituito dall'impostazione `editor.detectIndentation`.", @@ -20,8 +20,9 @@ "detectIndentation": "All'apertura di un file, `editor.tabSize` e `editor.insertSpaces` verranno rilevati in base al contenuto del file.", "roundedSelection": "Controlla se gli angoli delle selezioni sono arrotondati", "scrollBeyondLastLine": "Controlla se l'editor scorrerĆ  oltre l'ultima riga", + "smoothScrolling": "Controlla se per lo scorrimento dell'editor verrĆ  usata un'animazione.", "minimap.enabled": "Controlla se la mini mappa ĆØ visualizzata", - "minimap.showSlider": "Controlla se lo slider della mini mappa viene nascosto automaticamente.", + "minimap.showSlider": "Controlla se il dispositivo di scorrimento della mini mappa viene nascosto automaticamente. I valori possibili sono 'always' e 'mouseover'", "minimap.renderCharacters": "Esegue il rendering dei caratteri effettivi di una riga (in contrapposizione ai blocchi colore)", "minimap.maxColumn": "Limita la larghezza della mini mappa in modo da eseguire il rendering al massimo di un certo numero di colonne", "find.seedSearchStringFromSelection": "Controlla se inizializzare la stringa di ricerca nel Widget Trova con il testo selezionato nell'editor", @@ -50,6 +51,10 @@ "suggestOnTriggerCharacters": "Controlla se i suggerimenti devono essere visualizzati automaticamente durante la digitazione dei caratteri trigger", "acceptSuggestionOnEnter": "Controlla se i suggerimenti devono essere accettati con 'INVIO' in aggiunta a 'TAB'. In questo modo ĆØ possibile evitare ambiguitĆ  tra l'inserimento di nuove righe e l'accettazione di suggerimenti. Il valore 'smart' indica di accettare un suggerimento con 'INVIO' quando comporta una modifica al testo", "acceptSuggestionOnCommitCharacter": "Controlla se accettare i suggerimenti con i caratteri di commit. Ad esempio, in JavaScript il punto e virgola (';') può essere un carattere di commit che accetta un suggerimento e digita tale carattere.", + "snippetSuggestions.top": "Visualizza i suggerimenti dello snippet sopra gli altri suggerimenti.", + "snippetSuggestions.bottom": "Visualizza i suggerimenti dello snippet sotto gli altri suggerimenti.", + "snippetSuggestions.inline": "Visualizza i suggerimenti degli snippet insieme agli altri suggerimenti.", + "snippetSuggestions.none": "Non mostrare i suggerimenti sugli snippet.", "snippetSuggestions": "Controlla se i frammenti di codice sono visualizzati con altri suggerimenti e il modo in cui sono ordinati.", "emptySelectionClipboard": "Consente di controllare se, quando si copia senza aver effettuato una selezione, viene copiata la riga corrente.", "wordBasedSuggestions": "Controlla se calcolare i completamenti in base alle parole presenti nel documento.", @@ -82,6 +87,8 @@ "accessibilitySupport.off": "L'editor non sarĆ  mai ottimizzato per l'utilizzo con un'utilitĆ  per la lettura dello schermo.", "accessibilitySupport": "Controlla se l'editor deve essere eseguito in una modalitĆ  ottimizzata per le utilitĆ  per la lettura dello schermo.", "links": "Controlla se l'editor deve individuare i collegamenti e renderli cliccabili", + "colorDecorators": "Controlla se l'editor deve eseguire il rendering del selettore di colore e degli elementi Decorator di tipo colore inline.", + "codeActions": "Abilita il codice azione lightbulb", "sideBySide": "Controlla se l'editor diff mostra le differenze affiancate o incorporate", "ignoreTrimWhitespace": "Controlla se l'editor diff mostra come differenze le modifiche relative a spazi vuoti iniziali e finali", "renderIndicators": "Consente di controllare se l'editor diff mostra gli indicatori +/- per le modifiche aggiunte/rimosse", diff --git a/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json index 9b92b52f5c5..bd8958bdf97 100644 --- a/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/ita/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "Colore primo piano degli squiggle di errore nell'editor.", "errorBorder": "Colore del bordo degli squiggle di errore nell'editor.", "warningForeground": "Colore primo piano degli squiggle di avviso nell'editor", - "warningBorder": "Colore del bordo degli squggle di avviso nell'editor." + "warningBorder": "Colore del bordo degli squggle di avviso nell'editor.", + "infoForeground": "Colore primo piano degli squiggle di informazione nell'editor", + "infoBorder": "Colore del bordo degli squiggle di informazione nell'editor", + "overviewRulerRangeHighlight": "Colore del marcatore del righello delle annotazioni per le evidenziazioni degli intervalli.", + "overviewRuleError": "Colore del marcatore del righello delle annotazioni per gli errori.", + "overviewRuleWarning": "Colore del marcatore del righello delle annotazioni per gli avvisi.", + "overviewRuleInfo": "Colore del marcatore del righello delle annotazioni per i messaggi di tipo informativo." } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json index aadb8148c62..f8b42e27976 100644 --- a/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "Sostituisci", "label.replaceAllButton": "Sostituisci tutto", "label.toggleReplaceButton": "Attiva/Disattiva modalitĆ  sostituzione", - "title.matchesCountLimit": "Vengono evidenziati solo i primi 999 risultati, ma tutte le operazioni di ricerca funzionano sull'intero testo.", + "title.matchesCountLimit": "Solo i primi {0} risultati vengono evidenziati, ma tutte le operazioni di ricerca funzionano su tutto il testo.", "label.matchesLocation": "{0} di {1}", - "label.noResults": "Nessuna impostazione corrispondente" + "label.noResults": "Nessun risultato" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json index acd2bdb447c..753c08a072a 100644 --- a/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,10 +10,6 @@ "nextSelectionMatchFindAction": "Trova selezione successiva", "previousSelectionMatchFindAction": "Trova selezione precedente", "startReplace": "Sostituisci", - "addSelectionToNextFindMatch": "Aggiungi selezione a risultato ricerca successivo", - "addSelectionToPreviousFindMatch": "Aggiungi selezione a risultato ricerca precedente", - "moveSelectionToNextFindMatch": "Sposta ultima selezione a risultato ricerca successivo", - "moveSelectionToPreviousFindMatch": "Sposta ultima selezione a risultato ricerca precedente", - "selectAllOccurrencesOfFindMatch": "Seleziona tutte le occorrenze del risultato ricerca", - "changeAll.label": "Cambia tutte le occorrenze" + "showNextFindTermAction": "Mostra il termine di ricerca successivo", + "showPreviousFindTermAction": "Mostra il termine di ricerca precedente" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/ita/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 7c31ed06f01..1232d4a3bb3 100644 --- a/i18n/ita/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "Sono state apportate {0} modifiche di formattazione a riga {1}", "hint1n": "ƈ stata apportata 1 modifica di formattazione tra le righe {0} e {1}", "hintnn": "Sono state apportate {0} modifiche di formattazione tra le righe {1} e {2}", + "no.provider": "Ci dispiace, ma non c'ĆØ alcun formattatore per i file '{0}' installati.", "formatDocument.label": "Formatta documento", "formatSelection.label": "Formatta selezione" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/ita/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index a38b2519a5d..2d24c4f96ea 100644 --- a/i18n/ita/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "Vai a errore o avviso precedente", "editorMarkerNavigationError": "Colore per gli errori del widget di spostamento tra marcatori dell'editor.", "editorMarkerNavigationWarning": "Colore per gli avvisi del widget di spostamento tra marcatori dell'editor.", + "editorMarkerNavigationInfo": "Colore delle informazioni del widget di navigazione marcatori dell'editor.", "editorMarkerNavigationBackground": "Sfondo del widget di spostamento tra marcatori dell'editor." } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 732a2e19079..af2b081d453 100644 --- a/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Aggiungi cursore sopra", "mutlicursor.insertBelow": "Aggiungi cursore sotto", - "mutlicursor.insertAtEndOfEachLineSelected": "Aggiungi cursore alla fine delle righe" + "mutlicursor.insertAtEndOfEachLineSelected": "Aggiungi cursore alla fine delle righe", + "addSelectionToNextFindMatch": "Aggiungi selezione a risultato ricerca successivo", + "addSelectionToPreviousFindMatch": "Aggiungi selezione a risultato ricerca precedente", + "moveSelectionToNextFindMatch": "Sposta ultima selezione a risultato ricerca successivo", + "moveSelectionToPreviousFindMatch": "Sposta ultima selezione a risultato ricerca precedente", + "selectAllOccurrencesOfFindMatch": "Seleziona tutte le occorrenze del risultato ricerca", + "changeAll.label": "Cambia tutte le occorrenze" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/ita/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..fe8e7a6d653 --- /dev/null +++ b/i18n/ita/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "Chiudi" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/ita/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index 7aa67ed2c81..d57627a559a 100644 --- a/i18n/ita/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Colore di sfondo di un simbolo durante l'accesso in lettura, ad esempio durante la lettura di una variabile.", - "wordHighlightStrong": "Colore di sfondo di un simbolo durante l'accesso in scrittura, ad esempio durante la scrittura in una variabile." + "wordHighlightStrong": "Colore di sfondo di un simbolo durante l'accesso in scrittura, ad esempio durante la scrittura in una variabile.", + "overviewRulerWordHighlightForeground": "Colore del marcatore del righello delle annotazioni per le evidenziazioni dei simboli.", + "overviewRulerWordHighlightStrongForeground": "Colore del marcatore del righello delle annotazioni per le evidenziazioni dei simboli di accesso in scrittura.", + "wordHighlight.next.label": "Vai al prossimo simbolo evidenziato", + "wordHighlight.previous.label": "Vai al precedente simbolo evidenziato" } \ No newline at end of file diff --git a/i18n/ita/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/ita/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index f595c9809b7..32a58ae4a61 100644 --- a/i18n/ita/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/ita/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "Gruppo a cui appartiene questo comando", "vscode.extension.contributes.menus": "Aggiunge voci del menu all'editor come contributo", "menus.commandPalette": "Riquadro comandi", + "menus.touchBar": "La Touch Bar (solo Mac OS)", "menus.editorTitle": "Menu del titolo dell'editor", "menus.editorContext": "Menu di scelta rapida dell'editor", "menus.explorerContext": "Menu di scelta rapida Esplora file", "menus.editorTabContext": "Menu di scelta rapida delle schede dell'editor", "menus.debugCallstackContext": "Menu di scelta rapida dello stack di chiamate di debug", "menus.scmTitle": "Menu del titolo del controllo del codice sorgente", + "menus.scmSourceControl": "Menu del controllo del codice sorgente", "menus.resourceGroupContext": "Menu di scelta rapida del gruppo di risorse del controllo del codice sorgente", "menus.resourceStateContext": "Menu di scelta rapida dello stato delle risorse del controllo del codice sorgente", "view.viewTitle": "Menu del titolo della visualizzazione contribuita", diff --git a/i18n/ita/src/vs/platform/environment/node/argv.i18n.json b/i18n/ita/src/vs/platform/environment/node/argv.i18n.json index e9a4ecff7e0..871d55bf6d3 100644 --- a/i18n/ita/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/ita/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "Gli argomenti nella modalitĆ  `--goto` devono essere espressi nel formato `FILE(:LINE(:CHARACTER))`.", - "diff": "Apre un editor diff. Richiede il passaggio di due percorsi di file come argomenti.", - "goto": "Apre il file nel percorso alla riga e carattere indicati (aggiunge :line[:character] al percorso).", + "diff": "Confronta due file tra loro.", + "add": "Aggiunge la cartella o le cartelle all'ultima finestra attiva.", + "goto": "Apre un file nel percorso alla posizione specificata di riga e carattere.", "locale": "Impostazioni locali da usare, ad esempio en-US o it-IT.", "newWindow": "Forza una nuova istanza di Code.", "performance": "Eseguire l'avvio con il comando 'Developer: Startup Performance' abilitato.", @@ -14,7 +15,7 @@ "reuseWindow": "Forza l'apertura di un file o di una cartella nell'ultima finestra attiva.", "userDataDir": "Consente di specificare la directory in cui si trovano i dati utente. Utile quando viene eseguito come root.", "verbose": "Visualizza l'output dettagliato (implica --wait).", - "wait": "Attende la chiusura della finestra prima della restituzione.", + "wait": "Attendere la chiusura dei file prima della restituzione.", "extensionHomePath": "Impostare il percorso radice per le estensioni.", "listExtensions": "Elenca le estensioni installate.", "showVersions": "Mostra le versioni delle estensioni installate, quando si usa --list-extension.", diff --git a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 2c46cc8fbb5..e76a4c1b8b1 100644 --- a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Estensione non valida: package.json non ĆØ un file JSON.", - "restartCode": "Riavviare Code prima di reinstallare {0}.", - "installDependeciesConfirmation": "Se si installa '{0}', verranno installate anche le relative dipendenze. Continuare?", - "install": "SƬ", - "doNotInstall": "No", + "restartCodeLocal": "Riavviare Code prima di reinstallare {0}.", + "restartCodeGallery": "Si prega di riavviare Code prima di reinstallare.", "uninstallDependeciesConfirmation": "Disinstallare solo '{0}' o anche le relative dipendenze?", "uninstallOnly": "Solo", "uninstallAll": "Tutto", diff --git a/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index afe0f0f2880..20c377c8508 100644 --- a/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "Eventi di attivazione per l'estensione Visual Studio Code.", "vscode.extension.activationEvents.onLanguage": "Un evento di attivazione emesso ogni volta che viene aperto un file che risolve nella lingua specificata.", "vscode.extension.activationEvents.onCommand": "Un evento di attivazione emesso ogni volta che viene invocato il comando specificato.", - "vscode.extension.activationEvents.onDebug": "Un evento di attivazione emesso ogni volta che viene iniziata una sessione di debug del tipo specificato.", + "vscode.extension.activationEvents.onDebug": "Un evento di attivazione emesso ogni volta che un utente sta per avviare il debug o sta per impostare le configurazioni di debug.", "vscode.extension.activationEvents.workspaceContains": "Un evento di attivazione emesso ogni volta che si apre una cartella che contiene almeno un file corrispondente al criterio GLOB specificato.", "vscode.extension.activationEvents.onView": "Un evento di attivazione emesso ogni volta che la visualizzazione specificata viene espansa.", "vscode.extension.activationEvents.star": "Un evento di attivazione emesso all'avvio di VS Code. Per garantire la migliore esperienza per l'utente finale, sei pregato di utilizzare questo evento di attivazione nella tua estensione solo quando nessun'altra combinazione di eventi di attivazione funziona nel tuo caso.", diff --git a/i18n/ita/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/ita/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..88108cb9b11 --- /dev/null +++ b/i18n/ita/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "Aggiunge colori tematizzabili alle estensioni definite", + "contributes.color.id": "Identificatore del colore che supporta i temi", + "contributes.color.id.format": "Gli identificativi devono rispettare il formato aa[.bb]*", + "contributes.color.description": "Descrizione del colore che supporta i temi", + "contributes.defaults.light": "Colore predefinito per i temi chiari. Può essere un valore di colore in formato esadecimale (#RRGGBB[AA]) oppure l'identificativo di un colore che supporta i temi e fornisce l'impostazione predefinita.", + "contributes.defaults.dark": "Colore predefinito per i temi scuri. Può essere un valore di colore in formato esadecimale (#RRGGBB[AA]) oppure l'identificativo di un colore che supporta i temi e fornisce l'impostazione predefinita.", + "contributes.defaults.highContrast": "Colore predefinito per i temi a contrasto elevato. Può essere un valore di colore in formato esadecimale (#RRGGBB[AA]) oppure l'identificativo di un colore che supporta i temi e fornisce l'impostazione predefinita.", + "invalid.colorConfiguration": "'configuration.colors' deve essere un array", + "invalid.default.colorType": "{0} deve essere un valore di colore in formato esadecimale (#RRGGBB [AA] o #RGB[A]) o l'identificativo di un colore che supporta i temi e che fornisce il valore predefinito. ", + "invalid.id": "'configuration.colors.id' deve essere definito e non può essere vuoto", + "invalid.id.format": "'configuration.colors.id' deve essere specificato dopo parola[.parola]*", + "invalid.description": "'configuration.colors.description' deve essere definito e non può essere vuoto", + "invalid.defaults": "'configuration.colors.defaults' deve essere definito e deve contenere 'light', 'dark' e 'highContrast'" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json index 2abb6be7b97..6505e976a25 100644 --- a/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/ita/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Formato colore non valido. Usare #RGB, #RGBA, #RRGGBB o #RRGGBBAA", "schema.colors": "Colori usati nell'area di lavoro.", "foreground": "Colore primo piano. Questo colore ĆØ utilizzato solo se non viene sovrascritto da un componente.", "errorForeground": "Colore primo piano globale per i messaggi di errore. Questo colore ĆØ utilizzato solamente se non viene sottoposto a override da un componente.", @@ -45,6 +44,7 @@ "listHoverForeground": "Primo piano Elenco/Struttura ad albero al passaggio del mouse sugli elementi.", "listDropBackground": "Sfondo Elenco/Struttura ad albero durante il trascinamento degli elementi selezionati.", "highlight": "Colore primo piano Elenco/Struttura ad albero delle occorrenze trovate durante la ricerca nell'Elenco/Struttura ad albero.", + "invalidItemForeground": "Colore di primo piano di Elenco/Struttura ad albero per gli elementi non validi, ad esempio una radice non risolta in Esplora.", "pickerGroupForeground": "Colore di selezione rapida per il raggruppamento delle etichette.", "pickerGroupBorder": "Colore di selezione rapida per il raggruppamento dei bordi.", "buttonForeground": "Colore primo piano del pulsante.", @@ -85,5 +85,7 @@ "mergeBorder": "Colore bordo su intestazioni e sulla barra di divisione di conflitti di merge in linea.", "overviewRulerCurrentContentForeground": "Colore primo piano righello panoramica attuale per i conflitti di merge in linea.", "overviewRulerIncomingContentForeground": "Colore primo piano del righello panoramica modifiche in arrivo per i conflitti di merge in linea.", - "overviewRulerCommonContentForeground": "Colore primo piano righello panoramica dell'antenato comune per i conflitti di merge in linea." + "overviewRulerCommonContentForeground": "Colore primo piano righello panoramica dell'antenato comune per i conflitti di merge in linea.", + "overviewRulerFindMatchForeground": "Colore del marcatore del righello delle annotazioni per le corrispondenze della ricerca.", + "overviewRulerSelectionHighlightForeground": "Colore del marcatore del righello delle annotazioni per le evidenziazioni delle selezioni." } \ No newline at end of file diff --git a/i18n/ita/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/ita/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..4bf035be676 --- /dev/null +++ b/i18n/ita/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Area di lavoro del codice", + "untitledWorkspace": "Senza titolo (Area di lavoro)", + "workspaceNameVerbose": "{0} (Area di lavoro)", + "workspaceName": "{0} (Area di lavoro)" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/ita/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..ebd673947fb --- /dev/null +++ b/i18n/ita/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "Visualizzazioni devono essere una matrice", + "requirestring": "la proprietĆ  `{0}` ĆØ obbligatoria e deve essere di tipo `string`", + "optstring": "la proprietĆ  `{0}` può essere omessa o deve essere di tipo `string`", + "vscode.extension.contributes.view.id": "Identificatore della vista. Utilizzare questo per registrare un provider di dati tramite l'API 'vscode.window.registerTreeDataProviderForView'. Anche per innescare l'attivazione dell'estensione tramite la registrazione dell'evento 'onView: ${id}' a 'activationEvents'.", + "vscode.extension.contributes.view.name": "Il nome della visualizzazione. VerrĆ  mostrato", + "vscode.extension.contributes.view.when": "Condizione che deve essere vera per mostrare questa visualizzazione", + "vscode.extension.contributes.views": "Contribuisce visualizzazioni all'editor", + "views.explorer": "Visualizzazione di esplorazione", + "views.debug": "Visualizzazione Debug", + "locationId.invalid": "'{0}' non ĆØ una posizione valida per la visualizzazione", + "duplicateView1": "Non ĆØ possibile registrare più visualizzazioni con stesso ID `{0}` nel percorso `{1}`", + "duplicateView2": "Nel percorso `{1}` ĆØ giĆ  registrata una visualizzazione con ID `{0}` " +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/ita/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..be99767feaa --- /dev/null +++ b/i18n/ita/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "L'attivazione dell'estensione `{1}` non ĆØ riuscita. Motivo: la dipendenza `{0}` ĆØ sconosciuta.", + "failedDep1": "L'attivazione dell'estensione `{1}` non ĆØ riuscita. Motivo: non ĆØ stato possibile attivare la dipendenza `{0}`.", + "failedDep2": "L'attivazione dell'estensione `{0}` non ĆØ riuscita. Motivo: sono presenti più di 10 livelli di dipendenze (molto probabilmente un ciclo di dipendenze).", + "activationError": "L'attivazione dell'estensione `{0}` non ĆØ riuscita: {1}." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 0375c531a5b..3ce1b25b498 100644 --- a/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,11 +4,18 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "Apri file...", "openFolder": "Apri cartella...", "openFileFolder": "Apri...", - "cancel": "Annulla", "addFolderToWorkspace": "Aggiungi cartella all'area di lavoro...", + "add": "&&Aggiungi", "addFolderToWorkspaceTitle": "Aggiungi cartella all'area di lavoro", "removeFolderFromWorkspace": "Rimuovi cartella dall'area di lavoro", - "save": "&&Salva" + "openFolderSettings": "Apri impostazioni cartella", + "saveWorkspaceAsAction": "Salva area di lavoro come...", + "save": "&&Salva", + "saveWorkspace": "Salva area di lavoro", + "openWorkspaceAction": "Apri area di lavoro...", + "openWorkspaceConfigFile": "Apri file di configurazione dell'area di lavoro", + "workspaceFolderPickerPlaceholder": "Selezionare la cartella dell'area di lavoro" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index f4d0bdccbf0..492b8e03095 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "Rimuovi da barra attivitĆ ", - "keepInActivityBar": "Mantieni in barra attivitĆ ", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Nascondi in barra attivitĆ ", + "keepInActivityBar": "Mantieni in barra attivitĆ ", "additionalViews": "Visualizzazioni aggiuntive", "numberBadge": "{0} ({1})", "manageExtension": "Gestisci estensione", diff --git a/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index d8cbee32bd5..bee5fb6341a 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Nascondi barra attivitĆ ", - "activityBarAriaLabel": "Cambio visualizzazione attiva", "globalActions": "Azioni globali" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..33e0b7a1979 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "Cambio visualizzazione attiva" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..427b8914624 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Visualizzazioni aggiuntive", + "numberBadge": "{0} ({1})", + "manageExtension": "Gestisci estensione", + "titleKeybinding": "{0} ({1})", + "toggle": "Attiva/Disattiva visualizzazione bloccata" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 766b02a726a..aa914d12c1d 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "Mostra editor nel secondo gruppo", "groupThreePicker": "Mostra editor nel terzo gruppo", "allEditorsPicker": "Mostra tutti gli editor aperti", - "view": "Visualizza" + "view": "Visualizza", + "file": "File" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index ad121771c6a..089f3a4202c 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,7 +35,9 @@ "openPreviousEditorInGroup": "Apri editor precedente del gruppo", "navigateNext": "Avanti", "navigatePrevious": "Indietro", + "navigateLast": "Vai all'ultima", "reopenClosedEditor": "Riapri editor chiuso", + "clearRecentFiles": "Cancella elementi aperti di recente", "showEditorsInFirstGroup": "Mostra editor nel primo gruppo", "showEditorsInSecondGroup": "Mostra editor nel secondo gruppo", "showEditorsInThirdGroup": "Mostra editor nel terzo gruppo", diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 2cbca2d7f97..c8ef3502070 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "TAB per spostare lo stato attivo", - "screenReaderDetected": "Rilevata utilitĆ  per la lettura dello schermo", + "screenReaderDetected": "Ottimizzato per l'utilitĆ  per la lettura dello schermo", "screenReaderDetectedExtra": "Se non si utilizza un'utilitĆ  per la lettura dello schermo, si prega di impostare 'editor.accessibilitySupport' a \"off\".", "disableTabMode": "Disabilita modalitĆ  accessibilitĆ ", "gotoLine": "Vai alla riga", @@ -47,5 +47,11 @@ "reopenWithEncoding": "Riapri con codifica", "guessedEncoding": "Ipotizzata dal contenuto", "pickEncodingForReopen": "Seleziona codifica per la riapertura del file", - "pickEncodingForSave": "Seleziona codifica per il salvataggio del file" + "pickEncodingForSave": "Seleziona codifica per il salvataggio del file", + "screenReaderDetectedExplanation.title": "Ottimizzato per l'utilitĆ  per la lettura dello schermo", + "screenReaderDetectedExplanation.question": "Si usa un'utilitĆ  per la lettura per lo schermo per VS Code?", + "screenReaderDetectedExplanation.answerYes": "SƬ", + "screenReaderDetectedExplanation.answerNo": "No", + "screenReaderDetectedExplanation.body1": "VS Code ĆØ ora ottimizzato per l'utilizzo con un'utilitĆ  per la lettura dello schermo.", + "screenReaderDetectedExplanation.body2": "Il comportamento di alcune funzionalitĆ  dell'editor sarĆ  diverso, ad esempio a capo automatico, riduzione del codice, chiusura automatica delle parentesi e cosƬ via." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 0219b0ee2fa..e288ac91066 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Chiudi pannello", "togglePanel": "Attiva/Disattiva pannello", "focusPanel": "Sposta lo stato attivo nel pannello", diff --git a/i18n/ita/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json index 3ba6e23918d..69d8f45b5e6 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "compositePart.hideSideBarLabel": "Nascondi barra laterale", "focusSideBar": "Sposta lo stato attivo nella barra laterale", "viewCategory": "Visualizza" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 9b0548995db..358f121a809 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "Il comando '{0}' non ĆØ attualmente abilitato e non può essere eseguito.", "manageExtension": "Gestisci estensione" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..a7b1c661726 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "Azioni di {0}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..860e3f239f2 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "Azioni di {0}", + "hideView": "Nascondi da barra laterale" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..ed1c7bde950 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "Nel percorso `{1}` ĆØ giĆ  registrata una visualizzazione con ID `{0}` " +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..f5ecae5746b --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "Nascondi da barra laterale" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/common/theme.i18n.json b/i18n/ita/src/vs/workbench/common/theme.i18n.json index 94f6d56ff31..3d0d9d93c84 100644 --- a/i18n/ita/src/vs/workbench/common/theme.i18n.json +++ b/i18n/ita/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "Colore di sfondo delle schede attive. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", "tabInactiveBackground": "Colore di sfondo delle schede inattive. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", "tabBorder": "Bordo per separare le schede l'una dall'altra. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", + "tabActiveBorder": "Bordo per evidenziare le schede attive. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", + "tabActiveUnfocusedBorder": "Bordo per evidenziare le schede attive in un gruppo con stato non attivo. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", "tabActiveForeground": "Colore di primo piano delle schede attive in un gruppo attivo. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", "tabInactiveForeground": "Colore di primo piano delle schede inattive in un gruppo attivo. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", - "tabUnfocusedActiveForeground": "Colore di primo piano delle schede attive in un gruppo inattivo. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", - "tabUnfocusedInactiveForeground": "Colore di primo piano delle schede inattiva in un gruppo inattivo. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", + "tabUnfocusedActiveForeground": "Colore primo piano delle schede attive in un gruppo con stato non attivo. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", + "tabUnfocusedInactiveForeground": "Colore primo piano delle schede inattiva in un gruppo con stato non attivo. Le schede sono i contenitori degli editor nell'area degli editor. ƈ possibile aprire più schede in un gruppo di editor e possono esistere più gruppi di editor.", "editorGroupBackground": "Colore di sfondo di un gruppo di editor. I gruppi di editor sono contenitori di editor. Il colore di sfondo viene visualizzato quando si trascinano i gruppi di editor in un'altra posizione.", "tabsContainerBackground": "Colore di sfondo dell'intestazione del titolo di gruppo di editor, quando le schede sono abilitate. I gruppi di editor sono i contenitori degli editor.", "tabsContainerBorder": "Colore del bordo dell'intestazione del titolo di gruppo di editor, quando le schede sono abilitate. I gruppi di editor sono i contenitori degli editor.", @@ -18,15 +20,15 @@ "editorGroupBorder": "Colore per separare più gruppi di editor l'uno dall'altro. I gruppi di editor sono i contenitori degli editor.", "editorDragAndDropBackground": "Colore di sfondo quando si trascinano gli editor. Il colore dovrebbe avere una trasparenza impostata in modo che il contenuto dell'editor sia ancora visibile.", "panelBackground": "Colore di sfondo dei pannelli. I pannelli sono visualizzati sotto l'area degli editor e contengono visualizzazioni quali quella di output e del terminale integrato.", - "panelBorder": "Colore del bordo dei pannelli nella parte superiore di separazione dall'editor. I pannelli sono visualizzati sotto l'area degli editor e contengono visualizzazioni quali quella di output e del terminale integrato.", "panelActiveTitleForeground": "Colore del titolo del pannello attivo. I pannelli sono visualizzati sotto l'area degli editor e contengono visualizzazioni quali quella di output e quella del terminale integrato.", "panelInactiveTitleForeground": "Colore del titolo del pannello inattivo. I pannelli sono visualizzati sotto l'area degli editor e contengono visualizzazioni quali quella di output e quella del terminale integrato.", "panelActiveTitleBorder": "Colore del bordo del titolo del pannello attivo. I pannelli sono visualizzati sotto l'area degli editor e contengono visualizzazioni quali quella di output e del terminale integrato.", - "statusBarForeground": "Colore primo piano della barra di stato. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", + "statusBarForeground": "Colore primo piano quando viene aperta un'area di lavoro. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", "statusBarNoFolderForeground": "Colore primo piano quando non ci sono cartelle aperte. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", - "statusBarBackground": "Colore di sfondo della barra di stato standard. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", + "statusBarBackground": "Colore di sfondo della barra di stato quando viene aperta un'area di lavoro. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", "statusBarNoFolderBackground": "Colore di sfondo della barra di stato quando non ci sono cartelle aperte. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", "statusBarBorder": "Colore del bordo della barra di stato che la separa dalla sidebar e dall'editor. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", + "statusBarNoFolderBorder": "Colore del bordo della barra di stato che la separa dalla barra laterale e dall'editor quando non ci sono cartelle aperte. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", "statusBarItemActiveBackground": "Colore di sfondo degli elementi della barra di stato quando si fa clic. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", "statusBarItemHoverBackground": "Colore di sfondo degli elementi della barra di stato al passaggio del mouse. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", "statusBarProminentItemBackground": "Colore di sfondo degli elementi rilevanti della barra di stato. Gli elementi rilevanti spiccano rispetto ad altre voci della barra di stato. La barra di stato ĆØ visualizzata nella parte inferiore della finestra.", @@ -41,12 +43,14 @@ "sideBarForeground": "Colore primo piano della barra laterale. La barra laterale ĆØ il contenitore per le visualizzazioni come Esplora risorse e Cerca.", "sideBarBorder": "Colore del bordo della barra laterale che la separa all'editor. La barra laterale ĆØ il contenitore per visualizzazioni come Esplora risorse e Cerca.", "sideBarTitleForeground": "Colore primo piano del titolo della barra laterale. La barra laterale ĆØ il contenitore per visualizzazioni come Explorer e ricerca.", + "sideBarDragAndDropBackground": "Colore di retroazione di trascinamento della selezione per le sezioni della barra laterale. Il colore dovrebbe avere una trasparenza impostata in modo che le sezioni della barra laterale siano ancora visibili. La barra laterale ĆØ il contenitore di visualizzazioni come Esplora risorse e Cerca.", "sideBarSectionHeaderBackground": "Colore di sfondo dell'intestazione di sezione della barra laterale. La barra laterale ĆØ il contenitore di visualizzazioni quali Esplora risorse e Cerca.", "sideBarSectionHeaderForeground": "Colore primo piano dell'intestazione di sezione della barra laterale. La barra laterale ĆØ il contenitore di visualizzazioni come Esplora risorse e Cerca.", "titleBarActiveForeground": "Colore primo piano della barra del titolo quando la finestra ĆØ attiva. Si noti che questo colore ĆØ attualmente supportato solo su macOS.", "titleBarInactiveForeground": "Colore primo piano della barra del titolo quando la finestra ĆØ inattiva. Si noti che questo colore ĆØ attualmente supportato solo su macOS.", "titleBarActiveBackground": "Colore di sfondo della barra di titolo quando la finestra ĆØ attiva. Si noti che questo colore ĆØ attualmente solo supportati su macOS.", "titleBarInactiveBackground": "Colore di sfondo della barra del titolo quando la finestra ĆØ inattiva. Si noti che questo colore ĆØ attualmente supportato solo su macOS.", + "titleBarBorder": "Colore del bordo della barra di stato. Si noti che questo colore ĆØ attualmente supportato solo su macOS.", "notificationsForeground": "Colore primo piano delle notifiche. Le notifiche scorrono dalla parte superiore della finestra.", "notificationsBackground": "Colore di sfondo delle notifiche. Le notifiche scorrono dalla parte superiore della finestra.", "notificationsButtonBackground": "Colore di sfondo del pulsante delle notifiche. Le notifiche scorrono dalla parte superiore della finestra.", diff --git a/i18n/ita/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/ita/src/vs/workbench/electron-browser/actions.i18n.json index ce7aaf644a5..4a97354ad49 100644 --- a/i18n/ita/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/ita/src/vs/workbench/electron-browser/actions.i18n.json @@ -6,6 +6,8 @@ { "closeActiveEditor": "Chiudi editor", "closeWindow": "Chiudi finestra", + "closeWorkspace": "Chiudi area di lavoro", + "noWorkspaceOpened": "In questa istanza non ci sono attualmente aree di lavoro aperte da chiudere.", "newWindow": "Nuova finestra", "toggleFullScreen": "Attiva/Disattiva schermo intero", "toggleMenuBar": "Attiva/Disattiva barra dei menu", @@ -20,7 +22,11 @@ "close": "Chiudi finestra", "switchWindow": "Cambia finestra...", "quickSwitchWindow": "Cambio rapido finestra...", + "workspaces": "aree di lavoro", "files": "file", + "openRecentPlaceHolderMac": "Selezionare per aprirlo (tenere premuto CMD per aprire l'elemento in una nuova finestra)", + "openRecentPlaceHolder": "Selezionare per aprirlo (tenere premuto CTRL per aprire l'elemento in una nuova finestra)", + "remove": "Rimuovi dagli elementi aperti di recente", "openRecent": "Apri recenti...", "quickOpenRecent": "Apertura rapida recenti...", "closeMessages": "Chiudi messaggi di notifica", @@ -36,5 +42,10 @@ "navigateUp": "Passa alla visualizzazione in alto", "navigateDown": "Passa alla visualizzazione in basso", "increaseViewSize": "Aumenta la dimensione della visualizzazione corrente", - "decreaseViewSize": "Diminuisce la dimensione della visualizzazione corrente" + "decreaseViewSize": "Diminuisce la dimensione della visualizzazione corrente", + "showPreviousTab": "Visualizza scheda della finestra precedente", + "showNextWindowTab": "Visualizza scheda della finestra successiva", + "moveWindowTabToNewWindow": "Sposta scheda della finestra in una nuova finestra", + "mergeAllWindowTabs": "Unisci tutte le finestre", + "toggleWindowTabsBar": "Attiva/Disattiva barra delle schede delle finestre" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/ita/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..a124f7f6f31 --- /dev/null +++ b/i18n/ita/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "Configura lingua", + "displayLanguage": "Definisce la lingua visualizzata di VSCode.", + "doc": "Per un elenco delle lingue supportate, vedere {0}.", + "restart": "Se si modifica il valore, ĆØ necessario riavviare VSCode.", + "fail.createSettings": "Non ĆØ possibile creare '{0}' ({1}).", + "JsonSchema.locale": "Linguaggio dell'interfaccia utente da usare." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json index 310e156f903..f17ae8d5fa8 100644 --- a/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -7,15 +7,17 @@ "view": "Visualizza", "help": "Guida", "file": "File", + "workspaces": "Aree di lavoro", "developer": "Sviluppatore", "showEditorTabs": "Controlla se visualizzare o meno gli editor aperti in schede.", + "workbench.editor.labelFormat.short": "Visualizza il nome del file seguito dal relativo nome di directory.", + "workbench.editor.labelFormat.long": "Visualizza il nome del file seguito dal relativo percorso assoluto.", + "tabDescription": "Controlla il formato dell'etichetta per un editor. Se si modifica questa impostazione, ad esempio, risulterĆ  più agevole individuare il percorso di un file:\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', quando un'altra scheda condivide lo stesso titolo, oppure il percorso relativo dell'area di lavoro se le schede sono disabilitate", "editorTabCloseButton": "Controlla la posizione dei pulsanti di chiusura delle schede dell'editor oppure li disabilita quando ĆØ impostata su 'off'.", "showIcons": "Controlla se visualizzare o meno un'icona per gli editor aperti. Richiede l'abilitazione anche di un tema dell'icona.", - "enablePreview": "Controlla se gli editor aperti vengono visualizzati come anteprima. Le anteprime editor vengono riutilizzate finchĆ© vengono mantenute, ad esempio tramite doppio clic o modifica.", + "enablePreview": "Controlla se gli editor aperti vengono visualizzati come anteprima. Le anteprime editor vengono riutilizzate finchĆ© vengono mantenute (ad esempio tramite doppio clic o modifica) e vengono visualizzate in corsivo.", "enablePreviewFromQuickOpen": "Controlla se gli editor aperti da Quick Open vengono visualizzati come anteprima. Le anteprime editor vengono riutilizzate finchĆ© vengono mantenute, ad esempio tramite doppio clic o modifica.", - "editorOpenPositioning": "Controlla la posizione in cui vengono aperti gli editor. Selezionare 'left' o 'right' per aprire gli editor a sinistra o a destra di quello attualmente attivo. Selezionare 'first' o 'last' per aprire gli editor indipendentemente da quello attualmente attivo.", "revealIfOpen": "Controlla se un editor viene visualizzato in uno qualsiasi dei gruppi visibili se viene aperto. Se l'opzione ĆØ disabilitata, un editor verrĆ  aperto preferibilmente nel gruppo di editor attualmente attivo. Se ĆØ abilitata, un editor giĆ  aperto verrĆ  visualizzato e non aperto di nuovo nel gruppo di editor attualmente attivo. Nota: in alcuni casi questa impostazione viene ignorata, ad esempio quando si forza l'apertura di un editor in un gruppo specifico oppure a lato del gruppo attualmente attivo.", - "commandHistory": "Controlla il numero di comandi usati di recente da mantenere nella cronologia per il riquadro comandi. Impostare su 0 per disabilitare la cronologia dei comandi.", "preserveInput": "Controlla se l'ultimo input digitato nel riquadro comandi deve essere ripristinato alla successiva riapertura del riquadro.", "closeOnFocusLost": "Controlla se Quick Open deve essere chiuso automaticamente quando perde lo stato attivo.", "openDefaultSettings": "Controlla se all'apertura delle impostazioni viene aperto anche un editor che mostra tutte le impostazioni predefinite.", @@ -23,6 +25,10 @@ "statusBarVisibility": "Controlla la visibilitĆ  della barra di stato nella parte inferiore del workbench.", "activityBarVisibility": "Controlla la visibilitĆ  della barra attivitĆ  nel workbench.", "closeOnFileDelete": "Controlla se gli editor che visualizzano un file devono chiudersi automaticamente quando il file viene eliminato o rinominato da un altro processo. Se si disabilita questa opzione, in una simile circostanza l'editor verrĆ  aperto e i file risulteranno modificati ma non salvati. Nota: se si elimina il file dall'interno dell'applicazione, l'editor verrĆ  sempre chiuso e i file modificati ma non salvati non verranno mai chiusi allo scopo di salvaguardare i dati.", + "fontAliasing": "Controlla il metodo di aliasing dei caratteri nell'area di lavoro.\n- impostazione predefinita: anti-aliasing dei caratteri a livello di sub-pixel. Nella maggior parte delle visualizzazioni non retina consentirĆ  di ottenere un testo con il massimo contrasto.\n- anti-aliasing: anti-aliasing dei caratteri a livello di pixel, invece che a livello di sub-pixel. Consente di visualizzare i caratteri più chiari.\n- nessuno: disabilita l'anti-aliasing dei caratteri. Il testo verrĆ  visualizzato con contorni irregolari.", + "workbench.fontAliasing.default": "Anti-aliasing dei caratteri a livello di sub-pixel. Nella maggior parte delle visualizzazioni non retina consentirĆ  di ottenere un testo con il massimo contrasto.", + "workbench.fontAliasing.antialiased": "Anti-aliasing dei caratteri a livello di pixel, invece che a livello di sub-pixel. Consente di visualizzare i caratteri più chiari.", + "workbench.fontAliasing.none": "Disabilita l'anti-aliasing dei caratteri. Il testo verrĆ  visualizzato con contorni irregolari. ", "swipeToNavigate": "Scorrere orizzontalmente con tre dita per spostarsi tra i file aperti.", "workbenchConfigurationTitle": "Area di lavoro", "window.openFilesInNewWindow.on": "I file verranno aperti in una nuova finestra", @@ -34,16 +40,18 @@ "window.openFoldersInNewWindow.default": "Le cartelle verranno aperte in una nuova finestra a meno che non si selezioni una cartella dall'interno dell'applicazione, ad esempio tramite il menu File", "openFoldersInNewWindow": "Controlla se le cartelle devono essere aperte in una nuova finestra o sostituire l'ultima finestra attiva.\n- default: le cartelle verranno aperte in una nuova finestra a meno che non si selezioni una cartella dall'interno dell'applicazione, ad esempio tramite il menu File\n- on: le cartelle verranno aperte in una nuova finestra\n- off: le cartelle sostituiranno l'ultima finestra attiva\nNota: possono comunque verificarsi casi in cui questa impostazione viene ignorata, ad esempio quando si usa l'opzione della riga di comando -new-window o -reuse-window.", "window.reopenFolders.all": "Riapre tutte le finestre.", + "window.reopenFolders.folders": "Riapre tutte le cartelle. Le aree di lavoro vuote non verranno ripristinate.", "window.reopenFolders.one": "Riapre l'ultima finestra attiva.", "window.reopenFolders.none": "Non riapre mai una finestra. Inizia sempre con una finestra vuota.", + "restoreWindows": "Controlla la modalitĆ  di riapertura delle finestre dopo un riavvio. Selezionare 'none' per iniziare sempre con un'area di lavoro vuota, 'one' per riaprire l'ultima finestra usata, 'folders' per riaprire tutte le finestre con cartelle aperte oppure 'all' per riaprire tutte le finestre dell'ultima sessione.", "restoreFullscreen": "Controlla se una finestra deve essere ripristinata a schermo intero se ĆØ stata chiusa in questa modalitĆ .", "zoomLevel": "Consente di modificare il livello di zoom della finestra. Il valore originale ĆØ 0 e ogni incremento superiore (ad esempio 1) o inferiore (ad esempio -1) rappresenta un aumento o una diminuzione del 20% della percentuale di zoom. ƈ anche possibile immettere valori decimali per modificare il livello di zoom con maggiore granularitĆ .", - "title": "Controlla il titolo della finestra in base all'editor attivo. Le variabili vengono sostituite in base al contesto:\n${activeEditorShort}: ad esempio myFile.txt\n${activeEditorMedium}: ad esempio myFolder/myFile.txt\n${activeEditorLong}: ad esempio /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: ad esempio myFolder\n${folderPath}: ad esempio /Users/Development/myFolder\n${rootName}: ad esempio myFolder1, myFolder2, myFolder3\n${rootPath}: ad esempio /Users/Development/myWorkspace\n${appName}: ad esempio VS Code\n${dirty}: indicatore dirty se l'editor attivo ĆØ dirty\n${separator}: separatore condizionale (\" - \") visualizzato solo quando ĆØ racchiuso tra variabili con valori", "window.newWindowDimensions.default": "Apre nuove finestre al centro della schermata.", "window.newWindowDimensions.inherit": "Apre nuove finestre le cui dimensioni sono uguali a quelle dell'ultima finestra attiva.", "window.newWindowDimensions.maximized": "Apre nuove finestre ingrandite a schermo intero.", "window.newWindowDimensions.fullscreen": "Apre nuove finestre nella modalitĆ  a schermo intero.", "newWindowDimensions": "Controlla le dimensioni relative all'apertura di una nuova finestra quando almeno un'altra finestra ĆØ giĆ  aperta. Per impostazione predefinita, una nuova finestra di dimensioni ridotte viene aperta al centro della schermata. Se ĆØ impostata su 'inherit', la finestra assumerĆ  le stesse dimensioni dell'ultima finestra attiva. Se ĆØ impostata su 'maximized', la finestra aperta risulterĆ  ingrandita, mentre con 'fullscreen' verrĆ  visualizzata a schermo intero. Sia noti che questa impostazione non impatta sulla prima finestra che era stata aperta. La prima finestra si riaprirĆ  sempre con la dimensione e la posizione che aveva prima della chiusura.", + "closeWhenEmpty": "Controlla se con la chiusura dell'ultimo editor deve essere chiusa ancge la finestra. Questa impostazione viene applicata solo alle finestre che non contengono cartelle.", "window.menuBarVisibility.default": "Il menu ĆØ nascosto solo nella modalitĆ  a schermo intero.", "window.menuBarVisibility.visible": "Il menu ĆØ sempre visibile, anche nella modalitĆ  a schermo intero.", "window.menuBarVisibility.toggle": "Il menu ĆØ nascosto ma può essere visualizzato premendo ALT.", diff --git a/i18n/ita/src/vs/workbench/electron-browser/window.i18n.json b/i18n/ita/src/vs/workbench/electron-browser/window.i18n.json index 424eb5bfbe5..8c2277fae11 100644 --- a/i18n/ita/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/ita/src/vs/workbench/electron-browser/window.i18n.json @@ -9,6 +9,5 @@ "cut": "Taglia", "copy": "Copia", "paste": "Incolla", - "selectAll": "Seleziona tutto", - "confirmOpenButton": "&&Apri" + "selectAll": "Seleziona tutto" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 20b6f54dcb3..baba081c726 100644 --- a/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Se una riga corrisponde a questo criterio, il rientro non deve essere modificato e la riga non deve essere valutata rispetto alle altre regole.", "schema.indentationRules.unIndentedLinePattern.pattern": "Criterio di RegExp per unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Flag di RegExp per unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Deve corrispondere al modello `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Deve corrispondere al modello `/^([gimuy]+)$/`.", + "schema.folding": "Impostazioni di riduzione del codice del linguaggio.", + "schema.folding.offSide": "Un linguaggio ĆØ conforme alla regola di offside se i blocchi in tale linguaggio vengono espressi in base al relativo rientro. Se questa opzione ĆØ impostata, le righe vuote appartengono al blocco successivo.", + "schema.folding.markers": "Marcatori di riduzione del codice specifici del linguaggio, come '#region' e '#endregion'. Le espressioni regolari di inizio e fine verranno confrontate con il contenuto di tutte le righe e devono essere progettate in modo efficace", + "schema.folding.markers.start": "Criterio di espressione regolare per il marcatore di inizio. L'espressione regolare deve iniziare con '^'.", + "schema.folding.markers.end": "Criterio di espressione regolare per il marcatore di fine. L'espressione regolare deve iniziare con '^'." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..bfbba165ded --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "Visualizza: Attiva/Disattiva mini mappa" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index 7e765bb3a32..cb0ebbb30fd 100644 --- a/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "Attiva/Disattiva caratteri di controllo" + "toggleRenderControlCharacters": "Visualizza: Attiva/Disattiva caratteri di controllo" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index b5457f45cbd..b874a5cc057 100644 --- a/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "Attiva/Disattiva rendering spazi vuoti" + "toggleRenderWhitespace": "Visualizza: Attiva/Disattiva rendering spazi vuoti" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index e9aa4159529..01c6c92eb4a 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "Non ci sono configurazioni", + "addConfigTo": "Aggiungi configurazione ({0})...", "addConfiguration": "Aggiungi configurazione..." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index b3b797b17a0..cd95d333b64 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, debug", "debugAriaLabel": "Digitare il nome di una configurazione di avvio da eseguire.", + "addConfigTo": "Aggiungi configurazione ({0})...", + "addConfiguration": "Aggiungi configurazione...", "noConfigurationsMatching": "Non esistono configurazioni di debug corrispondenti", "noConfigurationsFound": "Non ĆØ stata trovata alcuna configurazione di debug. Creare un file 'launch.json'." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 2b0ce6dfdf4..7729690837e 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "Configurazioni per generare la versione iniziale di 'launch.json'.", "vscode.extension.contributes.debuggers.languages": "Elenco dei linguaggi. per cui l'estensione di debug può essere considerata il \"debugger predefinito\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Se ĆØ specificato, Visual Studio Code chiamerĆ  questo comando per determinare il percorso eseguibile della scheda di debug e gli argomenti da passare.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Se ĆØ specificato, Visual Studio Code chiamerĆ  questo comando per le azioni \"debug\" o \"run\" previste come destinazione di questa estensione.", "vscode.extension.contributes.debuggers.configurationSnippets": "Frammenti per l'aggiunta di nuove configurazioni in 'launch.json'.", "vscode.extension.contributes.debuggers.configurationAttributes": "Configurazioni dello schema JSON per la convalida di 'launch.json'.", "vscode.extension.contributes.debuggers.windows": "Impostazioni specifiche di Windows.", diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 9df96f524f9..2a7a5e5d5a5 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -13,11 +13,10 @@ "compoundMustHaveConfigurations": "Per avviare più configurazioni, deve essere impostato l'attributo \"configurations\" dell'elemento compounds.", "configMissing": "In 'launch.json' manca la configurazione '{0}'.", "debugTypeNotSupported": "Il tipo di debug configurato '{0}' non ĆØ supportato.", - "debugTypeMissing": "Manca la proprietĆ  'type' per la configurazione di avvio scelta.", + "debugAnyway": "Eseguire comunque il debug", "preLaunchTaskErrors": "Sono stati rilevati errori di compilazione durante preLaunchTask '{0}'.", "preLaunchTaskError": "ƈ stato rilevato un errore di compilazione durante preLaunchTask '{0}'.", "preLaunchTaskExitCode": "L'attivitĆ  di preavvio '{0}' ĆØ stata terminata ed ĆØ stato restituito il codice di uscita {1}.", - "debugAnyway": "Eseguire comunque il debug", "noFolderWorkspaceDebugError": "Non ĆØ possibile eseguire il debug del file attivo. Assicurarsi che sia salvato su disco e che sia installata un'estensione di debug per tale tipo di file.", "NewLaunchConfig": "Impostare il file di configurazione di avvio per l'applicazione. {0}", "DebugTaskNotFound": "L'attivitĆ  di preavvio '{0}' non ĆØ stata trovata." diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index fff7cbcba9e..2740934029a 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "Lo stato dell'oggetto viene acquisito dalla prima valutazione", "replVariableAriaLabel": "Il valore della variabile {0} ĆØ {1}, ciclo Read Eval Print, debug", "replExpressionAriaLabel": "Il valore dell'espressione {0} ĆØ {1}, ciclo Read Eval Print, debug", - "replValueOutputAriaLabel": "{0}, ciclo Read Eval Print, debug", - "replKeyValueOutputAriaLabel": "Il valore della variabile di output {0} ĆØ {1}, ciclo Read Eval Print, debug" + "replValueOutputAriaLabel": "{0}, ciclo Read Eval Print, debug" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index c13997bfc29..cfdee9e4ec2 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "Colore di sfondo della barra di stato quando ĆØ in corso il debug di un programma. La barra di stato ĆØ visualizzata nella parte inferiore della finestra", - "statusBarDebuggingForeground": "Colore primo piano della barra di stato quando ĆØ in corso il debug di un programma. La barra di stato ĆØ visualizzata nella parte inferiore della finestra" + "statusBarDebuggingForeground": "Colore primo piano della barra di stato quando ĆØ in corso il debug di un programma. La barra di stato ĆØ visualizzata nella parte inferiore della finestra", + "statusBarDebuggingBorder": "Colore del bordo della barra di stato che la separa dalla barra laterale e dall'editor durante il debug di un programma. La barra di stato ĆØ visualizzata nella parte inferiore della finestra." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index d116abf4820..b4cf1e3c59d 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "Il file eseguibile '{0}' dell'adattatore di debug non esiste.", "debugAdapterCannotDetermineExecutable": "Non ĆØ possibile determinare il file eseguibile per l'adattatore di debug '{0}'.", + "launch.config.comment1": "Usare IntelliSense per informazioni sui possibili attributi.", + "launch.config.comment2": "Al passaggio del mouse vengono visualizzate le descrizioni degli attributi esistenti.", + "launch.config.comment3": "Per ulteriori informazioni, visitare: {0}", "debugType": "Tipo di configurazione.", "debugTypeNotRecognised": "Il tipo di debug non ĆØ riconosciuto. Assicurarsi di avere un'estensione appropriata per il debug installata e che sia abilitata.", "node2NotSupported": "\"node2\" non ĆØ più supportato. In alternativa, usare \"node\" e impostare l'attributo \"protocol\" su \"inspector\".", diff --git a/i18n/ita/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json index adf7b3f4042..1b150a45b5f 100644 --- a/i18n/ita/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "terminalConfigurationTitle": "Terminale esterno", + "explorer.openInTerminalKind": "Personalizza il tipo di terminale da avviare.", "terminal.external.windowsExec": "Personalizza il terminale da eseguire in Windows.", "terminal.external.osxExec": "Personalizza l'applicazione di terminale da eseguire in OS X.", "terminal.external.linuxExec": "Personalizza il terminale da eseguire in Linux.", diff --git a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index d621f11350a..64cacf41da1 100644 --- a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "Nome", "view location": "Dove", - "themes": "Temi ({0})", + "colorThemes": "Temi colore ({0})", + "iconThemes": "Temi icona ({0})", + "colors": "Colori ({0})", + "colorId": "ID", + "defaultDark": "Predefinito scuro", + "defaultLight": "Predefinito chiaro", + "defaultHC": "Predefinito contrasto elevato", "JSON Validation": "Convalida JSON ({0})", "commands": "Comandi ({0})", "command name": "Nome", diff --git a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 2430ac5cd9b..3d729450651 100644 --- a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,23 +34,24 @@ "postDisableMessage": "Ricaricare questa finestra per disattivare l'estensione '{0}'?", "postUninstallTooltip": "Ricaricare per disattivare", "postUninstallMessage": "Ricaricare questa finestra per disattivare l'estensione disinstallata '{0}'?", - "reload": "&&Ricarica finestra", "toggleExtensionsViewlet": "Mostra estensioni", "installExtensions": "Installa estensioni", + "showEnabledExtensions": "Mostra estensioni abilitate", "showInstalledExtensions": "Mostra estensioni installate", "showDisabledExtensions": "Mostra estensioni disabilitate", "clearExtensionsInput": "Cancella input estensioni", "showOutdatedExtensions": "Mostra estensioni obsolete", "showPopularExtensions": "Mostra estensioni più richieste", "showRecommendedExtensions": "Mostra estensioni consigliate", - "showWorkspaceRecommendedExtensions": "Mostra estensioni consigliate per l'area di lavoro", "showRecommendedKeymapExtensions": "Mostra mappature tastiera consigliate", "showRecommendedKeymapExtensionsShort": "Mappature tastiera", "showLanguageExtensions": "Mostra estensioni del linguaggio", "showLanguageExtensionsShort": "Estensioni del linguaggio", - "configureWorkspaceRecommendedExtensions": "Configura estensioni consigliate (area di lavoro)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Gli elementi consigliati sono disponibili solo per una cartella dell'area di lavoro.", + "showAzureExtensions": "Mostra estensioni di Azure", + "showAzureExtensionsShort": "Estensioni di Azure", "OpenExtensionsFile.failed": "Non ĆØ possibile creare il file 'extensions.json' all'interno della cartella '.vscode' ({0}).", + "configureWorkspaceRecommendedExtensions": "Configura estensioni consigliate (area di lavoro)", + "configureWorkspaceFolderRecommendedExtensions": "Configura estensioni consigliate (cartella dell'area di lavoro)", "builtin": "Predefinita", "disableAll": "Disabilita tutte le estensioni installate", "disableAllWorkspace": "Disabilita tutte le estensioni installate per questa area di lavoro", diff --git a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..7270442b342 --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "Consigliate" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index 0aa6089b6dc..c399ecf9352 100644 --- a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "Premere INVIO per gestire le estensioni.", + "notfound": "Estensione '{0}' non trovata nel Marketplace.", + "install": "Premere INVIO per installare '{0}' dal Marketplace.", "searchFor": "Premere INVIO per cercare '{0}' nel Marketplace.", "noExtensionsToInstall": "Digitare un nome di estensione" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 9d16c7dad0f..235d3012292 100644 --- a/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -5,11 +5,13 @@ // Do not edit this file. It is machine generated. { "reallyRecommended2": "Per questo tipo di file ĆØ consigliabile utilizzare l'estensione '{0}'.", + "reallyRecommendedExtensionPack": "Per questo tipo di file ĆØ consigliabile usare il pacchetto di estensione '{0}'.", "showRecommendations": "Mostra gli elementi consigliati", + "install": "Installa", "neverShowAgain": "Non visualizzare più questo messaggio", "close": "Chiudi", "workspaceRecommended": "Per questa area di lavoro sono disponibili estensioni consigliate.", - "ignoreExtensionRecommendations": "Si desidera ignorare tutte le raccomandazioni di estensioni?", + "ignoreExtensionRecommendations": "Ignorare tutti i suggerimenti per le estensioni?", "ignoreAll": "SƬ, ignora tutti", "no": "No", "cancel": "Annulla" diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 08176692fa7..979ee1896bb 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -5,5 +5,7 @@ // Do not edit this file. It is machine generated. { "filesCategory": "File", - "revealInSideBar": "Visualizza nella barra laterale" + "revealInSideBar": "Visualizza nella barra laterale", + "acceptLocalChanges": "Utilizzare le modifiche e sovrascrivere il contenuto del disco", + "revertLocalChanges": "Annullare le modifiche e tornare al contenuto sul disco" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json index ffdd6650295..ce01ca87af5 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,17 +37,14 @@ "openToSide": "Apri lateralmente", "compareSource": "Seleziona per il confronto", "globalCompareFile": "Confronta file attivo con...", - "pickHistory": "Selezionare un file aperto in precedenza per il confronto", - "unableToFileToCompare": "Non ĆØ possibile confrontare il file selezionato con '{0}'.", "openFileToCompare": "Aprire prima un file per confrontarlo con un altro file.", - "compareWith": "Confronta con '{0}'", + "compareWith": "Confronta '{0}' con '{1}'", "compareFiles": "Confronta file", "refresh": "Aggiorna", "save": "Salva", "saveAs": "Salva con nome...", "saveAll": "Salva tutto", "saveAllInGroup": "Salva tutto nel gruppo", - "saveFiles": "Salva file modificati ma non salvati", "revert": "Ripristina file", "focusOpenEditors": "Stato attivo su visualizzazione editor aperti", "focusFilesExplorer": "Stato attivo su Esplora file", @@ -55,7 +52,6 @@ "openFileToShow": "Aprire prima di tutto un file per visualizzarlo in Esplora risorse", "collapseExplorerFolders": "Comprimi cartelle in Explorer", "refreshExplorer": "Aggiorna Explorer", - "openFile": "Apri file...", "openFileInNewWindow": "Apri file attivo in un'altra finestra", "openFileToShowInNewWindow": "Aprire prima un file per visualizzarlo in un'altra finestra", "revealInWindows": "Visualizza in Esplora risorse", @@ -69,5 +65,7 @@ "emptyFileNameError": "ƈ necessario specificare un nome file o un nome di cartella.", "fileNameExistsError": "In questo percorso esiste giĆ  un file o una cartella **{0}**. Scegliere un nome diverso.", "invalidFileNameError": "Il nome **{0}** non ĆØ valido per un nome file o un nome di cartella. Scegliere un nome diverso.", - "filePathTooLongError": "Con il nome **{0}** il percorso diventa troppo lungo. Scegliere un nome più breve." + "filePathTooLongError": "Con il nome **{0}** il percorso diventa troppo lungo. Scegliere un nome più breve.", + "compareWithSaved": "Confronta file attivo con file salvato", + "modifiedLabel": "{0} (su disco) ↔ {1}" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 8139ec4bf13..34e5d5d0c26 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "Editor file di testo", "binaryFileEditor": "Editor file binari", "filesConfigurationTitle": "File", - "exclude": "Consente di configurare i criteri di ricerca GLOB per escludere file e cartelle.", + "exclude": "Consente di configurare i criteri GLOB per escludere file e cartelle. Ad esempio, la funzionalitĆ  Esplora file stabilisce quali file e cartelle mostrare o nascondere in base a questa impostazione.", "files.exclude.boolean": "Criterio GLOB da usare per trovare percorsi file. Impostare su True o False per abilitare o disabilitare il criterio.", "files.exclude.when": "Controllo aggiuntivo sugli elementi di pari livello di un file corrispondente. Usare $(basename) come variabile del nome file corrispondente.", "associations": "Consente di configurare le associazioni tra file e linguaggi, ad esempio \"*.extension\": \"html\". Queste hanno la precedenza sulle associazioni predefinite dei linguaggi installate.", - "encoding": "Codifica del set di caratteri predefinita da usare durante la lettura e la scrittura di file.", - "autoGuessEncoding": "Quando questa opzione ĆØ abilitata, la codifica del set di caratteri viene ipotizzata all'apertura dei file", + "encoding": "Codifica del set di caratteri predefinita da usare durante la lettura e la scrittura di file. ƈ possibile configurare questa impostazione anche in base alla lingua.", + "autoGuessEncoding": "Quando questa opzione ĆØ abilitata, la codifica del set di caratteri viene ipotizzata all'apertura dei file. ƈ possibile configurare questa impostazione anche in base alla lingua.", "eol": "Il carattere di fine riga predefinito. Utilizzare \\n per LF e \\r\\n per CRLF.", "trimTrailingWhitespace": "Se ĆØ abilitato, taglierĆ  lo spazio vuoto quando si salva un file.", "insertFinalNewline": "Se ĆØ abilitato, inserisce un carattere di nuova riga finale alla fine del file durante il salvataggio.", + "trimFinalNewlines": "Se ĆØ abilitato, taglia tutte le nuove righe dopo il carattere di nuova riga finale alla fine del file durante il salvataggio.", "files.autoSave.off": "Un file dirty non viene mai salvato automaticamente.", "files.autoSave.afterDelay": "Un file dirty viene salvato automaticamente in base al valore configurato di 'files.autoSaveDelay'.", "files.autoSave.onFocusChange": "Un file dirty viene salvato automaticamente quando l'editor perde lo stato attivo.", @@ -38,5 +39,11 @@ "openEditorsVisible": "Numero di editor visualizzati nel riquadro degli editor aperti. Impostarlo su 0 per nascondere il riquadro.", "dynamicHeight": "Controlla se l'altezza della sezione degli editor aperti deve essere adattata o meno dinamicamente al numero di elementi.", "autoReveal": "Controlla se Esplora risorse deve rivelare automaticamente e selezionare i file durante l'apertura.", - "enableDragAndDrop": "Controlla se Esplora risorse deve consentire lo spostamento di file e cartelle tramite trascinamento della selezione." + "enableDragAndDrop": "Controlla se Esplora risorse deve consentire lo spostamento di file e cartelle tramite trascinamento della selezione.", + "sortOrder.default": "I file e le cartelle vengono ordinati in ordine alfabetico in base al nome. Le cartelle vengono visualizzate prima dei file.", + "sortOrder.mixed": "I file e le cartelle vengono ordinati ordine alfabetico in base al nome, in un unico elenco ordinato.", + "sortOrder.filesFirst": "I file e le cartelle vengono ordinati in ordine alfabetico in base al nome. I file vengono visualizzati prima delle cartelle.", + "sortOrder.type": "I file e le cartelle vengono ordinati in ordine alfabetico in base all'estensione. Le cartelle vengono visualizzate prima dei file.", + "sortOrder.modified": "I file e le cartelle vengono ordinati in ordine decrescente in base alla data dell'ultima modifica. Le cartelle vengono visualizzate prima dei file.", + "sortOrder": "Controlla l'ordinamento di file e cartelle in Esplora risorse. Oltre all'ordinamento predefinito, ĆØ possibile impostare l'ordine su 'mixed' (file e cartelle vengono ordinati insieme), 'type' (in base al tipo di file), 'modified' (in base alla data dell'ultima modifica) o 'filesFirst' (i file vengono ordinati prima delle cartelle)." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 676f0815dca..49ebceb9611 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "Usare le azioni della barra degli strumenti dell'editor a destra per **annullare** le modifiche o per **sovrascrivere** il contenuto su disco con le modifiche", "discard": "Rimuovi", "overwrite": "Sovrascrivi", "retry": "Riprova", diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 9ae2216ff99..586895b4e44 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "Nessuna cartella aperta", "explorerSection": "Sezione Esplora file", - "noWorkspaceHelp": "Non ci sono ancora cartelle aperte.", + "noFolderHelp": "Non ci sono ancora cartelle aperte.", "openFolder": "Apri cartella" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..e0b8c74653b --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Esplora risorse" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 1ae9f2df391..dc14341c65f 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,10 @@ { "fileInputAriaLabel": "Digitare il nome file. Premere INVIO per confermare oppure ESC per annullare.", "filesExplorerViewerAriaLabel": "{0}, Esplora file", + "dropFolders": "Aggiungere le cartelle all'area di lavoro?", + "dropFolder": "Aggiungere la cartella all'area di lavoro?", + "addFolders": "&& Aggiungi cartelle", + "addFolder": "&&Aggiungi cartella", "confirmOverwriteMessage": "'{0}' esiste giĆ  nella cartella di destinazione. Sostituirlo?", "irreversible": "Questa azione ĆØ irreversibile.", "replaceButtonLabel": "&&Sostituisci" diff --git a/i18n/ita/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json b/i18n/ita/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json index da4666ce1f4..8cdbd287795 100644 --- a/i18n/ita/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json @@ -9,6 +9,7 @@ "saveAll": "Salva tutto", "closeAllUnmodified": "Chiudi non modificate", "closeAll": "Chiudi tutto", + "compareWithSaved": "Confronta con file salvato", "close": "Chiudi", "closeOthers": "Chiudi altri" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/ita/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 53e90cc6554..92d5051b4e0 100644 --- a/i18n/ita/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 file non salvato", "dirtyFiles": "{0} file non salvati" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/ita/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..a94d98e0980 --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Problemi", + "tooltip.1": "1 problema in questo file", + "tooltip.N": "{0} problemi in questo file", + "markers.showOnFile": "Visualizza errori & avvisi su file e cartella." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/ita/src/vs/workbench/parts/markers/common/messages.i18n.json index f912757227d..ec1b923160e 100644 --- a/i18n/ita/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "Visualizza", + "problems.view.toggle.label": "Attiva/disattiva problemi", "problems.view.show.label": "Mostra problemi", + "problems.view.hide.label": "Nascondi problemi", "problems.panel.configuration.title": "Visualizzazione Problemi", "problems.panel.configuration.autoreveal": "Controlla se la visualizzazione Problemi deve visualizzare automaticamente i file durante l'apertura", "markers.panel.title.problems": "Problemi", diff --git a/i18n/ita/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/ita/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index 3ccaa2931c5..3a6a357492a 100644 --- a/i18n/ita/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "Copia" + "copyMarker": "Copia", + "copyMarkerMessage": "Copia messaggio" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index e72592662b9..a4bad776c26 100644 --- a/i18n/ita/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "ƈ stato rilevato un rallentamento all'avvio", - "slow.detail": "ƈ stato appena rilevato un rallentamento all'avvio. Per consentire a Microsoft di analizzare e risolvere il problema, riavviare '{0}' con la profilatura abilitata e condividere i profili.", "prof.message": "I profili sono stati creati.", "prof.detail": "Creare un problema e allegare manualmente i file seguenti:\n{0}", "prof.restartAndFileIssue": "Crea problema e riavvia", diff --git a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 12a31fb4c16..a5a6e8a1bba 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -8,6 +8,7 @@ "openGlobalKeybindings": "Apri tasti di scelta rapida", "openGlobalKeybindingsFile": "Apri file dei tasti di scelta rapida", "openWorkspaceSettings": "Apri impostazioni area di lavoro", + "openFolderSettings": "Apri impostazioni cartella", "configureLanguageBasedSettings": "Configura impostazioni specifiche del linguaggio...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Seleziona linguaggio" diff --git a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index 411f31bd650..973412c0e73 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -8,7 +8,7 @@ "SearchSettingsWidget.AriaLabel": "Cerca impostazioni", "SearchSettingsWidget.Placeholder": "Cerca impostazioni", "totalSettingsMessage": "{0} impostazioni in totale", - "noSettingsFound": "Nessuna impostazione corrispondente", + "noSettingsFound": "Nessun risultato", "oneSettingFound": "1 impostazione corrispondente", "settingsFound": "{0} impostazioni corrispondenti", "fileEditorWithInputAriaLabel": "{0}. Editor file di testo.", diff --git a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index cb813bd7a4f..bfe4ac78d72 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "Impossibile scrivere nelle impostazioni. Correggere eventuali errori o avvisi nel file e riprovare.", + "emptyUserSettingsHeader": "Inserire le impostazioni qui per sovrascrivere quelle predefinite.", + "emptyWorkspaceSettingsHeader": "Inserire le impostazioni qui per sovrascrivere le impostazioni utente.", + "emptyFolderSettingsHeader": "Inserire le impostazioni cartella qui per sovrascrivere quelle dell'area di lavoro.", + "defaultFolderSettingsTitle": "Impostazioni cartella predefinite", "defaultSettingsTitle": "Impostazioni predefinite", - "noSettingsFound": "Non sono state trovate impostazioni.", "editTtile": "Modifica", "replaceDefaultValue": "Sostituisci nelle impostazioni", "copyDefaultValue": "Copia nelle impostazioni", "unsupportedPHPExecutablePathSetting": "Questa deve essere un'impostazione utente. Per configurare PHP per l'area di lavoro, aprire un file PHP e fare clic su 'Percorso PHP' nella barra di stato.", - "unsupportedWorkspaceSetting": "Questa deve essere un'impostazione utente." + "unsupportedWorkspaceSetting": "Questa deve essere un'impostazione utente.", + "unsupportedWorkbenchSetting": "Non ĆØ possibile applicare ora questa impostazione. VerrĆ  applicata direttamente all'apertura della cartella." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json index dcc0829c0a6..6bdc47b5796 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json @@ -7,5 +7,6 @@ "openFolderFirst": "Aprire prima una cartella per creare le impostazioni dell'area di lavoro", "emptyKeybindingsHeader": "Inserire i tasti di scelta rapida in questo file per sovrascrivere i valori predefiniti", "defaultKeybindings": "Tasti di scelta rapida predefiniti", + "folderSettingsName": "{0} (Impostazioni cartella)", "fail.createSettings": "Non ĆØ possibile creare '{0}' ({1})." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 8b6ad71cd4e..58c15096c23 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "noSettingsFound": "Non sono state trovate impostazioni.", + "folderSettingsDetails": "Impostazioni cartella" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index da90d23aa12..7149b64d24f 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "Più usate", - "noSettings": "Nessuna impostazione", "defaultKeybindingsHeader": "Per sovrascrivere i tasti di scelta rapida, inserirli nel file dei tasti di scelta rapida." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 28964d0cf5c..543c602df83 100644 --- a/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "Il comando '{0}' non ĆØ abilitato nel contesto corrente.", "recentlyUsed": "usate di recente", "morecCommands": "altri comandi", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Non ci sono comandi corrispondenti" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index b04fcadda7a..2a7acdf1e22 100644 --- a/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,6 +6,5 @@ { "relaunchSettingMessage": "ƈ necessario riavviare per rendere effettiva un'impostazione modificata.", "relaunchSettingDetail": "Fare clic sul pulsante di riavvio per riavviare {0} e abilitare l'impostazione.", - "restart": "Riavvia", - "reload": "Ricarica" + "restart": "&&Riavvia" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/ita/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 504c42cd090..273b2228aba 100644 --- a/i18n/ita/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} di {1} modifiche", + "change": "{0} di {1} modifica", + "show previous change": "Mostra modifica precedente", + "show next change": "Mostra modifica successiva", "editorGutterModifiedBackground": "Colore di sfondo della barra di navigazione dell'editor per le righe che sono state modificate.", "editorGutterAddedBackground": "Colore di sfondo della barra di navigazione dell'editor per le righe che sono state aggiunte.", - "editorGutterDeletedBackground": "Colore di sfondo della barra di navigazione dell'editor per le righe che sono state cancellate." + "editorGutterDeletedBackground": "Colore di sfondo della barra di navigazione dell'editor per le righe che sono state cancellate.", + "overviewRulerModifiedForeground": "Colore del marcatore del righello delle annotazioni per il contenuto modificato.", + "overviewRulerAddedForeground": "Colore del marcatore del righello delle annotazioni per il contenuto aggiunto.", + "overviewRulerDeletedForeground": "Colore del marcatore del righello delle annotazioni per il contenuto eliminato." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index acbf024d405..44389863a65 100644 --- a/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Mostra GIT", - "installAdditionalSCMProviders": "Installa ulteriori provider SCM ...", "source control": "Controllo del codice sorgente", "toggleSCMViewlet": "Mostra Gestione controllo servizi", "view": "Visualizza" diff --git a/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 6400c7be4ed..8bc8834c5e7 100644 --- a/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Provider di controllo del codice sorgente", + "hideRepository": "Nascondi", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "Installa ulteriori provider SCM ...", + "no open repo": "Non esistono provider di controllo codice sorgente attivi.", "source control": "Controllo del codice sorgente", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 4daa1ea7025..9cda34a7b9a 100644 --- a/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "Vai al simbolo nell'area di lavoro...", "name": "Cerca", - "showSearchViewlet": "Mostra Cerca", + "search": "Cerca", "view": "Visualizza", - "findInFiles": "Cerca nei file", "openAnythingHandlerDescription": "Vai al file", "openSymbolDescriptionNormal": "Vai al simbolo nell'area di lavoro", "searchOutputChannelTitle": "Cerca", @@ -16,7 +15,7 @@ "exclude": "Consente di configurare i criteri GLOB per escludere file e cartelle nelle ricerche. Eredita tutti i criteri GLOB dall'impostazione files.exclude.", "exclude.boolean": "Criterio GLOB da usare per trovare percorsi file. Impostare su True o False per abilitare o disabilitare il criterio.", "exclude.when": "Controllo aggiuntivo sugli elementi di pari livello di un file corrispondente. Usare $(basename) come variabile del nome file corrispondente.", - "useRipgrep": "Controlla se usare ripgrep durante la ricerca di testo", - "useIgnoreFilesByDefault": "Controlla se utilizzare i file .gitignore e .ignore come impostazione predefinita durante la ricerca in una nuova area di lavoro", - "search.quickOpen.includeSymbols": "Configurare questa opzione per includere i risultati di una ricerca di simboli globale nei risultati dei file per Quick Open." + "useRipgrep": "Controlla l'utilizzo di ripgrep nelle ricerche su testo e file", + "search.quickOpen.includeSymbols": "Configurare questa opzione per includere i risultati di una ricerca di simboli globale nei risultati dei file per Quick Open.", + "search.followSymlinks": "Controlla se seguire i collegamenti simbolici durante la ricerca." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 21137b24d8a..8d2f14cd8ac 100644 --- a/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,16 +4,23 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "Mostra i criteri di inclusione per la ricerca successivi", + "previousSearchIncludePattern": "Mostra i criteri di inclusione per la ricerca precedenti", + "nextSearchExcludePattern": "Mostra i criteri di esclusione per la ricerca successivi", + "previousSearchExcludePattern": "Mostra i criteri di esclusione per la ricerca precedenti", "nextSearchTerm": "Mostra il termine di ricerca successivo", "previousSearchTerm": "Mostra il termine di ricerca precedente", "focusNextInputBox": "Sposta lo stato attivo sulla casella di input successiva", "focusPreviousInputBox": "Sposta lo stato attivo sulla casella di input precedente", + "showSearchViewlet": "Mostra Cerca", + "findInFiles": "Cerca nei file", "replaceInFiles": "Sostituisci nei file", + "findInWorkspace": "Trova nell'area di lavoro...", + "findInFolder": "Trova nella cartella...", "RefreshAction.label": "Aggiorna", "ClearSearchResultsAction.label": "Cancella risultati della ricerca", "FocusNextSearchResult.label": "Sposta lo stato attivo sul risultato della ricerca successivo", "FocusPreviousSearchResult.label": "Sposta lo stato attivo sul risultato della ricerca precedente", - "RemoveAction.label": "Rimuovi", "file.replaceAll.label": "Sostituisci tutto", "match.replace.label": "Sostituisci" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json b/i18n/ita/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json index 13608466e81..53c1288f408 100644 --- a/i18n/ita/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "searchFolderMatch.other.label": "Altri file", + "searchFileMatches": "{0} file trovati", + "searchFileMatch": "{0} file trovato", "searchMatches": "{0} corrispondenze trovate", "searchMatch": "{0} corrispondenza trovata", + "folderMatchAriaLabel": "{0} corrispondenze nella cartella radice {1}, risultato della ricerca", "fileMatchAriaLabel": "{0} corrispondenze nel file {1} della cartella {2}, risultato della ricerca", "replacePreviewResultAria": "Sostituisce il termine {0} con {1} alla colonna {2} in linea con il testo {3}", "searchResultAria": "Trovato termine {0} alla colonna {1} in linea con il testo {2}" diff --git a/i18n/ita/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/ita/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index fbd469a7550..82b6def2af9 100644 --- a/i18n/ita/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "file da escludere", "label.excludes": "Criteri di esclusione per la ricerca", "replaceAll.confirmation.title": "Sostituisci tutto", - "replaceAll.confirm.button": "Sostituisci", + "replaceAll.confirm.button": "&&Sostituisci", "replaceAll.occurrence.file.message": "{0} occorrenza in {1} file ĆØ stata sostituita con '{2}'.", "removeAll.occurrence.file.message": "ƈ stata sostituita {0} occorrenza in {1} file.", "replaceAll.occurrence.files.message": "{0} occorrenza in {1} file ĆØ stata sostituita con '{2}'.", @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "Sostituire {0} occorrenze in {1} file con '{2}'?", "replaceAll.occurrences.files.confirmation.message": "Sostituire {0} occorrenze in {1} file?", "treeAriaLabel": "Risultati ricerca", + "searchPathNotFoundError": "Percorso di ricerca non trovato: {0}", "searchMaxResultsWarning": "Il set di risultati contiene solo un subset di tutte le corrispondenze. Eseguire una ricerca più specifica per ridurre il numero di risultati.", "searchCanceled": "La ricerca ĆØ stata annullata prima della visualizzazione dei risultati - ", "noResultsIncludesExcludes": "Non sono stati trovati risultati in '{0}' escludendo '{1}' - ", "noResultsIncludes": "Non sono stati trovati risultati in '{0}' - ", "noResultsExcludes": "Non sono stati trovati risultati escludendo '{0}' - ", - "noResultsFound": "Non sono stati trovati risultati. Rivedere le impostazioni relative alle esclusioni configurate - ", + "noResultsFound": "Nessun risultato trovato. Rivedere le impostazioni delle esclusioni configurate e file ignorati - ", "rerunSearch.message": "Cerca di nuovo", "rerunSearchInAll.message": "Cerca di nuovo in tutti i file", "openSettings.message": "Apri impostazioni", + "openSettings.learnMore": "Altre informazioni", "ariaSearchResultsStatus": "La ricerca ha restituito {0} risultati in {1} file", "search.file.result": "{0} risultato in {1} file", "search.files.result": "{0} risultato in {1} file", diff --git a/i18n/ita/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/ita/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..a6395559551 --- /dev/null +++ b/i18n/ita/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Nell'area di lavoro non ci sono cartelle denominate {0}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index f501a03d135..580b9d74850 100644 --- a/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "Inserisci frammento" + "snippet.suggestions.label": "Inserisci frammento", + "sep.userSnippet": "Frammenti utente", + "sep.extSnippet": "Frammenti estensione" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index d64cfaa2128..afa0a10cc14 100644 --- a/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "Il linguaggio in `contributes.{0}.language` ĆØ sconosciuto. Valore specificato: {1}", + "invalid.path.0": "ƈ previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", + "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile.", + "vscode.extension.contributes.snippets": "Frammenti per contributes.", + "vscode.extension.contributes.snippets-language": "Identificatore di linguaggio per cui si aggiunge come contributo questo frammento.", + "vscode.extension.contributes.snippets-path": "Percorso del file snippets. ƈ relativo alla cartella delle estensioni e in genere inizia con './snippets/'.", + "badFile": "Non ĆØ stato possibile leggere il file di frammento \"{0}\".", "source.snippet": "Frammento utente", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 5894505714e..bdf08a4e790 100644 --- a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "Consente di configurare il pannello usato per presentare l'output dell'attivitĆ  e legge il relativo input.", "JsonSchema.tasks.presentation.echo": "Controlla se l'eco del comando eseguito viene visualizzato nel pannello. Il valore predefinito ĆØ true.", "JsonSchema.tasks.presentation.focus": "Controlla se il pannello riceve lo stato attivo. Il valore predefinito ĆØ false. Se ĆØ impostato su true, il pannello viene anche visualizzato.", + "JsonSchema.tasks.presentation.reveal.always": "Visualizza sempre il terminale quando viene eseguita questa attivitĆ .", + "JsonSchema.tasks.presentation.reveal.silent": "Visualizza il terminale solo se all'attivitĆ  non ĆØ associato alcun matcher problemi e si verifica un errore durante l'esecuzione dell'attivitĆ .", + "JsonSchema.tasks.presentation.reveal.never": "Non visualizza mai il terminale quando viene eseguita questa attivitĆ .", "JsonSchema.tasks.presentation.reveals": "Controlla se il pannello che esegue l'attivitĆ  viene visualizzato o meno. Il valore predefinito ĆØ \"always\".", "JsonSchema.tasks.presentation.instance": "Controlli se il pannello ĆØ condiviso tra le attivitĆ , dedicato a quest'attivitĆ  o se ne viene creato uno nuovo a ogni esecuzione.", "JsonSchema.tasks.terminal": "La proprietĆ  terminal ĆØ deprecata. In alternativa, usare presentation.", @@ -22,7 +25,6 @@ "JsonSchema.tasks.group.test": "Contrassegna l'attivitĆ  come attivitĆ  di test accessibile tramite il comando 'Esegui attivitĆ  di test'.", "JsonSchema.tasks.group.none": "Non assegna l'attivitĆ  ad alcun gruppo", "JsonSchema.tasks.group": "Definisce il gruppo di esecuzione a cui appartiene questa attivitĆ . Supporta \"build\" per aggiungerlo al gruppo di compilazione e \"test\" per aggiungerlo al gruppo di test.", - "JsonSchema.tasks.type": "Definisce se l'attivitĆ  viene eseguita come un processo o come un comando all'interno di una shell. L'impostazione predefinita ĆØ processo.", "JsonSchema.version": "Numero di versione della configurazione", "JsonSchema.tasks.identifier": "Identificatore definito dall'utente per fare riferimento all'attivitĆ  in launch.json o in una clausola dependsOn.", "JsonSchema.tasks.taskLabel": "Etichetta dell'attivitĆ ", @@ -35,8 +37,10 @@ "JsonSchema.tasks.customize.deprecated": "La proprietĆ  customize ĆØ deprecata. Vedere le note sulla versione 1.14 per informazioni su come eseguire la migrazione al nuovo approccio di personalizzazione delle attivitĆ ", "JsonSchema.tasks.showOputput.deprecated": "La proprietĆ  showOutput ĆØ deprecata. In alternativa, usare invece la proprietĆ  reveal all'interno della proprietĆ  presentation. Vedere anche le note sulla versione 1.14.", "JsonSchema.tasks.echoCommand.deprecated": "La proprietĆ  echoCommand ĆØ deprecata. In alternativa, usare la proprietĆ  echo all'interno della proprietĆ  presentation. Vedere anche le note sulla versione 1.14.", + "JsonSchema.tasks.suppressTaskName.deprecated": "La proprietĆ  suppressTaskName ĆØ deprecata. In alternativa, incorporare nell'attivitĆ  il comando con i relativi argomenti. Vedere anche le note sulla versione 1.14.", "JsonSchema.tasks.isBuildCommand.deprecated": "La proprietĆ  isBuildCommand ĆØ deprecata. In alternativa, usare la proprietĆ  group. Vedere anche le note sulla versione 1.14.", "JsonSchema.tasks.isTestCommand.deprecated": "La proprietĆ  isTestCommand ĆØ deprecata. In alternativa, usare la proprietĆ  group. Vedere anche le note sulla versione 1.14.", + "JsonSchema.tasks.taskSelector.deprecated": "La proprietĆ  taskSelector ĆØ deprecata. In alternativa, incorporare nell'attivitĆ  il comando con i relativi argomenti. Vedere anche le note sulla versione 1.14. ", "JsonSchema.windows": "Configurazione dei comandi specifica di Windows", "JsonSchema.mac": "Configurazione dei comandi specifica di Mac", "JsonSchema.linux": "Configurazione dei comandi specifica di Linux" diff --git a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 5e2515ceeda..86527fb1ac6 100644 --- a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,30 +5,34 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "AttivitĆ ", - "ConfigureTaskRunnerAction.noWorkspace": "Le attivitĆ  sono disponibili solo per una cartella dell'area di lavoro.", - "ConfigureTaskRunnerAction.quickPick.template": "Seleziona strumento di esecuzione attivitĆ ", - "ConfigureTaskRunnerAction.autoDetecting": "Rilevamento automatico delle attivitĆ  per {0}", - "ConfigureTaskRunnerAction.autoDetect": "Il rilevamento automatico del sistema dell'attivitĆ  non ĆØ riuscito. VerrĆ  usato il modello predefinito. Per i dettagli, vedere l'output dell'attivitĆ .", - "ConfigureTaskRunnerAction.autoDetectError": "Il rilevamento automatico del sistema dell'attivitĆ  ha restituito errori. Per i dettagli, vedere l'output dell'attivitĆ .", - "ConfigureTaskRunnerAction.failed": "Non ĆØ possibile creare il file 'tasks.json' all'interno della cartella '.vscode'. Per dettagli, vedere l'output dell'attivitĆ .", - "ConfigureTaskRunnerAction.label": "Configura esecuzione attivitĆ ", + "ConfigureTaskRunnerAction.label": "Configura attivitĆ ", "ConfigureBuildTaskAction.label": "Configura attivitĆ  di compilazione", "CloseMessageAction.label": "Chiudi", "ShowTerminalAction.label": "Visualizza terminale", "problems": "Problemi", "manyMarkers": "Più di 99", + "runningTasks": "Visualizza attivitĆ  in esecuzione", "tasks": "AttivitĆ ", - "TaskSystem.noHotSwap": "Per modificare il motore di esecuzione delle attivitĆ , ĆØ necessario riavviare VS Code. La modifica verrĆ  ignorata.", + "TaskSystem.noHotSwap": "Se si cambia il motore di esecuzione delle attivitĆ  con un'attivitĆ  attiva in esecuzione, ĆØ necessario ricaricare la finestra", + "TaskServer.folderIgnored": "La cartella {0} viene ignorata poichĆ© utilizza attivitĆ  (task) versione 0.1.0", "TaskService.noBuildTask1": "Non ĆØ stata definita alcuna attivitĆ  di compilazione. Contrassegnare un'attivitĆ  con 'isBuildCommand' nel file tasks.json.", "TaskService.noBuildTask2": "Non ĆØ stata definita alcuna attivitĆ  di compilazione. Contrassegnare un'attivitĆ  come gruppo 'build' nel file tasks.json.", "TaskService.noTestTask1": "Non ĆØ stata definita alcuna attivitĆ  di test. Contrassegnare un'attivitĆ  con 'isTestCommand' nel file tasks.json.", "TaskService.noTestTask2": "Non ĆØ stata definita alcuna attivitĆ  di test. Contrassegnare un'attivitĆ  come gruppo 'test' nel file tasks.json.", "TaskServer.noTask": "AttivitĆ  {0} richiesta per l'esecuzione non trovata", + "TaskService.associate": "associare", + "TaskService.attachProblemMatcher.continueWithout": "Continua senza analizzare l'output dell'attivitĆ ", + "TaskService.attachProblemMatcher.never": "Mai analizzare l'output dell'attivitĆ ", + "TaskService.attachProblemMatcher.learnMoreAbout": "Ulteriori informazioni sull'analisi dell'output della attivitĆ ", + "selectProblemMatcher": "Selezionare il tipo di errori e di avvisi per cui analizzare l'output dell'attivitĆ ", "customizeParseErrors": "La configurazione dell'attivitĆ  corrente presenta errori. Per favore correggere gli errori prima di personalizzazione un'attivitĆ .", "moreThanOneBuildTask": "tasks.json contiene molte attivitĆ  di compilazione. ƈ in corso l'esecuzione della prima.\n", + "TaskSystem.activeSame.background": "L'attivitĆ  '{0}' ĆØ giĆ  attiva ed in modalitĆ  background. Per terminarla, usare `Termina attivitĆ ` dal menu AttivitĆ ", + "TaskSystem.activeSame.noBackground": "L'attivitĆ  '{0}' ĆØ giĆ  attiva. Per terminarla utilizzare 'Termina attivitĆ ...' dal menu AttivitĆ .", "TaskSystem.active": "Al momento c'ĆØ giĆ  un'attivitĆ  in esecuzione. Terminarla prima di eseguirne un'altra.", "TaskSystem.restartFailed": "Non ĆØ stato possibile terminare e riavviare l'attivitĆ  {0}", "TaskSystem.configurationErrors": "Errore: la configurazione delle attivitĆ  specificata contiene errori di convalida e non ĆØ utilizzabile. Correggere prima gli errori.", + "taskService.ignoreingFolder": "Le configurazioni delle attivitĆ  per la cartella dell'area di lavoro {0} verranno ignorate. Per il supporto delle attivitĆ  delle aree di lavoro in più cartelle ĆØ necessario che tutte le cartelle usino la versione 2.0.0 delle attivitĆ \n", "TaskSystem.invalidTaskJson": "Errore: nel contenuto del file tasks.json sono presenti errori di sintassi. Correggerli prima di eseguire un'attivitĆ .\n", "TaskSystem.runningTask": "ƈ presente un'attivitĆ  in esecuzione. Terminarla?", "TaskSystem.terminateTask": "&&Termina attivitĆ ", @@ -40,25 +44,37 @@ "recentlyUsed": "attivitĆ  usate di recente", "configured": "attivitĆ  configurate", "detected": "attivitĆ  rilevate", + "TaskService.ignoredFolder": "Le cartelle dell'area di lavoro seguenti verranno ignorate perchĆ© usano la versione 0.1.0 delle attivitĆ : ", + "TaskService.notAgain": "Non visualizzare più questo messaggio", + "TaskService.ok": "OK", + "TaskService.pickRunTask": "Selezionare l'attivitĆ  da eseguire", + "TaslService.noEntryToRun": "Non ĆØ stata trovata alcuna attivitĆ  da eseguire. Configurare le attivitĆ ...", "TaskService.fetchingBuildTasks": "Recupero delle attivitĆ  di compilazione...", - "TaskService.noBuildTaskTerminal": "Non ĆØ stata trovata alcuna attivitĆ  di compilazione. Fare clic su 'Configura attivitĆ  di compilazione' per definirne una.", "TaskService.pickBuildTask": "Selezionare l'attivitĆ  di compilazione da eseguire", + "TaskService.noBuildTask": "Non ĆØ stata trovata alcuna attivitĆ  di compilazione da eseguire. Configurare le attivitĆ ...", "TaskService.fetchingTestTasks": "Recupero delle attivitĆ  di test...", - "TaskService.noTestTaskTerminal": "Non ĆØ stata trovata alcuna attivitĆ  di test. Fare clic su 'Configura Test Runner' per definirne una.", "TaskService.pickTestTask": "Selezionare l'attivitĆ  di test da eseguire", - "TaskService.noTaskRunning": "Non ci sono attivitĆ  attualmente in esecuzione.", + "TaskService.noTestTaskTerminal": "Non ĆØ stata trovata alcuna attivitĆ  di test da eseguire. Configurare le attivitĆ ...", "TaskService.tastToTerminate": "Selezionare l'attivitĆ  da terminare", + "TaskService.noTaskRunning": "Non ci sono attivitĆ  attualmente in esecuzione", "TerminateAction.noProcess": "Il processo avviato non esiste più. Se l'attivitĆ  implica la generazione di attivitĆ  in background, uscendo da Visual Studio Code potrebbero essere presenti processi orfani.", "TerminateAction.failed": "Non ĆØ stato possibile terminare l'attivitĆ  in esecuzione", - "TaskService.noTaskToRestart": "Non ci sono attivitĆ  da riavviare.", "TaskService.tastToRestart": "Selezionare l'attivitĆ  da riavviare", - "TaskService.defaultBuildTaskExists": "{0} ĆØ giĆ  contrassegnato come attivitĆ  di compilazione predefinita.", + "TaskService.noTaskToRestart": "Non ci sono attivitĆ  da riavviare", + "TaskService.template": "Selezionare un modello di attivitĆ ", + "TaskService.createJsonFile": "Crea il file tasks.json dal modello", + "TaskService.openJsonFile": "Apri il file tasks.json", + "TaskService.pickTask": "Selezionare un'attivitĆ  da configurare", + "TaskService.defaultBuildTaskExists": "{0} ĆØ giĆ  contrassegnato come attivitĆ  di compilazione predefinita", "TaskService.pickDefaultBuildTask": "Selezionare l'attivitĆ  da usare come attivitĆ  di compilazione predefinita", "TaskService.defaultTestTaskExists": "{0} ĆØ giĆ  contrassegnato come attivitĆ  di test predefinita.", "TaskService.pickDefaultTestTask": "Selezionare l'attivitĆ  da usare come attivitĆ  di test predefinita", + "TaskService.pickShowTask": "Selezionare l'attivitĆ  di cui mostrare l'output", + "TaskService.noTaskIsRunning": "Non ci sono attivitĆ  in esecuzione", "ShowLogAction.label": "Mostra log attivitĆ ", "RunTaskAction.label": "Esegui attivitĆ ", "RestartTaskAction.label": "Riavvia attivitĆ  in esecuzione", + "ShowTasksAction.label": "Mostra attivitĆ  in esecuzione", "BuildAction.label": "Esegui attivitĆ  di compilazione", "TestAction.label": "Esegui attivitĆ  di test", "ConfigureDefaultBuildTask.label": "Configura attivitĆ  di compilazione predefinita", diff --git a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 3d9e3d5f42b..acc06bc45a5 100644 --- a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Si ĆØ verificato un errore sconosciuto durante l'esecuzione di un'attivitĆ . Per dettagli, vedere il log di output dell'attivitĆ .", + "dependencyFailed": "Non ĆØ stato possibile risolvere l'attivitĆ  dipendente '{0}' nella cartella dell'area di lavoro '{1}'", "TerminalTaskSystem.terminalName": "AttivitĆ  - {0}", "reuseTerminal": "Terminale verrĆ  riutilizzato dalle attivitĆ , premere un tasto qualsiasi per chiuderlo.", "TerminalTaskSystem": "Non ĆØ possibile eseguire un comando della shell su un'unitĆ  UNC.", diff --git a/i18n/ita/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/ita/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index a966fb16e92..5adc56a7ea0 100644 --- a/i18n/ita/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,9 +11,12 @@ "ConfigurationParser.unknownMatcherKind": "Avviso: il matcher problemi definito ĆØ sconosciuto. I tipi supportati sono string | ProblemMatcher | (string | ProblemMatcher)[].\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "Errore: il riferimento a problemMatcher non ĆØ valido: {0}\n", "ConfigurationParser.noTaskType": "Errore: la configurazione di tasks deve contenere una proprietĆ  di tipo. La configurazione verrĆ  ignorata.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "Errore: non ci sono attivitĆ  registrate di tipo '{0}'. Non ĆØ stata installata un'estensione che fornisce un provider di task corrispondente?", + "ConfigurationParser.missingRequiredProperty": "Errore: nella configurazione di attivitĆ  '{0}' manca la proprietĆ  obbligatoria '{1}'. La configurazione dell'attivitĆ  verrĆ  ignorata.", "ConfigurationParser.notCustom": "Errore: tasks non ĆØ dichiarato come un'attivitĆ  personalizzata. La configurazione verrĆ  ignorata.\n{0}\n", "ConfigurationParser.noTaskName": "Errore: le attivitĆ  devono specificare una proprietĆ  taskName. L'attivitĆ  verrĆ  ignorata.\n{0}\n", "taskConfiguration.shellArgs": "Avviso: l'attivitĆ  '{0}' ĆØ un comando della shell e il nome del comando o uno dei relativi argomenti contiene spazi senza codice di escape. Per garantire la corretta indicazione della riga di comando, unire gli argomenti nel comando.", "taskConfiguration.noCommandOrDependsOn": "Errore: l'attivitĆ  '{0}' non specifica un comando nĆ© una proprietĆ  dependsOn. L'attivitĆ  verrĆ  ignorata. La sua definizione ĆØ:\n{1}", - "taskConfiguration.noCommand": "Errore: l'attivitĆ  '{0}' non definisce un comando. L'attivitĆ  verrĆ  ignorata. Definizione dell'attivitĆ :\n{1}" + "taskConfiguration.noCommand": "Errore: l'attivitĆ  '{0}' non definisce un comando. L'attivitĆ  verrĆ  ignorata. Definizione dell'attivitĆ :\n{1}", + "TaskParse.noOsSpecificGlobalTasks": "L'attivitĆ  versione 2.0.0 non supporta attivitĆ  specifiche globali del sistema operativo. Convertirle in un'attivitĆ  con un comando specifico del sistema operativo. AttivitĆ  interessate:\n{0}" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 8b6ad71cd4e..606a321e648 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "termEntryAriaLabel": "{0}, selettore terminale", + "termCreateEntryAriaLabel": "{0}, crea un nuovo terminale", + "'workbench.action.terminal.newplus": "$(plus) Crea nuovo terminale integrato", + "noTerminalsMatching": "Nessun terminale corrispondente", + "noTerminalsFound": "Nessun terminale aperto" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 9b3321eecb5..fe866565bf0 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -4,18 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "quickOpen.terminal": "Mostra tutti i terminali aperti", + "terminal": "Terminale", "terminalIntegratedConfigurationTitle": "Terminale integrato", "terminal.integrated.shell.linux": "Percorso della shell usata dal terminale in Linux.", "terminal.integrated.shellArgs.linux": "Argomenti della riga di comando da usare nel terminale Linux.", "terminal.integrated.shell.osx": "Percorso della shell usata dal terminale in OS X.", "terminal.integrated.shellArgs.osx": "Argomenti della riga di comando da usare nel terminale OS X.", + "terminal.integrated.shell.windows": "Il percorso della shell che il terminale utilizza su Windows. Quando si utilizzano shell fornite con Windows (cmd, PowerShell o Bash su Ubuntu).", "terminal.integrated.shellArgs.windows": "Argomenti della riga di comando da usare nel terminale Windows.", "terminal.integrated.rightClickCopyPaste": "Se impostata, impedirĆ  la visualizzazione del menu di scelta rapida quando si fa clic con il pulsante destro del mouse all'interno del terminale, ma eseguirĆ  il comando Copia in presenza di una selezione e il comando Incolla in assenza di una selezione.", "terminal.integrated.fontFamily": "Controlla la famiglia di caratteri del terminale. L'impostazione predefinita ĆØ il valore di editor.fontFamily.", - "terminal.integrated.fontLigatures": "Controlla se i caratteri legatura sono abilitati nel terminale.", "terminal.integrated.fontSize": "Consente di controllare le dimensioni del carattere in pixel del terminale.", "terminal.integrated.lineHeight": "Controlla l'altezza della riga del terminale. Questo numero ĆØ moltiplicato dalle dimensioni del carattere del terminale per ottenere l'altezza di riga effettiva in pixel.", - "terminal.integrated.enableBold": "Indica se abilitare il testo in grassetto nella console del terminale. Richiede il supporto da parte della console", + "terminal.integrated.enableBold": "Per abilitare il grassetto del testo all'interno del terminale, ĆØ necessario il supporto della shell del terminale.", "terminal.integrated.cursorBlinking": "Controlla se il cursore del terminale ĆØ intermittente o meno.", "terminal.integrated.cursorStyle": "Controlla lo stile del cursore del terminale.", "terminal.integrated.scrollback": "Consente di controllare il numero massimo di righe che il terminale mantiene nel buffer.", @@ -23,7 +25,9 @@ "terminal.integrated.cwd": "Percorso di avvio esplicito in cui verrĆ  avviato il terminale. Viene usato come directory di lavoro corrente per il processo della shell. Può risultare particolarmente utile nelle impostazioni dell'area di lavoro se la directory radice non costituisce una directory di lavoro corrente comoda.", "terminal.integrated.confirmOnExit": "Indica se confermare all'uscita la presenza di sessioni di terminale attive.", "terminal.integrated.commandsToSkipShell": "Set di ID comando i cui tasti di scelta rapida non verranno inviati alla shell e verranno sempre gestiti da Code. In tal modo i tasti di scelta rapida normalmente utilizzati dalla shell avranno lo stesso effetto di quando il terminale non ha lo stato attivo, ad esempio CTRL+P per avviare Quick Open.", - "terminal": "Terminale", + "terminal.integrated.env.osx": "Oggetto con variabili di ambiente che verrĆ  aggiunto al processo VS Code per essere utilizzato dal terminale su OS X", + "terminal.integrated.env.linux": "Oggetto con variabili di ambiente che verrĆ  aggiunto al processo VS Code per essere utilizzato dal terminale su Linux", + "terminal.integrated.env.windows": "Oggetto con variabili di ambiente che verrĆ  aggiunto al processo VS Code per essere utilizzato dal terminale su Windows", "terminalCategory": "Terminale", "viewCategory": "Visualizza" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index a676775b5fc..9941d145008 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "Attiva/Disattiva terminale integrato", "workbench.action.terminal.kill": "Termina istanza attiva del terminale", "workbench.action.terminal.kill.short": "Termina il terminale", + "workbench.action.terminal.quickKill": "Termina istanza del terminale", "workbench.action.terminal.copySelection": "Copia selezione", "workbench.action.terminal.selectAll": "Seleziona tutto", + "workbench.action.terminal.deleteWordLeft": "Elimina parola a sinistra", + "workbench.action.terminal.deleteWordRight": "Elimina la parola a destra", "workbench.action.terminal.new": "Crea nuovo terminale integrato", "workbench.action.terminal.new.short": "Nuovo terminale", "workbench.action.terminal.focus": "Sposta stato attivo su terminale", "workbench.action.terminal.focusNext": "Sposta stato attivo su terminale successivo", - "workbench.action.terminal.focusAtIndex": "Sposta stato attivo su terminale {0}", "workbench.action.terminal.focusPrevious": "Sposta stato attivo su terminale precedente", "workbench.action.terminal.paste": "Incolla nel terminale attivo", "workbench.action.terminal.DefaultShell": "Selezionare la Shell di Default", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "Rinomina", "workbench.action.terminal.rename.prompt": "Immettere il nome del terminale", "workbench.action.terminal.focusFindWidget": "Stato attivo su widget Trova", - "workbench.action.terminal.hideFindWidget": "Nascondi widget Trova" + "workbench.action.terminal.hideFindWidget": "Nascondi widget Trova", + "nextTerminalFindTerm": "Mostra il termine di ricerca successivo", + "previousTerminalFindTerm": "Mostra il termine di ricerca precedente", + "quickOpenTerm": "Cambia terminale attivo" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 43f3afaeb30..6d85a595027 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -6,5 +6,8 @@ { "terminal.background": "Il colore di sfondo del terminale, questo consente di colorare il terminale in modo diverso dal pannello.", "terminal.foreground": "Il colore di primo piano del terminale.", + "terminalCursor.foreground": "Colore di primo piano del cursore del terminale.", + "terminalCursor.background": "Colore di sfondo del cursore del terminale. Permette di personalizzare il colore di un carattere quando sovrapposto da un blocco cursore.", + "terminal.selectionBackground": "Colore di sfondo di selezione del terminale.", "terminal.ansiColor": "Colore ANSI '{0}' nel terminale." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index e32834163e9..adc0b4440da 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copia", - "createNewTerminal": "Nuovo terminale", "paste": "Incolla", "selectAll": "Seleziona tutto", "clear": "Cancella" diff --git a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index e21d2d1aaf0..6055f7da096 100644 --- a/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OK, non visualizzare più", "terminal.integrated.chooseWindowsShell": "Seleziona la shell di terminale preferita - ĆØ possibile modificare questa impostazione dopo", "terminalService.terminalCloseConfirmationSingular": "C'ĆØ una sessione di terminale attiva. Terminarla?", - "terminalService.terminalCloseConfirmationPlural": "Ci sono {0} sessioni di terminale attive. Terminarle?", - "yes": "SƬ" + "terminalService.terminalCloseConfirmationPlural": "Ci sono {0} sessioni di terminale attive. Terminarle?" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 9dd33f62814..46c966a637e 100644 --- a/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,9 @@ "licenseChanged": "I termini della licenza sono cambiati. Leggerli con attenzione.", "license": "Leggi licenza", "neveragain": "Non visualizzare più questo messaggio", + "64bitisavailable": "{0} per Windows a 64 bit ĆØ ora disponibile.", "learn more": "Altre informazioni", + "updateIsReady": "Nuovo aggiornamento di {0} disponibile.", "thereIsUpdateAvailable": "ƈ disponibile un aggiornamento.", "updateAvailable": "{0} verrĆ  aggiornato dopo il riavvio.", "noUpdatesAvailable": "Al momento non sono disponibili aggiornamenti.", diff --git a/i18n/ita/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/ita/src/vs/workbench/parts/views/browser/views.i18n.json index a7b1c661726..860e3f239f2 100644 --- a/i18n/ita/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/views/browser/views.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "viewToolbarAriaLabel": "Azioni di {0}" + "viewToolbarAriaLabel": "Azioni di {0}", + "hideView": "Nascondi da barra laterale" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json b/i18n/ita/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json index 98cf912e7cc..79ac78f96ad 100644 --- a/i18n/ita/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json @@ -12,5 +12,6 @@ "vscode.extension.contributes.view.when": "Condizione che deve essere vera per mostrare questa visualizzazione", "vscode.extension.contributes.views": "Contribuisce visualizzazioni all'editor", "views.explorer": "Visualizzazione di esplorazione", + "views.debug": "Visualizzazione Debug", "locationId.invalid": "'{0}' non ĆØ una posizione valida per la visualizzazione" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 4d0a4f3dde5..3e37440e803 100644 --- a/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "Avvia", "welcomePage.newFile": "Nuovo file", "welcomePage.openFolder": "Apri cartella...", - "welcomePage.cloneGitRepository": "Clona repository GIT...", + "welcomePage.addWorkspaceFolder": "Aggiungi cartella dell'area di lavoro...", "welcomePage.recent": "Recenti", "welcomePage.moreRecent": "Altro...", "welcomePage.noRecentFolders": "Non ci sono cartelle recenti", diff --git a/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json index 300eb2118f1..1f9832cab99 100644 --- a/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json @@ -8,5 +8,6 @@ "workbench.startupEditor.none": "Avvia senza un editor.", "workbench.startupEditor.welcomePage": "Apre la pagina di benvenuto (impostazione predefinita).", "workbench.startupEditor.newUntitledFile": "Apre un nuovo file senza nome.", + "workbench.startupEditor": "Controlla quale editor viene visualizzato all'avvio, se non ne ĆØ stato ripristinato nessuno dalla versione precedente. Selezionare 'none' per avviare senza un editor, 'welcomePage' per aprire la pagina di benvenuto (impostazione predefinita), 'newUntitledFile' per aprire un nuovo file senza nome (solo quando si apre uno spazio di lavoro vuoto).", "help": "Guida" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index b6dde7dcf2c..81a32bb4779 100644 --- a/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Mostra estensioni di Azure", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/ita/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/ita/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 2b28fa7289b..723449aaedf 100644 --- a/i18n/ita/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "Playground interattivo", - "editorWalkThrough.title": "Playground interattivo" + "editorWalkThrough.title": "Playground interattivo", + "editorWalkThrough": "Playground interattivo" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/ita/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..39e782467df --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Riepilogo delle impostazioni. Questa etichetta verrĆ  usata nel file di impostazioni come commento di separazione.", + "vscode.extension.contributes.configuration.properties": "Descrizione delle proprietĆ  di configurazione.", + "scope.window.description": "Configurazione specifica della finestra, che può essere configurata nelle impostazioni dell'utente o dell'area di lavoro.", + "scope.resource.description": "Configurazione specifica di risorse, che possono essere configurate nelle impostazioni utente, in quelle dell'area di lavoro o di una cartella.", + "scope.description": "Ambito in cui la configurazione ĆØ applicabile. Gli ambiti disponibili sono 'finestra' e 'risorsa'.", + "vscode.extension.contributes.configuration": "Impostazioni di configurazione di contributes.", + "invalid.title": "'configuration.title' deve essere una stringa", + "vscode.extension.contributes.defaultConfiguration": "Aggiunge come contributo le impostazioni di configurazione predefinite dell'editor in base al linguaggio.", + "invalid.properties": "'configuration.properties' deve essere un oggetto", + "invalid.allOf": "'configuration.allOf' ĆØ deprecato e non deve più essere usato. Passare invece una matrice di sezioni di configurazione al punto di aggiunta contributo 'configuration'.", + "workspaceConfig.folders.description": "Elenco di cartelle da caricare nell'area di lavoro.", + "workspaceConfig.path.description": "Percorso di file, ad esempio `/root/folderA` o `./folderA` per un percorso relativo che verrĆ  risolto in base alla posizione del file dell'area di lavoro.", + "workspaceConfig.name.description": "Nome facoltativo per la cartella. ", + "workspaceConfig.uri.description": "URI della cartella", + "workspaceConfig.settings.description": "Impostazioni area di lavoro", + "workspaceConfig.extensions.description": "Estensioni dell'area di lavoro", + "unknownWorkspaceProperty": "La proprietĆ  di configurazione dell'area di lavoro ĆØ sconosciuta" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json index a7e15b8a414..b5a489af390 100644 --- a/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,11 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "Impostazioni di configurazione di contributes.", "vscode.extension.contributes.configuration.title": "Riepilogo delle impostazioni. Questa etichetta verrĆ  usata nel file di impostazioni come commento di separazione.", "vscode.extension.contributes.configuration.properties": "Descrizione delle proprietĆ  di configurazione.", - "invalid.type": "se impostato, 'configuration.type' deve essere impostato su 'object", + "scope.window.description": "Configurazione specifica della finestra, che può essere configurata nelle impostazioni dell'utente o dell'area di lavoro.", + "scope.resource.description": "Configurazione specifica di risorse, che possono essere configurate nelle impostazioni utente, in quelle dell'area di lavoro o di una cartella.", + "scope.description": "Ambito in cui la configurazione ĆØ applicabile. Gli ambiti disponibili sono 'finestra' e 'risorsa'.", + "vscode.extension.contributes.configuration": "Impostazioni di configurazione di contributes.", "invalid.title": "'configuration.title' deve essere una stringa", "vscode.extension.contributes.defaultConfiguration": "Aggiunge come contributo le impostazioni di configurazione predefinite dell'editor in base al linguaggio.", - "invalid.properties": "'configuration.properties' deve essere un oggetto" + "invalid.properties": "'configuration.properties' deve essere un oggetto", + "invalid.allOf": "'configuration.allOf' ĆØ deprecato e non deve più essere usato. Passare invece una matrice di sezioni di configurazione al punto di aggiunta contributo 'configuration'.", + "workspaceConfig.folders.description": "Elenco di cartelle da caricare nell'area di lavoro.", + "workspaceConfig.path.description": "Percorso di file, ad esempio `/root/folderA` o `./folderA` per un percorso relativo che verrĆ  risolto in base alla posizione del file dell'area di lavoro.", + "workspaceConfig.name.description": "Nome facoltativo per la cartella. ", + "workspaceConfig.uri.description": "URI della cartella", + "workspaceConfig.settings.description": "Impostazioni di area di lavoro", + "workspaceConfig.extensions.description": "Estensioni dell'area di lavoro", + "unknownWorkspaceProperty": "La proprietĆ  di configurazione dell'area di lavoro ĆØ sconosciuta" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/ita/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index 72151489b4a..965f92ae5a1 100644 --- a/i18n/ita/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/ita/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Apri impostazioni", + "openTasksConfiguration": "Apri configurazione attivitĆ ", + "openLaunchConfiguration": "Apri configurazione di avvio", "close": "Chiudi", - "saveAndRetry": "Salva le impostazioni e riprova", - "errorInvalidConfiguration": "Impossibile scrivere nelle impostazioni. Si prega di aprire **Impostazioni utente** per correggere eventuali errori o avvisi nel file e riprovare.", - "errorInvalidConfigurationWorkspace": "Impossibile scrivere in impostazioni. Si prega di aprire **Impostazioni area di lavoro** per correggere eventuali errori o avvisi nel file e riprovare.", - "errorConfigurationFileDirty": "Impossibile scrivere nelle impostazioni perchĆ© il file ĆØ stato modificato ma non salvato. Si prega di salvare il file **impostazioni utente** e riprovare.", - "errorConfigurationFileDirtyWorkspace": "Non ĆØ possibile scrivere in impostazioni perchĆ© il file ĆØ stato modificato ma non salvato. Salvare il file delle **Impostazioni area di lavoro** e riprovare.", + "open": "Apri impostazioni", + "saveAndRetry": "Salva e riprova", + "errorUnknownKey": "Impossibile scrivere {0} perchĆ© {1} non ĆØ una configurazione registrata.", + "errorInvalidFolderConfiguration": "Impossibile scrivere nella cartella impostazioni perchĆ© {0} non supporta l'ambito di risorsa della cartella.", + "errorInvalidUserTarget": "Impossibile scrivere le impostazioni utente perchĆ© {0} non supporta l'ambito globale.", + "errorInvalidFolderTarget": "Impossibile scrivere nella cartella impostazioni perchĆ© non viene fornita alcuna risorsa.", + "errorNoWorkspaceOpened": "Impossibile scrivere su {0} poichĆ© nessuna area di lavoro ĆØ aperta. Si prega di aprire un'area di lavoro e riprovare.", + "errorInvalidTaskConfiguration": "Non ĆØ possibile scrivere nel file delle attivitĆ . Aprire il file **AttivitĆ ** per correggere eventuali errori/avvisi, quindi riprovare.", + "errorInvalidLaunchConfiguration": "Non ĆØ possibile scrivere nel file di avvio. Aprire il file **Avvio** per correggere eventuali errori/avvisi, quindi riprovare.", + "errorInvalidConfiguration": "Non ĆØ possibile scrivere nelle impostazioni utente. Aprire il file **Impostazioni utente** per correggere eventuali errori/avvisi presenti, quindi riprovare.", + "errorInvalidConfigurationWorkspace": "Non ĆØ possibile scrivere nelle impostazioni dell'area di lavoro. Aprire il file **Impostazioni area di lavoro** per correggere eventuali errori/avvisi presenti, quindi riprovare.", + "errorInvalidConfigurationFolder": "Non ĆØ possibile scrivere nelle impostazioni della cartella. Aprire il file **Impostazioni cartella** nella cartella **{0}** per correggere eventuali errori/avvisi presenti, quindi riprovare.", + "errorTasksConfigurationFileDirty": "Non ĆØ possibile scrivere nel file delle attivitĆ  perchĆ© ĆØ stato modificato. Salvare il file **Configurazione attivitĆ ** , quindi riprovare.", + "errorLaunchConfigurationFileDirty": "Non ĆØ possibile scrivere nel file di avvio perchĆ© ĆØ stato modificato. Salvare il file **Configurazione di avvio** , quindi riprovare.", + "errorConfigurationFileDirty": "Non ĆØ possibile scrivere nelle impostazioni utente perchĆ© il file ĆØ stato modificato. Salvare il file **Impostazioni utente** , quindi riprovare.", + "errorConfigurationFileDirtyWorkspace": "Non ĆØ possibile scrivere nelle impostazioni dell'area di lavoro perchĆ© il file ĆØ stato modificato. Salvare il file **Impostazioni area di lavoro** , quindi riprovare.", + "errorConfigurationFileDirtyFolder": "Non ĆØ possibile scrivere nelle impostazioni della cartella perchĆ© il file ĆØ stato modificato. Salvare il file **Impostazioni cartella** nella cartella **{0}**, quindi riprovare.", "userTarget": "Impostazioni utente", - "workspaceTarget": "Impostazioni area di lavoro" + "workspaceTarget": "Impostazioni area di lavoro", + "folderTarget": "Impostazioni della cartella" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json b/i18n/ita/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json index 8b6ad71cd4e..337b884305c 100644 --- a/i18n/ita/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json +++ b/i18n/ita/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "errorInvalidFile": "Impossibile scrivere nel file. Si prega di aprire il file per correggere eventuali errori o avvisi nel file e riprovare.", + "errorFileDirty": "Impossibile scrivere nel file perchĆ© il file ĆØ stato modificato. Si prega di salvare il file e riprovare." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/ita/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/ita/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..e77d27848ab --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "L'host dell'estensione non ĆØ stato avviato entro 10 secondi. Potrebbe essersi arrestato alla prima riga e richiedere un debugger per continuare.", + "extensionHostProcess.startupFail": "L'host dell'estensione non ĆØ stato avviato entro 10 secondi. Potrebbe essersi verificato un problema.", + "extensionHostProcess.error": "Errore restituito dall'host dell'estensione: {0}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..a8123821923 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "Non ĆØ stato possibile analizzare {0}: {1}.", + "fileReadFail": "Non ĆØ possibile leggere il file {0}: {1}.", + "jsonsParseFail": "Non ĆØ stato possibile analizzare {0} o {1}: {2}.", + "missingNLSKey": "Il messaggio per la chiave {0} non ĆØ stato trovato." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..037da6258e4 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "Strumenti di sviluppo", + "restart": "Riavvia host dell'estensione", + "extensionHostProcess.crash": "L'host dell'estensione ĆØ stato terminato in modo imprevisto.", + "extensionHostProcess.unresponsiveCrash": "L'host dell'estensione ĆØ stato terminato perchĆ© non rispondeva.", + "overwritingExtension": "Sovrascrittura dell'estensione {0} con {1}.", + "extensionUnderDevelopment": "Caricamento dell'estensione di sviluppo in {0}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/ita/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..6952c245dd7 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Il file sembra essere binario e non può essere aperto come file di testo" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/ita/src/vs/workbench/services/files/node/fileService.i18n.json index ea915074a17..158f28c3a3e 100644 --- a/i18n/ita/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/ita/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "Risorsa del file non valida ({0})", - "fileIsDirectoryError": "Il file ĆØ la directory ({0})", + "fileIsDirectoryError": "Il File ĆØ una Directory", "fileNotModifiedError": "File non modificato dal giorno", "fileTooLargeError": "File troppo grande per essere aperto", "fileBinaryError": "Il file sembra essere binario e non può essere aperto come file di testo", "fileNotFoundError": "Il file non ĆØ stato trovato ({0})", + "fileExists": "Il file da creare esiste giĆ  ({0})", "fileMoveConflict": "Non ĆØ possibile eseguire operazioni di spostamento/copia. Il file esiste giĆ  nella destinazione.", "unableToMoveCopyError": "Non ĆØ possibile eseguire operazioni di spostamento/copia. Il file sostituirebbe la cartella in cui ĆØ contenuto.", "foldersCopyError": "Non ĆØ possibile copiare le cartelle nell'area di lavoro. Selezionare i singoli file per copiarli.", diff --git a/i18n/ita/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/ita/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/ita/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/ita/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/ita/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 5c07d905441..3b13087ceea 100644 --- a/i18n/ita/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/ita/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "Stile del carattere della regola: uno o combinazione di 'italic', 'bold' e 'underline'", - "schema.colors": "Colori per l'evidenziazione della sintassi", - "schema.properties.name": "Descrizione della regola", - "schema.tokenColors.path": "Percorso di un file tmTheme (relativo al file corrente)" + "schema.token.settings": "Colori e stili per il token.", + "schema.token.foreground": "Colore primo piano per il token.", + "schema.token.fontStyle": "Stile del carattere della regola: uno o combinazione di 'italic', 'bold' e 'underline'", + "schema.fontStyle.error": "Lo stile del carattere deve essere una combinazione di 'italic', 'bold' e 'underline'", + "schema.properties.name": "Descrizione della regola.", + "schema.properties.scope": "Selettore di ambito usato per la corrispondenza della regola.", + "schema.tokenColors.path": "Percorso di un file tmTheme (relativo al file corrente).", + "schema.colors": "Colori per l'evidenziazione della sintassi" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 0aee1a7594d..ad9328eb682 100644 --- a/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "Problemi durante l'analisi del file di tema di JSON: {0}", "error.invalidformat.colors": "Si ĆØ verificato un problema durante l'analisi del file di tema {0}. La proprietĆ  'colors' non ĆØ di tipo 'object'.", - "error.invalidformat.tokenColors": "Si ĆØ verificato un problema durante l'analisi del file di tema {0}. La proprietĆ  'tokenColors' deve essere una matrice che specifica i colori o un percorso di un file di tema TextMate", + "error.invalidformat.tokenColors": "Si ĆØ verificato un problema durante l'analisi del file del tema colori {0}. La proprietĆ  'tokenColors' deve essere una matrice che specifica colori oppure un percorso di un file di tema TextMate", "error.plist.invalidformat": "Si ĆØ verificato un problema durante l'analisi del file tmTheme {0}. 'settings' non ĆØ una matrice.", "error.cannotparse": "Si sono verificati problemi durante l'analisi del file tmTheme {0}", "error.cannotload": "Si sono verificati problemi durante il caricamento del file tmTheme {0}: {1}" diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..34e0bc8f5e8 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "ID del tema dell'icona usato nelle impostazioni utente.", + "vscode.extension.contributes.themes.label": "Etichetta del tema colori visualizzata nell'interfaccia utente.", + "vscode.extension.contributes.themes.uiTheme": "Tema di base che definisce i colori nell'editor: 'vs' ĆØ il tema colori chiaro, mentre 'vs-dark' ĆØ il tema colori scuro e 'hc-black' ĆØ il tema a contrasto elevato scuro.", + "vscode.extension.contributes.themes.path": "Percorso del file tmTheme. ƈ relativo alla cartella delle estensioni e corrisponde in genere a './themes/themeFile.tmTheme'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "ƈ previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", + "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..53cc79371c9 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "ID del tema dell'icona usato nelle impostazioni utente.", + "vscode.extension.contributes.iconThemes.label": "Etichetta del tema dell'icona visualizzata nell'interfaccia utente.", + "vscode.extension.contributes.iconThemes.path": "Percorso del file di definizione del tema dell'icona. ƈ relativo alla cartella delle estensioni e corrisponde in genere a './icons/awesome-icon-theme.json'.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "ƈ previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", + "reqid": "ƈ previsto un valore stringa in `contributes.{0}.id`. Valore specificato: {1}", + "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile." +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 031d6c9544a..97d1cdc1754 100644 --- a/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/ita/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,29 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "ID del tema dell'icona usato nelle impostazioni utente.", - "vscode.extension.contributes.themes.label": "Etichetta del tema colori visualizzata nell'interfaccia utente.", - "vscode.extension.contributes.themes.uiTheme": "Tema di base che definisce i colori nell'editor: 'vs' ĆØ il tema colori chiaro, mentre 'vs-dark' ĆØ il tema colori scuro e 'hc-black' ĆØ il tema a contrasto elevato scuro.", - "vscode.extension.contributes.themes.path": "Percorso del file tmTheme. ƈ relativo alla cartella delle estensioni e corrisponde in genere a './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ID del tema dell'icona usato nelle impostazioni utente.", - "vscode.extension.contributes.iconThemes.label": "Etichetta del tema dell'icona visualizzata nell'interfaccia utente.", - "vscode.extension.contributes.iconThemes.path": "Percorso del file di definizione del tema dell'icona. ƈ relativo alla cartella delle estensioni e corrisponde in genere a './icons/awesome-icon-theme.json'.", "migration.completed": "Sono state aggiunte nuove impostazioni tema alle impostazioni utente. Backup disponibile in {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "ƈ previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", - "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile.", - "reqid": "ƈ previsto un valore stringa in `contributes.{0}.id`. Valore specificato: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Specifica il tema dell'icona usato nell'area di lavoro oppure 'null' se non viene visualizzato alcun icona di file.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "Sostituisce i colori del tema colori attualmente selezionato.", - "workbenchColors.deprecated": "L'impostazione non ĆØ più sperimentale ed ĆØ stata rinominata in 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "In alternativa, usare 'workbench.colorCustomizations'" + "editorColors": "Sostituisce i colori dell'editor e lo stile dei font nel tema colori attualmente selezionato.", + "editorColors.comments": "Imposta i colori e gli stili per i commenti", + "editorColors.strings": "Imposta i colori e gli stili per i valori letterali stringa.", + "editorColors.keywords": "Imposta i colori e gli stili per le parole chiave.", + "editorColors.numbers": "Imposta i colori e stili per i valori letterali numerici.", + "editorColors.types": "Imposta i colori e gli stili per i riferimenti e le dichiarazioni di tipo.", + "editorColors.functions": "Imposta i colori e gli stili per i riferimenti e le dichiarazioni di funzioni.", + "editorColors.variables": "Imposta i colori e gli stili per i riferimenti e le dichiarazioni di variabili.", + "editorColors.textMateRules": "Imposta i colori e gli stili usando le regole di creazione temi di TextMate (impostazione avanzata)." } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/ita/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..83c0f4d81a8 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "Impossibile scrivere nel file di configurazione dell'area di lavoro. Si prega di aprire il file per correggere eventuali errori/avvisi e riprovare.", + "errorWorkspaceConfigurationFileDirty": "Impossibile scrivere nel file di configurazione dell'area di lavoro, perchĆ© il file ĆØ sporco. Si prega di salvarlo e riprovare.", + "openWorkspaceConfigurationFile": "Apri file di configurazione dell'area di lavoro", + "close": "Chiudi", + "enterWorkspace.close": "Chiudi", + "enterWorkspace.dontShowAgain": "Non visualizzare più questo messaggio", + "enterWorkspace.moreInfo": "Altre informazioni", + "enterWorkspace.prompt": "Ulteriori informazioni su come lavorare con più cartelle in VS Code." +} \ No newline at end of file diff --git a/i18n/jpn/extensions/azure-account/out/azure-account.i18n.json b/i18n/jpn/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..30b2830386c --- /dev/null +++ b/i18n/jpn/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "ć‚³ćƒ”ćƒ¼ć—ć¦é–‹ć", + "azure-account.close": "閉恘悋", + "azure-account.login": "ćƒ­ć‚°ć‚¤ćƒ³", + "azure-account.loginFirst": "ęœ€åˆć«ćƒ­ć‚°ć‚¤ćƒ³ćŒåæ…č¦ć§ć™ć€‚", + "azure-account.userCodeFailed": "ćƒ¦ćƒ¼ć‚¶ćƒ¼ć‚³ćƒ¼ćƒ‰ć®å–å¾—ć«å¤±ę•—ć—ć¾ć—ćŸ", + "azure-account.tokenFailed": "ćƒ‡ćƒć‚¤ć‚¹ ć‚³ćƒ¼ćƒ‰ć‚’ęŒć¤ćƒˆćƒ¼ć‚Æćƒ³ć‚’å–å¾—", + "azure-account.tokenFromRefreshTokenFailed": "ćƒŖćƒ•ćƒ¬ćƒƒć‚·ćƒ„ ćƒˆćƒ¼ć‚Æćƒ³ć‚’å«ć‚€ćƒˆćƒ¼ć‚Æćƒ³ć®å–å¾—" +} \ No newline at end of file diff --git a/i18n/jpn/extensions/azure-account/out/extension.i18n.json b/i18n/jpn/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..e643d542223 --- /dev/null +++ b/i18n/jpn/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: ćƒ­ć‚°ć‚¤ćƒ³...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 7c9fffc491f..f8b65e69685 100644 --- a/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/jpn/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "例: myFile.txt", - "activeEditorMedium": "例: myFolder/myFile.txt", - "activeEditorLong": "例: /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "例: myFolder1, myFolder2, myFolder3", - "rootPath": "例: /Users/Development/myProject", - "folderName": "例: myFolder", - "folderPath": "例: /Users/Development/myFolder", + "activeEditorShort": "ćƒ•ć‚”ć‚¤ćƒ«å (例: myFile.txt)", + "activeEditorMedium": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć«ē›øåÆ¾ēš„ćŖćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹ (例: myFolder/myFile.txt)", + "activeEditorLong": "ćƒ•ć‚”ć‚¤ćƒ«ć®å®Œå…ØćŖćƒ‘ć‚¹ (例: /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®åå‰ (例: myFolder または myWorkspace)", + "rootPath": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćƒ•ć‚”ć‚¤ćƒ« ćƒ‘ć‚¹ (例: /Users/Development/myWorkspace)", + "folderName": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå«ć¾ć‚Œć¦ć„ć‚‹ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®åå‰ (例: myFolder)", + "folderPath": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå«ć¾ć‚Œć¦ć„ć‚‹ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ćƒ•ć‚”ć‚¤ćƒ« ćƒ‘ć‚¹ (例: /Users/Development/myFolder)", "appName": "例: VS Code", "dirty": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒćƒ€ćƒ¼ćƒ†ć‚£ć§ć‚ć‚‹å “åˆć®ćƒ€ćƒ¼ćƒ†ć‚£ ć‚¤ćƒ³ć‚øć‚±ćƒ¼ć‚æćƒ¼", "separator": "å€¤ć®ć‚ć‚‹å¤‰ę•°ć§å›²ć¾ć‚ŒćŸå “åˆć«ć®ćæč”Øē¤ŗć•ć‚Œć‚‹ę”ä»¶ä»˜ćåŒŗåˆ‡ć‚ŠčØ˜å· (' - ')", diff --git a/i18n/jpn/extensions/css/package.i18n.json b/i18n/jpn/extensions/css/package.i18n.json index 0d0d4cde3c9..5ff9ba2550a 100644 --- a/i18n/jpn/extensions/css/package.i18n.json +++ b/i18n/jpn/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "ę­£ć—ććŖć„ćƒ‘ćƒ©ćƒ”ćƒ¼ć‚æćƒ¼ć®ę•°", "css.lint.boxModel.desc": "ćƒ‘ćƒ‡ć‚£ćƒ³ć‚°ć¾ćŸćÆęž ē·šć‚’ä½æē”Øć™ć‚‹å “åˆćÆå¹…ć¾ćŸćÆé«˜ć•ć‚’ä½æē”Øć—ćŖć„ć§ćć ć•ć„", "css.lint.compatibleVendorPrefixes.desc": "ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ć‚’ä½æē”Øć™ć‚‹å “åˆćÆć€ä»–ć®ć™ć¹ć¦ć®ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚‚åæ…ćšå«ć‚ć¦ćć ć•ć„", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "äøę˜ŽćŖćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć€‚", "css.lint.vendorPrefix.desc": "ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ć‚’ä½æē”Øć™ć‚‹å “åˆćÆć€ęØ™ęŗ–ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚‚å«ć‚ć¾ć™", "css.lint.zeroUnits.desc": "0 ć®å˜ä½ćÆåæ…č¦ć‚ć‚Šć¾ć›ć‚“", + "css.trace.server.desc": "VS Code と CSS čØ€čŖžć‚µćƒ¼ćƒćƒ¼é–“ć®é€šäæ”ć‚’ćƒˆćƒ¬ćƒ¼ć‚¹ć—ć¾ć™ć€‚", + "css.validate.title": "CSS ć®ę¤œčØ¼ćØå•é”Œć®é‡å¤§åŗ¦ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "css.validate.desc": "ć™ć¹ć¦ć®ę¤œčØ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "ę­£ć—ććŖć„ćƒ‘ćƒ©ćƒ”ćƒ¼ć‚æćƒ¼ć®ę•°", "less.lint.boxModel.desc": "ćƒ‘ćƒ‡ć‚£ćƒ³ć‚°ć¾ćŸćÆęž ē·šć‚’ä½æē”Øć™ć‚‹å “åˆćÆå¹…ć¾ćŸćÆé«˜ć•ć‚’ä½æē”Øć—ćŖć„ć§ćć ć•ć„", "less.lint.compatibleVendorPrefixes.desc": "ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ć‚’ä½æē”Øć™ć‚‹å “åˆćÆć€ä»–ć®ć™ć¹ć¦ć®ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚‚åæ…ćšå«ć‚ć¦ćć ć•ć„", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "äøę˜ŽćŖćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć€‚", "less.lint.vendorPrefix.desc": "ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ć‚’ä½æē”Øć™ć‚‹å “åˆćÆć€ęØ™ęŗ–ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚‚å«ć‚ć¾ć™", "less.lint.zeroUnits.desc": "0 ć®å˜ä½ćÆåæ…č¦ć‚ć‚Šć¾ć›ć‚“", + "less.validate.title": "LESS ć®ę¤œčØ¼ćØå•é”Œć®é‡å¤§åŗ¦ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "less.validate.desc": "ć™ć¹ć¦ć®ę¤œčØ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "ę­£ć—ććŖć„ćƒ‘ćƒ©ćƒ”ćƒ¼ć‚æćƒ¼ć®ę•°", "scss.lint.boxModel.desc": "ćƒ‘ćƒ‡ć‚£ćƒ³ć‚°ć¾ćŸćÆęž ē·šć‚’ä½æē”Øć™ć‚‹å “åˆćÆå¹…ć¾ćŸćÆé«˜ć•ć‚’ä½æē”Øć—ćŖć„ć§ćć ć•ć„", "scss.lint.compatibleVendorPrefixes.desc": "ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ć‚’ä½æē”Øć™ć‚‹å “åˆćÆć€ä»–ć®ć™ć¹ć¦ć®ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚‚åæ…ćšå«ć‚ć¦ćć ć•ć„", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "äøę˜ŽćŖćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć€‚", "scss.lint.vendorPrefix.desc": "ćƒ™ćƒ³ćƒ€ćƒ¼å›ŗęœ‰ć®ćƒ—ćƒ¬ćƒ•ć‚£ćƒƒć‚Æć‚¹ć‚’ä½æē”Øć™ć‚‹å “åˆćÆć€ęØ™ęŗ–ć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚‚å«ć‚ć¾ć™", "scss.lint.zeroUnits.desc": "0 ć®å˜ä½ćÆåæ…č¦ć‚ć‚Šć¾ć›ć‚“", + "scss.validate.title": "SCSS ć®ę¤œčØ¼ćØå•é”Œć®é‡å¤§åŗ¦ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "scss.validate.desc": "ć™ć¹ć¦ć®ę¤œčØ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™", "less.colorDecorators.enable.desc": "ć‚«ćƒ©ćƒ¼ ćƒ‡ć‚³ćƒ¬ćƒ¼ć‚æćƒ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™", "scss.colorDecorators.enable.desc": "ć‚«ćƒ©ćƒ¼ ćƒ‡ć‚³ćƒ¬ćƒ¼ć‚æćƒ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™", - "css.colorDecorators.enable.desc": "ć‚«ćƒ©ćƒ¼ ćƒ‡ć‚³ćƒ¬ćƒ¼ć‚æćƒ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™" + "css.colorDecorators.enable.desc": "ć‚«ćƒ©ćƒ¼ ćƒ‡ć‚³ćƒ¬ćƒ¼ć‚æćƒ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™", + "css.colorDecorators.enable.deprecationMessage": "設定 `css.colorDecorators.enable` ćÆä½æē”Øć•ć‚ŒćŖććŖć‚Šć¾ć—ćŸć€‚`editor.colorDecorators` ć‚’ä½æē”Øć—ć¦ćć ć•ć„ć€‚", + "scss.colorDecorators.enable.deprecationMessage": "設定 `scss.colorDecorators.enable` ćÆä½æē”Øć•ć‚ŒćŖććŖć‚Šć¾ć—ćŸć€‚`editor.colorDecorators` ć‚’ä½æē”Øć—ć¦ćć ć•ć„ć€‚", + "less.colorDecorators.enable.deprecationMessage": "設定 `less.colorDecorators.enable` ćÆä½æē”Øć•ć‚ŒćŖććŖć‚Šć¾ć—ćŸć€‚`editor.colorDecorators` ć‚’ä½æē”Øć—ć¦ćć ć•ć„ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/extensions/emmet/package.i18n.json b/i18n/jpn/extensions/emmet/package.i18n.json index ce72c51b95b..e29ab462a72 100644 --- a/i18n/jpn/extensions/emmet/package.i18n.json +++ b/i18n/jpn/extensions/emmet/package.i18n.json @@ -4,15 +4,50 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "ćƒ©ćƒƒćƒ—å¤‰ę›", + "command.wrapIndividualLinesWithAbbreviation": "å€‹ć€…ć®č”Œć§ćƒ©ćƒƒćƒ—å¤‰ę›", + "command.removeTag": "ć‚æć‚°ć®å‰Šé™¤", + "command.updateTag": "タグの曓新", "command.matchTag": "äø€č‡“ć™ć‚‹ćƒšć‚¢ć«ē§»å‹•", + "command.balanceIn": "ćƒćƒ©ćƒ³ć‚¹ (内偓)", + "command.balanceOut": "ćƒćƒ©ćƒ³ć‚¹ (外偓)", "command.prevEditPoint": "å‰ć®ē·Øé›†ē‚¹ć«ē§»å‹•", "command.nextEditPoint": "欔の編集点に移動", + "command.mergeLines": "č”Œć®ćƒžćƒ¼ć‚ø", "command.selectPrevItem": "å‰ć®é …ē›®ć‚’éøęŠž", "command.selectNextItem": "ę¬”ć®é …ē›®ć‚’éøęŠž", + "command.splitJoinTag": "ć‚æć‚°ć®åˆ†å‰²/結合", + "command.toggleComment": "ć‚³ćƒ”ćƒ³ćƒˆć®åˆ‡ć‚Šę›æćˆ", + "command.evaluateMathExpression": "ę•°å¼ć®č©•ä¾”", + "command.updateImageSize": "ć‚¤ćƒ”ćƒ¼ć‚ø サイズの曓新", + "command.reflectCSSValue": "CSS å€¤ć‚’åę˜ ", "command.incrementNumberByOne": "1 ćšć¤å¢—åŠ ", "command.decrementNumberByOne": "1 ćšć¤ęø›å°‘", "command.incrementNumberByOneTenth": "0.1 ćšć¤å¢—åŠ ", "command.decrementNumberByOneTenth": "0.1 ćšć¤ęø›å°‘", "command.incrementNumberByTen": "10 ćšć¤å¢—åŠ ", - "command.decrementNumberByTen": "10 ćšć¤ęø›å°‘" + "command.decrementNumberByTen": "10 ćšć¤ęø›å°‘", + "emmetSyntaxProfiles": "ęŒ‡å®šć—ćŸę§‹ę–‡ć«åÆ¾ć—ć¦ćƒ—ćƒ­ćƒ•ć‚”ć‚¤ćƒ«ć‚’å®šē¾©ć™ć‚‹ć‹ć€ē‰¹å®šć®č¦å‰‡ćŒć‚ć‚‹ē‹¬č‡Ŗć®ćƒ—ćƒ­ćƒ•ć‚”ć‚¤ćƒ«ć‚’ć”ä½æē”Øćć ć•ć„ć€‚", + "emmetExclude": "Emmet ēœē•„čØ˜ę³•ć‚’å±•é–‹ć™ć¹ćć§ćŖć„čØ€čŖžć®é…åˆ—ć€‚", + "emmetExtensionsPath": "Emmet ć®ćƒ—ćƒ­ćƒ•ć‚”ć‚¤ćƒ«ćØć‚¹ćƒ‹ćƒšćƒƒćƒˆć‚’å«ć‚€ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćøć®ćƒ‘ć‚¹ć€‚", + "emmetShowExpandedAbbreviation": "å±•é–‹ć•ć‚ŒćŸ Emmet ēœē•„čØ˜ę³•ć‚’å€™č£œćØć—ć¦č”Øē¤ŗć—ć¾ć™ć€‚\n\"inMarkupAndStylesheetFilesOnly\" ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ćÆć€html态haml态jade态slim态xml态xsl态css态scss态sass态less态stylus ć«é©ē”Øć•ć‚Œć¾ć™ć€‚\n\"always\" ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ćÆ markup/css ć«é–¢äæ‚ćŖććƒ•ć‚”ć‚¤ćƒ«ć®ć™ć¹ć¦ć®éƒØåˆ†ć«é©ē”Øć•ć‚Œć¾ć™ć€‚", + "emmetShowAbbreviationSuggestions": "åˆ©ē”Øć§ćć‚‹ Emmet ēœē•„čØ˜ę³•ć‚’å€™č£œćØć—ć¦č”Øē¤ŗć—ć¾ć™ć€‚ć‚¹ć‚æć‚¤ćƒ«ć‚·ćƒ¼ćƒˆć‚„ emmet.showExpandedAbbreviation 悒 \"never\" ć«čØ­å®šć—ć¦ć„ć‚‹ćØé©ē”Øć•ć‚Œć¾ć›ć‚“ć€‚", + "emmetIncludeLanguages": "ę—¢å®šć§ć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ćŖć„čØ€čŖžć§ Emmet ēœē•„čØ˜ę³•ć‚’ęœ‰åŠ¹ć«ć—ć¾ć™ć€‚ čØ€čŖžćØ Emmet ćŒć‚µćƒćƒ¼ćƒˆć™ć‚‹čØ€čŖžć®é–“ć«ćƒžćƒƒćƒ”ćƒ³ć‚°ć‚’čæ½åŠ ć—ć¾ć™ć€‚\n例: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "Emmet ć®ć‚¹ćƒ‹ćƒšćƒƒćƒˆć§ä½æē”Øć•ć‚Œć‚‹å¤‰ę•°", + "emmetTriggerExpansionOnTab": "ęœ‰åŠ¹ć«ć™ć‚‹ćØć€TAB ć‚­ćƒ¼ć‚’ęŠ¼ć—ćŸćØćć« Eemmet ēœē•„čØ˜ę³•ćŒå±•é–‹ć•ć‚Œć¾ć™ć€‚", + "emmetPreferences": "Emmet ć®äø€éƒØć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³ć‚„ćƒŖć‚¾ćƒ«ćƒćƒ¼ć®å‹•ä½œć®å¤‰ę›“ć«ä½æē”Øć•ć‚Œć‚‹åŸŗęœ¬čØ­å®šć€‚", + "emmetPreferencesIntUnit": "ę•“ę•°å€¤ć«ä½æē”Øć™ć‚‹ę—¢å®šć®å˜ä½", + "emmetPreferencesFloatUnit": "float å€¤ć«ä½æē”Øć™ć‚‹ę—¢å®šć®å˜ä½", + "emmetPreferencesCssAfter": "CSS ć®ē•„čŖžć‚’å±•é–‹ć™ć‚‹ćØćć« CSS ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć®ęœ«å°¾ć«é…ē½®ć•ć‚Œć‚‹ć‚·ćƒ³ćƒœćƒ«", + "emmetPreferencesSassAfter": "Sass ćƒ•ć‚”ć‚¤ćƒ«ć§ CSS ē•„čŖžć‚’å±•é–‹ć™ć‚‹ćØćć« CSS ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć®ęœ«å°¾ć«é…ē½®ć•ć‚Œć‚‹ć‚·ćƒ³ćƒœćƒ«", + "emmetPreferencesStylusAfter": "StylusĀ ćƒ•ć‚”ć‚¤ćƒ«ć§ CSS ē•„čŖžć‚’å±•é–‹ć™ć‚‹ćØćć« CSS ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć®ęœ«å°¾ć«é…ē½®ć•ć‚Œć‚‹ć‚·ćƒ³ćƒœćƒ«", + "emmetPreferencesCssBetween": "CSS ć®ē•„čŖžć‚’å±•é–‹ć™ć‚‹ćØćć« CSS ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćØå€¤ć®é–“ć«é…ē½®ć•ć‚Œć‚‹ć‚·ćƒ³ćƒœćƒ« ", + "emmetPreferencesSassBetween": "Sass ćƒ•ć‚”ć‚¤ćƒ«ć§ CSS ć®ē•„čŖžć‚’å±•é–‹ć™ć‚‹ćØćć« CSS ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćØå€¤ć®é–“ć«é…ē½®ć•ć‚Œć‚‹ć‚·ćƒ³ćƒœćƒ« ", + "emmetPreferencesStylusBetween": "StylusĀ ćƒ•ć‚”ć‚¤ćƒ«ć§ CSS ć®ē•„čŖžć‚’å±•é–‹ć™ć‚‹ćØćć« CSS ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćØå€¤ć®é–“ć«é…ē½®ć•ć‚Œć‚‹ć‚·ćƒ³ćƒœćƒ« ", + "emmetShowSuggestionsAsSnippets": "true ć®å “åˆć€Emmet å€™č£œć‚’ć‚¹ćƒ‹ćƒšćƒƒćƒˆćØć—ć¦č”Øē¤ŗć—ć¦ editor.snippetSuggestions čØ­å®šć«å¾“ć£ć¦ćć‚Œć‚‰ć‚’äø¦ć³ę›æćˆć¾ć™ć€‚", + "emmetPreferencesBemElementSeparator": "BEM ćƒ•ć‚£ćƒ«ć‚æćƒ¼ć‚’åˆ©ē”Øę™‚ć«ć‚Æćƒ©ć‚¹ä½æē”Øć™ć‚‹ Element ć®åŒŗåˆ‡ć‚Šę–‡å­— ", + "emmetPreferencesBemModifierSeparator": "BEM ćƒ•ć‚£ćƒ«ć‚æćƒ¼ć‚’åˆ©ē”Øę™‚ć«ć‚Æćƒ©ć‚¹ä½æē”Øć™ć‚‹ Modifier ć®åŒŗåˆ‡ć‚Šę–‡å­—", + "emmetPreferencesFilterCommentBefore": "ć‚³ćƒ”ćƒ³ćƒˆ ćƒ•ć‚£ćƒ«ć‚æćƒ¼ä½æē”Øę™‚ć€äø€č‡“ć—ćŸč¦ē“ ć®å‰ć«é…ē½®ć™ć‚‹ć‚³ćƒ”ćƒ³ćƒˆć®å®šē¾©ć€‚ ", + "emmetPreferencesFilterCommentAfter": "ć‚³ćƒ”ćƒ³ćƒˆ ćƒ•ć‚£ćƒ«ć‚æćƒ¼ä½æē”Øę™‚ć€äø€č‡“ć—ćŸč¦ē“ ć®å¾Œć«é…ē½®ć™ć‚‹ć‚³ćƒ”ćƒ³ćƒˆć®å®šē¾©ć€‚", + "emmetPreferencesFilterCommentTrigger": "ć‚³ćƒ”ćƒ³ćƒˆ ćƒ•ć‚£ćƒ«ć‚æćƒ¼ć«é©ē”Øć•ć‚Œć‚‹ē•„čŖžć«å­˜åœØć™ć‚‹å±žę€§åć®ć‚«ćƒ³ćƒžåŒŗåˆ‡ć‚Šć®ćƒŖć‚¹ćƒˆ" } \ No newline at end of file diff --git a/i18n/jpn/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/jpn/extensions/extension-editing/out/extensionLinter.i18n.json index 41d43b02c1f..09e430952b7 100644 --- a/i18n/jpn/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/jpn/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "ē”»åƒć«ćÆ HTTPS ćƒ—ćƒ­ćƒˆć‚³ćƒ«ć‚’ä½æē”Øć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", "svgsNotValid": "SVG ćÆē„”åŠ¹ćŖē”»åƒć®ć‚½ćƒ¼ć‚¹ć§ć™ć€‚", "embeddedSvgsNotValid": "åŸ‹ć‚č¾¼ćæ SVG ćÆē„”åŠ¹ćŖē”»åƒć®ć‚½ćƒ¼ć‚¹ć§ć™ć€‚", - "dataUrlsNotValid": "Data URL ćÆē„”åŠ¹ćŖē”»åƒć®ć‚½ćƒ¼ć‚¹ć§ć™ć€‚" + "dataUrlsNotValid": "Data URL ćÆē„”åŠ¹ćŖē”»åƒć®ć‚½ćƒ¼ć‚¹ć§ć™ć€‚", + "relativeUrlRequiresHttpsRepository": "ē›øåÆ¾ēš„ćŖē”»åƒ URL では、HTTPS ćƒ—ćƒ­ćƒˆć‚³ćƒ«ć®ćƒŖćƒć‚øćƒˆćƒŖćŒ package.json ć§ęŒ‡å®šć•ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", + "relativeIconUrlRequiresHttpsRepository": "ć‚¢ć‚¤ć‚³ćƒ³ćÆć€HTTPS ćƒ—ćƒ­ćƒˆć‚³ćƒ«ć®ćƒŖćƒć‚øćƒˆćƒŖćŒć“ć® package.json ć§ęŒ‡å®šć•ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ ", + "relativeBadgeUrlRequiresHttpsRepository": "ē›øåÆ¾ēš„ćŖćƒćƒƒć‚ø URL では、HTTPS ćƒ—ćƒ­ćƒˆć‚³ćƒ«ć®ćƒŖćƒć‚øćƒˆćƒŖćŒ package.json ć§ęŒ‡å®šć•ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/extensions/git/out/commands.i18n.json b/i18n/jpn/extensions/git/out/commands.i18n.json index e0b20cd3072..e825de0716d 100644 --- a/i18n/jpn/extensions/git/out/commands.i18n.json +++ b/i18n/jpn/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "Git ćƒŖćƒć‚øćƒˆćƒŖć‚’č¤‡č£½ć—ć¦ć„ć¾ć™...", "openrepo": "ćƒŖćƒć‚øćƒˆćƒŖć‚’é–‹ć", "proposeopen": "č¤‡č£½ć—ćŸćƒŖćƒć‚øćƒˆćƒŖć‚’é–‹ćć¾ć™ć‹?", + "init repo": "ćƒŖćƒć‚øćƒˆćƒŖć®åˆęœŸåŒ–", + "create repo": "ćƒŖćƒć‚øćƒˆćƒŖć®åˆęœŸåŒ–", + "are you sure": "'{0}' 恫 Git ćƒŖćƒć‚øćƒˆćƒŖć‚’ä½œęˆć—ć¾ć™ć€‚ē¶šč”Œć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?", "HEAD not available": "'{0}' 恮 HEAD ćƒćƒ¼ć‚øćƒ§ćƒ³ćÆåˆ©ē”Øć§ćć¾ć›ć‚“ć€‚", + "confirm stage files with merge conflicts": "ćƒžćƒ¼ć‚øć®ē«¶åˆćŒć‚ć‚‹ {0} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’ć‚¹ćƒ†ćƒ¼ć‚øć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?", + "confirm stage file with merge conflicts": "ćƒžćƒ¼ć‚øć®ē«¶åˆćŒć‚ć‚‹ {0} ć‚’ć‚¹ćƒ†ćƒ¼ć‚øć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹? ", + "yes": "はい", "confirm revert": "{0} ć§éøęŠžć—ćŸå¤‰ę›“ć‚’å…ƒć«ęˆ»ć—ć¾ć™ć‹?", "revert": "å¤‰ę›“ć‚’å…ƒć«ęˆ»ć™", + "discard": "変曓を砓棄", + "confirm delete": "ęœ¬å½“ć« {0} ć‚’å‰Šé™¤ć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?", + "delete file": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’å‰Šé™¤", "confirm discard": "{0} の変曓を砓棄しますか?", "confirm discard multiple": "{0} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć®å¤‰ę›“å†…å®¹ć‚’ē “ę£„ć—ć¾ć™ć‹?", - "discard": "変曓を砓棄", - "confirm discard all": "すべての変曓を砓棄しますか? å¤‰ę›“ćÆęˆ»ć‚Šć¾ć›ć‚“!", - "discardAll": "すべての変曓を砓棄", + "warn untracked": "ęœŖčæ½č·”ćƒ•ć‚”ć‚¤ćƒ« {0} ćŒå‰Šé™¤ć•ć‚Œć¾ć™!", + "confirm discard all single": "{0} の変曓を砓棄しますか?", + "confirm discard all": "{0} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć®ć™ć¹ć¦ć®å¤‰ę›“ć‚’ē “ę£„ć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?\nć“ć®å¤‰ę›“ćÆå…ƒć«ęˆ»ć™ć“ćØćŒć§ćć¾ć›ć‚“!\nē¾åœØć®ćƒÆćƒ¼ć‚­ćƒ³ć‚° ć‚»ćƒƒćƒˆćÆę°øä¹…ć«å¤±ć‚ć‚Œć¾ć™ć€‚", + "discardAll multiple": "1 ć¤ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’ē “ę£„", + "discardAll": "{0} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’ć™ć¹ć¦ē “ę£„", + "confirm delete multiple": "ęœ¬å½“ć« {0} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’å‰Šé™¤ć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?", + "delete files": "č¤‡ę•°ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’å‰Šé™¤", + "there are untracked files single": "ē “ę£„ć™ć‚‹ćØę¬”ć®ęœŖčæ½č·”ćƒ•ć‚”ć‚¤ćƒ«ćŒćƒ‡ć‚£ć‚¹ć‚Æć‹ć‚‰å‰Šé™¤ć•ć‚Œć¾ć™: {0}怂", + "there are untracked files": "砓棄すると {0} å€‹ć®ęœŖčæ½č·”ćƒ•ć‚”ć‚¤ćƒ«ćŒćƒ‡ć‚£ć‚¹ć‚Æć‹ć‚‰å‰Šé™¤ć•ć‚Œć¾ć™ć€‚", + "confirm discard all 2": "{0}\n\nć“ć®å¤‰ę›“ćÆå…ƒć«ęˆ»ć™ć“ćØćÆć§ćć¾ć›ć‚“ć€‚ē¾åœØć®ćƒÆćƒ¼ć‚­ćƒ³ć‚° ć‚»ćƒƒćƒˆćÆę°øä¹…ć«å¤±ć‚ć‚Œć¾ć™ć€‚", + "yes discard tracked": "1 ć¤ć®čæ½č·”ćƒ•ć‚”ć‚¤ćƒ«ć‚’ē “ę£„", + "yes discard tracked multiple": "{0} å€‹ć®čæ½č·”ćƒ•ć‚”ć‚¤ćƒ«ć‚’ē “ę£„", "no staged changes": "ć‚³ćƒŸćƒƒćƒˆć™ć‚‹ć‚¹ćƒ†ćƒ¼ć‚øć•ć‚ŒćŸå¤‰ę›“ćŒć‚ć‚Šć¾ć›ć‚“ć€‚\n\nć™ć¹ć¦ć®å¤‰ę›“ć‚’č‡Ŗå‹•ēš„ć«ć‚¹ćƒ†ćƒ¼ć‚øć—ć¦ć€ē›“ęŽ„ć‚³ćƒŸćƒƒćƒˆć—ć¾ć™ć‹?", - "yes": "はい", "always": "åøøć«č”Œć†", "no changes": "ć‚³ćƒŸćƒƒćƒˆć™ć‚‹åæ…č¦ć®ć‚ć‚‹å¤‰ę›“ćÆć‚ć‚Šć¾ć›ć‚“ć€‚", "commit message": "ć‚³ćƒŸćƒƒćƒˆ ćƒ”ćƒƒć‚»ćƒ¼ć‚ø", @@ -34,16 +51,25 @@ "delete branch": "ćƒ–ćƒ©ćƒ³ćƒć®å‰Šé™¤", "select a branch to merge from": "ćƒžćƒ¼ć‚øå…ƒć®ćƒ–ćƒ©ćƒ³ćƒć‚’éøęŠž", "merge conflicts": "ćƒžćƒ¼ć‚øć®ē«¶åˆćŒć‚ć‚Šć¾ć™ć€‚ć‚³ćƒŸćƒƒćƒˆć™ć‚‹å‰ć«ć“ć‚Œć‚’č§£ę±ŗć—ć¦ćć ć•ć„ć€‚", + "tag name": "ć‚æć‚°å", + "provide tag name": "ć‚æć‚°åć‚’å…„åŠ›ć—ć¦ćć ć•ć„ć€‚", + "tag message": "ćƒ”ćƒƒć‚»ćƒ¼ć‚ø", + "provide tag message": "ę³Øé‡ˆä»˜ćć‚æć‚°ć«ć¤ć‘ć‚‹ćƒ”ćƒƒć‚»ćƒ¼ć‚øć‚’å…„åŠ›ć—ć¦ćć ć•ć„", "no remotes to pull": "ćƒŖćƒć‚øćƒˆćƒŖć«ćÆć€ćƒ—ćƒ«å…ƒćØć—ć¦ę§‹ęˆć•ć‚Œć¦ć„ć‚‹ćƒŖćƒ¢ćƒ¼ćƒˆćŒć‚ć‚Šć¾ć›ć‚“ć€‚", "pick remote pull repo": "ćƒŖćƒ¢ćƒ¼ćƒˆć‚’éøć‚“ć§ć€ćƒ–ćƒ©ćƒ³ćƒć‚’ę¬”ć‹ć‚‰ćƒ—ćƒ«ć—ć¾ć™:", "no remotes to push": "ćƒŖćƒć‚øćƒˆćƒŖć«ćÆć€ćƒ—ćƒƒć‚·ćƒ„å…ˆćØć—ć¦ę§‹ęˆć•ć‚Œć¦ć„ć‚‹ćƒŖćƒ¢ćƒ¼ćƒˆćŒć‚ć‚Šć¾ć›ć‚“ć€‚", + "push with tags success": "ć‚æć‚°ćŒę­£åøøć«ćƒ—ćƒƒć‚·ćƒ„ć•ć‚Œć¾ć—ćŸć€‚", "nobranch": "ćƒŖćƒ¢ćƒ¼ćƒˆć«ćƒ—ćƒƒć‚·ćƒ„ć™ć‚‹ćƒ–ćƒ©ćƒ³ćƒć‚’ćƒć‚§ćƒƒć‚Æć‚¢ć‚¦ćƒˆć—ć¦ćć ć•ć„ć€‚", "pick remote": "ćƒŖćƒ¢ćƒ¼ćƒˆć‚’éøć‚“ć§ć€ćƒ–ćƒ©ćƒ³ćƒ '{0}' を欔に公開します:", "sync is unpredictable": "ć“ć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³ćÆć‚³ćƒŸćƒƒćƒˆć‚’ '{0}' ćØć®é–“ć§ćƒ—ćƒƒć‚·ćƒ„ć—ćŸć‚Šćƒ—ćƒ«ć—ćŸć‚Šć—ć¾ć™ć€‚", "ok": "OK", "never again": "OKć€ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", "no remotes to publish": "ćƒŖćƒć‚øćƒˆćƒŖć«ćÆć€ē™ŗč”Œå…ˆćØć—ć¦ę§‹ęˆć•ć‚Œć¦ć„ć‚‹ćƒŖćƒ¢ćƒ¼ćƒˆćŒć‚ć‚Šć¾ć›ć‚“ć€‚", - "disabled": "ć“ć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć§ćÆć€Git ćŒē„”åŠ¹ć«ćŖć£ć¦ć„ć‚‹ć‹ć€ć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć¾ć›ć‚“", + "no changes stash": "ć‚¹ć‚æćƒƒć‚·ćƒ„ć™ć‚‹å¤‰ę›“ćŒć‚ć‚Šć¾ć›ć‚“ć€‚", + "provide stash message": "åæ…č¦ć«åæœć˜ć¦ć‚¹ć‚æćƒƒć‚·ćƒ„ ćƒ”ćƒƒć‚»ćƒ¼ć‚øć‚’å…„åŠ›ć—ć¦ćć ć•ć„", + "stash message": "ć‚¹ć‚æćƒƒć‚·ćƒ„ ćƒ”ćƒƒć‚»ćƒ¼ć‚ø", + "no stashes": "å¾©å…ƒć™ć‚‹ć‚¹ć‚æćƒƒć‚·ćƒ„ćŒć‚ć‚Šć¾ć›ć‚“ć€‚", + "pick stash to pop": "é©ē”Øć™ć‚‹ć‚¹ć‚æćƒƒć‚·ćƒ„ć‚’éøęŠžć—ć¦ćć ć•ć„", "clean repo": "ćƒć‚§ćƒƒć‚Æć‚¢ć‚¦ćƒˆć®å‰ć«ć€ćƒŖćƒć‚øćƒˆćƒŖć®ä½œę„­ćƒ„ćƒŖćƒ¼ć‚’ę¶ˆåŽ»ć—ć¦ćć ć•ć„ć€‚", "cant push": "å‚ē…§ä»•ę§˜ć‚’ćƒŖćƒ¢ćƒ¼ćƒˆć«ćƒ—ćƒƒć‚·ćƒ„ć§ćć¾ć›ć‚“ć€‚ęœ€åˆć« 'Pull' ć‚’å®Ÿč”Œć—ć¦å¤‰ę›“ć‚’ēµ±åˆć—ć¦ćć ć•ć„ć€‚", "git error details": "Git: {0}", diff --git a/i18n/jpn/extensions/git/out/model.i18n.json b/i18n/jpn/extensions/git/out/model.i18n.json index 87fddca5688..223a2121eec 100644 --- a/i18n/jpn/extensions/git/out/model.i18n.json +++ b/i18n/jpn/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "開恏", - "merge changes": "å¤‰ę›“ć®ćƒžćƒ¼ć‚ø", - "staged changes": "ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°ęøˆćæć®å¤‰ę›“", - "changes": "変曓", - "ok": "OK", - "neveragain": "ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", - "huge": "'{0}' 恮Git ćƒŖćƒć‚øćƒˆćƒŖć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖå¤‰ę›“ćŒå¤šć„ćŸć‚ć€ Git ę©Ÿčƒ½ć®äø€éƒØć®ćæćŒęœ‰åŠ¹ć«ćŖć‚Šć¾ć™ć€‚" + "no repositories": "åˆ©ē”ØåÆčƒ½ćŖćƒŖćƒć‚øćƒˆćƒŖćŒć‚ć‚Šć¾ć›ć‚“", + "pick repo": "ćƒŖćƒć‚øćƒˆćƒŖć®éøęŠž" } \ No newline at end of file diff --git a/i18n/jpn/extensions/git/out/repository.i18n.json b/i18n/jpn/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..553e8a8277f --- /dev/null +++ b/i18n/jpn/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "開恏", + "index modified": "ć‚¤ćƒ³ćƒ‡ćƒƒć‚Æć‚¹ć®å¤‰ę›“", + "modified": "å¤‰ę›“ęøˆćæ", + "index added": "ć‚¤ćƒ³ćƒ‡ćƒƒć‚Æć‚¹ć®čæ½åŠ ", + "index deleted": "ć‚¤ćƒ³ćƒ‡ćƒƒć‚Æć‚¹ć®å‰Šé™¤", + "deleted": "å‰Šé™¤ęøˆćæ", + "index renamed": "ć‚¤ćƒ³ćƒ‡ćƒƒć‚Æć‚¹ć®åå‰å¤‰ę›“", + "index copied": "ć‚¤ćƒ³ćƒ‡ćƒƒć‚Æć‚¹ć‚’ć‚³ćƒ”ćƒ¼", + "untracked": "追跔対豔外", + "ignored": "焔視", + "both deleted": "åŒę–¹ćØć‚‚å‰Šé™¤", + "added by us": "ć“ć”ć‚‰å“ć«ć‚ˆć‚‹čæ½åŠ ", + "deleted by them": "ć‚ć”ć‚‰å“ć«ć‚ˆć‚‹å‰Šé™¤", + "added by them": "ć‚ć”ć‚‰å“ć«ć‚ˆć‚‹čæ½åŠ ", + "deleted by us": "ć“ć”ć‚‰å“ć«ć‚ˆć‚‹å‰Šé™¤", + "both added": "åŒę–¹ćØć‚‚čæ½åŠ ", + "both modified": "åŒę–¹ćØć‚‚å¤‰ę›“", + "commit": "ć‚³ćƒŸćƒƒćƒˆ", + "merge changes": "å¤‰ę›“ć®ćƒžćƒ¼ć‚ø", + "staged changes": "ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°ęøˆćæć®å¤‰ę›“", + "changes": "変曓", + "ok": "OK", + "neveragain": "ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", + "huge": "'{0}' 恮Git ćƒŖćƒć‚øćƒˆćƒŖć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖå¤‰ę›“ćŒå¤šć„ćŸć‚ć€ Git ę©Ÿčƒ½ć®äø€éƒØć®ćæćŒęœ‰åŠ¹ć«ćŖć‚Šć¾ć™ć€‚" +} \ No newline at end of file diff --git a/i18n/jpn/extensions/git/package.i18n.json b/i18n/jpn/extensions/git/package.i18n.json index 07f940f4757..e176e6c6ec0 100644 --- a/i18n/jpn/extensions/git/package.i18n.json +++ b/i18n/jpn/extensions/git/package.i18n.json @@ -6,38 +6,48 @@ { "command.clone": "複製", "command.init": "ćƒŖćƒć‚øćƒˆćƒŖć®åˆęœŸåŒ–", + "command.close": "ćƒŖćƒć‚øćƒˆćƒŖć‚’é–‰ć˜ć‚‹", "command.refresh": "ęœ€ę–°ć®ęƒ…å ±ć«ę›“ę–°", "command.openChange": "å¤‰ę›“ć‚’é–‹ć", "command.openFile": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", "command.openHEADFile": "HEAD ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", "command.stage": "å¤‰ę›“ć®ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°", - "command.stageAll": "ć™ć¹ć¦ć®å¤‰ę›“ć®ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°", - "command.stageSelectedRanges": "éøęŠžć—ćŸēÆ„å›²ć‚’ć‚¹ćƒ†ćƒ¼ć‚øć™ć‚‹", + "command.stageAll": "ć™ć¹ć¦ć®å¤‰ę›“ć‚’ć‚¹ćƒ†ćƒ¼ć‚ø", + "command.stageSelectedRanges": "éøęŠžć—ćŸēÆ„å›²ć‚’ć‚¹ćƒ†ćƒ¼ć‚ø", "command.revertSelectedRanges": "éøęŠžēÆ„å›²ć‚’å…ƒć«ęˆ»ć™", + "command.stageChange": "å¤‰ę›“ć®ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°", + "command.revertChange": "å¤‰ę›“ć‚’å…ƒć«ęˆ»ć™", "command.unstage": "å¤‰ę›“ć®ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°č§£é™¤", "command.unstageAll": "ć™ć¹ć¦ć®å¤‰ę›“ć®ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°č§£é™¤", - "command.unstageSelectedRanges": "éøęŠžć—ćŸēÆ„å›²ć‚’ć‚¢ćƒ³ć‚¹ćƒ†ćƒ¼ć‚øć™ć‚‹", + "command.unstageSelectedRanges": "éøęŠžć—ćŸēÆ„å›²ć®ć‚¹ćƒ†ćƒ¼ć‚øć‚’č§£é™¤", "command.clean": "変曓を砓棄", "command.cleanAll": "すべての変曓を砓棄", "command.commit": "Commit", "command.commitStaged": "ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚°ęøˆćæć‚’ć‚³ćƒŸćƒƒćƒˆ", "command.commitStagedSigned": "ć‚³ćƒŸćƒƒćƒˆć—ć¦ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚° (ć‚µć‚¤ćƒ³ć‚Ŗćƒ•)", + "command.commitStagedAmend": "ć‚³ćƒŸćƒƒćƒˆć—ć¦ć‚¹ćƒ†ćƒ¼ć‚øćƒ³ć‚° (修正)", "command.commitAll": "ć™ć¹ć¦ć‚³ćƒŸćƒƒćƒˆ", "command.commitAllSigned": "ć™ć¹ć¦ć‚³ćƒŸćƒƒćƒˆ (ć‚µć‚¤ćƒ³ć‚Ŗćƒ•)", + "command.commitAllAmend": "ć™ć¹ć¦ć‚³ćƒŸćƒƒćƒˆ (修正)", "command.undoCommit": "å‰å›žć®ć‚³ćƒŸćƒƒćƒˆć‚’å…ƒć«ęˆ»ć™", "command.checkout": "ćƒć‚§ćƒƒć‚Æć‚¢ć‚¦ćƒˆå…ˆ...", - "command.branch": "åˆ†å²ć®ä½œęˆ...", + "command.branch": "ćƒ–ćƒ©ćƒ³ćƒć‚’ä½œęˆ...", "command.deleteBranch": "ćƒ–ćƒ©ćƒ³ćƒć®å‰Šé™¤...", "command.merge": "ćƒ–ćƒ©ćƒ³ćƒć‚’ćƒžćƒ¼ć‚ø...", + "command.createTag": "ć‚æć‚°ć‚’ä½œęˆ", "command.pull": "ćƒ—ćƒ«", "command.pullRebase": "ćƒ—ćƒ« (ćƒŖćƒ™ćƒ¼ć‚¹)", "command.pullFrom": "ęŒ‡å®šå…ƒć‹ć‚‰ćƒ—ćƒ«...", "command.push": "ćƒ—ćƒƒć‚·ćƒ„", "command.pushTo": "ćƒ—ćƒƒć‚·ćƒ„å…ˆ...", + "command.pushWithTags": "ć‚æć‚°ć‚’ć¤ć‘ć¦ćƒ—ćƒƒć‚·ćƒ„", "command.sync": "同期", "command.publish": "ćƒ–ćƒ©ćƒ³ćƒć®ē™ŗč”Œ", "command.showOutput": "Git å‡ŗåŠ›ć®č”Øē¤ŗ", "command.ignore": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’ .gitignore に追加", + "command.stash": "ć‚¹ć‚æćƒƒć‚·ćƒ„", + "command.stashPop": "ć‚¹ć‚æćƒƒć‚·ćƒ„ć‚’é©ē”Øć—ć¦å‰Šé™¤...", + "command.stashPopLatest": "ęœ€ę–°ć®ć‚¹ć‚æćƒƒć‚·ćƒ„ć‚’é©ē”Øć—ć¦å‰Šé™¤", "config.enabled": "Git ćŒęœ‰åŠ¹ć«ćŖć£ć¦ć„ć‚‹ć‹ć©ć†ć‹", "config.path": "Git å®Ÿč”ŒåÆčƒ½ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹", "config.autorefresh": "č‡Ŗå‹•ę›“ę–°ćŒęœ‰åŠ¹ć‹ć©ć†ć‹", @@ -49,5 +59,7 @@ "config.ignoreLegacyWarning": "ꗧ Git ć®č­¦å‘Šć‚’ē„”č¦–ć—ć¾ć™", "config.ignoreLimitWarning": "ćƒŖćƒć‚øćƒˆćƒŖå†…ć«å¤‰ę›“ćŒå¤šć„å “åˆćÆč­¦å‘Šć‚’ē„”č¦–ć—ć¾ć™", "config.defaultCloneDirectory": "Git ćƒŖćƒć‚øćƒˆćƒŖć‚’ć‚Æćƒ­ćƒ¼ćƒ³ć™ć‚‹ę—¢å®šć®å “ę‰€", - "config.enableSmartCommit": "ć‚¹ćƒ†ćƒ¼ć‚øć•ć‚ŒćŸå¤‰ę›“ćŒćŖć„å “åˆćÆć™ć¹ć¦ć®å¤‰ę›“ć‚’ć‚³ćƒŸćƒƒćƒˆć—ć¾ć™ć€‚" + "config.enableSmartCommit": "ć‚¹ćƒ†ćƒ¼ć‚øć•ć‚ŒćŸå¤‰ę›“ćŒćŖć„å “åˆćÆć™ć¹ć¦ć®å¤‰ę›“ć‚’ć‚³ćƒŸćƒƒćƒˆć—ć¾ć™ć€‚", + "config.enableCommitSigning": "GPG ć«ć‚ˆć‚Šćƒ‡ć‚øć‚æćƒ«ē½²åć•ć‚ŒćŸć‚³ćƒŸćƒƒćƒˆć‚’ęœ‰åŠ¹ć«ć—ć¾ć™ć€‚", + "config.discardAllScope": "'すべての変曓を砓棄' ć‚³ćƒžćƒ³ćƒ‰ć«ć‚ˆć£ć¦ć©ć®å¤‰ę›“ćŒē “ę£„ć•ć‚Œć‚‹ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚'all' はすべての変曓を砓棄します。 'tracked' ćÆčæ½č·”ć•ć‚Œć¦ć„ć‚‹ćƒ•ć‚”ć‚¤ćƒ«ć ć‘ć‚’ē “ę£„ć—ć¾ć™ć€‚ 'prompt' ćÆć€ć‚¢ć‚Æć‚·ćƒ§ćƒ³ćŒå®Ÿč”Œć•ć‚Œć‚‹ćŸć³ć«ćƒ—ćƒ­ćƒ³ćƒ—ā€‹ā€‹ćƒˆ ćƒ€ć‚¤ć‚¢ćƒ­ć‚°ć‚’č”Øē¤ŗć—ć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/extensions/grunt/out/main.i18n.json b/i18n/jpn/extensions/grunt/out/main.i18n.json index 32ff080491f..c7f240f8ee9 100644 --- a/i18n/jpn/extensions/grunt/out/main.i18n.json +++ b/i18n/jpn/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Grunt ć®č‡Ŗå‹•ę¤œå‡ŗćŒę¬”ć®ć‚Øćƒ©ćƒ¼ć§å¤±ę•—ć—ć¾ć—ćŸ: {0}" + "execFailed": "ćƒ•ć‚©ćƒ«ćƒ€ {0} 恧Grunt ć®ć‚Øćƒ©ćƒ¼ć«ć‚ˆć‚‹å¤±ę•—ć‚’č‡Ŗå‹•ę¤œå‡ŗ: {1}" } \ No newline at end of file diff --git a/i18n/jpn/extensions/gulp/out/main.i18n.json b/i18n/jpn/extensions/gulp/out/main.i18n.json index ccb0e658af1..69bef1eecdc 100644 --- a/i18n/jpn/extensions/gulp/out/main.i18n.json +++ b/i18n/jpn/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "gulp ć®ć‚Øćƒ©ćƒ¼ć«ć‚ˆć‚‹å¤±ę•—ć‚’č‡Ŗå‹•ę¤œå‡ŗ: {0}" + "execFailed": "ćƒ•ć‚©ćƒ«ćƒ€ {0} 恧gulp ć®ć‚Øćƒ©ćƒ¼ć«ć‚ˆć‚‹å¤±ę•—ć‚’č‡Ŗå‹•ę¤œå‡ŗ: {1}" } \ No newline at end of file diff --git a/i18n/jpn/extensions/html/package.i18n.json b/i18n/jpn/extensions/html/package.i18n.json index b543141db66..52563f5a543 100644 --- a/i18n/jpn/extensions/html/package.i18n.json +++ b/i18n/jpn/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "ę—¢å®šć® HTML ćƒ•ć‚©ćƒ¼ćƒžćƒƒć‚æć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ (å†čµ·å‹•ćŒåæ…č¦ć§ć™)", + "html.format.enable.desc": "ę—¢å®šć® HTML ćƒ•ć‚©ćƒ¼ćƒžćƒƒć‚æć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™", "html.format.wrapLineLength.desc": "1 č”Œć‚ćŸć‚Šć®ęœ€å¤§ę–‡å­—ę•° (0 = ē„”åŠ¹ć«ć™ć‚‹)怂", "html.format.unformatted.desc": "å†ćƒ•ć‚©ćƒ¼ćƒžćƒƒćƒˆć—ć¦ćÆćŖć‚‰ćŖć„ć‚æć‚°ć®ć€ć‚³ćƒ³ćƒžåŒŗåˆ‡ć‚Šć®äø€č¦§ć€‚'null' ć®å “åˆć€ę—¢å®šć§ https://www.w3.org/TR/html5/dom.html#phrasing-content ć«ćƒŖć‚¹ćƒˆć•ć‚Œć¦ć„ć‚‹ć™ć¹ć¦ć®ć‚æć‚°ć«ćŖć‚Šć¾ć™ć€‚", "html.format.contentUnformatted.desc": "ć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć‚’å†ćƒ•ć‚©ćƒ¼ćƒžćƒƒćƒˆć—ć¦ćÆćŖć‚‰ćŖć„ć‚æć‚°ć‚’ć‚³ćƒ³ćƒžć§åŒŗåˆ‡ć£ć¦ćƒŖć‚¹ćƒˆć«ć—ć¾ć™ć€‚'null' ćÆć€ę—¢å®šå€¤ć® 'pre' タグを蔨します。", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "ćƒ“ćƒ«ćƒˆć‚¤ćƒ³ HTML čØ€čŖžć‚µćƒćƒ¼ćƒˆćŒ Angular V1 ć®ć‚æć‚°ćŠć‚ˆć³ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚’å€™č£œč”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’ę§‹ęˆć—ć¾ć™ć€‚", "html.suggest.ionic.desc": "ćƒ“ćƒ«ćƒˆć‚¤ćƒ³ HTML čØ€čŖžć‚µćƒćƒ¼ćƒˆćŒ Ionic ć®ć‚æć‚°ć€ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć€ćŠć‚ˆć³å€¤ć‚’å€™č£œč”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’ę§‹ęˆć—ć¾ć™ć€‚", "html.suggest.html5.desc": "ćƒ“ćƒ«ćƒˆć‚¤ćƒ³ HTML čØ€čŖžć‚µćƒćƒ¼ćƒˆćŒ HTML5 ć®ć‚æć‚°ć€ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć€ćŠć‚ˆć³å€¤ć‚’å€™č£œč”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’ę§‹ęˆć—ć¾ć™ć€‚", + "html.trace.server.desc": "VS Code と HTML čØ€čŖžć‚µćƒ¼ćƒćƒ¼é–“ć®é€šäæ”ć‚’ćƒˆćƒ¬ćƒ¼ć‚¹ć—ć¾ć™ć€‚", "html.validate.scripts": "ćƒ“ćƒ«ćƒˆć‚¤ćƒ³ HTML čØ€čŖžć‚µćƒćƒ¼ćƒˆćŒåŸ‹ć‚č¾¼ćæć‚¹ć‚ÆćƒŖćƒ—ćƒˆć‚’ę¤œčØ¼ć™ć‚‹ć‹ć©ć†ć‹ć‚’ę§‹ęˆć—ć¾ć™ć€‚", - "html.validate.styles": "ćƒ“ćƒ«ćƒˆć‚¤ćƒ³ HTML čØ€čŖžć‚µćƒćƒ¼ćƒˆćŒåŸ‹ć‚č¾¼ćæć‚¹ć‚æć‚¤ćƒ«ć‚’ę¤œčØ¼ć™ć‚‹ć‹ć©ć†ć‹ć‚’ę§‹ęˆć—ć¾ć™ć€‚" + "html.validate.styles": "ćƒ“ćƒ«ćƒˆć‚¤ćƒ³ HTML čØ€čŖžć‚µćƒćƒ¼ćƒˆćŒåŸ‹ć‚č¾¼ćæć‚¹ć‚æć‚¤ćƒ«ć‚’ę¤œčØ¼ć™ć‚‹ć‹ć©ć†ć‹ć‚’ę§‹ęˆć—ć¾ć™ć€‚", + "html.autoClosingTags": "HTML ć‚æć‚°ć®č‡Ŗå‹•ć‚Æćƒ­ćƒ¼ć‚ŗć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/extensions/jake/out/main.i18n.json b/i18n/jpn/extensions/jake/out/main.i18n.json index 0f77342ecbc..bd786d74d17 100644 --- a/i18n/jpn/extensions/jake/out/main.i18n.json +++ b/i18n/jpn/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Jake ć®ć‚Øćƒ©ćƒ¼ć«ć‚ˆć‚‹å¤±ę•—ć‚’č‡Ŗå‹•ę¤œå‡ŗ: {0}" + "execFailed": "ćƒ•ć‚©ćƒ«ćƒ€ {0} 恧Jake ć®ć‚Øćƒ©ćƒ¼ć«ć‚ˆć‚‹å¤±ę•—ć‚’č‡Ŗå‹•ę¤œå‡ŗ: {1}" } \ No newline at end of file diff --git a/i18n/jpn/extensions/json/package.i18n.json b/i18n/jpn/extensions/json/package.i18n.json index 7020b602951..365d8a0de8d 100644 --- a/i18n/jpn/extensions/json/package.i18n.json +++ b/i18n/jpn/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "ęŒ‡å®šć•ć‚ŒćŸ URL ć®ć‚¹ć‚­ćƒ¼ćƒžå®šē¾©ć§ć™ć€‚ć‚¹ć‚­ćƒ¼ćƒžćÆć€ć‚¹ć‚­ćƒ¼ćƒž URL ćøć®ć‚¢ć‚Æć‚»ć‚¹ć‚’éæć‘ć‚‹ćŸć‚ć«ć®ćæęŒ‡å®šć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", "json.format.enable.desc": "ę—¢å®šć® JSON ćƒ•ć‚©ćƒ¼ćƒžćƒƒć‚æć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ (å†čµ·å‹•ćŒåæ…č¦ć§ć™)", "json.tracing.desc": "VS Code と JSON čØ€čŖžć‚µćƒ¼ćƒćƒ¼é–“ć®é€šäæ”ć‚’ćƒˆćƒ¬ćƒ¼ć‚¹ć—ć¾ć™ć€‚", - "json.colorDecorators.enable.desc": "ć‚«ćƒ©ćƒ¼ ćƒ‡ć‚³ćƒ¬ćƒ¼ć‚æćƒ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™" + "json.colorDecorators.enable.desc": "ć‚«ćƒ©ćƒ¼ ćƒ‡ć‚³ćƒ¬ćƒ¼ć‚æćƒ¼ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™", + "json.colorDecorators.enable.deprecationMessage": "設定 `json.colorDecorators.enable` ćÆä½æē”Øć•ć‚ŒćŖććŖć‚Šć¾ć—ćŸć€‚`editor.colorDecorators` ć‚’ä½æē”Øć—ć¦ćć ć•ć„ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/extensions/markdown/out/extension.i18n.json b/i18n/jpn/extensions/markdown/out/extension.i18n.json index fd083fda4b6..20d27004e03 100644 --- a/i18n/jpn/extensions/markdown/out/extension.i18n.json +++ b/i18n/jpn/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "'markdown.styles' ć‚’čŖ­ćæč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“: {0}" + "onPreviewStyleLoadError": "'markdown.styles' ć‚’čŖ­ćæč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“: {0}", + "previewTitle": "ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ {0}" } \ No newline at end of file diff --git a/i18n/jpn/extensions/markdown/out/security.i18n.json b/i18n/jpn/extensions/markdown/out/security.i18n.json index dc234e49ac5..4ef933fbf91 100644 --- a/i18n/jpn/extensions/markdown/out/security.i18n.json +++ b/i18n/jpn/extensions/markdown/out/security.i18n.json @@ -4,9 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.strictTitle": "åŽ³åÆ†ć§ć™ć€‚ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć§äæč­·ć•ć‚ŒćŸć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć®ćæć‚’čŖ­ćæč¾¼ćæć¾ć™ć€‚ ", - "preview.showPreviewSecuritySelector.currentSelection": "ē¾åœØć®čØ­å®š", - "preview.showPreviewSecuritySelector.insecureContentTitle": "HTTP ć‚’ä»‹ć—ćŸć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć®čŖ­ćæč¾¼ćæć‚’čØ±åÆć—ć¾ć™ć€‚", - "preview.showPreviewSecuritySelector.scriptsAndAllContent": "ć™ć¹ć¦ć®ć‚³ćƒ³ćƒ†ćƒ³ćƒ„ćØć‚¹ć‚ÆćƒŖćƒ—ćƒˆć®å®Ÿč”Œć‚’čØ±åÆć—ć¾ć™ć€‚ęŽØå„Øć•ć‚Œć¾ć›ć‚“ć€‚", + "strict.title": "é«˜ćƒ¬ćƒ™ćƒ«", + "strict.description": "ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć§äæč­·ć•ć‚ŒćŸć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć®ćæć‚’čŖ­ćæč¾¼ć‚€", + "insecureContent.title": "ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£ć§äæč­·ć•ć‚Œć¦ć„ćŖć„ć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć‚’čØ±åÆć™ć‚‹", + "insecureContent.description": "HTTP ć‚’ä»‹ć—ćŸć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć®čŖ­ćæč¾¼ćæć‚’ęœ‰åŠ¹ć«ć™ć‚‹", + "disable.title": "ē„”åŠ¹ć«ć™ć‚‹", + "disable.description": "ć™ć¹ć¦ć®ć‚³ćƒ³ćƒ†ćƒ³ćƒ„ćØć‚¹ć‚ÆćƒŖćƒ—ćƒˆć®å®Ÿč”Œć‚’čØ±åÆć—ć¾ć™ć€‚ęŽØå„Øć•ć‚Œć¾ć›ć‚“ć€‚", + "moreInfo.title": "č©³ē“°ęƒ…å ±", "preview.showPreviewSecuritySelector.title": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć«é–¢ć™ć‚‹ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£čØ­å®šć‚’éøęŠž " } \ No newline at end of file diff --git a/i18n/jpn/extensions/markdown/package.i18n.json b/i18n/jpn/extensions/markdown/package.i18n.json index 5efdc62eafa..9c09de2d69a 100644 --- a/i18n/jpn/extensions/markdown/package.i18n.json +++ b/i18n/jpn/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć§ę”¹č”Œć‚’ćƒ¬ćƒ³ćƒ€ćƒŖćƒ³ć‚°ć™ć‚‹ę–¹ę³•ć‚’čØ­å®šć—ć¾ć™ć€‚'true' ć«čØ­å®šć™ć‚‹ćØę”¹č”Œć”ćØć«
ć‚’ä½œęˆć—ć¾ć™ć€‚", + "markdown.preview.linkify": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć§ URL å½¢å¼ć®ćƒ†ć‚­ć‚¹ćƒˆć‹ć‚‰ćƒŖćƒ³ć‚Æćøć®å¤‰ę›ć‚’ęœ‰åŠ¹ć¾ćŸćÆē„”åŠ¹ć«ć—ć¾ć™ć€‚", "markdown.preview.doubleClickToSwitchToEditor.desc": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ć®ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć§ćƒ€ćƒ–ćƒ«ć‚ÆćƒŖćƒƒć‚Æć™ć‚‹ćØć€ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć«åˆ‡ć‚Šę›æć‚ć‚Šć¾ć™ć€‚", "markdown.preview.fontFamily.desc": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć§ä½æē”Øć•ć‚Œć‚‹ćƒ•ć‚©ćƒ³ćƒˆ ćƒ•ć‚”ćƒŸćƒŖć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "markdown.preview.fontSize.desc": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć§ä½æē”Øć•ć‚Œć‚‹ćƒ•ć‚©ćƒ³ćƒˆ サイズ (ćƒ”ć‚Æć‚»ćƒ«å˜ä½) ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć‚’ęØŖć«č”Øē¤ŗ", "markdown.showSource.title": "ć‚½ćƒ¼ć‚¹ć®č”Øē¤ŗ", "markdown.styles.dec": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć‹ć‚‰ä½æē”Øć™ć‚‹ CSS ć‚¹ć‚æć‚¤ćƒ« ć‚·ćƒ¼ćƒˆć® URL ć¾ćŸćÆćƒ­ćƒ¼ć‚«ćƒ« ćƒ‘ć‚¹ć®äø€č¦§ć€‚ē›øåÆ¾ćƒ‘ć‚¹ćÆć€ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§é–‹ć‹ć‚Œć¦ć„ć‚‹ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćøć®ēµ¶åÆ¾ćƒ‘ć‚¹ćØč§£é‡ˆć•ć‚Œć¾ć™ć€‚é–‹ć‹ć‚Œć¦ć„ć‚‹ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćŒćŖć„å “åˆć€ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ•ć‚”ć‚¤ćƒ«ć®å “ę‰€ć‚’åŸŗęŗ–ćØć—ć¦ć„ć‚‹ćØč§£é‡ˆć•ć‚Œć¾ć™ć€‚'\\' はすべて '\\\\' ćØå…„åŠ›ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", - "markdown.showPreviewSecuritySelector.title": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć®ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£čØ­å®šć®å¤‰ę›“", - "markdown.trace.desc": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ę‹”å¼µę©Ÿčƒ½ć®ćƒ‡ćƒćƒƒć‚°ćƒ­ć‚°ć‚’ęœ‰åŠ¹ć«ć—ć¾ć™ć€‚" + "markdown.showPreviewSecuritySelector.title": "ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ ć®ć‚»ć‚­ćƒ„ćƒŖćƒ†ć‚£čØ­å®šć‚’å¤‰ę›“", + "markdown.trace.desc": "ćƒžćƒ¼ć‚Æćƒ€ć‚¦ćƒ³ę‹”å¼µę©Ÿčƒ½ć®ćƒ‡ćƒćƒƒć‚°ćƒ­ć‚°ć‚’ęœ‰åŠ¹ć«ć—ć¾ć™ć€‚", + "markdown.refreshPreview.title": "ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ć‚’ę›“ę–°" } \ No newline at end of file diff --git a/i18n/jpn/extensions/npm/out/main.i18n.json b/i18n/jpn/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..3e583a812d8 --- /dev/null +++ b/i18n/jpn/extensions/npm/out/main.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "npm.parseError": "npmć‚æć‚¹ć‚Æę¤œå‡ŗ: ćƒ•ć‚”ć‚¤ćƒ« {0} ć®č§£ęžć«å¤±ę•—ć—ć¾ć—ćŸ" +} \ No newline at end of file diff --git a/i18n/jpn/extensions/npm/package.i18n.json b/i18n/jpn/extensions/npm/package.i18n.json index 3ada7cc9839..6ef74ccbb61 100644 --- a/i18n/jpn/extensions/npm/package.i18n.json +++ b/i18n/jpn/extensions/npm/package.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "config.npm.autoDetect": "npm ć‚¹ć‚ÆćƒŖćƒ—ćƒˆć®č‡Ŗå‹•ę¤œå‡ŗć‚’ć‚Ŗćƒ³ć«ć™ć‚‹ć‹ć‚Ŗćƒ•ć«ć™ć‚‹ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ę—¢å®šćÆć‚Ŗćƒ³ć§ć™ć€‚", - "config.npm.runSilent": "`--silent` ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć‚’ä½æē”Øć—ć¦ npm ć‚³ćƒžćƒ³ćƒ‰ć‚’å®Ÿč”Œ" + "config.npm.runSilent": "`--silent` ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć‚’ä½æē”Øć—ć¦ npm ć‚³ćƒžćƒ³ćƒ‰ć‚’å®Ÿč”Œ", + "npm.parseError": "npmć‚æć‚¹ć‚Æę¤œå‡ŗ: ćƒ•ć‚”ć‚¤ćƒ« {0} ć®č§£ęžć«å¤±ę•—ć—ć¾ć—ćŸ" } \ No newline at end of file diff --git a/i18n/jpn/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/jpn/extensions/typescript/out/features/taskProvider.i18n.json index 99ed0a8c043..36836cc0bf0 100644 --- a/i18n/jpn/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/jpn/extensions/typescript/out/features/taskProvider.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "buildAndWatchTscLabel": "ć‚¦ć‚©ćƒƒćƒ - {0}", - "buildTscLabel": "ćƒ“ćƒ«ćƒ‰ - {0}" + "buildTscLabel": "ćƒ“ćƒ«ćƒ‰ - {0}", + "buildAndWatchTscLabel": "ć‚¦ć‚©ćƒƒćƒ - {0}" } \ No newline at end of file diff --git a/i18n/jpn/extensions/typescript/out/utils/api.i18n.json b/i18n/jpn/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..b15aaab723f --- /dev/null +++ b/i18n/jpn/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "ćƒćƒ¼ć‚øćƒ§ćƒ³ćŒē„”åŠ¹ć§ć™" +} \ No newline at end of file diff --git a/i18n/jpn/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/jpn/extensions/typescript/out/utils/versionPicker.i18n.json index e23b727c846..1668a6e2c03 100644 --- a/i18n/jpn/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/jpn/extensions/typescript/out/utils/versionPicker.i18n.json @@ -5,7 +5,7 @@ // Do not edit this file. It is machine generated. { "useVSCodeVersionOption": "VS Code ć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’ä½æē”Ø", - "useWorkspaceVersionOption": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒćƒ¼ć‚øćƒ§ćƒ³ć®ä½æē”Ø", + "useWorkspaceVersionOption": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’ä½æē”Ø", "learnMore": "č©³ē“°ęƒ…å ±", "selectTsVersion": "JavaScript ćŠć‚ˆć³ TypeScript čØ€čŖžć®ę©Ÿčƒ½ć«ä½æē”Øć™ć‚‹ TypeScript ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’éøęŠžć—ć¾ć™" } \ No newline at end of file diff --git a/i18n/jpn/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/jpn/extensions/typescript/out/utils/versionProvider.i18n.json index b756a20a584..7aeb9d9672f 100644 --- a/i18n/jpn/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/jpn/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "é©åˆ‡ć«å‹•ä½œć—ćŖć„ć‚¦ć‚¤ćƒ«ć‚¹ę¤œå‡ŗćƒ„ćƒ¼ćƒ«ćŖć©ć®ä»–ć®ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć«ć‚ˆć‚Šć€VSCode 恮 tsserver ćÆå‰Šé™¤ć•ć‚Œć¾ć—ćŸć€‚VS Code ć‚’å†ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¦ćć ć•ć„ć€‚" + "couldNotLoadTsVersion": "ć“ć®ćƒ‘ć‚¹ć§ćÆ TypeScript ć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’čŖ­ćæč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“", + "noBundledServerFound": "VS Code 恮 tsserver ćŒé©åˆ‡ć«å‹•ä½œć—ćŖć„ć‚¦ć‚¤ćƒ«ć‚¹ę¤œå‡ŗćƒ„ćƒ¼ćƒ«ćŖć©ć®ä»–ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć«ć‚ˆć‚Šå‰Šé™¤ć•ć‚Œć¾ć—ćŸć€‚VS Code ć‚’å†ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¦ćć ć•ć„ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/extensions/typescript/package.i18n.json b/i18n/jpn/extensions/typescript/package.i18n.json index 79c205c42ce..b8035031298 100644 --- a/i18n/jpn/extensions/typescript/package.i18n.json +++ b/i18n/jpn/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "ćƒ‘ćƒ©ćƒ”ćƒ¼ć‚æćƒ¼ ć‚·ć‚°ćƒćƒćƒ£ć‚’å«ć‚€å®Œå…ØćŖé–¢ę•°ć€‚", "typescript.tsdk.desc": "使用する tsserver と lib*.d.ts ćƒ•ć‚”ć‚¤ćƒ«ćŒå«ć¾ć‚Œć¦ć„ć‚‹ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ćƒ‘ć‚¹ć‚’ęŒ‡å®šć—ć¾ć™ć€‚", - "typescript.disableAutomaticTypeAcquisition": "ēØ®é”žć®č‡Ŗå‹•ēš„ćŖå–å¾—ć‚’ē„”åŠ¹ć«ć—ć¾ć™ć€‚å¤‰ę›“å¾Œć€TypeScript 2.0.6 ä»„é™ćØå†čµ·å‹•ćŒåæ…č¦ć§ć™ć€‚", + "typescript.disableAutomaticTypeAcquisition": "åž‹å®šē¾©ć®č‡Ŗå‹•å–å¾—ć‚’ē„”åŠ¹ć«ć—ć¾ć™ć€‚TypeScript 2.0.6 ä»„äøŠćŒåæ…č¦ć§ć™ć€‚", "typescript.tsserver.log": "ćƒ•ć‚”ć‚¤ćƒ«ćøć® TS ć‚µćƒ¼ćƒćƒ¼ć®ćƒ­ć‚°ć‚’ęœ‰åŠ¹ć«ć—ć¾ć™ć€‚ć“ć®ćƒ­ć‚°ćÆ TS ć‚µćƒ¼ćƒćƒ¼ć®å•é”Œć‚’čØŗę–­ć™ć‚‹ćŸć‚ć«ä½æē”Øć§ćć¾ć™ć€‚ćƒ­ć‚°ć«ćÆć€ćƒ—ćƒ­ć‚øć‚§ć‚Æćƒˆć®ćƒ•ć‚”ć‚¤ćƒ«ćƒ‘ć‚¹ć€ć‚½ćƒ¼ć‚¹ć‚³ćƒ¼ćƒ‰ć€ćć®ä»–ć®ę½œåœØēš„ć«ę©ŸåÆ†ę€§ć®é«˜ć„ęƒ…å ±ćŒå«ć¾ć‚Œć¦ć„ć‚‹å “åˆćŒć‚ć‚Šć¾ć™ć€‚", "typescript.tsserver.trace": "TS ć‚µćƒ¼ćƒćƒ¼ć«é€äæ”ć•ć‚Œć‚‹ćƒ”ćƒƒć‚»ćƒ¼ć‚øć®ćƒˆćƒ¬ćƒ¼ć‚¹ć‚’ęœ‰åŠ¹ć«ć—ć¾ć™ć€‚ć“ć®ćƒˆćƒ¬ćƒ¼ć‚¹ćÆ TS ć‚µćƒ¼ćƒćƒ¼ć®å•é”Œć‚’čØŗę–­ć™ć‚‹ćŸć‚ć«ä½æē”Øć§ćć¾ć™ć€‚ćƒˆćƒ¬ćƒ¼ć‚¹ć«ćÆć€ćƒ—ćƒ­ć‚øć‚§ć‚Æćƒˆć®ćƒ•ć‚”ć‚¤ćƒ«ćƒ‘ć‚¹ć€ć‚½ćƒ¼ć‚¹ć‚³ćƒ¼ćƒ‰ć€ćć®ä»–ć®ę½œåœØēš„ć«ę©ŸåÆ†ę€§ć®é«˜ć„ęƒ…å ±ćŒå«ć¾ć‚Œć¦ć„ć‚‹å “åˆćŒć‚ć‚Šć¾ć™ć€‚", "typescript.validate.enable": "TypeScript ć®ę¤œčØ¼ć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ć€‚", @@ -44,7 +44,11 @@ "typescript.npm": "åž‹å®šē¾©ć®č‡Ŗå‹•å–å¾—ć«ä½æē”Øć•ć‚Œć‚‹ NPM å®Ÿč”ŒåÆčƒ½ćƒ•ć‚”ć‚¤ćƒ«ćøć®ćƒ‘ć‚¹ć‚’ęŒ‡å®šć—ć¾ć™ć€‚TypeScriptĀ 2.3.4 ä»„äøŠćŒåæ…č¦ć§ć™ć€‚", "typescript.check.npmIsInstalled": "åž‹å®šē¾©ć®č‡Ŗå‹•å–å¾—ć« NPM ćŒć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć‚‹ć‹ć©ć†ć‹ć‚’ē¢ŗčŖć—ć¾ć™ć€‚", "javascript.nameSuggestions": "JavaScript ć®å€™č£œćƒŖć‚¹ćƒˆå†…ć§ćƒ•ć‚”ć‚¤ćƒ«ć‹ć‚‰äø€ę„ć®åå‰ć‚’å«ć‚€ć‹ć©ć†ć‹ć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ć€‚", - "typescript.tsc.autoDetect": "tsc ć‚æć‚¹ć‚Æć®č‡Ŗå‹•ę¤œå‡ŗć‚’ć‚Ŗćƒ³ć«ć™ć‚‹ć‹ć‚Ŗćƒ•ć«ć™ć‚‹ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", + "typescript.tsc.autoDetect": "tsc ć‚æć‚¹ć‚Æć®č‡Ŗå‹•ę¤œå‡ŗć‚’åˆ¶å¾”ć—ć¾ć™ć€‚'off' ćÆć“ć®ę©Ÿčƒ½ć‚’ē„”åŠ¹ć«ć—ć¾ć™ć€‚'build' は 1 ć¤ć®ć‚³ćƒ³ćƒ‘ć‚¤ćƒ«å®Ÿč”Œć‚æć‚¹ć‚Æć®ćæć‚’č”Øē¤ŗć—ć¾ć™ć€‚'watch' ćÆć‚³ćƒ³ćƒ‘ć‚¤ćƒ«ćØć‚¦ć‚©ćƒƒćƒ タスクのみを蔨示します。'on'Ā ćÆćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćØć‚¦ć‚©ćƒƒćƒ ć‚æć‚¹ć‚Æć®äø”ę–¹ć‚’č”Øē¤ŗć—ć¾ć™ć€‚ę—¢å®šå€¤ćÆ 'on' 恧恙怂", "typescript.problemMatchers.tsc.label": "TypeScript ć®å•é”Œ", - "typescript.problemMatchers.tscWatch.label": "TypeScript ć®å•é”Œ (ć‚¦ć‚©ćƒƒćƒ ćƒ¢ćƒ¼ćƒ‰)" + "typescript.problemMatchers.tscWatch.label": "TypeScript ć®å•é”Œ (ć‚¦ć‚©ćƒƒćƒ ćƒ¢ćƒ¼ćƒ‰)", + "typescript.quickSuggestionsForPaths": "Import ćƒ‘ć‚¹ć‚’å…„åŠ›ć™ć‚‹ćØćć®ć‚Æć‚¤ćƒƒć‚Æå€™č£œć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ć€‚", + "typescript.locale": "TypeScript ć®ć‚Øćƒ©ćƒ¼ć‚’å ±å‘Šć™ć‚‹ćŸć‚ć«ä½æē”Øć™ć‚‹ćƒ­ć‚±ćƒ¼ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚TypeScriptĀ 2.6.0 ä»„äøŠćŒåæ…č¦ć§ć™ć€‚'null'Ā ć®č¦å®šå€¤ćÆ TypeScript ć®ć‚Øćƒ©ćƒ¼ć« VS Code ć®ćƒ­ć‚±ćƒ¼ćƒ«ć‚’ä½æē”Øć—ć¾ć™ć€‚", + "javascript.implicitProjectConfig.experimentalDecorators": "ćƒ—ćƒ­ć‚øć‚§ć‚Æćƒˆå¤–ć® JavaScript ćƒ•ć‚”ć‚¤ćƒ«ć® 'experimentalDecorators' ć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ć€‚ę—¢å­˜ć® jsconfi.json 悄 tsconfi.json ćƒ•ć‚”ć‚¤ćƒ«ć®čØ­å®šćÆć“ć‚Œć‚ˆć‚Šå„Ŗå…ˆć•ć‚Œć¾ć™ć€‚TypeScript は 2.3.1 ä»„äøŠć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", + "typescript.autoImportSuggestions.enabled": "自動 import ęę”ˆć‚’ęœ‰åŠ¹/ē„”åŠ¹ć«ć—ć¾ć™ć€‚TypeScript 2.6.1 ä»„äøŠćŒåæ…č¦ć§ć™" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/code/electron-main/menus.i18n.json b/i18n/jpn/src/vs/code/electron-main/menus.i18n.json index 2f15aceaa80..776dd81e332 100644 --- a/i18n/jpn/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/jpn/src/vs/code/electron-main/menus.i18n.json @@ -102,6 +102,7 @@ "miHideActivityBar": "ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć‚’éžč”Øē¤ŗć«ć™ć‚‹(&&A)", "miShowActivityBar": "ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć‚’č”Øē¤ŗć™ć‚‹(&&A)", "miToggleWordWrap": "ęŠ˜ć‚Ščæ”ć—ć®åˆ‡ć‚Šę›æćˆ(&&W)", + "miToggleMinimap": "ćƒŸćƒ‹ćƒžćƒƒćƒ—ć®åˆ‡ć‚Šę›æćˆ(&&M)", "miToggleRenderWhitespace": "ē©ŗē™½ę–‡å­—ć®č”Øē¤ŗć®åˆ‡ć‚Šę›æćˆ(&&R)", "miToggleRenderControlCharacters": "åˆ¶å¾”ę–‡å­—ć®åˆ‡ć‚Šę›æćˆ(&&C)", "miZoomIn": "拔大(&&Z)", @@ -150,6 +151,10 @@ "mZoom": "ć‚ŗćƒ¼ćƒ ", "mBringToFront": "ć™ć¹ć¦ć‚’å‰é¢ć«é…ē½®", "miSwitchWindow": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®åˆ‡ć‚Šę›æćˆ(&&W)...", + "mShowPreviousTab": "å‰ć®ć‚æćƒ–ć‚’č”Øē¤ŗ", + "mShowNextTab": "ę¬”ć®ć‚æćƒ–ć‚’č”Øē¤ŗ", + "mMoveTabToNewWindow": "ć‚æćƒ–ć‚’ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć«ē§»å‹•", + "mMergeAllWindows": "ć™ć¹ć¦ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’ēµ±åˆ", "miToggleDevTools": "é–‹ē™ŗč€…ćƒ„ćƒ¼ćƒ«ć®åˆ‡ć‚Šę›æćˆ(&&T)", "miAccessibilityOptions": "ćƒ¦ćƒ¼ć‚¶ćƒ¼č£œåŠ©ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³(&&O)", "miReportIssues": "å•é”Œć®å ±å‘Š(&&I)", @@ -170,8 +175,8 @@ "miRunningTask": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚Æć‚’č”Øē¤ŗ(&&G)...", "miRestartTask": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚Æć®å†čµ·å‹•(&&E)...", "miTerminateTask": "タスクの終了(&&T)...", - "miConfigureTask": "ć‚æć‚¹ć‚Æć®ę§‹ęˆ(&&C)", - "miConfigureBuildTask": "ę—¢å®šć®ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚Æć®ę§‹ęˆ(&&F)", + "miConfigureTask": "ć‚æć‚¹ć‚Æć®ę§‹ęˆ(&&C)…", + "miConfigureBuildTask": "ę—¢å®šć®ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚Æć®ę§‹ęˆ(&&F)…", "accessibilityOptionsWindowTitle": "ćƒ¦ćƒ¼ć‚¶ćƒ¼č£œåŠ©ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³", "miRestartToUpdate": "å†čµ·å‹•ć—ć¦ę›“ę–°...", "miCheckingForUpdates": "ę›“ę–°ć‚’ē¢ŗčŖć—ć¦ć„ć¾ć™...", diff --git a/i18n/jpn/src/vs/code/electron-main/windows.i18n.json b/i18n/jpn/src/vs/code/electron-main/windows.i18n.json index d8c6d81fa40..7df7f3ceec8 100644 --- a/i18n/jpn/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/jpn/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,22 @@ "ok": "OK", "pathNotExistTitle": "ćƒ‘ć‚¹ćŒå­˜åœØć—ć¾ć›ć‚“", "pathNotExistDetail": "ćƒ‘ć‚¹ '{0}' ćÆćƒ‡ć‚£ć‚¹ć‚Æć«å­˜åœØć—ćŖććŖć£ćŸć‚ˆć†ć§ć™ć€‚", - "reopen": "ć‚‚ć†äø€åŗ¦é–‹ć", - "wait": "å¾…ę©Ÿć‚’ē¶šć‘ć‚‹", - "close": "閉恘悋", + "close": "閉恘悋(&&C)", "appStalled": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‹ć‚‰åæœē­”ćŒć‚ć‚Šć¾ć›ć‚“", "appStalledDetail": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å†åŗ¦é–‹ćć‹ć€é–‰ć˜ć‚‹ć‹ć€ć“ć®ć¾ć¾å¾…ę©Ÿć§ćć¾ć™ć€‚", "appCrashed": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ćŒć‚Æćƒ©ćƒƒć‚·ćƒ„ć—ć¾ć—ćŸ", "appCrashedDetail": "ć”äøä¾æć‚’ćŠć‹ć‘ć—ć¦ē”³ć—čØ³ć‚ć‚Šć¾ć›ć‚“ć€‚ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å†åŗ¦é–‹ć„ć¦ć€äø­ę–­ć—ćŸćØć“ć‚ć‹ć‚‰ē¶šč”Œć§ćć¾ć™ć€‚", + "open": "開恏", + "openFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć", "openFile": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", - "openFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć" + "workspaceOpenedMessage": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ '{0}' ć‚’äæå­˜ć§ćć¾ć›ć‚“", + "workspaceOpenedDetail": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ćÆę—¢ć«åˆ„ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć§é–‹ć„ć¦ć„ć¾ć™ć€‚ęœ€åˆć«ćć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’é–‰ć˜ć¦ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ć‚„ć‚Šē›“ć—ć¦ćć ć•ć„ć€‚", + "openWorkspace": "開恏(&&O)", + "openWorkspaceTitle": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’é–‹ć", + "save": "äæå­˜(&&S)", + "doNotSave": "äæå­˜ć—ćŖć„(&&N)", + "cancel": "ć‚­ćƒ£ćƒ³ć‚»ćƒ«", + "saveWorkspaceMessage": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ę§‹ęˆć‚’ćƒ•ć‚”ć‚¤ćƒ«ćØć—ć¦äæå­˜ć—ć¾ć™ć‹?", + "saveWorkspaceDetail": "å†åŗ¦é–‹ćäŗˆå®šćŒć‚ć‚‹ćŖć‚‰ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’äæå­˜ć—ć¾ć™ć€‚", + "saveWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’äæå­˜" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json index d8054ab9fe4..1d383dff2bb 100644 --- a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "č”Œć®é«˜ć•ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚fontSize ć«åŸŗć„ć„ć¦ lineHeight ć‚’čØˆē®—ć™ć‚‹å “åˆć«ćÆć€0 を使用します。", "letterSpacing": "ę–‡å­—ć®é–“éš”ć‚’ćƒ”ć‚Æć‚»ćƒ«å˜ä½ć§åˆ¶å¾”ć—ć¾ć™ć€‚", "lineNumbers": "č”Œē•Ŗå·ć®č”Øē¤ŗć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ä½æē”ØåÆčƒ½ćŖå€¤ćÆć€'on'态'off'ć€ćŠć‚ˆć³ 'relative' 恧恙怂'relative' ćÆē¾åœØć®ć‚«ćƒ¼ć‚½ćƒ«ä½ē½®ć‹ć‚‰ć®č”Œę•°ć‚’ē¤ŗć—ć¾ć™ć€‚", - "rulers": "åž‚ē›“ćƒ«ćƒ¼ćƒ©ćƒ¼ć‚’č”Øē¤ŗć™ć‚‹åˆ—", + "rulers": "ē­‰å¹…ćƒ•ć‚©ćƒ³ćƒˆć®ē‰¹å®šē•Ŗå·ć®å¾Œć‚ć«åž‚ē›“ćƒ«ćƒ¼ćƒ©ćƒ¼ć‚’č”Øē¤ŗć—ć¾ć™ć€‚č¤‡ę•°ć®ćƒ«ćƒ¼ćƒ©ćƒ¼ć«ćÆč¤‡ę•°ć®å€¤ć‚’ä½æē”Øć—ć¾ć™ć€‚é…åˆ—ćŒē©ŗć®å “åˆćÆćƒ«ćƒ¼ćƒ©ćƒ¼ć‚’č”Øē¤ŗć—ć¾ć›ć‚“ć€‚", "wordSeparators": "å˜čŖžć«é–¢é€£ć—ćŸćƒŠćƒ“ć‚²ćƒ¼ć‚·ćƒ§ćƒ³ć¾ćŸćÆę“ä½œć‚’å®Ÿč”Œć™ć‚‹ćØćć«ć€å˜čŖžć®åŒŗåˆ‡ć‚Šę–‡å­—ćØć—ć¦ä½æē”Øć•ć‚Œć‚‹ę–‡å­—", "tabSize": "1 ć¤ć®ć‚æćƒ–ć«ē›øå½“ć™ć‚‹ć‚¹ćƒšćƒ¼ć‚¹ć®ę•°ć€‚`editor.detectIndentation` ćŒć‚Ŗćƒ³ć®å “åˆć€ć“ć®čØ­å®šćÆćƒ•ć‚”ć‚¤ćƒ« ć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć«åŸŗć„ć„ć¦äøŠę›øćć•ć‚Œć¾ć™ć€‚", "tabSize.errorMessage": "'number' ćŒåæ…č¦ć§ć™ć€‚`editor.detectIndentation` čØ­å®šć«ć‚ˆć£ć¦å€¤ \"auto\" ćŒē½®ćę›ćˆć‚‰ć‚Œć¦ć„ć‚‹ć“ćØć«ę³Øę„ć—ć¦ćć ć•ć„ć€‚", @@ -20,8 +20,9 @@ "detectIndentation": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ććØć€ćć®ćƒ•ć‚”ć‚¤ćƒ«ć®å†…å®¹ć«åŸŗć„ć„ć¦ `editor.tabSize` と `editor.insertSpaces` ćŒę¤œå‡ŗć•ć‚Œć¾ć™ć€‚", "roundedSelection": "éøęŠžēÆ„å›²ć®č§’ć‚’äøøćć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", "scrollBeyondLastLine": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§ęœ€å¾Œć®č”Œć‚’č¶Šćˆć¦ć‚¹ć‚Æćƒ­ćƒ¼ćƒ«ć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", + "smoothScrolling": "ć‚¢ćƒ‹ćƒ”ćƒ¼ć‚·ćƒ§ćƒ³ć§ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ć‚¹ć‚Æćƒ­ćƒ¼ćƒ«ć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", "minimap.enabled": "ćƒŸćƒ‹ćƒžćƒƒćƒ—ć‚’č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", - "minimap.showSlider": "ćƒŸćƒ‹ćƒžćƒƒćƒ—ć®ć‚¹ćƒ©ć‚¤ćƒ€ćƒ¼ć‚’č‡Ŗå‹•ēš„ć«éžč”Øē¤ŗć«ć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", + "minimap.showSlider": "ćƒŸćƒ‹ćƒžćƒƒćƒ—ć®ć‚¹ćƒ©ć‚¤ćƒ€ćƒ¼ć‚’č‡Ŗå‹•ēš„ć«éžč”Øē¤ŗć«ć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ęŒ‡å®šć§ćć‚‹å€¤ćÆ 'always' と 'mouseover' 恧恙", "minimap.renderCharacters": "蔌に (ć‚«ćƒ©ćƒ¼ ćƒ–ćƒ­ćƒƒć‚Æć§ćÆćŖć) å®Ÿéš›ć®ę–‡å­—ć‚’č”Øē¤ŗć—ć¾ć™", "minimap.maxColumn": "č”Øē¤ŗć™ć‚‹ćƒŸćƒ‹ćƒžćƒƒćƒ—ć®ęœ€å¤§å¹…ć‚’ē‰¹å®šć®ę”ę•°ć«åˆ¶é™ć—ć¾ć™", "find.seedSearchStringFromSelection": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®éøęŠžć‹ć‚‰ę¤œē“¢ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆå†…ć®ę¤œē“¢ę–‡å­—åˆ—ć‚’äøŽćˆć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", @@ -86,6 +87,8 @@ "accessibilitySupport.off": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćÆć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ ćƒŖćƒ¼ćƒ€ćƒ¼å‘ć‘ć«ęœ€é©åŒ–ć•ć‚Œć¾ć›ć‚“ć€‚", "accessibilitySupport": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ ćƒŖćƒ¼ćƒ€ćƒ¼ć«ęœ€é©åŒ–ć•ć‚ŒćŸćƒ¢ćƒ¼ćƒ‰ć§å®Ÿč”Œć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "links": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒćƒŖćƒ³ć‚Æć‚’ę¤œå‡ŗć—ć¦ć‚ÆćƒŖćƒƒć‚ÆåÆčƒ½ćŖēŠ¶ę…‹ć«ć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", + "colorDecorators": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§ć‚¤ćƒ³ćƒ©ć‚¤ćƒ³ ć‚«ćƒ©ćƒ¼ ćƒ‡ć‚³ćƒ¬ćƒ¼ć‚æćƒ¼ćØč‰²ć®éøęŠžć‚’č”Øē¤ŗć™ć‚‹åæ…č¦ćŒć‚ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", + "codeActions": "ć‚³ćƒ¼ćƒ‰ ć‚¢ć‚Æć‚·ćƒ§ćƒ³ (lightbulb) ć‚’ęœ‰åŠ¹ć«ć™ć‚‹", "sideBySide": "å·®åˆ†ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒå·®åˆ†ć‚’ęØŖć«äø¦ć¹ć¦č”Øē¤ŗć™ć‚‹ć‹ć€č”Œå†…ć«č”Øē¤ŗć™ć‚‹ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", "ignoreTrimWhitespace": "å·®åˆ†ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒć€å…ˆé ­ć¾ćŸćÆęœ«å°¾ć®ē©ŗē™½ć®å¤‰ę›“ć‚’å·®åˆ†ćØć—ć¦č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "renderIndicators": "å·®åˆ†ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒčæ½åŠ /å‰Šé™¤ć•ć‚ŒćŸå¤‰ę›“ć« +/- ć‚¤ćƒ³ć‚øć‚±ćƒ¼ć‚æćƒ¼ć‚’ē¤ŗć™ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", diff --git a/i18n/jpn/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/jpn/src/vs/editor/common/view/editorColorRegistry.i18n.json index a41f64b8ff2..ccbe80f4d39 100644 --- a/i18n/jpn/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/jpn/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§ć‚Øćƒ©ćƒ¼ć‚’ē¤ŗć™ę³¢ē·šć®å‰ę™Æč‰²ć€‚", "errorBorder": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§ć‚Øćƒ©ćƒ¼ć‚’ē¤ŗć™ę³¢ē·šć®å¢ƒē•Œē·šć®č‰²ć€‚", "warningForeground": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§č­¦å‘Šć‚’ē¤ŗć™ę³¢ē·šć®å‰ę™Æč‰²ć€‚", - "warningBorder": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§č­¦å‘Šć‚’ē¤ŗć™ę³¢ē·šć®å¢ƒē•Œē·šć®č‰²ć€‚" + "warningBorder": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§č­¦å‘Šć‚’ē¤ŗć™ę³¢ē·šć®å¢ƒē•Œē·šć®č‰²ć€‚", + "infoForeground": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§ęƒ…å ±ć‚’ē¤ŗć™ę³¢ē·šć®å‰ę™Æč‰²ć€‚", + "infoBorder": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć§ęƒ…å ±ć‚’ē¤ŗć™ę³¢ē·šć®å¢ƒē•Œē·šć®č‰²ć€‚", + "overviewRulerRangeHighlight": "ēÆ„å›²ć‚’å¼·čŖæč”Øē¤ŗć™ć‚‹ćØćć®ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "overviewRuleError": "ć‚Øćƒ©ćƒ¼ć‚’ē¤ŗć™ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "overviewRuleWarning": "č­¦å‘Šć‚’ē¤ŗć™ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "overviewRuleInfo": "ęƒ…å ±ć‚’ē¤ŗć™ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 17c146860ec..4dc327d6de8 100644 --- a/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "ē½®ę›", "label.replaceAllButton": "ć™ć¹ć¦ē½®ę›", "label.toggleReplaceButton": "ē½®ę›ćƒ¢ćƒ¼ćƒ‰ć®åˆ‡ć‚Šę›æćˆ", - "title.matchesCountLimit": "ęœ€åˆć® 999 ć®ēµęžœć ć‘ć‚’å¼·čŖæč”Øē¤ŗć—ć¾ć™ćŒć€ćƒ†ć‚­ć‚¹ćƒˆå…Øä½“ć‚’ę¤œē“¢ć—ć¾ć™ć€‚", - "label.matchesLocation": "{1} 恮 {0}", + "title.matchesCountLimit": "ęœ€åˆć® {0} ä»¶ć®ēµęžœć ć‘ćŒå¼·čŖæč”Øē¤ŗć•ć‚Œć¾ć™ćŒć€ć™ć¹ć¦ć®ę¤œē“¢ę“ä½œćÆćƒ†ć‚­ć‚¹ćƒˆå…Øä½“ć§ę©Ÿčƒ½ć—ć¾ć™ć€‚", + "label.matchesLocation": "{0} / {1} ä»¶", "label.noResults": "ēµęžœćŖć—" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json index c8149938eee..93947cdf9ce 100644 --- a/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "ę¬”ć®éøęŠžé …ē›®ć‚’ę¤œē“¢", "previousSelectionMatchFindAction": "å‰ć®éøęŠžé …ē›®ć‚’ę¤œē“¢", "startReplace": "ē½®ę›", - "addSelectionToNextFindMatch": "éøęŠžć—ćŸé …ē›®ć‚’ę¬”ć®äø€č‡“é …ē›®ć«čæ½åŠ ", - "addSelectionToPreviousFindMatch": "éøć‚“ć é …ē›®ć‚’å‰ć®äø€č‡“é …ē›®ć«čæ½åŠ ć™ć‚‹", - "moveSelectionToNextFindMatch": "ęœ€å¾Œć«éøęŠžć—ćŸé …ē›®ć‚’ę¬”ć®äø€č‡“é …ē›®ć«ē§»å‹•", - "moveSelectionToPreviousFindMatch": "ęœ€å¾Œć«éøć‚“ć é …ē›®ć‚’å‰ć®äø€č‡“é …ē›®ć«ē§»å‹•ć™ć‚‹", - "selectAllOccurrencesOfFindMatch": "äø€č‡“ć™ć‚‹ć™ć¹ć¦ć®å‡ŗē¾ē®‡ę‰€ć‚’éøęŠžć—ć¾ć™", - "changeAll.label": "ć™ć¹ć¦ć®å‡ŗē¾ē®‡ę‰€ć‚’å¤‰ę›“", "showNextFindTermAction": "ę¬”ć®ę¤œē“¢čŖžå„ć‚’č”Øē¤ŗ", "showPreviousFindTermAction": "å‰ć®ę¤œē“¢čŖžå„ć‚’č”Øē¤ŗ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/jpn/src/vs/editor/contrib/format/browser/formatActions.i18n.json index fb7ac8bef60..077fe93a291 100644 --- a/i18n/jpn/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "蔌 {1} 恧 {0} å€‹ć®ę›øå¼čØ­å®šć‚’ē·Øé›†", "hint1n": "蔌 {0} と {1} 恮間恧 1 ć¤ć®ę›øå¼čØ­å®šć‚’ē·Øé›†", "hintnn": "蔌 {1} と {2} 恮間恧 {0} å€‹ć®ę›øå¼čØ­å®šć‚’ē·Øé›†", + "no.provider": "ē”³ć—čØ³ć‚ć‚Šć¾ć›ć‚“ć€‚ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚ŒćŸ '{0}'ćƒ•ć‚”ć‚¤ćƒ«ē”Øć®ćƒ•ć‚©ćƒ¼ćƒžćƒƒć‚æćƒ¼ćŒå­˜åœØć—ć¾ć›ć‚“ć€‚", "formatDocument.label": "ćƒ‰ć‚­ćƒ„ćƒ”ćƒ³ćƒˆć®ćƒ•ć‚©ćƒ¼ćƒžćƒƒćƒˆ", "formatSelection.label": "éøęŠžēÆ„å›²ć®ćƒ•ć‚©ćƒ¼ćƒžćƒƒćƒˆ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/jpn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 4fbcbda9f94..53ea71a9d4e 100644 --- a/i18n/jpn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "å‰ć®ć‚Øćƒ©ćƒ¼ć¾ćŸćÆč­¦å‘Šćøē§»å‹•", "editorMarkerNavigationError": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼ ćƒŠćƒ“ć‚²ćƒ¼ć‚·ćƒ§ćƒ³ ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆć®ć‚Øćƒ©ćƒ¼ć®č‰²ć€‚", "editorMarkerNavigationWarning": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼ ćƒŠćƒ“ć‚²ćƒ¼ć‚·ćƒ§ćƒ³ ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆć®č­¦å‘Šć®č‰²ć€‚", + "editorMarkerNavigationInfo": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼ ćƒŠćƒ“ć‚²ćƒ¼ć‚·ćƒ§ćƒ³ ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆć®ęƒ…å ±ć®č‰²ć€‚", "editorMarkerNavigationBackground": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼ ćƒŠćƒ“ć‚²ćƒ¼ć‚·ćƒ§ćƒ³ ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆć®čƒŒę™Æć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 47f31c8a681..0df6dca88c6 100644 --- a/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "ć‚«ćƒ¼ć‚½ćƒ«ć‚’äøŠć«ęŒæå…„", "mutlicursor.insertBelow": "ć‚«ćƒ¼ć‚½ćƒ«ć‚’äø‹ć«ęŒæå…„", - "mutlicursor.insertAtEndOfEachLineSelected": "ć‚«ćƒ¼ć‚½ćƒ«ć‚’č”Œęœ«ć«ęŒæå…„" + "mutlicursor.insertAtEndOfEachLineSelected": "ć‚«ćƒ¼ć‚½ćƒ«ć‚’č”Œęœ«ć«ęŒæå…„", + "addSelectionToNextFindMatch": "éøęŠžć—ćŸé …ē›®ć‚’ę¬”ć®äø€č‡“é …ē›®ć«čæ½åŠ ", + "addSelectionToPreviousFindMatch": "éøć‚“ć é …ē›®ć‚’å‰ć®äø€č‡“é …ē›®ć«čæ½åŠ ć™ć‚‹", + "moveSelectionToNextFindMatch": "ęœ€å¾Œć«éøęŠžć—ćŸé …ē›®ć‚’ę¬”ć®äø€č‡“é …ē›®ć«ē§»å‹•", + "moveSelectionToPreviousFindMatch": "ęœ€å¾Œć«éøć‚“ć é …ē›®ć‚’å‰ć®äø€č‡“é …ē›®ć«ē§»å‹•ć™ć‚‹", + "selectAllOccurrencesOfFindMatch": "äø€č‡“ć™ć‚‹ć™ć¹ć¦ć®å‡ŗē¾ē®‡ę‰€ć‚’éøęŠžć—ć¾ć™", + "changeAll.label": "ć™ć¹ć¦ć®å‡ŗē¾ē®‡ę‰€ć‚’å¤‰ę›“" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/jpn/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..e6139bff349 --- /dev/null +++ b/i18n/jpn/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "閉恘悋" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/jpn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index e091fdcbaec..8eac21c6979 100644 --- a/i18n/jpn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "å¤‰ę•°ć®čŖ­ćæå–ć‚ŠćŖć©čŖ­ćæå–ć‚Šć‚¢ć‚Æć‚»ć‚¹äø­ć®ć‚·ćƒ³ćƒœćƒ«ć®čƒŒę™Æč‰²ć€‚", - "wordHighlightStrong": "å¤‰ę•°ćøć®ę›øćč¾¼ćæćŖć©ę›øćč¾¼ćæć‚¢ć‚Æć‚»ć‚¹äø­ć®ć‚·ćƒ³ćƒœćƒ«ć®čƒŒę™Æč‰²ć€‚" + "wordHighlightStrong": "å¤‰ę•°ćøć®ę›øćč¾¼ćæćŖć©ę›øćč¾¼ćæć‚¢ć‚Æć‚»ć‚¹äø­ć®ć‚·ćƒ³ćƒœćƒ«ć®čƒŒę™Æč‰²ć€‚", + "overviewRulerWordHighlightForeground": "ć‚·ćƒ³ćƒœćƒ«ć‚’å¼·čŖæč”Øē¤ŗć™ć‚‹ćØćć®ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "overviewRulerWordHighlightStrongForeground": "ę›øćč¾¼ćæć‚¢ć‚Æć‚»ć‚¹ ć‚·ćƒ³ćƒœćƒ«ć‚’å¼·čŖæč”Øē¤ŗć™ć‚‹ćØćć®ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "wordHighlight.next.label": "ę¬”ć®ć‚·ćƒ³ćƒœćƒ« ćƒć‚¤ćƒ©ć‚¤ćƒˆć«ē§»å‹•", + "wordHighlight.previous.label": "å‰ć®ć‚·ćƒ³ćƒœćƒ« ćƒć‚¤ćƒ©ć‚¤ćƒˆć«ē§»å‹•" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/jpn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 33d151e7f9b..981e3bb87da 100644 --- a/i18n/jpn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/jpn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "ć“ć®ć‚³ćƒžćƒ³ćƒ‰ćŒå±žć™ć‚‹ć‚°ćƒ«ćƒ¼ćƒ—", "vscode.extension.contributes.menus": "ćƒ”ćƒ‹ćƒ„ćƒ¼é …ē›®ć‚’ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć«ęä¾›ć—ć¾ć™", "menus.commandPalette": "ć‚³ćƒžćƒ³ćƒ‰ ćƒ‘ćƒ¬ćƒƒćƒˆ", + "menus.touchBar": "Touch Bar (macOS のみ)", "menus.editorTitle": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚æć‚¤ćƒˆćƒ« ćƒ”ćƒ‹ćƒ„ćƒ¼", "menus.editorContext": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆ ćƒ”ćƒ‹ćƒ„ćƒ¼", "menus.explorerContext": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć®ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆ ćƒ”ćƒ‹ćƒ„ćƒ¼", "menus.editorTabContext": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚æćƒ–ć®ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆ ćƒ”ćƒ‹ćƒ„ćƒ¼", "menus.debugCallstackContext": "ćƒ‡ćƒćƒƒć‚°ć®å‘¼ć³å‡ŗć—å±„ę­“ć®ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆ ćƒ”ćƒ‹ćƒ„ćƒ¼", "menus.scmTitle": "ć‚½ćƒ¼ć‚¹ē®”ē†ć®ć‚æć‚¤ćƒˆćƒ« ćƒ”ćƒ‹ćƒ„ćƒ¼", + "menus.scmSourceControl": "ć‚½ćƒ¼ć‚¹ē®”ē†ćƒ”ćƒ‹ćƒ„ćƒ¼", "menus.resourceGroupContext": "ć‚½ćƒ¼ć‚¹ē®”ē†ćƒŖć‚½ćƒ¼ć‚¹ ć‚°ćƒ«ćƒ¼ćƒ—ć®ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆ ćƒ”ćƒ‹ćƒ„ćƒ¼", "menus.resourceStateContext": "ć‚½ćƒ¼ć‚¹ē®”ē†ćƒŖć‚½ćƒ¼ć‚¹ēŠ¶ę…‹ć®ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆ ćƒ”ćƒ‹ćƒ„ćƒ¼", "view.viewTitle": "ęä¾›ć•ć‚ŒćŸćƒ“ćƒ„ćƒ¼ć®ć‚æć‚¤ćƒˆćƒ« ćƒ”ćƒ‹ćƒ„ćƒ¼", diff --git a/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json b/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json index 6cd2c2e4b34..1545142948e 100644 --- a/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "`--goto` ćƒ¢ćƒ¼ćƒ‰ć®å¼•ę•°ćÆ `FILE(:LINE(:CHARACTER))` ć®å½¢å¼ć«ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", - "diff": "å·®åˆ†ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ćć¾ć™ć€‚å¼•ę•°ćØć—ć¦ 2 ć¤ć®ćƒ•ć‚”ć‚¤ćƒ« ćƒ‘ć‚¹ć‚’ęø”ć™åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", - "goto": "ęŒ‡å®šć®č”ŒćØę–‡å­—ć®ä½ē½®ć§ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ćć¾ć™(ćƒ‘ć‚¹ć« :line[:character] ć‚’čæ½åŠ ć—ć¦ćć ć•ć„)怂", + "diff": "2 ć¤ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’ęÆ”č¼ƒć—ć¾ć™ć€‚", + "add": "ęœ€å¾Œć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–ć ć£ćŸć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć«ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’čæ½åŠ ć—ć¾ć™ć€‚", + "goto": "ęŒ‡å®šć—ćŸč”ŒćØę–‡å­—ć®ä½ē½®ć«ć‚ć‚‹ćƒ‘ć‚¹ć§ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ćć¾ć™ć€‚", "locale": "ä½æē”Øć™ć‚‹å›½ćØåœ°åŸŸ (例:en-US 悄 zh-TW など)怂", "newWindow": "ꖰ恗恄 Code ć®ć‚¤ćƒ³ć‚¹ć‚æćƒ³ć‚¹ć‚’å¼·åˆ¶ć—ć¾ć™ć€‚", "performance": "'Developer: Startup Performance' ć‚³ćƒžćƒ³ćƒ‰ć‚’ęœ‰åŠ¹ć«ć—ć¦é–‹å§‹ć—ć¾ć™ć€‚", @@ -14,7 +15,7 @@ "reuseWindow": "ęœ€å¾Œć®ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć«ćƒ•ć‚”ć‚¤ćƒ«ć¾ćŸćÆćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’å¼·åˆ¶ēš„ć«é–‹ćć¾ć™ć€‚", "userDataDir": "ćƒ¦ćƒ¼ć‚¶ćƒ¼ ćƒ‡ćƒ¼ć‚æć‚’äæęŒć™ć‚‹ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć‚’ęŒ‡å®šć—ć¾ć™ć€‚ćƒ«ćƒ¼ćƒˆć§å®Ÿč”Œć—ć¦ć„ć‚‹å “åˆć«å½¹ē«‹ć”ć¾ć™ć€‚", "verbose": "č©³ē“°å‡ŗåŠ›ć‚’č”Øē¤ŗć—ć¾ć™ (--wait を含みます)怂", - "wait": "ē¾åœØć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ćŒé–‰ć˜ć‚‹ć¾ć§å¾…ę©Ÿć—ć¾ć™ć€‚", + "wait": "ē¾åœØć®ćƒ•ć‚”ć‚¤ćƒ«ćŒé–‰ć˜ć‚‰ć‚Œć‚‹ć¾ć§å¾…ę©Ÿć—ć¾ć™ć€‚", "extensionHomePath": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ«ćƒ¼ćƒˆ ćƒ‘ć‚¹ć‚’čØ­å®šć—ć¾ć™ć€‚", "listExtensions": "ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć‚‹ę‹”å¼µę©Ÿčƒ½ć‚’äø€č¦§č”Øē¤ŗć—ć¾ć™ć€‚", "showVersions": "--list-extension ćØä½æē”Øć™ć‚‹ćØćć€ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć‚‹ę‹”å¼µę©Ÿčƒ½ć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’č”Øē¤ŗć—ć¾ć™ć€‚", diff --git a/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 2753d38a6d2..c6bfbf6288e 100644 --- a/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "ę­£ć—ććŖć„ę‹”å¼µę©Ÿčƒ½: package.json は JSON ćƒ•ć‚”ć‚¤ćƒ«ć§ćÆć‚ć‚Šć¾ć›ć‚“ć€‚", - "restartCode": "{0} ć‚’å†ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć™ć‚‹å‰ć«ć€Code ć‚’å†čµ·å‹•ć—ć¦ćć ć•ć„ć€‚", - "installDependeciesConfirmation": "'{0}' ć‚’ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć™ć‚‹ćØć€ćć®ä¾å­˜é–¢äæ‚ć‚‚ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¾ć™ć€‚ē¶šč”Œć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?", - "install": "はい", - "doNotInstall": "恄恄恈", + "restartCodeLocal": "{0} ć‚’å†ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć™ć‚‹å‰ć«ć€Code ć‚’å†čµ·å‹•ć—ć¦ćć ć•ć„ć€‚", + "restartCodeGallery": "å†ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć™ć‚‹å‰ć« Code ć‚’å†čµ·å‹•ć—ć¦ćć ć•ć„ć€‚", "uninstallDependeciesConfirmation": "'{0}' ć®ćæć‚’ć‚¢ćƒ³ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¾ć™ć‹ć€ć¾ćŸćÆä¾å­˜é–¢äæ‚ć‚‚ć‚¢ćƒ³ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¾ć™ć‹?", "uninstallOnly": "限定", "uninstallAll": "すべて", diff --git a/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 38e5bf8d7a1..ebcd92b7c61 100644 --- a/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "VS Code ę‹”å¼µę©Ÿčƒ½ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆć€‚", "vscode.extension.activationEvents.onLanguage": "ęŒ‡å®šć•ć‚ŒćŸčØ€čŖžć‚’č§£ę±ŗć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«ćŒé–‹ć‹ć‚Œć‚‹ćŸć³ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆćŒē™ŗč”Œć•ć‚Œć¾ć™ć€‚", "vscode.extension.activationEvents.onCommand": "ęŒ‡å®šć—ćŸć‚³ćƒžćƒ³ćƒ‰ćŒå‘¼ć³å‡ŗć•ć‚Œć‚‹ćŸć³ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆćŒē™ŗč”Œć•ć‚Œć¾ć™ć€‚", - "vscode.extension.activationEvents.onDebug": "ęŒ‡å®šć•ć‚ŒćŸć‚æć‚¤ćƒ—ć®ćƒ‡ćƒćƒƒć‚° ć‚»ćƒƒć‚·ćƒ§ćƒ³ćŒé–‹å§‹ć•ć‚Œć‚‹ćŸć³ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆćŒē™ŗč”Œć•ć‚Œć¾ć™ć€‚", + "vscode.extension.activationEvents.onDebug": "ćƒ‡ćƒćƒƒć‚°ć®é–‹å§‹ć¾ćŸćÆćƒ‡ćƒćƒƒć‚°ę§‹ęˆćŒć‚»ćƒƒćƒˆć‚¢ćƒƒćƒ—ć•ć‚Œć‚‹ćŸć³ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆćŒē™ŗč”Œć•ć‚Œć¾ć™ć€‚", "vscode.extension.activationEvents.workspaceContains": "ęŒ‡å®šć—ćŸ glob ćƒ‘ć‚æćƒ¼ćƒ³ć«äø€č‡“ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«ć‚’å°‘ćŖććØć‚‚ 1 ć¤ä»„äøŠå«ć‚€ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ććŸć³ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆćŒē™ŗč”Œć•ć‚Œć¾ć™ć€‚", "vscode.extension.activationEvents.onView": "ęŒ‡å®šć—ćŸćƒ“ćƒ„ćƒ¼ć‚’å±•é–‹ć™ć‚‹ćŸć³ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆćŒē™ŗč”Œć•ć‚Œć¾ć™ć€‚", "vscode.extension.activationEvents.star": "VS Code čµ·å‹•ę™‚ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆć‚’ē™ŗč”Œć—ć¾ć™ć€‚å„Ŗć‚ŒćŸć‚Øćƒ³ćƒ‰ćƒ¦ćƒ¼ć‚¶ćƒ¼ ć‚Øć‚Æć‚¹ćƒšćƒŖć‚Øćƒ³ć‚¹ć‚’ē¢ŗäæć™ć‚‹ćŸć‚ć«ć€ä»–ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚¤ćƒ™ćƒ³ćƒˆć®ēµ„ćæåˆć‚ć›ć§ćÆęœ›ć‚€å‹•ä½œć«ćŖć‚‰ćŖć„ćØćć®ćæä½æē”Øć—ć¦ćć ć•ć„ć€‚", diff --git a/i18n/jpn/src/vs/platform/markers/common/problemMatcher.i18n.json b/i18n/jpn/src/vs/platform/markers/common/problemMatcher.i18n.json index b3cbfeb9bda..f06c6d391bc 100644 --- a/i18n/jpn/src/vs/platform/markers/common/problemMatcher.i18n.json +++ b/i18n/jpn/src/vs/platform/markers/common/problemMatcher.i18n.json @@ -66,5 +66,5 @@ "jshint-stylish": "JSHint ć®å•é”Œ (stylish)", "eslint-compact": "ESLint ć®å•é”Œ (compact)", "eslint-stylish": "ESLint ć®å•é”Œ (stylish)", - "go": "å•é”Œć«ē§»å‹•ć™ć‚‹" + "go": "Go ć®å•é”Œ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/jpn/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..5a5b9134955 --- /dev/null +++ b/i18n/jpn/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "ę‹”å¼µę©Ÿčƒ½ć§ćƒ†ćƒ¼ćƒžčØ­å®šć®åÆčƒ½ćŖé…č‰²ć‚’ęä¾›ć—ć¾ć™", + "contributes.color.id": "ćƒ†ćƒ¼ćƒžčØ­å®šåÆčƒ½ćŖé…č‰²ć®č­˜åˆ„å­", + "contributes.color.id.format": "識刄子は aa[.bb]* ć®å½¢å¼ć«ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", + "contributes.color.description": "ćƒ†ćƒ¼ćƒžčØ­å®šåÆčƒ½ćŖé…č‰²ć®čŖ¬ę˜Ž", + "contributes.defaults.light": "light ćƒ†ćƒ¼ćƒžć®ę—¢å®šć®é…č‰²ć€‚é…č‰²ć®å€¤ćÆ 16 進数(#RRGGBB[AA])Ā ć€ć¾ćŸćÆ ę—¢å®šć§ęä¾›ć•ć‚Œć¦ć„ć‚‹ćƒ†ćƒ¼ćƒžčØ­å®šåÆčƒ½ćŖé…č‰²ć®č­˜åˆ„å­ć®ę—¢å®šå€¤ć®ć„ćšć‚Œć‹ć€‚", + "contributes.defaults.dark": "dark ćƒ†ćƒ¼ćƒžć®ę—¢å®šć®é…č‰²ć€‚é…č‰²ć®å€¤ćÆ 16 進数(#RRGGBB[AA])Ā ć€ć¾ćŸćÆ ę—¢å®šć§ęä¾›ć•ć‚Œć¦ć„ć‚‹ćƒ†ćƒ¼ćƒžčØ­å®šåÆčƒ½ćŖé…č‰²ć®č­˜åˆ„å­ć®ę—¢å®šå€¤ć®ć„ćšć‚Œć‹ć€‚", + "contributes.defaults.highContrast": "high contrastĀ ćƒ†ćƒ¼ćƒžć®ę—¢å®šć®é…č‰²ć€‚é…č‰²ć®å€¤ćÆ 16 進数(#RRGGBB[AA])Ā ć€ć¾ćŸćÆ ę—¢å®šć§ęä¾›ć•ć‚Œć¦ć„ć‚‹ćƒ†ćƒ¼ćƒžčØ­å®šåÆčƒ½ćŖé…č‰²ć®č­˜åˆ„å­ć®ę—¢å®šå€¤ć®ć„ćšć‚Œć‹ć€‚", + "invalid.colorConfiguration": "'configuration.colors' ćÆé…åˆ—ć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", + "invalid.default.colorType": "{0} は 16 進数(#RRGGBB[AA] または #RGB[A])Ā ć€ć¾ćŸćÆ ę—¢å®šć§ęä¾›ć•ć‚Œć¦ć„ć‚‹ćƒ†ćƒ¼ćƒžčØ­å®šåÆčƒ½ćŖé…č‰²ć®č­˜åˆ„å­ć®ę—¢å®šå€¤ć®ć„ćšć‚Œć‹ć§ćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“ć€‚", + "invalid.id": "'configuration.colors.id' ć‚’å®šē¾©ć—ć¦ćć ć•ć„ć€‚ē©ŗć«ćÆć§ćć¾ć›ć‚“ć€‚", + "invalid.id.format": "'configuration.colors.id' は word[.word]* ć®å½¢å¼ć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", + "invalid.description": "'configuration.colors.description' ć‚’å®šē¾©ć—ć¦ćć ć•ć„ć€‚ē©ŗć«ćÆć§ćć¾ć›ć‚“ć€‚", + "invalid.defaults": "'configuration.colors.defaults' ćÆå®šē¾©ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚'light' 恋 'dark'态'highContrast' ć‚’å«ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json index 272213197af..24c492550e3 100644 --- a/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/jpn/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "ē„”åŠ¹ćŖč‰²å½¢å¼ć§ć™ć€‚ #RGB态#RGBA态#RRGGBB态#RRGGBBAA ć®ć„ćšć‚Œć‹ć‚’ä½æē”Øć—ć¦ćć ć•ć„", "schema.colors": "ćƒÆćƒ¼ć‚Æćƒ™ćƒ³ćƒć§ä½æē”Øć™ć‚‹č‰²ć€‚", "foreground": "å…Øä½“ć®å‰ę™Æč‰²ć€‚ć“ć®č‰²ćÆć€ć‚³ćƒ³ćƒćƒ¼ćƒćƒ³ćƒˆć«ć‚ˆć£ć¦ć‚Ŗćƒ¼ćƒćƒ¼ćƒ©ć‚¤ćƒ‰ć•ć‚Œć¦ć„ćŖć„å “åˆć«ć®ćæä½æē”Øć•ć‚Œć¾ć™ć€‚", "errorForeground": "ć‚Øćƒ©ćƒ¼ ćƒ”ćƒƒć‚»ćƒ¼ć‚øå…Øä½“ć®å‰ę™Æč‰²ć€‚ć“ć®č‰²ćÆć€ć‚³ćƒ³ćƒćƒ¼ćƒćƒ³ćƒˆć«ć‚ˆć£ć¦äøŠę›øćć•ć‚Œć¦ć„ćŖć„å “åˆć«ć®ćæä½æē”Øć•ć‚Œć¾ć™ć€‚", @@ -45,6 +44,7 @@ "listHoverForeground": "ćƒžć‚¦ć‚¹ę“ä½œć§é …ē›®ć‚’ćƒ›ćƒćƒ¼ć™ć‚‹ćØćć®ćƒ„ćƒŖćƒ¼ćƒŖć‚¹ćƒˆå‰ę™Æć€‚", "listDropBackground": "ćƒžć‚¦ć‚¹ę“ä½œć§é …ē›®ć‚’ē§»å‹•ć™ć‚‹ćØćć®ćƒ„ćƒŖćƒ¼ćƒŖć‚¹ćƒˆ ćƒ‰ćƒ©ćƒƒć‚° ć‚¢ćƒ³ćƒ‰ ćƒ‰ćƒ­ćƒƒćƒ—ć®čƒŒę™Æć€‚", "highlight": "ćƒ„ćƒŖćƒ¼ćƒŖć‚¹ćƒˆå†…ć‚’ę¤œē“¢ć—ć¦ć„ć‚‹ćØćć€äø€č‡“ć—ćŸå¼·čŖæć®ćƒ„ćƒŖćƒ¼ćƒŖć‚¹ćƒˆå‰ę™Æč‰²ć€‚", + "invalidItemForeground": "ē„”åŠ¹ćŖé …ē›®ć®ćƒ„ćƒŖćƒ¼ćƒŖć‚¹ćƒˆć®å‰ę™Æč‰²ć€‚ćŸćØćˆć°ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć®ęœŖč§£ę±ŗćŖćƒ«ćƒ¼ćƒˆć€‚", "pickerGroupForeground": "ćƒ©ćƒ™ćƒ«ć‚’ć‚°ćƒ«ćƒ¼ćƒ—åŒ–ć™ć‚‹ćŸć‚ć®ć‚ÆćƒŖćƒƒć‚ÆéøęŠžć®č‰²ć€‚", "pickerGroupBorder": "å¢ƒē•Œē·šć‚’ć‚°ćƒ«ćƒ¼ćƒ—åŒ–ć™ć‚‹ćŸć‚ć®ć‚Æć‚¤ćƒƒć‚ÆéøęŠžć®č‰²ć€‚", "buttonForeground": "ćƒœć‚æćƒ³ć®å‰ę™Æč‰²ć€‚", @@ -85,5 +85,7 @@ "mergeBorder": "č”Œå†…ćƒžćƒ¼ć‚øē«¶åˆć®ćƒ˜ćƒƒćƒ€ćƒ¼ćØć‚¹ćƒ—ćƒŖćƒƒć‚æćƒ¼ć®å¢ƒē•Œē·šć®č‰²ć€‚", "overviewRulerCurrentContentForeground": "č”Œå†…ćƒžćƒ¼ć‚øē«¶åˆć®ē¾åœØć®ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼å‰ę™Æč‰²ć€‚", "overviewRulerIncomingContentForeground": "č”Œå†…ćƒžćƒ¼ć‚øē«¶åˆć®å…„åŠ›å“ć®ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼å‰ę™Æč‰²ć€‚", - "overviewRulerCommonContentForeground": "č”Œå†…ćƒžćƒ¼ć‚øē«¶åˆć®å…±é€šć®ē„–å…ˆę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼å‰ę™Æč‰²ć€‚" + "overviewRulerCommonContentForeground": "č”Œå†…ćƒžćƒ¼ć‚øē«¶åˆć®å…±é€šć®ē„–å…ˆę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼å‰ę™Æč‰²ć€‚", + "overviewRulerFindMatchForeground": "äø€č‡“é …ē›®ć‚’ē¤ŗć™ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "overviewRulerSelectionHighlightForeground": "éøęŠžåÆ¾č±”ć‚’å¼·čŖæč”Øē¤ŗć™ć‚‹ćØćć®ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/jpn/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..fad7eabca20 --- /dev/null +++ b/i18n/jpn/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "ć‚³ćƒ¼ćƒ‰ ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹", + "untitledWorkspace": "未設定 (ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹)", + "workspaceNameVerbose": "{0} (ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹)", + "workspaceName": "{0} (ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹)" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/jpn/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..c17b073b1d3 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "ćƒ“ćƒ„ćƒ¼ćÆé…åˆ—ć«ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", + "requirestring": " `{0}` ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćÆåæ…é ˆć§ć€`string` åž‹ć§ćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“", + "optstring": "`{0}` ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćÆēœē•„ć™ć‚‹ć‹ć€`string` åž‹ć«ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", + "vscode.extension.contributes.view.id": "ćƒ“ćƒ„ćƒ¼ć®č­˜åˆ„å­ć€‚`vscode.window.registerTreeDataProviderForView` API ć‚’ä»‹ć—ć¦ćƒ‡ćƒ¼ć‚æ ćƒ—ćƒ­ćƒć‚¤ćƒ€ćƒ¼ć‚’ē™»éŒ²ć™ć‚‹ć«ćÆć€ć“ć‚Œć‚’ä½æē”Øć—ć¾ć™ć€‚ć¾ćŸć€`onView:${id}` ć‚¤ćƒ™ćƒ³ćƒˆć‚’ `activationEvents` ć«ē™»éŒ²ć™ć‚‹ć“ćØć«ć‚ˆć£ć¦ć€ę‹”å¼µę©Ÿčƒ½ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć‚’ćƒˆćƒŖć‚¬ćƒ¼ć™ć‚‹ćŸć‚ć«ć‚‚ä½æē”Øć§ćć¾ć™ć€‚", + "vscode.extension.contributes.view.name": "ćƒ“ćƒ„ćƒ¼ć®åˆ¤čŖ­ć§ćć‚‹åå‰ć€‚č”Øē¤ŗć•ć‚Œć¾ć™", + "vscode.extension.contributes.view.when": "ć“ć®ćƒ“ćƒ„ćƒ¼ć‚’č”Øē¤ŗć™ć‚‹ćŸć‚ć«ęŗ€ćŸć™åæ…č¦ćŒć‚ć‚‹ę”ä»¶", + "vscode.extension.contributes.views": "ćƒ“ćƒ„ćƒ¼ć‚’ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć«ęä¾›ć—ć¾ć™", + "views.explorer": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ ćƒ“ćƒ„ćƒ¼", + "views.debug": "惇惐惃悰 ćƒ“ćƒ„ćƒ¼", + "locationId.invalid": "`{0}` ćÆęœ‰åŠ¹ćŖćƒ“ćƒ„ćƒ¼ć®å “ę‰€ć§ćÆć‚ć‚Šć¾ć›ć‚“", + "duplicateView1": "location `{1}` で同じ id `{0}` ć‚’ä½æē”Øć™ć‚‹č¤‡ę•°ć®ćƒ“ćƒ„ćƒ¼ć‚’ē™»éŒ²ć§ćć¾ć›ć‚“", + "duplicateView2": "location `{1}` 恧 id `{0}` ć®ćƒ“ćƒ„ćƒ¼ćŒę—¢ć«ē™»éŒ²ć•ć‚Œć¦ć„ć¾ć™" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/jpn/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..5d369543a9a --- /dev/null +++ b/i18n/jpn/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "ę‹”å¼µę©Ÿčƒ½ `{1}` ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć«å¤±ę•—ć—ć¾ć—ćŸć€‚ē†ē”±: ä¾å­˜é–¢äæ‚ `{0}` ćŒäøę˜Žć§ć™ć€‚", + "failedDep1": "ę‹”å¼µę©Ÿčƒ½ `{1}` ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć«å¤±ę•—ć—ć¾ć—ćŸć€‚ē†ē”±: ä¾å­˜é–¢äæ‚ `{0}` ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć«å¤±ę•—ć—ć¾ć—ćŸć€‚", + "failedDep2": "ę‹”å¼µę©Ÿčƒ½ `{0}` ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć«å¤±ę•—ć—ć¾ć—ćŸć€‚ē†ē”±: ä¾å­˜é–¢äæ‚ć®ćƒ¬ćƒ™ćƒ«ćŒ 10 ć‚’č¶…ćˆć¦ć„ć¾ć™ (ä¾å­˜é–¢äæ‚ć®ćƒ«ćƒ¼ćƒ—ć®åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™)怂", + "activationError": "ę‹”å¼µę©Ÿčƒ½ `{0}` ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć«å¤±ę•—ć—ć¾ć—ćŸ: {1}怂" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 779f48926f3..60ed1228f04 100644 --- a/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,23 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć...", "openFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć...", "openFileFolder": "開恏...", - "reload": "å†čŖ­ćæč¾¼ćæ(&&R)", - "cancel": "ć‚­ćƒ£ćƒ³ć‚»ćƒ«", - "select": "éøęŠž(&&S)", - "selectWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’éøęŠž", - "addSupported": "č¤‡ę•°ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ćć«ćÆć€ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®å†čŖ­ćæč¾¼ćæćŒåæ…č¦ć§ć™ć€‚", "addFolderToWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć«ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’čæ½åŠ ...", "add": "追加(&&A)", "addFolderToWorkspaceTitle": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć«ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’čæ½åŠ ", + "globalRemoveFolderFromWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‹ć‚‰ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’å‰Šé™¤...", "removeFolderFromWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‹ć‚‰ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’å‰Šé™¤", + "openFolderSettings": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®šć‚’é–‹ć", "saveWorkspaceAsAction": "åå‰ć‚’ä»˜ć‘ć¦ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’äæå­˜...", - "saveEmptyWorkspaceNotSupported": "ęœ€åˆć«äæå­˜ć™ć‚‹ćŸć‚ć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’é–‹ć„ć¦ćć ć•ć„ć€‚", - "saveNotSupported": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’äæå­˜ć™ć‚‹ć«ćÆć€ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®å†čŖ­ćæč¾¼ćæćŒåæ…č¦ć§ć™ć€‚", "save": "äæå­˜(&&S)", "saveWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’äæå­˜", "openWorkspaceAction": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’é–‹ć...", - "newWorkspace": "ę–°ć—ć„ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹...", - "openWorkspaceConfigFile": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ę§‹ęˆćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć" + "openWorkspaceConfigFile": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ę§‹ęˆćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", + "openFolderAsWorkspaceInNewWindow": "ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć§ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ćØć—ć¦ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć", + "workspaceFolderPickerPlaceholder": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’éøęŠž" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 7a03a21eed0..8cee18d4c69 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć‹ć‚‰å‰Šé™¤", - "keepInActivityBar": "ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć«äæęŒ", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć‹ć‚‰éžč”Øē¤ŗ", + "keepInActivityBar": "ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć«äæęŒ", "additionalViews": "ćć®ä»–ć®ćƒ“ćƒ„ćƒ¼", "numberBadge": "{0} ({1})", "manageExtension": "ę‹”å¼µę©Ÿčƒ½ć‚’ē®”ē†", diff --git a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index b9c158c0786..85e7c1f4a9c 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć‚’éžč”Øē¤ŗć«ć™ć‚‹", - "activityBarAriaLabel": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖćƒ“ćƒ„ćƒ¼ ć‚¹ć‚¤ćƒƒćƒćƒ£ćƒ¼", "globalActions": "ć‚°ćƒ­ćƒ¼ćƒćƒ«ę“ä½œ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..23e9cfae128 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖćƒ“ćƒ„ćƒ¼ ć‚¹ć‚¤ćƒƒćƒćƒ£ćƒ¼" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..eb0a5534713 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "ćć®ä»–ć®ćƒ“ćƒ„ćƒ¼", + "numberBadge": "{0} ({1})", + "manageExtension": "ę‹”å¼µę©Ÿčƒ½ć‚’ē®”ē†", + "titleKeybinding": "{0} ({1})", + "hide": "éžč”Øē¤ŗ", + "keep": "äæęŒ", + "toggle": "ćƒ“ćƒ„ćƒ¼ć®ćƒ”ćƒ³ē•™ć‚ć®åˆ‡ć‚Šę›æćˆ" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 198f105b057..86cc5cdfa14 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "2 ē•Ŗē›®ć®ć‚°ćƒ«ćƒ¼ćƒ—ć§ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’č”Øē¤ŗć™ć‚‹", "groupThreePicker": "3 ē•Ŗē›®ć®ć‚°ćƒ«ćƒ¼ćƒ—ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’č”Øē¤ŗć™ć‚‹", "allEditorsPicker": "é–‹ć„ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ć™ć¹ć¦č”Øē¤ŗć™ć‚‹", - "view": "蔨示" + "view": "蔨示", + "file": "ćƒ•ć‚”ć‚¤ćƒ«" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index d1ccb18830d..5c802777acf 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "ć‚°ćƒ«ćƒ¼ćƒ—å†…ć§å‰ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ć", "navigateNext": "欔に進む", "navigatePrevious": "å‰ć«ęˆ»ć‚‹", + "navigateLast": "ęˆ»ć‚‹", "reopenClosedEditor": "é–‰ć˜ćŸć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’å†åŗ¦é–‹ć", "clearRecentFiles": "ęœ€čæ‘é–‹ć„ćŸé …ē›®ć‚’ć‚ÆćƒŖć‚¢", "showEditorsInFirstGroup": "ęœ€åˆć®ć‚°ćƒ«ćƒ¼ćƒ—ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’č”Øē¤ŗć™ć‚‹", diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 0154710e818..9a2136e7640 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "ć‚æćƒ–ć«ć‚ˆć‚‹ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć®ē§»å‹•", - "screenReaderDetected": "ć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ ćƒŖćƒ¼ćƒ€ćƒ¼ć‚’ę¤œå‡ŗć—ć¾ć—ćŸ", + "screenReaderDetected": "ć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ ćƒŖćƒ¼ćƒ€ćƒ¼ć«ęœ€é©åŒ–", "screenReaderDetectedExtra": "ć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ ćƒŖćƒ¼ćƒ€ćƒ¼ć‚’ä½æē”Øć—ćŖć„å “åˆć€`editor.accessibilitySupport` 悒 \"off\" ć«ć—ć¦ćć ć•ć„ć€‚", "disableTabMode": "ć‚¢ć‚Æć‚»ć‚·ćƒ“ćƒŖćƒ†ć‚£ ćƒ¢ćƒ¼ćƒ‰ć‚’ē„”åŠ¹ć«ć™ć‚‹", "gotoLine": "č”Œćøē§»å‹•", @@ -47,5 +47,11 @@ "reopenWithEncoding": "ć‚Øćƒ³ć‚³ćƒ¼ćƒ‰ä»˜ćć§å†åŗ¦é–‹ć", "guessedEncoding": "ć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć‹ć‚‰ęŽØęø¬", "pickEncodingForReopen": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’å†åŗ¦é–‹ććØćć®ćƒ•ć‚”ć‚¤ćƒ«ć®ć‚Øćƒ³ć‚³ćƒ¼ćƒ‰ć®éøęŠž", - "pickEncodingForSave": "äæå­˜ę™‚ć®ćƒ•ć‚”ć‚¤ćƒ«ć®ć‚Øćƒ³ć‚³ćƒ¼ćƒ‰ć®éøęŠž" + "pickEncodingForSave": "äæå­˜ę™‚ć®ćƒ•ć‚”ć‚¤ćƒ«ć®ć‚Øćƒ³ć‚³ćƒ¼ćƒ‰ć®éøęŠž", + "screenReaderDetectedExplanation.title": "ć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ ćƒŖćƒ¼ćƒ€ćƒ¼ć«ęœ€é©åŒ–", + "screenReaderDetectedExplanation.question": "VS Codeć®ę“ä½œć«ć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ćƒŖćƒ¼ćƒ€ćƒ¼ć‚’ä½æē”Øć—ć¦ć„ć¾ć™ć‹?", + "screenReaderDetectedExplanation.answerYes": "はい", + "screenReaderDetectedExplanation.answerNo": "恄恄恈", + "screenReaderDetectedExplanation.body1": "VS CodećÆē¾åœØć‚¹ć‚ÆćƒŖćƒ¼ćƒ³ćƒŖćƒ¼ćƒ€ćƒ¼ć®ä½æē”ØēŠ¶ę³ć«ęœ€é©åŒ–ć•ć‚Œć¦ć„ć¾ć™ć€‚", + "screenReaderDetectedExplanation.body2": "ć„ćć¤ć‹ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ę©Ÿčƒ½ćŒé€šåøøćØē•°ćŖć‚‹å‹•ä½œć‚’ć—ć¾ć™ć€‚ä¾‹: ęŠ˜ć‚Ščæ”ć—ć€ęŠ˜ć‚ŠćŸćŸćæć€ć‹ć£ć“ć®č‡Ŗå‹•é–‰ć˜ćŖć©" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 46f3a0b954e..afb57d9fbb2 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "ćƒ‘ćƒćƒ«ć‚’é–‰ć˜ć‚‹", "togglePanel": "ćƒ‘ćƒćƒ«ć®åˆ‡ć‚Šę›æćˆ", "focusPanel": "ćƒ‘ćƒćƒ«ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć™ć‚‹", + "toggledPanelPosition": "ćƒ‘ćƒćƒ«ä½ē½®ć®åˆ‡ć‚Šę›æćˆ", + "moveToRight": "å³ć«ē§»å‹•", + "moveToBottom": "下に移動", "toggleMaximizedPanel": "ęœ€å¤§åŒ–ć•ć‚Œć‚‹ćƒ‘ćƒćƒ«ć®åˆ‡ć‚Šę›æćˆ", "maximizePanel": "ćƒ‘ćƒćƒ« ć‚µć‚¤ć‚ŗć®ęœ€å¤§åŒ–", "minimizePanel": "ćƒ‘ćƒćƒ« ć‚µć‚¤ć‚ŗć‚’å…ƒć«ęˆ»ć™", diff --git a/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 8056b34fd1f..e750906b858 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "ć‚³ćƒžćƒ³ćƒ‰ '{0}' ćÆē¾åœØęœ‰åŠ¹ć§ćÆćŖćć€å®Ÿč”Œć§ćć¾ć›ć‚“ć€‚", "manageExtension": "ę‹”å¼µę©Ÿčƒ½ć‚’ē®”ē†" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..6bcbcb522f9 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} å€‹ć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..77323e2fdd2 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} å€‹ć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³", + "hideView": "ć‚µć‚¤ćƒ‰ ćƒćƒ¼ć‹ć‚‰éžč”Øē¤ŗ" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..3607a9f498a --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "location `{1}` 恧 id `{0}` ć®ćƒ“ćƒ„ćƒ¼ćŒę—¢ć«ē™»éŒ²ć•ć‚Œć¦ć„ć¾ć™" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..39d2dcfed3e --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "ć‚µć‚¤ćƒ‰ ćƒćƒ¼ć‹ć‚‰éžč”Øē¤ŗ" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/common/theme.i18n.json b/i18n/jpn/src/vs/workbench/common/theme.i18n.json index 33e26a1ff3f..a72d62e8dec 100644 --- a/i18n/jpn/src/vs/workbench/common/theme.i18n.json +++ b/i18n/jpn/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®čƒŒę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", "tabInactiveBackground": "éžć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®čƒŒę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", "tabBorder": "ć‚æćƒ–åŒå£«ć‚’åˆ†ć‘ć‚‹ćŸć‚ć®å¢ƒē•Œē·šć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸå†…ć«ć‚ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚č¤‡ę•°ć®ć‚æćƒ–ć‚’ 1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§é–‹ćć“ćØćŒć§ćć¾ć™ć€‚č¤‡ę•°ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ćŒć‚ć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚", + "tabActiveBorder": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚æćƒ–ć‚’å¼·čŖæč”Øē¤ŗć™ć‚‹ćŸć‚ć®å¢ƒē•Œē·šć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸå†…ć«ć‚ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚č¤‡ę•°ć®ć‚æćƒ–ć‚’ 1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§é–‹ćć“ćØćŒć§ćć¾ć™ć€‚č¤‡ę•°ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ćŒć‚ć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚", + "tabActiveUnfocusedBorder": "ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć•ć‚Œć¦ć„ćŖć„ć‚°ćƒ«ćƒ¼ćƒ—å†…ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć‚’å¼·čŖæč”Øē¤ŗć™ć‚‹ćŸć‚ć®å¢ƒē•Œē·šć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸå†…ć«ć‚ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚č¤‡ę•°ć®ć‚æćƒ–ć‚’ 1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§é–‹ćć“ćØćŒć§ćć¾ć™ć€‚č¤‡ę•°ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ćŒć‚ć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚", "tabActiveForeground": "ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚°ćƒ«ćƒ¼ćƒ—å†…ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®å‰ę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", "tabInactiveForeground": "ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚°ćƒ«ćƒ¼ćƒ—å†…ć®éžć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®å‰ę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", - "tabUnfocusedActiveForeground": "éžć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚°ćƒ«ćƒ¼ćƒ—å†…ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®å‰ę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", - "tabUnfocusedInactiveForeground": "éžć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®å‰ę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", + "tabUnfocusedActiveForeground": "ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć•ć‚Œć¦ć„ćŖć„ć‚°ćƒ«ćƒ¼ćƒ—å†…ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®å‰ę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", + "tabUnfocusedInactiveForeground": "ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć•ć‚Œć¦ć„ćŖć„ć‚°ćƒ«ćƒ¼ćƒ—å†…ć®éžć‚¢ć‚Æćƒ†ć‚£ćƒ– ć‚æćƒ–ć®å‰ę™Æč‰²ć€‚ć‚æćƒ–ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć«ćŠć‘ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚1 ć¤ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć§č¤‡ę•°ć®ć‚æćƒ–ć‚’é–‹ćć“ćØćŒć§ćć¾ć™ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’č¤‡ę•°ć«ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", "editorGroupBackground": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć®čƒŒę™Æč‰²ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚čƒŒę™Æč‰²ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’ćƒ‰ćƒ©ćƒƒć‚°ć™ć‚‹ćØč”Øē¤ŗć•ć‚Œć¾ć™ć€‚", "tabsContainerBackground": "ć‚æćƒ–ćŒęœ‰åŠ¹ćŖå “åˆć® ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ— ć‚æć‚¤ćƒˆćƒ« ćƒ˜ćƒƒćƒ€ćƒ¼ć®čƒŒę™Æč‰²ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚", "tabsContainerBorder": "ć‚æćƒ–ćŒęœ‰åŠ¹ćŖå “åˆć® ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ— ć‚æć‚¤ćƒˆćƒ« ćƒ˜ćƒƒćƒ€ćƒ¼ć®å¢ƒē•Œē·šč‰²ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚", @@ -18,13 +20,13 @@ "editorGroupBorder": "č¤‡ę•°ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć‚’äŗ’ć„ć«åˆ†é›¢ć™ć‚‹ćŸć‚ć®č‰²ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒŠćƒ¼ć§ć™ć€‚", "editorDragAndDropBackground": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®å‘Øå›²ć‚’ćƒ‰ćƒ©ćƒƒć‚°ć—ć¦ć„ć‚‹ćØćć®čƒŒę™Æč‰²ć€‚ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚³ćƒ³ćƒ†ćƒ³ćƒ„ćŒęœ€å¾Œć¾ć§č¼ććŸć‚ć«ć€č‰²ćÆé€éŽć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", "panelBackground": "ćƒ‘ćƒćƒ«ć®čƒŒę™Æč‰²ć€‚ćƒ‘ćƒćƒ«ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć®äø‹ć«č”Øē¤ŗć•ć‚Œć€å‡ŗåŠ›ć‚„ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ćŖć©ć®ćƒ“ćƒ„ćƒ¼ć‚’å«ćæć¾ć™ć€‚", - "panelBorder": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćØć®åŒŗåˆ‡ć‚Šć‚’ē¤ŗć™ćƒ‘ćƒćƒ«äøŠéƒØć®ē½«ē·šć®č‰²ć€‚ćƒ‘ćƒćƒ«ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć®äø‹ć«č”Øē¤ŗć•ć‚Œć€å‡ŗåŠ›ć‚„ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ćŖć©ć®ćƒ“ćƒ„ćƒ¼ć‚’å«ćæć¾ć™ć€‚", "panelActiveTitleForeground": "ć‚¢ć‚Æćƒ†ć‚£ćƒ– ćƒ‘ćƒćƒ«ć®ć‚æć‚¤ćƒˆćƒ«ć®č‰²ć€‚ćƒ‘ćƒćƒ«ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć®äø‹ć«č”Øē¤ŗć•ć‚Œć€å‡ŗåŠ›ć‚„ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ćŖć©ć®ćƒ“ćƒ„ćƒ¼ć‚’å«ćæć¾ć™ć€‚", "panelInactiveTitleForeground": "éžć‚¢ć‚Æćƒ†ć‚£ćƒ– ćƒ‘ćƒćƒ«ć®ć‚æć‚¤ćƒˆćƒ«ć®č‰²ć€‚ćƒ‘ćƒćƒ«ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć®äø‹ć«č”Øē¤ŗć•ć‚Œć€å‡ŗåŠ›ć‚„ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ćŖć©ć®ćƒ“ćƒ„ćƒ¼ć‚’å«ćæć¾ć™ć€‚", "panelActiveTitleBorder": "ć‚¢ć‚Æćƒ†ć‚£ćƒ– ćƒ‘ćƒćƒ« ć‚æć‚¤ćƒˆćƒ«ć®å¢ƒē•Œē·šć®č‰²ć€‚ćƒ‘ćƒćƒ«ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼é ˜åŸŸć®äø‹ć«č”Øē¤ŗć•ć‚Œć€å‡ŗåŠ›ć‚„ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ćŖć©ć®ćƒ“ćƒ„ćƒ¼ć‚’å«ćæć¾ć™ć€‚", - "statusBarForeground": "ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®å‰ę™Æč‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "panelDragAndDropBackground": "ćƒ‘ćƒćƒ« ć‚æć‚¤ćƒˆćƒ«é …ē›®ć®ćƒ‰ćƒ©ćƒƒć‚° ć‚¢ćƒ³ćƒ‰ 惉惭惃惗 ćƒ•ć‚£ćƒ¼ćƒ‰ćƒćƒƒć‚Æć®č‰²ć€‚ćƒ‘ćƒćƒ« ć‚Øćƒ³ćƒˆćƒŖćƒ¼ćŒęœ€å¾Œć¾ć§č¼ććŸć‚ć«ć€č‰²ćÆé€éŽć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ćƒ‘ćƒćƒ«ćÆć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚ØćƒŖć‚¢ć®äø‹å“ć«č”Øē¤ŗć•ć‚Œć€å‡ŗåŠ›ć‚„ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ć‚ˆć†ćŖćƒ“ćƒ„ćƒ¼ć‚’å«ćæć¾ć™ć€‚", + "statusBarForeground": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’é–‹ć„ć¦ć„ćŖć„ćØćć®ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®å‰ę™Æč‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", "statusBarNoFolderForeground": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćŒé–‹ć„ć¦ć„ćŖć„ćØćć®ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®å‰ę™Æč‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", - "statusBarBackground": "ęØ™ęŗ–ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®čƒŒę™Æč‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "statusBarBackground": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’é–‹ć„ć¦ć„ćŖć„ćØćć®ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®čƒŒę™Æč‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", "statusBarNoFolderBackground": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćŒé–‹ć„ć¦ć„ćŖć„ćØćć®ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®čƒŒę™Æč‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", "statusBarBorder": "ć‚µć‚¤ćƒ‰ćƒćƒ¼ćØć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’éš”ć¦ć‚‹ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®å¢ƒē•Œē·šč‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", "statusBarNoFolderBorder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć„ć¦ć„ćŖć„ćØćć«ć‚µć‚¤ćƒ‰ćƒćƒ¼ćØć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’éš”ć¦ć‚‹ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć®å¢ƒē•Œē·šć®č‰²ć€‚ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ćÆć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®äø‹éƒØć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚ ", diff --git a/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json index 8938e8dd9e8..a31924013b2 100644 --- a/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "äøŠć®ćƒ“ćƒ„ćƒ¼éƒØåˆ†ć«ē§»å‹•", "navigateDown": "äø‹ć®ćƒ“ćƒ„ćƒ¼éƒØåˆ†ć«ē§»å‹•", "increaseViewSize": "ē¾åœØć®ćƒ“ćƒ„ćƒ¼ć®ć‚µć‚¤ć‚ŗć®ę‹”å¤§", - "decreaseViewSize": "ē¾åœØć®ćƒ“ćƒ„ćƒ¼ć®ć‚µć‚¤ć‚ŗć®ēø®å°" + "decreaseViewSize": "ē¾åœØć®ćƒ“ćƒ„ćƒ¼ć®ć‚µć‚¤ć‚ŗć®ēø®å°", + "showPreviousTab": "å‰ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ ć‚æćƒ–ć‚’č”Øē¤ŗ", + "showNextWindowTab": "ę¬”ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ ć‚æćƒ–ć‚’č”Øē¤ŗ", + "moveWindowTabToNewWindow": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ ć‚æćƒ–ć‚’ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć«ē§»å‹•", + "mergeAllWindowTabs": "ć™ć¹ć¦ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’ēµ±åˆ", + "toggleWindowTabsBar": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ ć‚æćƒ– ćƒćƒ¼ć®åˆ‡ć‚Šę›æćˆ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..21107d326ab --- /dev/null +++ b/i18n/jpn/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "čØ€čŖžć‚’ę§‹ęˆć™ć‚‹", + "displayLanguage": "VSCode ć®č”Øē¤ŗčØ€čŖžć‚’å®šē¾©ć—ć¾ć™ć€‚", + "doc": "ć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć‚‹čØ€čŖžć®äø€č¦§ć«ć¤ć„ć¦ćÆć€{0} ć‚’ć”č¦§ćć ć•ć„ć€‚", + "restart": "値を変曓するには VS Code ć®å†čµ·å‹•ćŒåæ…č¦ć§ć™ć€‚", + "fail.createSettings": "'{0}' ({1}) ć‚’ä½œęˆć§ćć¾ć›ć‚“ć€‚", + "JsonSchema.locale": "使用する UI čØ€čŖžć€‚" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json index 6061715ea0e..35db8c1bace 100644 --- a/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,17 +10,25 @@ "workspaces": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹", "developer": "開発者", "showEditorTabs": "é–‹ć„ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ć‚æćƒ–ć«č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", + "workbench.editor.labelFormat.default": "ćƒ•ć‚”ć‚¤ćƒ«ć®åå‰ć‚’č”Øē¤ŗć—ć¾ć™ć€‚ć‚æćƒ–ćŒęœ‰åŠ¹ć‹ć¤ 1 ć¤ć®ć‚°ćƒ«ćƒ¼ćƒ—å†…ć® 2 ć¤ć®åŒåćƒ•ć‚”ć‚¤ćƒ«ćŒć‚ć‚‹ćØćć«å„ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹ć®åŒŗåˆ‡ć‚ŠčØ˜å·ćŒčæ½åŠ ć•ć‚Œć¾ć™ć€‚ć‚æćƒ–ć‚’ē„”åŠ¹ć«ć™ć‚‹ćØć€ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖę™‚ć«ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ē›øåÆ¾ćƒ‘ć‚¹ćŒč”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "workbench.editor.labelFormat.short": "ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖåć«ē¶šć‘ć¦ćƒ•ć‚”ć‚¤ćƒ«åć‚’č”Øē¤ŗć—ć¾ć™ć€‚", + "workbench.editor.labelFormat.medium": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‹ć‚‰ć®ē›øåÆ¾ćƒ‘ć‚¹ć«ē¶šć‘ć¦ćƒ•ć‚”ć‚¤ćƒ«åć‚’č”Øē¤ŗć—ć¾ć™ć€‚", + "workbench.editor.labelFormat.long": "ēµ¶åÆ¾ćƒ‘ć‚¹ć«ē¶šć‘ć¦ćƒ•ć‚”ć‚¤ćƒ«åć‚’č”Øē¤ŗć—ć¾ć™ć€‚", + "tabDescription": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ćƒ©ćƒ™ćƒ«ć®ę›øå¼ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ä¾‹ćØć—ć¦ć“ć®čØ­å®šć‚’å¤‰ę›“ć™ć‚‹ć“ćØć§ćƒ•ć‚”ć‚¤ćƒ«ć®å “ę‰€ć‚’ē†č§£ć—ć‚„ć™ććŖć‚Šć¾ć™:\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', ć€€åˆ„ć‚æćƒ–ć§ć€åŒć˜ć‚æć‚¤ćƒˆćƒ«ć‚’å…±ęœ‰ć™ć‚‹å “åˆć‚„ć€ē›øåÆ¾ēš„ćŖćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ‘ć‚¹ ć‚æćƒ–ćŒē„”åŠ¹ć«ćŖć£ć¦ć„ć‚‹å “åˆ", "editorTabCloseButton": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚æćƒ–ć®é–‰ć˜ć‚‹ćƒœć‚æćƒ³ć®ä½ē½®ć‚’åˆ¶å¾”ć™ć‚‹ć‹ć€[off] ć«čØ­å®šć—ćŸå “åˆć«ē„”åŠ¹ć«ć—ć¾ć™ć€‚", "showIcons": "é–‹ć„ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ć‚¢ć‚¤ć‚³ćƒ³ć§č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ć“ć‚Œć«ćÆć€ć‚¢ć‚¤ć‚³ćƒ³ć®ćƒ†ćƒ¼ćƒžć‚’ęœ‰åŠ¹ć«ć™ć‚‹åæ…č¦ć‚‚ć‚ć‚Šć¾ć™ć€‚", - "enablePreview": "é–‹ć„ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ćØć—ć¦č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćÆć€äæęŒć•ć‚Œć¦ć„ć‚‹é–“ć€å†åˆ©ē”Øć•ć‚Œć¾ć™ (ćƒ€ćƒ–ćƒ«ć‚ÆćƒŖćƒƒć‚Æć¾ćŸćÆē·Øé›†ćŖć©ć«ć‚ˆć£ć¦)怂", + "enablePreview": "é–‹ć‹ć‚Œć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ćØć—ć¦č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćÆ (例: ćƒ€ćƒ–ćƒ« ć‚ÆćƒŖćƒƒć‚Æć¾ćŸćÆē·Øé›†ćŖć©ć«ć‚ˆć£ć¦) å¤‰ę›“ć•ć‚Œć‚‹ę™‚ć¾ć§å†åˆ©ē”Øć—ć€ę–œä½“ć§č”Øē¤ŗć—ć¾ć™ć€‚", "enablePreviewFromQuickOpen": "Quick Open ć§é–‹ć„ćŸć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ćØć—ć¦č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ćƒ—ćƒ¬ćƒ“ćƒ„ćƒ¼ ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćÆć€äæęŒć•ć‚Œć¦ć„ć‚‹é–“ć€å†åˆ©ē”Øć•ć‚Œć¾ć™ (ćƒ€ćƒ–ćƒ«ć‚ÆćƒŖćƒƒć‚Æć¾ćŸćÆē·Øé›†ćŖć©ć«ć‚ˆć£ć¦)怂", - "editorOpenPositioning": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ćå “ę‰€ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚[å·¦] または [右] ć‚’éøęŠžć—ć¦ć€ē¾åœØć‚¢ć‚Æćƒ†ć‚£ćƒ–ć«ćŖć£ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®å·¦ć¾ćŸćÆå³ć«ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ćć¾ć™ć€‚[ęœ€åˆ] または [ęœ€å¾Œ] ć‚’éøęŠžć—ć¦ć€ē¾åœØć‚¢ć‚Æćƒ†ć‚£ćƒ–ć«ćŖć£ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćØćÆåˆ„å€‹ć«ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ćć¾ć™ć€‚", + "editorOpenPositioning": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ćå “ę‰€ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚'left' または 'right' ć‚’éøęŠžć™ć‚‹ćØē¾åœØć‚¢ć‚Æćƒ†ć‚£ćƒ–ć«ćŖć£ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®å·¦ć¾ćŸćÆå³ć«ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ćć¾ć™ć€‚'first' または 'last' ć‚’éøęŠžć™ć‚‹ćØē¾åœØć‚¢ć‚Æćƒ†ć‚£ćƒ–ć«ćŖć£ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćØćÆåˆ„å€‹ć«ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ćć¾ć™ć€‚", "revealIfOpen": "ä»»ę„ć®č”Øē¤ŗć‚°ćƒ«ćƒ¼ćƒ—ćŒé–‹ć‹ć‚ŒćŸå “åˆć«ć€ćć“ć«ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ē„”åŠ¹ć«ć—ćŸå “åˆć€ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćÆē¾åœØć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć«å„Ŗå…ˆć—ć¦é–‹ć‹ć‚Œć¾ć™ć€‚ęœ‰åŠ¹ć«ć—ćŸå “åˆćÆć€ē¾åœØć®ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚Øćƒ‡ć‚£ć‚æćƒ¼ ć‚°ćƒ«ćƒ¼ćƒ—ć«ć‚‚ć†äø€åŗ¦é–‹ćć®ć§ćÆćŖćć€ę—¢ć«é–‹ć„ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒč”Øē¤ŗć•ć‚Œć¾ć™ć€‚ē‰¹å®šć®ć‚°ćƒ«ćƒ¼ćƒ—å†…ć‚„ē¾åœØć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚°ćƒ«ćƒ¼ćƒ—ć®ęØŖć«å¼·åˆ¶ēš„ć«ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’é–‹ć„ćŸå “åˆćŖć©ć«ć€ć“ć®čØ­å®šćŒē„”č¦–ć•ć‚Œć‚‹å “åˆć‚‚ć‚ć‚‹ć“ćØć«ć”ę³Øę„ćć ć•ć„ć€‚", "commandHistory": "ć‚³ćƒžćƒ³ćƒ‰ ćƒ‘ćƒ¬ćƒƒćƒˆć§ęœ€čæ‘ä½æē”Øć—ćŸć‚³ćƒžćƒ³ćƒ‰å±„ę­“ć‚’äæęŒć™ć‚‹ę•°ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚0 ć«čØ­å®šć™ć‚‹ćØć‚³ćƒžćƒ³ćƒ‰å±„ę­“ć‚’ē„”åŠ¹ć«ć—ć¾ć™ć€‚", "preserveInput": "ę¬”å›žé–‹ć„ćŸćØćć€ć‚³ćƒžćƒ³ćƒ‰ ćƒ‘ćƒ¬ćƒƒćƒˆć®ęœ€å¾Œć®å…„åŠ›ć‚’å¾©å…ƒć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "closeOnFocusLost": "ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć‚’å¤±ć£ćŸćØćć« Quick Open ć‚’č‡Ŗå‹•ēš„ć«é–‰ć˜ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "openDefaultSettings": "čØ­å®šć‚’é–‹ććØć™ć¹ć¦ć®ę—¢å®šć®čØ­å®šć‚’č”Øē¤ŗć™ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚‚é–‹ćć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", + "experimentalFuzzySearchEndpoint": "č©¦éØ“ēš„ćŖčØ­å®šę¤œē“¢ć§ä½æē”Øć™ć‚‹ć‚Øćƒ³ćƒ‰ćƒć‚¤ćƒ³ćƒˆć‚’ęŒ‡å®šć—ć¾ć™ć€‚", + "experimentalFuzzySearchKey": "č©¦éØ“ēš„ćŖčØ­å®šę¤œē“¢ć§ä½æē”Øć™ć‚‹ć‚­ćƒ¼ć‚’ęŒ‡å®šć—ć¾ć™ć€‚", "sideBarLocation": "ć‚µć‚¤ćƒ‰ ćƒćƒ¼ć®ä½ē½®ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ćƒÆćƒ¼ć‚Æćƒ™ćƒ³ćƒć®å·¦å³ć®ć„ćšć‚Œć‹ć«č”Øē¤ŗć§ćć¾ć™ć€‚", + "panelLocation": "ćƒ‘ćƒćƒ«ć®ä½ē½®ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ćƒÆćƒ¼ć‚Æćƒ™ćƒ³ćƒć®äø‹éƒØć¾ćŸćÆå³ć®ć„ćšć‚Œć‹ć«č”Øē¤ŗć§ćć¾ć™ć€‚", "statusBarVisibility": "ćƒÆćƒ¼ć‚Æćƒ™ćƒ³ćƒć®äø‹éƒØć«ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ ćƒćƒ¼ć‚’č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "activityBarVisibility": "ćƒÆćƒ¼ć‚Æćƒ™ćƒ³ćƒć§ć®ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ ćƒćƒ¼ć®č”Øē¤ŗć‚’ć‚³ćƒ³ćƒˆćƒ­ćƒ¼ćƒ«ć—ć¾ć™ć€‚", "closeOnFileDelete": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’č”Øē¤ŗć—ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ć€ćƒ•ć‚”ć‚¤ćƒ«ćŒå‰Šé™¤ć•ć‚Œć‚‹ć‹ćć®ä»–ć®ćƒ—ćƒ­ć‚»ć‚¹ć«ć‚ˆć£ć¦åå‰ć‚’å¤‰ę›“ć•ć‚ŒćŸå “åˆć«ć€č‡Ŗå‹•ēš„ć«é–‰ć˜ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ć“ć‚Œć‚’ē„”åŠ¹ć«ć™ć‚‹ćØć€ć“ć®ć‚ˆć†ćŖå “åˆć«ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćÆćƒ€ćƒ¼ćƒ†ć‚£ć§é–‹ć‹ć‚ŒćŸć¾ć¾ć«ćŖć‚Šć¾ć™ć€‚ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³å†…ć§å‰Šé™¤ć™ć‚‹ćØć€åæ…ćšć‚Øćƒ‡ć‚£ć‚æćƒ¼ćÆé–‰ć˜ć‚‰ć‚Œć€ćƒ€ćƒ¼ćƒ†ć‚£ ćƒ•ć‚”ć‚¤ćƒ«ćÆé–‰ć˜ć‚‰ć‚Œć‚‹ć“ćØćŒćŖćć€ćƒ‡ćƒ¼ć‚æćÆäæå­˜ć•ć‚Œć¾ć›ć‚“ć®ć§ć”ę³Øę„ćć ć•ć„ć€‚", @@ -45,7 +53,7 @@ "restoreWindows": "å†čµ·å‹•å¾Œć«ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’å†åŗ¦é–‹ćę–¹ę³•ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚'none' ć‚’éøęŠžć™ć‚‹ćØåøøć«ē©ŗć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć§é–‹å§‹ć—ć¾ć™ć€‚'one' ć‚’éøęŠžć™ć‚‹ćØęœ€å¾Œć«ä½æē”Øć—ćŸć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å†åŗ¦é–‹ćć¾ć™ć€‚'folders' ć‚’éøęŠžć™ć‚‹ćØé–‹ć‹ć‚Œć¦ć„ćŸćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćØć™ć¹ć¦ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å†åŗ¦é–‹ćć¾ć™ć€‚'all' ć‚’éøęŠžć™ć‚‹ćØå‰å›žć®ć‚»ćƒƒć‚·ćƒ§ćƒ³ć®ć™ć¹ć¦ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å†åŗ¦é–‹ćć¾ć™ć€‚", "restoreFullscreen": "å…Øē”»é¢č”Øē¤ŗćƒ¢ćƒ¼ćƒ‰ć§ēµ‚äŗ†ć—ćŸå “åˆć«ć€ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å…Øē”»é¢č”Øē¤ŗćƒ¢ćƒ¼ćƒ‰ć«å¾©å…ƒć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "zoomLevel": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®ć‚ŗćƒ¼ćƒ  ćƒ¬ćƒ™ćƒ«ć‚’čŖæę•“ć—ć¾ć™ć€‚å…ƒć®ć‚µć‚¤ć‚ŗćÆ 0 恧态1 ć¤äøŠć’ć‚‹ć”ćØć« (1 など) 20% ćšć¤ę‹”å¤§ć™ć‚‹ć“ćØć‚’č”Øć—ć€1 つ下げるごとに (-1 など) 20% ćšć¤ēø®å°ć™ć‚‹ć“ćØć‚’č”Øć—ć¾ć™ć€‚å°ę•°ē‚¹ä»„äø‹ć®ę”ę•°ć‚’å…„åŠ›ć—ć¦ć€ć•ć‚‰ć«ē“°ć‹ćć‚ŗćƒ¼ćƒ  ćƒ¬ćƒ™ćƒ«ć‚’čŖæę•“ć™ć‚‹ć“ćØć‚‚ć§ćć¾ć™ć€‚", - "title": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚Øćƒ‡ć‚£ć‚æćƒ¼ć«åŸŗć„ć„ć¦ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®ć‚æć‚¤ćƒˆćƒ«ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚å¤‰ę•°ćÆć€ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆć«åŸŗć„ć„ć¦ē½®ę›ć•ć‚Œć¾ć™:\n${activeEditorShort}: 例: myFile.txt\n${activeEditorMedium}: 例: myFolder/myFile.txt\n${activeEditorLong}: 例: /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 例: myFolder\n${folderPath}: 例: /Users/Development/myFolder\n${rootName}: 例: myFolder1, myFolder2, myFolder3\n${rootPath}: 例: /Users/Development/myWorkspace\n${appName}: 例: VS Code\n${dirty}: ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒćƒ€ćƒ¼ćƒ†ć‚£ć§ć‚ć‚‹å “åˆć®ćƒ€ćƒ¼ćƒ†ć‚£ ć‚¤ćƒ³ć‚øć‚²ćƒ¼ć‚æćƒ¼\n${separator}: å€¤ć®ć‚ć‚‹å¤‰ę•°ć§å›²ć¾ć‚ŒćŸå “åˆć«ć®ćæč”Øē¤ŗć•ć‚Œć‚‹ę”ä»¶ä»˜ćåŒŗåˆ‡ć‚ŠčØ˜å· (\" - \")", + "title": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚Øćƒ‡ć‚£ć‚æćƒ¼ć«åŸŗć„ć„ć¦ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®ć‚æć‚¤ćƒˆćƒ«ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚å¤‰ę•°ćÆć€ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆć«åŸŗć„ć„ć¦ē½®ę›ć•ć‚Œć¾ć™:\n${activeEditorShort}: ćƒ•ć‚”ć‚¤ćƒ«å (例: myFile.txt)\n${activeEditorMedium}: ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćøć®ē›øåÆ¾ćƒ‘ć‚¹ (例: myFolder/myFile.txt)\n${activeEditorLong}: ćƒ•ć‚”ć‚¤ćƒ«ć®å®Œå…ØćŖćƒ‘ć‚¹ (例: /Users/Development/myProject/myFolder/myFile.txt)\n${folderName}: ćƒ•ć‚”ć‚¤ćƒ«ćŒå«ć¾ć‚Œć¦ć„ć‚‹ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼å (例: myFolder)\n${folderPath}: ć‚”ć‚¤ćƒ«ćŒå«ć¾ć‚Œć¦ć„ć‚‹ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ćƒ•ć‚”ć‚¤ćƒ«ćƒ‘ć‚¹ (例: /Users/Development/myFolder)\n${rootName}: ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®åå‰ (例: myFolder 悄 myWorkspace)\n${rootPath}: ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćƒ•ć‚”ć‚¤ćƒ« ćƒ‘ć‚¹ (例: /Users/Development/myWorkspace)\n${appName}: 例: VS Code\n${dirty}: ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒćƒ€ćƒ¼ćƒ†ć‚£ć§ć‚ć‚‹å “åˆć®ćƒ€ćƒ¼ćƒ†ć‚£ ć‚¤ćƒ³ć‚øć‚²ćƒ¼ć‚æćƒ¼\n${separator}: å€¤ć®ć‚ć‚‹å¤‰ę•°ć§å›²ć¾ć‚ŒćŸå “åˆć«ć®ćæč”Øē¤ŗć•ć‚Œć‚‹ę”ä»¶ä»˜ćåŒŗåˆ‡ć‚ŠčØ˜å· (\" - \")", "window.newWindowDimensions.default": "ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’ē”»é¢ć®äø­å¤®ć«é–‹ćć¾ć™ć€‚", "window.newWindowDimensions.inherit": "ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’ć€ęœ€å¾Œć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–ć ć£ćŸć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ćØåŒć˜ć‚µć‚¤ć‚ŗć§é–‹ćć¾ć™ć€‚", "window.newWindowDimensions.maximized": "ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’ęœ€å¤§åŒ–ć—ćŸēŠ¶ę…‹ć§é–‹ćć¾ć™ć€‚", diff --git a/i18n/jpn/src/vs/workbench/electron-browser/window.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/window.i18n.json index 090217063f9..0813ed28598 100644 --- a/i18n/jpn/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/jpn/src/vs/workbench/electron-browser/window.i18n.json @@ -9,7 +9,5 @@ "cut": "åˆ‡ć‚Šå–ć‚Š", "copy": "ć‚³ćƒ”ćƒ¼", "paste": "č²¼ć‚Šä»˜ć‘", - "selectAll": "ć™ć¹ć¦éøęŠž", - "confirmOpen": "{0} ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’é–‹ćć¾ć™ć‹?", - "confirmOpenButton": "開恏(&&O)" + "selectAll": "ć™ć¹ć¦éøęŠž" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index a89e2005ea3..701e79dd4f4 100644 --- a/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "ć‚ć‚‹č”ŒćŒć“ć®ćƒ‘ć‚æćƒ¼ćƒ³ćØäø€č‡“ć™ć‚‹å “åˆćÆć€ćć®ć‚¤ćƒ³ćƒ‡ćƒ³ćƒˆć‚’å¤‰ę›“ć—ć¦ćÆćŖć‚‰ćšć€ä»–ć®ćƒ«ćƒ¼ćƒ«ć«åÆ¾ć—ć¦č©•ä¾”ć—ć¦ć‚‚ćŖć‚Šć¾ć›ć‚“ć€‚", "schema.indentationRules.unIndentedLinePattern.pattern": "unIndentedLinePattern ć«ä½æē”Øć™ć‚‹ę­£č¦č”Øē¾ćƒ‘ć‚æćƒ¼ćƒ³ć€‚", "schema.indentationRules.unIndentedLinePattern.flags": "unIndentedLinePattern ć«ä½æē”Øć™ć‚‹ę­£č¦č”Øē¾ćƒ•ćƒ©ć‚°ć€‚", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` ćƒ‘ć‚æćƒ¼ćƒ³ć«äø€č‡“ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚" + "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` ćƒ‘ć‚æćƒ¼ćƒ³ć«äø€č‡“ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", + "schema.folding": "čØ€čŖžć®ęŠ˜ć‚Šē•³ćæčØ­å®šć€‚", + "schema.folding.offSide": "ćć®čØ€čŖžć®ćƒ–ćƒ­ćƒƒć‚ÆćŒć‚¤ćƒ³ćƒ‡ćƒ³ćƒˆć§č”Øē¾ć•ć‚Œć¦ć„ć‚‹å “åˆć€čØ€čŖžćÆć‚Ŗćƒ•ć‚µć‚¤ćƒ‰ćƒ«ćƒ¼ćƒ«ć«å¾“ć„ć¾ć™ć€‚ čØ­å®šć•ć‚Œć¦ć„ć‚‹å “åˆć€ē©ŗč”ŒćÆå¾Œē¶šć®ćƒ–ćƒ­ćƒƒć‚Æć«å±žć—ć¾ć™ć€‚", + "schema.folding.markers": "'#region'悄 '#endregion'ćŖć©ć®čØ€čŖžå›ŗęœ‰ć®ęŠ˜ć‚ŠćŸćŸćæćƒžćƒ¼ć‚«ćƒ¼ć€‚é–‹å§‹ćØēµ‚äŗ†ć®ę­£č¦č”Øē¾ćÆć™ć¹ć¦ć®č”Œć®å†…å®¹ć«åÆ¾ć—ć¦ćƒ†ć‚¹ćƒˆć—åŠ¹ēŽ‡ēš„ć«čØ­čØˆć—ć¦ćć ć•ć„ć€‚", + "schema.folding.markers.start": "é–‹å§‹ćƒžćƒ¼ć‚«ćƒ¼ć®ę­£č¦č”Øē¾ćƒ‘ć‚æćƒ¼ćƒ³ć€‚ ę­£č¦č”Øē¾ćÆ '^' ć§å§‹ć‚ć¦ćć ć•ć„ć€‚", + "schema.folding.markers.end": "ēµ‚äŗ†ćƒžćƒ¼ć‚«ćƒ¼ć®ę­£č¦č”Øē¾ćƒ‘ć‚æćƒ¼ćƒ³ć€‚ ę­£č¦č”Øē¾ćÆ '^' ć§å§‹ć‚ć¦ćć ć•ć„ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..7ad50e6716e --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "蔨示:Ā ćƒŸćƒ‹ćƒžćƒƒćƒ—ć®åˆ‡ć‚Šę›æćˆ" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index a507f746844..debd28baf64 100644 --- a/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "åˆ¶å¾”ę–‡å­—ć®åˆ‡ć‚Šę›æćˆ" + "toggleRenderControlCharacters": "蔨示: åˆ¶å¾”ę–‡å­—ć®åˆ‡ć‚Šę›æćˆ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index eae0b2cf15a..9601fcc6e74 100644 --- a/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "ē©ŗē™½ę–‡å­—ć®č”Øē¤ŗć®åˆ‡ć‚Šę›æćˆ" + "toggleRenderWhitespace": "蔨示: ē©ŗē™½ę–‡å­—ć®č”Øē¤ŗć®åˆ‡ć‚Šę›æćˆ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index 8eef43766e8..52c478e6b95 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "ę§‹ęˆćŒć‚ć‚Šć¾ć›ć‚“", + "addConfigTo": "設定 ({0}) の追加 ...", "addConfiguration": "ę§‹ęˆć®čæ½åŠ ..." } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 24b30de36ed..f9530ecfb90 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}态惇惐惃悰", "debugAriaLabel": "å®Ÿč”Œć™ć‚‹čµ·å‹•ę§‹ęˆć®åå‰ć‚’å…„åŠ›ć—ć¦ćć ć•ć„ć€‚", + "addConfigTo": "設定 ({0}) の追加 ...", + "addConfiguration": "ę§‹ęˆć®čæ½åŠ ...", "noConfigurationsMatching": "äø€č‡“ć™ć‚‹ćƒ‡ćƒćƒƒć‚°ę§‹ęˆćÆć‚ć‚Šć¾ć›ć‚“", "noConfigurationsFound": "ćƒ‡ćƒćƒƒć‚°ę§‹ęˆćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć€‚'launch.json' ćƒ•ć‚”ć‚¤ćƒ«ć‚’ä½œęˆć—ć¦ćć ć•ć„ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..b317922a971 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "å¤‰ę•°ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", + "debugFocusWatchView": "ć‚¦ć‚©ćƒƒćƒć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", + "debugFocusCallStackView": "ć‚³ćƒ¼ćƒ«ć‚¹ć‚æćƒƒć‚Æć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", + "debugFocusBreakpointsView": "ćƒ–ćƒ¬ćƒ¼ć‚Æćƒć‚¤ćƒ³ćƒˆć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 03f52be8c47..84777c482b2 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "åˆęœŸ 'launch.json' ć‚’ē”Ÿęˆć™ć‚‹ćŸć‚ć®ę§‹ęˆć€‚", "vscode.extension.contributes.debuggers.languages": "ćƒ‡ćƒćƒƒć‚°ę‹”å¼µę©Ÿčƒ½ćŒ \"ę—¢å®šć®ćƒ‡ćƒćƒƒć‚¬ćƒ¼\" ćØć•ć‚Œć‚‹čØ€čŖžć®äø€č¦§ć€‚", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "ęŒ‡å®šć•ć‚Œć¦ć„ć‚‹å “åˆć€VS Code ćÆć“ć®ć‚³ćƒžćƒ³ćƒ‰ć‚’å‘¼ć³å‡ŗć—ć€ćƒ‡ćƒćƒƒć‚° ć‚¢ćƒ€ćƒ—ć‚æćƒ¼ć®å®Ÿč”ŒåÆčƒ½ćƒ‘ć‚¹ćØć€ęø”ć™å¼•ę•°ć‚’ę±ŗå®šć—ć¾ć™ć€‚", - "vscode.extension.contributes.debuggers.startSessionCommand": "VS Code ćŒęŒ‡å®šć•ć‚Œć¦ć„ć‚‹å “åˆć€ć“ć®ę‹”å¼µę©Ÿčƒ½ć‚’åÆ¾č±”ćØć™ć‚‹ \"惇惐惃悰\" または \"実蔌\" ć‚¢ć‚Æć‚·ćƒ§ćƒ³ć«ć“ć®ć‚³ćƒžćƒ³ćƒ‰ćŒå‘¼ć³å‡ŗć•ć‚Œć¾ć™ć€‚", "vscode.extension.contributes.debuggers.configurationSnippets": "'launch.json' ć«ę–°ć—ć„ę§‹ęˆć‚’čæ½åŠ ć™ć‚‹ćŸć‚ć®ć‚¹ćƒ‹ćƒšćƒƒćƒˆć€‚", "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json' ć‚’ę¤œčØ¼ć™ć‚‹ćŸć‚ć® JSON ć‚¹ć‚­ćƒ¼ćƒžę§‹ęˆć€‚", "vscode.extension.contributes.debuggers.windows": "Windows å›ŗęœ‰ć®čØ­å®šć€‚", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 27747833c51..c52fc9a42ea 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,14 +12,14 @@ "breakpointRemoved": "ćƒ–ćƒ¬ćƒ¼ć‚Æćƒć‚¤ćƒ³ćƒˆć‚’å‰Šé™¤ć—ć¾ć—ćŸć€‚č”Œ {0}ć€ćƒ•ć‚”ć‚¤ćƒ« {1}", "compoundMustHaveConfigurations": "č¤‡åˆę§‹ęˆć‚’é–‹å§‹ć™ć‚‹ć«ćÆć€č¤‡åˆć« \"configurations\" å±žę€§ćŒčØ­å®šć•ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", "configMissing": "꧋ꈐ '{0}' が 'launch.json' å†…ć«ć‚ć‚Šć¾ć›ć‚“ć€‚", + "debugRequestNotSupported": "éøęŠžć—ć¦ć„ć‚‹ćƒ‡ćƒćƒƒć‚°ę§‹ęˆć§ `{0}` å±žę€§ćÆć‚µćƒćƒ¼ćƒˆć•ć‚ŒćŖć„å€¤ '{1}' ć‚’ęŒ‡å®šć—ć¦ć„ć¾ć™ć€‚", "debugTypeNotSupported": "ę§‹ęˆć•ć‚Œć¦ć„ć‚‹ćƒ‡ćƒćƒƒć‚°ć®ēØ®é”ž '{0}' ćÆć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚", - "debugTypeMissing": "éøęŠžć•ć‚ŒćŸčµ·å‹•ę§‹ęˆć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ 'type' ćŒć‚ć‚Šć¾ć›ć‚“ć€‚", + "debugTypeMissing": "éøęŠžć—ć¦ć„ć‚‹čµ·å‹•ę§‹ęˆć® `type` ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćŒć‚ć‚Šć¾ć›ć‚“ć€‚", + "debugAnyway": "ć“ć®ć¾ć¾ćƒ‡ćƒćƒƒć‚°ć‚’ē¶šć‘ć‚‹", "preLaunchTaskErrors": "preLaunchTask '{0}' ć®å®Ÿč”Œäø­ć«ćƒ“ćƒ«ćƒ‰ ć‚Øćƒ©ćƒ¼ćŒę¤œå‡ŗć•ć‚Œć¾ć—ćŸć€‚", "preLaunchTaskError": "preLaunchTask '{0}' ć®å®Ÿč”Œäø­ć«ćƒ“ćƒ«ćƒ‰ ć‚Øćƒ©ćƒ¼ćŒę¤œå‡ŗć•ć‚Œć¾ć—ćŸć€‚", "preLaunchTaskExitCode": "preLaunchTask '{0}' ćŒēµ‚äŗ†ć‚³ćƒ¼ćƒ‰ {1} ć§ēµ‚äŗ†ć—ć¾ć—ćŸć€‚", - "debugAnyway": "ć“ć®ć¾ć¾ćƒ‡ćƒćƒƒć‚°ć‚’ē¶šć‘ć‚‹", "noFolderWorkspaceDebugError": "ć‚¢ć‚Æćƒ†ć‚£ćƒ– ćƒ•ć‚”ć‚¤ćƒ«ć‚’ćƒ‡ćƒćƒƒć‚°ć§ćć¾ć›ć‚“ć€‚ćƒ•ć‚”ć‚¤ćƒ«ćŒćƒ‡ć‚£ć‚¹ć‚Æć«äæå­˜ć•ć‚Œć¦ćŠć‚Šć€ćć®ćƒ•ć‚”ć‚¤ćƒ« ć‚æć‚¤ćƒ—ć®ćƒ‡ćƒćƒƒć‚°ę‹”å¼µę©Ÿčƒ½ćŒć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć‚‹ć“ćØć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚", "NewLaunchConfig": "ć‚¢ćƒ—ćƒŖć‚±ćƒ¼ć‚·ćƒ§ćƒ³ć®čµ·å‹•ę§‹ęˆćƒ•ć‚”ć‚¤ćƒ«ć‚’ć‚»ćƒƒćƒˆć‚¢ćƒƒćƒ—ć—ć¦ćć ć•ć„ć€‚{0}", - "DebugTaskNotFound": "preLaunchTask '{0}' ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸć€‚", - "differentTaskRunning": "タスク '{0}' ćÆę—¢ć«å®Ÿč”Œäø­ć§ć™ć€‚čµ·å‹•å‰ć‚æć‚¹ć‚Æ '{1}' ćÆå®Ÿč”Œć§ćć¾ć›ć‚“ć€‚ " + "DebugTaskNotFound": "preLaunchTask '{0}' ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 38c84790727..57032e9d668 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "変数 {0} に値 {1} ćŒć‚ć‚Šć¾ć™ć€Read Eval Print Loop态惇惐惃悰", "replExpressionAriaLabel": "式 {0} に値 {1} ćŒć‚ć‚Šć¾ć™ć€Read Eval Print Loop态惇惐惃悰", "replValueOutputAriaLabel": "{0}态Read Eval Print Loop态惇惐惃悰", - "replKeyValueOutputAriaLabel": "å‡ŗåŠ›å¤‰ę•° {0} に値 {1} ćŒć‚ć‚Šć¾ć™ć€Read Eval Print Loop态惇惐惃悰" + "replRawObjectAriaLabel": "Repl 変数 {0} に値 {1} ćŒć‚ć‚Šć¾ć™ć€Read Eval Print Loop态惇惐惃悰" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index d63fe387f50..e96a6ca7456 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "惇惐惃悰 ć‚¢ćƒ€ćƒ—ć‚æćƒ¼ć®å®Ÿč”ŒåÆčƒ½ćƒ•ć‚”ć‚¤ćƒ« '{0}' ćŒć‚ć‚Šć¾ć›ć‚“ć€‚", "debugAdapterCannotDetermineExecutable": "惇惐惃悰 ć‚¢ćƒ€ćƒ—ć‚æćƒ¼ '{0}' ć®å®Ÿč”ŒåÆčƒ½ćƒ•ć‚”ć‚¤ćƒ«ć‚’åˆ¤åˆ„ć§ćć¾ć›ć‚“ć€‚", + "launch.config.comment1": "IntelliSense ć‚’ä½æē”Øć—ć¦åˆ©ē”ØåÆčƒ½ćŖå±žę€§ć‚’å­¦ć¹ć¾ć™ć€‚", + "launch.config.comment2": "ę—¢å­˜ć®å±žę€§ć®čŖ¬ę˜Žć‚’ćƒ›ćƒćƒ¼ć—ć¦č”Øē¤ŗć—ć¾ć™ć€‚", + "launch.config.comment3": "č©³ē“°ęƒ…å ±ćÆę¬”ć‚’ē¢ŗčŖć—ć¦ćć ć•ć„: {0}", "debugType": "ę§‹ęˆć®ēØ®é”žć€‚", "debugTypeNotRecognised": "ćƒ‡ćƒćƒƒć‚°ć®ēØ®é”žćÆčŖč­˜ć•ć‚Œć¾ć›ć‚“ć§ć—ćŸć€‚åÆ¾åæœć™ć‚‹ćƒ‡ćƒćƒƒć‚°ć®ę‹”å¼µę©Ÿčƒ½ćŒć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ćŠć‚Šć€ęœ‰åŠ¹ć«ćŖć£ć¦ć„ć‚‹ć“ćØć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚", "node2NotSupported": "\"node2\" ćÆć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚ä»£ć‚ć‚Šć« \"node\" を使用し、\"protocol\" å±žę€§ć‚’ \"inspector\" ć«čØ­å®šć—ć¦ćć ć•ć„ć€‚", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index b8608b055ff..16b98008acb 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "名前", "view location": "堓所", - "themes": "ćƒ†ćƒ¼ćƒž ({0})", + "colorThemes": "é…č‰²ćƒ†ćƒ¼ćƒž ({0})", + "iconThemes": "ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒž ({0})", + "colors": "é…č‰² ({0})", + "colorId": "Id", + "defaultDark": "ćƒ€ćƒ¼ć‚Æ ćƒ†ćƒ¼ćƒžć®ę—¢å®šå€¤", + "defaultLight": "ćƒ©ć‚¤ćƒˆ ćƒ†ćƒ¼ćƒžć®ę—¢å®šå€¤", + "defaultHC": "惏悤 ć‚³ćƒ³ćƒˆćƒ©ć‚¹ćƒˆć®ę—¢å®šå€¤", "JSON Validation": "JSON 検証 ({0})", "commands": "ć‚³ćƒžćƒ³ćƒ‰ ({0})", "command name": "名前", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index c967445c40c..c2fdd0e989a 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,7 +34,6 @@ "postDisableMessage": "ć“ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å†čŖ­ćæč¾¼ćæć—ć¦ć€ę‹”å¼µę©Ÿčƒ½ '{0}' ć‚’éžć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć—ć¾ć™ć‹?", "postUninstallTooltip": "å†čŖ­ćæč¾¼ćæć—ć¦éžć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć™ć‚‹", "postUninstallMessage": "ć“ć®ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć‚’å†åŗ¦čŖ­ćæč¾¼ć‚“ć§ć€ć‚¢ćƒ³ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ęøˆćæć®ę‹”å¼µę©Ÿčƒ½ '{0}' ć‚’éžć‚¢ć‚Æćƒ†ć‚£ćƒ–åŒ–ć—ć¾ć™ć‹?", - "reload": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®å†čŖ­ćæč¾¼ćæ(&&R)", "toggleExtensionsViewlet": "ę‹”å¼µę©Ÿčƒ½ć‚’č”Øē¤ŗć™ć‚‹", "installExtensions": "ę‹”å¼µę©Ÿčƒ½ć®ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«", "showEnabledExtensions": "ęœ‰åŠ¹ćŖę‹”å¼µę©Ÿčƒ½ć®č”Øē¤ŗ", @@ -44,14 +43,17 @@ "showOutdatedExtensions": "å¤ććŖć£ćŸę‹”å¼µę©Ÿčƒ½ć®č”Øē¤ŗ", "showPopularExtensions": "äŗŗę°—ć®ę‹”å¼µę©Ÿčƒ½ć®č”Øē¤ŗ", "showRecommendedExtensions": "ćŠå‹§ć‚ć®ę‹”å¼µę©Ÿčƒ½ć‚’č”Øē¤ŗ", - "showWorkspaceRecommendedExtensions": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćŠć™ć™ć‚ć®ę‹”å¼µę©Ÿčƒ½ć‚’č”Øē¤ŗ", + "installWorkspaceRecommendedExtensions": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćŠć™ć™ć‚ć®ę‹”å¼µę©Ÿčƒ½ć‚’ć™ć¹ć¦ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«", + "installRecommendedExtension": "ćŠć™ć™ć‚ć®ę‹”å¼µę©Ÿčƒ½ć®ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«", "showRecommendedKeymapExtensions": "ęŽØå„Øć®ć‚­ćƒ¼ćƒžćƒƒćƒ—ć‚’č”Øē¤ŗć™ć‚‹", "showRecommendedKeymapExtensionsShort": "ć‚­ćƒ¼ćƒžćƒƒćƒ—", "showLanguageExtensions": "čØ€čŖžć®ę‹”å¼µę©Ÿčƒ½ć‚’č”Øē¤ŗ", "showLanguageExtensionsShort": "čØ€čŖžć®ę‹”å¼µę©Ÿčƒ½", - "configureWorkspaceRecommendedExtensions": "ćŠå‹§ć‚ć®ę‹”å¼µę©Ÿčƒ½ć®ę§‹ęˆ (ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹)", - "ConfigureWorkspaceRecommendations.noWorkspace": "ęŽØå„Øäŗ‹é …ćÆćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć§ć®ćæåˆ©ē”ØåÆčƒ½ć§ć™ć€‚", + "showAzureExtensions": "Azure ę‹”å¼µę©Ÿčƒ½ć®č”Øē¤ŗ", + "showAzureExtensionsShort": "Azure ę‹”å¼µę©Ÿčƒ½", "OpenExtensionsFile.failed": "'.vscode' ćƒ•ć‚”ćƒ«ćƒ€ćƒ¼ ({0}) 内に 'extensions.json' ćƒ•ć‚”ć‚¤ćƒ«ć‚’ä½œęˆć§ćć¾ć›ć‚“ć€‚", + "configureWorkspaceRecommendedExtensions": "ęŽØå„Øäŗ‹é …ć®ę‹”å¼µę©Ÿčƒ½ć‚’ę§‹ęˆ (ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹)", + "configureWorkspaceFolderRecommendedExtensions": "ęŽØå„Øäŗ‹é …ć®ę‹”å¼µę©Ÿčƒ½ć‚’ę§‹ęˆ (ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼)", "builtin": "ćƒ“ćƒ«ćƒˆć‚¤ćƒ³", "disableAll": "ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ęøˆćæć®ć™ć¹ć¦ć®ę‹”å¼µę©Ÿčƒ½ć‚’ē„”åŠ¹ć«ć™ć‚‹", "disableAllWorkspace": "ć“ć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ęøˆćæć®ę‹”å¼µę©Ÿčƒ½ć‚’ć™ć¹ć¦ē„”åŠ¹ć«ć™ć‚‹", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..7fd46ed2ab6 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "ęŽØå„Ø" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index cb6785d0102..685b5ccd148 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "ę‹”å¼µę©Ÿčƒ½ć‚’ē®”ē†ć™ć‚‹ć«ćÆ Enter ć‚­ćƒ¼ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚", + "notfound": "ę‹”å¼µę©Ÿčƒ½ '{0}' が Marketplace ć«č¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸć€‚", + "install": "Marketplace ć‹ć‚‰ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć™ć‚‹ 恋悉 '{0}'Ā ć‚’ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć™ć‚‹ć«ćÆ Enter ć‚­ćƒ¼ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚", "searchFor": "ćƒžćƒ¼ć‚±ćƒƒćƒˆćƒ—ćƒ¬ćƒ¼ć‚¹å†…ć§ '{0}' ć‚’ę¤œē“¢ć™ć‚‹ć«ćÆć€Enter ć‚­ćƒ¼ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚", "noExtensionsToInstall": "ę‹”å¼µę©Ÿčƒ½åć‚’å…„åŠ›ć—ć¦ćć ć•ć„" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/common/extensionsFileTemplate.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/common/extensionsFileTemplate.i18n.json index 72c1edd109b..ad8152b1d4c 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/common/extensionsFileTemplate.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/common/extensionsFileTemplate.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "app.extensions.json.title": "ę‹”å¼µę©Ÿčƒ½", - "app.extensions.json.recommendations": "ę‹”å¼µę©Ÿčƒ½ć®ćŠć™ć™ć‚å€™č£œć®äø€č¦§ć€‚ę‹”å¼µę©Ÿčƒ½ć® ID は常に '${publisher}.${name}' です。例: 'vscode.csharp'怂", + "app.extensions.json.recommendations": "ę‹”å¼µę©Ÿčƒ½ć®ęŽØå„Øäŗ‹é …ć®ćƒŖć‚¹ćƒˆć€‚ę‹”å¼µę©Ÿčƒ½ć® ID は常に '${publisher}.${name}' です。例: 'vscode.csharp'怂", "app.extension.identifier.errorMessage": "äŗˆęœŸć•ć‚Œć‚‹å½¢å¼ '${publisher}.${name}'。例: 'vscode.csharp'怂" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index f7a0d5005fc..5b07cd1e3ef 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -4,11 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "fileBasedRecommendation": "ęœ€čæ‘é–‹ć„ćŸćƒ•ć‚”ć‚¤ćƒ«ć«åŸŗć„ć„ć¦ć“ć®ę‹”å¼µę©Ÿčƒ½ćŒęŽØå„Øć•ć‚Œć¾ć™ć€‚", + "workspaceRecommendation": "ē¾åœØć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćƒ¦ćƒ¼ć‚¶ćƒ¼ć«ć‚ˆć£ć¦ć“ć®ę‹”å¼µę©Ÿčƒ½ćŒęŽØå„Øć•ć‚Œć¦ć„ć¾ć™ć€‚", "reallyRecommended2": "ć“ć®ćƒ•ć‚”ć‚¤ćƒ«ć®ēØ®é”žć«ćÆę‹”å¼µę©Ÿčƒ½ '{0}' ćŒęŽØå„Øć•ć‚Œć¾ć™ć€‚", + "reallyRecommendedExtensionPack": "ć“ć®ćƒ•ć‚”ć‚¤ćƒ«ć®ēØ®é”žć«ćÆę‹”å¼µę©Ÿčƒ½ćƒ‘ćƒƒć‚Æ '{0}' ćŒęŽØå„Øć•ć‚Œć¾ć™ć€‚", "showRecommendations": "ęŽØå„Øäŗ‹é …ć‚’č”Øē¤ŗ", + "install": "ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«", "neverShowAgain": "ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", "close": "閉恘悋", "workspaceRecommended": "ć“ć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć«ćÆę‹”å¼µę©Ÿčƒ½ć®ęŽØå„Øäŗ‹é …ćŒć‚ć‚Šć¾ć™ć€‚", + "installAll": "ć™ć¹ć¦ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«", "ignoreExtensionRecommendations": "ć™ć¹ć¦ć®ę‹”å¼µę©Ÿčƒ½ć®ęŽØå„Øäŗ‹é …ć‚’ē„”č¦–ć—ć¾ć™ć‹?", "ignoreAll": "はい、すべて焔視します", "no": "恄恄恈", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json index f5ca28fa3d4..d9d2527ff37 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json @@ -8,6 +8,8 @@ "installedExtensions": "ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ęøˆćæ", "searchInstalledExtensions": "ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ęøˆćæ", "recommendedExtensions": "ęŽØå„Ø", + "otherRecommendedExtensions": "ćć®ä»–ć®ęŽØå„Øäŗ‹é …", + "workspaceRecommendedExtensions": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ęŽØå„Øäŗ‹é …", "searchExtensions": "Marketplace ć§ę‹”å¼µę©Ÿčƒ½ć‚’ę¤œē“¢ć™ć‚‹", "sort by installs": "äø¦ć¹ę›æćˆ: ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ę•°", "sort by rating": "äø¦ć¹ę›æćˆ: č©•ä¾”", diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json index b2abd33ddd4..a17a249ed45 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "'{0}' ć‚’å‰Šé™¤ć—ć¾ć™ć‹?", "undoBin": "ć”ćæē®±ć‹ć‚‰å¾©å…ƒć§ćć¾ć™ć€‚", "undoTrash": "ć‚“ćƒŸē®±ć‹ć‚‰å¾©å…ƒć§ćć¾ć™ć€‚", + "doNotAskAgain": "å†åŗ¦č”Øē¤ŗć—ćŖć„", "confirmDeleteMessageFolder": "'{0}' ćØćć®å†…å®¹ć‚’å®Œå…Øć«å‰Šé™¤ć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?", "confirmDeleteMessageFile": "'{0}' ć‚’å®Œå…Øć«å‰Šé™¤ć—ć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹?", "irreversible": "ć“ć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³ćÆå…ƒć«ęˆ»ć™ć“ćØćŒć§ćć¾ć›ć‚“ć€‚", @@ -37,17 +38,15 @@ "openToSide": "ęØŖć«äø¦ć¹ć¦é–‹ć", "compareSource": "ęÆ”č¼ƒåÆ¾č±”ć®éøęŠž", "globalCompareFile": "ć‚¢ć‚Æćƒ†ć‚£ćƒ– ćƒ•ć‚”ć‚¤ćƒ«ć‚’ęÆ”č¼ƒć—ć¦ć„ć¾ć™...", - "pickHistory": "ęÆ”č¼ƒåÆ¾č±”ćØć—ć¦ć€ä»„å‰ć«é–‹ć„ćŸćƒ•ć‚”ć‚¤ćƒ«ć‚’éøęŠžć™ć‚‹", - "unableToFileToCompare": "éøęŠžć•ć‚ŒćŸćƒ•ć‚”ć‚¤ćƒ«ć‚’ '{0}' ćØęÆ”č¼ƒć§ćć¾ć›ć‚“ć€‚", "openFileToCompare": "ć¾ćšćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć‹ć‚‰åˆ„ć®ćƒ•ć‚”ć‚¤ćƒ«ćØęÆ”č¼ƒć—ć¦ćć ć•ć„", - "compareWith": "'{0}' ćØęÆ”č¼ƒ", + "compareWith": "'{0}' と '{1}' ć‚’ęÆ”č¼ƒ", "compareFiles": "ćƒ•ć‚”ć‚¤ćƒ«ć®ęÆ”č¼ƒ", "refresh": "ęœ€ę–°ć®ęƒ…å ±ć«ę›“ę–°", "save": "äæå­˜", "saveAs": "åå‰ć‚’ä»˜ć‘ć¦äæå­˜...", "saveAll": "ć™ć¹ć¦äæå­˜", "saveAllInGroup": "ć‚°ćƒ«ćƒ¼ćƒ—å†…ć®ć™ć¹ć¦ć‚’äæå­˜ć™ć‚‹", - "saveFiles": "ćƒ€ćƒ¼ćƒ†ć‚£ ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜", + "saveFiles": "ć™ć¹ć¦ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜", "revert": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’å…ƒć«ęˆ»ć™", "focusOpenEditors": "é–‹ć„ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ćƒ“ćƒ„ćƒ¼ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć™ć‚‹", "focusFilesExplorer": "ćƒ•ć‚”ć‚¤ćƒ« ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć‚’ē½®ć", @@ -55,10 +54,9 @@ "openFileToShow": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§ćƒ•ć‚”ć‚¤ćƒ«ć‚’č”Øē¤ŗć™ć‚‹ć«ćÆć€ćƒ•ć‚”ć‚¤ćƒ«ć‚’ć¾ćšé–‹ćåæ…č¦ćŒć‚ć‚Šć¾ć™", "collapseExplorerFolders": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ęŠ˜ć‚ŠćŸćŸć‚€", "refreshExplorer": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć‚’ęœ€ę–°č”Øē¤ŗć™ć‚‹", - "openFile": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć...", "openFileInNewWindow": "ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć§ć‚¢ć‚Æćƒ†ć‚£ćƒ– ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", "openFileToShowInNewWindow": "ć¾ćšćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć‹ć‚‰ę–°ć—ć„ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć§é–‹ćć¾ć™", - "revealInWindows": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§č”Øē¤ŗć—ć¾ć™", + "revealInWindows": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§č”Øē¤ŗ", "revealInMac": "Finder で蔨示します", "openContainer": "ć“ć®ć‚¢ć‚¤ćƒ†ćƒ ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć", "revealActiveFileInWindows": "Windows ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§ć‚¢ć‚Æćƒ†ć‚£ćƒ– ćƒ•ć‚”ć‚¤ćƒ«ć‚’č”Øē¤ŗć™ć‚‹", diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 137f07f4650..f5e47e18761 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "ćƒ†ć‚­ć‚¹ćƒˆ ćƒ•ć‚”ć‚¤ćƒ« ć‚Øćƒ‡ć‚£ć‚æćƒ¼", "binaryFileEditor": "ćƒć‚¤ćƒŠćƒŖ ćƒ•ć‚”ć‚¤ćƒ« ć‚Øćƒ‡ć‚£ć‚æćƒ¼", "filesConfigurationTitle": "ćƒ•ć‚”ć‚¤ćƒ«", - "exclude": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é™¤å¤–ć™ć‚‹ćŸć‚ć® glob ćƒ‘ć‚æćƒ¼ćƒ³ć‚’ę§‹ęˆć—ć¾ć™ć€‚", + "exclude": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é™¤å¤–ć™ć‚‹ćŸć‚ć® glob ćƒ‘ć‚æćƒ¼ćƒ³ć‚’ę§‹ęˆć—ć¾ć™ć€‚ćŸćØćˆć°ć€ćƒ•ć‚”ć‚¤ćƒ« ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§ćÆć“ć®čØ­å®šć«åŸŗć„ć„ć¦ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®č”Øē¤ŗć‚„éžč”Øē¤ŗć‚’ę±ŗå®šć—ć¾ć™ć€‚", "files.exclude.boolean": "ćƒ•ć‚”ć‚¤ćƒ« ćƒ‘ć‚¹ć®ē…§åˆåŸŗęŗ–ćØćŖć‚‹ glob ćƒ‘ć‚æćƒ¼ćƒ³ć€‚ć“ć‚Œć‚’ true または false ć«čØ­å®šć™ć‚‹ćØć€ćƒ‘ć‚æćƒ¼ćƒ³ćŒćć‚Œćžć‚Œęœ‰åŠ¹/ē„”åŠ¹ć«ćŖć‚Šć¾ć™ć€‚", "files.exclude.when": "äø€č‡“ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«ć®å…„å¼Ÿć‚’ć•ć‚‰ć«ćƒć‚§ćƒƒć‚Æć—ć¾ć™ć€‚äø€č‡“ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«åć®å¤‰ę•°ćØć—ć¦ $(basename) を使用します。", "associations": "čØ€čŖžć«åÆ¾ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«ć®é–¢é€£ä»˜ć‘ (例 \"*.extension\": \"html\") ć‚’ę§‹ęˆć—ć¾ć™ć€‚ć“ć‚Œć‚‰ć®é–¢é€£ä»˜ć‘ćÆć€ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć‚‹čØ€čŖžć®ę—¢å®šć®é–¢é€£ä»˜ć‘ć‚ˆć‚Šå„Ŗå…ˆć•ć‚Œć¾ć™ć€‚", - "encoding": "ćƒ•ć‚”ć‚¤ćƒ«ć®čŖ­ćæå–ć‚Š/ę›øćč¾¼ćæć§ä½æē”Øć™ć‚‹ę—¢å®šć®ę–‡å­—ć‚»ćƒƒćƒˆ ć‚Øćƒ³ć‚³ćƒ¼ćƒ‡ć‚£ćƒ³ć‚°ć€‚", - "autoGuessEncoding": "ęœ‰åŠ¹ćŖå “åˆć€ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ććØćć«ę–‡å­—ć‚»ćƒƒćƒˆ ć‚Øćƒ³ć‚³ćƒ¼ćƒ‰ć‚’ęŽØęø¬ć—ć¾ć™", + "encoding": "ćƒ•ć‚”ć‚¤ćƒ«ć®čŖ­ćæå–ć‚Š/ę›øćč¾¼ćæć§ä½æē”Øć™ć‚‹ę—¢å®šć®ę–‡å­—ć‚»ćƒƒćƒˆ ć‚Øćƒ³ć‚³ćƒ¼ćƒ‡ć‚£ćƒ³ć‚°ć€‚čØ€čŖžć”ćØć«ę§‹ęˆć™ć‚‹ć“ćØć‚‚åÆčƒ½ć§ć™ć€‚", + "autoGuessEncoding": "ęœ‰åŠ¹ćŖå “åˆć€ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ććØćć«ę–‡å­—ć‚»ćƒƒćƒˆ ć‚Øćƒ³ć‚³ćƒ¼ćƒ‰ć‚’ęŽØęø¬ć—ć¾ć™ć€‚čØ€čŖžć”ćØć«ę§‹ęˆć™ć‚‹ć“ćØć‚‚åÆčƒ½ć§ć™ć€‚", "eol": "ę—¢å®šć®ę”¹č”Œę–‡å­—ć€‚LF の堓合には \\n 悒 CRLF の堓合には \\r\\n ć‚’ä½æē”Øć—ć¦ćć ć•ć„ć€‚", "trimTrailingWhitespace": "ęœ‰åŠ¹ć«ć™ć‚‹ćØć€ćƒ•ć‚”ć‚¤ćƒ«ć®äæå­˜ę™‚ć«ęœ«å°¾ć®ē©ŗē™½ć‚’ćƒˆćƒŖćƒŸćƒ³ć‚°ć—ć¾ć™ć€‚", "insertFinalNewline": "ęœ‰åŠ¹ć«ć™ć‚‹ćØć€ćƒ•ć‚”ć‚¤ćƒ«ć®äæå­˜ę™‚ć«ęœ€ę–°ć®č”Œć‚’ęœ«å°¾ć«ęŒæå…„ć—ć¾ć™ć€‚", + "trimFinalNewlines": "ęœ‰åŠ¹ć«ć™ć‚‹ćØć€ćƒ•ć‚”ć‚¤ćƒ«ć®äæå­˜ę™‚ć«ęœ€ēµ‚č”Œä»„é™ć®ę–°ć—ć„č”Œć‚’ćƒˆćƒŖćƒŸćƒ³ć‚°ć—ć¾ć™ć€‚", "files.autoSave.off": "ćƒ€ćƒ¼ćƒ†ć‚£ ćƒ•ć‚”ć‚¤ćƒ«ć‚’č‡Ŗå‹•ēš„ć«äæå­˜ć™ć‚‹ć“ćØćÆć—ć¾ć›ć‚“ć€‚", "files.autoSave.afterDelay": "'files.autoSaveDelay' ć§ę§‹ęˆć•ć‚ŒćŸę™‚é–“ć®ēµŒéŽå¾Œć«ć€ćƒ€ćƒ¼ćƒ†ć‚£ ćƒ•ć‚”ć‚¤ćƒ«ć‚’č‡Ŗå‹•ēš„ć«äæå­˜ć—ć¾ć™ć€‚", "files.autoSave.onFocusChange": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ćŒćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć‚’å¤±ć£ćŸę™‚ē‚¹ć§ć€ćƒ€ćƒ¼ćƒ†ć‚£ ćƒ•ć‚”ć‚¤ćƒ«ć‚’č‡Ŗå‹•ēš„ć«äæå­˜ć—ć¾ć™ć€‚", @@ -39,10 +40,13 @@ "dynamicHeight": "é–‹ć„ć¦ć„ć‚‹ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®ć‚»ć‚Æć‚·ćƒ§ćƒ³ć®é«˜ć•ć‚’č¦ē“ ć®ę•°ć«åˆć‚ć›ć¦å‹•ēš„ć«čŖæę•“ć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "autoReveal": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ććØćć€č‡Ŗå‹•ēš„ć«ćƒ•ć‚”ć‚¤ćƒ«ć®å†…å®¹ć‚’č”Øē¤ŗć—ć¦éøęŠžć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "enableDragAndDrop": "ćƒ‰ćƒ©ćƒƒć‚° ć‚¢ćƒ³ćƒ‰ ćƒ‰ćƒ­ćƒƒćƒ—ć‚’ä½æē”Øć—ćŸćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ē§»å‹•ć‚’ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ćŒčØ±åÆć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", - "sortOrder.default": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«åå‰ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖćÆćƒ•ć‚”ć‚¤ćƒ«ć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", - "sortOrder.mixed": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«åå‰ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ•ć‚”ć‚¤ćƒ«ćÆćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖćØę··äŗ¤ć—ć¦č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", - "sortOrder.filesFirst": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«åå‰ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ•ć‚”ć‚¤ćƒ«ćÆćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", - "sortOrder.type": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«ę‹”å¼µå­ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖćÆćƒ•ć‚”ć‚¤ćƒ«ć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", - "sortOrder.modified": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć‚’é™é †ć«ęœ€ēµ‚ę›“ę–°ę—„ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖćÆćƒ•ć‚”ć‚¤ćƒ«ć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", - "sortOrder": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć§ć®ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć®äø¦ć³ę›æćˆę–¹ę³•ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚" + "confirmDelete": "ć”ćæē®±ć‚’ēµŒē”±ć—ćŸćƒ•ć‚”ć‚¤ćƒ«å‰Šé™¤ę™‚ć«ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ćŒē¢ŗčŖć‚’ę±‚ć‚ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", + "sortOrder.default": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«åå‰ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćÆćƒ•ć‚”ć‚¤ćƒ«ć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "sortOrder.mixed": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«åå‰ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ•ć‚”ć‚¤ćƒ«ćÆćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćØę··äŗ¤ć—ć¦č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "sortOrder.filesFirst": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«åå‰ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ•ć‚”ć‚¤ćƒ«ćÆćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "sortOrder.type": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ć‚¢ćƒ«ćƒ•ć‚”ćƒ™ćƒƒćƒˆé †ć«ę‹”å¼µå­ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćÆćƒ•ć‚”ć‚¤ćƒ«ć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "sortOrder.modified": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é™é †ć«ęœ€ēµ‚ę›“ę–°ę—„ć§äø¦ć³ę›æćˆć¾ć™ć€‚ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćÆćƒ•ć‚”ć‚¤ćƒ«ć®å‰ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "sortOrder": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼å†…ć®ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®äø¦ć³é †ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ę—¢å®šć®äø¦ć³é †ć«åŠ ćˆć¦ć€'mixed' (ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ę··äŗ¤ć—ćŸäø¦ć³é †)态' type' (ćƒ•ć‚”ć‚¤ćƒ«ć®ēØ®é”žé †)态' modified' (ęœ€ēµ‚ę›“ę–°ę—„ę™‚é †)ć€ć¾ćŸćÆ 'filesFirst' (ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®å‰ć«ćƒ•ć‚”ć‚¤ćƒ«ć‚’äø¦ć¹ć‚‹) ć®ć„ćšć‚Œć‹ć®äø¦ć³é †ć«čØ­å®šć§ćć¾ć™ć€‚Ā ", + "explorer.decorations.colors": "ćƒ•ć‚”ć‚¤ćƒ«ć®č£…é£¾ć«é…č‰²ć‚’ä½æē”Øć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", + "explorer.decorations.badges": "ćƒ•ć‚”ć‚¤ćƒ«ć®č£…é£¾ć«ćƒćƒƒć‚øć‚’ä½æē”Øć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 32f19d4912e..a11f1cb6ffc 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "å³å“ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ćƒ„ćƒ¼ćƒ« ćƒćƒ¼ć®ę“ä½œć§ć€å¤‰ę›“ć‚’ [å…ƒć«ęˆ»ć™] ć‹ć€ćƒ‡ć‚£ć‚¹ć‚Æć®å†…å®¹ć‚’å¤‰ę›“å†…å®¹ć§ [äøŠę›øć] します", "discard": "砓棄", "overwrite": "äøŠę›øć", "retry": "å†č©¦č”Œ", @@ -11,6 +12,5 @@ "genericSaveError": "'{0}' ć®äæå­˜ć«å¤±ę•—ć—ć¾ć—ćŸ: {1}", "staleSaveError": "'{0} ć®äæå­˜ć«å¤±ę•—ć—ć¾ć—ćŸć€‚ćƒ‡ć‚£ć‚¹ć‚Æć®å†…å®¹ć®ę–¹ćŒę–°ć—ććŖć£ć¦ć„ć¾ć™ć€‚[ęÆ”č¼ƒ] ć‚’ć‚ÆćƒŖćƒƒć‚Æć—ć¦ć”ä½æē”Øć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’ćƒ‡ć‚£ć‚¹ć‚ÆäøŠć®ćƒćƒ¼ć‚øćƒ§ćƒ³ćØęÆ”č¼ƒć—ć¦ćć ć•ć„ć€‚", "compareChanges": "ęÆ”č¼ƒ", - "saveConflictDiffLabel": "{0} (ćƒ‡ć‚£ć‚¹ć‚ÆäøŠ) ↔ {1} ({2} 内) - äæå­˜ć®ē«¶åˆć‚’č§£ę±ŗ", - "userGuide": "å³å“ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ ćƒ„ćƒ¼ćƒ« ćƒćƒ¼ć®ę“ä½œć§ć€å¤‰ę›“ć‚’ [å…ƒć«ęˆ»ć™] ć‹ć€ćƒ‡ć‚£ć‚¹ć‚Æć®å†…å®¹ć‚’å¤‰ę›“å†…å®¹ć§ [äøŠę›øć] します" + "saveConflictDiffLabel": "{0} (ćƒ‡ć‚£ć‚¹ć‚ÆäøŠ) ↔ {1} ({2} 内) - äæå­˜ć®ē«¶åˆć‚’č§£ę±ŗ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 93f172ab424..ac152686d08 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "é–‹ć„ć¦ć„ć‚‹ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćŒć‚ć‚Šć¾ć›ć‚“", "explorerSection": "ćƒ•ć‚”ć‚¤ćƒ« ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ ć‚»ć‚Æć‚·ćƒ§ćƒ³", - "noWorkspaceHelp": "ć¾ć ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć„ć¦ć„ć¾ć›ć‚“ć€‚", + "noWorkspaceHelp": "ć¾ć ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć«čæ½åŠ ć—ć¦ć„ć¾ć›ć‚“ć€‚", + "addFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čæ½åŠ ", + "noFolderHelp": "ć¾ć ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć„ć¦ć„ć¾ć›ć‚“ć€‚", "openFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..641ba8764bc --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 7e7aa33fae7..11e1b120a7c 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,12 @@ { "fileInputAriaLabel": "ćƒ•ć‚”ć‚¤ćƒ«åć‚’å…„åŠ›ć—ć¾ć™ć€‚Enter ć‚­ćƒ¼ć‚’ęŠ¼ć—ć¦ē¢ŗčŖć™ć‚‹ć‹ć€Esc ć‚­ćƒ¼ć‚’ęŠ¼ć—ć¦å–ć‚Šę¶ˆć—ć¾ć™ć€‚", "filesExplorerViewerAriaLabel": "{0}ć€ćƒ•ć‚”ć‚¤ćƒ« ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼", + "dropFolders": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć«ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’čæ½åŠ ć—ć¾ć™ć‹?", + "dropFolder": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć«ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’čæ½åŠ ć—ć¾ć™ć‹?", + "addFolders": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čæ½åŠ (&&A)", + "addFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čæ½åŠ (&&A)", + "confirmMove": "'{0}' を移動しますか?", + "doNotAskAgain": "å†åŗ¦č”Øē¤ŗć—ćŖć„", "confirmOverwriteMessage": "'{0}' ćÆäæå­˜å…ˆćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć«ę—¢ć«å­˜åœØć—ć¾ć™ć€‚ē½®ćę›ćˆć¦ć‚‚ć‚ˆć‚ć—ć„ć§ć™ć‹ć€‚", "irreversible": "ć“ć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³ćÆå…ƒć«ęˆ»ć™ć“ćØćŒć§ćć¾ć›ć‚“ć€‚", "replaceButtonLabel": "ē½®ę›(&&R)" diff --git a/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index e8bcfe52d77..a21e553496c 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 ć¤ć®ęœŖäæå­˜ć®ćƒ•ć‚”ć‚¤ćƒ«", "dirtyFiles": "{0} å€‹ć®ęœŖäæå­˜ć®ćƒ•ć‚”ć‚¤ćƒ«" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/jpn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..1f12247ced5 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "問锌", + "tooltip.1": "ć“ć®ćƒ•ć‚”ć‚¤ćƒ«ć« 1 ć¤ć®å•é”Œ", + "tooltip.N": "ć“ć®ćƒ•ć‚”ć‚¤ćƒ«ć« {0} å€‹ć®å•é”Œ", + "markers.showOnFile": "ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć«ć‚Øćƒ©ćƒ¼ćØč­¦å‘Šć‚’č”Øē¤ŗć—ć¾ć™ć€‚" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/jpn/src/vs/workbench/parts/markers/common/messages.i18n.json index 0fc672f8743..9a17f323ff9 100644 --- a/i18n/jpn/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "蔨示", + "problems.view.toggle.label": "å•é”Œć®åˆ‡ć‚Šę›æćˆ", "problems.view.show.label": "å•é”Œć‚’č”Øē¤ŗć™ć‚‹", + "problems.view.hide.label": "å•é”Œć®éžč”Øē¤ŗ", "problems.panel.configuration.title": "å•é”Œćƒ“ćƒ„ćƒ¼", "problems.panel.configuration.autoreveal": "ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ććØćć«å•é”Œćƒ“ćƒ„ćƒ¼ć«č‡Ŗå‹•ēš„ć«ćć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", "markers.panel.title.problems": "問锌", diff --git a/i18n/jpn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/jpn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index 1030fc85a7a..ce0e5088462 100644 --- a/i18n/jpn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "ć‚³ćƒ”ćƒ¼" + "copyMarker": "ć‚³ćƒ”ćƒ¼", + "copyMarkerMessage": "ćƒ”ćƒƒć‚»ćƒ¼ć‚øć®ć‚³ćƒ”ćƒ¼" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index e14e57a90eb..bc5d929551c 100644 --- a/i18n/jpn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "ć‚¹ć‚æćƒ¼ćƒˆć‚¢ćƒƒćƒ—ć®é…å»¶ćŒę¤œå‡ŗć•ć‚Œć¾ć—ćŸ", - "slow.detail": "ć‚¹ć‚æćƒ¼ćƒˆć‚¢ćƒƒćƒ—ćŒé…ć‹ć£ćŸćØć®ć“ćØć€ē”³ć—čØ³ć”ć–ć„ć¾ć›ć‚“ć€‚ćƒ—ćƒ­ćƒ•ć‚”ć‚¤ćƒ«ć‚’ęœ‰åŠ¹ć«ć—ć¦ć€'{0}' ć‚’å†čµ·å‹•ć—ć€ćƒ—ćƒ­ćƒ•ć‚”ć‚¤ćƒ«ć‚’å…±ęœ‰ć—ć¦ćć ć•ć„ć€‚ć‚¹ć‚æćƒ¼ćƒˆć‚¢ćƒƒćƒ—ć®ę”¹å–„ć®ćŸć‚ć«å‚č€ƒć«ć•ć›ć¦ć„ćŸć ćć¾ć™ć€‚", "prof.message": "ćƒ—ćƒ­ćƒ•ć‚”ć‚¤ćƒ«ćŒę­£åøøć«ä½œęˆć•ć‚Œć¾ć—ćŸć€‚", "prof.detail": "ę”ˆä»¶ć‚’ä½œęˆć—ć€ę‰‹å‹•ć§ę¬”ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’ę·»ä»˜ć—ć¦ćć ć•ć„:\\n{0}", "prof.restartAndFileIssue": "å•é”Œć‚’ä½œęˆć—ć¦å†čµ·å‹•", diff --git a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index c1aa63ce163..3257770db15 100644 --- a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "ć‚­ćƒ¼ćƒœćƒ¼ćƒ‰ ć‚·ćƒ§ćƒ¼ćƒˆć‚«ćƒƒćƒˆ ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", "openWorkspaceSettings": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹čØ­å®šć‚’é–‹ć", "openFolderSettings": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®šć‚’é–‹ć", - "pickFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®éøęŠž", "configureLanguageBasedSettings": "čØ€čŖžå›ŗęœ‰ć®čØ­å®šć‚’ę§‹ęˆć—ć¾ć™...", "languageDescriptionConfigured": "({0})", "pickLanguage": "čØ€čŖžć®éøęŠž" diff --git a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index c2dee25a5d5..4df3bbb8de6 100644 --- a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -13,5 +13,6 @@ "settingsFound": "{0} å€‹ć®čØ­å®šćŒäø€č‡“ć—ć¾ć™", "fileEditorWithInputAriaLabel": "{0}ć€‚ćƒ†ć‚­ć‚¹ćƒˆ ćƒ•ć‚”ć‚¤ćƒ« ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć€‚", "fileEditorAriaLabel": "ćƒ†ć‚­ć‚¹ćƒˆ ćƒ•ć‚”ć‚¤ćƒ« ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć€‚", + "defaultEditorReadonly": "ę—¢å®šå€¤ć‚’äøŠę›øćć™ć‚‹ć«ćÆć€å³å“ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć‚’ē·Øé›†ć—ć¾ć™ć€‚", "preferencesAriaLabel": "ę—¢å®šć®åŸŗęœ¬čØ­å®šć€‚čŖ­ćæå–ć‚Šå°‚ē”Øć®ćƒ†ć‚­ć‚¹ćƒˆ ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 4de3a3dae6f..77e44623852 100644 --- a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,13 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "emptyUserSettingsHeader": "ę—¢å®šć®čØ­å®šć‚’äøŠę›øćć™ć‚‹ć«ćÆć€ć“ć®ćƒ•ć‚”ć‚¤ćƒ«å†…ć«čØ­å®šć‚’ęŒæå…„ć—ć¾ć™ć€‚", + "emptyWorkspaceSettingsHeader": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć‚’äøŠę›øćć™ć‚‹ć«ćÆć€ć“ć®ćƒ•ć‚”ć‚¤ćƒ«å†…ć«čØ­å®šć‚’ęŒæå…„ć—ć¾ć™ć€‚", + "emptyFolderSettingsHeader": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®šć‚’äøŠę›øćć™ć‚‹ć«ćÆć€ć“ć®ćƒ•ć‚”ć‚¤ćƒ«å†…ć«ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®šć‚’ęŒæå…„ć—ć¾ć™ć€‚", "defaultFolderSettingsTitle": "ę—¢å®šć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼čØ­å®š", "defaultSettingsTitle": "ę—¢å®šć®čØ­å®š", - "noSettingsFound": "čØ­å®šćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć€‚", "editTtile": "編集", "replaceDefaultValue": "čØ­å®šć‚’ē½®ę›", "copyDefaultValue": "čØ­å®šć«ć‚³ćƒ”ćƒ¼", "unsupportedPHPExecutablePathSetting": "ć“ć®čØ­å®šćÆćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć§ćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“ć€‚ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ćŸć‚ć« PHP ć‚’ę§‹ęˆć™ć‚‹ć«ćÆć€PHP ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ćć€ć‚¹ćƒ†ćƒ¼ć‚æć‚¹ バーの [PHP ćƒ‘ć‚¹] ć‚’ć‚ÆćƒŖćƒƒć‚Æć—ć¾ć™ć€‚", - "unsupportedWorkspaceSetting": "ć“ć®čØ­å®šćÆćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć§ćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“ć€‚" + "unsupportedWorkspaceSetting": "ć“ć®čØ­å®šćÆćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć§ćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“ć€‚", + "unsupportedWorkbenchSetting": "ć“ć®čØ­å®šćÆē¾åœØé©ē”Øć§ćć¾ć›ć‚“ć€‚ć“ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ē›“ęŽ„é–‹ć„ćŸćØćć«é©ē”Øć•ć‚Œć¾ć™ć€‚", + "unsupportedWorkbenchSettingDevMode": "ć“ć®čØ­å®šćÆē¾åœØé©ē”Øć§ćć¾ć›ć‚“ć€‚ē™»éŒ²ę™‚ć«ć‚¹ć‚³ćƒ¼ćƒ—ć‚’ 'resource' ćØå®šē¾©ć—ć¦ć„ć‚‹å “åˆć‹ć“ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ē›“ęŽ„é–‹ć„ćŸćØćć«é©ē”Øć•ć‚Œć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index dda7fd4e0db..3997e1202fd 100644 --- a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "folderSettingsDetails": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®š" + "defaultSettingsFuzzyPrompt": "ć‚ć„ć¾ć„ę¤œē“¢ć‚’ćŠč©¦ć—ćć ć•ć„!", + "defaultSettings": "äøŠę›øćć™ć‚‹ć«ćÆć€å³å“ć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć«čØ­å®šć‚’å…„åŠ›ć—ć¾ć™ć€‚", + "noSettingsFound": "čØ­å®šćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć€‚", + "folderSettingsDetails": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®š", + "enableFuzzySearch": "č©¦éØ“ēš„ćŖć‚ć„ć¾ć„ę¤œē“¢ć‚’ęœ‰åŠ¹ć«ć™ć‚‹" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/jpn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index d4c0f156330..a99b14b8dd8 100644 --- a/i18n/jpn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "ć‚ˆćä½æē”Øć™ć‚‹ć‚‚ć®", - "noSettings": "čØ­å®šćÆć‚ć‚Šć¾ć›ć‚“", + "mostRelevant": "ęœ€ć‚‚é–¢é€£ę€§ć®é«˜ć„", "defaultKeybindingsHeader": "ć‚­ćƒ¼ ćƒć‚¤ćƒ³ćƒ‰ ćƒ•ć‚”ć‚¤ćƒ«å†…ć«ć‚­ćƒ¼ ćƒć‚¤ćƒ³ćƒ‰ć‚’ęŒæå…„ć—ć¦ć€ć‚­ćƒ¼ ćƒć‚¤ćƒ³ćƒ‰ć‚’äøŠę›øćć—ć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index b0aca24403e..306d7198a6b 100644 --- a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "ć‚³ćƒžćƒ³ćƒ‰ '{0}' ćÆē¾åœØć®ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆć§ćÆē„”åŠ¹ć§ć™ć€‚", "recentlyUsed": "ęœ€čæ‘ä½æē”Øć—ćŸć‚‚ć®", "morecCommands": "ćć®ä»–ć®ć‚³ćƒžćƒ³ćƒ‰", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "äø€č‡“ć™ć‚‹ć‚³ćƒžćƒ³ćƒ‰ćÆć‚ć‚Šć¾ć›ć‚“" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 34db8f687ec..301e0c41656 100644 --- a/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -5,8 +5,5 @@ // Do not edit this file. It is machine generated. { "relaunchSettingMessage": "å†čµ·å‹•ćŒåæ…č¦ćŖčØ­å®šć‚’å¤‰ę›“ć—ć¾ć—ćŸć€‚", - "relaunchSettingDetail": "{0} ć‚’å†čµ·å‹•ćƒœć‚æćƒ³ć§å†čµ·å‹•ć—ć¦ć€čØ­å®šć‚’ęœ‰åŠ¹ć«ć—ć¦ćć ć•ć„ć€‚", - "restart": "å†čµ·å‹•", - "relaunchWorkspaceMessage": "ć“ć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®å¤‰ę›“ć«ćÆć€ę‹”å¼µć‚·ć‚¹ćƒ†ćƒ ć®å†čŖ­ćæč¾¼ćæćŒåæ…č¦ć§ć™ć€‚", - "reload": "å†čŖ­ćæč¾¼ćæ" + "relaunchSettingDetail": "{0} ć‚’å†čµ·å‹•ćƒœć‚æćƒ³ć§å†čµ·å‹•ć—ć¦ć€čØ­å®šć‚’ęœ‰åŠ¹ć«ć—ć¦ćć ć•ć„ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 3902ae77527..043a0f4014f 100644 --- a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{1} 個のうご {0} 個の変曓", + "change": "{1} 個のうご {0} 個の変曓 ", + "show previous change": "å‰ć®å¤‰ę›“ē®‡ę‰€ć‚’č”Øē¤ŗ", + "show next change": "欔の変曓箇所を蔨示", "editorGutterModifiedBackground": "ē·Øé›†ć•ć‚ŒćŸč”Œć‚’ē¤ŗć™ć‚Øćƒ‡ć‚£ć‚æćƒ¼ä½™ē™½ć®čƒŒę™Æč‰²ć€‚", "editorGutterAddedBackground": "čæ½åŠ ć•ć‚ŒćŸč”Œć‚’ē¤ŗć™ć‚Øćƒ‡ć‚£ć‚æćƒ¼ä½™ē™½ć®čƒŒę™Æč‰²ć€‚", - "editorGutterDeletedBackground": "å‰Šé™¤ć•ć‚ŒćŸč”Œć‚’ē¤ŗć™ć‚Øćƒ‡ć‚£ć‚æćƒ¼ä½™ē™½ć®čƒŒę™Æč‰²ć€‚" + "editorGutterDeletedBackground": "å‰Šé™¤ć•ć‚ŒćŸč”Œć‚’ē¤ŗć™ć‚Øćƒ‡ć‚£ć‚æćƒ¼ä½™ē™½ć®čƒŒę™Æč‰²ć€‚", + "overviewRulerModifiedForeground": "å¤‰ę›“ć•ć‚ŒćŸć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć‚’ē¤ŗć™ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "overviewRulerAddedForeground": "čæ½åŠ ć•ć‚ŒćŸć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć‚’ē¤ŗć™ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚", + "overviewRulerDeletedForeground": "å‰Šé™¤ć•ć‚ŒćŸć‚³ćƒ³ćƒ†ćƒ³ćƒ„ć‚’ē¤ŗć™ę¦‚č¦ćƒ«ćƒ¼ćƒ©ćƒ¼ć®ćƒžćƒ¼ć‚«ćƒ¼č‰²ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index d45b8437459..b650b0b0eb3 100644 --- a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Git を蔨示", - "installAdditionalSCMProviders": "ćć®ä»–ć® SCM ćƒ—ćƒ­ćƒć‚¤ćƒ€ćƒ¼ć‚’ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«...", "source control": "ć‚½ćƒ¼ć‚¹ē®”ē†", "toggleSCMViewlet": "SCM を蔨示", "view": "蔨示" diff --git a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 6ff988da156..8f9dfe27002 100644 --- a/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "ć‚½ćƒ¼ć‚¹ē®”ē†ćƒ—ćƒ­ćƒć‚¤ćƒ€ćƒ¼", + "hideRepository": "éžč”Øē¤ŗ", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "ćć®ä»–ć® SCM ćƒ—ćƒ­ćƒć‚¤ćƒ€ćƒ¼ć‚’ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«...", + "no open repo": "ęœ‰åŠ¹ćŖć‚½ćƒ¼ć‚¹ē®”ē†ćƒ—ćƒ­ćƒć‚¤ćƒ€ćƒ¼ćŒć‚ć‚Šć¾ć›ć‚“ć€‚", "source control": "ć‚½ćƒ¼ć‚¹ē®”ē†", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 3f7491c52a6..b9e95372194 100644 --- a/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹å†…ć®ć‚·ćƒ³ćƒœćƒ«ćøē§»å‹•...", "name": "検瓢", - "showSearchViewlet": "検瓢の蔨示", + "search": "検瓢", "view": "蔨示", - "findInFiles": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ęŒ‡å®šć—ć¦ę¤œē“¢", "openAnythingHandlerDescription": "ćƒ•ć‚”ć‚¤ćƒ«ć«ē§»å‹•ć™ć‚‹", "openSymbolDescriptionNormal": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹å†…ć®ć‚·ćƒ³ćƒœćƒ«ćøē§»å‹•", "searchOutputChannelTitle": "検瓢", @@ -16,7 +15,7 @@ "exclude": "ę¤œē“¢ć§ćƒ•ć‚”ć‚¤ćƒ«ćØćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é™¤å¤–ć™ć‚‹ćŸć‚ć« glob ćƒ‘ć‚æćƒ¼ćƒ³ć‚’ę§‹ęˆć—ć¾ć™ć€‚files.exclude čØ­å®šć‹ć‚‰ć™ć¹ć¦ć® glob ćƒ‘ć‚æćƒ¼ćƒ³ć‚’ē¶™ę‰æć—ć¾ć™ć€‚", "exclude.boolean": "ćƒ•ć‚”ć‚¤ćƒ« ćƒ‘ć‚¹ć®ē…§åˆåŸŗęŗ–ćØćŖć‚‹ glob ćƒ‘ć‚æćƒ¼ćƒ³ć€‚ć“ć‚Œć‚’ true または false ć«čØ­å®šć™ć‚‹ćØć€ćƒ‘ć‚æćƒ¼ćƒ³ćŒćć‚Œćžć‚Œęœ‰åŠ¹/ē„”åŠ¹ć«ćŖć‚Šć¾ć™ć€‚", "exclude.when": "äø€č‡“ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«ć®å…„å¼Ÿć‚’ć•ć‚‰ć«ćƒć‚§ćƒƒć‚Æć—ć¾ć™ć€‚äø€č‡“ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«åć®å¤‰ę•°ćØć—ć¦ $(basename) を使用します。", - "useRipgrep": "ćƒ†ć‚­ć‚¹ćƒˆę¤œē“¢ć§ ripgrep ć‚’ä½æē”Øć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", - "useIgnoreFilesByDefault": "ę–°ć—ć„ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć§ę¤œē“¢ć™ć‚‹ćØćć«ć€ę—¢å®šć§ .gitignore ćƒ•ć‚”ć‚¤ćƒ«ć‚’ä½æē”Øć™ć‚‹ć‹ .ignore ćƒ•ć‚”ć‚¤ćƒ«ć‚’ä½æē”Øć™ć‚‹ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", - "search.quickOpen.includeSymbols": "ć‚°ćƒ­ćƒ¼ćƒćƒ« ć‚·ćƒ³ćƒœćƒ«ę¤œē“¢ć®ēµęžœć‚’ć€Quick Open ć®ēµęžœćƒ•ć‚”ć‚¤ćƒ«ć«å«ć‚ć‚‹ć‚ˆć†ć«ę§‹ęˆć—ć¾ć™ć€‚" + "useRipgrep": "ćƒ†ć‚­ć‚¹ćƒˆćØćƒ•ć‚”ć‚¤ćƒ«ę¤œē“¢ć§ ripgrep ć‚’ä½æē”Øć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™", + "search.quickOpen.includeSymbols": "ć‚°ćƒ­ćƒ¼ćƒćƒ« ć‚·ćƒ³ćƒœćƒ«ę¤œē“¢ć®ēµęžœć‚’ć€Quick Open ć®ēµęžœćƒ•ć‚”ć‚¤ćƒ«ć«å«ć‚ć‚‹ć‚ˆć†ć«ę§‹ęˆć—ć¾ć™ć€‚", + "search.followSymlinks": "ę¤œē“¢äø­ć«ć‚·ćƒ³ćƒœćƒŖćƒƒć‚Æ ćƒŖćƒ³ć‚Æć‚’čæ½č·”ć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 47d6b9c337e..e06a40eed9b 100644 --- a/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,10 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "ę¬”ć®ę¤œē“¢åŒ…å«ćƒ‘ć‚æćƒ¼ćƒ³ć‚’č”Øē¤ŗ", + "previousSearchIncludePattern": "å‰ć®ę¤œē“¢åŒ…å«ćƒ‘ć‚æćƒ¼ćƒ³ć‚’č”Øē¤ŗ", + "nextSearchExcludePattern": "ę¬”ć®ę¤œē“¢é™¤å¤–ćƒ‘ć‚æćƒ¼ćƒ³ć‚’č”Øē¤ŗ", + "previousSearchExcludePattern": "å‰ć®ę¤œē“¢é™¤å¤–ćƒ‘ć‚æćƒ¼ćƒ³ć‚’č”Øē¤ŗ", "nextSearchTerm": "ę¬”ć®ę¤œē“¢čŖžå„ć‚’č”Øē¤ŗ", "previousSearchTerm": "å‰ć®ę¤œē“¢čŖžå„ć‚’č”Øē¤ŗ", "focusNextInputBox": "ę¬”ć®å…„åŠ›ćƒœćƒƒć‚Æć‚¹ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", "focusPreviousInputBox": "å‰ć®å…„åŠ›ćƒœćƒƒć‚Æć‚¹ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", + "showSearchViewlet": "検瓢の蔨示", + "findInFiles": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ęŒ‡å®šć—ć¦ę¤œē“¢", "replaceInFiles": "č¤‡ę•°ć®ćƒ•ć‚”ć‚¤ćƒ«ć§ē½®ę›", "findInWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹å†…ć‚’ę¤œē“¢...", "findInFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼å†…ć‚’ę¤œē“¢...", @@ -15,7 +21,7 @@ "ClearSearchResultsAction.label": "ę¤œē“¢ēµęžœć®ć‚ÆćƒŖć‚¢", "FocusNextSearchResult.label": "ę¬”ć®ę¤œē“¢ēµęžœć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", "FocusPreviousSearchResult.label": "å‰ć®ę¤œē“¢ēµęžœć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", - "RemoveAction.label": "削除", + "RemoveAction.label": "å“äø‹", "file.replaceAll.label": "ć™ć¹ć¦ē½®ę›", "match.replace.label": "ē½®ę›" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/jpn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 78356e3e0f4..0654fdfc662 100644 --- a/i18n/jpn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "é™¤å¤–ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«", "label.excludes": "ę¤œē“¢é™¤å¤–ćƒ‘ć‚æćƒ¼ćƒ³", "replaceAll.confirmation.title": "ć™ć¹ć¦ē½®ę›", - "replaceAll.confirm.button": "ē½®ę›", + "replaceAll.confirm.button": "ē½®ę›(&&R)", "replaceAll.occurrence.file.message": "{1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć§ {0} ä»¶ć®å‡ŗē¾ē®‡ę‰€ć‚’ '{2}' ć«ē½®ę›ć—ć¾ć—ćŸć€‚", "removeAll.occurrence.file.message": "{1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć§ {0} ä»¶ć®å‡ŗē¾ē®‡ę‰€ć‚’ē½®ę›ć—ć¾ć—ćŸć€‚", "replaceAll.occurrence.files.message": "{1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć§ {0} ä»¶ć®å‡ŗē¾ē®‡ę‰€ć‚’ '{2}' ć«ē½®ę›ć—ć¾ć—ćŸć€‚", @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "{1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć§ {0} ä»¶ć®å‡ŗē¾ē®‡ę‰€ć‚’ '{2}' ć«ē½®ę›ć—ć¾ć™ć‹?", "replaceAll.occurrences.files.confirmation.message": "{1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć§ {0} ä»¶ć®å‡ŗē¾ē®‡ę‰€ć‚’ē½®ę›ć—ć¾ć™ć‹?", "treeAriaLabel": "ę¤œē“¢ēµęžœ", + "searchPathNotFoundError": "ę¤œē“¢ćƒ‘ć‚¹ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“: {0}", "searchMaxResultsWarning": "ēµęžœć‚»ćƒƒćƒˆć«ćÆć™ć¹ć¦ć®äø€č‡“é …ē›®ć®ć‚µćƒ–ć‚»ćƒƒćƒˆć®ćæćŒå«ć¾ć‚Œć¦ć„ć¾ć™ć€‚ć‚ˆć‚Šé™å®šēš„ćŖę¤œē“¢ę”ä»¶ć‚’å…„åŠ›ć—ć¦ć€ę¤œē“¢ēµęžœć‚’ēµžć‚Šč¾¼ć‚“ć§ćć ć•ć„ć€‚", "searchCanceled": "ēµęžœćŒč¦‹ć¤ć‹ć‚‹å‰ć«ę¤œē“¢ćŒå–ć‚Šę¶ˆć•ć‚Œć¾ć—ćŸ - ", "noResultsIncludesExcludes": "'{0}' 恫 '{1}' ć‚’é™¤å¤–ć—ćŸēµęžœćÆć‚ć‚Šć¾ć›ć‚“ - ", "noResultsIncludes": "'{0}' ć«ēµęžœćÆć‚ć‚Šć¾ć›ć‚“ - ", "noResultsExcludes": "'{0}' ć‚’é™¤å¤–ć—ćŸēµęžœćÆć‚ć‚Šć¾ć›ć‚“ć§ć—ćŸ - ", - "noResultsFound": "ēµęžœćÆć‚ć‚Šć¾ć›ć‚“ć€‚ę§‹ęˆć•ć‚ŒćŸé™¤å¤–ć®čØ­å®šć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ - ", + "noResultsFound": "ēµęžœćÆć‚ć‚Šć¾ć›ć‚“ć€‚ę§‹ęˆć•ć‚ŒćŸé™¤å¤–ćØē„”č¦–ć™ć‚‹ćƒ•ć‚”ć‚¤ćƒ«ć®čØ­å®šć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ -", "rerunSearch.message": "ć‚‚ć†äø€åŗ¦ę¤œē“¢ć—ć¦ćć ć•ć„", "rerunSearchInAll.message": "ć™ć¹ć¦ć®ćƒ•ć‚”ć‚¤ćƒ«ć§ć‚‚ć†äø€åŗ¦ę¤œē“¢ć—ć¦ćć ć•ć„", "openSettings.message": "čØ­å®šć‚’é–‹ć", + "openSettings.learnMore": "č©³ē“°ęƒ…å ±", "ariaSearchResultsStatus": "ę¤œē“¢ć«ć‚ˆć‚Š {1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«å†…ć® {0} ä»¶ć®ēµęžœćŒčæ”ć•ć‚Œć¾ć—ćŸ", "search.file.result": "{1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć« {0} ä»¶ć®ēµęžœ", "search.files.result": "{1} å€‹ć®ćƒ•ć‚”ć‚¤ćƒ«ć« {0} ä»¶ć®ēµęžœ", diff --git a/i18n/jpn/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/jpn/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..91bb212b330 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć«ę¬”ć®åå‰ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćÆć‚ć‚Šć¾ć›ć‚“: {0}" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index c3de7d0fb34..cc309b1f286 100644 --- a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "ć‚¹ćƒ‹ćƒšćƒƒćƒˆć®ęŒæå…„" + "snippet.suggestions.label": "ć‚¹ćƒ‹ćƒšćƒƒćƒˆć®ęŒæå…„", + "sep.userSnippet": "ćƒ¦ćƒ¼ć‚¶ćƒ¼ ć‚¹ćƒ‹ćƒšćƒƒćƒˆ", + "sep.extSnippet": "ę‹”å¼µę©Ÿčƒ½ć®ć‚¹ćƒ‹ćƒšćƒƒćƒˆ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index dcf5681cf72..247f01f3cea 100644 --- a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "`contributes.{0}.language` ć§äøę˜ŽćŖčØ€čŖžć§ć™ć€‚ęä¾›ć•ć‚ŒćŸå€¤: {1}", + "invalid.path.0": "`contributes.{0}.path` ć«ę–‡å­—åˆ—ćŒåæ…č¦ć§ć™ć€‚ęä¾›ć•ć‚ŒćŸå€¤: {1}", + "invalid.path.1": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ ({2}) の中に `contributes.{0}.path` ({1}) ćŒå«ć¾ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ć“ć‚Œć«ć‚ˆć‚Šę‹”å¼µć‚’ē§»ę¤ć§ććŖććŖć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚", + "vscode.extension.contributes.snippets": "ć‚¹ćƒ‹ćƒšćƒƒćƒˆć‚’ęä¾›ć—ć¾ć™ć€‚", + "vscode.extension.contributes.snippets-language": "ć“ć®ć‚¹ćƒ‹ćƒšćƒƒćƒˆć®ęä¾›å…ˆć®čØ€čŖžč­˜åˆ„å­ć§ć™ć€‚", + "vscode.extension.contributes.snippets-path": "ć‚¹ćƒ‹ćƒšćƒƒćƒˆ ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹ć€‚ę‹”å¼µę©Ÿčƒ½ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ē›øåÆ¾ćƒ‘ć‚¹ć§ć‚ć‚Šć€é€šåøø './snippets/' ć§å§‹ć¾ć‚Šć¾ć™ć€‚", + "badVariableUse": "ę‹”å¼µę©Ÿčƒ½ '{0}' 恮 1 ć¤ć¾ćŸćÆč¤‡ę•°ć®ć‚¹ćƒ‹ćƒšćƒƒćƒˆćÆć€ć‚¹ćƒ‹ćƒšćƒƒćƒˆå¤‰ę•°ćØć‚¹ćƒ‹ćƒšćƒƒćƒˆ ćƒ—ćƒ¬ćƒ¼ć‚¹ ćƒ›ćƒ«ćƒ€ćƒ¼ć‚’ę··ä¹±ć•ć›ć‚‹åÆčƒ½ę€§ćŒéžåøøć«ć‚ć‚Šć¾ć™ć€‚ (詳瓰については、 https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax ć‚’å‚ē…§ć—ć¦ćć ć•ć„)", + "badFile": "ć‚¹ćƒ‹ćƒšćƒƒćƒˆ ćƒ•ć‚”ć‚¤ćƒ« \"{0}\"Ā ć‚’čŖ­ćæč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“ć§ć—ćŸć€‚", "source.snippet": "ćƒ¦ćƒ¼ć‚¶ćƒ¼ ć‚¹ćƒ‹ćƒšćƒƒćƒˆ", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 1048a9303ee..745928fd06a 100644 --- a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "ć‚æć‚¹ć‚Æć®å‡ŗåŠ›ć®č”Øē¤ŗćØå…„åŠ›ć®čŖ­ćæå–ć‚Šć«ä½æē”Øć™ć‚‹ć‚ˆć†ć«ćƒ‘ćƒćƒ«ć‚’ę§‹ęˆć—ć¾ć™ć€‚", "JsonSchema.tasks.presentation.echo": "å®Ÿč”Œć•ć‚ŒćŸć‚³ćƒžćƒ³ćƒ‰ćŒćƒ‘ćƒćƒ«ć«ć‚Øć‚³ćƒ¼ć•ć‚Œć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ę—¢å®šćÆ true恧恙怂", "JsonSchema.tasks.presentation.focus": "ćƒ‘ćƒćƒ«ćŒćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć•ć‚Œć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ę—¢å®šćÆ false 恧恙怂true ć«čØ­å®šć—ćŸå “åˆć€ćƒ‘ćƒćƒ«ć‚‚č”Øē¤ŗć•ć‚Œć¾ć™ć€‚", + "JsonSchema.tasks.presentation.reveal.always": "ć‚æć‚¹ć‚Æć‚’å®Ÿč”Œć—ćŸćØćåøøć«ć‚æćƒ¼ćƒŸćƒŠćƒ«ć‚’č”Øē¤ŗć—ć¾ć™ć€‚", + "JsonSchema.tasks.presentation.reveal.silent": "ć‚æć‚¹ć‚Æć«é–¢é€£ä»˜ć‘ć‚‰ć‚ŒćŸå•é”Œćƒžćƒƒćƒćƒ£ćƒ¼ćŒćŖćć€å®Ÿč”Œę™‚ć«ć‚Øćƒ©ćƒ¼ćŒē™ŗē”Ÿć—ćŸå “åˆć®ćæć‚æćƒ¼ćƒŸćƒŠćƒ«ć‚’č”Øē¤ŗć—ć¾ć™ć€‚", + "JsonSchema.tasks.presentation.reveal.never": "ć“ć®ć‚æć‚¹ć‚Æć‚’å®Ÿč”Œć™ć‚‹ćØćć«ć€ä»Šå¾Œć‚æćƒ¼ćƒŸćƒŠćƒ«ć‚’č”Øē¤ŗć—ć¾ć›ć‚“ć€‚", "JsonSchema.tasks.presentation.reveals": "ć‚æć‚¹ć‚Æć‚’å®Ÿč”Œć—ć¦ć„ć‚‹ćƒ‘ćƒćƒ«ć‚’č”Øē¤ŗć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ę—¢å®šćÆ \"always\" 恧恙怂", "JsonSchema.tasks.presentation.instance": "ć‚æć‚¹ć‚Æé–“ć§ćƒ‘ćƒćƒ«ć‚’å…±ęœ‰ć™ć‚‹ć‹ć€ć¾ćŸćÆć“ć®ć‚æć‚¹ć‚Æć§å ęœ‰ć™ć‚‹ć‹ć€å®Ÿč”Œć”ćØć«ę–°ć—ć„ćƒ‘ćƒćƒ«ć‚’ä½œęˆć™ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "JsonSchema.tasks.terminal": "terminal ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćÆéžęŽØå„Øć§ć™ć€‚ä»£ć‚ć‚Šć« presentation ć‚’ć”ä½æē”Øćć ć•ć„", @@ -22,7 +25,8 @@ "JsonSchema.tasks.group.test": "タスクを 'Run Test Task' (ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚Æć®å®Ÿč”Œ) ć‚³ćƒžćƒ³ćƒ‰ć‚’ä»‹ć—ć¦ć‚¢ć‚Æć‚»ć‚¹åÆčƒ½ćŖćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚ÆćØć—ć¦ćƒžćƒ¼ć‚Æć—ć¾ć™ć€‚", "JsonSchema.tasks.group.none": "ć‚æć‚¹ć‚Æć‚’ć‚°ćƒ«ćƒ¼ćƒ—ć«å‰²ć‚Šå½“ć¦ćŖć„", "JsonSchema.tasks.group": "ć“ć®ć‚æć‚¹ć‚ÆćŒå±žć™ć‚‹å®Ÿč”Œć‚°ćƒ«ćƒ¼ćƒ—ć‚’å®šē¾©ć—ć¾ć™ć€‚ćƒ“ćƒ«ćƒ‰ ć‚°ćƒ«ćƒ¼ćƒ—ć«čæ½åŠ ć™ć‚‹ \"build\" ćØćƒ†ć‚¹ćƒˆ ć‚°ćƒ«ćƒ¼ćƒ—ć«čæ½åŠ ć™ć‚‹ \"test\" ć‚’ć‚µćƒćƒ¼ćƒˆć—ć¦ć„ć¾ć™ć€‚", - "JsonSchema.tasks.type": "ć‚æć‚¹ć‚Æć‚’ćƒ—ćƒ­ć‚»ć‚¹ćØć—ć¦å®Ÿč”Œć™ć‚‹ć‹ć€ć¾ćŸćÆć‚·ć‚§ćƒ«å†…éƒØć§ć‚³ćƒžćƒ³ćƒ‰ćØć—ć¦å®Ÿč”Œć™ć‚‹ć‹ć©ć†ć‹ć‚’å®šē¾©ć—ć¾ć™ć€‚ę—¢å®šćÆ process 恧恙怂", + "JsonSchema.tasks.type": "ć‚æć‚¹ć‚Æć‚’ćƒ—ćƒ­ć‚»ć‚¹ćØć—ć¦å®Ÿč”Œć™ć‚‹ć‹ć€ć¾ćŸćÆć‚·ć‚§ćƒ«å†…éƒØć§ć‚³ćƒžćƒ³ćƒ‰ćØć—ć¦å®Ÿč”Œć™ć‚‹ć‹ć©ć†ć‹ć‚’å®šē¾©ć—ć¾ć™ć€‚", + "JsonSchema.tasks.label": "ć‚æć‚¹ć‚Æć®ćƒ¦ćƒ¼ć‚¶ćƒ¼ ć‚¤ćƒ³ć‚æćƒ¼ćƒ•ć‚§ć‚¤ć‚¹ ćƒ©ćƒ™ćƒ«", "JsonSchema.version": "ę§‹ęˆć®ćƒćƒ¼ć‚øćƒ§ćƒ³ē•Ŗå·", "JsonSchema.tasks.identifier": "launch.json または dependsOn å„ć®ć‚æć‚¹ć‚Æć‚’å‚ē…§ć™ć‚‹ćƒ¦ćƒ¼ć‚¶ćƒ¼å®šē¾©ć®č­˜åˆ„å­ć€‚", "JsonSchema.tasks.taskLabel": "ć‚æć‚¹ć‚Æć®ćƒ©ćƒ™ćƒ«", diff --git a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index bec8ad05112..ec353f855bf 100644 --- a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "タスク", - "ConfigureTaskRunnerAction.noWorkspace": "ć‚æć‚¹ć‚ÆćÆćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć§ć®ćæåˆ©ē”ØåÆčƒ½ć§ć™ć€‚", - "ConfigureTaskRunnerAction.quickPick.template": "タスク ćƒ©ćƒ³ćƒŠćƒ¼ć‚’éøęŠž", - "ConfigureTaskRunnerAction.autoDetecting": "{0} ć®ć‚æć‚¹ć‚Æć‚’č‡Ŗå‹•ę¤œå‡ŗ", - "ConfigureTaskRunnerAction.autoDetect": "タスク ć‚·ć‚¹ćƒ†ćƒ ć®č‡Ŗå‹•ę¤œå‡ŗćŒå¤±ę•—ć—ć¾ć—ćŸć€‚ę—¢å®šć®ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć‚’ä½æē”Øć—ć¦ć„ć¾ć™ć€‚č©³ē“°ć«ć¤ć„ć¦ćÆć€ć‚æć‚¹ć‚Æå‡ŗåŠ›ć‚’å‚ē…§ć—ć¦ćć ć•ć„", - "ConfigureTaskRunnerAction.autoDetectError": "タスク ć‚·ć‚¹ćƒ†ćƒ ć®č‡Ŗå‹•ę¤œå‡ŗć§ć‚Øćƒ©ćƒ¼ćŒē™ŗē”Ÿć—ć¾ć—ćŸć€‚č©³ē“°ć«ć¤ć„ć¦ćÆć€ć‚æć‚¹ć‚Æå‡ŗåŠ›ć‚’å‚ē…§ć—ć¦ćć ć•ć„ć€‚", - "ConfigureTaskRunnerAction.failed": "'.vscode' ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼å†…ć« 'tasks.json' ćƒ•ć‚”ć‚¤ćƒ«ć‚’ä½œęˆć§ćć¾ć›ć‚“ć€‚č©³ē“°ć«ć¤ć„ć¦ćÆć€ć‚æć‚¹ć‚Æå‡ŗåŠ›ć‚’å‚ē…§ć—ć¦ćć ć•ć„ć€‚", - "ConfigureTaskRunnerAction.label": "タスク ćƒ©ćƒ³ćƒŠćƒ¼ć®ę§‹ęˆ", + "ConfigureTaskRunnerAction.label": "ć‚æć‚¹ć‚Æć®ę§‹ęˆ", "ConfigureBuildTaskAction.label": "ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚Æć‚’ę§‹ęˆć—ć¾ć™", "CloseMessageAction.label": "閉恘悋", "ShowTerminalAction.label": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®č”Øē¤ŗ", @@ -19,13 +13,17 @@ "manyMarkers": "99+", "runningTasks": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚Æć‚’č”Øē¤ŗ", "tasks": "タスク", - "TaskSystem.noHotSwap": "ć‚æć‚¹ć‚Æå®Ÿč”Œć‚Øćƒ³ć‚øćƒ³ć‚’å¤‰ę›“ć™ć‚‹ć«ćÆ VS Code ć®å†čµ·å‹•ćŒåæ…č¦ć§ć™ć€‚å¤‰ę›“ćÆē„”č¦–ć•ć‚Œć¾ć™ć€‚", + "TaskSystem.noHotSwap": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚æć‚¹ć‚Æć‚’å®Ÿč”Œć—ć¦ć„ć‚‹ć‚æć‚¹ć‚Æå®Ÿč”Œć‚Øćƒ³ć‚øćƒ³ć‚’å¤‰ę›“ć™ć‚‹ć«ćÆć€ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦ć®å†čŖ­ćæč¾¼ćæćŒåæ…č¦ć§ć™", + "TaskServer.folderIgnored": "{0} ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćÆć‚æć‚¹ć‚Æ ćƒćƒ¼ć‚øćƒ§ćƒ³ 0.1.0 ć‚’ä½æē”Øć—ć¦ć„ć‚‹ćŸć‚ć«ē„”č¦–ć•ć‚Œć¾ć™", "TaskService.noBuildTask1": "ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćŒå®šē¾©ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚tasks.json ćƒ•ć‚”ć‚¤ćƒ«ć§ć‚æć‚¹ć‚Æć« 'isBuildCommand' ćØć„ć†ćƒžćƒ¼ć‚Æć‚’ä»˜ć‘ć¦ćć ć•ć„ć€‚", "TaskService.noBuildTask2": "ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćŒå®šē¾©ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚tasks.json ćƒ•ć‚”ć‚¤ćƒ«ć§ć‚æć‚¹ć‚Æć« 'build' ć‚°ćƒ«ćƒ¼ćƒ—ćØć—ć¦ćƒžćƒ¼ć‚Æć‚’ä»˜ć‘ć¦ćć ć•ć„ć€‚", "TaskService.noTestTask1": "ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚ÆćŒå®šē¾©ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚tasks.json ćƒ•ć‚”ć‚¤ćƒ«ć§ć‚æć‚¹ć‚Æć« 'isTestCommand' ćØć„ć†ćƒžćƒ¼ć‚Æć‚’ä»˜ć‘ć¦ćć ć•ć„ć€‚", "TaskService.noTestTask2": "ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚ÆćŒå®šē¾©ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚tasks.json ćƒ•ć‚”ć‚¤ćƒ«ć§ć‚æć‚¹ć‚Æć« 'test' ć‚°ćƒ«ćƒ¼ćƒ—ćØć—ć¦ćƒžćƒ¼ć‚Æć‚’ä»˜ć‘ć¦ćć ć•ć„ć€‚", "TaskServer.noTask": "å®Ÿč”ŒćŒč¦ę±‚ć•ć‚ŒćŸć‚æć‚¹ć‚Æ {0} ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć€‚", + "TaskService.associate": "関連", "TaskService.attachProblemMatcher.continueWithout": "ć‚æć‚¹ć‚Æć®å‡ŗåŠ›ć‚’ć‚¹ć‚­ćƒ£ćƒ³ć›ćšć«ē¶šč”Œ", + "TaskService.attachProblemMatcher.never": "ä»Šå¾Œć“ć®ć‚æć‚¹ć‚Æć®å‡ŗåŠ›ć‚’ć‚¹ć‚­ćƒ£ćƒ³ć—ćŖć„", + "TaskService.attachProblemMatcher.learnMoreAbout": "ć‚æć‚¹ć‚Æå‡ŗåŠ›ć®ć‚¹ć‚­ćƒ£ćƒ³ć«ć¤ć„ć¦ć®č©³ē“°", "selectProblemMatcher": "ć‚¹ć‚­ćƒ£ćƒ³ć™ć‚‹ć‚æć‚¹ć‚Æå‡ŗåŠ›ć®ć‚Øćƒ©ćƒ¼ćØč­¦å‘Šć®ēØ®é”žć‚’éøęŠž", "customizeParseErrors": "ē¾åœØć®ć‚æć‚¹ć‚Æć®ę§‹ęˆć«ćÆć‚Øćƒ©ćƒ¼ćŒć‚ć‚Šć¾ć™ć€‚ć‚æć‚¹ć‚Æć‚’ć‚«ć‚¹ć‚æćƒžć‚¤ć‚ŗć™ć‚‹å‰ć«ć‚Øćƒ©ćƒ¼ć‚’äæ®ę­£ć—ć¦ćć ć•ć„ć€‚", "moreThanOneBuildTask": "tasks.json ć§č¤‡ę•°ć®ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćŒå®šē¾©ć•ć‚Œć¦ć„ć¾ć™ć€‚ęœ€åˆć®ć‚æć‚¹ć‚Æć®ćæć‚’å®Ÿč”Œć—ć¾ć™ć€‚\\n", @@ -33,7 +31,9 @@ "TaskSystem.activeSame.noBackground": "'{0}' ć‚æć‚¹ć‚ÆćÆę—¢ć«ć‚¢ć‚Æćƒ†ć‚£ćƒ–ć§ć™ć€‚ć‚æć‚¹ć‚Æć‚’ēµ‚äŗ†ć™ć‚‹ć«ćÆć‚æć‚¹ć‚ÆĀ ćƒ”ćƒ‹ćƒ„ćƒ¼ć‹ć‚‰`タスクの終了...` ć‚’ä½æē”Øć—ć¦ćć ć•ć„ć€‚ ", "TaskSystem.active": "ę—¢ć«å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚ÆćŒć‚ć‚Šć¾ć™ć€‚ć¾ćšć“ć®ć‚æć‚¹ć‚Æć‚’ēµ‚äŗ†ć—ć¦ć‹ć‚‰ć€åˆ„ć®ć‚æć‚¹ć‚Æć‚’å®Ÿč”Œć—ć¦ćć ć•ć„ć€‚", "TaskSystem.restartFailed": "タスク {0} ć‚’ēµ‚äŗ†ć—ć¦å†é–‹ć§ćć¾ć›ć‚“ć§ć—ćŸ", + "TaskService.noConfiguration": "ć‚Øćƒ©ćƒ¼: {0} ć‚æć‚¹ć‚Æę¤œå‡ŗćÆę¬”ć®ę§‹ęˆć«åÆ¾ć—ć¦ć‚æć‚¹ć‚Æć‚’ęä¾›ć—ć¦ć„ć¾ć›ć‚“:\n{1}\nć“ć®ć‚æć‚¹ć‚ÆćÆē„”č¦–ć•ć‚Œć¾ć™ć€‚\n", "TaskSystem.configurationErrors": "ć‚Øćƒ©ćƒ¼: ęŒ‡å®šć—ćŸć‚æć‚¹ć‚Æę§‹ęˆć«ę¤œčØ¼ć‚Øćƒ©ćƒ¼ćŒć‚ć‚Šć€ä½æē”Øć§ćć¾ć›ć‚“ć€‚ęœ€åˆć«ć‚Øćƒ©ćƒ¼ć‚’äæ®ę­£ć—ć¦ćć ć•ć„ć€‚", + "taskService.ignoreingFolder": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ {0} ć®ć‚æć‚¹ć‚Æę§‹ęˆć‚’ē„”č¦–ć—ć¾ć™ć€‚ćƒžćƒ«ćƒ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ć‚æć‚¹ć‚Æć®ć‚µćƒćƒ¼ćƒˆć«ćÆć€ć™ć¹ć¦ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćŒć‚æć‚¹ć‚Æ ćƒćƒ¼ć‚øćƒ§ćƒ³ 2.0.0 ć‚’ä½æē”Øć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚\n", "TaskSystem.invalidTaskJson": "ć‚Øćƒ©ćƒ¼: tasks.json ćƒ•ć‚”ć‚¤ćƒ«ć®å†…å®¹ć«ę§‹ę–‡ć‚Øćƒ©ćƒ¼ćŒć‚ć‚Šć¾ć™ć€‚čØ‚ę­£ć—ć¦ć‹ć‚‰ć‚æć‚¹ć‚Æć‚’å®Ÿč”Œć—ć¦ćć ć•ć„ć€‚\n", "TaskSystem.runningTask": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚ÆćŒć‚ć‚Šć¾ć™ć€‚ēµ‚äŗ†ć—ć¾ć™ć‹?", "TaskSystem.terminateTask": "タスクの終了(&&T)", @@ -45,24 +45,33 @@ "recentlyUsed": "ęœ€čæ‘ä½æē”Øć—ćŸć‚æć‚¹ć‚Æ", "configured": "ę§‹ęˆęøˆćæć®ć‚æć‚¹ć‚Æ", "detected": "ę¤œå‡ŗć•ć‚ŒćŸć‚æć‚¹ć‚Æ", + "TaskService.ignoredFolder": "ę¬”ć®ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćÆć‚æć‚¹ć‚Æ ćƒćƒ¼ć‚øćƒ§ćƒ³ 0.1.0 ć‚’ä½æē”Øć—ć¦ć„ć‚‹ćŸć‚ć«ē„”č¦–ć•ć‚Œć¾ć™:", + "TaskService.notAgain": "ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", + "TaskService.ok": "OK", + "TaskService.pickRunTask": "å®Ÿč”Œć™ć‚‹ć‚æć‚¹ć‚Æć‚’éøęŠžć—ć¦ćć ć•ć„", + "TaslService.noEntryToRun": "å®Ÿč”Œć™ć‚‹ć‚æć‚¹ć‚ÆćŒć‚ć‚Šć¾ć›ć‚“ć€‚ć‚æć‚¹ć‚Æć‚’ę§‹ęˆć™ć‚‹...", "TaskService.fetchingBuildTasks": "ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚Æć‚’ćƒ•ć‚§ćƒƒćƒć—ć¦ć„ć¾ć™...", - "TaskService.noBuildTaskTerminal": "ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć€‚å®šē¾©ć™ć‚‹ć«ćÆ 'Configure Build Task' (ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚Æć‚’ę§‹ęˆć—ć¾ć™) ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚", "TaskService.pickBuildTask": "å®Ÿč”Œć™ć‚‹ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚Æć‚’éøęŠž", + "TaskService.noBuildTask": "å®Ÿč”Œć™ć‚‹ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćŒć‚ć‚Šć¾ć›ć‚“ć€‚ć‚æć‚¹ć‚Æć‚’ę§‹ęˆć™ć‚‹... ", "TaskService.fetchingTestTasks": "ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚Æć‚’ćƒ•ć‚§ćƒƒćƒć—ć¦ć„ć¾ć™...", - "TaskService.noTestTaskTerminal": "ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚ÆćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć€‚å®šē¾©ć™ć‚‹ć«ćÆ 'Configure Build Task' (タスク ćƒ©ćƒ³ćƒŠćƒ¼ć®ę§‹ęˆ) ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚", "TaskService.pickTestTask": "å®Ÿč”Œć™ć‚‹ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚Æć‚’éøęŠžć—ć¦ćć ć•ć„", - "TaskService.noTaskRunning": "ē¾åœØå®Ÿč”Œäø­ć®ć‚æć‚¹ć‚ÆćÆć‚ć‚Šć¾ć›ć‚“ć€‚", + "TaskService.noTestTaskTerminal": "å®Ÿč”Œć™ć‚‹ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚ÆćŒć‚ć‚Šć¾ć›ć‚“ć€‚ć‚æć‚¹ć‚Æć‚’ę§‹ęˆć™ć‚‹... ", "TaskService.tastToTerminate": "ēµ‚äŗ†ć™ć‚‹ć‚æć‚¹ć‚Æć‚’éøęŠž", + "TaskService.noTaskRunning": "ē¾åœØå®Ÿč”Œäø­ć®ć‚æć‚¹ć‚ÆćÆć‚ć‚Šć¾ć›ć‚“", "TerminateAction.noProcess": "čµ·å‹•ć—ćŸćƒ—ćƒ­ć‚»ć‚¹ćÆę—¢ć«å­˜åœØć—ć¾ć›ć‚“ć€‚ć‚æć‚¹ć‚Æć‚’čµ·å‹•ć—ćŸćƒćƒƒć‚Æć‚°ćƒ©ć‚¦ćƒ³ćƒ‰ ć‚æć‚¹ć‚ÆćŒ VS ć‚³ćƒ¼ćƒ‰ć§ēµ‚äŗ†ć™ć‚‹ćØć€ćƒ—ćƒ­ć‚»ć‚¹ćŒå­¤ē«‹ć™ć‚‹ć“ćØćŒć‚ć‚Šć¾ć™ć€‚", "TerminateAction.failed": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚Æć®ēµ‚äŗ†ć«å¤±ę•—ć—ć¾ć—ćŸ", - "TaskService.noTaskToRestart": "å†čµ·å‹•ć™ć‚‹ć‚æć‚¹ć‚ÆćŒć‚ć‚Šć¾ć›ć‚“ć€‚", "TaskService.tastToRestart": "å†čµ·å‹•ć™ć‚‹ć‚æć‚¹ć‚Æć‚’éøęŠžć—ć¦ćć ć•ć„", - "TaskService.defaultBuildTaskExists": "{0} ćÆę—¢ć«ę—¢å®šć®ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćØć—ć¦ćƒžćƒ¼ć‚Æć•ć‚Œć¦ć„ć¾ć™ć€‚", + "TaskService.noTaskToRestart": "å†čµ·å‹•ć™ć‚‹ć‚æć‚¹ć‚ÆćŒć‚ć‚Šć¾ć›ć‚“", + "TaskService.template": "タスク ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć‚’éøęŠž", + "TaskService.createJsonFile": "ćƒ†ćƒ³ćƒ—ćƒ¬ćƒ¼ćƒˆć‹ć‚‰ tasks.json ć‚’ē”Ÿęˆ", + "TaskService.openJsonFile": "tasks.json ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", + "TaskService.pickTask": "ę§‹ęˆć™ć‚‹ć‚æć‚¹ć‚Æć‚’éøęŠž", + "TaskService.defaultBuildTaskExists": "{0} ćÆę—¢ć«ę—¢å®šć®ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćØć—ć¦ćƒžćƒ¼ć‚Æć•ć‚Œć¦ć„ć¾ć™", "TaskService.pickDefaultBuildTask": "ę—¢å®šć®ćƒ“ćƒ«ćƒ‰ ć‚æć‚¹ć‚ÆćØć—ć¦ä½æē”Øć™ć‚‹ć‚æć‚¹ć‚Æć‚’éøęŠž", "TaskService.defaultTestTaskExists": "{0} ćÆę—¢ć«ę—¢å®šć®ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚ÆćØć—ć¦ćƒžćƒ¼ć‚Æć•ć‚Œć¦ć„ć¾ć™ć€‚", "TaskService.pickDefaultTestTask": "ę—¢å®šć®ćƒ†ć‚¹ćƒˆ ć‚æć‚¹ć‚ÆćØć—ć¦ä½æē”Øć™ć‚‹ć‚æć‚¹ć‚Æć‚’éøęŠž", - "TaskService.noTaskIsRunning": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚ÆćÆć‚ć‚Šć¾ć›ć‚“ć€‚", "TaskService.pickShowTask": "å‡ŗåŠ›ć‚’č”Øē¤ŗć™ć‚‹ć‚æć‚¹ć‚Æć‚’éøęŠž", + "TaskService.noTaskIsRunning": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚ÆćÆć‚ć‚Šć¾ć›ć‚“", "ShowLogAction.label": "タスク ćƒ­ć‚°ć®č”Øē¤ŗ", "RunTaskAction.label": "ć‚æć‚¹ć‚Æć®å®Ÿč”Œ", "RestartTaskAction.label": "å®Ÿč”Œäø­ć®ć‚æć‚¹ć‚Æć®å†čµ·å‹•", diff --git a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 40f8e647676..0fe8ccee4c6 100644 --- a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "ć‚æć‚¹ć‚Æć®å®Ÿč”Œäø­ć«äøę˜ŽćŖć‚Øćƒ©ćƒ¼ćŒē™ŗē”Ÿć—ć¾ć—ćŸć€‚č©³ē“°ć«ć¤ć„ć¦ćÆć€ć‚æć‚¹ć‚Æå‡ŗåŠ›ćƒ­ć‚°ć‚’å‚ē…§ć—ć¦ćć ć•ć„ć€‚", + "dependencyFailed": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ '{1}' å†…ć§ä¾å­˜ć‚æć‚¹ć‚Æć® '{0}' ć‚’č§£ę±ŗć§ćć¾ć›ć‚“ć§ć—ćŸ", "TerminalTaskSystem.terminalName": "タスク - {0}", - "reuseTerminal": "ē«Æęœ«ćÆć‚æć‚¹ć‚Æć§å†åˆ©ē”Øć•ć‚Œć¾ć™ć€é–‰ć˜ć‚‹ć«ćÆä»»ę„ć®ć‚­ćƒ¼ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚", + "reuseTerminal": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ćÆć‚æć‚¹ć‚Æć§å†åˆ©ē”Øć•ć‚Œć¾ć™ć€é–‰ć˜ć‚‹ć«ćÆä»»ę„ć®ć‚­ćƒ¼ć‚’ęŠ¼ć—ć¦ćć ć•ć„ć€‚", "TerminalTaskSystem": "UNC ćƒ‰ćƒ©ć‚¤ćƒ–ć§ć‚·ć‚§ćƒ« ć‚³ćƒžćƒ³ćƒ‰ć‚’å®Ÿč”Œć§ćć¾ć›ć‚“ć€‚", "unkownProblemMatcher": "å•é”Œćƒžćƒƒćƒćƒ£ćƒ¼ {0} ćÆč§£ę±ŗć§ćć¾ć›ć‚“ć§ć—ćŸć€‚ćƒžćƒƒćƒćƒ£ćƒ¼ćÆē„”č¦–ć•ć‚Œć¾ć™" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/jpn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index 787ca113029..ac618cfa97a 100644 --- a/i18n/jpn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,6 +11,8 @@ "ConfigurationParser.unknownMatcherKind": "č­¦å‘Š: å®šē¾©ć•ć‚Œć¦ć„ć‚‹å•é”Œćƒžćƒƒćƒćƒ£ćƒ¼ćŒäøę˜Žć§ć™ć€‚ć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć‚‹åž‹ćÆ string | ProblemMatcher | (string | ProblemMatcher)[] 恧恙怂\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "ć‚Øćƒ©ćƒ¼: ę­£ć—ććŖć„ problemMatcher å‚ē…§ {0}\n", "ConfigurationParser.noTaskType": "ć‚Øćƒ©ćƒ¼: ć‚æć‚¹ć‚Æć®ę§‹ęˆć«ćÆ type ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćŒåæ…č¦ć§ć™ć€‚ć“ć®ę§‹ęˆćÆē„”č¦–ć•ć‚Œć¾ć™ć€‚\n{0}\n", + "ConfigurationParser.noTypeDefinition": "Error: タスク ć‚æć‚¤ćƒ— '{0}' ćÆē™»éŒ²ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚åÆ¾åæœć™ć‚‹ć‚æć‚¹ć‚Æ ćƒ—ćƒ­ćƒć‚¤ćƒ€ćƒ¼ć‚’ęä¾›ć™ć‚‹ę‹”å¼µę©Ÿčƒ½ć‚’ć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć—ć¾ć—ćŸć‹?", + "ConfigurationParser.missingRequiredProperty": "ć‚Øćƒ©ćƒ¼: ć‚æć‚¹ć‚Æę§‹ęˆ '{0}' に必要な '{1}' ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćŒć‚ć‚Šć¾ć›ć‚“ć€‚ę§‹ęˆćÆē„”č¦–ć•ć‚Œć¾ć™ć€‚Ā ", "ConfigurationParser.notCustom": "ć‚Øćƒ©ćƒ¼: ć‚æć‚¹ć‚ÆćŒć‚«ć‚¹ć‚æćƒ  ć‚æć‚¹ć‚ÆćØć—ć¦å®šē¾©ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚ć“ć®ę§‹ęˆćÆē„”č¦–ć•ć‚Œć¾ć™ć€‚\n{0}\n", "ConfigurationParser.noTaskName": "ć‚Øćƒ©ćƒ¼: ć‚æć‚¹ć‚ÆćŒ taskName ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć‚’ęä¾›ć—ćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“ć€‚ć“ć®ć‚æć‚¹ć‚ÆćÆē„”č¦–ć•ć‚Œć¾ć™ć€‚\n{0}\n", "taskConfiguration.shellArgs": "č­¦å‘Š: タスク '{0}' ćÆć‚·ć‚§ćƒ« ć‚³ćƒžćƒ³ćƒ‰ć§ć™ć€‚ć‚³ćƒžćƒ³ćƒ‰åć¾ćŸćÆå¼•ę•°ć® 1 ć¤ć«ć€ć‚Øć‚¹ć‚±ćƒ¼ćƒ—ć•ć‚Œć¦ć„ćŖć„ć‚¹ćƒšćƒ¼ć‚¹ćŒå«ć¾ć‚Œć¦ć„ć¾ć™ć€‚ć‚³ćƒžćƒ³ćƒ‰ ćƒ©ć‚¤ćƒ³ć®å¼•ē”ØćŒę­£ć—ćč§£é‡ˆć•ć‚Œć‚‹ć‚ˆć†ć«ć€å¼•ę•°ć‚’ć‚³ćƒžćƒ³ćƒ‰ć«ćƒžćƒ¼ć‚øć—ć¦ćć ć•ć„ć€‚", diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index b99e360cd8b..f4845c96a75 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "entryAriaLabel": "{0}ć€ć‚æćƒ¼ćƒŸćƒŠćƒ« ćƒ”ćƒƒć‚«ćƒ¼", + "termEntryAriaLabel": "{0}ć€ć‚æćƒ¼ćƒŸćƒŠćƒ« ćƒ”ćƒƒć‚«ćƒ¼", + "termCreateEntryAriaLabel": "{0} ć€ę–°ć—ć„ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ä½œęˆ", + "'workbench.action.terminal.newplus": "$(plus) ę–°ć—ć„ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ä½œęˆ", "noTerminalsMatching": "äø€č‡“ć™ć‚‹ć‚æćƒ¼ćƒŸćƒŠćƒ«ćŒć‚ć‚Šć¾ć›ć‚“", "noTerminalsFound": "é–‹ć„ć¦ć„ć‚‹ć‚æćƒ¼ćƒŸćƒŠćƒ«ćŒć‚ć‚Šć¾ć›ć‚“" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 16366e22ca2..76dbf9d84f0 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -5,18 +5,19 @@ // Do not edit this file. It is machine generated. { "quickOpen.terminal": "é–‹ć„ć¦ć„ć‚‹ć™ć¹ć¦ć®ć‚æćƒ¼ćƒŸćƒŠćƒ«ć‚’č”Øē¤ŗ", + "terminal": "ć‚æćƒ¼ćƒŸćƒŠćƒ«", "terminalIntegratedConfigurationTitle": "ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«", "terminal.integrated.shell.linux": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ćŒ Linux ć§ä½æē”Øć™ć‚‹ć‚·ć‚§ćƒ«ć®ćƒ‘ć‚¹ć€‚", "terminal.integrated.shellArgs.linux": "Linux ć®ć‚æćƒ¼ćƒŸćƒŠćƒ«ć§ä½æē”Øć™ć‚‹ć‚³ćƒžćƒ³ćƒ‰ ćƒ©ć‚¤ćƒ³å¼•ę•°ć€‚", "terminal.integrated.shell.osx": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ćŒ OS X ć§ä½æē”Øć™ć‚‹ć‚·ć‚§ćƒ«ć®ćƒ‘ć‚¹ć€‚", "terminal.integrated.shellArgs.osx": "OS X ē«Æęœ«ć§ä½æē”Øć™ć‚‹ć‚³ćƒžćƒ³ćƒ‰ ćƒ©ć‚¤ćƒ³å¼•ę•°ć€‚", + "terminal.integrated.shell.windows": "Windows ć§ć‚æćƒ¼ćƒŸćƒŠćƒ«ćŒä½æē”Øć™ć‚‹ć‚·ć‚§ćƒ«ć®ćƒ‘ć‚¹ć€‚ Windows ć«åŒę¢±ć•ć‚Œć¦ć„ć‚‹ć‚·ć‚§ćƒ«ć‚’ä½æē”Øć™ć‚‹å “åˆ (cmd态PowerShellć€ć¾ćŸćÆ Bash on Ubuntu) 怂", "terminal.integrated.shellArgs.windows": "Windows ć‚æćƒ¼ćƒŸćƒŠćƒ«äøŠć®å “åˆć«ä½æē”Øć•ć‚Œć‚‹ć‚³ćƒžćƒ³ćƒ‰ ćƒ©ć‚¤ćƒ³å¼•ę•°ć€‚", "terminal.integrated.rightClickCopyPaste": "čØ­å®šć—ć¦ć„ć‚‹å “åˆć€ć‚æćƒ¼ćƒŸćƒŠćƒ«å†…ć§å³ć‚ÆćƒŖćƒƒć‚Æć—ćŸćØćć«ć‚³ćƒ³ćƒ†ć‚­ć‚¹ćƒˆ ćƒ”ćƒ‹ćƒ„ćƒ¼ć‚’č”Øē¤ŗć•ć›ćšć€éøęŠžēÆ„å›²ćŒć‚ć‚‹å “åˆćÆć‚³ćƒ”ćƒ¼ć€éøęŠžēÆ„å›²ćŒćŖć„å “åˆćÆč²¼ć‚Šä»˜ć‘ć®ę“ä½œć‚’č”Œć„ć¾ć™ć€‚", "terminal.integrated.fontFamily": "ē«Æęœ«ć®ćƒ•ć‚©ćƒ³ćƒˆ ćƒ•ć‚”ćƒŸćƒŖć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ę—¢å®šå€¤ćÆ editor.fontFamily ć«ćŖć‚Šć¾ć™ć€‚", - "terminal.integrated.fontLigatures": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć§ćƒ•ć‚©ćƒ³ćƒˆć®åˆå­—ćŒęœ‰åŠ¹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "terminal.integrated.fontSize": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ćƒ•ć‚©ćƒ³ćƒˆ ć‚µć‚¤ć‚ŗć‚’ćƒ”ć‚Æć‚»ćƒ«å˜ä½ć§åˆ¶å¾”ć—ć¾ć™ć€‚", "terminal.integrated.lineHeight": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®č”Œć®é«˜ć•ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚ć“ć®ę•°å€¤ć«ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ćƒ•ć‚©ćƒ³ćƒˆ ć‚µć‚¤ć‚ŗć‚’ä¹—ē®—ć™ć‚‹ćØć€å®Ÿéš›ć®č”Œć®é«˜ć• (ćƒ”ć‚Æć‚»ćƒ«å˜ä½) ć«ćŖć‚Šć¾ć™ć€‚", - "terminal.integrated.enableBold": "ć‚æćƒ¼ćƒŸćƒŠćƒ«å†…ć§å¤Ŗå­—ć‚’ęœ‰åŠ¹ć«ć™ć‚‹ć‹ć©ć†ć‹ć€‚ć“ć‚Œć«ćÆć‚æćƒ¼ćƒŸćƒŠćƒ«ć‚·ć‚§ćƒ«ć‹ć‚‰ć®ć‚µćƒćƒ¼ćƒˆćŒć²ć¤ć‚ˆć†ć§ć™ć€‚", + "terminal.integrated.enableBold": "ć‚æćƒ¼ćƒŸćƒŠćƒ«å†…ć§ćƒ†ć‚­ć‚¹ćƒˆć‚’å¤Ŗå­—ć«ć™ć‚‹ć‹ć©ć†ć‹ć€‚ć‚æćƒ¼ćƒŸćƒŠćƒ« ć‚·ć‚§ćƒ«ć®ć‚µćƒćƒ¼ćƒˆćŒåæ…č¦ćŖć“ćØć«ę³Øę„ć—ć¦ćć ć•ć„ć€‚", "terminal.integrated.cursorBlinking": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ć‚«ćƒ¼ć‚½ćƒ«ć‚’ē‚¹ę»…ć•ć›ć‚‹ć‹ć©ć†ć‹ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "terminal.integrated.cursorStyle": "ē«Æęœ«ć®ć‚«ćƒ¼ć‚½ćƒ«ć®ć‚¹ć‚æć‚¤ćƒ«ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", "terminal.integrated.scrollback": "ē«Æęœ«ćŒćć®ćƒćƒƒćƒ•ć‚”ćƒ¼ć«äæęŒć§ćć‚‹ęœ€å¤§č”Œę•°ć‚’åˆ¶å¾”ć—ć¾ć™ć€‚", @@ -27,7 +28,6 @@ "terminal.integrated.env.osx": "OS X ć®ć‚æćƒ¼ćƒŸćƒŠćƒ«ć§ä½æē”Øć•ć‚Œć‚‹ VS Code ć®ćƒ—ćƒ­ć‚»ć‚¹ć«čæ½åŠ ć•ć‚Œć‚‹ē’°å¢ƒå¤‰ę•°ć‚’ęŒć¤ć‚Ŗćƒ–ć‚øć‚§ć‚Æćƒˆ", "terminal.integrated.env.linux": "Linux ć®ć‚æćƒ¼ćƒŸćƒŠćƒ«ć§ä½æē”Øć•ć‚Œć‚‹ VS Code ć®ćƒ—ćƒ­ć‚»ć‚¹ć«čæ½åŠ ć•ć‚Œć‚‹ē’°å¢ƒå¤‰ę•°ć‚’ęŒć¤ć‚Ŗćƒ–ć‚øć‚§ć‚Æćƒˆ", "terminal.integrated.env.windows": "Windows ć®ć‚æćƒ¼ćƒŸćƒŠćƒ«ć§ä½æē”Øć•ć‚Œć‚‹ VS Code ć®ćƒ—ćƒ­ć‚»ć‚¹ć«čæ½åŠ ć•ć‚Œć‚‹ē’°å¢ƒå¤‰ę•°ć‚’ęŒć¤ć‚Ŗćƒ–ć‚øć‚§ć‚Æćƒˆ", - "terminal": "ć‚æćƒ¼ćƒŸćƒŠćƒ«", "terminalCategory": "ć‚æćƒ¼ćƒŸćƒŠćƒ«", "viewCategory": "蔨示" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index a046b227b93..6015fb400ae 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,6 +7,7 @@ "workbench.action.terminal.toggleTerminal": "ēµ±åˆć‚æćƒ¼ćƒŸćƒŠćƒ«ć®åˆ‡ć‚Šę›æćˆ", "workbench.action.terminal.kill": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖē«Æęœ«ć‚¤ćƒ³ć‚¹ć‚æćƒ³ć‚¹ć‚’å¼·åˆ¶ēµ‚äŗ†", "workbench.action.terminal.kill.short": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®å¼·åˆ¶ēµ‚äŗ†", + "workbench.action.terminal.quickKill": "ć‚æćƒ¼ćƒŸćƒŠćƒ« ć‚¤ćƒ³ć‚¹ć‚æćƒ³ć‚¹ć®åœę­¢", "workbench.action.terminal.copySelection": "éøęŠžå†…å®¹ć®ć‚³ćƒ”ćƒ¼", "workbench.action.terminal.selectAll": "ć™ć¹ć¦éøęŠž", "workbench.action.terminal.deleteWordLeft": "å·¦ć®ę–‡å­—ć‚’å‰Šé™¤", @@ -15,7 +16,6 @@ "workbench.action.terminal.new.short": "ę–°ć—ć„ć‚æćƒ¼ćƒŸćƒŠćƒ«", "workbench.action.terminal.focus": "ē«Æęœ«ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", "workbench.action.terminal.focusNext": "ę¬”ć®ē«Æęœ«ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", - "workbench.action.terminal.focusAtIndex": "ć‚æćƒ¼ćƒŸćƒŠćƒ« {0} ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", "workbench.action.terminal.focusPrevious": "å‰ć®ć‚æćƒ¼ćƒŸćƒŠćƒ«ć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹", "workbench.action.terminal.paste": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚æćƒ¼ćƒŸćƒŠćƒ«ć«č²¼ć‚Šä»˜ć‘", "workbench.action.terminal.DefaultShell": "ę—¢å®šć®ć‚·ć‚§ćƒ«ć®éøęŠž", @@ -35,5 +35,8 @@ "workbench.action.terminal.rename": "åå‰å¤‰ę›“", "workbench.action.terminal.rename.prompt": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®åå‰ć‚’å…„åŠ›ć—ć¦ćć ć•ć„", "workbench.action.terminal.focusFindWidget": "ę¤œē“¢ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆć«ćƒ•ć‚©ćƒ¼ć‚«ć‚¹ć™ć‚‹", - "workbench.action.terminal.hideFindWidget": "ę¤œē“¢ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆć‚’éžč”Øē¤ŗć«ć™ć‚‹" + "workbench.action.terminal.hideFindWidget": "ę¤œē“¢ć‚¦ć‚£ć‚øć‚§ćƒƒćƒˆć‚’éžč”Øē¤ŗć«ć™ć‚‹", + "nextTerminalFindTerm": "ę¬”ć®ę¤œē“¢čŖžå„ć‚’č”Øē¤ŗ", + "previousTerminalFindTerm": "å‰ć®ę¤œē“¢čŖžå„ć‚’č”Øē¤ŗ", + "quickOpenTerm": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚æćƒ¼ćƒŸćƒŠćƒ«ć®åˆ‡ć‚Šę›æćˆ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index b44e4e0fdf7..6cc81e64612 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®å‰ę™Æč‰²ć€‚", "terminalCursor.foreground": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ć‚«ćƒ¼ć‚½ćƒ«å‰ę™Æč‰²ć€‚", "terminalCursor.background": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®ć‚«ćƒ¼ć‚½ćƒ«ć®čƒŒę™Æč‰²ć€‚ćƒ–ćƒ­ćƒƒć‚Æć‚«ćƒ¼ć‚½ćƒ«ć§é‡ć­ćŸę–‡å­—ć®č‰²ć‚’ć‚«ć‚¹ć‚æćƒžć‚¤ć‚ŗć§ćć¾ć™ć€‚", + "terminal.selectionBackground": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć®éøęŠžēÆ„å›²ć®čƒŒę™Æč‰²ć€‚", "terminal.ansiColor": "ć‚æćƒ¼ćƒŸćƒŠćƒ«ć® '{0}' ANSI ć‚«ćƒ©ćƒ¼ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 0c5802f9502..acbc00bf882 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "ć‚³ćƒ”ćƒ¼", - "createNewTerminal": "ę–°ć—ć„ć‚æćƒ¼ćƒŸćƒŠćƒ«", "paste": "č²¼ć‚Šä»˜ć‘", "selectAll": "ć™ć¹ć¦éøęŠž", "clear": "ć‚ÆćƒŖć‚¢" diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 0303f610bb0..42ec3aff619 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "OKć€ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", "terminal.integrated.chooseWindowsShell": "å„Ŗå…ˆć™ć‚‹ć‚æćƒ¼ćƒŸćƒŠćƒ« ć‚·ć‚§ćƒ«ć‚’éøęŠžć—ć¾ć™ć€‚ć“ć‚ŒćÆå¾Œć§čØ­å®šć‹ć‚‰å¤‰ę›“ć§ćć¾ć™", "terminalService.terminalCloseConfirmationSingular": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚æćƒ¼ćƒŸćƒŠćƒ« ć‚»ćƒƒć‚·ćƒ§ćƒ³ćŒ 1 ć¤ć‚ć‚Šć¾ć™ć€‚äø­ę­¢ć—ć¾ć™ć‹?", - "terminalService.terminalCloseConfirmationPlural": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚æćƒ¼ćƒŸćƒŠćƒ« ć‚»ćƒƒć‚·ćƒ§ćƒ³ćŒ {0} å€‹ć‚ć‚Šć¾ć™ć€‚äø­ę­¢ć—ć¾ć™ć‹?", - "yes": "はい" + "terminalService.terminalCloseConfirmationPlural": "ć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖć‚æćƒ¼ćƒŸćƒŠćƒ« ć‚»ćƒƒć‚·ćƒ§ćƒ³ćŒ {0} å€‹ć‚ć‚Šć¾ć™ć€‚äø­ę­¢ć—ć¾ć™ć‹?" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 01396d39cfb..5007e4d58ae 100644 --- a/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,6 +14,7 @@ "licenseChanged": "ćƒ©ć‚¤ć‚»ćƒ³ć‚¹ę”é …ćŒå¤‰ę›“ć•ć‚Œć¾ć—ćŸć€‚å†…å®¹ć‚’ć”ē¢ŗčŖćć ć•ć„ć€‚", "license": "ćƒ©ć‚¤ć‚»ćƒ³ć‚¹ć®é–²č¦§", "neveragain": "ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", + "64bitisavailable": "64 惓惃惈 Windows 用の {0} ćŒåˆ©ē”ØåÆčƒ½ć«ćŖć‚Šć¾ć—ćŸļ¼", "learn more": "č©³ē“°ęƒ…å ±", "updateIsReady": "ꖰ恗恄ꛓꖰ {0} ćŒåˆ©ē”ØåÆčƒ½ć§ć™ć€‚", "thereIsUpdateAvailable": "åˆ©ē”ØåÆčƒ½ćŖę›“ę–°ćƒ—ćƒ­ć‚°ćƒ©ćƒ ćŒć‚ć‚Šć¾ć™ć€‚", diff --git a/i18n/jpn/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/jpn/src/vs/workbench/parts/views/browser/views.i18n.json index bac786d4014..77323e2fdd2 100644 --- a/i18n/jpn/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/views/browser/views.i18n.json @@ -5,5 +5,5 @@ // Do not edit this file. It is machine generated. { "viewToolbarAriaLabel": "{0} å€‹ć®ć‚¢ć‚Æć‚·ćƒ§ćƒ³", - "removeView": "ć‚µć‚¤ćƒ‰ ćƒćƒ¼ć‹ć‚‰å‰Šé™¤" + "hideView": "ć‚µć‚¤ćƒ‰ ćƒćƒ¼ć‹ć‚‰éžč”Øē¤ŗ" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 6b8b81bf3c1..fbd940c7d47 100644 --- a/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "開始", "welcomePage.newFile": "ę–°ć—ć„ćƒ•ć‚”ć‚¤ćƒ«", "welcomePage.openFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’é–‹ć...", - "welcomePage.cloneGitRepository": "Git ćƒŖćƒć‚øćƒˆćƒŖć‚’č¤‡č£½...", + "welcomePage.addWorkspaceFolder": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’čæ½åŠ ā€¦", "welcomePage.recent": "ęœ€čæ‘", "welcomePage.moreRecent": "ćć®ä»–", "welcomePage.noRecentFolders": "ęœ€čæ‘ä½æē”Øć—ćŸćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćŖć—", diff --git a/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 6bda9ff5357..0ee74727bf3 100644 --- a/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Azure ę‹”å¼µę©Ÿčƒ½ć®č”Øē¤ŗ", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/jpn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/jpn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 47830f896d2..1fccee043f5 100644 --- a/i18n/jpn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "åÆ¾č©±åž‹ćƒ—ćƒ¬ć‚¤ć‚°ćƒ©ć‚¦ćƒ³ćƒ‰", - "editorWalkThrough.title": "åÆ¾č©±åž‹ćƒ—ćƒ¬ć‚¤ć‚°ćƒ©ć‚¦ćƒ³ćƒ‰" + "editorWalkThrough.title": "åÆ¾č©±åž‹ćƒ—ćƒ¬ć‚¤ć‚°ćƒ©ć‚¦ćƒ³ćƒ‰", + "editorWalkThrough": "åÆ¾č©±åž‹ćƒ—ćƒ¬ć‚¤ć‚°ćƒ©ć‚¦ćƒ³ćƒ‰" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/jpn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..76c3f968a64 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "čØ­å®šć®ę¦‚č¦ć§ć™ć€‚ć“ć®ćƒ©ćƒ™ćƒ«ćÆć€čØ­å®šćƒ•ć‚”ć‚¤ćƒ«ć§ć‚³ćƒ”ćƒ³ćƒˆć®åŒŗåˆ‡ć‚Šę–‡å­—ćØć—ć¦ä½æē”Øć—ć¾ć™ć€‚", + "vscode.extension.contributes.configuration.properties": "ę§‹ęˆć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć®čŖ¬ę˜Žć§ć™ć€‚", + "scope.window.description": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦å›ŗęœ‰ć®ę§‹ęˆć€‚ćƒ¦ćƒ¼ć‚¶ćƒ¼ć¾ćŸćÆćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®šć§ę§‹ęˆć§ćć¾ć™ć€‚", + "scope.resource.description": "ćƒŖć‚½ćƒ¼ć‚¹å›ŗęœ‰ć®ę§‹ęˆć€‚ćƒ¦ćƒ¼ć‚¶ćƒ¼ć€ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć€ć¾ćŸćÆćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®šć§ę§‹ęˆć§ćć¾ć™ć€‚", + "scope.description": "ę§‹ęˆćŒé©ē”Øć•ć‚Œć‚‹ēÆ„å›²ć€‚ ä½æē”ØåÆčƒ½ćŖć‚¹ć‚³ćƒ¼ćƒ—ćÆ `window` と ` resource` 恧恙怂", + "vscode.extension.contributes.configuration": "ę§‹ęˆć®čØ­å®šć‚’ęä¾›ć—ć¾ć™ć€‚", + "invalid.title": "'configuration.title' ćÆć€ę–‡å­—åˆ—ć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", + "vscode.extension.contributes.defaultConfiguration": "čØ€čŖžć”ćØć«ę—¢å®šć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ę§‹ęˆć®čØ­å®šć‚’ęä¾›ć—ć¾ć™ć€‚", + "invalid.properties": "'configuration.properties' ćÆć€ć‚Ŗćƒ–ć‚øć‚§ć‚Æćƒˆć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", + "invalid.allOf": "'configuration.allOf' ćÆéžęŽØå„Øć§ä½æē”Øć§ććŖććŖć‚Šć¾ć™ć€‚ä»£ć‚ć‚Šć« 'configuration'Ā ć‚³ćƒ³ćƒˆćƒŖćƒ“ćƒ„ćƒ¼ć‚·ćƒ§ćƒ³ ćƒć‚¤ćƒ³ćƒˆć«č¤‡ę•°ć®ę§‹ęˆć‚»ć‚Æć‚·ćƒ§ćƒ³ć‚’é…åˆ—ćØć—ć¦ęø”ć—ć¾ć™ć€‚", + "workspaceConfig.folders.description": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć§čŖ­ćæč¾¼ć¾ć‚Œć‚‹ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ćƒŖć‚¹ćƒˆć€‚", + "workspaceConfig.path.description": "ćƒ•ć‚”ć‚¤ćƒ«ćƒ‘ć‚¹ć€‚ä¾‹: `/root/folderA` または `./folderA` ć®ć‚ˆć†ćŖćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚”ć‚¤ćƒ«ć®å “ę‰€ć«åÆ¾ć—ć¦č§£ę±ŗć•ć‚Œć‚‹ē›øåÆ¾ćƒ‘ć‚¹ć€‚", + "workspaceConfig.name.description": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć«ć¤ć‘ć‚‹ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć®åå‰ć€‚", + "workspaceConfig.uri.description": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć® URI", + "workspaceConfig.settings.description": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®š", + "workspaceConfig.extensions.description": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ę‹”å¼µę©Ÿčƒ½", + "unknownWorkspaceProperty": "äøę˜ŽćŖćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ę§‹ęˆć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json index a0d2093c119..60bf4e08cf5 100644 --- a/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,12 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "ę§‹ęˆć®čØ­å®šć‚’ęä¾›ć—ć¾ć™ć€‚", "vscode.extension.contributes.configuration.title": "čØ­å®šć®ę¦‚č¦ć§ć™ć€‚ć“ć®ćƒ©ćƒ™ćƒ«ćÆć€čØ­å®šćƒ•ć‚”ć‚¤ćƒ«ć§ć‚³ćƒ”ćƒ³ćƒˆć®åŒŗåˆ‡ć‚Šę–‡å­—ćØć—ć¦ä½æē”Øć—ć¾ć™ć€‚", "vscode.extension.contributes.configuration.properties": "ę§‹ęˆć®ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć®čŖ¬ę˜Žć§ć™ć€‚", - "invalid.type": "čØ­å®šć™ć‚‹ćØć€'configuration.type' は 'ć‚Ŗćƒ–ć‚øć‚§ć‚Æćƒˆć«čØ­å®šć•ć‚ŒćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“", + "scope.window.description": "ć‚¦ć‚£ćƒ³ćƒ‰ć‚¦å›ŗęœ‰ć®ę§‹ęˆć€‚ćƒ¦ćƒ¼ć‚¶ćƒ¼ć¾ćŸćÆćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®šć§ę§‹ęˆć§ćć¾ć™ć€‚", + "scope.resource.description": "ćƒŖć‚½ćƒ¼ć‚¹å›ŗęœ‰ć®ę§‹ęˆć€‚ćƒ¦ćƒ¼ć‚¶ćƒ¼ć€ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć€ć¾ćŸćÆćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®šć§ę§‹ęˆć§ćć¾ć™ć€‚", + "scope.description": "ę§‹ęˆćŒé©ē”Øć•ć‚Œć‚‹ēÆ„å›²ć€‚ ä½æē”ØåÆčƒ½ćŖć‚¹ć‚³ćƒ¼ćƒ—ćÆ `window` と ` resource` 恧恙怂", + "vscode.extension.contributes.configuration": "ę§‹ęˆć®čØ­å®šć‚’ęä¾›ć—ć¾ć™ć€‚", "invalid.title": "'configuration.title' ćÆć€ę–‡å­—åˆ—ć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", "vscode.extension.contributes.defaultConfiguration": "čØ€čŖžć”ćØć«ę—¢å®šć®ć‚Øćƒ‡ć‚£ć‚æćƒ¼ę§‹ęˆć®čØ­å®šć‚’ęä¾›ć—ć¾ć™ć€‚", "invalid.properties": "'configuration.properties' ćÆć€ć‚Ŗćƒ–ć‚øć‚§ć‚Æćƒˆć§ć‚ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™", - "workspaceConfig.settings.description": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®š" + "invalid.allOf": "'configuration.allOf' ćÆéžęŽØå„Øć§ä½æē”Øć§ććŖććŖć‚Šć¾ć™ć€‚ä»£ć‚ć‚Šć« 'configuration'Ā ć‚³ćƒ³ćƒˆćƒŖćƒ“ćƒ„ćƒ¼ć‚·ćƒ§ćƒ³ ćƒć‚¤ćƒ³ćƒˆć«č¤‡ę•°ć®ę§‹ęˆć‚»ć‚Æć‚·ćƒ§ćƒ³ć‚’é…åˆ—ćØć—ć¦ęø”ć—ć¾ć™ć€‚", + "workspaceConfig.folders.description": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć§čŖ­ćæč¾¼ć¾ć‚Œć‚‹ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ćƒŖć‚¹ćƒˆć€‚", + "workspaceConfig.path.description": "ćƒ•ć‚”ć‚¤ćƒ«ćƒ‘ć‚¹ć€‚ä¾‹: `/root/folderA` または `./folderA` ć®ć‚ˆć†ćŖćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ćƒ•ć‚”ć‚¤ćƒ«ć®å “ę‰€ć«åÆ¾ć—ć¦č§£ę±ŗć•ć‚Œć‚‹ē›øåÆ¾ćƒ‘ć‚¹ć€‚", + "workspaceConfig.name.description": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć«ć¤ć‘ć‚‹ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć®åå‰ć€‚", + "workspaceConfig.uri.description": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć® URI", + "workspaceConfig.settings.description": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®š", + "workspaceConfig.extensions.description": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ę‹”å¼µę©Ÿčƒ½", + "unknownWorkspaceProperty": "äøę˜ŽćŖćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ę§‹ęˆćƒ—ćƒ­ćƒ‘ćƒ†ć‚£" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/jpn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index c3d8ee097dc..5433eec4f35 100644 --- a/i18n/jpn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,28 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "čØ­å®šć‚’é–‹ć", + "openTasksConfiguration": "ć‚æć‚¹ć‚Æę§‹ęˆć‚’é–‹ć", + "openLaunchConfiguration": "čµ·å‹•ę§‹ęˆć‚’é–‹ć", "close": "閉恘悋", - "saveAndRetry": "čØ­å®šć‚’äæå­˜ć—ć¦å†č©¦č”Œ", - "errorInvalidConfiguration": "čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**User Settings** ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", - "errorInvalidConfigurationWorkspace": "čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Workspace Settings** ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", - "errorConfigurationFileDirty": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**User Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", - "errorConfigurationFileDirtyWorkspace": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Workspace Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "open": "čØ­å®šć‚’é–‹ć", + "saveAndRetry": "äæå­˜ć—ć¦å†č©¦č”Œ", + "errorUnknownKey": "{1} ćÆē™»éŒ²ęøˆćæć®ę§‹ęˆć§ćÆćŖć„ćŸć‚ć€{0} ć«ę›øćč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“ć€‚", + "errorInvalidFolderConfiguration": "{0} ćÆćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ćƒŖć‚½ćƒ¼ć‚¹ ć‚¹ć‚³ćƒ¼ćƒ—ć‚’ć‚µćƒćƒ¼ćƒˆć—ć¦ć„ćŖć„ćŸć‚ć€ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼čØ­å®šć«ę›øćč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“ć€‚", + "errorInvalidUserTarget": "{0} ćÆć‚°ćƒ­ćƒ¼ćƒćƒ« ć‚¹ć‚³ćƒ¼ćƒ—ć‚’ć‚µćƒćƒ¼ćƒˆć—ć¦ć„ćŖć„ćŸć‚ć€ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć«ę›øćč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“ć€‚", + "errorInvalidWorkspaceTarget": "{0} ćÆćƒžćƒ«ćƒ ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć§ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ ć‚¹ć‚³ćƒ¼ćƒ—ć‚’ć‚µćƒćƒ¼ćƒˆć—ć¦ć„ćŖć„ćŸć‚ć€ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹čØ­å®šć‚’ę›øćč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“ć€‚", + "errorInvalidFolderTarget": "ćƒŖć‚½ćƒ¼ć‚¹ćŒęŒ‡å®šć•ć‚Œć¦ć„ćŖć„ćŸć‚ć€ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼čØ­å®šć«ę›øćč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“ć€‚", + "errorNoWorkspaceOpened": "é–‹ć„ć¦ć„ć‚‹ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ćŒćŖć„ćŸć‚ć€{0} ć«ę›øćč¾¼ć‚€ć“ćØćŒć§ćć¾ć›ć‚“ć€‚ęœ€åˆć«ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć‚’é–‹ć„ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorInvalidTaskConfiguration": "タスク ćƒ•ć‚”ć‚¤ćƒ«ć«ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Tasks** ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorInvalidLaunchConfiguration": "čµ·å‹•ćƒ•ć‚”ć‚¤ćƒ«ć«ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Launch** ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorInvalidConfiguration": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć«ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**User Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorInvalidConfigurationWorkspace": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹čØ­å®šć«ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Workspace Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorInvalidConfigurationFolder": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼čØ­å®šć«ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**{0}** ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼é…äø‹ć® **Folder Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorTasksConfigurationFileDirty": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€ć‚æć‚¹ć‚Æ ćƒ•ć‚”ć‚¤ćƒ«ć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Tasks Configuration**ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚ ", + "errorLaunchConfigurationFileDirty": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€čµ·å‹•čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Launch Configuration**ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚ ", + "errorConfigurationFileDirty": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**User Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorConfigurationFileDirtyWorkspace": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**Workspace Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorConfigurationFileDirtyFolder": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼čØ­å®šć‚’ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚**{0}** é…äø‹ć® **Folder Settings** ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", "userTarget": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®š", - "workspaceTarget": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®š" + "workspaceTarget": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®čØ­å®š", + "folderTarget": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®čØ­å®š" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/jpn/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/jpn/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..37c4d971a1c --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "ę‹”å¼µę©Ÿčƒ½ćƒ›ć‚¹ćƒˆćŒ 10 ē§’ä»„å†…ć«é–‹å§‹ć•ć‚Œć¾ć›ć‚“ć§ć—ćŸć€‚å…ˆé ­č”Œć§åœę­¢ć—ć¦ć„ć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć€ē¶šč”Œć™ć‚‹ć«ćÆćƒ‡ćƒćƒƒć‚¬ćƒ¼ćŒåæ…č¦ć§ć™ć€‚", + "extensionHostProcess.startupFail": "ę‹”å¼µę©Ÿčƒ½ćƒ›ć‚¹ćƒˆćŒ 10 ē§’ä»„å†…ć«é–‹å§‹ć•ć‚Œć¾ć›ć‚“ć§ć—ćŸć€‚å•é”ŒćŒē™ŗē”Ÿć—ć¦ć„ć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚", + "extensionHostProcess.error": "ę‹”å¼µę©Ÿčƒ½ćƒ›ć‚¹ćƒˆć‹ć‚‰ć®ć‚Øćƒ©ćƒ¼: {0}" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..7d36d86d279 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "{0} ć‚’č§£ęžć§ćć¾ć›ć‚“: {1}怂", + "fileReadFail": "ćƒ•ć‚”ć‚¤ćƒ« {0} ć‚’čŖ­ćæå–ć‚Œć¾ć›ć‚“: {1}怂", + "jsonsParseFail": "{0} または {1} ć‚’č§£ęžć§ćć¾ć›ć‚“ć§ć—ćŸ: {2}怂", + "missingNLSKey": "ć‚­ćƒ¼ {0} ć®ćƒ”ćƒƒć‚»ćƒ¼ć‚øćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸć€‚" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..a4d588df685 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "é–‹ē™ŗč€…ćƒ„ćƒ¼ćƒ«", + "restart": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ›ć‚¹ćƒˆć‚’å†čµ·å‹•", + "extensionHostProcess.crash": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ›ć‚¹ćƒˆćŒäŗˆęœŸć›ćšć«ēµ‚äŗ†ć—ć¾ć—ćŸć€‚", + "extensionHostProcess.unresponsiveCrash": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ›ć‚¹ćƒˆćŒåæœē­”ć—ćŖć„ćŸć‚ēµ‚äŗ†ć—ć¾ć—ćŸć€‚", + "overwritingExtension": "ę‹”å¼µę©Ÿčƒ½ {0} 悒 {1} ć§äøŠę›øćć—ć¦ć„ć¾ć™ć€‚", + "extensionUnderDevelopment": "é–‹ē™ŗć®ę‹”å¼µę©Ÿčƒ½ć‚’ {0} に読み込んでいます" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/jpn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..26fc5404882 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "ćƒ•ć‚”ć‚¤ćƒ«ćÆćƒć‚¤ćƒŠćƒŖć®ć‚ˆć†ćŖć®ć§ć€ćƒ†ć‚­ć‚¹ćƒˆćØć—ć¦é–‹ćć“ćØćŒć§ćć¾ć›ć‚“" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json index 021b92585e2..af58e0c5a88 100644 --- a/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒŖć‚½ćƒ¼ć‚¹ ({0}) ćŒē„”åŠ¹ć§ć™", - "fileIsDirectoryError": "ćƒ•ć‚”ć‚¤ćƒ«ćŒćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć§ć™ ({0})", + "fileIsDirectoryError": "ćƒ•ć‚”ć‚¤ćƒ«ćÆćƒ‡ć‚£ćƒ¬ć‚ÆćƒˆćƒŖć§ć™", "fileNotModifiedError": "ćƒ•ć‚”ć‚¤ćƒ«ćÆę¬”ć®ę™‚ē‚¹ä»„å¾Œć«å¤‰ę›“ć•ć‚Œć¦ć„ć¾ć›ć‚“:", "fileTooLargeError": "é–‹ććƒ•ć‚”ć‚¤ćƒ«ćŒå¤§ćć™ćŽć¾ć™", "fileBinaryError": "ćƒ•ć‚”ć‚¤ćƒ«ćÆćƒć‚¤ćƒŠćƒŖć®ć‚ˆć†ćŖć®ć§ć€ćƒ†ć‚­ć‚¹ćƒˆćØć—ć¦é–‹ćć“ćØćŒć§ćć¾ć›ć‚“", "fileNotFoundError": "ćƒ•ć‚”ć‚¤ćƒ«ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ ({0})", + "fileExists": "ē”Ÿęˆć—ć‚ˆć†ćØć—ć¦ć„ć‚‹ćƒ•ć‚”ć‚¤ćƒ« ({0}) ćÆę—¢ć«å­˜åœØć—ć¦ć„ć¾ć™", "fileMoveConflict": "移動/ć‚³ćƒ”ćƒ¼ć§ćć¾ć›ć‚“ć€‚ē§»å‹•/ć‚³ćƒ”ćƒ¼å…ˆć«ćƒ•ć‚”ć‚¤ćƒ«ćŒę—¢ć«å­˜åœØć—ć¾ć™ć€‚", "unableToMoveCopyError": "移動/ć‚³ćƒ”ćƒ¼ć§ćć¾ć›ć‚“ć€‚ćƒ•ć‚”ć‚¤ćƒ«ćŒå«ć¾ć‚Œć‚‹ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ćŒē½®ćę›ć‚ć‚‹ć“ćØć«ćŖć‚Šć¾ć™ć€‚", "foldersCopyError": "ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć‚’ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹å†…ć«ć‚³ćƒ”ćƒ¼ć§ćć¾ć›ć‚“ć€‚å€‹ć€…ć®ćƒ•ć‚”ć‚¤ćƒ«ć‚’éøęŠžć—ć¦ć‚³ćƒ”ćƒ¼ć—ć¦ćć ć•ć„ć€‚", diff --git a/i18n/jpn/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/jpn/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/jpn/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 4ac14b2ebbc..31dd84eaa5c 100644 --- a/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "ćƒ«ćƒ¼ćƒ«ć®ćƒ•ć‚©ćƒ³ćƒˆ ć‚¹ć‚æć‚¤ćƒ«: 'ę–œä½“'态'太字'态'äø‹ē·š' ć®ć„ćšć‚Œć‹ć¾ćŸćÆć“ć‚Œć‚‰ć®ēµ„ćæåˆć‚ć›", - "schema.colors": "構文の強調蔨示をする色", - "schema.properties.name": "ćƒ«ćƒ¼ćƒ«ć®čŖ¬ę˜Ž", - "schema.tokenColors.path": "tmTheme ćƒ•ć‚”ć‚¤ćƒ«ćøć®ćƒ‘ć‚¹ (ē¾åœØć®ćƒ•ć‚”ć‚¤ćƒ«ćØć®ē›øåÆ¾ćƒ‘ć‚¹)" + "schema.token.settings": "ćƒˆćƒ¼ć‚Æćƒ³ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć€‚", + "schema.token.foreground": "ćƒˆćƒ¼ć‚Æćƒ³ć®å‰ę™Æč‰²ć€‚", + "schema.token.background.warning": "ćƒˆćƒ¼ć‚Æćƒ³ć®čƒŒę™Æč‰²ćÆć€ē¾åœØć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚", + "schema.token.fontStyle": "ćƒ«ćƒ¼ćƒ«ć®ćƒ•ć‚©ćƒ³ćƒˆ ć‚¹ć‚æć‚¤ćƒ«: 'ę–œä½“'态'太字'态'äø‹ē·š' ć®ć„ćšć‚Œć‹ć¾ćŸćÆć“ć‚Œć‚‰ć®ēµ„ćæåˆć‚ć›", + "schema.fontStyle.error": "ćƒ•ć‚©ćƒ³ćƒˆ ć‚¹ć‚æć‚¤ćƒ«ćÆ 'ę–œä½“'态'太字'态'äø‹ē·š'ć‚’ēµ„ćæåˆć‚ć›ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", + "schema.properties.name": "ćƒ«ćƒ¼ćƒ«ć®čŖ¬ę˜Žć€‚", + "schema.properties.scope": "ć“ć®ćƒ«ćƒ¼ćƒ«ć«äø€č‡“ć™ć‚‹ć‚¹ć‚³ćƒ¼ćƒ— ć‚»ćƒ¬ć‚Æć‚æćƒ¼ć€‚", + "schema.tokenColors.path": "tmTheme ćƒ•ć‚”ć‚¤ćƒ«ćøć®ćƒ‘ć‚¹ (ē¾åœØć®ćƒ•ć‚”ć‚¤ćƒ«ćØć®ē›øåÆ¾ćƒ‘ć‚¹)怂", + "schema.colors": "構文の強調蔨示をする色" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index a38d55a5642..335b53c2495 100644 --- a/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "ćƒ•ć‚©ćƒ³ćƒˆć‚’ä½æē”Øć™ć‚‹å “åˆ: ćƒ†ć‚­ć‚¹ćƒˆ ćƒ•ć‚©ćƒ³ćƒˆć«åÆ¾ć™ć‚‹ćƒ•ć‚©ćƒ³ćƒˆć‚µć‚¤ć‚ŗć®å‰²åˆć€‚čØ­å®šć•ć‚Œć¦ć„ćŖć„å “åˆć€ę—¢å®šå€¤ćÆćƒ•ć‚©ćƒ³ćƒˆå®šē¾©ć®ć‚µć‚¤ć‚ŗć«ćŖć‚Šć¾ć™ć€‚", "schema.fontId": "ćƒ•ć‚©ćƒ³ćƒˆć‚’ä½æē”Øć™ć‚‹å “åˆ: ćƒ•ć‚©ćƒ³ćƒˆć® IDć€‚čØ­å®šć•ć‚Œć¦ć„ćŖć„å “åˆć€ę—¢å®šå€¤ćÆęœ€åˆć®ćƒ•ć‚©ćƒ³ćƒˆå®šē¾©ć«ćŖć‚Šć¾ć™ć€‚", "schema.light": "ę˜Žć‚‹ć„é…č‰²ćƒ†ćƒ¼ćƒžć§ć®ćƒ•ć‚”ć‚¤ćƒ« ć‚¢ć‚¤ć‚³ćƒ³ć®ä»»ę„ć®é–¢é€£ä»˜ć‘ć€‚", - "schema.highContrast": "惏悤 ć‚³ćƒ³ćƒˆćƒ©ć‚¹ćƒˆé…č‰²ćƒ†ćƒ¼ćƒžć§ć®ćƒ•ć‚”ć‚¤ćƒ« ć‚¢ć‚¤ć‚³ćƒ³ć®ä»»ę„ć®é–¢é€£ä»˜ć‘ć€‚" + "schema.highContrast": "惏悤 ć‚³ćƒ³ćƒˆćƒ©ć‚¹ćƒˆé…č‰²ćƒ†ćƒ¼ćƒžć§ć®ćƒ•ć‚”ć‚¤ćƒ« ć‚¢ć‚¤ć‚³ćƒ³ć®ä»»ę„ć®é–¢é€£ä»˜ć‘ć€‚", + "schema.hidesExplorerArrows": "ć“ć®ćƒ†ćƒ¼ćƒžćŒć‚¢ć‚Æćƒ†ć‚£ćƒ–ćŖę™‚ć«ć€ć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć®ēŸ¢å°ć‚’éžč”Øē¤ŗć«ć™ć‚‹ć‹ć©ć†ć‹ć‚’ę§‹ęˆć—ć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 782cc7b29de..546df93122c 100644 --- a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "JSON ćƒ†ćƒ¼ćƒž ćƒ•ć‚”ć‚¤ćƒ«ć®č§£ęžäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {0}", "error.invalidformat.colors": "é…č‰²ćƒ†ćƒ¼ćƒž ćƒ•ć‚”ć‚¤ćƒ«ć®č§£ęžäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {0}怂'colors' ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćÆ 'object' åž‹ć§ćÆć‚ć‚Šć¾ć›ć‚“ć€‚", - "error.invalidformat.tokenColors": "é…č‰²ćƒ†ćƒ¼ćƒž ćƒ•ć‚”ć‚¤ćƒ«ć®č§£ęžäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {0}怂'tokenColors' ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ćÆć€é…č‰²ć‚’ęŒ‡å®šć™ć‚‹é…åˆ—ć‹ć€TextMate ćƒ†ćƒ¼ćƒžćƒ•ć‚”ć‚¤ćƒ«ćøć®ćƒ‘ć‚¹ć§ćŖć‘ć‚Œć°ćŖć‚Šć¾ć›ć‚“", + "error.invalidformat.tokenColors": "é…č‰²ćƒ†ćƒ¼ćƒž ćƒ•ć‚”ć‚¤ćƒ«ć‚’č§£ęžäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {0}怂'tokenColors' ćƒ—ćƒ­ćƒ‘ćƒ†ć‚£ć«ćÆé…č‰²ć‚’ęŒ‡å®šć—ćŸé…åˆ—ć€ć¾ćŸćÆ TextMate ćƒ†ćƒ¼ćƒž ćƒ•ć‚”ć‚¤ćƒ«ćøć®ćƒ‘ć‚¹ć‚’ęŒ‡å®šć—ć¦ćć ć•ć„ć€‚", "error.plist.invalidformat": "tmTheme ćƒ•ć‚”ć‚¤ćƒ«ć®č§£ęžäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {0}怂'settings' ćÆé…åˆ—ć§ćÆć‚ć‚Šć¾ć›ć‚“ć€‚", "error.cannotparse": "tmTheme ćƒ•ć‚”ć‚¤ćƒ«ć®č§£ęžäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {0}", "error.cannotload": "tmTheme ćƒ•ć‚”ć‚¤ćƒ« {0} ć®čŖ­ćæč¾¼ćæäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {1}" diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..c985a8de47f --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "TextMate ć®é…č‰²ćƒ†ćƒ¼ćƒžć‚’ęä¾›ć—ć¾ć™ć€‚", + "vscode.extension.contributes.themes.id": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć§ä½æē”Øć•ć‚Œć‚‹ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć® ID怂", + "vscode.extension.contributes.themes.label": "UI ć§č”Øē¤ŗć•ć‚Œć‚‹é…č‰²ćƒ†ćƒ¼ćƒžć®ćƒ©ćƒ™ćƒ«ć€‚", + "vscode.extension.contributes.themes.uiTheme": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®å‘Øå›²ć®č‰²ć‚’å®šē¾©ć™ć‚‹åŸŗęœ¬ćƒ†ćƒ¼ćƒž: 'vs' ćÆę˜Žć‚‹ć„č‰²ć®ćƒ†ćƒ¼ćƒžć§ć€'vs-dark' ćÆęæƒć„č‰²ć®ćƒ†ćƒ¼ćƒžć§ć™ć€‚'hc-black' ćÆęæƒć„č‰²ć®ćƒć‚¤ ć‚³ćƒ³ćƒˆćƒ©ć‚¹ćƒˆć®ćƒ†ćƒ¼ćƒžć§ć™ć€‚", + "vscode.extension.contributes.themes.path": "tmTheme ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹ć€‚ę‹”å¼µę©Ÿčƒ½ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć«åÆ¾ć™ć‚‹ē›øåÆ¾ćƒ‘ć‚¹ć§ć€é€šåøø './themes/themeFile.tmTheme' 恧恙怂", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path` ć«ę–‡å­—åˆ—ćŒåæ…č¦ć§ć™ć€‚ęä¾›ć•ć‚ŒćŸå€¤: {1}", + "invalid.path.1": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ ({2}) の中に `contributes.{0}.path` ({1}) ćŒå«ć¾ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ć“ć‚Œć«ć‚ˆć‚Šę‹”å¼µć‚’ē§»ę¤ć§ććŖććŖć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..26366aa3de6 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "ć‚¢ć‚¤ć‚³ćƒ³ ćƒ•ć‚”ć‚¤ćƒ«ć®č§£ęžäø­ć«å•é”ŒćŒē™ŗē”Ÿć—ć¾ć—ćŸ: {0}" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..b9a14b3199a --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć§ä½æē”Øć•ć‚Œć‚‹ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć® ID怂", + "vscode.extension.contributes.iconThemes.label": "UI ć«č”Øē¤ŗć•ć‚Œć‚‹ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć®ćƒ©ćƒ™ćƒ«ć€‚", + "vscode.extension.contributes.iconThemes.path": "ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć®å®šē¾©ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹ć€‚ć“ć®ćƒ‘ć‚¹ćÆę‹”å¼µćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ē›øåÆ¾ćƒ‘ć‚¹ć§ć‚ć‚Šć€é€šåøøćÆ './icons/awesome-icon-theme.json' 恧恙怂", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path` ć«ę–‡å­—åˆ—ćŒåæ…č¦ć§ć™ć€‚ęä¾›ć•ć‚ŒćŸå€¤: {1}", + "reqid": "`contributes.{0}.id` ć«ę–‡å­—åˆ—ćŒåæ…č¦ć§ć™ć€‚ęä¾›ć•ć‚ŒćŸå€¤: {1}", + "invalid.path.1": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ ({2}) の中に `contributes.{0}.path` ({1}) ćŒå«ć¾ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ć“ć‚Œć«ć‚ˆć‚Šę‹”å¼µć‚’ē§»ę¤ć§ććŖććŖć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index c13ce183204..db40a8ef3c1 100644 --- a/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,30 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "TextMate ć®é…č‰²ćƒ†ćƒ¼ćƒžć‚’ęä¾›ć—ć¾ć™ć€‚", - "vscode.extension.contributes.themes.id": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć§ä½æē”Øć•ć‚Œć‚‹ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć® ID怂", - "vscode.extension.contributes.themes.label": "UI ć§č”Øē¤ŗć•ć‚Œć‚‹é…č‰²ćƒ†ćƒ¼ćƒžć®ćƒ©ćƒ™ćƒ«ć€‚", - "vscode.extension.contributes.themes.uiTheme": "ć‚Øćƒ‡ć‚£ć‚æćƒ¼ć®å‘Øå›²ć®č‰²ć‚’å®šē¾©ć™ć‚‹åŸŗęœ¬ćƒ†ćƒ¼ćƒž: 'vs' ćÆę˜Žć‚‹ć„č‰²ć®ćƒ†ćƒ¼ćƒžć§ć€'vs-dark' ćÆęæƒć„č‰²ć®ćƒ†ćƒ¼ćƒžć§ć™ć€‚'hc-black' ćÆęæƒć„č‰²ć®ćƒć‚¤ ć‚³ćƒ³ćƒˆćƒ©ć‚¹ćƒˆć®ćƒ†ćƒ¼ćƒžć§ć™ć€‚", - "vscode.extension.contributes.themes.path": "tmTheme ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹ć€‚ę‹”å¼µę©Ÿčƒ½ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć«åÆ¾ć™ć‚‹ē›øåÆ¾ćƒ‘ć‚¹ć§ć€é€šåøø './themes/themeFile.tmTheme' 恧恙怂", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć§ä½æē”Øć•ć‚Œć‚‹ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć® ID怂", - "vscode.extension.contributes.iconThemes.label": "UI ć«č”Øē¤ŗć•ć‚Œć‚‹ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć®ćƒ©ćƒ™ćƒ«ć€‚", - "vscode.extension.contributes.iconThemes.path": "ć‚¢ć‚¤ć‚³ćƒ³ ćƒ†ćƒ¼ćƒžć®å®šē¾©ćƒ•ć‚”ć‚¤ćƒ«ć®ćƒ‘ć‚¹ć€‚ć“ć®ćƒ‘ć‚¹ćÆę‹”å¼µćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ē›øåÆ¾ćƒ‘ć‚¹ć§ć‚ć‚Šć€é€šåøøćÆ './icons/awesome-icon-theme.json' 恧恙怂", "migration.completed": "ćƒ¦ćƒ¼ć‚¶ćƒ¼čØ­å®šć«ę–°ć—ć„ćƒ†ćƒ¼ćƒžć®čØ­å®šćŒčæ½åŠ ć•ć‚Œć¾ć—ćŸć€‚{0} ć«åˆ©ē”ØåÆčƒ½ćŖćƒćƒƒć‚Æć‚¢ćƒƒćƒ—ćŒć‚ć‚Šć¾ć™ć€‚", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "`contributes.{0}.path` ć«ę–‡å­—åˆ—ćŒåæ…č¦ć§ć™ć€‚ęä¾›ć•ć‚ŒćŸå€¤: {1}", - "invalid.path.1": "ę‹”å¼µę©Ÿčƒ½ć®ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ ({2}) の中に `contributes.{0}.path` ({1}) ćŒå«ć¾ć‚Œć¦ć„ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚ć“ć‚Œć«ć‚ˆć‚Šę‹”å¼µć‚’ē§»ę¤ć§ććŖććŖć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚", - "reqid": "`contributes.{0}.id` ć«ę–‡å­—åˆ—ćŒåæ…č¦ć§ć™ć€‚ęä¾›ć•ć‚ŒćŸå€¤: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "ćƒÆćƒ¼ć‚Æćƒ™ćƒ³ćƒć§ä½æē”Øć™ć‚‹é…č‰²ćƒ†ćƒ¼ćƒžć‚’ęŒ‡å®šć—ć¾ć™ć€‚", - "colorThemeError": "Theme is unknown or not installed.", + "colorThemeError": "ćƒ†ćƒ¼ćƒžćŒäøę˜Žć€ć¾ćŸćÆć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚", "iconTheme": "ćƒÆćƒ¼ć‚Æćƒ™ćƒ³ćƒć§ä½æē”Øć™ć‚‹ć‚¢ć‚¤ć‚³ćƒ³ć®ćƒ†ćƒ¼ćƒžć‚’ęŒ‡å®šć—ć¾ć™ć€‚'null'Ā ć‚’ęŒ‡å®šć™ć‚‹ćØćƒ•ć‚”ć‚¤ćƒ« ć‚¢ć‚¤ć‚³ćƒ³ćŒč”Øē¤ŗć•ć‚ŒćŖććŖć‚Šć¾ć™ć€‚", - "noIconThemeDesc": "No file icons", - "iconThemeError": "File icon theme is unknown or not installed.", + "noIconThemeDesc": "ćƒ•ć‚”ć‚¤ćƒ« ć‚¢ć‚¤ć‚³ćƒ³ćŒć‚ć‚Šć¾ć›ć‚“", + "iconThemeError": "ćƒ•ć‚”ć‚¤ćƒ« ć‚¢ć‚¤ć‚³ćƒ³ć®ćƒ†ćƒ¼ćƒžćŒäøę˜Žć€ć¾ćŸćÆć‚¤ćƒ³ć‚¹ćƒˆćƒ¼ćƒ«ć•ć‚Œć¦ć„ć¾ć›ć‚“ć€‚", "workbenchColors": "ē¾åœØéøęŠžć—ć¦ć„ć‚‹é…č‰²ćƒ†ćƒ¼ćƒžć§é…č‰²ć‚’äøŠę›øćć—ć¾ć™ć€‚", - "workbenchColors.deprecated": "ć“ć®čØ­å®šćÆć‚‚ć†č©¦éØ“ēš„ćŖć‚‚ć®ć§ćÆćŖćć€åå‰ćŒ 'workbench.colorCustomizations' ć«å¤‰ę›“ć•ć‚Œć¦ć„ć¾ć™", - "workbenchColors.deprecatedDescription": "ä»£ć‚ć‚Šć« 'workbench.colorCustomizations' ć‚’ä½æē”Øć—ć¦ćć ć•ć„", - "editorColors": "ē¾åœØéøęŠžć—ć¦ć„ć‚‹é…č‰²ćƒ†ćƒ¼ćƒžć§é…č‰²ćØćƒ•ć‚©ćƒ³ćƒˆ ć‚¹ć‚æć‚¤ćƒ«ć‚’äøŠę›øćć—ć¾ć™ć€‚" + "editorColors": "ē¾åœØéøęŠžć—ć¦ć„ć‚‹é…č‰²ćƒ†ćƒ¼ćƒžć§é…č‰²ćØćƒ•ć‚©ćƒ³ćƒˆ ć‚¹ć‚æć‚¤ćƒ«ć‚’äøŠę›øćć—ć¾ć™ć€‚", + "editorColors.comments": "ć‚³ćƒ”ćƒ³ćƒˆć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™", + "editorColors.strings": "ę–‡å­—åˆ—ćƒŖćƒ†ćƒ©ćƒ«ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚", + "editorColors.keywords": "ć‚­ćƒ¼ćƒÆćƒ¼ćƒ‰ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚", + "editorColors.numbers": "ę•°å€¤ćƒŖćƒ†ćƒ©ćƒ«ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚", + "editorColors.types": "åž‹å®šē¾©ćØå‚ē…§ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚", + "editorColors.functions": "é–¢ę•°å®šē¾©ćØå‚ē…§ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚", + "editorColors.variables": "å¤‰ę•°å®šē¾©ćØå‚ē…§ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚", + "editorColors.textMateRules": "textmate ćƒ†ćƒ¼ćƒžč¦å‰‡ (高度) ć‚’ä½æć£ć¦ć®č‰²ćØć‚¹ć‚æć‚¤ćƒ«ć‚’čØ­å®šć—ć¾ć™ć€‚" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/jpn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..ec391b0543b --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ę§‹ęˆćƒ•ć‚”ć‚¤ćƒ«ć«ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚ćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć„ć¦ć€ćƒ•ć‚”ć‚¤ćƒ«å†…ć®ć‚Øćƒ©ćƒ¼/č­¦å‘Šć‚’äæ®ę­£ć—ć¦ć‹ć‚‰ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "errorWorkspaceConfigurationFileDirty": "ćƒ•ć‚”ć‚¤ćƒ«ćŒå¤‰ę›“ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ę§‹ęˆćƒ•ć‚”ć‚¤ćƒ«ć«ę›øćč¾¼ć‚ć¾ć›ć‚“ć€‚ćƒ•ć‚”ć‚¤ćƒ«ć‚’äæå­˜ć—ć¦ć‹ć‚‰ć€ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", + "openWorkspaceConfigurationFile": "ćƒÆćƒ¼ć‚Æć‚¹ćƒšćƒ¼ć‚¹ć®ę§‹ęˆćƒ•ć‚”ć‚¤ćƒ«ć‚’é–‹ć", + "close": "閉恘悋", + "enterWorkspace.close": "閉恘悋", + "enterWorkspace.dontShowAgain": "ä»Šå¾ŒćÆč”Øē¤ŗć—ćŖć„", + "enterWorkspace.moreInfo": "č©³ē“°ęƒ…å ±", + "enterWorkspace.prompt": "VS Code ć§ć®č¤‡ę•°ćƒ•ć‚©ćƒ«ćƒ€ćƒ¼ć®ę“ä½œć®č©³ē“°ć€‚" +} \ No newline at end of file diff --git a/i18n/kor/extensions/azure-account/out/azure-account.i18n.json b/i18n/kor/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..c939d0255af --- /dev/null +++ b/i18n/kor/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "복사 ė° ģ—“źø°", + "azure-account.close": "ė‹«źø°", + "azure-account.login": "ė”œź·øģø", + "azure-account.loginFirst": "ė”œź·øģøķ•˜ģ§€ ģ•Šģ•˜ģŠµė‹ˆė‹¤. 먼저 ė”œź·øģøķ•˜ģ„øģš”.", + "azure-account.userCodeFailed": "ģ‚¬ģš©ģž ģ½”ė“œė„¼ ź°€ģ øģ˜¤ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤.", + "azure-account.tokenFailed": "ģž„ģ¹˜ ķ† ķ°ģ„ ģ‚¬ģš©ķ•˜ģ—¬ ķ† ķ°ģ„ ź°€ģ øģ˜¤ėŠ” 중", + "azure-account.tokenFromRefreshTokenFailed": "새딜 고침 ķ† ķ°ģ„ ģ‚¬ģš©ķ•˜ģ—¬ ķ† ķ°ģ„ ź°€ģ øģ˜¤ėŠ” 중" +} \ No newline at end of file diff --git a/i18n/kor/extensions/azure-account/out/extension.i18n.json b/i18n/kor/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..f17dba5f8b8 --- /dev/null +++ b/i18n/kor/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: ė”œź·øģøķ•˜ėŠ” 중...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index c2b4c21ed25..1bd8b2bc3fb 100644 --- a/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/kor/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "예: myFile.txt", - "activeEditorMedium": "예: myFolder/myFile.txt", - "activeEditorLong": "예: /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "예: myFolder1, myFolder2, myFolder3", - "rootPath": "예: /Users/Development/myProject", - "folderName": "예: myFolder", - "folderPath": "예: /Users/Development/myFolder", + "activeEditorShort": "ķŒŒģ¼ ģ“ė¦„ (예: myFile.txt)", + "activeEditorMedium": "ģž‘ģ—… ģ˜ģ—­ ķ“ė” (예: myFolder/myFile.txt) ķŒŒģ¼ģ˜ 경딜", + "activeEditorLong": "(예: /Users/Development/myProject/myFolder/myFile.txt) ķŒŒģ¼ģ˜ 전첓 경딜", + "rootName": "ģž‘ģ—… ģ˜ģ—­ (예넼 들얓 myFolder ė˜ėŠ” myWorkspace)ģ˜ ģ“ė¦„", + "rootPath": "ģž‘ģ—… ģ˜ģ—­ (예: /Users/Development/myWorkspace)ģ˜ ķŒŒģ¼ 경딜", + "folderName": "ģž‘ģ—… ģ˜ģ—­ ķ“ė”ėŠ” ķŒŒģ¼ģ˜ ģ“ė¦„ (예넼 들얓 myFolder)에 ķ¬ķ•Ø ė˜ģ–“", + "folderPath": "ģž‘ģ—… ģ˜ģ—­ ķ“ė”ėŠ” ķŒŒģ¼ģ˜ ķŒŒģ¼ 경딜 (예: /Users/Development/myFolder)에 ķ¬ķ•Ø ė˜ģ–“", "appName": "예: VS Code", "dirty": "ķ™œģ„± ķŽøģ§‘źø°ź°€ ė”ķ‹°ģø 경우 ė”ķ‹° ķ‘œģ‹œźø°", "separator": "ź°’ģ“ ģžˆėŠ” ė³€ģˆ˜ė”œ ė‘˜ėŸ¬ģ‹øģø ź²½ģš°ģ—ė§Œ ķ‘œģ‹œė˜ėŠ” 씰걓부 구분 기호 (' - ')", diff --git a/i18n/kor/extensions/css/package.i18n.json b/i18n/kor/extensions/css/package.i18n.json index a8f1ec46a18..307e44f0902 100644 --- a/i18n/kor/extensions/css/package.i18n.json +++ b/i18n/kor/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "ģž˜ėŖ»ėœ 매개 ė³€ģˆ˜ 수", "css.lint.boxModel.desc": "ķŒØė”© ė˜ėŠ” ķ…Œė‘ė¦¬ė„¼ ģ‚¬ģš©ķ•˜ėŠ” 경우 ė„ˆė¹„ ė˜ėŠ” ė†’ģ“ė„¼ ģ‚¬ģš©ķ•˜ģ§€ ė§ˆģ„øģš”.", "css.lint.compatibleVendorPrefixes.desc": "공급업첓 ꓀련 접두사넼 ģ‚¬ģš©ķ•  경우 다넸 ėŖØė“  공급업첓 ꓀련 ģ†ģ„±ė„ ķ¬ķ•Øķ•©ė‹ˆė‹¤.", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "ģ•Œ 수 ģ—†ėŠ” 공급업첓 ꓀련 ģ†ģ„±ģž…ė‹ˆė‹¤.", "css.lint.vendorPrefix.desc": "공급업첓 ꓀련 접두사넼 ģ‚¬ģš©ķ•  ė•Œ ķ‘œģ¤€ ģ†ģ„±ė„ ķ¬ķ•Øķ•©ė‹ˆė‹¤.", "css.lint.zeroUnits.desc": "0ģ—ėŠ” ė‹Øģœ„ź°€ ķ•„ģš”ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "css.trace.server.desc": "VS Code와 CSS ģ–øģ–“ ģ„œė²„ ź°„ ķ†µģ‹ ģ„ ģ¶”ģ ķ•©ė‹ˆė‹¤.", + "css.validate.title": "CSS ģœ ķšØģ„± 검사 ė° 문제 ģ‹¬ź°ė„ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", "css.validate.desc": "ėŖØė“  ģœ ķšØģ„± 검사 ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "ģž˜ėŖ»ėœ 매개 ė³€ģˆ˜ 수", "less.lint.boxModel.desc": "ķŒØė”© ė˜ėŠ” ķ…Œė‘ė¦¬ė„¼ ģ‚¬ģš©ķ•˜ėŠ” 경우 ė„ˆė¹„ ė˜ėŠ” ė†’ģ“ė„¼ ģ‚¬ģš©ķ•˜ģ§€ ė§ˆģ„øģš”.", "less.lint.compatibleVendorPrefixes.desc": "공급업첓 ꓀련 접두사넼 ģ‚¬ģš©ķ•  경우 다넸 ėŖØė“  공급업첓 ꓀련 ģ†ģ„±ė„ ķ¬ķ•Øķ•©ė‹ˆė‹¤.", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "ģ•Œ 수 ģ—†ėŠ” 공급업첓 ꓀련 ģ†ģ„±ģž…ė‹ˆė‹¤.", "less.lint.vendorPrefix.desc": "공급업첓 ꓀련 접두사넼 ģ‚¬ģš©ķ•  ė•Œ ķ‘œģ¤€ ģ†ģ„±ė„ ķ¬ķ•Øķ•©ė‹ˆė‹¤.", "less.lint.zeroUnits.desc": "0ģ—ėŠ” ė‹Øģœ„ź°€ ķ•„ģš”ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "less.validate.title": "LESS ģœ ķšØģ„± 검사 ė° 문제 ģ‹¬ź°ė„ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", "less.validate.desc": "ėŖØė“  ģœ ķšØģ„± 검사 ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함", + "scss.title": "SCSS(Sass)", "scss.lint.argumentsInColorFunction.desc": "ģž˜ėŖ»ėœ 매개 ė³€ģˆ˜ 수", "scss.lint.boxModel.desc": "ķŒØė”© ė˜ėŠ” ķ…Œė‘ė¦¬ė„¼ ģ‚¬ģš©ķ•˜ėŠ” 경우 ė„ˆė¹„ ė˜ėŠ” ė†’ģ“ė„¼ ģ‚¬ģš©ķ•˜ģ§€ ė§ˆģ„øģš”.", "scss.lint.compatibleVendorPrefixes.desc": "공급업첓 ꓀련 접두사넼 ģ‚¬ģš©ķ•  경우 다넸 ėŖØė“  공급업첓 ꓀련 ģ†ģ„±ė„ ķ¬ķ•Øķ•©ė‹ˆė‹¤.", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "ģ•Œ 수 ģ—†ėŠ” 공급업첓 ꓀련 ģ†ģ„±ģž…ė‹ˆė‹¤.", "scss.lint.vendorPrefix.desc": "공급업첓 ꓀련 접두사넼 ģ‚¬ģš©ķ•  ė•Œ ķ‘œģ¤€ ģ†ģ„±ė„ ķ¬ķ•Øķ•©ė‹ˆė‹¤.", "scss.lint.zeroUnits.desc": "0ģ—ėŠ” ė‹Øģœ„ź°€ ķ•„ģš”ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "scss.validate.title": "SCSS ģœ ķšØģ„± 검사 ė° 문제 ģ‹¬ź°ė„ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", "scss.validate.desc": "ėŖØė“  ģœ ķšØģ„± 검사 ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함", "less.colorDecorators.enable.desc": "ģƒ‰ ė°ģ½”ė ˆģ“ķ„° ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함", "scss.colorDecorators.enable.desc": "ģƒ‰ ė°ģ½”ė ˆģ“ķ„° ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함", - "css.colorDecorators.enable.desc": "ģƒ‰ ė°ģ½”ė ˆģ“ķ„° ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함" + "css.colorDecorators.enable.desc": "ģƒ‰ ė°ģ½”ė ˆģ“ķ„° ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함", + "css.colorDecorators.enable.deprecationMessage": "`css.colorDecorators.enable` ģ„¤ģ •ģ€ `editor.colorDecorators`넼 ģœ„ķ•“ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "scss.colorDecorators.enable.deprecationMessage": "`scss.colorDecorators.enable` ģ„¤ģ •ģ€ `editor.colorDecorators`넼 ģœ„ķ•“ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "less.colorDecorators.enable.deprecationMessage": "`less.colorDecorators.enable` ģ„¤ģ •ģ€ `editor.colorDecorators`넼 ģœ„ķ•“ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/emmet/package.i18n.json b/i18n/kor/extensions/emmet/package.i18n.json index 8b6ad71cd4e..10291752ac2 100644 --- a/i18n/kor/extensions/emmet/package.i18n.json +++ b/i18n/kor/extensions/emmet/package.i18n.json @@ -3,4 +3,51 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "command.wrapWithAbbreviation": "ģ•½ģ–“ė”œ ėž˜ķ•‘", + "command.wrapIndividualLinesWithAbbreviation": "ģ•½ģ–“ė”œ ź°œė³„ 줄 ėž˜ķ•‘", + "command.removeTag": "태그 제거", + "command.updateTag": "태그 ģ—…ė°ģ“ķŠø", + "command.matchTag": "ģ¼ģ¹˜ķ•˜ėŠ” ģŒģœ¼ė”œ ģ“ė™", + "command.balanceIn": "ź· ķ˜•ģžˆź²Œ(ģ•ˆģŖ½ģœ¼ė”œ)", + "command.balanceOut": "ź· ķ˜•ģžˆź²Œ(ė°”ź¹„ģŖ½ģœ¼ė”œ)", + "command.prevEditPoint": "ģ“ģ „ ķŽøģ§‘ 점으딜 ģ“ė™", + "command.nextEditPoint": "ė‹¤ģŒ ķŽøģ§‘ 점으딜 ģ“ė™", + "command.mergeLines": "줄 병합", + "command.selectPrevItem": "ģ“ģ „ ķ•­ėŖ© ģ„ ķƒ", + "command.selectNextItem": "ė‹¤ģŒ ķ•­ėŖ© ģ„ ķƒ", + "command.splitJoinTag": "태그 ė¶„ķ• /ģ”°ģø", + "command.toggleComment": "ģ£¼ģ„ 토글", + "command.evaluateMathExpression": "ģˆ˜ģ‹ ķ‰ź°€", + "command.updateImageSize": "ģ“ėÆøģ§€ 크기 ģ—…ė°ģ“ķŠø", + "command.reflectCSSValue": "CSS ź°’ 반영", + "command.incrementNumberByOne": "1씩 ģ¦ź°€", + "command.decrementNumberByOne": "1씩 ź°ģ†Œ", + "command.incrementNumberByOneTenth": "0.1씩 ģ¦ź°€", + "command.decrementNumberByOneTenth": "0.1씩 ź°ģ†Œ", + "command.incrementNumberByTen": "10씩 ģ¦ź°€", + "command.decrementNumberByTen": "10씩 ź°ģ†Œ", + "emmetSyntaxProfiles": "ģ§€ģ •ėœ 구문에 ėŒ€ķ•œ ķ”„ė”œķ•„ģ„ ģ •ģ˜ķ•˜ź±°ė‚˜ ķŠ¹ģ • ź·œģ¹™ģ“ ķ¬ķ•Øėœ ź³ ģœ ķ•œ ķ”„ė”œķ•„ģ„ ģ‚¬ģš©ķ•˜ģ„øģš”.", + "emmetExclude": "Emmet ģ•½ģ–“ėŠ” ķ™•ģž„ķ•˜ė©“ ģ•ˆ ė˜ėŠ” ģ–øģ–“ģ˜ ė°°ģ—“ģž…ė‹ˆė‹¤.", + "emmetExtensionsPath": "Emmet ķ”„ė”œķ•„ ė° ģ½”ė“œ ģ”°ź°ģ“ ķ¬ķ•Øėœ ķ“ė”ģ˜ ź²½ė”œģž…ė‹ˆė‹¤.'", + "emmetShowExpandedAbbreviation": "ķ™•ģž„ėœ emmet 약얓넼 ģ œģ•ˆģœ¼ė”œ ķ‘œģ‹œķ•©ė‹ˆė‹¤.\n\"inMarkupAndStylesheetFilesOnly\" ģ˜µģ…˜ģ“ html, haml, jade, slim, xml, xsl, css, scss, sass, less ė° stylus에 ģ ģš©ė©ė‹ˆė‹¤.\n\"always\" ģ˜µģ…˜ģ“ ė§ˆķ¬ģ—…/css에 ź“€ź³„ģ—†ģ“ ķŒŒģ¼ģ˜ ėŖØė“  부분에 ģ ģš©ė©ė‹ˆė‹¤.", + "emmetShowAbbreviationSuggestions": "ź°€ėŠ„ķ•œ emmet 약얓넼 ģ œģ•ˆģœ¼ė”œ ķ‘œģ‹œķ•©ė‹ˆė‹¤. ģŠ¤ķƒ€ģ¼ģ‹œķŠøģ—ėŠ” ģ ģš©ė˜ģ§€ ģ•Šź³  emmet.showExpandedAbbreviationģ“ \"never\"딜 ģ„¤ģ •ė˜ģ–“ ģžˆģ„ ė•Œė„ ģ ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "emmetIncludeLanguages": "źø°ė³ø ģ§€ģ›ė˜ģ§€ ģ•ŠėŠ” ģ–øģ–“ģ—ģ„œ emmet 약얓넼 ģ‚¬ģš©ķ•©ė‹ˆė‹¤. 언얓와 emmet 지원 ģ–øģ–“ ģ‚¬ģ“ģ— ė§¤ķ•‘ģ„ ģ¶”ź°€ķ•©ė‹ˆė‹¤.\n예: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "emmet 씰각에 ģ‚¬ģš©ė˜ėŠ” ė³€ģˆ˜", + "emmetTriggerExpansionOnTab": "ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•˜ė©“ emmet ģ•½ģ–“ėŠ” Tab 키넼 ėˆŒė €ģ„ ė•Œ ķ™•ģž„ė©ė‹ˆė‹¤.", + "emmetPreferences": "Emmetģ˜ ģ¼ė¶€ ģž‘ģ—… ė° ķ•“ź²° ķ”„ė”œź·øėžØģ˜ ė™ģž‘ģ„ ģˆ˜ģ •ķ•˜ėŠ” ė° ģ‚¬ģš©ė˜ėŠ” źø°ė³ø ģ„¤ģ •ģž…ė‹ˆė‹¤.", + "emmetPreferencesIntUnit": "ģ •ģˆ˜ ź°’ģ˜ źø°ė³ø ė‹Øģœ„", + "emmetPreferencesFloatUnit": "ė¶€ė™ ģ†Œģˆ˜ģ  ź°’ģ˜ źø°ė³ø ė‹Øģœ„", + "emmetPreferencesCssAfter": "CSS 약얓넼 ķ™•ģž„ķ•  ė•Œ CSS ģ†ģ„±ģ˜ ėģ— ė°°ģ¹˜ķ•  기호", + "emmetPreferencesSassAfter": "Sass ķŒŒģ¼ģ—ģ„œ CSS 약얓넼 ķ™•ģž„ķ•  ė•Œ CSS ģ†ģ„±ģ˜ ėģ— ė°°ģ¹˜ķ•  기호", + "emmetPreferencesStylusAfter": "Stylus ķŒŒģ¼ģ—ģ„œ CSS 약얓넼 ķ™•ģž„ķ•  ė•Œ CSS ģ†ģ„±ģ˜ ėģ— ė°°ģ¹˜ķ•  기호", + "emmetPreferencesCssBetween": "CSS 약얓넼 ķ™•ģž„ķ•  ė•Œ CSS ģ†ģ„± ė° ź°’ ģ‚¬ģ“ģ— ė°°ģ¹˜ķ•  기호", + "emmetPreferencesSassBetween": "Sass ķŒŒģ¼ģ—ģ„œ CSS 약얓넼 ķ™•ģž„ķ•  ė•Œ CSS ģ†ģ„± ė° ź°’ ģ‚¬ģ“ģ— ė°°ģ¹˜ķ•  기호", + "emmetPreferencesStylusBetween": "Stylus ķŒŒģ¼ģ—ģ„œ CSS 약얓넼 ķ™•ģž„ķ•  ė•Œ CSS ģ†ģ„± ė° ź°’ ģ‚¬ģ“ģ— ė°°ģ¹˜ķ•  기호", + "emmetShowSuggestionsAsSnippets": "Trueģ“ė©“ emmet ģ œģ•ˆģ“ ģ½”ė“œ 씰각으딜 ķ‘œģ‹œė˜ė©° editor.snippetSuggestions 설정에 ė”°ė¼ ģ½”ė“œ ģ”°ź°ģ„ 정렬할 수 ģžˆģŠµė‹ˆė‹¤.", + "emmetPreferencesBemElementSeparator": "BEM ķ•„ķ„° ģ‚¬ģš©ģ‹œ ģš”ģ†Œ źµ¬ė¶„ģžė„¼ ķ“ėž˜ģŠ¤ė”œ ģ‚¬ģš©ķ•©ė‹ˆė‹¤.", + "emmetPreferencesBemModifierSeparator": "BEM ķ•„ķ„° ģ‚¬ģš©ģ‹œ ė³€ź²½ėœ źµ¬ė¶„ģžė„¼ ķ“ėž˜ģŠ¤ė”œ ģ‚¬ģš©ķ•©ė‹ˆė‹¤.", + "emmetPreferencesFilterCommentBefore": "ģ½”ė©˜ķŠø ķ•„ķ„°ź°€ 적용 ė ė•Œ ģ½”ė§ØķŠø ķ‘œģ‹œėŠ” ķ•“ė‹¹ėœ ģš”ģ†Œ ģ•žģ— 배치 ķ•“ģ•¼ķ•©ė‹ˆė‹¤.", + "emmetPreferencesFilterCommentAfter": "ģ½”ė©˜ķŠø ķ•„ķ„°ź°€ 적용 ė ė•Œ ģ½”ė§ØķŠø ķ‘œģ‹œėŠ” ķ•“ė‹¹ėœ ģš”ģ†Œ 뒤에 배치 ķ•“ģ•¼ķ•©ė‹ˆė‹¤.", + "emmetPreferencesFilterCommentTrigger": "콤마딜 źµ¬ė¶„ėœ ė¦¬ģŠ¤ķŠøģ˜ ģ†ģ„±ģ€ ģ½”ė©˜ķŠø ķ•„ķ„° ģ•½ģ–“ė”œ ģ”“ģž¬ķ•“ģ•¼ ķ•©ė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/kor/extensions/extension-editing/out/extensionLinter.i18n.json index 8a96502e3a7..f8432086d51 100644 --- a/i18n/kor/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/kor/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "ģ“ėÆøģ§€ėŠ” HTTPS ķ”„ė”œķ† ģ½œģ„ ģ‚¬ģš©ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", "svgsNotValid": "SVGėŠ” ģ˜¬ė°”ė„ø ģ“ėÆøģ§€ ģ†ŒģŠ¤ź°€ ģ•„ė‹™ė‹ˆė‹¤.", "embeddedSvgsNotValid": "ė‚“ģž„ SVGėŠ” ģ˜¬ė°”ė„ø ģ“ėÆøģ§€ ģ†ŒģŠ¤ź°€ ģ•„ė‹™ė‹ˆė‹¤.", - "dataUrlsNotValid": "ė°ģ“ķ„° URLģ€ ģ˜¬ė°”ė„ø ģ“ėÆøģ§€ ģ†ŒģŠ¤ź°€ ģ•„ė‹™ė‹ˆė‹¤." + "dataUrlsNotValid": "ė°ģ“ķ„° URLģ€ ģ˜¬ė°”ė„ø ģ“ėÆøģ§€ ģ†ŒģŠ¤ź°€ ģ•„ė‹™ė‹ˆė‹¤.", + "relativeUrlRequiresHttpsRepository": "ź“€ź³„ķ˜• ģ“ėÆøģ§€ URLģ€ package.json에 HTTPS ķ”„ė”œķ† ģ½œģ“ ģ§€ģ •ėœ ģ €ģž„ģ†Œź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤.", + "relativeIconUrlRequiresHttpsRepository": "ģ•„ģ“ģ½˜ģ€ package.json에 HTTPS ķ”„ė”œķ† ģ½œģ“ ģ§€ģ •ėœ ģ €ģž„ģ†Œź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤.", + "relativeBadgeUrlRequiresHttpsRepository": "ź“€ź³„ķ˜• ė°°ģ§€ URLģ€ package.json에 HTTPS ķ”„ė”œķ† ģ½œģ“ ģ§€ģ •ėœ ģ €ģž„ģ†Œź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/git/out/commands.i18n.json b/i18n/kor/extensions/git/out/commands.i18n.json index 600483c9e09..1e7920f8a21 100644 --- a/i18n/kor/extensions/git/out/commands.i18n.json +++ b/i18n/kor/extensions/git/out/commands.i18n.json @@ -6,21 +6,38 @@ { "tag at": "{0}ģ˜ 태그", "remote branch at": "{0}ģ—ģ„œ 원격 ė¶„źø°", + "create branch": "$(plus) 새 ė¶„źø° ģƒģ„±", "repourl": "ė¦¬ķ¬ģ§€ķ† ė¦¬ URL", "parent": "부모 디렉터리", "cloning": "Git ė¦¬ķ¬ģ§€ķ† ė¦¬ė„¼ ė³µģ œķ•˜ėŠ” 중...", "openrepo": "ė¦¬ķ¬ģ§€ķ† ė¦¬ ģ—“źø°", "proposeopen": "복제된 ė¦¬ķ¬ģ§€ķ† ė¦¬ė„¼ ģ—¬ģ‹œź² ģŠµė‹ˆź¹Œ?", + "init repo": "ė¦¬ķ¬ģ§€ķ† ė¦¬ ģ“ˆźø°ķ™”", + "create repo": "ė¦¬ķ¬ģ§€ķ† ė¦¬ ģ“ˆźø°ķ™”", "HEAD not available": "'{0}'ģ˜ HEAD ė²„ģ „ģ“ ģ—†ģŠµė‹ˆė‹¤.", + "confirm stage files with merge conflicts": "병합 ģ¶©ėŒģ“ ģžˆėŠ” {0} ķŒŒģ¼ģ„ ģŠ¤ķ…Œģ“ģ§•ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "confirm stage file with merge conflicts": "병합 ģ¶©ėŒģ“ ģžˆėŠ” {0}ģ„(넼) ģŠ¤ķ…Œģ“ģ§•ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "yes": "예", "confirm revert": "{0}ģ—ģ„œ ģ„ ķƒķ•œ 변경 ė‚“ģš©ģ„ ė˜ėŒė¦¬ģ‹œź² ģŠµė‹ˆź¹Œ?", "revert": "변경 ė‚“ģš© ė˜ėŒė¦¬źø°", + "discard": "변경 ė‚“ģš© ģ·Øģ†Œ", + "confirm delete": "{0}ģ„(넼) ģ‚­ģ œķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "delete file": "ķŒŒģ¼ ģ‚­ģ œ", "confirm discard": "{0}ģ˜ 변경 ė‚“ģš©ģ„ ģ·Øģ†Œķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", "confirm discard multiple": "{0}개 ķŒŒģ¼ģ˜ 변경 ė‚“ģš©ģ„ ģ·Øģ†Œķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", - "discard": "변경 ė‚“ģš© ģ·Øģ†Œ", - "confirm discard all": "ėŖØė“  변경 ė‚“ģš©ģ„ ģ·Øģ†Œķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ? ģ“ ģž‘ģ—…ģ€ ė˜ėŒė¦“ 수 ģ—†ģŠµė‹ˆė‹¤.", - "discardAll": "ėŖØė“  변경 ė‚“ģš© ģ·Øģ†Œ", + "warn untracked": "{0}ź°œģ˜ ģ¶”ģ ė˜ģ§€ ģ•Šģ€ ķŒŒģ¼ģ„ ģ‚­ģ œķ•©ė‹ˆė‹¤.", + "confirm discard all single": "{0}ģ˜ 변경 ė‚“ģš©ģ„ ģ·Øģ†Œķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "confirm discard all": "{0} ķŒŒģ¼ģ—ģ„œ 변경 ė‚“ģš©ģ„ 모두 ģ·Øģ†Œķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?\nģ“ ģž‘ģ—…ģ€ ė˜ėŒė¦“ 수 ģ—†ģŠµė‹ˆė‹¤.\nķ˜„ģž¬ ģž‘ģ—… ģ„¤ģ •ģ“ 영구적으딜 ģ†ģ‹¤ė©ė‹ˆė‹¤.", + "discardAll multiple": "1개 ķŒŒģ¼ ģ·Øģ†Œ", + "discardAll": "{0}개 ķŒŒģ¼ 모두 버리기", + "confirm delete multiple": "{0}개 ķŒŒģ¼ģ„ ģ‚­ģ œķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "delete files": "ķŒŒģ¼ ģ‚­ģ œ", + "there are untracked files single": "ģ·Øģ†Œķ•œ 경우 ė‹¤ģŒ ģ¶”ģ ė˜ģ§€ ģ•Šģ€ ķŒŒģ¼ģ“ ė””ģŠ¤ķ¬ģ—ģ„œ ģ‚­ģ œė©ė‹ˆė‹¤. {0}.", + "there are untracked files": "ģ·Øģ†Œķ•˜ėŠ” 경우 {0}ź°œģ˜ ģ¶”ģ ė˜ģ§€ ģ•Šģ€ ķŒŒģ¼ģ“ ė””ģŠ¤ķ¬ģ—ģ„œ ģ‚­ģ œė©ė‹ˆė‹¤.", + "confirm discard all 2": "{0}\n\nģ“ ģž‘ģ—…ģ€ ė˜ėŒė¦“ 수 ģ—†ģœ¼ė©°, ķ˜„ģž¬ ģž‘ģ—… ģ„¤ģ •ģ“ 영구적으딜 ģ†ģ‹¤ė©ė‹ˆė‹¤.", + "yes discard tracked": "1ź°œģ˜ ģ¶”ģ ėœ ķŒŒģ¼ ģ·Øģ†Œ", + "yes discard tracked multiple": "{0}ź°œģ˜ ģ¶”ģ ėœ ķŒŒģ¼ ģ·Øģ†Œ", "no staged changes": "ģ €ģž„ķ•  단계적 변경 ģ‚¬ķ•­ģ“ ģ—†ģŠµė‹ˆė‹¤.\n\nėŖØė“  변경 ģ‚¬ķ•­ģ„ ģžė™ģœ¼ė”œ ģŠ¤ķ…Œģ“ģ§•ķ•˜ź³  직접 ģ €ģž„ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", - "yes": "예", "always": "ķ•­ģƒ", "no changes": "커밋할 변경 ė‚“ģš©ģ“ ģ—†ģŠµė‹ˆė‹¤.", "commit message": "커밋 ė©”ģ‹œģ§€", @@ -33,16 +50,25 @@ "delete branch": "ė¶„źø° ģ‚­ģ œ", "select a branch to merge from": "병합할 ė¶„źø° ģ„ ķƒ", "merge conflicts": "병합 ģ¶©ėŒģ“ ģžˆģŠµė‹ˆė‹¤. ķ•“ź²°ķ•œ 후 ź³„ģ†ķ•˜ģ‹­ģ‹œģ˜¤.", + "tag name": "태그 ģ“ė¦„", + "provide tag name": "태그 ģ“ė¦„ģ„ ģž…ė „ķ•˜ģ„øģš”.", + "tag message": "ė©”ģ‹œģ§€", + "provide tag message": "ķƒœź·øģ— ģ£¼ģ„ģ„ 달 ė©”ģ‹œģ§€ė„¼ ģž…ė „ķ•˜ģ„øģš”.", "no remotes to pull": "ė¦¬ķ¬ģ§€ķ† ė¦¬ģ— ķ’€ķ•˜ė„ė” źµ¬ģ„±ėœ 원격 ķ•­ėŖ©ģ“ ģ—†ģŠµė‹ˆė‹¤.", "pick remote pull repo": "분기넼 ź°€ģ øģ˜¬ 원격 ģ„ ķƒ", "no remotes to push": "ė¦¬ķ¬ģ§€ķ† ė¦¬ģ— ķ‘øģ‹œķ•˜ė„ė” źµ¬ģ„±ėœ ģ›ź²©ģ“ ģ—†ģŠµė‹ˆė‹¤.", + "push with tags success": "ķƒœź·øģ™€ ķ•Øź»˜ ķ‘øģ‹œė˜ģ—ˆģŠµė‹ˆė‹¤.", "nobranch": "원격에 ķ‘øģ‹œķ•  분기넼 첓크 ģ•„ģ›ƒķ•˜ģ„øģš”.", "pick remote": "'{0}' 분기넼 ė‹¤ģŒģ— ź²Œģ‹œķ•˜ė ¤ė©“ ģ›ź²©ģ„ ģ„ ķƒķ•˜ģ„øģš”.", "sync is unpredictable": "ģ“ ģž‘ģ—…ģ€ '{0}' 간에 ģ»¤ė°‹ģ„ ķ‘øģ‹œķ•˜ź³  ķ’€ķ•©ė‹ˆė‹¤.", "ok": "ķ™•ģø", "never again": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", "no remotes to publish": "ė¦¬ķ¬ģ§€ķ† ė¦¬ģ— ź²Œģ‹œķ•˜ė„ė” źµ¬ģ„±ėœ ģ›ź²©ģ“ ģ—†ģŠµė‹ˆė‹¤.", - "disabled": "Gitģ€ ģ“ ģž‘ģ—… ģ˜ģ—­ģ—ģ„œ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ė˜ģ–“ ģžˆź±°ė‚˜ ģ§€ģ›ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "no changes stash": "ģŠ¤ķƒœģ‹œķ•  변경 ė‚“ģš©ģ“ ģ—†ģŠµė‹ˆė‹¤.", + "provide stash message": "ķ•„ģš”ķ•œ 경우 ģŠ¤ķƒœģ‹œ ė©”ģ‹œģ§€ė„¼ ģž…ė „ķ•˜ģ„øģš”.", + "stash message": "ģŠ¤ķƒœģ‹œ ė©”ģ‹œģ§€", + "no stashes": "복원할 ģŠ¤ķƒœģ‹œź°€ ģ—†ģŠµė‹ˆė‹¤.", + "pick stash to pop": "ķ‘œģ‹œķ•  ģŠ¤ķƒœģ‹œ ģ„ ķƒ", "clean repo": "첓크 ģ•„ģ›ƒķ•˜źø° 전에 ė¦¬ķ¬ģ§€ķ† ė¦¬ ģž‘ģ—… 트리넼 ģ •ė¦¬ķ•˜ģ„øģš”.", "cant push": "참씰넼 원격에 ķ‘øģ‹œķ•  수 ģ—†ģŠµė‹ˆė‹¤. 먼저 'ķ’€'ģ„ ģ‹¤ķ–‰ķ•˜ģ—¬ 변경 ė‚“ģš©ģ„ ķ†µķ•©ķ•˜ģ„øģš”.", "git error details": "Git: {0}", diff --git a/i18n/kor/extensions/git/out/model.i18n.json b/i18n/kor/extensions/git/out/model.i18n.json index 79de8a8d0b3..0992c34ccab 100644 --- a/i18n/kor/extensions/git/out/model.i18n.json +++ b/i18n/kor/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "ģ—“źø°", - "merge changes": "변경 ė‚“ģš© 병합", - "staged changes": "ģŠ¤ķ…Œģ“ģ§•ėœ 변경 ė‚“ģš©", - "changes": "변경 ė‚“ģš©", - "ok": "ķ™•ģø", - "neveragain": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", - "huge": "'{0}'ģ˜ Git ė¦¬ķ¬ģ§€ķ† ė¦¬ģ— ķ™œģ„± 변경 ė‚“ģš©ģ“ ė„ˆė¬“ ė§ŽģŠµė‹ˆė‹¤. Git źø°ėŠ„ģ˜ ķ•˜ģœ„ ģ§‘ķ•©ė§Œ ģ‚¬ģš©ķ•  수 ģžˆė„ė” ģ„¤ģ •ė©ė‹ˆė‹¤." + "no repositories": "ģ‚¬ģš© ź°€ėŠ„ķ•œ ė¦¬ķ¬ģ§€ķ† ė¦¬ź°€ ģ—†ģŠµė‹ˆė‹¤.", + "pick repo": "ė¦¬ķ¬ģ§€ķ† ė¦¬ ģ„ ķƒ" } \ No newline at end of file diff --git a/i18n/kor/extensions/git/out/repository.i18n.json b/i18n/kor/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..c5c45af0062 --- /dev/null +++ b/i18n/kor/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "ģ—“źø°", + "index modified": "ģøė±ģŠ¤ ģˆ˜ģ •ėØ", + "modified": "ģˆ˜ģ •ėØ", + "index added": "ģøė±ģŠ¤ 추가됨", + "index deleted": "ģøė±ģŠ¤ ģ‚­ģ œėØ", + "deleted": "ģ‚­ģ œėØ", + "index renamed": "ģøė±ģŠ¤ ģ“ė¦„ 변경됨", + "index copied": "ģøė±ģŠ¤ 복사됨", + "untracked": "ģ¶”ģ ė˜ģ§€ ģ•ŠģŒ", + "ignored": "ė¬“ģ‹œėØ", + "both deleted": "ė‘˜ 다 ģ‚­ģ œėØ", + "added by us": "ė³øģøģ“ 추가함", + "deleted by them": "ķƒ€ģøģ“ ģ‚­ģ œķ•Ø", + "added by them": "ķƒ€ģøģ“ 추가함", + "deleted by us": "ė³øģøģ“ ģ‚­ģ œķ•Ø", + "both added": "ė‘˜ 다 추가됨", + "both modified": "ė‘˜ 다 ģˆ˜ģ •ėØ", + "commit": "커밋", + "merge changes": "변경 ė‚“ģš© 병합", + "staged changes": "ģŠ¤ķ…Œģ“ģ§•ėœ 변경 ė‚“ģš©", + "changes": "변경 ė‚“ģš©", + "ok": "ķ™•ģø", + "neveragain": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", + "huge": "'{0}'ģ˜ Git ė¦¬ķ¬ģ§€ķ† ė¦¬ģ— ķ™œģ„± 변경 ė‚“ģš©ģ“ ė„ˆė¬“ ė§ŽģŠµė‹ˆė‹¤. Git źø°ėŠ„ģ˜ ķ•˜ģœ„ ģ§‘ķ•©ė§Œ ģ‚¬ģš©ķ•  수 ģžˆė„ė” ģ„¤ģ •ė©ė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/extensions/git/package.i18n.json b/i18n/kor/extensions/git/package.i18n.json index 38e31439c8c..836154a75aa 100644 --- a/i18n/kor/extensions/git/package.i18n.json +++ b/i18n/kor/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "복제", "command.init": "ė¦¬ķ¬ģ§€ķ† ė¦¬ ģ“ˆźø°ķ™”", + "command.close": "ė¦¬ķ¬ģ§€ķ† ė¦¬ ė‹«źø°", "command.refresh": "새딜 고침", "command.openChange": "변경 ė‚“ģš© ģ—“źø°", "command.openFile": "ķŒŒģ¼ ģ—“źø°", @@ -22,22 +23,29 @@ "command.commit": "Commit", "command.commitStaged": "ģŠ¤ķ…Œģ“ģ§•ėœ ķ•­ėŖ© 커밋", "command.commitStagedSigned": "ģŠ¤ķ…Œģ“ģ§•ėœ ķ•­ėŖ© 커밋(ė”œź·øģ˜¤ķ”„ėØ)", + "command.commitStagedAmend": "ģŠ¤ķ…Œģ“ģ§•ėœ ķ•­ėŖ© 커밋(ģˆ˜ģ •)", "command.commitAll": "모두 커밋", "command.commitAllSigned": "모두 커밋(ė”œź·øģ˜¤ķ”„ėØ)", + "command.commitAllAmend": "모두 커밋 (ģˆ˜ģ •)", "command.undoCommit": "ė§ˆģ§€ė§‰ 커밋 실행 ģ·Øģ†Œ", "command.checkout": "ė‹¤ģŒģœ¼ė”œ 첓크 ģ•„ģ›ƒ...", "command.branch": "ė¶„źø° ė§Œė“¤źø°...", "command.deleteBranch": "ė¶„źø° ģ‚­ģ œ...", "command.merge": "ė¶„źø° 병합...", + "command.createTag": "태그 ģƒģ„±", "command.pull": "ķ’€", "command.pullRebase": "ķ’€(ė‹¤ģ‹œ 지정)", "command.pullFrom": "ź°€ģ øģ˜¬ ģœ„ģ¹˜...", "command.push": "ķ‘øģ‹œ", "command.pushTo": "ė‹¤ģŒģœ¼ė”œ ķ‘øģ‹œ...", + "command.pushWithTags": "태그딜 ķ‘øģ‹œ", "command.sync": "ė™źø°ķ™”", "command.publish": "ė¶„źø° ź²Œģ‹œ", "command.showOutput": "Git 출렄 ķ‘œģ‹œ", "command.ignore": ".gitignore에 ķŒŒģ¼ 추가", + "command.stash": "ģŠ¤ķƒœģ‹œ", + "command.stashPop": "ģŠ¤ķƒœģ‹œ ķ‘œģ‹œ...", + "command.stashPopLatest": "ģµœģ‹  ģŠ¬ėž˜ģ‹œ ķ‘œģ‹œ", "config.enabled": "Git ģ‚¬ģš© 여부", "config.path": "Git 실행 ķŒŒģ¼ģ˜ 경딜", "config.autorefresh": "ģžė™ 새딜 고침 ģ‚¬ģš© 여부", @@ -49,5 +57,7 @@ "config.ignoreLegacyWarning": "ė ˆź±°ģ‹œ Git 경고넼 ė¬“ģ‹œķ•©ė‹ˆė‹¤.", "config.ignoreLimitWarning": "ė¦¬ķ¬ģ§€ķ† ė¦¬ģ— 변경 ė‚“ģš©ģ“ ė„ˆė¬“ ė§Žģœ¼ė©“ 경고넼 ė¬“ģ‹œķ•©ė‹ˆė‹¤.", "config.defaultCloneDirectory": "git ė¦¬ķ¬ģ§€ķ† ė¦¬ė„¼ ė³µģ œķ•  źø°ė³ø ģœ„ģ¹˜", - "config.enableSmartCommit": "단계적 변경 ģ‚¬ķ•­ģ“ ģ—†ėŠ” 경우 ėŖØė“  변경 ģ‚¬ķ•­ģ„ ģ €ģž„ķ•©ė‹ˆė‹¤." + "config.enableSmartCommit": "단계적 변경 ģ‚¬ķ•­ģ“ ģ—†ėŠ” 경우 ėŖØė“  변경 ģ‚¬ķ•­ģ„ ģ €ģž„ķ•©ė‹ˆė‹¤.", + "config.enableCommitSigning": "GPG넼 ģ‚¬ģš©ķ•œ 커밋 ģ„œėŖ…ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "config.discardAllScope": "`ėŖØė“  변경 ė‚“ģš© ģ·Øģ†Œ` ėŖ…ė ¹ģœ¼ė”œ ģ·Øģ†Œė˜ėŠ” 변경 ė‚“ģš©ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤. `all`ģ“ė©“ ėŖØė“  변경 ė‚“ģš©ģ„ ģ·Øģ†Œķ•©ė‹ˆė‹¤. `tracked`ģ“ė©“ ģ¶”ģ ėœ ķŒŒģ¼ė§Œ ģ·Øģ†Œķ•©ė‹ˆė‹¤. `prompt`ģ“ė©“ ģž‘ģ—…ģ„ 실행할 ė•Œė§ˆė‹¤ ķ”„ė”¬ķ”„ķŠø ėŒ€ķ™” ģƒģžė„¼ ķ‘œģ‹œķ•©ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/grunt/out/main.i18n.json b/i18n/kor/extensions/grunt/out/main.i18n.json index 8456653bb0c..e7957d307fc 100644 --- a/i18n/kor/extensions/grunt/out/main.i18n.json +++ b/i18n/kor/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Grunt ģžė™ ź²€ģƒ‰ģ— ģ‹¤ķŒØķ•˜ź³  [0} ģ˜¤ė„˜ź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤." + "execFailed": "ķ“ė” {0}에 ėŒ€ķ•“ Grunt ģžė™ ź²€ģƒ‰ģ— ģ‹¤ķŒØķ•˜ź³  {1} ģ˜¤ė„˜ź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/gulp/out/main.i18n.json b/i18n/kor/extensions/gulp/out/main.i18n.json index e88e41a1fa9..87895182ec6 100644 --- a/i18n/kor/extensions/gulp/out/main.i18n.json +++ b/i18n/kor/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Gulp ģžė™ ź²€ģƒ‰ģ— ģ‹¤ķŒØķ•˜ź³  {0} ģ˜¤ė„˜ź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤." + "execFailed": "ķ“ė” {0}에 ėŒ€ķ•“ Gulp ģžė™ ź²€ģƒ‰ģ— ģ‹¤ķŒØķ•˜ź³  {1} ģ˜¤ė„˜ź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/html/package.i18n.json b/i18n/kor/extensions/html/package.i18n.json index 413a15e786c..17e48a1237b 100644 --- a/i18n/kor/extensions/html/package.i18n.json +++ b/i18n/kor/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "źø°ė³ø HTML ķ¬ė§·ķ„° ģ‚¬ģš©/ģ‚¬ģš© ģ•ˆ 함(ė‹¤ģ‹œ ģ‹œģž‘ķ•“ģ•¼ 함)", + "html.format.enable.desc": "źø°ė³ø HTML ķ¬ė§·ķ„°ė„¼ ģ‚¬ģš©ķ•˜ź±°ė‚˜ ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "html.format.wrapLineLength.desc": "ķ•œ 줄당 ģµœėŒ€ ė¬øģž ģˆ˜ģž…ė‹ˆė‹¤(0 = ģ‚¬ģš© ģ•ˆ 함).", "html.format.unformatted.desc": "ģ‰¼ķ‘œė”œ ė¶„ė¦¬ėœ 태그 ėŖ©ė”ģœ¼ė”œ, ģ„œģ‹ģ„ ė‹¤ģ‹œ ģ§€ģ •ķ•“ģ„œėŠ” ģ•ˆ ė©ė‹ˆė‹¤. https://www.w3.org/TR/html5/dom.html#phrasing-content에 ė‚˜ģ—“ėœ ėŖØė“  ķƒœź·øģ˜ źø°ė³øź°’ģ€ 'null'딜 ģ„¤ģ •ė©ė‹ˆė‹¤.", "html.format.contentUnformatted.desc": "ģ‰¼ķ‘œė”œ ė¶„ė¦¬ėœ 태그 ėŖ©ė”ģœ¼ė”œ, ģ½˜ķ…ģø ģ˜ ģ„œģ‹ģ„ ė‹¤ģ‹œ ģ§€ģ •ķ•“ģ„œėŠ” ģ•ˆ ė©ė‹ˆė‹¤. 'pre' ķƒœź·øģ˜ źø°ė³øź°’ģ€ 'null'딜 ģ„¤ģ •ė©ė‹ˆė‹¤.", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "źø°ė³ø 제공 HTML ģ–øģ–“ ģ§€ģ›ģ—ģ„œ Angular V1 태그 ė° ģ†ģ„±ģ„ ģ œģ•ˆķ•˜ėŠ”ģ§€ 여부넼 źµ¬ģ„±ķ•©ė‹ˆė‹¤.", "html.suggest.ionic.desc": "źø°ė³ø 제공 HTML ģ–øģ–“ ģ§€ģ›ģ—ģ„œ Ionic 태그, ģ†ģ„± ė° ź°’ģ„ ģ œģ•ˆķ•˜ėŠ”ģ§€ 여부넼 źµ¬ģ„±ķ•©ė‹ˆė‹¤.", "html.suggest.html5.desc": "źø°ė³ø 제공 HTML ģ–øģ–“ ģ§€ģ›ģ—ģ„œ HTML5 태그, ģ†ģ„± ė° ź°’ģ„ ģ œģ•ˆķ•˜ėŠ”ģ§€ 여부넼 źµ¬ģ„±ķ•©ė‹ˆė‹¤.", + "html.trace.server.desc": "VS Code와 HTML ģ–øģ–“ ģ„œė²„ ź°„ ķ†µģ‹ ģ„ ģ¶”ģ ķ•©ė‹ˆė‹¤.", "html.validate.scripts": "źø°ė³ø 제공 HTML ģ–øģ–“ ģ§€ģ›ģ—ģ„œ ķ¬ķ•Ø ģŠ¤ķ¬ė¦½ķŠøģ˜ ģœ ķšØģ„±ģ„ ź²€ģ‚¬ķ•˜ėŠ”ģ§€ 여부넼 źµ¬ģ„±ķ•©ė‹ˆė‹¤.", - "html.validate.styles": "źø°ė³ø 제공 HTML ģ–øģ–“ ģ§€ģ›ģ—ģ„œ ķ¬ķ•Ø ģŠ¤ķƒ€ģ¼ģ˜ ģœ ķšØģ„±ģ„ ź²€ģ‚¬ķ•˜ėŠ”ģ§€ 여부넼 źµ¬ģ„±ķ•©ė‹ˆė‹¤." + "html.validate.styles": "źø°ė³ø 제공 HTML ģ–øģ–“ ģ§€ģ›ģ—ģ„œ ķ¬ķ•Ø ģŠ¤ķƒ€ģ¼ģ˜ ģœ ķšØģ„±ģ„ ź²€ģ‚¬ķ•˜ėŠ”ģ§€ 여부넼 źµ¬ģ„±ķ•©ė‹ˆė‹¤.", + "html.autoClosingTags": "HTML ķƒœź·øģ˜ ģžė™ 닫기넼 ģ‚¬ģš©ķ•˜ź±°ė‚˜ ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/jake/out/main.i18n.json b/i18n/kor/extensions/jake/out/main.i18n.json index 2e5af401ba1..508a5285839 100644 --- a/i18n/kor/extensions/jake/out/main.i18n.json +++ b/i18n/kor/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Jake ģžė™ ź²€ģƒ‰ ģ‹¤ķŒØ 오넘: {0}" + "execFailed": "ķ“ė” {0}에 ėŒ€ķ•“ Jake ģžė™ ź²€ģƒ‰ģ— ģ‹¤ķŒØķ•˜ź³  {1} ģ˜¤ė„˜ź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/json/package.i18n.json b/i18n/kor/extensions/json/package.i18n.json index 0f62fca8d06..c8cfa96cabf 100644 --- a/i18n/kor/extensions/json/package.i18n.json +++ b/i18n/kor/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "ģ§€ģ •ėœ URL에 ėŒ€ķ•œ ģŠ¤ķ‚¤ė§ˆ ģ •ģ˜ģž…ė‹ˆė‹¤. ģŠ¤ķ‚¤ė§ˆ URL에 ėŒ€ķ•œ ģ•”ģ„øģŠ¤ 방지넼 ģœ„ķ•“ģ„œė§Œ ģŠ¤ķ‚¤ė§ˆė„¼ ģ œź³µķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", "json.format.enable.desc": "źø°ė³ø JSON ķ¬ė§·ķ„° ģ‚¬ģš©/ģ‚¬ģš© ģ•ˆ 함(ė‹¤ģ‹œ ģ‹œģž‘ķ•“ģ•¼ 함)", "json.tracing.desc": "VS Code와 JSON ģ–øģ–“ ģ„œė²„ ź°„ ķ†µģ‹ ģ„ ģ¶”ģ ķ•©ė‹ˆė‹¤.", - "json.colorDecorators.enable.desc": "ģƒ‰ ė°ģ½”ė ˆģ“ķ„° ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함" + "json.colorDecorators.enable.desc": "ģƒ‰ ė°ģ½”ė ˆģ“ķ„° ģ‚¬ģš© ė˜ėŠ” ģ‚¬ģš© ģ•ˆ 함", + "json.colorDecorators.enable.deprecationMessage": "`json.colorDecorators.enable` ģ„¤ģ •ģ€ `editor.colorDecorators`넼 ģœ„ķ•“ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/extensions/markdown/out/extension.i18n.json b/i18n/kor/extensions/markdown/out/extension.i18n.json index f38833da5da..81729088db3 100644 --- a/i18n/kor/extensions/markdown/out/extension.i18n.json +++ b/i18n/kor/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "'markdown.styles': {0}ģ„ 불러올 수 ģ—†ģŒ" + "onPreviewStyleLoadError": "'markdown.styles': {0}ģ„ 불러올 수 ģ—†ģŒ", + "previewTitle": "{0} 미리 볓기" } \ No newline at end of file diff --git a/i18n/kor/extensions/markdown/out/previewContentProvider.i18n.json b/i18n/kor/extensions/markdown/out/previewContentProvider.i18n.json index 8b6ad71cd4e..966b7d5fad1 100644 --- a/i18n/kor/extensions/markdown/out/previewContentProvider.i18n.json +++ b/i18n/kor/extensions/markdown/out/previewContentProvider.i18n.json @@ -3,4 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "preview.securityMessage.text": "ģ“ ė¬øģ„œģ—ģ„œ ģ¼ė¶€ ģ½˜ķ…ģø ź°€ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ė˜ģ—ˆģŠµė‹ˆė‹¤.", + "preview.securityMessage.title": "Markdown 미리 ė³“źø°ģ—ģ„œ ģž ģž¬ģ ģœ¼ė”œ ģ•ˆģ „ķ•˜ģ§€ ģ•Šź±°ė‚˜ ė³“ģ•ˆė˜ģ§€ ģ•Šģ€ ģ½˜ķ…ģø ź°€ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ė˜ģ–“ ģžˆģŠµė‹ˆė‹¤. ģ“ ģ½˜ķ…ģø ė‚˜ 스크립트넼 ķ—ˆģš©ķ•˜ė ¤ė©“ Markdown 미리 볓기 ė³“ģ•ˆ ģ„¤ģ •ģ„ ė³€ź²½ķ•˜ģ„øģš”.", + "preview.securityMessage.label": "ģ½˜ķ…ģø  ģ‚¬ģš©ķ•  수 ģ—†ģŒ ė³“ģ•ˆ 경고" +} \ No newline at end of file diff --git a/i18n/kor/extensions/markdown/out/security.i18n.json b/i18n/kor/extensions/markdown/out/security.i18n.json index fea668373d1..6dd50f40273 100644 --- a/i18n/kor/extensions/markdown/out/security.i18n.json +++ b/i18n/kor/extensions/markdown/out/security.i18n.json @@ -4,5 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.currentSelection": "ķ˜„ģž¬ 설정" + "strict.title": "Strict", + "strict.description": "ė³“ģ•ˆ ģ½˜ķ…ģø ė§Œ ė”œė“œ", + "insecureContent.title": "ė³“ģ•„ė˜ģ§€ ģ•Šģ€ ģ½˜ķ…ģø  ķ—ˆģš©", + "insecureContent.description": "http넼 ķ†µķ•œ ģ½˜ķ…ģø  ė”œė“œ ģ‚¬ģš©", + "disable.title": "ģ‚¬ģš© ģ•ˆ 함", + "disable.description": "ėŖØė“  ģ½˜ķ…ģø  ė° 스크립트 ģ‹¤ķ–‰ģ„ ķ—ˆģš©ķ•©ė‹ˆė‹¤. ź¶Œģž„ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "moreInfo.title": "추가 정볓", + "preview.showPreviewSecuritySelector.title": "ģ“ ģž‘ģ—… ģ˜ģ—­ģ— ėŒ€ķ•“ Markdown 미리 ė³“źø°ģ˜ ė³“ģ•ˆ 설정 ģ„ ķƒ" } \ No newline at end of file diff --git a/i18n/kor/extensions/markdown/package.i18n.json b/i18n/kor/extensions/markdown/package.i18n.json index f4dc3e5e6f1..dc173d21269 100644 --- a/i18n/kor/extensions/markdown/package.i18n.json +++ b/i18n/kor/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "ė§ˆķ¬ė‹¤ģš“ 미리 ė³“źø°ģ—ģ„œ ģ¤„ė°”źæˆ ė Œė”ė§ ė°©ģ‹ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤. 'true'딜 ģ„¤ģ •ķ•˜ė©“ ėŖØė“  행에 ėŒ€ķ•“
ģ“(ź°€) ģƒģ„±ė©ė‹ˆė‹¤.", + "markdown.preview.linkify": "Markdown 미리 ė³“źø°ģ—ģ„œ URL ź°™ģ€ ķ…ģŠ¤ķŠøė„¼ 링크딜 ė³€ķ™˜ģ„ ģ‚¬ģš©ķ•˜ź±°ė‚˜ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ķ•©ė‹ˆė‹¤.", "markdown.preview.doubleClickToSwitchToEditor.desc": "markdown 미리 ė³“źø°ģ—ģ„œ 두 번 ķ“ė¦­ķ•˜ģ—¬ ķŽøģ§‘źø°ė”œ ģ „ķ™˜ķ•©ė‹ˆė‹¤.", "markdown.preview.fontFamily.desc": "markdown 미리 ė³“źø°ģ—ģ„œ ģ‚¬ģš©ė˜ėŠ” 글꼓 ķŒØė°€ė¦¬ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", "markdown.preview.fontSize.desc": "markdown 미리 ė³“źø°ģ—ģ„œ ģ‚¬ģš©ė˜ėŠ” 글꼓 크기(픽셀)넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "ģø”ė©“ģ—ģ„œ 미리 볓기 ģ—“źø°", "markdown.showSource.title": "ģ†ŒģŠ¤ ķ‘œģ‹œ", "markdown.styles.dec": "markdown 미리 ė³“źø°ģ—ģ„œ ģ‚¬ģš©ķ•  CSS ģŠ¤ķƒ€ģ¼ģ‹œķŠøģ˜ URL ė˜ėŠ” 딜컬 경딜 ėŖ©ė”ģž…ė‹ˆė‹¤. ģƒėŒ€ ź²½ė”œėŠ” ķƒģƒ‰źø°ģ—ģ„œ 엓린 ķ“ė”ė„¼ źø°ģ¤€ģœ¼ė”œ ķ•“ģ„ė©ė‹ˆė‹¤. 엓린 ķ“ė”ź°€ ģ—†ģœ¼ė©“ markdown ķŒŒģ¼ģ˜ ģœ„ģ¹˜ė„¼ źø°ģ¤€ģœ¼ė”œ ķ•“ģ„ė©ė‹ˆė‹¤. ėŖØė“  '\\'ėŠ” '\\\\'딜 ģØģ•¼ ķ•©ė‹ˆė‹¤.", - "markdown.showPreviewSecuritySelector.title": "Markdown 미리 볓기 ė³“ģ•ˆ 설정 변경", - "markdown.trace.desc": "Markdown ķ™•ģž„ģ— ėŒ€ķ•“ 디버그 ė”œź¹…ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•©ė‹ˆė‹¤." + "markdown.showPreviewSecuritySelector.title": "미리 볓기 ė³“ģ•ˆ 설정 변경", + "markdown.trace.desc": "Markdown ķ™•ģž„ģ— ėŒ€ķ•“ 디버그 ė”œź¹…ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "markdown.refreshPreview.title": "미리 볓기 새딜 고침" } \ No newline at end of file diff --git a/i18n/kor/extensions/npm/out/main.i18n.json b/i18n/kor/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/kor/extensions/npm/out/main.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/kor/extensions/npm/package.i18n.json b/i18n/kor/extensions/npm/package.i18n.json index bae4e5954d0..04e51b003ca 100644 --- a/i18n/kor/extensions/npm/package.i18n.json +++ b/i18n/kor/extensions/npm/package.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "config.npm.autoDetect": "npm ģŠ¤ķ¬ė¦½ķŠøģ— ėŒ€ķ•œ ģžė™ ź²€ģƒ‰ 여부넼 ģ„¤ģ •ķ•©ė‹ˆė‹¤. źø°ė³øź°’ģ€ [켜기]ģž…ė‹ˆė‹¤." + "config.npm.autoDetect": "npm ģŠ¤ķ¬ė¦½ķŠøģ— ėŒ€ķ•œ ģžė™ ź²€ģƒ‰ 여부넼 ģ„¤ģ •ķ•©ė‹ˆė‹¤. źø°ė³øź°’ģ€ [켜기]ģž…ė‹ˆė‹¤.", + "config.npm.runSilent": " `--silent` ģ˜µģ…˜ģœ¼ė”œ npm ėŖ…ė ¹ 실행" } \ No newline at end of file diff --git a/i18n/kor/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/kor/extensions/typescript/out/features/taskProvider.i18n.json index 8b6ad71cd4e..77e42347178 100644 --- a/i18n/kor/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/kor/extensions/typescript/out/features/taskProvider.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "buildTscLabel": "ė¹Œė“œ - {0}", + "buildAndWatchTscLabel": "볓기 - {0}" +} \ No newline at end of file diff --git a/i18n/kor/extensions/typescript/out/utils/api.i18n.json b/i18n/kor/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..128cac23b14 --- /dev/null +++ b/i18n/kor/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "ģž˜ėŖ»ėœ 버전" +} \ No newline at end of file diff --git a/i18n/kor/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/kor/extensions/typescript/out/utils/versionPicker.i18n.json index 52fb57a72ed..13043b07ab1 100644 --- a/i18n/kor/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/kor/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "VSCodeģ˜ 버전 ģ‚¬ģš©", + "useVSCodeVersionOption": "VS Codeģ˜ 버전 ģ‚¬ģš©", "useWorkspaceVersionOption": "ģž‘ģ—… ģ˜ģ—­ 버전 ģ‚¬ģš©", "learnMore": "ģžģ„øķ•œ 정볓", "selectTsVersion": "JavaScript ė° TypeScript ģ–øģ–“ źø°ėŠ„ģ— ģ‚¬ģš©ė˜ėŠ” TypeScript 버전 ģ„ ķƒ" diff --git a/i18n/kor/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/kor/extensions/typescript/out/utils/versionProvider.i18n.json index 6bdc1aa86dd..ce4b4570352 100644 --- a/i18n/kor/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/kor/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "ģž˜ėŖ» ė™ģž‘ķ•˜ėŠ” ė°”ģ“ėŸ¬ģŠ¤ 감지 ė„źµ¬ģ™€ ź°™ģ€ 다넸 ģ‘ģš© ķ”„ė”œź·øėžØģ—ģ„œ VSCodeģ˜ tsserverź°€ ģ‚­ģ œė˜ģ—ˆģŠµė‹ˆė‹¤. VS Code넼 ė‹¤ģ‹œ ģ„¤ģ¹˜ķ•˜ģ„øģš”." + "couldNotLoadTsVersion": "ģ“ ź²½ė”œģ—ģ„œ TypeScript ė²„ģ „ģ„ ė”œė“œķ•  수 ģ—†ģŠµė‹ˆė‹¤.", + "noBundledServerFound": "ģž˜ėŖ» ė™ģž‘ķ•˜ėŠ” ė°”ģ“ėŸ¬ģŠ¤ 감지 ė„źµ¬ģ™€ ź°™ģ€ 다넸 ģ‘ģš© ķ”„ė”œź·øėžØģ—ģ„œ VS Codeģ˜ tsserverź°€ ģ‚­ģ œė˜ģ—ˆģŠµė‹ˆė‹¤. VS Code넼 ė‹¤ģ‹œ ģ„¤ģ¹˜ķ•˜ģ„øģš”." } \ No newline at end of file diff --git a/i18n/kor/extensions/typescript/package.i18n.json b/i18n/kor/extensions/typescript/package.i18n.json index ebf695748cc..7077f24ff61 100644 --- a/i18n/kor/extensions/typescript/package.i18n.json +++ b/i18n/kor/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "매개 ė³€ģˆ˜ ģ„œėŖ…ģœ¼ė”œ ķ•Øģˆ˜ė„¼ ģ™„ė£Œķ•˜ģ„øģš”.", "typescript.tsdk.desc": "ģ‚¬ģš©ķ•  tsserver ė° lib*.d.ts ķŒŒģ¼ģ“ 들얓 ģžˆėŠ” ķ“ė” 경딜넼 ģ§€ģ •ķ•©ė‹ˆė‹¤.", - "typescript.disableAutomaticTypeAcquisition": "ģžė™ ķ˜•ģ‹ ģøģ‹ģ„ ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. TypeScript >= 2.0.6ģ“ ķ•„ģš”ķ•˜ė©° 변경 후 ė‹¤ģ‹œ ģ‹œģž‘ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", + "typescript.disableAutomaticTypeAcquisition": "ģžė™ ķ˜•ģ‹ ģøģ‹ģ„ ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. TypeScript >= 2.0.6ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤.", "typescript.tsserver.log": "ķŒŒģ¼ģ— ėŒ€ķ•“ TS ģ„œė²„ ė”œź¹…ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•©ė‹ˆė‹¤. ģ“ ė”œź·øėŠ” TS ģ„œė²„ 문제넼 ģ§„ė‹Øķ•˜ėŠ” ė° ģ‚¬ģš©ė  수 ģžˆģŠµė‹ˆė‹¤. ė”œź·øģ—ėŠ” ķŒŒģ¼ 경딜, ģ†ŒģŠ¤ ģ½”ė“œ ė° ķ”„ė”œģ ķŠøģ—ģ„œ ģž ģž¬ģ ģœ¼ė”œ ģ¤‘ģš”ķ•œ źø°ķƒ€ 정볓가 ķ¬ķ•Øė  수 ģžˆģŠµė‹ˆė‹¤.", "typescript.tsserver.trace": "TS ģ„œė²„ė”œ ģ „ģ†”ķ•œ ė©”ģ‹œģ§€ ģ¶”ģ ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•©ė‹ˆė‹¤. ģ“\n ģ¶”ģ ģ€ TS ģ„œė²„ 문제넼 ģ§„ė‹Øķ•˜ėŠ” ė° ģ‚¬ģš©ė  수 ģžˆģŠµė‹ˆė‹¤. ģ¶”ģ ģ—ėŠ” ķŒŒģ¼ 경딜, ģ†ŒģŠ¤ ģ½”ė“œ ė° ķ”„ė”œģ ķŠøģ—ģ„œ ģž ģž¬ģ ģœ¼ė”œ ģ¤‘ģš”ķ•œ\n źø°ķƒ€ 정볓가 ķ¬ķ•Øė  수 ģžˆģŠµė‹ˆė‹¤.", "typescript.validate.enable": "TypeScript ģœ ķšØģ„± 검사넼 ģ‚¬ģš©ķ•˜ź±°ė‚˜ ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", @@ -44,7 +44,6 @@ "typescript.npm": "ģžė™ ģž…ė „ ģøģ‹ģ— ģ‚¬ģš©ėœ NPM 실행 ķŒŒģ¼ 경딜넼 ģ§€ģ •ķ•©ė‹ˆė‹¤. TypeScript >= 2.3.4ź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤.", "typescript.check.npmIsInstalled": "ģžė™ ģž…ė „ ģøģ‹ģ— ėŒ€ķ•“ NPMģ“ ģ„¤ģ¹˜ė˜ģ–“ ģžˆėŠ”ģ§€ ķ™•ģøķ•©ė‹ˆė‹¤.", "javascript.nameSuggestions": "JavaScript ģ œģ•ˆ ėŖ©ė”ģ˜ ķŒŒģ¼ģ—ģ„œ ź³ ģœ ķ•œ ģ“ė¦„ ķ¬ķ•Øģ„ ģ‚¬ģš©/ģ‚¬ģš© ģ•ˆ ķ•Øģœ¼ė”œ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", - "typescript.tsc.autoDetect": "tsc ģž‘ģ—…ģ˜ ģžė™ ź²€ģƒ‰ģ„ ģ¼œź±°ė‚˜ ė•ė‹ˆė‹¤.", "typescript.problemMatchers.tsc.label": "TypeScript 문제", "typescript.problemMatchers.tscWatch.label": "TypeScript 문제(ź°ģ‹œ ėŖØė“œ)" } \ No newline at end of file diff --git a/i18n/kor/src/vs/code/electron-main/auth.i18n.json b/i18n/kor/src/vs/code/electron-main/auth.i18n.json index 8b6ad71cd4e..4b003737236 100644 --- a/i18n/kor/src/vs/code/electron-main/auth.i18n.json +++ b/i18n/kor/src/vs/code/electron-main/auth.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "authRequire": "ķ”„ė”ģ‹œ ģøģ¦ ķ•„ģš”", + "proxyauth": "ķ”„ė”ģ‹œ {0}에 ģøģ¦ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/code/electron-main/menus.i18n.json b/i18n/kor/src/vs/code/electron-main/menus.i18n.json index 9f3f01d8dbf..2e942d1252d 100644 --- a/i18n/kor/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/kor/src/vs/code/electron-main/menus.i18n.json @@ -22,9 +22,11 @@ "miQuit": "{0} ģ¢…ė£Œ", "miNewFile": "새 ķŒŒģ¼(&&N)", "miOpen": "ģ—“źø°(&&O)...", + "miOpenWorkspace": "ģž‘ģ—… ģ˜ģ—­ ģ—“źø°(&O)...", "miOpenFolder": "ķ“ė” ģ—“źø°(&&F)...", "miOpenFile": "ķŒŒģ¼ ģ—“źø°(&&O)...", "miOpenRecent": "최근 ķ•­ėŖ© ģ—“źø°(&&R)", + "miSaveWorkspaceAs": "다넸 ģ“ė¦„ģœ¼ė”œ ģž‘ģ—… ģ˜ģ—­ ģ €ģž„(&S)...", "miAddFolderToWorkspace": "ģž‘ģ—… ģ˜ģ—­ģ— ķ“ė” 추가(&&A)", "miSave": "ģ €ģž„(&&S)", "miSaveAs": "다넸 ģ“ė¦„ģœ¼ė”œ ģ €ģž„(&&A)...", @@ -32,6 +34,7 @@ "miAutoSave": "ģžė™ ģ €ģž„", "miRevert": "ķŒŒģ¼ ė˜ėŒė¦¬źø°(&&V)", "miCloseWindow": "ģ°½ ė‹«źø°(&&E)", + "miCloseWorkspace": "ģž‘ģ—… ģ˜ģ—­ ė‹«źø°(&W)", "miCloseFolder": "ķ“ė” ė‹«źø°(&&F)", "miCloseEditor": "ķŽøģ§‘źø° ė‹«źø°(&&C)", "miExit": "ėė‚“źø°(&X)", @@ -44,6 +47,7 @@ "miPreferences": "źø°ė³ø 설정(&&P)", "miReopenClosedEditor": "ė‹«ķžŒ ķŽøģ§‘źø° ė‹¤ģ‹œ ģ—“źø°(&&R)", "miMore": "ģžģ„øķžˆ...(&M)", + "miClearRecentOpen": "ģµœź·¼ģ— ģ—° ķ•­ėŖ© ģ§€ģš°źø°(&&C)", "miUndo": "실행 ģ·Øģ†Œ(&&U)", "miRedo": "ė‹¤ģ‹œ 실행(&&R)", "miCut": "ģžė„“źø°(&T)", @@ -98,6 +102,7 @@ "miHideActivityBar": "ģž‘ģ—… ė§‰ėŒ€ 숨기기(&&A)", "miShowActivityBar": "ģž‘ģ—… ė§‰ėŒ€ ķ‘œģ‹œ(&&A)", "miToggleWordWrap": "ģžė™ 줄 ė°”źæˆ 설정/ķ•“ģ œ(&&W)", + "miToggleMinimap": "ėÆøė‹ˆė§µ 토글(&&M)", "miToggleRenderWhitespace": "공백 설정/ķ•“ģ œ ė° ė Œė”ė§(&&R)", "miToggleRenderControlCharacters": "ģ œģ–“ ė¬øģž 설정/ķ•“ģ œ(&&C)", "miZoomIn": "ķ™•ėŒ€(&&Z)", @@ -146,6 +151,10 @@ "mZoom": "ķ™•ėŒ€/ģ¶•ģ†Œ", "mBringToFront": "모두 ė§Ø ģ•žģœ¼ė”œ ź°€ģ øģ˜¤źø°", "miSwitchWindow": "ģ°½ ģ „ķ™˜(&&W)", + "mShowPreviousTab": "ģ“ģ „ 탭 ķ‘œģ‹œ", + "mShowNextTab": "ė‹¤ģŒ 탭 ķ‘œģ‹œ", + "mMoveTabToNewWindow": "새 창으딜 탭 ģ“ė™", + "mMergeAllWindows": "ėŖØė“  ģ°½ 병합", "miToggleDevTools": "ź°œė°œģž ė„źµ¬ 설정/ķ•“ģ œ(&&T)", "miAccessibilityOptions": "접근성 ģ˜µģ…˜(&&O)", "miReportIssues": "문제 볓고(&&I)", @@ -163,10 +172,11 @@ "miAbout": "정볓(&&A)", "miRunTask": "ģž‘ģ—… 실행(&&R)...", "miBuildTask": "ė¹Œė“œ ģž‘ģ—… 실행(&&B)...", + "miRunningTask": "실행 ģ¤‘ģø ģž‘ģ—… ķ‘œģ‹œ(&&G)...", "miRestartTask": "실행 ģ¤‘ģø ģž‘ģ—… ė‹¤ģ‹œ ģ‹œģž‘(&&E)...", "miTerminateTask": "ģž‘ģ—… ģ¢…ė£Œ(&&T)...", - "miConfigureTask": "ģž‘ģ—… 구성(&&C)", - "miConfigureBuildTask": "źø°ė³ø ė¹Œė“œ ģž‘ģ—… 구성(&&F)", + "miConfigureTask": "ģž‘ģ—… 구성(&&C)...", + "miConfigureBuildTask": "źø°ė³ø ė¹Œė“œ ģž‘ģ—… 구성(&&F)...", "accessibilityOptionsWindowTitle": "접근성 ģ˜µģ…˜", "miRestartToUpdate": "ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ģ—¬ ģ—…ė°ģ“ķŠø...", "miCheckingForUpdates": "ģ—…ė°ģ“ķŠøė„¼ ķ™•ģøķ•˜ėŠ” 중...", @@ -174,5 +184,6 @@ "miDownloadingUpdate": "ģ—…ė°ģ“ķŠøė„¼ ė‹¤ģš“ė”œė“œķ•˜ėŠ” 중...", "miInstallingUpdate": "ģ—…ė°ģ“ķŠøė„¼ ģ„¤ģ¹˜ķ•˜ėŠ” 중...", "miCheckForUpdates": "ģ—…ė°ģ“ķŠø ķ™•ģø...", + "aboutDetail": "\n버전 {0}\n커밋 {1}\nė‚ ģ§œ {2}\nģ…ø {3}\nė Œė”ėŸ¬ {4}\nė…øė“œ {5}\nģ•„ķ‚¤ķ…ģ²˜ {6}", "okButton": "ķ™•ģø" } \ No newline at end of file diff --git a/i18n/kor/src/vs/code/electron-main/windows.i18n.json b/i18n/kor/src/vs/code/electron-main/windows.i18n.json index 827fd75a50f..dc8b9079e3c 100644 --- a/i18n/kor/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/kor/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,21 @@ "ok": "ķ™•ģø", "pathNotExistTitle": "ź²½ė”œź°€ ģ—†ģŠµė‹ˆė‹¤.", "pathNotExistDetail": "'{0}' ź²½ė”œź°€ ė””ģŠ¤ķ¬ģ— ė” ģ“ģƒ ģ—†ėŠ” 것 ź°™ģŠµė‹ˆė‹¤.", - "reopen": "ė‹¤ģ‹œ ģ—“źø°", - "wait": "ź³„ģ† ėŒ€źø°", - "close": "ė‹«źø°", "appStalled": "ģ°½ģ“ ė” ģ“ģƒ ģ‘ė‹µķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "appStalledDetail": "ģ°½ģ„ ė‹¤ģ‹œ ģ—“ź±°ė‚˜, ė‹«ź±°ė‚˜, ź³„ģ† 기다릓 수 ģžˆģŠµė‹ˆė‹¤.", "appCrashed": "ģ°½ģ“ ģ¶©ėŒķ–ˆģŠµė‹ˆė‹¤.", "appCrashedDetail": "ė¶ˆķŽøģ„ ė“œė ¤ģ„œ ģ£„ģ†”ķ•©ė‹ˆė‹¤. ģ°½ģ„ ė‹¤ģ‹œ ģ—“ė©“ ģ¤‘ė‹Øėœ ģœ„ģ¹˜ģ—ģ„œ ź³„ģ†ķ•  수 ģžˆģŠµė‹ˆė‹¤.", + "open": "ģ—“źø°", + "openFolder": "ķ“ė” ģ—“źø°", "openFile": "ķŒŒģ¼ ģ—“źø°", - "openFolder": "ķ“ė” ģ—“źø°" + "workspaceOpenedMessage": "'{0}' ģž‘ģ—… ģ˜ģ—­ģ„ ģ €ģž„ķ•  수 ģ—†ģŒ", + "workspaceOpenedDetail": "ģž‘ģ—… ģ˜ģ—­ģ“ ģ“ėÆø 다넸 창에 ģ—“ė øģŠµė‹ˆė‹¤. 먼저 핓당 ģ°½ģ„ ė‹«ģ€ 후 ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "openWorkspace": "ģ—“źø°(&&O)", + "openWorkspaceTitle": "ģž‘ģ—… ģ˜ģ—­ ģ—“źø°", + "save": "ģ €ģž„(&&S)", + "doNotSave": "ģ €ģž„ ģ•ˆ 함(&&N)", + "cancel": "ģ·Øģ†Œ", + "saveWorkspaceMessage": "ģž‘ģ—… ģ˜ģ—­ źµ¬ģ„±ģ„ ķŒŒģ¼ė”œ ģ €ģž„ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "saveWorkspaceDetail": "ģž‘ģ—… ģ˜ģ—­ģ„ ė‹¤ģ‹œ 엓려멓 ģž‘ģ—… ģ˜ģ—­ģ„ ģ €ģž„ķ•˜ģ„øģš”.", + "saveWorkspace": "ģž‘ģ—… ģ˜ģ—­ ģ €ģž„" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/browser/widget/diffEditorWidget.i18n.json b/i18n/kor/src/vs/editor/browser/widget/diffEditorWidget.i18n.json index 8b6ad71cd4e..748a7f2cb39 100644 --- a/i18n/kor/src/vs/editor/browser/widget/diffEditorWidget.i18n.json +++ b/i18n/kor/src/vs/editor/browser/widget/diffEditorWidget.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "diff.tooLarge": "ķŒŒģ¼ 1ź°œź°€ ė„ˆė¬“ ģ»¤ģ„œ ķŒŒģ¼ģ„ 비교할 수 ģ—†ģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json index 2c53ffbfb61..7bfa5cfc187 100644 --- a/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "줄 ė†’ģ“ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤. fontSizeģ˜ lineHeight넼 ź³„ģ‚°ķ•˜ė ¤ė©“ 0ģ„ ģ‚¬ģš©ķ•©ė‹ˆė‹¤.", "letterSpacing": "źø€ģž ź°„ź²©ģ„ 픽셀 ė‹Øģœ„ė”œ ģ”°ģ •ķ•©ė‹ˆė‹¤.", "lineNumbers": "줄 ė²ˆķ˜øģ˜ ķ‘œģ‹œ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. ź°€ėŠ„ķ•œ ź°’ģ€ 'on', 'off', 'relative'ģž…ė‹ˆė‹¤. 'relative'ėŠ” ķ˜„ģž¬ ģ»¤ģ„œ ģœ„ģ¹˜ģ—ģ„œ 줄 수넼 ķ‘œģ‹œķ•©ė‹ˆė‹¤.", - "rulers": "ģ„øė”œ ėˆˆźøˆģžė„¼ ķ‘œģ‹œķ•  ģ—“", + "rulers": "ķŠ¹ģ • ģˆ˜ģ˜ ź³ ģ • ķ­ ė¬øģž 뒤에 ģ„øė”œ ėˆˆźøˆģžė„¼ ė Œė”ė§ķ•©ė‹ˆė‹¤. ģ—¬ėŸ¬ ėˆˆźøˆģžģ˜ 경우 ģ—¬ėŸ¬ ź°’ģ„ ģ‚¬ģš©ķ•©ė‹ˆė‹¤. ė°°ģ—“ģ“ 비얓 ģžˆėŠ” 경우 ėˆˆźøˆģžź°€ 그려져 ģžˆģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "wordSeparators": "단얓 ꓀련 ķƒģƒ‰ ė˜ėŠ” ģž‘ģ—…ģ„ ģˆ˜ķ–‰ķ•  ė•Œ 단얓 구분 기호딜 ģ‚¬ģš©ė˜ėŠ” ė¬øģžģž…ė‹ˆė‹¤.", "tabSize": "탭 ķ•œ ź°œģ— ķ•“ė‹¹ķ•˜ėŠ” 공백 ģˆ˜ģž…ė‹ˆė‹¤. `editor.detectIndentation`ģ“ 켜져 ģžˆėŠ” 경우 ģ“ ģ„¤ģ •ģ€ ķŒŒģ¼ ģ½˜ķ…ģø ģ— ė”°ė¼ ģž¬ģ •ģ˜ė©ė‹ˆė‹¤.", "tabSize.errorMessage": "'number'ź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤. ź°’ \"auto\"ėŠ” `editor.detectIndentation` 설정에 ģ˜ķ•“ ė°”ė€Œģ—ˆģŠµė‹ˆė‹¤.", @@ -20,8 +20,9 @@ "detectIndentation": "ķŒŒģ¼ģ„ ģ—“ė©“ ķŒŒģ¼ ģ½˜ķ…ģø ė„¼ 기반으딜 ķ•˜ģ—¬ 'editor.tabSize'와 'editor.insertSpaces'ź°€ ź²€ģƒ‰ė©ė‹ˆė‹¤.", "roundedSelection": "ģ„ ķƒ ķ•­ėŖ©ģ˜ ėŖØģ„œė¦¬ė„¼ ė‘„źø€ź²Œ ķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "scrollBeyondLastLine": "ķŽøģ§‘źø°ģ—ģ„œ ė§ˆģ§€ė§‰ 줄 ģ“ķ›„ė”œ ģŠ¤ķ¬ė”¤ķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", + "smoothScrolling": "ķŽøģ§‘źø°ģ—ģ„œ ģ• ė‹ˆė©”ģ“ģ…˜ģ„ ģ‚¬ģš©ķ•˜ģ—¬ ģŠ¤ķ¬ė”¤ķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "minimap.enabled": "ėÆøė‹ˆė§µ ķ‘œģ‹œ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", - "minimap.showSlider": "ėÆøė‹ˆė§µ ģŠ¬ė¼ģ“ė”ė„¼ ģžė™ģœ¼ė”œ ģˆØźøøģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤.", + "minimap.showSlider": "ėÆøė‹ˆė§µ ģŠ¬ė¼ģ“ė”ė„¼ ģžė™ģœ¼ė”œ ģˆØźøøģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤. ź°€ėŠ„ķ•œ ź°’ģ€ 'always' ė° 'mouseover'ģž…ė‹ˆė‹¤.", "minimap.renderCharacters": "ģ¤„ģ˜ ģ‹¤ģ œ ė¬øģž(ģƒ‰ ėø”ė” ģ•„ė‹˜) ė Œė”ė§", "minimap.maxColumn": "ģµœėŒ€ ķŠ¹ģ • ģˆ˜ģ˜ ģ—“ģ„ ė Œė”ė§ķ•˜ė„ė” ėÆøė‹ˆė§µģ˜ ė„ˆė¹„ė„¼ ģ œķ•œķ•©ė‹ˆė‹¤.", "find.seedSearchStringFromSelection": "ķŽøģ§‘źø° ģ„ ķƒģ—ģ„œ Find Widgetģ˜ ź²€ģƒ‰ ė¬øģžģ—“ģ„ ģ‹œė”©ķ• ģ§€ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", @@ -46,10 +47,13 @@ "autoClosingBrackets": "ź“„ķ˜øė„¼ ģ—° ė‹¤ģŒģ— ķŽøģ§‘źø°ģ—ģ„œ ź“„ķ˜øė„¼ ģžė™ģœ¼ė”œ ė‹«ģ„ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "formatOnType": "ģž…ė „ 후 ķŽøģ§‘źø°ģ—ģ„œ ģžė™ģœ¼ė”œ ģ¤„ģ˜ ģ„œģ‹ģ„ 지정할지 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "formatOnPaste": "ė¶™ģ—¬ė„£ģ€ ģ½˜ķ…ģø ģ˜ ģ„œģ‹ģ„ ķŽøģ§‘źø°ģ—ģ„œ ģžė™ģœ¼ė”œ 지정할지 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. ķ¬ė§·ķ„°ėŠ” ė°˜ė“œģ‹œ ģ‚¬ģš©ķ•  수 ģžˆģ–“ģ•¼ ķ•˜ė©° ė¬øģ„œģ—ģ„œ ė²”ģœ„ģ˜ ģ„œģ‹ģ„ 지정할 수 ģžˆģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", - "autoIndent": "ģ‚¬ģš©ģžź°€ ģž…ė „ģ„ ķ•˜ź±°ė‚˜ ķ–‰ģ„ 붙여넣기 ė˜ėŠ” ģ“ė™ķ•  ė•Œ ķŽøģ§‘źø°ź°€ ģžė™ģœ¼ė”œ 들여쓰기넼 ģ ģš©ķ• ģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤. 핓당 ģ–øģ–“ģ˜ 들여쓰기 ź·œģ¹™ģ“ ģžˆģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", "suggestOnTriggerCharacters": "트리거 ė¬øģžė„¼ ģž…ė „ķ•  ė•Œ ģ œģ•ˆģ„ ģžė™ģœ¼ė”œ ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "acceptSuggestionOnEnter": "'Tab' 키 외에 'Enter' 키에 ėŒ€ķ•œ ģ œģ•ˆė„ ķ—ˆģš©ķ• ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤. 새 ģ¤„ģ„ ģ‚½ģž…ķ•˜ėŠ” ė™ģž‘ź³¼ ģ œģ•ˆģ„ ķ—ˆģš©ķ•˜ėŠ” ė™ģž‘ ź°„ģ˜ ėŖØķ˜øķ•Øģ„ 없앨 수 ģžˆģŠµė‹ˆė‹¤.", "acceptSuggestionOnCommitCharacter": "커밋 ė¬øģžģ— ėŒ€ķ•œ ģ œģ•ˆģ„ ķ—ˆģš©ķ• ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤. 예넼 들얓 JavaScriptģ—ģ„œėŠ” ģ„øėÆøģ½œė” (';')ģ“ ģ œģ•ˆģ„ ķ—ˆģš©ķ•˜ź³  핓당 ė¬øģžė„¼ ģž…ė „ķ•˜ėŠ” 커밋 ė¬øģžģ¼ 수 ģžˆģŠµė‹ˆė‹¤.", + "snippetSuggestions.top": "다넸 ģ œģ•ˆ ģœ„ģ— 씰각 ģ œģ•ˆģ„ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", + "snippetSuggestions.bottom": "다넸 ģ œģ•ˆ ģ•„ėž˜ģ— 씰각 ģ œģ•ˆģ„ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", + "snippetSuggestions.inline": "다넸 ģ œģ•ˆź³¼ ķ•Øź»˜ 씰각 ģ œģ•ˆģ„ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", + "snippetSuggestions.none": "ģ½”ė“œ 씰각 ģ œģ•ˆģ„ ķ‘œģ‹œķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.\n", "snippetSuggestions": "ģ½”ė“œ ģ”°ź°ģ“ 다넸 ģ¶”ģ²œź³¼ ķ•Øź»˜ ķ‘œģ‹œė˜ėŠ”ģ§€ 여부 ė° ģ •ė ¬ ė°©ė²•ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤.", "emptySelectionClipboard": "ģ„ ķƒ ģ˜ģ—­ ģ—†ģ“ ķ˜„ģž¬ 줄 복사 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "wordBasedSuggestions": "ė¬øģ„œ ė‚“ 단얓넼 기반으딜 ģ™„ģ„±ģ„ 계산할지 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", @@ -82,6 +86,8 @@ "accessibilitySupport.off": "ķŽøģ§‘źø°ź°€ 스크린 ė¦¬ė” ģ‚¬ģš©ģ„ ģœ„ķ•“ ģµœģ ķ™”ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "accessibilitySupport": "ķŽøģ§‘źø°ė„¼ 스크린 ė¦¬ė”ė„¼ ģœ„ķ•“ ģµœģ ķ™”ėœ ėŖØė“œė”œ 실행할지 ź²°ģ •ķ•©ė‹ˆė‹¤.", "links": "ķŽøģ§‘źø°ģ—ģ„œ 링크넼 ź°ģ§€ķ•˜ź³  큓릭할 수 ģžˆź²Œ ė§Œė“¤ģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤.", + "colorDecorators": "ķŽøģ§‘źø°ģ—ģ„œ ģøė¼ģø ģƒ‰ ė°ģ½”ė ˆģ“ķ„° ė° ģƒ‰ ģ„ ķƒģ„ ė Œė”ė§ķ• ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", + "codeActions": "ģ½”ė“œ ė™ģž‘ 전구넼 ģ‚¬ģš©ķ•©ė‹ˆė‹¤.", "sideBySide": "diff ķŽøģ§‘źø°ģ—ģ„œ diff넼 ė‚˜ėž€ķžˆ ķ‘œģ‹œķ• ģ§€ ģøė¼ģøģœ¼ė”œ ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "ignoreTrimWhitespace": "diff ķŽøģ§‘źø°ģ—ģ„œ ģ„ ķ–‰ 공백 ė˜ėŠ” 후행 공백 ė³€ź²½ģ„ diffs딜 ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "renderIndicators": "diff ķŽøģ§‘źø°ģ—ģ„œ 추가/제거된 변경 ė‚“ģš©ģ— ėŒ€ķ•“ +/- ķ‘œģ‹œźø°ė„¼ ķ‘œģ‹œķ•˜ėŠ”ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", diff --git a/i18n/kor/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/kor/src/vs/editor/common/view/editorColorRegistry.i18n.json index dcef1416eba..a8423dd155b 100644 --- a/i18n/kor/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/kor/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -8,6 +8,7 @@ "lineHighlightBorderBox": "ģ»¤ģ„œ ģœ„ģ¹˜ģ˜ 줄 ķ…Œė‘ė¦¬ģ— ėŒ€ķ•œ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "rangeHighlight": "빠넸 ģ—“źø° ė° 찾기 기늄 ė“±ģ„ 통핓 ź°•ģ”° ķ‘œģ‹œėœ ģ˜ģ—­ģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "caret": "ķŽøģ§‘źø° ģ»¤ģ„œ ģƒ‰ģž…ė‹ˆė‹¤.", + "editorCursorBackground": "ķŽøģ§‘źø° ģ»¤ģ„œģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ėø”ė” ģ»¤ģ„œģ™€ ź²¹ģ¹˜ėŠ” źø€ģžģ˜ ģƒ‰ģƒģ„ ģ‚¬ģš©ģž ģ •ģ˜ķ•  수 ģžˆģŠµė‹ˆė‹¤.", "editorWhitespaces": "ķŽøģ§‘źø°ģ˜ 공백 ė¬øģž ģƒ‰ģž…ė‹ˆė‹¤.", "editorIndentGuides": "ķŽøģ§‘źø° 들여쓰기 ģ•ˆė‚“ģ„  ģƒ‰ģž…ė‹ˆė‹¤.", "editorLineNumbers": "ķŽøģ§‘źø° 줄 번호 ģƒ‰ģž…ė‹ˆė‹¤.", @@ -20,5 +21,11 @@ "errorForeground": "ķŽøģ§‘źø° ė‚“ 오넘 ķ‘œģ‹œģ„ ģ˜ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "errorBorder": "ķŽøģ§‘źø° ė‚“ 오넘 ķ‘œģ‹œģ„ ģ˜ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤.", "warningForeground": "ķŽøģ§‘źø° ė‚“ 경고 ķ‘œģ‹œģ„ ģ˜ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", - "warningBorder": "ķŽøģ§‘źø° ė‚“ 경고 ķ‘œģ‹œģ„ ģ˜ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤." + "warningBorder": "ķŽøģ§‘źø° ė‚“ 경고 ķ‘œģ‹œģ„ ģ˜ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤.", + "infoForeground": "ķŽøģ§‘źø° ė‚“ 정볓 ķ‘œģ‹œģ„ ģ˜ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "infoBorder": "ķŽøģ§‘źø° ė‚“ 정볓 ķ‘œģ‹œģ„ ģ˜ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerRangeHighlight": "ė²”ģœ„ ź°•ģ”° ķ‘œģ‹œģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRuleError": "ģ˜¤ė„˜ģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRuleWarning": "ź²½ź³ ģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRuleInfo": "ģ •ė³“ģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json index c60d6d54352..f820392132e 100644 --- a/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "바꾸기", "label.replaceAllButton": "모두 바꾸기", "label.toggleReplaceButton": "바꾸기 ėŖØė“œ 설정/ķ•“ģ œ", - "title.matchesCountLimit": "ģ²˜ģŒ 999ź°œģ˜ 결과가 ź°•ģ”° ķ‘œģ‹œė˜ģ§€ė§Œ ėŖØė“  찾기 ģž‘ģ—…ģ€ 전첓 ķ…ģŠ¤ķŠøģ— ėŒ€ķ•“ ģˆ˜ķ–‰ė©ė‹ˆė‹¤.", + "title.matchesCountLimit": "ģ²˜ģŒ {0}ź°œģ˜ 결과가 ź°•ģ”° ķ‘œģ‹œė˜ģ§€ė§Œ ėŖØė“  찾기 ģž‘ģ—…ģ€ 전첓 ķ…ģŠ¤ķŠøģ— ėŒ€ķ•“ ģˆ˜ķ–‰ė©ė‹ˆė‹¤.", "label.matchesLocation": "{0}/{1}", "label.noResults": "ź²°ź³¼ ģ—†ģŒ" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json index 8c6b4441dfc..7201d1ab08f 100644 --- a/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,10 +10,6 @@ "nextSelectionMatchFindAction": "ė‹¤ģŒ ģ„ ķƒ 찾기", "previousSelectionMatchFindAction": "ģ“ģ „ ģ„ ķƒ 찾기", "startReplace": "바꾸기", - "addSelectionToNextFindMatch": "ė‹¤ģŒ ģ¼ģ¹˜ ķ•­ėŖ© 찾기에 ģ„ ķƒ ķ•­ėŖ© 추가", - "addSelectionToPreviousFindMatch": "ģ“ģ „ ģ¼ģ¹˜ ķ•­ėŖ© 찾기에 ģ„ ķƒ ķ•­ėŖ© 추가", - "moveSelectionToNextFindMatch": "ė‹¤ģŒ ģ¼ģ¹˜ ķ•­ėŖ© 찾기딜 ė§ˆģ§€ė§‰ ģ„ ķƒ ķ•­ėŖ© ģ“ė™", - "moveSelectionToPreviousFindMatch": "ė§ˆģ§€ė§‰ ģ„ ķƒ ķ•­ėŖ©ģ„ ģ“ģ „ ģ¼ģ¹˜ ķ•­ėŖ© 찾기딜 ģ“ė™", - "selectAllOccurrencesOfFindMatch": "ģ¼ģ¹˜ ķ•­ėŖ© ģ°¾źø°ģ˜ ėŖØė“  ķ•­ėŖ© ģ„ ķƒ", - "changeAll.label": "ėŖØė“  ķ•­ėŖ© 변경" + "showNextFindTermAction": "ė‹¤ģŒ ź²€ģƒ‰ģ–“ ķ‘œģ‹œ", + "showPreviousFindTermAction": "ģ“ģ „ ź²€ģƒ‰ģ–“ ķ‘œģ‹œ" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/kor/src/vs/editor/contrib/format/browser/formatActions.i18n.json index bab39c690ec..8811618c869 100644 --- a/i18n/kor/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "줄 {1}ģ—ģ„œ {0}개 ģ„œģ‹ ķŽøģ§‘ģ„ ģˆ˜ķ–‰ķ–ˆģŠµė‹ˆė‹¤.", "hint1n": "줄 {0}ź³¼(와) {1} ģ‚¬ģ“ģ—ģ„œ 1개 ģ„œģ‹ ķŽøģ§‘ģ„ ģˆ˜ķ–‰ķ–ˆģŠµė‹ˆė‹¤.", "hintnn": "줄 {1}ź³¼(와) {2} ģ‚¬ģ“ģ—ģ„œ {0}개 ģ„œģ‹ ķŽøģ§‘ģ„ ģˆ˜ķ–‰ķ–ˆģŠµė‹ˆė‹¤.", + "no.provider": "죄솔 ķ•©ė‹ˆė‹¤, ķ•˜ģ§€ė§Œ ' {0} 'ķŒŒģ¼ģ— ėŒ€ ķ•œ ķ¬ė§·ķ„°ź°€ ģ”“ģž¬ ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤..", "formatDocument.label": "ė¬øģ„œ ģ„œģ‹", "formatSelection.label": "ģ„ ķƒ ģ˜ģ—­ ģ„œģ‹" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/kor/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 9d89202d022..58029e4cfcd 100644 --- a/i18n/kor/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "ģ“ģ „ 오넘 ė˜ėŠ” 경고딜 ģ“ė™", "editorMarkerNavigationError": "ķŽøģ§‘źø° ķ‘œģ‹ ķƒģƒ‰ ģœ„ģ Æ 오넘 ģƒ‰ģž…ė‹ˆė‹¤.", "editorMarkerNavigationWarning": "ķŽøģ§‘źø° ķ‘œģ‹ ķƒģƒ‰ ģœ„ģ Æ 경고 ģƒ‰ģž…ė‹ˆė‹¤.", + "editorMarkerNavigationInfo": "ķŽøģ§‘źø° ķ‘œģ‹ ķƒģƒ‰ ģœ„ģ Æ 정볓 ģƒ‰ģž…ė‹ˆė‹¤.", "editorMarkerNavigationBackground": "ķŽøģ§‘źø° ķ‘œģ‹ ķƒģƒ‰ ģœ„ģ Æ ė°°ź²½ģž…ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/links/browser/links.i18n.json b/i18n/kor/src/vs/editor/contrib/links/browser/links.i18n.json index ddf7b26a227..2bc3afdb9fc 100644 --- a/i18n/kor/src/vs/editor/contrib/links/browser/links.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/links/browser/links.i18n.json @@ -6,7 +6,10 @@ { "links.navigate.mac": "Cmd 키넼 ėˆ„ė„“ź³  ķ“ė¦­ķ•˜ģ—¬ 링크딜 ģ“ė™", "links.navigate": "Ctrl 키넼 ėˆ„ė„“ź³  ķ“ė¦­ķ•˜ģ—¬ 링크딜 ģ“ė™", + "links.command.mac": "ėŖ…ė ¹ģ„ ģ‹¤ķ–‰ķ•˜ė ¤ė©“ Cmd+큓릭", + "links.command": "ėŖ…ė ¹ģ„ ģ‹¤ķ–‰ķ•˜ė ¤ė©“ Ctrl+큓릭", "links.navigate.al": "Alt 키넼 ėˆ„ė„“ź³  ķ“ė¦­ķ•˜ģ—¬ 링크딜 ģ“ė™", + "links.command.al": "ėŖ…ė ¹ģ„ ģ‹¤ķ–‰ķ•˜ė ¤ė©“ Alt+큓릭", "invalid.url": "ģ£„ģ†”ķ•©ė‹ˆė‹¤. ģ“ ė§ķ¬ėŠ” ķ˜•ģ‹ģ“ ģ˜¬ė°”ė„“ģ§€ ģ•Šģœ¼ėÆ€ė”œ ģ—“ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤. {0}", "missing.url": "ģ£„ģ†”ķ•©ė‹ˆė‹¤. ėŒ€ģƒģ“ ģ—†ģœ¼ėÆ€ė”œ ģ“ 링크넼 ģ—“ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤.", "label": "링크 ģ—“źø°" diff --git a/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 2cd42573465..af6f5d6235c 100644 --- a/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "ģœ„ģ— ģ»¤ģ„œ 추가", "mutlicursor.insertBelow": "ģ•„ėž˜ģ— ģ»¤ģ„œ 추가", - "mutlicursor.insertAtEndOfEachLineSelected": "줄 ėģ— ģ»¤ģ„œ 추가" + "mutlicursor.insertAtEndOfEachLineSelected": "줄 ėģ— ģ»¤ģ„œ 추가", + "addSelectionToNextFindMatch": "ė‹¤ģŒ ģ¼ģ¹˜ ķ•­ėŖ© 찾기에 ģ„ ķƒ ķ•­ėŖ© 추가", + "addSelectionToPreviousFindMatch": "ģ“ģ „ ģ¼ģ¹˜ ķ•­ėŖ© 찾기에 ģ„ ķƒ ķ•­ėŖ© 추가", + "moveSelectionToNextFindMatch": "ė‹¤ģŒ ģ¼ģ¹˜ ķ•­ėŖ© 찾기딜 ė§ˆģ§€ė§‰ ģ„ ķƒ ķ•­ėŖ© ģ“ė™", + "moveSelectionToPreviousFindMatch": "ė§ˆģ§€ė§‰ ģ„ ķƒ ķ•­ėŖ©ģ„ ģ“ģ „ ģ¼ģ¹˜ ķ•­ėŖ© 찾기딜 ģ“ė™", + "selectAllOccurrencesOfFindMatch": "ģ¼ģ¹˜ ķ•­ėŖ© ģ°¾źø°ģ˜ ėŖØė“  ķ•­ėŖ© ģ„ ķƒ", + "changeAll.label": "ėŖØė“  ķ•­ėŖ© 변경" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/kor/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..9befc5560b1 --- /dev/null +++ b/i18n/kor/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "ė‹«źø°" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/kor/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index 4ea06482be0..ab340d73f19 100644 --- a/i18n/kor/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "ė³€ģˆ˜ ģ½źø°ģ™€ ź°™ģ€ ģ½źø° ģ•”ģ„øģŠ¤ 중 źø°ķ˜øģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", - "wordHighlightStrong": "ė³€ģˆ˜ģ— 쓰기와 ź°™ģ€ ģ“°źø° ģ•”ģ„øģŠ¤ 중 źø°ķ˜øģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤." + "wordHighlightStrong": "ė³€ģˆ˜ģ— 쓰기와 ź°™ģ€ ģ“°źø° ģ•”ģ„øģŠ¤ 중 źø°ķ˜øģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerWordHighlightForeground": "기호 ź°•ģ”° ķ‘œģ‹œģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerWordHighlightStrongForeground": "ģ“°źø° ź¶Œķ•œ 기호 ź°•ģ”° ķ‘œģ‹œģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "wordHighlight.next.label": "ė‹¤ģŒ ź°•ģ”° 기호딜 ģ“ė™", + "wordHighlight.previous.label": "ģ“ģ „ ź°•ģ”° 기호딜 ģ“ė™" } \ No newline at end of file diff --git a/i18n/kor/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/kor/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 1c5f62b7b23..ee9870e16a1 100644 --- a/i18n/kor/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/kor/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "ģ“ ėŖ…ė ¹ģ“ ģ†ķ•˜ėŠ” ź·øė£¹ģž…ė‹ˆė‹¤.", "vscode.extension.contributes.menus": "ķŽøģ§‘źø°ģ— 메뉓 ķ•­ėŖ©ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", "menus.commandPalette": "ėŖ…ė ¹ ķŒ”ė ˆķŠø", + "menus.touchBar": "ķ„°ģ¹˜ ė°”(macOS ģ „ģš©)", "menus.editorTitle": "ķŽøģ§‘źø° 제목 메뉓", "menus.editorContext": "ķŽøģ§‘źø° ģƒķ™©ģ— ė§žėŠ” 메뉓", "menus.explorerContext": "ķŒŒģ¼ ķƒģƒ‰źø° ģƒķ™©ģ— ė§žėŠ” 메뉓", "menus.editorTabContext": "ķŽøģ§‘źø° 탭 ģƒķ™©ģ— ė§žėŠ” 메뉓", "menus.debugCallstackContext": "디버그 호출 ģŠ¤ķƒ ģƒķ™©ģ— ė§žėŠ” 메뉓", "menus.scmTitle": "ģ†ŒģŠ¤ ģ œģ–“ 제목 메뉓", + "menus.scmSourceControl": "ģ†ŒģŠ¤ ģ œģ–“ 메뉓", "menus.resourceGroupContext": "ģ†ŒģŠ¤ ģ œģ–“ ė¦¬ģ†ŒģŠ¤ 그룹 ģƒķ™©ģ— ė§žėŠ” 메뉓", "menus.resourceStateContext": "ģ†ŒģŠ¤ ģ œģ–“ ė¦¬ģ†ŒģŠ¤ 상태 ģƒķ™©ģ— ė§žėŠ” 메뉓", "view.viewTitle": "źø°ģ—¬ 씰회 제목 메뉓", diff --git a/i18n/kor/src/vs/platform/environment/node/argv.i18n.json b/i18n/kor/src/vs/platform/environment/node/argv.i18n.json index 95f21567a73..b8dae1071a7 100644 --- a/i18n/kor/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/kor/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "`--goto` ėŖØė“œģ—ģ„œ ģøģˆ˜ėŠ” `FILE(:LINE(:CHARACTER))` ķ˜•ģ‹ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", - "diff": "diff ķŽøģ§‘źø°ė„¼ ģ—½ė‹ˆė‹¤. ģøģˆ˜ė”œ 두 ź°œģ˜ ķŒŒģ¼ 경딜넼 전달핓야 ķ•©ė‹ˆė‹¤.", - "goto": "줄과 ė¬øģžģ— ģžˆėŠ” ź²½ė”œģ˜ ķŒŒģ¼ģ„ ģ—½ė‹ˆė‹¤(ź²½ė”œģ— :line[:character] 추가).", + "diff": "두 ķŒŒģ¼ģ„ ģ„œė”œ ė¹„źµķ•©ė‹ˆė‹¤.", + "add": "ė§ˆģ§€ė§‰ ķ™œģ„± 창에 ķ“ė”ė„¼ ģ¶”ź°€ķ•©ė‹ˆė‹¤.", + "goto": "ģ§€ģ •ėœ 줄과 ė¬øģž ģœ„ģ¹˜ģ— ģžˆėŠ” ź²½ė”œģ˜ ķŒŒģ¼ģ„ ģ—½ė‹ˆė‹¤.", "locale": "ģ‚¬ģš©ķ•  딜캘(예: en-US ė˜ėŠ” zh-TW)ģž…ė‹ˆė‹¤.", "newWindow": "Codeģ˜ 새 ģøģŠ¤ķ„“ģŠ¤ė„¼ ź°•ģ œ ģ ģš©ķ•©ė‹ˆė‹¤.", "performance": "'Developer: Startup Performance' ėŖ…ė ¹ģ„ ģ‚¬ģš©ķ•˜ģ—¬ ģ‹œģž‘ķ•©ė‹ˆė‹¤.", @@ -14,7 +15,7 @@ "reuseWindow": "ė§ˆģ§€ė§‰ ķ™œģ„± ģ°½ģ—ģ„œ ķŒŒģ¼ ė˜ėŠ” ķ“ė”ė„¼ ź°•ģ œė”œ ģ—½ė‹ˆė‹¤.", "userDataDir": "ģ‚¬ģš©ģž ė°ģ“ķ„°ź°€ ģ €ģž„ė˜ėŠ” 디렉터리넼 ģ§€ģ •ķ•©ė‹ˆė‹¤(루트딜 실행할 경우 ģœ ģš©ķ•Ø).", "verbose": "ģžģ„øķ•œ 정볓 ķ‘œģ‹œė„¼ ģ¶œė „ķ•©ė‹ˆė‹¤(--wait넼 ģ˜ėÆø).", - "wait": "ģ°½ģ“ ė‹«ķž ė•Œź¹Œģ§€ 기다린 후 ėŒģ•„ź°‘ė‹ˆė‹¤.", + "wait": "ķŒŒģ¼ģ“ ė‹«ķž ė•Œ ź¹Œģ§€ 기다린 후 ėŒģ•„ź°‘ė‹ˆė‹¤.", "extensionHomePath": "ķ™•ģž„ģ˜ 루트 경딜넼 ģ„¤ģ •ķ•©ė‹ˆė‹¤.", "listExtensions": "ģ„¤ģ¹˜ėœ ķ™•ģž„ģ„ ė‚˜ģ—“ķ•©ė‹ˆė‹¤.", "showVersions": "#NAME?", diff --git a/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 7119dd38b12..a346e007e1c 100644 --- a/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "ģž˜ėŖ»ėœ ķ™•ģž„: package.jsonģ“ JSON ķŒŒģ¼ģ“ ģ•„ė‹™ė‹ˆė‹¤.", - "restartCode": "{0}ģ„(넼) ė‹¤ģ‹œ ģ„¤ģ¹˜ķ•˜źø° 전에 Code넼 ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ģ„øģš”.", - "installDependeciesConfirmation": "'{0}'ģ„(넼) ģ„¤ģ¹˜ķ•˜ė©“ ģ¢…ģ†ģ„±ė„ ģ„¤ģ¹˜ė©ė‹ˆė‹¤. ź³„ģ†ķ• ź¹Œģš”?", - "install": "예", - "doNotInstall": "ģ•„ė‹ˆģš”", + "restartCodeLocal": "{0}ģ„(넼) ė‹¤ģ‹œ ģ„¤ģ¹˜ķ•˜źø° 전에 Code넼 ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ģ„øģš”.", + "restartCodeGallery": "ė‹¤ģ‹œ ģ„¤ģ¹˜ķ•˜źø° 전에 Code넼 ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ģ„øģš”.", "uninstallDependeciesConfirmation": "'{0}'만 ģ œź±°ķ• ź¹Œģš”, ģ•„ė‹ˆė©“ ģ¢…ģ†ģ„±ė„ ģ œź±°ķ• ź¹Œģš”?", "uninstallOnly": "만", "uninstallAll": "모두", diff --git a/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 7207158c622..cb72ee5dd24 100644 --- a/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "VS Code ķ™•ģž„ģ— ėŒ€ķ•œ ķ™œģ„±ķ™” ģ“ė²¤ķŠøģž…ė‹ˆė‹¤.", "vscode.extension.activationEvents.onLanguage": "ģ§€ģ •ėœ ģ–øģ–“ė”œ ķ™•ģøė˜ėŠ” ķŒŒģ¼ģ„ ģ—“ ė•Œė§ˆė‹¤ ķ™œģ„±ķ™” ģ“ė²¤ķŠøź°€ ė°œģ†”ė©ė‹ˆė‹¤.", "vscode.extension.activationEvents.onCommand": "ģ§€ģ •ėœ ėŖ…ė ¹ģ„ ķ˜øģ¶œķ•  ė•Œė§ˆė‹¤ ķ™œģ„±ķ™” ģ“ė²¤ķŠøź°€ ė°œģ†”ė©ė‹ˆė‹¤.", - "vscode.extension.activationEvents.onDebug": "ģ§€ģ •ėœ ģœ ķ˜•ģ˜ 디버깅 ģ„øģ…˜ģ„ ģ‹œģž‘ķ•  ė•Œė§ˆė‹¤ ķ™œģ„±ķ™” ģ•Œė¦¼ģ“ ė°œģ†”ė©ė‹ˆė‹¤.", + "vscode.extension.activationEvents.onDebug": "ģ‚¬ģš©ģžź°€ ė””ė²„ź¹…ģ„ ģ‹œģž‘ķ•˜ź±°ė‚˜ 디버그 źµ¬ģ„±ģ„ ģ„¤ģ •ķ•˜ė ¤ź³  ķ•  ė•Œė§ˆė‹¤ ķ™œģ„±ķ™” ģ“ė²¤ķŠøė„¼ ė‚“ė³“ėƒ…ė‹ˆė‹¤.", "vscode.extension.activationEvents.workspaceContains": "ģ§€ģ •ėœ glob ķŒØķ„“ź³¼ ģ¼ģ¹˜ķ•˜ėŠ” ķŒŒģ¼ģ“ ķ•˜ė‚˜ ģ“ģƒ ģžˆėŠ” ķ“ė”ė„¼ ģ—“ ė•Œė§ˆė‹¤ ķ™œģ„±ķ™” ģ•Œė¦¼ģ“ ė°œģ†”ė©ė‹ˆė‹¤.", "vscode.extension.activationEvents.onView": "ģ§€ģ •ėœ ė·°ź°€ ķ™•ģž„ė  ė•Œė§ˆė‹¤ ķ™œģ„±ķ™” ģ“ė²¤ķŠøź°€ 낓볓낓 ģ§‘ė‹ˆė‹¤.", "vscode.extension.activationEvents.star": "VS Code ģ‹œģž‘ ģ‹œ ķ™œģ„±ķ™” ģ“ė²¤ķŠøź°€ ė°œģ†”ė©ė‹ˆė‹¤. ķ›Œė„­ķ•œ ģµœģ¢… ģ‚¬ģš©ģž ź²½ķ—˜ģ„ ė³“ģž„ķ•˜ė ¤ė©“ ģ‚¬ģš© ģ¼€ģ“ģŠ¤ģ—ģ„œ 다넸 ķ™œģ„±ķ™” ģ“ė²¤ķŠø ģ”°ķ•©ģ“ ģž‘ė™ķ•˜ģ§€ ģ•Šģ„ ė•Œģ—ė§Œ ķ™•ģž„ģ—ģ„œ ģ“ ķ™œģ„±ķ™” ģ“ė²¤ķŠøė„¼ ģ‚¬ģš©ķ•˜ģ„øģš”.", diff --git a/i18n/kor/src/vs/platform/history/electron-main/historyMainService.i18n.json b/i18n/kor/src/vs/platform/history/electron-main/historyMainService.i18n.json index ee033a6e86d..74f2992518a 100644 --- a/i18n/kor/src/vs/platform/history/electron-main/historyMainService.i18n.json +++ b/i18n/kor/src/vs/platform/history/electron-main/historyMainService.i18n.json @@ -6,5 +6,7 @@ { "newWindow": "새 ģ°½", "newWindowDesc": "새 ģ°½ģ„ ģ—½ė‹ˆė‹¤.", - "folderDesc": "{0} {1}" + "recentFolders": "최근 ģž‘ģ—… ģ˜ģ—­", + "folderDesc": "{0} {1}", + "codeWorkspace": "ģ½”ė“œ ģž‘ģ—… ģ˜ģ—­" } \ No newline at end of file diff --git a/i18n/kor/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/kor/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..9553ac369b7 --- /dev/null +++ b/i18n/kor/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "ķ™•ģž„ ģ •ģ˜ ķ…Œė§ˆ 지정 ź°€ėŠ„ ģƒ‰ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", + "contributes.color.id": "ķ…Œė§ˆ 지정 ź°€ėŠ„ ģƒ‰ģ˜ ģ‹ė³„ģžģž…ė‹ˆė‹¤.", + "contributes.color.id.format": "ģ‹ė³„ģžėŠ” aa[.bb]* ķ˜•ģ‹ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "contributes.color.description": "ķ…Œė§ˆ 지정 ź°€ėŠ„ ģƒ‰ģ— ėŒ€ķ•œ ģ„¤ėŖ…ģž…ė‹ˆė‹¤.", + "contributes.defaults.light": "ė°ģ€ ķ…Œė§ˆģ˜ źø°ė³ø ģƒ‰ģž…ė‹ˆė‹¤. 16ģ§„ģˆ˜ģ˜ ģƒ‰ ź°’(#RRGGBB[AA]) ė˜ėŠ” źø°ė³øź°’ģ„ ģ œź³µķ•˜ėŠ” ķ…Œė§ˆ 지정 ź°€ėŠ„ ģƒ‰ģ˜ ģ‹ė³„ģžģž…ė‹ˆė‹¤.", + "contributes.defaults.dark": "ģ–“ė‘ģš“ ķ…Œė§ˆģ˜ źø°ė³ø ģƒ‰ģž…ė‹ˆė‹¤. 16ģ§„ģˆ˜ģ˜ ģƒ‰ ź°’(#RRGGBB[AA]) ė˜ėŠ” źø°ė³øź°’ģ„ ģ œź³µķ•˜ėŠ” ķ…Œė§ˆ 지정 ź°€ėŠ„ ģƒ‰ģ˜ ģ‹ė³„ģžģž…ė‹ˆė‹¤.", + "contributes.defaults.highContrast": "ź³ ėŒ€ė¹„ ķ…Œė§ˆģ˜ źø°ė³ø ģƒ‰ģƒģž…ė‹ˆė‹¤. źø°ė³øź°’ģ„ ģ œź³µķ•˜ėŠ” 16ģ§„ģˆ˜(#RRGGBB[AA])ģ˜ ģƒ‰ģƒ ź°’ ė˜ėŠ” ķ…Œė§ˆ 지정 ź°€ėŠ„ ģƒ‰ģ˜ ģ‹ė³„ģžģž…ė‹ˆė‹¤.", + "invalid.colorConfiguration": "'configuration.colors'ėŠ” ė°°ģ—“ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "invalid.default.colorType": "{0}ģ€(ėŠ”) 16ģ§„ģˆ˜ģ˜ ģƒ‰ ź°’(#RRGGBB[AA] ė˜ėŠ” #RGB[A]) ė˜ėŠ” źø°ė³øź°’ģ„ ģ œź³µķ•˜ėŠ” ķ…Œė§ˆ 지정 ź°€ėŠ„ ģƒ‰ģ˜ ģ‹ė³„ģžģž…ė‹ˆė‹¤.", + "invalid.id": "'configuration.colors.id'넼 ģ •ģ˜ķ•“ģ•¼ ķ•˜ė©° ė¹„ģ›Œė‘˜ 수 ģ—†ģŠµė‹ˆė‹¤.", + "invalid.id.format": "'configuration.colors.id'ėŠ” 단얓[.word]* ė‹¤ģŒģ— 와야 ķ•©ė‹ˆė‹¤.", + "invalid.description": "'configuration.colors.description'ģ„ ģ •ģ˜ķ•“ģ•¼ ķ•˜ė©° ė¹„ģ›Œė‘˜ 수 ģ—†ģŠµė‹ˆė‹¤.", + "invalid.defaults": "'configuration.colors.defaults'넼 ģ •ģ˜ķ•“ģ•¼ ķ•˜ė©° 'light', 'dark' ė° 'highContrast'넼 ķ¬ķ•Øķ•“ģ•¼ ķ•©ė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json index ab5da7316c6..8e8997c7ddf 100644 --- a/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/kor/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "ģž˜ėŖ»ėœ ģƒ‰ ķ˜•ģ‹ģž…ė‹ˆė‹¤. #RGB, #RGBA, #RRGGBB ė˜ėŠ” #RRGGBBAA넼 ģ‚¬ģš©ķ•˜ģ„øģš”.", "schema.colors": "ģ›Œķ¬ė²¤ģ¹˜ģ—ģ„œ ģ‚¬ģš©ė˜ėŠ” ģƒ‰ģž…ė‹ˆė‹¤.", "foreground": "전첓 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ“ ģƒ‰ģ€ 구성 ģš”ģ†Œģ—ģ„œ ģž¬ģ •ģ˜ķ•˜ģ§€ ģ•Šģ€ ź²½ģš°ģ—ė§Œ ģ‚¬ģš©ė©ė‹ˆė‹¤.", "errorForeground": "오넘 ė©”ģ‹œģ§€ģ— ėŒ€ķ•œ 전첓 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ“ ģƒ‰ģ€ 구성 ģš”ģ†Œģ—ģ„œ ģž¬ģ •ģ˜ķ•˜ģ§€ ģ•Šģ€ ź²½ģš°ģ—ė§Œ ģ‚¬ģš©ė©ė‹ˆė‹¤.", @@ -53,6 +52,9 @@ "badgeBackground": "ė°°ģ§€ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ė°°ģ§€ėŠ” ź²€ģƒ‰ ź²°ź³¼ ģˆ˜ģ™€ ź°™ģ€ ģ†ŒėŸ‰ģ˜ 정볓 ė ˆģ“ėø”ģž…ė‹ˆė‹¤.", "badgeForeground": "ė°°ģ§€ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ė°°ģ§€ėŠ” ź²€ģƒ‰ ź²°ź³¼ ģˆ˜ģ™€ ź°™ģ€ ģ†ŒėŸ‰ģ˜ 정볓 ė ˆģ“ėø”ģž…ė‹ˆė‹¤.", "scrollbarShadow": "ģŠ¤ķ¬ė”¤ė˜ėŠ” 볓기넼 ė‚˜ķƒ€ė‚“ėŠ” 스크딤 ė§‰ėŒ€ ź·øė¦¼ģžģž…ė‹ˆė‹¤.", + "scrollbarSliderBackground": "스크딤 ė§‰ėŒ€ ģŠ¬ė¼ģ“ė²„ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "scrollbarSliderHoverBackground": "마우스딜 가리킬 ė•Œ 스크딤 ė§‰ėŒ€ ģŠ¬ė¼ģ“ė” ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "scrollbarSliderActiveBackground": "ķ™œģ„± ģƒķƒœģ¼ ė•Œ 스크딤 ė§‰ėŒ€ ģŠ¬ė¼ģ“ė” ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "progressBarBackground": "ģ˜¤ėž˜ 실행 ģ¤‘ģø ģž‘ģ—…ģ— ėŒ€ķ•“ ķ‘œģ‹œė˜ėŠ” 진행넠 ķ‘œģ‹œ ė§‰ėŒ€ģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "editorBackground": "ķŽøģ§‘źø° ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "editorForeground": "ķŽøģ§‘źø° źø°ė³ø ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", @@ -82,5 +84,7 @@ "mergeBorder": "ģøė¼ģø 병합 ģ¶©ėŒģ—ģ„œ ķ—¤ė” ė° ģŠ¤ķ”Œė¦¬ķ„°ģ˜ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤.", "overviewRulerCurrentContentForeground": "ģøė¼ģø 병합 ģ¶©ėŒģ—ģ„œ ķ˜„ģž¬ ź°œģš” 눈금 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "overviewRulerIncomingContentForeground": "ģøė¼ģø 병합 ģ¶©ėŒģ—ģ„œ ģˆ˜ģ‹  ź°œģš” 눈금 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", - "overviewRulerCommonContentForeground": "ģøė¼ģø 병합 ģ¶©ėŒģ—ģ„œ 공통 과거 ź°œģš” 눈금 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤." + "overviewRulerCommonContentForeground": "ģøė¼ģø 병합 ģ¶©ėŒģ—ģ„œ 공통 과거 ź°œģš” 눈금 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerFindMatchForeground": "찾기 ģ¼ģ¹˜ ķ•­ėŖ©ģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerSelectionHighlightForeground": "ģ„ ķƒ ģ˜ģ—­ ź°•ģ”° ķ‘œģ‹œģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/kor/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..6a58bb38610 --- /dev/null +++ b/i18n/kor/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "ģ½”ė“œ ģž‘ģ—… ģ˜ģ—­", + "untitledWorkspace": "제목 ģ—†ģŒ(ģž‘ģ—… ģ˜ģ—­)", + "workspaceNameVerbose": "{0}(ģž‘ģ—… ģ˜ģ—­)", + "workspaceName": "{0}(ģž‘ģ—… ģ˜ģ—­)" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/kor/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..22493f55ddf --- /dev/null +++ b/i18n/kor/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "ė·°ėŠ” ė°°ģ—“ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "requirestring": "ģ†ģ„± `{0}`ģ€(ėŠ”) ķ•„ģˆ˜ģ“ė©° `string` ķ˜•ģ‹ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "optstring": "ģ†ģ„± `{0}`ģ€(ėŠ”) ģƒėžµķ•  수 ģžˆģœ¼ė©° `string` ķ˜•ģ‹ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "vscode.extension.contributes.view.id": "ė·°ģ˜ ģ‹ė³„ģžģž…ė‹ˆė‹¤. 'vscode.window.registerTreeDataProviderForView` API넼 통핓 ė°ģ“ķ„° ź³µźø‰ģžė„¼ ė“±ė”ķ•˜ėŠ” ė° ģ‚¬ģš©ķ•©ė‹ˆė‹¤. `onView:${id}` ģ“ė²¤ķŠøė„¼ `activationEvents`에 ė“±ė”ķ•˜ģ—¬ ķ™•ģž„ ķ™œģ„±ķ™”ė„¼ ķŠøė¦¬ź±°ķ•˜ėŠ” ė°ģ—ė„ ģ‚¬ģš©ķ•©ė‹ˆė‹¤.", + "vscode.extension.contributes.view.name": "ģ‚¬ģš©ģžź°€ ģ½ģ„ 수 ģžˆėŠ” ė·° ģ“ė¦„ģž…ė‹ˆė‹¤. ķ‘œģ‹œė©ė‹ˆė‹¤.", + "vscode.extension.contributes.view.when": "ģ“ 볓기넼 ķ‘œģ‹œķ•˜źø° ģœ„ķ•“ true여야 ķ•˜ėŠ” ģ”°ź±“ģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.views": "뷰넼 에디터에 ģ ģš©ķ•©ė‹ˆė‹¤.", + "views.explorer": "ķƒģƒ‰źø° ė·°", + "views.debug": "디버그 볓기", + "locationId.invalid": "`{0}`ģ€(ėŠ”) ģœ ķšØķ•œ ė·° ģœ„ģ¹˜ź°€ ģ•„ė‹™ė‹ˆė‹¤.", + "duplicateView1": "ģœ„ģ¹˜ '{1}'ģ—ģ„œ ė™ģ¼ķ•œ ID '{0}'(으)딜된 ģ—¬ėŸ¬ ź°œģ˜ 볓기넼 ė“±ė”ķ•  수 ģ—†ģŠµė‹ˆė‹¤.", + "duplicateView2": "ID `{0}`ģ“(ź°€) ķ¬ķ•Øėœ ė·°ź°€ ģœ„ģ¹˜ `{1}`에 ģ“ėÆø ė“±ė”ė˜ģ–“ ģžˆģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/kor/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..6aaab18c9bf --- /dev/null +++ b/i18n/kor/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "ķ™•ģž„ `{1}`ģ„(넼) ķ™œģ„±ķ™”ķ•˜ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤. ģ“ģœ : ģ•Œ 수 ģ—†ėŠ” ģ¢…ģ†ģ„± `{0}`.", + "failedDep1": "ķ™•ģž„ `{1}`ģ„(넼) ķ™œģ„±ķ™”ķ•˜ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤. ģ“ģœ : ģ¢…ģ†ģ„± `{0}`ģ“(ź°€) ķ™œģ„±ķ™”ė˜ģ§€ ģ•Šģ•˜ģŠµė‹ˆė‹¤.", + "failedDep2": "ķ™•ģž„ `{0}`ģ„(넼) ķ™œģ„±ķ™”ķ•˜ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤. ģ“ģœ : ģ¢…ģ†ģ„± ģˆ˜ģ¤€ģ“ 10ź°œź°€ ė„˜ģŒ(ģ¢…ģ†ģ„± ė£Øķ”„ģ¼ ź°€ėŠ„ģ„±ģ“ ė†’ģŒ).", + "activationError": "ķ™•ģž„ `{0}` ķ™œģ„±ķ™” ģ‹¤ķŒØ: {1}." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 56b8182afa2..08bfa81a98e 100644 --- a/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,11 +4,18 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "ķŒŒģ¼ ģ—“źø°...", "openFolder": "ķ“ė” ģ—“źø°...", "openFileFolder": "ģ—“źø°...", - "cancel": "ģ·Øģ†Œ", "addFolderToWorkspace": "ģž‘ģ—… ģ˜ģ—­ģ— ķ“ė” 추가...", + "add": "추가(&&A)", "addFolderToWorkspaceTitle": "ģž‘ģ—… ģ˜ģ—­ģ— ķ“ė” 추가", "removeFolderFromWorkspace": "ģž‘ģ—… ģ˜ģ—­ģ—ģ„œ ķ“ė” ģ‚­ģ œ", - "save": "ģ €ģž„(&&S)" + "openFolderSettings": "ķ“ė” 설정 ģ—“źø°", + "saveWorkspaceAsAction": "ģž‘ģ—… ģ˜ģ—­ģ„ 다넸 ģ“ė¦„ģœ¼ė”œ ģ €ģž„", + "save": "ģ €ģž„(&&S)", + "saveWorkspace": "ģž‘ģ—… ģ˜ģ—­ ģ €ģž„", + "openWorkspaceAction": "ģž‘ģ—… ģ˜ģ—­ ģ—“źø°...", + "openWorkspaceConfigFile": "ģž‘ģ—… ģ˜ģ—­ 구성 ķŒŒģ¼ ģ—“źø°", + "workspaceFolderPickerPlaceholder": "ģž‘ģ—… ģ˜ģ—­ ķ“ė” ģ„ ķƒ" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 9f4e768eccf..2c8a795fe67 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "ģž‘ģ—… ė§‰ėŒ€ģ—ģ„œ 제거", - "keepInActivityBar": "ģž‘ģ—… ė§‰ėŒ€ģ— ģœ ģ§€", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0}({1})", + "removeFromActivityBar": "ģž‘ģ—… ė§‰ėŒ€ģ—ģ„œ 숨기기", + "keepInActivityBar": "ģž‘ģ—… ė§‰ėŒ€ģ— ģœ ģ§€", "additionalViews": "추가 ė·°", "numberBadge": "{0}({1})", "manageExtension": "ķ™•ģž„ ꓀리", diff --git a/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 775ac027185..6ab66076b97 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "ģž‘ģ—… ė§‰ėŒ€ 숨기기", - "activityBarAriaLabel": "ķ™œģ„± ė·° ģ „ķ™˜źø°", "globalActions": "ģ „ģ—­ ģž‘ģ—…" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..f515e983418 --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "ķ™œģ„± ė·° ģ „ķ™˜źø°" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..882b528591a --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "추가 ė·°", + "numberBadge": "{0}({1})", + "manageExtension": "ķ™•ģž„ ꓀리", + "titleKeybinding": "{0}({1})", + "toggle": "ė·° ź³ ģ • ģ „ķ™˜" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 29467820136..32f439e8de1 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "두 번째 그룹에 ķŽøģ§‘źø° ķ‘œģ‹œ", "groupThreePicker": "세 번째 그룹에 ķŽøģ§‘źø° ķ‘œģ‹œ", "allEditorsPicker": "ģ—“ė ¤ ģžˆėŠ” ėŖØė“  ķŽøģ§‘źø° ķ‘œģ‹œ", - "view": "볓기" + "view": "볓기", + "file": "ķŒŒģ¼" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 0977d6d1b49..d5bda0aa791 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,7 +35,9 @@ "openPreviousEditorInGroup": "ź·øė£¹ģ—ģ„œ ģ“ģ „ ķŽøģ§‘źø° ģ—“źø°", "navigateNext": "ģ•žģœ¼ė”œ ģ“ė™", "navigatePrevious": "ė’¤ė”œ ģ“ė™", + "navigateLast": "ė§ˆģ§€ė§‰ģœ¼ė”œ ģ“ė™", "reopenClosedEditor": "ė‹«ķžŒ ķŽøģ§‘źø° ė‹¤ģ‹œ ģ—“źø°", + "clearRecentFiles": "최근 ģ‚¬ģš© ķ•­ėŖ© ģ§€ģš°źø°", "showEditorsInFirstGroup": "첫 번째 그룹에 ķŽøģ§‘źø° ķ‘œģ‹œ", "showEditorsInSecondGroup": "두 번째 그룹에 ķŽøģ§‘źø° ķ‘œģ‹œ", "showEditorsInThirdGroup": "세 번째 그룹에 ķŽøģ§‘źø° ķ‘œģ‹œ", diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 4a541795165..3c0b9b984d4 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "Tab으딜 ķ¬ģ»¤ģŠ¤ ģ“ė™", - "screenReaderDetected": "화멓 ģ½źø° ķ”„ė”œź·øėžØ ź²€ģƒ‰ėØ", + "screenReaderDetected": "화멓 ģ½źø° ķ”„ė”œź·øėžØģ“ ģµœģ ķ™”ėØ", "screenReaderDetectedExtra": "화멓 ģ½źø° ķ”„ė”œź·øėžØģ„ ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠėŠ” 경우 `editor.accessibilitySupport` ģ„¤ģ •ģ„ \"off\"딜 ė³€ź²½ķ•˜ģ„øģš”.", "disableTabMode": "접근성 ėŖØė“œ ģ‚¬ģš© ģ•ˆ 함", "gotoLine": "줄 ģ“ė™", @@ -47,5 +47,11 @@ "reopenWithEncoding": "ģøģ½”ė”©ķ•˜ģ—¬ ė‹¤ģ‹œ ģ—“źø°", "guessedEncoding": "ģ½˜ķ…ģø ģ—ģ„œ 추츔함", "pickEncodingForReopen": "ķŒŒģ¼ģ„ ė‹¤ģ‹œ ģ—“ ķŒŒģ¼ ģøģ½”ė”© ģ„ ķƒ", - "pickEncodingForSave": "ķŒŒģ¼ģ„ ģ €ģž„ķ•  ķŒŒģ¼ ģøģ½”ė”© ģ„ ķƒ" + "pickEncodingForSave": "ķŒŒģ¼ģ„ ģ €ģž„ķ•  ķŒŒģ¼ ģøģ½”ė”© ģ„ ķƒ", + "screenReaderDetectedExplanation.title": "화멓 ģ½źø° ķ”„ė”œź·øėžØģ“ ģµœģ ķ™”ėØ", + "screenReaderDetectedExplanation.question": "VS Code넼 ģž‘ė™ķ•˜źø° ģœ„ķ•“ 화멓 ģ½źø° ķ”„ė”œź·øėžØģ„ ģ‚¬ģš©ķ•˜ģ‹­ė‹ˆź¹Œ?", + "screenReaderDetectedExplanation.answerYes": "예", + "screenReaderDetectedExplanation.answerNo": "ģ•„ė‹ˆģš”", + "screenReaderDetectedExplanation.body1": "VS Codeź°€ ģ“ģ œ 화멓 ģ½źø° ķ”„ė”œź·øėžØź³¼ ģ‚¬ģš©ķ•˜ėŠ” ė° ģµœģ ķ™”ė˜ģ—ˆģŠµė‹ˆė‹¤.", + "screenReaderDetectedExplanation.body2": "ģ¼ė¶€ ķŽøģ§‘źø° źø°ėŠ„ģ—ėŠ” ģžė™ ģ¤„ė°”źæˆ, ģ ‘źø°, ģžė™ ė‹«ėŠ” ėŒ€ź“„ķ˜ø 등 ģ—¬ėŸ¬ 가지 ė™ģž‘ģ“ ģžˆģŠµė‹ˆė‹¤. " } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 47bcc420bbc..a028fc067e5 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0}({1})", "closePanel": "ķŒØė„ ė‹«źø°", "togglePanel": "ķŒØė„ 설정/ķ•“ģ œ", "focusPanel": "ķŒØė„ė”œ ķ¬ģ»¤ģŠ¤ ģ“ė™", diff --git a/i18n/kor/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json index 5e2f77ce29d..d6de5173416 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "compositePart.hideSideBarLabel": "ģ‚¬ģ“ė“œ ė§‰ėŒ€ 숨기기", "focusSideBar": "ģ‚¬ģ“ė“œė°”ģ— ķ¬ģ»¤ģŠ¤", "viewCategory": "볓기" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 1b2e94b2c53..1a622afa7d4 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "'{0}' ėŖ…ė ¹ģ€ ķ˜„ģž¬ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ė˜ģ§€ ģ•Šģ•„ 실행할 수 ģ—†ģŠµė‹ˆė‹¤.", "manageExtension": "ķ™•ģž„ ꓀리" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..8d20ba83c9a --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} ė™ģž‘" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..126ed4fd56c --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} ė™ģž‘", + "hideView": "ģ‚¬ģ“ė“œė°”ģ—ģ„œ 숨기기" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..6a3532ad44d --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "ID `{0}`ģ“(ź°€) ķ¬ķ•Øėœ ė·°ź°€ ģœ„ģ¹˜ `{1}`에 ģ“ėÆø ė“±ė”ė˜ģ–“ ģžˆģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..b4ccb557e6a --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "ģ‚¬ģ“ė“œė°”ģ—ģ„œ 숨기기" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/common/theme.i18n.json b/i18n/kor/src/vs/workbench/common/theme.i18n.json index 71d7cfe6952..11018663022 100644 --- a/i18n/kor/src/vs/workbench/common/theme.i18n.json +++ b/i18n/kor/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "ķ™œģ„± 탭 ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", "tabInactiveBackground": "ė¹„ķ™œģ„± 탭 ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", "tabBorder": "ķƒ­ģ„ ģ„œė”œ źµ¬ė¶„ķ•˜źø° ģœ„ķ•œ ķ…Œė‘ė¦¬ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° 그룹에 ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", + "tabActiveBorder": "ķ™œģ„± ķƒ­ģ„ ź°•ģ”° ķ‘œģ‹œķ•˜źø° ģœ„ķ•œ ķ…Œė‘ė¦¬ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° 그룹에 ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", + "tabActiveUnfocusedBorder": "ķ¬ģ»¤ģŠ¤ź°€ ģ—†ėŠ” ź·øė£¹ģ—ģ„œ ķ™œģ„± ķƒ­ģ„ ź°•ģ”° ķ‘œģ‹œķ•˜źø° ģœ„ķ•œ ķ…Œė‘ė¦¬ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° 그룹에 ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", "tabActiveForeground": "ķ™œģ„± ź·øė£¹ģ˜ ķ™œģ„± 탭 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", "tabInactiveForeground": "ķ™œģ„± ź·øė£¹ģ˜ ė¹„ķ™œģ„± 탭 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", - "tabUnfocusedActiveForeground": "ė¹„ķ™œģ„± ź·øė£¹ģ˜ ķ™œģ„± 탭 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", - "tabUnfocusedInactiveForeground": "ė¹„ķ™œģ„± ź·øė£¹ģ˜ ė¹„ķ™œģ„± 탭 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", + "tabUnfocusedActiveForeground": "ķ¬ģ»¤ģŠ¤ź°€ ģ—†ėŠ” ź·øė£¹ģ˜ ķ™œģ„± 탭 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", + "tabUnfocusedInactiveForeground": "ķ¬ģ»¤ģŠ¤ź°€ ģ—†ėŠ” ź·øė£¹ģ˜ ė¹„ķ™œģ„± 탭 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķƒ­ģ€ ķŽøģ§‘źø° ģ˜ģ—­ģ—ģ„œ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ķ•œ ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ģ—¬ėŸ¬ ķƒ­ģ„ ģ—“ 수 ģžˆģŠµė‹ˆė‹¤. ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", "editorGroupBackground": "ķŽøģ§‘źø° ź·øė£¹ģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķŽøģ§‘źø° ź·øė£¹ģ€ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤. ė°°ź²½ģƒ‰ģ€ ķŽøģ§‘źø° ź·øė£¹ģ„ 끌 ė•Œ ķ‘œģ‹œė©ė‹ˆė‹¤.", "tabsContainerBackground": "ķƒ­ģ„ ģ‚¬ģš©ė„ė” ģ„¤ģ •ķ•œ 경우 ķŽøģ§‘źø° 그룹 제목 ėØøė¦¬źø€ģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķŽøģ§‘źø° ź·øė£¹ģ€ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", "tabsContainerBorder": "ķƒ­ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•œ 경우 ķŽøģ§‘źø° 그룹 제목 ėØøė¦¬źø€ģ˜ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. ķŽøģ§‘źø° ź·øė£¹ģ€ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", @@ -18,15 +20,15 @@ "editorGroupBorder": "ģ—¬ėŸ¬ ķŽøģ§‘źø° ź·øė£¹ģ„ ģ„œė”œ źµ¬ė¶„ķ•˜źø° ģœ„ķ•œ ģƒ‰ģž…ė‹ˆė‹¤. ķŽøģ§‘źø° ź·øė£¹ģ€ ķŽøģ§‘źø°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", "editorDragAndDropBackground": "ķŽøģ§‘źø°ė„¼ 끌 ė•Œ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķŽøģ§‘źø° ė‚“ģš©ģ“ ź³„ģ† 비추얓 ė³“ģ“ė„ė” ģ“ ģƒ‰ģ€ ķˆ¬ėŖ…ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", "panelBackground": "ķŒØė„ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ķŒØė„ģ€ ķŽøģ§‘źø° ģ˜ģ—­ ģ•„ėž˜ģ— ķ‘œģ‹œė˜ė©° 출렄 ė° 통합 터미널 ź°™ģ€ 볓기가 ķ¬ķ•Øė©ė‹ˆė‹¤.", - "panelBorder": "ķŽøģ§‘źø°ģ™€ źµ¬ė¶„ė˜ėŠ” ė§Ø ģœ„ģ˜ ķŒØė„ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. ķŒØė„ģ€ ķŽøģ§‘źø° ģ˜ģ—­ ģ•„ėž˜ģ— ķ‘œģ‹œė˜ė©° 출렄 ė° 통합 터미널 ź°™ģ€ 볓기가 ķ¬ķ•Øė©ė‹ˆė‹¤.", "panelActiveTitleForeground": "ķ™œģ„± ķŒØė„ģ˜ 제목 ģƒ‰ģž…ė‹ˆė‹¤. ķŒØė„ģ€ ķŽøģ§‘źø° ģ˜ģ—­ ģ•„ėž˜ģ— ķ‘œģ‹œė˜ė©° 출렄 ė° 통합 터미널 ź°™ģ€ 볓기가 ķ¬ķ•Øė©ė‹ˆė‹¤.", "panelInactiveTitleForeground": "ė¹„ķ™œģ„± ķŒØė„ģ˜ 제목 ģƒ‰ģž…ė‹ˆė‹¤. ķŒØė„ģ€ ķŽøģ§‘źø° ģ˜ģ—­ ģ•„ėž˜ģ— ķ‘œģ‹œė˜ė©° 출렄 ė° 통합 터미널 ź°™ģ€ 볓기가 ķ¬ķ•Øė©ė‹ˆė‹¤.", "panelActiveTitleBorder": "ķ™œģ„± ķŒØė„ ģ œėŖ©ģ˜ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. ķŒØė„ģ€ ķŽøģ§‘źø° ģ˜ģ—­ ģ•„ėž˜ģ— ķ‘œģ‹œė˜ė©° 출렄 ė° 통합 터미널 ź°™ģ€ 볓기가 ķ¬ķ•Øė©ė‹ˆė‹¤.", - "statusBarForeground": "상태 ķ‘œģ‹œģ¤„ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "statusBarForeground": "ģž‘ģ—… ģ˜ģ—­ģ“ ģ—“ė ¤ ģžˆģ„ ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "statusBarNoFolderForeground": "ķ“ė”ź°€ 엓리지 ģ•Šģ•˜ģ„ ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", - "statusBarBackground": "ķ‘œģ¤€ 상태 ķ‘œģ‹œģ¤„ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "statusBarBackground": "ģž‘ģ—… ģ˜ģ—­ģ“ ģ—“ė ¤ ģžˆģ„ ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "statusBarNoFolderBackground": "ķ“ė”ź°€ 엓리지 ģ•Šģ•˜ģ„ ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "statusBarBorder": "ģ‚¬ģ“ė“œė°” ė° ķŽøģ§‘źø°ģ™€ źµ¬ė¶„ķ•˜ėŠ” 상태 ķ‘œģ‹œģ¤„ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "statusBarNoFolderBorder": "엓린 ķ“ė”ź°€ ģ—†ģ„ ė•Œ ģ‚¬ģ“ė“œė°” ė° ķŽøģ§‘źø°ģ™€ źµ¬ė¶„ķ•˜ėŠ” 상태 ķ‘œģ‹œģ¤„ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "statusBarItemActiveBackground": "큓릭할 ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ķ•­ėŖ© ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "statusBarItemHoverBackground": "마우스딜 가리킬 ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ķ•­ėŖ© ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "statusBarProminentItemBackground": "상태 ķ‘œģ‹œģ¤„ ģ£¼ģš” ķ•­ėŖ© ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ£¼ģš” ķ•­ėŖ©ģ€ ģ¤‘ģš”ė„ė„¼ ė‚˜ķƒ€ė‚“ėŠ” 다넸 상태 ķ‘œģ‹œģ¤„ 항목볓다 ėˆˆģ— ģž˜ ė•ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", @@ -41,12 +43,14 @@ "sideBarForeground": "ģ‚¬ģ“ė“œė°” ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ‚¬ģ“ė“œė°”ėŠ” ķƒģƒ‰źø° ė° ź²€ģƒ‰ź³¼ ź°™ģ€ ė·°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", "sideBarBorder": "ķŽøģ§‘źø°ģ™€ źµ¬ė¶„ķ•˜ėŠ” ģø”ė©“ģ˜ ģ‚¬ģ“ė“œė°” ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. ģ‚¬ģ“ė“œė°”ėŠ” ķƒģƒ‰źø° ė° ź²€ģƒ‰ź³¼ ź°™ģ€ ė·°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", "sideBarTitleForeground": "ģ‚¬ģ“ė“œė°” 제목 ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ‚¬ģ“ė“œė°”ėŠ” ķƒģƒ‰źø° ė° ź²€ģƒ‰ź³¼ ź°™ģ€ ė·°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", + "sideBarDragAndDropBackground": "ģ‚¬ģ“ė“œ ė§‰ėŒ€ ģ„¹ģ…˜ģ˜ ėŒģ–“ģ„œ 놓기 ķ”¼ė“œė°± ģƒ‰ģž…ė‹ˆė‹¤. ģ‚¬ģ“ė“œ ė§‰ėŒ€ ģ„¹ģ…˜ģ“ ź³„ģ† 비추얓 ė³“ģ“ė„ė” ģ“ ģƒ‰ģ€ ķˆ¬ėŖ…ķ•“ģ•¼ ķ•©ė‹ˆė‹¤. ģ‚¬ģ“ė“œ ė§‰ėŒ€ėŠ” ģ™¼ģŖ½ģ“ė‚˜ 오넸쪽 ėģ— ķ‘œģ‹œė˜ė©° ģ‚¬ģ“ė“œė°”ģ˜ 볓기넼 ģ „ķ™˜ķ•  수 ģžˆģŠµė‹ˆė‹¤.", "sideBarSectionHeaderBackground": "ģ‚¬ģ“ė“œė°” ģ„¹ģ…˜ ķ—¤ė” ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ‚¬ģ“ė“œė°”ėŠ” ķƒģƒ‰źø° ė° ź²€ģƒ‰ź³¼ ź°™ģ€ ė·°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", "sideBarSectionHeaderForeground": "ģ‚¬ģ“ė“œė°” ģ„¹ģ…˜ ķ—¤ė” ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ‚¬ģ“ė“œė°”ėŠ” ķƒģƒ‰źø° ė° ź²€ģƒ‰ź³¼ ź°™ģ€ ė·°ģ˜ ģ»Øķ…Œģ“ė„ˆģž…ė‹ˆė‹¤.", "titleBarActiveForeground": "ģ°½ģ“ ķ™œģ„±ķ™”ėœ ź²½ģš°ģ˜ 제목 ķ‘œģ‹œģ¤„ ģ „ź²½ģž…ė‹ˆė‹¤. ģ“ ģƒ‰ģ€ ķ˜„ģž¬ macOSģ—ģ„œė§Œ ģ§€ģ›ė©ė‹ˆė‹¤.", "titleBarInactiveForeground": "ģ°½ģ“ ė¹„ķ™œģ„±ķ™”ėœ ź²½ģš°ģ˜ 제목 ķ‘œģ‹œģ¤„ ģ „ź²½ģž…ė‹ˆė‹¤. ģ“ ģƒ‰ģ€ ķ˜„ģž¬ macOSģ—ģ„œė§Œ ģ§€ģ›ė©ė‹ˆė‹¤.", "titleBarActiveBackground": "ģ°½ģ„ ķ™œģ„±ķ™”ķ•  ė•Œģ˜ 제목 ķ‘œģ‹œģ¤„ ģ „ź²½ģž…ė‹ˆė‹¤. ģ“ ģƒ‰ģ€ ķ˜„ģž¬ macOSģ—ģ„œė§Œ ģ§€ģ›ė©ė‹ˆė‹¤.", "titleBarInactiveBackground": "ģ°½ģ“ ė¹„ķ™œģ„±ķ™”ėœ ź²½ģš°ģ˜ 제목 ķ‘œģ‹œģ¤„ ė°°ź²½ģž…ė‹ˆė‹¤. ģ“ ģƒ‰ģ€ ķ˜„ģž¬ macOSģ—ģ„œė§Œ ģ§€ģ›ė©ė‹ˆė‹¤.", + "titleBarBorder": "제목 ė§‰ėŒ€ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. ķ˜„ģž¬ ģ“ ģƒ‰ģƒģ€ macOSģ—ģ„œė§Œ ģ§€ģ›ė©ė‹ˆė‹¤.", "notificationsForeground": "ģ•Œė¦¼ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ•Œė¦¼ģ€ ģ°½ģ˜ ģœ„ģŖ½ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "notificationsBackground": "ģ•Œė¦¼ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ•Œė¦¼ģ€ ģ°½ģ˜ ģœ„ģŖ½ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", "notificationsButtonBackground": "ģ•Œė¦¼ 단추 ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ•Œė¦¼ģ€ ģ°½ģ˜ ģœ„ģŖ½ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", diff --git a/i18n/kor/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/kor/src/vs/workbench/electron-browser/actions.i18n.json index d6e342c7b22..f652392a397 100644 --- a/i18n/kor/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/kor/src/vs/workbench/electron-browser/actions.i18n.json @@ -6,6 +6,8 @@ { "closeActiveEditor": "ķŽøģ§‘źø° ė‹«źø°", "closeWindow": "ģ°½ ė‹«źø°", + "closeWorkspace": "ģž‘ģ—… ģ˜ģ—­ ė‹«źø°", + "noWorkspaceOpened": "ķ˜„ģž¬ ģ“ ģøģŠ¤ķ„“ģŠ¤ģ— ģ—“ė ¤ ģžˆėŠ” ģž‘ģ—… ģ˜ģ—­ģ“ ģ—†ģŠµė‹ˆė‹¤.", "newWindow": "새 ģ°½", "toggleFullScreen": "전첓 화멓 설정/ķ•“ģ œ", "toggleMenuBar": "메뉓 ėŖØģŒ 설정/ķ•“ģ œ", @@ -20,7 +22,11 @@ "close": "ģ°½ ė‹«źø°", "switchWindow": "ģ°½ ģ „ķ™˜", "quickSwitchWindow": "빠넸 ģ°½ ģ „ķ™˜", + "workspaces": "ģž‘ģ—… ģ˜ģ—­", "files": "ķŒŒģ¼", + "openRecentPlaceHolderMac": "ģ„ ķƒķ•˜ģ—¬ ģ—“źø°(새 ģ°½ģ—ģ„œ 엓려멓 Cmd 키넼 길게 ėˆ„ė¦„)", + "openRecentPlaceHolder": "ģ„ ķƒķ•˜ģ—¬ ģ—“źø°(새 ģ°½ģ—ģ„œ 엓려멓 Ctrl 키넼 길게 ėˆ„ė¦„)", + "remove": "ģµœź·¼ģ— ģ‚¬ģš©ķ•œ ķ•­ėŖ©ģ—ģ„œ 제거", "openRecent": "최근 ķ•­ėŖ© ģ—“źø°...", "quickOpenRecent": "빠넸 최근 ķ•­ėŖ© ģ—“źø°...", "closeMessages": "ģ•Œė¦¼ ė©”ģ‹œģ§€ ė‹«źø°", @@ -36,5 +42,10 @@ "navigateUp": "ė·° ģœ„ė”œ ģ“ė™", "navigateDown": "ė·° ģ•„ėž˜ė”œ ģ“ė™", "increaseViewSize": "ķ˜„ģž¬ ė·° 크기 늘리기", - "decreaseViewSize": "ķ˜„ģž¬ ė·° 크기 ģ¤„ģ“źø°" + "decreaseViewSize": "ķ˜„ģž¬ ė·° 크기 ģ¤„ģ“źø°", + "showPreviousTab": "ģ“ģ „ ģ°½ 탭 ķ‘œģ‹œ", + "showNextWindowTab": "ė‹¤ģŒ ģ°½ 탭 ķ‘œģ‹œ", + "moveWindowTabToNewWindow": "ģ°½ ķƒ­ģ„ 새 창으딜 ģ“ė™", + "mergeAllWindowTabs": "ėŖØė“  ģ°½ 병합", + "toggleWindowTabsBar": "ģ°½ 탭 ėŖØģŒ 설정/ķ•“ģ œ" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/kor/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..3c255978d33 --- /dev/null +++ b/i18n/kor/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "ģ–øģ–“ 구성", + "displayLanguage": "VSCodeģ˜ ķ‘œģ‹œ 언얓넼 ģ •ģ˜ķ•©ė‹ˆė‹¤.", + "doc": "ģ§€ģ›ė˜ėŠ” ģ–øģ–“ ėŖ©ė”ģ€ {0} ģ„(넼) ģ°øģ”°ķ•˜ģ„øģš”.", + "restart": "ź°’ģ„ ė³€ź²½ķ•˜ė ¤ė©“ VSCode넼 ė‹¤ģ‹œ ģ‹œģž‘ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", + "fail.createSettings": "{0}'({1})ģ„(넼) ė§Œė“¤ 수 ģ—†ģŠµė‹ˆė‹¤.", + "JsonSchema.locale": "ģ‚¬ģš©ķ•  UI ģ–øģ–“ģž…ė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json index 96418c6f448..22baa2ccddf 100644 --- a/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -7,15 +7,17 @@ "view": "볓기", "help": "ė„ģ›€ė§", "file": "ķŒŒģ¼", + "workspaces": "ģž‘ģ—… ģ˜ģ—­", "developer": "ź°œė°œģž", "showEditorTabs": "ģ—“ė ¤ ģžˆėŠ” ķŽøģ§‘źø°ė„¼ ķƒ­ģ—ģ„œ ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", + "workbench.editor.labelFormat.short": "디렉터리 ģ“ė¦„ ģ•žģ— ģ˜¤ėŠ” ķŒŒģ¼ģ˜ ģ“ė¦„ģ„ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", + "workbench.editor.labelFormat.long": "ģ ˆėŒ€ 경딜 ģ•žģ— ģ˜¤ėŠ” ķŒŒģ¼ģ˜ ģ“ė¦„ģ„ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", + "tabDescription": "ķŽøģ§‘źø°ģ˜ ė ˆģ“ėø” ķ˜•ģ‹ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤. 예넼 들얓 ģ“ ģ„¤ģ •ģ„ ė³€ź²½ķ•˜ė©“ ķŒŒģ¼ģ˜ ģœ„ģ¹˜ė„¼ ė” ģ‰½ź²Œ ķŒŒģ•…ķ•  수 ģžˆģŠµė‹ˆė‹¤.:\n- 짧게: 'parent'\n- 중간: 'workspace/src/parent'\n- 길게: '/home/user/workspace/src/parent'\n- źø°ė³øź°’: '.../parent', 다넸 ķƒ­ģ“ ė™ģ¼ķ•œ ģ œėŖ©ģ„ ź³µģœ ķ•˜ź±°ė‚˜, ķƒ­ģ„ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ķ•œ 경우 ģž‘ģ—… ģ˜ģ—­ ģƒėŒ€ 경딜", "editorTabCloseButton": "ķŽøģ§‘źø°ģ˜ 탭 ė‹«źø° ė‹Øģ¶”ģ˜ ģœ„ģ¹˜ė„¼ ģ œģ–“ķ•˜ź±°ė‚˜ 'off'딜 ģ„¤ģ •ėœ 경우 ģ“ 단추넼 ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ķ•©ė‹ˆė‹¤.", "showIcons": "엓린 ķŽøģ§‘źø°ė„¼ ģ•„ģ“ģ½˜ź³¼ ķ•Øź»˜ ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. ģ“ė„¼ ģœ„ķ•“ģ„œėŠ” ģ•„ģ“ģ½˜ ķ…Œė§ˆė„ ģ‚¬ģš©ķ•˜ė„ė” 설정핓야 ķ•©ė‹ˆė‹¤.", - "enablePreview": "ģ—“ė ¤ ģžˆėŠ” ķŽøģ§‘źø°ė„¼ 미리 볓기딜 ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. 미리 볓기 ķŽøģ§‘źø°ėŠ” ģœ ģ§€ėœ ģƒķƒœź¹Œģ§€(예: 두 번 큓릭 ė˜ėŠ” ķŽøģ§‘ģ„ 통핓) ė‹¤ģ‹œ ģ‚¬ģš©ė©ė‹ˆė‹¤.", + "enablePreview": "ģ—“ė ¤ ģžˆėŠ” ķŽøģ§‘źø°ė„¼ 미리 볓기딜 ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. 미리 볓기 ķŽøģ§‘źø°ėŠ” ģœ ģ§€ėœ ģƒķƒœź¹Œģ§€(예: 두 번 큓릭 ė˜ėŠ” ķŽøģ§‘ģ„ 통핓) ė‹¤ģ‹œ ģ‚¬ģš©ė˜ė©° źø°ģšøģž„ź¼“ 글꼓 ģŠ¤ķƒ€ģ¼ė”œ ķ‘œģ‹œė©ė‹ˆė‹¤.", "enablePreviewFromQuickOpen": "Quick Openģ—ģ„œ ģ—° ķŽøģ§‘źø°ė„¼ 미리 볓기딜 ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. 미리 볓기 ķŽøģ§‘źø°ėŠ” ģœ ģ§€ėœ ģƒķƒœź¹Œģ§€(예: 두 번 큓릭 ė˜ėŠ” ķŽøģ§‘ģ„ 통핓) ė‹¤ģ‹œ ģ‚¬ģš©ė©ė‹ˆė‹¤.", - "editorOpenPositioning": "ķŽøģ§‘źø°ź°€ ģ—“ė¦¬ėŠ” ģœ„ģ¹˜ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤. ķ˜„ģž¬ ķ™œģ„± ķŽøģ§‘źø°ģ˜ 왼쪽 ė˜ėŠ” ģ˜¤ė„øģŖ½ģ—ģ„œ ķŽøģ§‘źø°ė„¼ 엓려멓 '왼쪽' ė˜ėŠ” '오넸쪽'ģ„ ģ„ ķƒķ•©ė‹ˆė‹¤. ķ˜„ģž¬ ķ™œģ„± ķŽøģ§‘źø°ģ™€ ė…ė¦½ģ ģœ¼ė”œ ķŽøģ§‘źø°ė„¼ 엓려멓 'ģ²˜ģŒ' ė˜ėŠ” 'ė§ˆģ§€ė§‰'ģ„ ģ„ ķƒķ•©ė‹ˆė‹¤.", "revealIfOpen": "ķŽøģ§‘źø°ė„¼ ģ—¬ėŠ” 경우 ė³“ģ“ėŠ” 그룹 중 ķ•˜ė‚˜ģ— ķ‘œģ‹œķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” 설정할 경우 ķŽøģ§‘źø°ź°€ 기본적으딜 ķ˜„ģž¬ ķ™œģ„± ķŽøģ§‘źø° 그룹에 ģ—“ė¦½ė‹ˆė‹¤. ģ‚¬ģš©ķ•˜ė„ė” 설정할 경우 ķ˜„ģž¬ ķ™œģ„± ķŽøģ§‘źø° ź·øė£¹ģ—ģ„œ ķŽøģ§‘źø°ź°€ ė‹¤ģ‹œ 엓리지 ģ•Šź³  ģ“ėÆø 엓린 ķŽøģ§‘źø°ź°€ ķ‘œģ‹œė©ė‹ˆė‹¤. ź°•ģ œė”œ ķŽøģ§‘źø°ź°€ ķŠ¹ģ • ź·øė£¹ģ—ģ„œ ģ—“ė¦¬ź±°ė‚˜ ķ˜„ģž¬ ķ™œģ„± 그룹 ģ˜†ģ— ģ—“ė¦¬ė„ė” ķ•˜ėŠ” ė“±ģ˜ ģ¼ė¶€ ź²½ģš°ģ—ėŠ” ģ“ ģ„¤ģ •ģ“ ė¬“ģ‹œė©ė‹ˆė‹¤.", - "commandHistory": "ėŖ…ė ¹ ķŒ”ė ˆķŠø źø°ė”ģ— 최근 ģ‚¬ģš© ėŖ…ė ¹ģ„ ėŖ‡ 개 ģœ ģ§€ķ• ģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤. 0으딜 ģ„¤ģ •ķ•˜ė©“ ėŖ…ė ¹ źø°ė”ģ„ ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "preserveInput": "ė‹¤ģŒģ— ģ—“ ė•Œ ė§ˆģ§€ė§‰ģœ¼ė”œ ėŖ…ė ¹ ķŒ”ė ˆķŠøģ— ģž…ė „ķ•œ ė‚“ģš©ģ„ 복원할지 ź²°ģ •ķ•©ė‹ˆė‹¤.", "closeOnFocusLost": "Quick Openź°€ ķ¬ģ»¤ģŠ¤ė„¼ ģžƒģœ¼ė©“ ģžė™ģœ¼ė”œ ė‹«ģ„ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "openDefaultSettings": "ģ„¤ģ •ģ„ ģ—“ė©“ ėŖØė“  źø°ė³ø ģ„¤ģ •ģ„ ķ‘œģ‹œķ•˜ėŠ” ķŽøģ§‘źø°ė„ ģ—“ė¦¬ėŠ”ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", @@ -23,6 +25,10 @@ "statusBarVisibility": "ģ›Œķ¬ė²¤ģ¹˜ ģ•„ėž˜ģŖ½ģ—ģ„œ 상태 ķ‘œģ‹œģ¤„ģ˜ ķ‘œģ‹œ ģœ ķ˜•ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤.", "activityBarVisibility": "ģ›Œķ¬ė²¤ģ¹˜ģ—ģ„œ ģž‘ģ—… ė§‰ėŒ€ģ˜ ķ‘œģ‹œ ģœ ķ˜•ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤.", "closeOnFileDelete": "ģ¼ė¶€ 다넸 ķ”„ė”œģ„øģŠ¤ģ—ģ„œ ķŒŒģ¼ģ„ ģ‚­ģ œķ•˜ź±°ė‚˜ ģ“ė¦„ģ„ 바꿀 ė•Œ ķŒŒģ¼ģ„ ķ‘œģ‹œķ•˜ėŠ” ķŽøģ§‘źø°ė„¼ ģžė™ģœ¼ė”œ ė‹«ģ„ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ķ•˜ėŠ” 경우 ģ“ėŸ¬ķ•œ ģ“ė²¤ķŠøź°€ ė°œģƒķ•˜ė©“ ķŽøģ§‘źø°ź°€ ė”ķ‹° 상태딜 ź³„ģ† ģ—“ė ¤ ģžˆģŠµė‹ˆė‹¤. ģ‘ģš© ķ”„ė”œź·øėžØ ė‚“ģ—ģ„œ ģ‚­ģ œķ•˜ė©“ ķ•­ģƒ ķŽøģ§‘źø°ź°€ ė‹«ķžˆź³  ė°ģ“ķ„°ė„¼ ģœ ģ§€ķ•˜źø° ģœ„ķ•“ ė”ķ‹° ķŒŒģ¼ģ€ ė‹«ķžˆģ§€ ģ•ŠģŠµė‹ˆė‹¤.", + "fontAliasing": "ģ›Œķ¬ė²¤ģ¹˜ģ—ģ„œ 글꼓 앨리얓싱 ė°©ģ‹ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤.\n- źø°ė³ø: ģ„œėøŒ 픽셀 글꼓 다듬기. ėŒ€ė¶€ė¶„ģ˜ ģ¼ė°˜ ė””ģŠ¤ķ”Œė ˆģ“ģ—ģ„œ ź°€ģž„ ģ„ ėŖ…ķ•œ 글꼓 제공\n- ģ•ˆķ‹°ģ•Øė¦¬ģ–“ģ‹±: ģ„œėøŒ ķ”½ģ…€ģ“ ģ•„ė‹Œ 픽셀 ė‹Øģœ„ģ—ģ„œ 글꼓 다듬기. ģ „ė°˜ģ ģœ¼ė”œ ė” ė°ģ€ ėŠė‚Œģ„ 줄 수 ģžˆģŒ\n- ģ—†ģŒ: 글꼓 다듬기 ģ‚¬ģš© ģ•ˆ 함. ķ…ģŠ¤ķŠø ėŖØģ„œė¦¬ź°€ ź°ģ§€ź²Œ ķ‘œģ‹œėØ", + "workbench.fontAliasing.default": "ģ„œėøŒ 픽셀 글꼓 다듬기. ėŒ€ė¶€ė¶„ģ˜ ģ¼ė°˜ ė””ģŠ¤ķ”Œė ˆģ“ģ—ģ„œ ź°€ģž„ ģ„ ėŖ…ķ•œ ķ…ģŠ¤ķŠøė„¼ ģ œź³µķ•©ė‹ˆė‹¤. ", + "workbench.fontAliasing.antialiased": "ģ„œėøŒ ķ”½ģ…€ģ“ ģ•„ė‹Œ 픽셀 ģˆ˜ģ¤€ģ—ģ„œ źø€ź¼“ģ„ ė‹¤ė“¬ģŠµė‹ˆė‹¤. ģ „ė°˜ģ ģœ¼ė”œ źø€ź¼“ģ“ ė” ė°ź²Œ ķ‘œģ‹œė©ė‹ˆė‹¤.", + "workbench.fontAliasing.none": "글꼓 다듬기넼 ģ‚¬ģš©ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ķ…ģŠ¤ķŠø ź°€ģž„ģžė¦¬ź°€ ź°ģ§€ź²Œ ķ‘œģ‹œė©ė‹ˆė‹¤.", "swipeToNavigate": "세 ģ†ź°€ė½ģœ¼ė”œ ź°€ė”œė”œ ģ‚“ģ§ 밀얓 ģ—“ė ¤ ģžˆėŠ” ķŒŒģ¼ ź°„ģ„ ģ“ė™ķ•©ė‹ˆė‹¤.", "workbenchConfigurationTitle": "ģ›Œķ¬ė²¤ģ¹˜", "window.openFilesInNewWindow.on": "ķŒŒģ¼ģ“ 새 ģ°½ģ—ģ„œ ģ—“ė¦½ė‹ˆė‹¤.", @@ -34,16 +40,18 @@ "window.openFoldersInNewWindow.default": "ķ“ė”ė„¼ ģ‘ģš© ķ”„ė”œź·øėžØ ė‚“ģ—ģ„œ ģ„ ķƒ(예: ķŒŒģ¼ 메뉓넼 통핓)ķ•˜ėŠ” 경우넼 ģ œģ™øķ•˜ź³  ķ“ė”ź°€ 새 ģ°½ģ—ģ„œ ģ—“ė¦½ė‹ˆė‹¤.", "openFoldersInNewWindow": "ķ“ė”ė„¼ 새 ģ°½ģ—ģ„œ ģ—“ģ§€, ė§ˆģ§€ė§‰ ķ™œģ„± 창과 바꿀지넼 ģ œģ–“ķ•©ė‹ˆė‹¤.\n- default: ģ‘ģš© ķ”„ė”œź·øėžØ ė‚“ģ—ģ„œ [ķŒŒģ¼] 메뉓 ė“±ģ„ 통핓 ķ“ė”ė„¼ ģ„ ķƒķ•˜ėŠ” 경우넼 ģ œģ™øķ•˜ź³ , ķ“ė”ėŠ” 새 ģ°½ģ—ģ„œ ģ—“ė¦½ė‹ˆė‹¤.\n- on: ķ“ė”ź°€ 새 ģ°½ģ—ģ„œ ģ—“ė¦½ė‹ˆė‹¤.\n- off: ķ“ė”ź°€ ė§ˆģ§€ė§‰ ķ™œģ„± ģ°½ģ„ ėŒ€ģ²“ķ•©ė‹ˆė‹¤\nģ“ ģ„¤ģ •ģ“ ė¬“ģ‹œė˜ėŠ” ź²½ģš°ė„ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤(예: -new-window ė˜ėŠ” -reuse-window 명령줄 ģ˜µģ…˜ģ„ ģ‚¬ģš©ķ•  경우).", "window.reopenFolders.all": "ėŖØė“  ģ°½ģ„ ė‹¤ģ‹œ ģ—½ė‹ˆė‹¤.", + "window.reopenFolders.folders": "ėŖØė“  ķ“ė”ė„¼ ė‹¤ģ‹œ ģ—½ė‹ˆė‹¤. 빈 ģž‘ģ—… ģ˜ģ—­ģ€ ė³µģ›ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "window.reopenFolders.one": "ė§ˆģ§€ė§‰ ķ™œģ„± ģ°½ģ„ ė‹¤ģ‹œ ģ—½ė‹ˆė‹¤.", "window.reopenFolders.none": "ģ°½ģ„ ė‹¤ģ‹œ ģ—“ģ§€ ģ•Šź³  ķ•­ģƒ 빈 창으딜 ģ‹œģž‘ķ•©ė‹ˆė‹¤.", + "restoreWindows": "ė‹¤ģ‹œ ģ‹œģž‘ķ•œ ģ“ķ›„ģ— ģ°½ģ„ ė‹¤ģ‹œ ģ—¬ėŠ” ė°©ė²•ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤. 'none'ģ„ ģ„ ķƒķ•˜ė©“ ķ•­ģƒ 빈 ģž‘ģ—… ģ˜ģ—­ģœ¼ė”œ ģ‹œģž‘ķ•˜ź³  'one'ģ„ ģ„ ķƒķ•˜ė©“ ė§ˆģ§€ė§‰ģœ¼ė”œ ģž‘ģ—…ķ•œ ģ°½ģ“ ė‹¤ģ‹œ 엓리고 'folders'넼 ģ„ ķƒķ•˜ė©“ ģ—“ģ—ˆė˜ ķ“ė”ź°€ ķ¬ķ•Øėœ ėŖØė“  ģ°½ģ“ ė‹¤ģ‹œ 엓리며 'all'ģ„ ģ„ ķƒķ•˜ė©“ ģ§€ė‚œ ģ„øģ…˜ģ˜ ėŖØė“  ģ°½ģ“ ė‹¤ģ‹œ ģ—“ė¦½ė‹ˆė‹¤.", "restoreFullscreen": "ģ°½ģ“ 전첓 화멓 ėŖØė“œģ—ģ„œ ģ¢…ė£Œėœ 경우 ģ°½ģ„ 전첓 화멓 ėŖØė“œė”œ 복원할지 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "zoomLevel": "ģ°½ģ˜ ķ™•ėŒ€/ģ¶•ģ†Œ ģˆ˜ģ¤€ģ„ ģ”°ģ •ķ•©ė‹ˆė‹¤. ģ›ėž˜ ķ¬źø°ėŠ” 0ģ“ź³  각 ģƒķ•œ ģ¦ė¶„(예: 1) ė˜ėŠ” ķ•˜ķ•œ ģ¦ė¶„(예: -1)ģ€ 20% ė” ķ¬ź±°ė‚˜ ė” ģž‘ź²Œ ķ™•ėŒ€/ģ¶•ģ†Œķ•˜ėŠ” ź²ƒģ„ ė‚˜ķƒ€ėƒ…ė‹ˆė‹¤. 10ģ§„ģˆ˜ė„¼ ģž…ė „ķ•˜ģ—¬ ķ™•ėŒ€/ģ¶•ģ†Œ ģˆ˜ģ¤€ģ„ ģ„øė¶€ģ ģœ¼ė”œ ģ”°ģ •ķ•  ģˆ˜ė„ ģžˆģŠµė‹ˆė‹¤.", - "title": "ķ™œģ„± ķŽøģ§‘źø°ė„¼ 기반으딜 ģ°½ ģ œėŖ©ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤. ė³€ģˆ˜ėŠ” ģ»Øķ…ģŠ¤ķŠøė„¼ 기반으딜 ėŒ€ģ²“ė©ė‹ˆė‹¤. \n${activeEditorShort}: 예: myFile.txt\n${activeEditorMedium}: 예: myFolder/myFile.txt\n${activeEditorLong}: 예: /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: 예: myFolder\n${folderPath}: 예: /Users/Development/myFolder\n${rootName}: 예: myFolder1, myFolder2, myFolder3\n${rootPath}: 예: /Users/Development/myWorkspace\n${appName}: 예: VS Code\n${dirty}: ķ™œģ„± ķŽøģ§‘źø°ź°€ ė”ķ‹°ģø 경우 ė”ķ‹° ķ‘œģ‹œźø°\n${separator}: ź°’ģ“ ģžˆėŠ” ė³€ģˆ˜ė”œ ė‘˜ėŸ¬ģ‹øģø ź²½ģš°ģ—ė§Œ ķ‘œģ‹œė˜ėŠ” 씰걓부 구분 기호(\" - \")", "window.newWindowDimensions.default": "화멓 ź°€ģš“ė°ģ—ģ„œ 새 ģ°½ģ„ ģ—½ė‹ˆė‹¤.", "window.newWindowDimensions.inherit": "ė§ˆģ§€ė§‰ ķ™œģ„± 창과 ė™ģ¼ķ•œ 크기딜 새 ģ°½ģ„ ģ—½ė‹ˆė‹¤.", "window.newWindowDimensions.maximized": "ģµœėŒ€ķ™”ėœ 새 ģ°½ģ„ ģ—½ė‹ˆė‹¤.", "window.newWindowDimensions.fullscreen": "전첓 화멓 ėŖØė“œģ—ģ„œ 새 ģ°½ģ„ ģ—½ė‹ˆė‹¤.", "newWindowDimensions": "ķ•˜ė‚˜ ģ“ģƒģ˜ ģ°½ģ“ ģ“ėÆø ģ—“ė ¤ ģžˆģ„ ė•Œ ģ—¬ėŠ” 새 새 ģ°½ģ˜ 크기넼 ģ œģ–“ķ•©ė‹ˆė‹¤. 기본적으딜 새 ģ°½ģ€ 화멓 ź°€ģš“ė°ģ— ģž‘ģ€ 크기딜 ģ—“ė¦½ė‹ˆė‹¤. 'inherit'으딜 설정할 경우 ė§ˆģ§€ė§‰ ķ™œģ„± 창과 ė™ģ¼ķ•œ 크기딜 ģ°½ģ“ ģ—“ė¦½ė‹ˆė‹¤. 'maximized'딜 설정할 경우 ģ°½ģ“ ģµœėŒ€ķ™”ė˜ģ–“ 엓리고 'fullscreen'으딜 구성할 경우 전첓 ķ™”ė©“ģœ¼ė”œ ģ—“ė¦½ė‹ˆė‹¤. ģ“ ģ„¤ģ •ģ€ ģ—¬ėŠ” 첫 번째 ģ°½ģ—ėŠ” ģ ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. 첫 번째 ģ°½ģ˜ 경우 ķ•­ģƒ ģ°½ģ„ ė‹«źø° ģ „ģ˜ 크기와 ģœ„ģ¹˜ź°€ ė³µģ›ė©ė‹ˆė‹¤.", + "closeWhenEmpty": "undefined", "window.menuBarVisibility.default": "메뉓가 전첓 화멓 ėŖØė“œģ—ģ„œė§Œ ģˆØź²Øģ§‘ė‹ˆė‹¤.", "window.menuBarVisibility.visible": "메뉓가 전첓 화멓 ėŖØė“œģ—ģ„œė„ ķ•­ģƒ ķ‘œģ‹œė©ė‹ˆė‹¤.", "window.menuBarVisibility.toggle": "메뉓가 숨겨져 ģžˆģ§€ė§Œ 키넼 통핓 메뉓넼 ķ‘œģ‹œķ•  수 ģžˆģŠµė‹ˆė‹¤.", diff --git a/i18n/kor/src/vs/workbench/electron-browser/window.i18n.json b/i18n/kor/src/vs/workbench/electron-browser/window.i18n.json index 25e82009859..dc0deb8eb7f 100644 --- a/i18n/kor/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/kor/src/vs/workbench/electron-browser/window.i18n.json @@ -9,6 +9,5 @@ "cut": "ģž˜ė¼ė‚“źø°", "copy": "복사", "paste": "붙여넣기", - "selectAll": "모두 ģ„ ķƒ", - "confirmOpenButton": "ģ—“źø°(&&O)" + "selectAll": "모두 ģ„ ķƒ" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index f113def895b..59ea1c2066d 100644 --- a/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "ķ–‰ģ“ ģ“ ķŒØķ„“ź³¼ ģ¼ģ¹˜ķ•˜ė©“ 들여쓰기넼 ģˆ˜ģ •ķ•˜ģ§€ ģ•Šź³  다넸 ź·œģ¹™ģ— ėŒ€ķ•“ģ„œ ķ‰ź°€ķ•˜ģ§€ė„ ģ•ŠģŠµė‹ˆė‹¤.", "schema.indentationRules.unIndentedLinePattern.pattern": "unIndentedLinePattern에 ėŒ€ķ•œ RegExp ķŒØķ„“ģž…ė‹ˆė‹¤.", "schema.indentationRules.unIndentedLinePattern.flags": "unIndentedLinePattern에 ėŒ€ķ•œ RegExp ķ”Œėž˜ź·øģž…ė‹ˆė‹¤.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` ķŒØķ„“ź³¼ ģ¼ģ¹˜ķ•“ģ•¼ ķ•©ė‹ˆė‹¤." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` ķŒØķ„“ź³¼ ģ¼ģ¹˜ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", + "schema.folding": "핓당 ģ–øģ–“ģ˜ ģ ‘źø° ģ„¤ģ •ģž…ė‹ˆė‹¤.", + "schema.folding.offSide": "핓당 ģ–øģ–“ģ˜ ėø”ė”ģ“ ė“¤ģ—¬ģ“°źø°ė”œ ķ‘œķ˜„ė˜ėŠ” 경우 ģ–øģ–“ėŠ” ģ˜¤ķ”„ģ‚¬ģ“ė“œ ź·œģ¹™ģ„ ģ¤€ģˆ˜ķ•©ė‹ˆė‹¤. ģ„¤ģ •ķ•˜ėŠ” 경우 빈 ģ¤„ģ€ ķ›„ģ† ėø”ė”ģ— ģ†ķ•©ė‹ˆė‹¤.", + "schema.folding.markers": "'#region' ė° '#endregion'처럼 언얓별 ģ ‘źø° ķ‘œģ‹ģž…ė‹ˆė‹¤. ģ‹œģž‘ ė° ģ¢…ė£Œ regexėŠ” ėŖØė“  ģ¤„ģ˜ ģ½˜ķ…ģø ģ— ėŒ€ķ•“ ķ…ŒģŠ¤ķŠøė˜ė©° 효율적으딜 ģ„¤ź³„ė˜ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "schema.folding.markers.start": "ģ‹œģž‘ ķ‘œģ‹ģ— ėŒ€ķ•œ RegExp ķŒØķ„“ģž…ė‹ˆė‹¤. regexpėŠ” '^'으딜 ģ‹œģž‘ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", + "schema.folding.markers.end": "ė ķ‘œģ‹ģ— ėŒ€ķ•œ RegExp ķŒØķ„“ģž…ė‹ˆė‹¤. regexpėŠ” '^'으딜 ģ‹œģž‘ķ•“ģ•¼ ķ•©ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..1e8111e9fe9 --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "볓기: ėÆøė‹ˆė§µ 토글" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index a111c0128f1..852c1e89096 100644 --- a/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "ģ œģ–“ ė¬øģž 설정/ķ•“ģ œ" + "toggleRenderControlCharacters": "볓기: ģ œģ–“ ė¬øģž 토글" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 0cdc554c0de..2b875500e85 100644 --- a/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "공백 ė Œė”ė§ 설정/ķ•“ģ œ" + "toggleRenderWhitespace": "볓기: ė Œė”ė§ 공백 토글" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index 33a1fa482a7..17a439db745 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "구성 ģ—†ģŒ", + "addConfigTo": "구성 추가 ({0})...", "addConfiguration": "구성 추가..." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 674839cc069..753a861d411 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, 디버그", "debugAriaLabel": "실행할 ģ‹œģž‘ źµ¬ģ„±ģ˜ ģ“ė¦„ģ„ ģž…ė „ķ•˜ģ„øģš”.", + "addConfigTo": "구성 추가 ({0})...", + "addConfiguration": "구성 추가...", "noConfigurationsMatching": "ģ¼ģ¹˜ķ•˜ėŠ” 디버그 구성 ģ—†ģŒ", "noConfigurationsFound": "디버그 źµ¬ģ„±ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤. 'launch.json' ķŒŒģ¼ģ„ ė§Œė“œģ„øģš”." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 2b0632b1635..0db91f83b2f 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "쓈기 'launch.json'ģ„ ģƒģ„±ķ•˜źø° ģœ„ķ•œ źµ¬ģ„±ģž…ė‹ˆė‹¤.", "vscode.extension.contributes.debuggers.languages": "디버그 ķ™•ģž„ģ“ \"źø°ė³ø 디버거\"딜 간주될 수 ģžˆėŠ” ģ–øģ–“ ėŖ©ė”ģž…ė‹ˆė‹¤.", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "ģ§€ģ •ķ•˜ėŠ” 경우 VS Codeģ—ģ„œ ģ“ ėŖ…ė ¹ģ„ ķ˜øģ¶œķ•˜ģ—¬ 디버그 ģ–“ėŒ‘ķ„°ģ˜ 실행 ķŒŒģ¼ 경딜 ė° 전달할 ģøģˆ˜ė„¼ ķ™•ģøķ•©ė‹ˆė‹¤.", - "vscode.extension.contributes.debuggers.startSessionCommand": "ģ§€ģ •ķ•˜ėŠ” 경우 VS Codeģ—ģ„œ ģ“ ķ™•ģž„ģ„ ėŒ€ģƒģœ¼ė”œ ķ•˜ėŠ” \"디버그\" ė˜ėŠ” \"실행\" ģž‘ģ—…ģ— ėŒ€ķ•“ ģ“ ėŖ…ė ¹ģ„ ķ˜øģ¶œķ•©ė‹ˆė‹¤.", "vscode.extension.contributes.debuggers.configurationSnippets": "'launch.json'에 새 źµ¬ģ„±ģ„ ģ¶”ź°€ķ•˜ėŠ” ģ½”ė“œ ģ”°ź°ģž…ė‹ˆė‹¤.", "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json'ģ˜ ģœ ķšØģ„± 검사넼 ģœ„ķ•œ JSON ģŠ¤ķ‚¤ė§ˆ źµ¬ģ„±ģž…ė‹ˆė‹¤.", "vscode.extension.contributes.debuggers.windows": "Windows ķŠ¹ģ • 설정", diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 3a1c8cbdce7..4cb60411f72 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -13,11 +13,10 @@ "compoundMustHaveConfigurations": "ģ—¬ėŸ¬ źµ¬ģ„±ģ„ ģ‹œģž‘ķ•˜ė ¤ė©“ 복합에 \"configurations\" ķŠ¹ģ„± ģ§‘ķ•©ģ“ ģžˆģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", "configMissing": "'{0}' źµ¬ģ„±ģ“ 'launch.json'에 ģ—†ģŠµė‹ˆė‹¤.", "debugTypeNotSupported": "źµ¬ģ„±ėœ 디버그 ķ˜•ģ‹ '{0}'ģ€(ėŠ”) ģ§€ģ›ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", - "debugTypeMissing": "ģ„ ķƒķ•œ ģ‹œģž‘ 구성에 ėŒ€ķ•œ 'type' ģ†ģ„±ģ“ ģ—†ģŠµė‹ˆė‹¤.", + "debugAnyway": "디버그", "preLaunchTaskErrors": "preLaunchTask '{0}' ģ§„ķ–‰ 중에 ė¹Œė“œ ģ˜¤ė„˜ź°€ ź°ģ§€ė˜ģ—ˆģŠµė‹ˆė‹¤.", "preLaunchTaskError": "preLaunchTask '{0}' ģ§„ķ–‰ 중에 ė¹Œė“œ ģ˜¤ė„˜ź°€ ź°ģ§€ė˜ģ—ˆģŠµė‹ˆė‹¤.", "preLaunchTaskExitCode": "preLaunchTask '{0}'ģ“(ź°€) {1} ģ¢…ė£Œ ģ½”ė“œģ™€ ķ•Øź»˜ ģ¢…ė£Œė˜ģ—ˆģŠµė‹ˆė‹¤.", - "debugAnyway": "디버그", "noFolderWorkspaceDebugError": "ķ™œģ„± ķŒŒģ¼ģ€ 디버그할 수 ģ—†ģŠµė‹ˆė‹¤. ģ“ ķŒŒģ¼ģ“ ė””ģŠ¤ķ¬ģ— ģ €ģž„ė˜ģ–“ ģžˆź³  핓당 ķŒŒģ¼ ķ˜•ģ‹ģ— ėŒ€ķ•œ 디버그 ķ™•ģž„ģ“ ģ„¤ģ¹˜ė˜ģ–“ ģžˆėŠ”ģ§€ ķ™•ģøķ•˜ģ„øģš”.", "NewLaunchConfig": "ģ‘ģš© ķ”„ė”œź·øėžØģ— ģ‚¬ģš©ķ•  구성 ģ‹œģž‘ ķŒŒģ¼ģ„ ģ„¤ģ •ķ•˜ģ„øģš”. {0}", "DebugTaskNotFound": "preLaunchTask '{0}'ģ„(넼) ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤." diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 9c417b8c7dd..1da0363bd93 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "개첓 ģƒķƒœėŠ” 첫 ė²ˆģž¬ ķ‰ź°€ģ—ģ„œ ģŗ”ģ²˜ė©ė‹ˆė‹¤.", "replVariableAriaLabel": "{0} ė³€ģˆ˜ģ— {1} ź°’ģ“ ģžˆģŠµė‹ˆė‹¤. ģ½źø° ķ‰ź°€ ģøģ‡„ 루프, 디버그", "replExpressionAriaLabel": "{0} ģ‹ģ— {1} ź°’ģ“ ģžˆģŠµė‹ˆė‹¤. ģ½źø° ķ‰ź°€ ģøģ‡„ 루프, 디버그", - "replValueOutputAriaLabel": "{0}, ģ½źø° ķ‰ź°€ ģøģ‡„ 루프, 디버그", - "replKeyValueOutputAriaLabel": "출렄 ė³€ģˆ˜ {0}에 {1} ź°’ģ“ ģžˆģŠµė‹ˆė‹¤. ģ½źø° ķ‰ź°€ ģøģ‡„ 루프, 디버그" + "replValueOutputAriaLabel": "{0}, ģ½źø° ķ‰ź°€ ģøģ‡„ 루프, 디버그" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index 6de8809b45e..86af02695e3 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "ķ”„ė”œź·øėžØģ“ 디버그될 ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", - "statusBarDebuggingForeground": "ķ”„ė”œź·øėžØģ“ 디버그될 ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤." + "statusBarDebuggingForeground": "ķ”„ė”œź·øėžØģ“ 디버그될 ė•Œģ˜ 상태 ķ‘œģ‹œģ¤„ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "statusBarDebuggingBorder": "ķ”„ė”œź·øėžØ 디버깅 중 ģ‚¬ģ“ė“œė°” ė° ķŽøģ§‘źø°ģ™€ źµ¬ė¶„ķ•˜ėŠ” 상태 ķ‘œģ‹œģ¤„ ķ…Œė‘ė¦¬ ģƒ‰ģž…ė‹ˆė‹¤. 상태 ķ‘œģ‹œģ¤„ģ€ ģ°½ģ˜ ė§Ø ģ•„ėž˜ģ— ķ‘œģ‹œė©ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 6be8b2345df..c5ed858c98b 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "디버그 ģ–“ėŒ‘ķ„° 실행 ķŒŒģ¼ '{0}'ģ“(ź°€) ģ—†ģŠµė‹ˆė‹¤.", "debugAdapterCannotDetermineExecutable": "디버그 ģ–“ėŒ‘ķ„° '{0}'에 ėŒ€ķ•œ 실행 ķŒŒģ¼ģ„ ķ™•ģøķ•  수 ģ—†ģŠµė‹ˆė‹¤.", + "launch.config.comment1": "IntelliSense넼 ģ‚¬ģš©ķ•˜ģ—¬ ź°€ėŠ„ķ•œ ķŠ¹ģ„±ģ— ėŒ€ķ•“ ģ•Œģ•„ė³“ģ„øģš”.", + "launch.config.comment2": "기씓 ķŠ¹ģ„±ģ— ėŒ€ķ•œ ģ„¤ėŖ…ģ„ 볓려멓 ź°€ė¦¬ķ‚µė‹ˆė‹¤.", + "launch.config.comment3": "ģžģ„øķ•œ ė‚“ģš©ģ„ 볓려멓 {0}ģ„(넼) ė°©ė¬øķ•˜ģ„øģš”.", "debugType": "źµ¬ģ„±ģ˜ ķ˜•ģ‹ģž…ė‹ˆė‹¤.", "debugTypeNotRecognised": "디버그 ķ˜•ģ‹ģ“ ģøģ‹ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ķ•“ė‹¹ķ•˜ėŠ” 디버그 ķ™•ģž„ģ„ ģ„¤ģ¹˜ķ•˜ź³  ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ–ˆėŠ”ģ§€ ķ™•ģøķ•˜ģ„øģš”.", "node2NotSupported": "\"node2\"ėŠ” ė” ģ“ģƒ ģ§€ģ›ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ėŒ€ģ‹  \"node\"넼 ģ‚¬ģš©ķ•˜ź³  \"protocol\" ķŠ¹ģ„±ģ„ \"inspector\"딜 ģ„¤ģ •ķ•˜ģ„øģš”.", diff --git a/i18n/kor/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json index 3eb884953bf..50730f44076 100644 --- a/i18n/kor/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "terminalConfigurationTitle": "외부 터미널", + "explorer.openInTerminalKind": "실행할 터미널 ģ¢…ė„˜ė„¼ ģ‚¬ģš©ģž ģ§€ģ •ķ•©ė‹ˆė‹¤.", "terminal.external.windowsExec": "Windowsģ—ģ„œ 실행할 ķ„°ėÆøė„ģ„ ģ‚¬ģš©ģž ģ§€ģ •ķ•©ė‹ˆė‹¤.", "terminal.external.osxExec": "OS Xģ—ģ„œ 실행할 터미널 ģ‘ģš© ķ”„ė”œź·øėžØģ„ ģ‚¬ģš©ģž ģ§€ģ •ķ•©ė‹ˆė‹¤.", "terminal.external.linuxExec": "Linuxģ—ģ„œ 실행할 ķ„°ėÆøė„ģ„ ģ‚¬ģš©ģž ģ§€ģ •ķ•©ė‹ˆė‹¤.", diff --git a/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 14206f8db05..7092740fd0c 100644 --- a/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "ģ“ė¦„", "view location": "ģœ„ģ¹˜", - "themes": "ķ…Œė§ˆ({0})", + "colorThemes": "ģƒ‰ ķ…Œė§ˆ({0})", + "iconThemes": "ģ•„ģ“ģ½˜ ķ…Œė§ˆ({0})", + "colors": "ģƒ‰({0})", + "colorId": "ID", + "defaultDark": "ģ–“ė‘”ź²Œ źø°ė³øź°’", + "defaultLight": "ė°ź²Œ źø°ė³øź°’", + "defaultHC": "ź³ ėŒ€ė¹„ źø°ė³øź°’", "JSON Validation": "JSON ģœ ķšØģ„± 검사({0})", "commands": "ėŖ…ė ¹({0})", "command name": "ģ“ė¦„", diff --git a/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 748fbd6e5f8..69ea1b57782 100644 --- a/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,23 +34,24 @@ "postDisableMessage": "ģ“ ģ°½ģ„ ė‹¤ģ‹œ ė”œė“œķ•˜ģ—¬ '{0}' ķ™•ģž„ģ„ ė¹„ķ™œģ„±ķ™”ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", "postUninstallTooltip": "ė¹„ķ™œģ„±ķ™”ķ•˜ė ¤ė©“ ė‹¤ģ‹œ ė”œė“œ", "postUninstallMessage": "ģ“ ģ°½ģ„ ė‹¤ģ‹œ ė”œė“œķ•˜ģ—¬ 제거된 ķ™•ģž„ '{0}'ģ„(넼) ė¹„ķ™œģ„±ķ™”ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", - "reload": "ģ°½ ė‹¤ģ‹œ ė”œė“œ(&&R)", "toggleExtensionsViewlet": "ķ™•ģž„ ķ‘œģ‹œ", "installExtensions": "ķ™•ģž„ ģ„¤ģ¹˜", + "showEnabledExtensions": "ģ‚¬ģš© ķ™•ģž„ģž ķ‘œģ‹œ", "showInstalledExtensions": "ģ„¤ģ¹˜ėœ ķ™•ģž„ ķ‘œģ‹œ", "showDisabledExtensions": "ģ‚¬ģš©ķ•  수 ģ—†ėŠ” ķ™•ģž„ ķ‘œģ‹œ", "clearExtensionsInput": "ķ™•ģž„ ģž…ė „ ģ§€ģš°źø°", "showOutdatedExtensions": "만료된 ķ™•ģž„ ķ‘œģ‹œ", "showPopularExtensions": "ģžģ£¼ ģ‚¬ģš©ė˜ėŠ” ķ™•ģž„ ķ‘œģ‹œ", "showRecommendedExtensions": "ź¶Œģž„ė˜ėŠ” ķ™•ģž„ ķ‘œģ‹œ", - "showWorkspaceRecommendedExtensions": "ģž‘ģ—… ģ˜ģ—­ ź¶Œģž„ ķ™•ģž„ ķ‘œģ‹œ", "showRecommendedKeymapExtensions": "ź¶Œģž„ė˜ėŠ” 키 ė§µ ķ‘œģ‹œ", "showRecommendedKeymapExtensionsShort": "키 ė§µ", "showLanguageExtensions": "ģ–øģ–“ ķ™•ģž„ ķ‘œģ‹œ", "showLanguageExtensionsShort": "ģ–øģ–“ ķ™•ģž„", - "configureWorkspaceRecommendedExtensions": "ź¶Œģž„ ķ™•ģž„ 구성(ģž‘ģ—… ģ˜ģ—­)", - "ConfigureWorkspaceRecommendations.noWorkspace": "ź¶Œģž„ ģ‚¬ķ•­ģ€ ģž‘ģ—… ģ˜ģ—­ ķ“ė”ģ—ģ„œė§Œ ģ‚¬ģš©ķ•  수 ģžˆģŠµė‹ˆė‹¤.", + "showAzureExtensions": "Azure ķ™•ģž„ ķ‘œģ‹œ", + "showAzureExtensionsShort": "Azure ķ™•ģž„", "OpenExtensionsFile.failed": "'.vscode' ķ“ė”({0}) 낓에 'extensions.json' ķŒŒģ¼ģ„ ė§Œė“¤ 수 ģ—†ģŠµė‹ˆė‹¤.", + "configureWorkspaceRecommendedExtensions": "ź¶Œģž„ ķ™•ģž„ 구성(ģž‘ģ—… ģ˜ģ—­)", + "configureWorkspaceFolderRecommendedExtensions": "ź¶Œģž„ ķ™•ģž„ 구성(ģž‘ģ—… ģ˜ģ—­ ķ“ė”)", "builtin": "źø°ė³ø 제공", "disableAll": "ģ„¤ģ¹˜ėœ ėŖØė“  ķ™•ģž„ ģ‚¬ģš© ģ•ˆ 함", "disableAllWorkspace": "ģ“ ģž‘ģ—… ģ˜ģ—­ģ— ėŒ€ķ•“ ģ„¤ģ¹˜ėœ ėŖØė“  ķ™•ģž„ ģ‚¬ģš© ģ•ˆ 함", diff --git a/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..b2d929577ac --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "ź¶Œģž„" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 3e7d2bd101a..758c995665c 100644 --- a/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "reallyRecommended2": "ģ“ ķŒŒģ¼ ķ˜•ģ‹ģ— ėŒ€ķ•“ '{0}' ķ™•ģž„ģ“ ź¶Œģž„ė©ė‹ˆė‹¤.", + "reallyRecommendedExtensionPack": "ģ“ ķŒŒģ¼ ķ˜•ģ‹ģ— ėŒ€ķ•“ '{0}' ķ™•ģž„ ķŒ©ģ“ ź¶Œģž„ė©ė‹ˆė‹¤.", "showRecommendations": "ź¶Œģž„ 사항 ķ‘œģ‹œ", + "install": "ģ„¤ģ¹˜", "neverShowAgain": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", "close": "ė‹«źø°", "workspaceRecommended": "ģ“ ģž‘ģ—… ģ˜ģ—­ģ— ķ™•ģž„ ź¶Œģž„ ģ‚¬ķ•­ģ“ ģžˆģŠµė‹ˆė‹¤.", diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index c19803eafbd..70dd8169321 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -5,5 +5,7 @@ // Do not edit this file. It is machine generated. { "filesCategory": "ķŒŒģ¼", - "revealInSideBar": "ģ„øė”œ ė§‰ėŒ€ģ— ķ‘œģ‹œ" + "revealInSideBar": "ģ„øė”œ ė§‰ėŒ€ģ— ķ‘œģ‹œ", + "acceptLocalChanges": "ė³€ź²½ģ„ ģ ģš©ķ•˜ź³  ė””ģŠ¤ķ¬ ģ½˜ķ…ģø  ė®ģ–“ģ“°źø°", + "revertLocalChanges": "변경 ė‚“ģš©ģ„ ģ·Øģ†Œķ•˜ź³  ė””ģŠ¤ķ¬ģ˜ ģ½˜ķ…ģø ė”œ ė˜ėŒė¦¬źø°" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 272b83e055a..4accb18e1c2 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,17 +37,14 @@ "openToSide": "ģø”ė©“ģ—ģ„œ ģ—“źø°", "compareSource": "비교넼 ģœ„ķ•“ ģ„ ķƒ", "globalCompareFile": "ķ™œģ„± ķŒŒģ¼ģ„ ė‹¤ģŒź³¼ 비교...", - "pickHistory": "비교할 ģ“ģ „ģ— ģ—° ķŒŒģ¼ ģ„ ķƒ", - "unableToFileToCompare": "ģ„ ķƒķ•œ ķŒŒģ¼ģ„ '{0}'ź³¼(와) 비교할 수 ģ—†ģŠµė‹ˆė‹¤.", "openFileToCompare": "첫 번째 ķŒŒģ¼ģ„ ģ—“ģ–“ģ„œ 다넸 ķŒŒģ¼ź³¼ ė¹„źµķ•©ė‹ˆė‹¤.", - "compareWith": "'{0}'ź³¼(와) 비교", + "compareWith": "'{0}'ź³¼(와) '{1}' 비교", "compareFiles": "ķŒŒģ¼ 비교", "refresh": "새딜 고침", "save": "ģ €ģž„", "saveAs": "다넸 ģ“ė¦„ģœ¼ė”œ ģ €ģž„...", "saveAll": "모두 ģ €ģž„", "saveAllInGroup": "ź·øė£¹ģ˜ ėŖØė“  ķ•­ėŖ© ģ €ģž„", - "saveFiles": "ė”ķ‹° ķŒŒģ¼ ģ €ģž„", "revert": "ķŒŒģ¼ ė˜ėŒė¦¬źø°", "focusOpenEditors": "ģ—“ė ¤ ģžˆėŠ” ķŽøģ§‘źø° 뷰에 ķ¬ģ»¤ģŠ¤", "focusFilesExplorer": "ķŒŒģ¼ ķƒģƒ‰źø°ģ— ķ¬ģ»¤ģŠ¤", @@ -55,7 +52,6 @@ "openFileToShow": "ķƒģƒ‰źø°ģ— ķ‘œģ‹œķ•˜ė ¤ė©“ 먼저 ķŒŒģ¼ģ„ ģ—½ė‹ˆė‹¤.", "collapseExplorerFolders": "ķƒģƒ‰źø°ģ—ģ„œ ķ“ė” ģ¶•ģ†Œ", "refreshExplorer": "ķƒģƒ‰źø° 새딜 고침", - "openFile": "ķŒŒģ¼ ģ—“źø°...", "openFileInNewWindow": "새 ģ°½ģ—ģ„œ ķ™œģ„± ķŒŒģ¼ ģ—“źø°", "openFileToShowInNewWindow": "먼저 ķŒŒģ¼ ķ•œ 개넼 새 ģ°½ģ—ģ„œ ģ—½ė‹ˆė‹¤.", "revealInWindows": "ķƒģƒ‰źø°ģ— ķ‘œģ‹œ", @@ -69,5 +65,7 @@ "emptyFileNameError": "ķŒŒģ¼ ė˜ėŠ” ķ“ė” ģ“ė¦„ģ„ ģž…ė „ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", "fileNameExistsError": "ķŒŒģ¼ ė˜ėŠ” ķ“ė” **{0}**ģ“(ź°€) ģ“ ģœ„ģ¹˜ģ— ģ“ėÆø ģžˆģŠµė‹ˆė‹¤. 다넸 ģ“ė¦„ģ„ ģ„ ķƒķ•˜ģ„øģš”.", "invalidFileNameError": "**{0}**(ģ“)ė¼ėŠ” ģ“ė¦„ģ€ ķŒŒģ¼ ė˜ėŠ” ķ“ė” ģ“ė¦„ģœ¼ė”œ ģ˜¬ė°”ė„“ģ§€ ģ•ŠģŠµė‹ˆė‹¤. 다넸 ģ“ė¦„ģ„ ģ„ ķƒķ•˜ģ„øģš”.", - "filePathTooLongError": "**{0}**(ģ“)ė¼ėŠ” ģ“ė¦„ģ„ ģ‚¬ģš©ķ•˜ė©“ ź²½ė”œź°€ ė„ˆė¬“ źøøģ–“ģ§‘ė‹ˆė‹¤. ģ§§ģ€ ģ“ė¦„ģ„ ģ„ ķƒķ•˜ģ„øģš”." + "filePathTooLongError": "**{0}**(ģ“)ė¼ėŠ” ģ“ė¦„ģ„ ģ‚¬ģš©ķ•˜ė©“ ź²½ė”œź°€ ė„ˆė¬“ źøøģ–“ģ§‘ė‹ˆė‹¤. ģ§§ģ€ ģ“ė¦„ģ„ ģ„ ķƒķ•˜ģ„øģš”.", + "compareWithSaved": "ķ™œģ„± ķŒŒģ¼ģ„ ģ €ģž„ėœ ķŒŒģ¼ź³¼ 비교", + "modifiedLabel": "{0}(ė””ģŠ¤ķ¬) ↔ {1}" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 2044ec34d69..c3fd559ec19 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "ķ…ģŠ¤ķŠø ķŒŒģ¼ ķŽøģ§‘źø°", "binaryFileEditor": "ģ“ģ§„ ķŒŒģ¼ ķŽøģ§‘źø°", "filesConfigurationTitle": "ķŒŒģ¼", - "exclude": "ķŒŒģ¼ź³¼ ķ“ė”ė„¼ ģ œģ™øķ•˜źø° ģœ„ķ•œ GLOB ķŒØķ„“ģ„ źµ¬ģ„±ķ•©ė‹ˆė‹¤.", + "exclude": "ķŒŒģ¼ ė° ķ“ė”ė„¼ ģ œģ™øķ•˜ė„ė” GLOB ķŒØķ„“ģ„ źµ¬ģ„±ķ•©ė‹ˆė‹¤. 예넼 들얓 ķŒŒģ¼ ķƒģƒ‰źø°ėŠ” ģ“ 설정에 ė”°ė¼ ķ‘œģ‹œķ•˜ź±°ė‚˜ 숨길 ķŒŒģ¼ ė° ķ“ė”ė„¼ ź²°ģ •ķ•©ė‹ˆė‹¤.", "files.exclude.boolean": "ķŒŒģ¼ 경딜넼 ģ¼ģ¹˜ģ‹œķ‚¬ GLOB ķŒØķ„“ģž…ė‹ˆė‹¤. ķŒØķ„“ģ„ ģ‚¬ģš©ķ•˜ź±°ė‚˜ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ķ•˜ė ¤ė©“ true ė˜ėŠ” false딜 ģ„¤ģ •ķ•˜ģ„øģš”.", "files.exclude.when": "ģ¼ģ¹˜ķ•˜ėŠ” ķŒŒģ¼ģ˜ ķ˜•ģ œģ— ėŒ€ķ•œ 추가 ź²€ģ‚¬ģž…ė‹ˆė‹¤. $(basename)ģ„ ģ¼ģ¹˜ķ•˜ėŠ” ķŒŒģ¼ ģ“ė¦„ģ— ėŒ€ķ•œ ė³€ģˆ˜ė”œ ģ‚¬ģš©ķ•˜ģ„øģš”.", "associations": "ķŒŒģ¼ź³¼ ģ–øģ–“ģ˜ ģ—°ź²°ģ„ źµ¬ģ„±ķ•˜ģ„øģš”(예: \"*.extension\": \"html\"). ģ“ėŸ¬ķ•œ źµ¬ģ„±ģ€ ģ„¤ģ¹˜ėœ ģ–øģ–“ģ˜ źø°ė³ø 연결볓다 ģš°ģ„  ģˆœģœ„ź°€ ė†’ģŠµė‹ˆė‹¤.", - "encoding": "ķŒŒģ¼ģ„ ģ½ź³  쓸 ė•Œ ģ‚¬ģš©ķ•  źø°ė³ø ė¬øģž ģ§‘ķ•© ģøģ½”ė”©ģž…ė‹ˆė‹¤.", - "autoGuessEncoding": "ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•˜ėŠ” 경우 ķŒŒģ¼ģ„ ģ—“ ė•Œ ė¬øģž ģ§‘ķ•© ģøģ½”ė”©ģ„ ģ¶”ģø”ķ•©ė‹ˆė‹¤.", + "encoding": "ķŒŒģ¼ģ„ ģ½ź³  쓸 ė•Œ ģ‚¬ģš©ķ•  źø°ė³ø ė¬øģž ģ§‘ķ•© ģøģ½”ė”©ģž…ė‹ˆė‹¤. ģ“ ģ„¤ģ •ģ€ ģ–øģ–“ė³„ė”œ 구성할 ģˆ˜ė„ ģžˆģŠµė‹ˆė‹¤.", + "autoGuessEncoding": "ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•˜ėŠ” 경우 ķŒŒģ¼ģ„ ģ—“ ė•Œ ė¬øģž ģ§‘ķ•© ģøģ½”ė”©ģ„ ģ¶”ģø”ķ•©ė‹ˆė‹¤. ģ“ ģ„¤ģ •ģ€ ģ–øģ–“ė³„ė”œ 구성할 ģˆ˜ė„ ģžˆģŠµė‹ˆė‹¤.", "eol": "줄 ė°”źæˆ ė¬øģžģ˜ źø°ė³ø ėģž…ė‹ˆė‹¤. LFģ—ėŠ” \\n, CRLFģ—ėŠ” \\r\\nģ„ ģ‚¬ģš©ķ•˜ģ„øģš”.", "trimTrailingWhitespace": "ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ė˜ė©“ ķŒŒģ¼ģ„ ģ €ģž„ķ•  ė•Œ 후행 ź³µė°±ģ“ ģž˜ė¦½ė‹ˆė‹¤.", "insertFinalNewline": "ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ė˜ė©“ ģ €ģž„ķ•  ė•Œ ķŒŒģ¼ ėģ— ė§ˆģ§€ė§‰ ģ¤„ė°”źæˆģ„ ģ‚½ģž…ķ•©ė‹ˆė‹¤.", + "trimFinalNewlines": "ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ė˜ė©“ ģ €ģž„ķ•  ė•Œ ķŒŒģ¼ ėģ— ė§ˆģ§€ė§‰ 줄 ė°”źæˆ ģ“ķ›„ģ˜ ėŖØė“  줄 ė°”źæˆģ“ ģž˜ė¦½ė‹ˆė‹¤.", "files.autoSave.off": "ė”ķ‹° ķŒŒģ¼ģ“ ģžė™ģœ¼ė”œ ģ €ģž„ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "files.autoSave.afterDelay": "'files.autoSaveDelay' 구성 후 ė”ķ‹° ķŒŒģ¼ģ“ ģžė™ģœ¼ė”œ ģ €ģž„ė©ė‹ˆė‹¤.", "files.autoSave.onFocusChange": "ķŽøģ§‘źø°ź°€ ķ¬ģ»¤ģŠ¤ė„¼ ģžƒģœ¼ė©“ ė”ķ‹° ķŒŒģ¼ģ“ ģžė™ģœ¼ė”œ ģ €ģž„ė©ė‹ˆė‹¤.", @@ -38,5 +39,11 @@ "openEditorsVisible": "ģ—“ė ¤ ģžˆėŠ” ķŽøģ§‘źø° 창에 ķ‘œģ‹œė˜ėŠ” ķŽøģ§‘źø° ģˆ˜ģž…ė‹ˆė‹¤. ģ°½ģ„ 숨기려멓 0으딜 ģ„¤ģ •ķ•©ė‹ˆė‹¤.", "dynamicHeight": "ģ—“ė ¤ ģžˆėŠ” ķŽøģ§‘źø° ģ„¹ģ…˜ģ˜ ė†’ģ“ź°€ ģš”ģ†Œ ģˆ˜ģ— ė”°ė¼ ė™ģ ģœ¼ė”œ ģ”°ģ •ė˜ėŠ”ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "autoReveal": "ķƒģƒ‰źø°ģ—ģ„œ ķŒŒģ¼ģ„ ģ—“ ė•Œ ģžė™ģœ¼ė”œ ķ‘œģ‹œķ•˜ź³  ģ„ ķƒķ• ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", - "enableDragAndDrop": "ķƒģƒ‰źø°ģ—ģ„œ ėŒģ–“ģ„œ 놓기넼 ķ†µķ•œ ķŒŒģ¼ ė° ķ“ė” ģ“ė™ģ„ ķ—ˆģš©ķ•˜ėŠ”ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤." + "enableDragAndDrop": "ķƒģƒ‰źø°ģ—ģ„œ ėŒģ–“ģ„œ 놓기넼 ķ†µķ•œ ķŒŒģ¼ ė° ķ“ė” ģ“ė™ģ„ ķ—ˆģš©ķ•˜ėŠ”ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", + "sortOrder.default": "ķŒŒģ¼ ė° ķ“ė”ź°€ ģ“ė¦„ģ„ źø°ģ¤€ģœ¼ė”œ ģ‚¬ģ „ģˆœģœ¼ė”œ ģ •ė ¬ė©ė‹ˆė‹¤. ķ“ė”ź°€ ķŒŒģ¼ ģ•žģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "sortOrder.mixed": "ķŒŒģ¼ ė° ķ“ė”ź°€ ģ“ė¦„ģ„ źø°ģ¤€ģœ¼ė”œ ģ‚¬ģ „ģˆœģœ¼ė”œ ģ •ė ¬ė©ė‹ˆė‹¤. ķŒŒģ¼ģ“ ķ“ė”ģ™€ ź²°ķ•©ė©ė‹ˆė‹¤.", + "sortOrder.filesFirst": "ķŒŒģ¼ ė° ķ“ė”ź°€ ģ“ė¦„ģ„ źø°ģ¤€ģœ¼ė”œ ģ‚¬ģ „ģˆœģœ¼ė”œ ģ •ė ¬ė©ė‹ˆė‹¤. ķŒŒģ¼ģ“ ķ“ė” ģ•žģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "sortOrder.type": "ķŒŒģ¼ ė° ķ“ė”ź°€ ķ™•ģž„ėŖ…ģ„ źø°ģ¤€ģœ¼ė”œ ģ‚¬ģ „ģˆœģœ¼ė”œ ģ •ė ¬ė©ė‹ˆė‹¤. ķ“ė”ź°€ ķŒŒģ¼ ģ•žģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "sortOrder.modified": "ķŒŒģ¼ ė° ķ“ė”ź°€ ė§ˆģ§€ė§‰ģœ¼ė”œ ģˆ˜ģ •ķ•œ ė‚ ģ§œė„¼ źø°ģ¤€ģœ¼ė”œ ė‚“ė¦¼ģ°Øģˆœ ģ •ė ¬ė©ė‹ˆė‹¤. ķ“ė”ź°€ ķŒŒģ¼ ģ•žģ— ķ‘œģ‹œė©ė‹ˆė‹¤.", + "sortOrder": "ķƒģƒ‰źø°ģ—ģ„œ ķŒŒģ¼ ė° ķ“ė”ģ˜ ģ •ė ¬ ģˆœģ„œė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤. źø°ė³ø ģ •ė ¬ 외에 ģˆœģ„œė„¼ 'mixed'(ķŒŒģ¼ ė° ķ“ė”ź°€ ź²°ķ•©ė˜ģ–“ ģ •ė ¬), 'type'(ķŒŒģ¼ ķ˜•ģ‹ 기준), 'modified'(ė§ˆģ§€ė§‰ģœ¼ė”œ ģˆ˜ģ •ķ•œ ė‚ ģ§œ 기준) ė˜ėŠ” 'filesFirst'(ķŒŒģ¼ģ„ ķ“ė” ģ•žģ— ģ •ė ¬)딜 설정할 수 ģžˆģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index cbfa5b0cef9..6cf353ae712 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "오넸쪽 ķŽøģ§‘źø° ė„źµ¬ ėŖØģŒģ˜ ģž‘ģ—…ģ„ ģ‚¬ģš©ķ•˜ģ—¬ 변경 ė‚“ģš©ģ„ **실행 ģ·Øģ†Œ**ķ•˜ź±°ė‚˜ ė””ģŠ¤ķ¬ģ˜ ģ½˜ķ…ģø ė„¼ 변경 ė‚“ģš©ģœ¼ė”œ **ė®ģ–“ģ“°źø°**", "discard": "ģ‚­ģ œ", "overwrite": "ė®ģ–“ģ“°źø°", "retry": "ė‹¤ģ‹œ ģ‹œė„", diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 643334c6aba..42fb83a81b7 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "엓린 ķ“ė” ģ—†ģŒ", "explorerSection": "ķŒŒģ¼ ķƒģƒ‰źø° ģ„¹ģ…˜", - "noWorkspaceHelp": "아직 ķ“ė”ė„¼ ģ—“ģ§€ ģ•Šģ•˜ģŠµė‹ˆė‹¤.", + "noFolderHelp": "아직 ķ“ė”ė„¼ ģ—“ģ§€ ģ•Šģ•˜ģŠµė‹ˆė‹¤.", "openFolder": "ķ“ė” ģ—“źø°" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..65c8759c915 --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "ķƒģƒ‰źø°" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 77df94558df..8d29882bc60 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,10 @@ { "fileInputAriaLabel": "ķŒŒģ¼ ģ“ė¦„ģ„ ģž…ė „ķ•©ė‹ˆė‹¤. ķ™•ģøķ•˜ė ¤ė©“ Enter 키넼 ėˆ„ė„“ź³ , ģ·Øģ†Œķ•˜ė ¤ė©“ Esc 키넼 ėˆ„ė¦…ė‹ˆė‹¤.", "filesExplorerViewerAriaLabel": "{0}, ķŒŒģ¼ ķƒģƒ‰źø°", + "dropFolders": "ģž‘ģ—… ģ˜ģ—­ģ— ķ“ė”ė„¼ ģ¶”ź°€ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "dropFolder": "ģž‘ģ—… ģ˜ģ—­ģ— ķ“ė”ė„¼ ģ¶”ź°€ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ?", + "addFolders": "ķ“ė” 추가(&&A)", + "addFolder": "ķ“ė” 추가(&&A)", "confirmOverwriteMessage": "'{0}'ģ“(ź°€) ėŒ€ģƒ ķ“ė”ģ— ģ“ėÆø ģžˆģŠµė‹ˆė‹¤. ė°”źæ€ź¹Œģš”?", "irreversible": "ģ“ ģž‘ģ—…ģ€ ģ·Øģ†Œķ•  수 ģ—†ģŠµė‹ˆė‹¤.", "replaceButtonLabel": "바꾸기(&&R)" diff --git a/i18n/kor/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json b/i18n/kor/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json index 467ecab8263..54e2599b3f7 100644 --- a/i18n/kor/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json @@ -9,6 +9,7 @@ "saveAll": "모두 ģ €ģž„", "closeAllUnmodified": "ģˆ˜ģ •ė˜ģ§€ ģ•Šģ€ ķ•­ėŖ© ė‹«źø°", "closeAll": "모두 ė‹«źø°", + "compareWithSaved": "ģ €ģž„ėœ ķ•­ėŖ©ź³¼ 비교", "close": "ė‹«źø°", "closeOthers": "źø°ķƒ€ ķ•­ėŖ© ė‹«źø°" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/kor/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index cbd0a366921..92d4ab06aac 100644 --- a/i18n/kor/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "ģ €ģž„ė˜ģ§€ ģ•Šģ€ ķŒŒģ¼ 1개", "dirtyFiles": "{0}ź°œģ˜ ģ €ģž„ė˜ģ§€ ģ•Šģ€ ķŒŒģ¼" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/kor/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..9a5ca02f322 --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "문제" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index 3eaa6c83509..d0885df5255 100644 --- a/i18n/kor/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "느린 ģ‹œģž‘ 감지됨", - "slow.detail": "방금 느리게 ģ‹œģž‘ė˜ģ—ˆģŠµė‹ˆė‹¤. ķ”„ė”œķŒŒģ¼ė§ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•œ 상태딜 '{0}'ģ„(넼) ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ģ„øģš”. ķ”„ė”œķ•„ģ„ ź³µģœ ķ•“ ģ£¼ģ‹œė©“ ė‹¤ģ‹œ 빠넓게 ģ‹œģž‘ė  수 ģžˆė„ė” ģµœģ„ ģ„ ė‹¤ķ•˜ź² ģŠµė‹ˆė‹¤.", "prof.message": "ķ”„ė”œķ•„ģ„ ė§Œė“¤ģ—ˆģŠµė‹ˆė‹¤.", "prof.detail": "문제넼 ė°œģƒģ‹œķ‚¤ź³  ė‹¤ģŒ ķŒŒģ¼ģ„ ģˆ˜ė™ģœ¼ė”œ ģ²Øė¶€ķ•˜ģ„øģš”.\n{0}", "prof.restartAndFileIssue": "문제 ė§Œė“¤źø° ė° ė‹¤ģ‹œ ģ‹œģž‘", diff --git a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 474bdeb6edf..3ded239f7d2 100644 --- a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -8,6 +8,7 @@ "openGlobalKeybindings": "ė°”ė”œ 가기 키 ģ—“źø°", "openGlobalKeybindingsFile": "ė°”ė”œ 가기 키 ķŒŒģ¼ ģ—“źø°", "openWorkspaceSettings": "ģž‘ģ—… ģ˜ģ—­ 설정 ģ—“źø°", + "openFolderSettings": "ķ“ė” 설정 ģ—“źø°", "configureLanguageBasedSettings": "언얓별 설정 구성...", "languageDescriptionConfigured": "({0})", "pickLanguage": "ģ–øģ–“ ģ„ ķƒ" diff --git a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 714541e3b4c..81148e5b1a9 100644 --- a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. ķŒŒģ¼ģ—ģ„œ 오넘/경고넼 ķ•“ź²°ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "emptyUserSettingsHeader": "ģ„¤ģ •ģ„ 여기에 ė„£ģ–“ģ„œ źø°ė³ø ģ„¤ģ •ģ„ ė®ģ–“ģ”ė‹ˆė‹¤.", + "emptyWorkspaceSettingsHeader": "ģ„¤ģ •ģ„ 여기에 ė„£ģ–“ģ„œ ģ‚¬ģš©ģž ģ„¤ģ •ģ„ ė®ģ–“ģ”ė‹ˆė‹¤.", + "emptyFolderSettingsHeader": "ķ“ė” ģ„¤ģ •ģ„ 여기에 ė„£ģ–“ģ„œ ģž‘ģ—… ģ˜ģ—­ ģ„¤ģ •ģ„ ė®ģ–“ģ”ė‹ˆė‹¤.", + "defaultFolderSettingsTitle": "źø°ė³ø ķ“ė” 설정", "defaultSettingsTitle": "źø°ė³ø 설정", - "noSettingsFound": "ģ„¤ģ •ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤.", "editTtile": "ķŽøģ§‘", "replaceDefaultValue": "ģ„¤ģ •ģ—ģ„œ 바꾸기", "copyDefaultValue": "설정에 복사", "unsupportedPHPExecutablePathSetting": "ģ“ ģ„¤ģ •ģ€ ģ‚¬ģš©ģž ģ„¤ģ •ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤. ģž‘ģ—… ģ˜ģ—­ģ— ėŒ€ķ•“ PHP넼 źµ¬ģ„±ķ•˜ė ¤ė©“ PHP ķŒŒģ¼ģ„ ģ—“ź³  상태 ķ‘œģ‹œģ¤„ģ—ģ„œ 'PHP 경딜'넼 ķ“ė¦­ķ•©ė‹ˆė‹¤.", - "unsupportedWorkspaceSetting": "ģ“ ģ„¤ģ •ģ€ ģ‚¬ģš©ģž ģ„¤ģ •ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤." + "unsupportedWorkspaceSetting": "ģ“ ģ„¤ģ •ģ€ ģ‚¬ģš©ģž ģ„¤ģ •ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "unsupportedWorkbenchSetting": "ģ“ ģ„¤ģ •ģ€ ģ§€źøˆ ģ ģš©ķ•  수 ģ—†ģœ¼ė©° ģ“ ķ“ė”ė„¼ 직접 ģ—“ ź²½ģš°ģ— ģ ģš©ė©ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json index f43ae31feda..7c672264d39 100644 --- a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json @@ -7,5 +7,6 @@ "openFolderFirst": "첫 번째 ķ“ė”ė„¼ ģ—“ģ–“ģ„œ ģž‘ģ—… ģ˜ģ—­ ģ„¤ģ •ģ„ ė§Œė“­ė‹ˆė‹¤.", "emptyKeybindingsHeader": "키 ė°”ģøė”©ģ„ ģ“ ķŒŒģ¼ģ— ė„£ģ–“ģ„œ źø°ė³øź°’ģ„ ė®ģ–“ģ”ė‹ˆė‹¤.", "defaultKeybindings": "źø°ė³ø 키 ė°”ģøė”©", + "folderSettingsName": "{0}(ķ“ė” 설정)", "fail.createSettings": "{0}'({1})ģ„(넼) ė§Œė“¤ 수 ģ—†ģŠµė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 8b6ad71cd4e..04033d76400 100644 --- a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "noSettingsFound": "ģ„¤ģ •ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤.", + "folderSettingsDetails": "ķ“ė” 설정" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/kor/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index b44107be4f3..90960b4f14d 100644 --- a/i18n/kor/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "ģ¼ė°˜ģ ģœ¼ė”œ ģ‚¬ģš©ė˜ėŠ” 설정", - "noSettings": "설정 ģ—†ģŒ", "defaultKeybindingsHeader": "키 ė°”ģøė”©ģ„ 키 ė°”ģøė”© ķŒŒģ¼ģ— ė°°ģ¹˜ķ•˜ģ—¬ ė®ģ–“ģ”ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 3643111bada..a8785cacb78 100644 --- a/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "'{0}' ėŖ…ė ¹ģ€ ķ˜„ģž¬ ģ»Øķ…ģŠ¤ķŠøģ—ģ„œ ģ‚¬ģš©ķ•  수 ģ—†ģŠµė‹ˆė‹¤.", "recentlyUsed": "ģµœź·¼ģ— ģ‚¬ģš©ķ•œ ķ•­ėŖ©", "morecCommands": "źø°ķƒ€ ėŖ…ė ¹", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "ģ¼ģ¹˜ķ•˜ėŠ” ėŖ…ė ¹ ģ—†ģŒ" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 4fe2fc0bfe2..cb13e895beb 100644 --- a/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -5,7 +5,5 @@ // Do not edit this file. It is machine generated. { "relaunchSettingMessage": "ģ„¤ģ •ģ“ ė³€ź²½ė˜ģ–“ ė‹¤ģ‹œ ģ‹œģž‘ķ•“ģ•¼ė§Œ ģ ģš©ė©ė‹ˆė‹¤.", - "relaunchSettingDetail": "[ė‹¤ģ‹œ ģ‹œģž‘] 단추넼 눌러 {0}ģ„(넼) ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ź³  ģ„¤ģ •ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•˜ģ„øģš”.", - "restart": "ė‹¤ģ‹œ ģ‹œģž‘", - "reload": "ė‹¤ģ‹œ ė”œė“œ" + "relaunchSettingDetail": "[ė‹¤ģ‹œ ģ‹œģž‘] 단추넼 눌러 {0}ģ„(넼) ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ź³  ģ„¤ģ •ģ„ ģ‚¬ģš©ķ•˜ė„ė” ģ„¤ģ •ķ•˜ģ„øģš”." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/kor/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 98455580521..06048cc7a3c 100644 --- a/i18n/kor/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -6,5 +6,8 @@ { "editorGutterModifiedBackground": "ģˆ˜ģ •ėœ ģ¤„ģ˜ ķŽøģ§‘źø° 여백 ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "editorGutterAddedBackground": "ģ¶”ź°€ėœ ģ¤„ģ˜ ķŽøģ§‘źø° 여백 ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", - "editorGutterDeletedBackground": "ģ‚­ģ œėœ ģ¤„ģ˜ ķŽøģ§‘źø° 여백 ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤." + "editorGutterDeletedBackground": "ģ‚­ģ œėœ ģ¤„ģ˜ ķŽøģ§‘źø° 여백 ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerModifiedForeground": "ģˆ˜ģ •ėœ ģ½˜ķ…ģø ģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerAddedForeground": "ģ¶”ź°€ėœ ģ½˜ķ…ģø ģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤.", + "overviewRulerDeletedForeground": "ģ‚­ģ œėœ ģ½˜ķ…ģø ģ˜ ź°œģš” ėˆˆźøˆģž 마커 ģƒ‰ģž…ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index 791c967182a..4b848835e91 100644 --- a/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Git ķ‘œģ‹œ", - "installAdditionalSCMProviders": "추가 SCM ź³µźø‰ģž ģ„¤ģ¹˜...", "source control": "ģ†ŒģŠ¤ ģ œģ–“", "toggleSCMViewlet": "SCM ķ‘œģ‹œ", "view": "볓기" diff --git a/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 8e1ae734793..7706711508b 100644 --- a/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "ģ†ŒģŠ¤ ģ œģ–“ ź³µźø‰ģž", + "hideRepository": "숨기기", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "추가 SCM ź³µźø‰ģž ģ„¤ģ¹˜...", + "no open repo": "ķ™œģ„± ģ†ŒģŠ¤ ģ œģ–“ ź³µźø‰ģžź°€ ģ—†ģŠµė‹ˆė‹¤.", "source control": "ģ†ŒģŠ¤ ģ œģ–“", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 43025c6d45c..dc970ca0af2 100644 --- a/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "ģž‘ģ—… ģ˜ģ—­ģ—ģ„œ 기호딜 ģ“ė™...", "name": "ź²€ģƒ‰", - "showSearchViewlet": "ź²€ģƒ‰ ķ‘œģ‹œ", + "search": "ź²€ģƒ‰", "view": "볓기", - "findInFiles": "ķŒŒģ¼ģ—ģ„œ 찾기", "openAnythingHandlerDescription": "ķŒŒģ¼ė”œ ģ“ė™", "openSymbolDescriptionNormal": "ģž‘ģ—… ģ˜ģ—­ģ—ģ„œ 기호딜 ģ“ė™", "searchOutputChannelTitle": "ź²€ģƒ‰", @@ -16,7 +15,5 @@ "exclude": "ź²€ģƒ‰ģ—ģ„œ ķŒŒģ¼ ė° ķ“ė”ė„¼ ģ œģ™øķ•˜ė„ė” GLOB ķŒØķ„“ģ„ źµ¬ģ„±ķ•©ė‹ˆė‹¤. files.exclude ģ„¤ģ •ģ—ģ„œ ėŖØė“  GLOB ķŒØķ„“ģ„ ģƒģ†ķ•©ė‹ˆė‹¤.", "exclude.boolean": "ķŒŒģ¼ 경딜넼 ģ¼ģ¹˜ģ‹œķ‚¬ GLOB ķŒØķ„“ģž…ė‹ˆė‹¤. ķŒØķ„“ģ„ ģ‚¬ģš©ķ•˜ź±°ė‚˜ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šė„ė” ģ„¤ģ •ķ•˜ė ¤ė©“ true ė˜ėŠ” false딜 ģ„¤ģ •ķ•˜ģ„øģš”.", "exclude.when": "ģ¼ģ¹˜ķ•˜ėŠ” ķŒŒģ¼ģ˜ ķ˜•ģ œģ— ėŒ€ķ•œ 추가 ź²€ģ‚¬ģž…ė‹ˆė‹¤. $(basename)ģ„ ģ¼ģ¹˜ķ•˜ėŠ” ķŒŒģ¼ ģ“ė¦„ģ— ėŒ€ķ•œ ė³€ģˆ˜ė”œ ģ‚¬ģš©ķ•˜ģ„øģš”.", - "useRipgrep": "ķ…ģŠ¤ķŠø ź²€ģƒ‰ģ—ģ„œ ripgrep ģ‚¬ģš© 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", - "useIgnoreFilesByDefault": "새 ģž‘ģ—… ģ˜ģ—­ģ—ģ„œ ź²€ģƒ‰ķ•  ė•Œ 기본적으딜 .gitignore ķŒŒģ¼ ė° .ignore ķŒŒģ¼ģ„ ģ‚¬ģš©ķ• ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "search.quickOpen.includeSymbols": "Quick Open에 ėŒ€ķ•œ ķŒŒģ¼ 결과에 ģ „ģ—­ 기호 ź²€ģƒ‰ 결과넼 ķ¬ķ•Øķ•˜ė„ė” źµ¬ģ„±ķ•©ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 7d857095262..787ec35e8aa 100644 --- a/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,16 +4,23 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "ė‹¤ģŒ ź²€ģƒ‰ ķ¬ķ•Ø ķŒØķ„“ ķ‘œģ‹œ", + "previousSearchIncludePattern": "ģ“ģ „ ź²€ģƒ‰ ķ¬ķ•Ø ķŒØķ„“ ķ‘œģ‹œ", + "nextSearchExcludePattern": "ė‹¤ģŒ ź²€ģƒ‰ ģ œģ™ø ķŒØķ„“ ķ‘œģ‹œ", + "previousSearchExcludePattern": "ģ“ģ „ ź²€ģƒ‰ ģ œģ™ø ķŒØķ„“ ķ‘œģ‹œ", "nextSearchTerm": "ė‹¤ģŒ ź²€ģƒ‰ģ–“ ķ‘œģ‹œ", "previousSearchTerm": "ģ“ģ „ ź²€ģƒ‰ģ–“ ķ‘œģ‹œ", "focusNextInputBox": "ė‹¤ģŒ ģž…ė „ ģƒģžģ— ķ¬ģ»¤ģŠ¤", "focusPreviousInputBox": "ģ“ģ „ ģž…ė „ ģƒģžģ— ķ¬ģ»¤ģŠ¤", + "showSearchViewlet": "ź²€ģƒ‰ ķ‘œģ‹œ", + "findInFiles": "ķŒŒģ¼ģ—ģ„œ 찾기", "replaceInFiles": "ķŒŒģ¼ģ—ģ„œ 바꾸기", + "findInWorkspace": "ģž‘ģ—… ģ˜ģ—­ģ—ģ„œ 찾기...", + "findInFolder": "ķ“ė”ģ—ģ„œ 찾기...", "RefreshAction.label": "새딜 고침", "ClearSearchResultsAction.label": "ź²€ģƒ‰ ź²°ź³¼ ģ§€ģš°źø°", "FocusNextSearchResult.label": "ė‹¤ģŒ ź²€ģƒ‰ 결과에 ķ¬ģ»¤ģŠ¤", "FocusPreviousSearchResult.label": "ģ“ģ „ ź²€ģƒ‰ 결과에 ķ¬ģ»¤ģŠ¤", - "RemoveAction.label": "제거", "file.replaceAll.label": "모두 바꾸기", "match.replace.label": "바꾸기" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json b/i18n/kor/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json index 4d21f25e146..2c8228cd8e4 100644 --- a/i18n/kor/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "searchFolderMatch.other.label": "다넸 ķŒŒģ¼", + "searchFileMatches": "{0}개 ķŒŒģ¼ ģ°¾ģŒ", + "searchFileMatch": "{0}개 ķŒŒģ¼ ģ°¾ģŒ", "searchMatches": "ģ¼ģ¹˜ķ•˜ėŠ” {0}개 ķ•­ėŖ©ģ„ ģ°¾ģŒ", "searchMatch": "ģ¼ģ¹˜ķ•˜ėŠ” {0}개 ķ•­ėŖ©ģ„ ģ°¾ģŒ", + "folderMatchAriaLabel": "ķ“ė” 루트 {1}ģ—ģ„œ {0}개 ģ¼ģ¹˜, ź²€ģƒ‰ ź²°ź³¼", "fileMatchAriaLabel": "{2} ķ“ė”ģ˜ {1} ķŒŒģ¼ģ— {0}ź°œģ˜ ģ¼ģ¹˜ ķ•­ėŖ©ģ“ ģžˆģŒ, ź²€ģƒ‰ ź²°ź³¼", "replacePreviewResultAria": "{3} ķ…ģŠ¤ķŠøź°€ ģžˆėŠ” ģ¤„ģ˜ ģ—“ ģœ„ģ¹˜ {2}ģ—ģ„œ ģš©ģ–“ {0}ģ„(넼) {1}(으)딜 바꾸기", "searchResultAria": "{2} ķ…ģŠ¤ķŠøź°€ ģžˆėŠ” ģ¤„ģ˜ ģ—“ ģœ„ģ¹˜ {1}ģ—ģ„œ {0} ģš©ģ–“ 찾기" diff --git a/i18n/kor/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/kor/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index c58a1130001..217c3845282 100644 --- a/i18n/kor/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "ģ œģ™øķ•  ķŒŒģ¼", "label.excludes": "ķŒØķ„“ ģ œģ™ø ź²€ģƒ‰", "replaceAll.confirmation.title": "모두 바꾸기", - "replaceAll.confirm.button": "바꾸기", + "replaceAll.confirm.button": "바꾸기(&&R)", "replaceAll.occurrence.file.message": "{1}개 ķŒŒģ¼ģ—ģ„œ {0}개넼 '{2}'(으)딜 ė°”źæØģŠµė‹ˆė‹¤.", "removeAll.occurrence.file.message": "{1}개 ķŒŒģ¼ģ—ģ„œ {0}개넼 ė°”źæØģŠµė‹ˆė‹¤.", "replaceAll.occurrence.files.message": "{1}개 ķŒŒģ¼ģ—ģ„œ {0}개넼 '{2}'(으)딜 ė°”źæØģŠµė‹ˆė‹¤.", @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "{1}개 ķŒŒģ¼ģ—ģ„œ {0}개넼 '{2}'(으)딜 ė°”ź¾øģ‹œź² ģŠµė‹ˆź¹Œ?", "replaceAll.occurrences.files.confirmation.message": "{1}개 ķŒŒģ¼ģ—ģ„œ {0}개넼 ė°”ź¾øģ‹œź² ģŠµė‹ˆź¹Œ?", "treeAriaLabel": "ź²€ģƒ‰ ź²°ź³¼", + "searchPathNotFoundError": "ź²€ģƒ‰ 경딜넼 ģ°¾ģ„ 수 ģ—†ģŒ: {0}", "searchMaxResultsWarning": "ź²°ź³¼ ģ§‘ķ•©ģ—ėŠ” ėŖØė“  ģ¼ģ¹˜ ķ•­ėŖ©ģ˜ ķ•˜ģœ„ ģ§‘ķ•©ė§Œ ķ¬ķ•Øė©ė‹ˆė‹¤. ź²°ź³¼ ė²”ģœ„ė„¼ ģ¢ķžˆė ¤ė©“ ź²€ģƒ‰ģ„ ė” ģ„øė¶„ķ™”ķ•˜ģ„øģš”.", "searchCanceled": "결과넼 찾기 ģ“ģ „ģ— ź²€ģƒ‰ģ“ ģ·Øģ†Œė˜ģ—ˆģŠµė‹ˆė‹¤. -", "noResultsIncludesExcludes": "'{0}'에 '{1}'ģ„(넼) ģ œģ™øķ•œ ź²°ź³¼ ģ—†ģŒ - ", "noResultsIncludes": "'{0}'에 ź²°ź³¼ ģ—†ģŒ - ", "noResultsExcludes": "'{0}'ģ„(넼) ģ œģ™øķ•˜ėŠ” 결과가 ģ—†ģŒ - ", - "noResultsFound": "결과가 ģ—†ģŠµė‹ˆė‹¤. źµ¬ģ„±ėœ ķ™•ģž„ģ— ėŒ€ķ•œ ģ„¤ģ •ģ„ ź²€ķ† ķ•˜ģ„øģš”. - ", + "noResultsFound": "결과가 ģ—†ģŠµė‹ˆė‹¤. źµ¬ģ„±ėœ ģ˜ˆģ™ø ģ„¤ģ •ģ„ ź²€ķ† ķ•˜ź³  ķŒŒģ¼ģ„ ė¬“ģ‹œķ•˜ģ„øģš”.", "rerunSearch.message": "ė‹¤ģ‹œ ź²€ģƒ‰", "rerunSearchInAll.message": "ėŖØė“  ķŒŒģ¼ģ—ģ„œ ė‹¤ģ‹œ ź²€ģƒ‰", "openSettings.message": "설정 ģ—“źø°", + "openSettings.learnMore": "ģžģ„øķ•œ 정볓", "ariaSearchResultsStatus": "ź²€ģƒ‰ģ—ģ„œ {1}ź°œģ˜ ķŒŒģ¼ģ— {0}ź°œģ˜ 결과넼 ė°˜ķ™˜ķ–ˆģŠµė‹ˆė‹¤.", "search.file.result": "{1}개 ķŒŒģ¼ģ—ģ„œ {0}개 ź²°ź³¼", "search.files.result": "{1}개 ķŒŒģ¼ģ—ģ„œ {0}개 ź²°ź³¼", diff --git a/i18n/kor/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/kor/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..b8d438493ca --- /dev/null +++ b/i18n/kor/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "ģž‘ģ—… ģ˜ģ—­ģ— ģ“ė¦„ģ“ {0}ģø ķ“ė”ź°€ ģ—†ģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 7fd318c3ac3..89f97af107d 100644 --- a/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "ģ½”ė“œ 씰각 ģ‚½ģž…" + "snippet.suggestions.label": "ģ½”ė“œ 씰각 ģ‚½ģž…", + "sep.userSnippet": "ģ‚¬ģš©ģž ģ½”ė“œ 씰각", + "sep.extSnippet": "ķ™•ģž„ ģ½”ė“œ 씰각" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 3019664bb2a..0c5d65d2c8d 100644 --- a/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "`contributes.{0}.language`에 ģ•Œ 수 ģ—†ėŠ” ģ–øģ–“ź°€ ģžˆģŠµė‹ˆė‹¤. 제공된 ź°’: {1}", + "invalid.path.0": "`contributes.{0}.path`에 ė¬øģžģ—“ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤. 제공된 ź°’: {1}", + "invalid.path.1": "ķ™•ģž„ ķ“ė”({2})에 ķ¬ķ•Øķ•  `contributes.{0}.path`({1})ź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤. ķ™•ģž„ģ“ ģ“ģ‹ ė¶ˆź°€ėŠ„ķ•“ģ§ˆ 수 ģžˆģŠµė‹ˆė‹¤.", + "vscode.extension.contributes.snippets": "ģ½”ė“œ ģ”°ź°ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", + "vscode.extension.contributes.snippets-language": "ģ“ ģ½”ė“œ ģ”°ź°ģ“ ģ ģš©ė˜ėŠ” ģ–øģ–“ ģ‹ė³„ģžģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.snippets-path": "ģ½”ė“œ 씰각 ķŒŒģ¼ģ˜ ź²½ė”œģž…ė‹ˆė‹¤. ģ“ ź²½ė”œėŠ” ķ™•ģž„ ķ“ė”ģ˜ ģƒėŒ€ ź²½ė”œģ“ė©° ģ¼ė°˜ģ ģœ¼ė”œ './snippets/'딜 ģ‹œģž‘ķ•©ė‹ˆė‹¤.", + "badFile": "ģ½”ė“œ 씰각 ķŒŒģ¼ \"{0}\"ģ„(넼) ģ½ģ„ 수 ģ—†ģŠµė‹ˆė‹¤.", "source.snippet": "ģ‚¬ģš©ģž ģ½”ė“œ 씰각", "detail.snippet": "{0}({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index e3482cdc4e3..514b9724ac8 100644 --- a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "ģž‘ģ—…ģ˜ ģ¶œė „ģ„ ģ œģ‹œķ•˜ź³  ģž…ė „ģ„ ģ½ėŠ” ė° ģ‚¬ģš©ķ•˜ėŠ” ķŒØė„ģ„ źµ¬ģ„±ķ•©ė‹ˆė‹¤.", "JsonSchema.tasks.presentation.echo": "ģ‹¤ķ–‰ėœ ėŖ…ė ¹ģ„ ķŒØė„ģ— 에코할지 ź²°ģ •ķ•©ė‹ˆė‹¤. źø°ė³øź°’ģ€ trueģž…ė‹ˆė‹¤.", "JsonSchema.tasks.presentation.focus": "ķŒØė„ģ“ ķ¬ģ»¤ģŠ¤ė„¼ ģž”ėŠ”ģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤. źø°ė³øź°’ģ€ falseģž…ė‹ˆė‹¤. true딜 ģ„¤ģ •ķ•˜ė©“ ķŒØė„ė„ ė“œėŸ¬ė‚©ė‹ˆė‹¤.", + "JsonSchema.tasks.presentation.reveal.always": "ģ“ ģž‘ģ—…ģ“ 호출될 ė•Œ ķ„°ėÆøė„ģ„ ķ•­ģƒ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", + "JsonSchema.tasks.presentation.reveal.silent": "문제 ģ„ ķƒźø°ź°€ ģž‘ģ—…ź³¼ ģ—°ź²°ė˜ģ–“ ģžˆģ§€ ģ•Šź³  ģ‹¤ķ–‰ķ•˜ėŠ” 중 ģ˜¤ė„˜ź°€ ė°œģƒķ•˜ėŠ” ź²½ģš°ģ—ė§Œ ķ„°ėÆøė„ģ„ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", + "JsonSchema.tasks.presentation.reveal.never": "ģž‘ģ—…ģ„ 실행할 ė•Œ ķ„°ėÆøė„ģ„ ķ‘œģ‹œķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "JsonSchema.tasks.presentation.reveals": "ģž‘ģ—…ģ„ 실행 ģ¤‘ģø ķŒØė„ģ“ ķ‘œģ‹œė˜ėŠ”ģ§€ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤. źø°ė³øź°’ģ€ \"ķ•­ģƒ\"ģž…ė‹ˆė‹¤.", "JsonSchema.tasks.presentation.instance": "ķŒØė„ģ„ ģž‘ģ—… 간에 ź³µģœ ķ• ģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤. ģ“ ģž‘ģ—… ģ „ģš© ķŒØė„ė”œ ģ‚¬ģš©ķ•˜ź±°ė‚˜ 실행할 ė•Œė§ˆė‹¤ 새딜 ģƒģ„±ķ•©ė‹ˆė‹¤.", "JsonSchema.tasks.terminal": "ģ“ 터미널 ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ķ”„ė ˆģ  ķ…Œģ“ģ…˜ģ„ ėŒ€ģ‹  ģ‚¬ģš©ķ•˜ģ„øģš”.", @@ -22,7 +25,6 @@ "JsonSchema.tasks.group.test": "ģ“ ģž‘ģ—…ģ„ 'ķ…ŒģŠ¤ķŠø ģž‘ģ—… 실행' ėŖ…ė ¹ģ„ 통핓 ģ•”ģ„øģŠ¤ķ•  수 ģžˆėŠ” ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģœ¼ė”œ ķ‘œģ‹œķ•©ė‹ˆė‹¤.", "JsonSchema.tasks.group.none": "ģž‘ģ—…ģ„ 그룹에 할당 ģ•ˆ 함", "JsonSchema.tasks.group": "ģ“ ģž‘ģ—…ģ„ 할당할 실행 ź·øė£¹ģ„ ģ •ģ˜ķ•©ė‹ˆė‹¤. ė¹Œė“œ 그룹에 추가넼 ģœ„ķ•œ \"build'와 ķ…ŒģŠ¤ķŠø 그룹에 추가넼 ģœ„ķ•œ \"test\"넼 ģ§€ģ›ķ•©ė‹ˆė‹¤.", - "JsonSchema.tasks.type": "ģž‘ģ—…ģ“ ķ”„ė”œģ„øģŠ¤ė”œ ģ‹¤ķ–‰ė˜ėŠ”ģ§€ ė˜ėŠ” ģ…ø ė‚“ģ˜ ėŖ…ė ¹ģœ¼ė”œ ģ‹¤ķ–‰ė˜ėŠ”ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤. źø°ė³øź°’ģ€ ķ”„ė”œģ„øģŠ¤ģž…ė‹ˆė‹¤.", "JsonSchema.version": "źµ¬ģ„±ģ˜ 버전 ė²ˆķ˜øģž…ė‹ˆė‹¤.", "JsonSchema.tasks.identifier": "ģž‘ģ—…ģ„ launch.json ė˜ėŠ” dependsOn źµ¬ė¬øģ—ģ„œ ģ°øģ”°ķ•  ģ‚¬ģš©ģž ģ •ģ˜ ģ‹ė³„ģžģž…ė‹ˆė‹¤.", "JsonSchema.tasks.taskLabel": "ģž‘ģ—… ė ˆģ“ėø”", @@ -35,8 +37,10 @@ "JsonSchema.tasks.customize.deprecated": "ģ‚¬ģš©ģž 지정 ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. 새딜욓 ģž‘ģ—… ģ‚¬ģš©ģž 지정 ė°©ģ‹ģœ¼ė”œ ė§ˆģ“ź·øė ˆģ“ģ…˜ģ„ ģœ„ķ•“ 1.14 릓리스 ė…øķŠøė„¼ ģ°øź³ ķ•˜ģ„øģš”.", "JsonSchema.tasks.showOputput.deprecated": "showOutput ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ėŒ€ģ‹  presentation ģ†ģ„± ė‚“ reveal ģ†ģ„±ģ„ ģ‚¬ģš©ķ•˜ģ„øģš”. 1.14 릓리스 ė…øķŠøė„ ģ°øź³ ķ•˜ģ„øģš”.", "JsonSchema.tasks.echoCommand.deprecated": "echoCommand ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ėŒ€ģ‹  presentation ģ†ģ„± ė‚“ echo ģ†ģ„±ģ„ ģ‚¬ģš©ķ•˜ģ„øģš”. 1.14 릓리스 ė…øķŠøė„ ģ°øź³ ķ•˜ģ„øģš”.", + "JsonSchema.tasks.suppressTaskName.deprecated": "suppressTaskName ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ėŒ€ģ‹  ėŖ…ė ¹ģ„ ģøģˆ˜ģ™€ ķ•Øź»˜ ģž‘ģ—…ģ— ģøė¼ģøģœ¼ė”œ ģ‚½ģž…ķ•˜ģ„øģš”. 1.14 릓리스 ė…øķŠøė„¼ ģ°øź³ ķ•˜ģ„øģš”.", "JsonSchema.tasks.isBuildCommand.deprecated": "isBuildCommand ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ėŒ€ģ‹  group ģ†ģ„±ģ„ ģ‚¬ģš©ķ•˜ģ„øģš”. 1.14 릓리스 ė…øķŠøė„ ģ°øź³ ķ•˜ģ„øģš”.", "JsonSchema.tasks.isTestCommand.deprecated": "isTestCommand ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ėŒ€ģ‹  group ģ†ģ„±ģ„ ģ‚¬ģš©ķ•˜ģ„øģš”. 1.14 릓리스 ė…øķŠøė„¼ ģ°øź³ ķ•˜ģ„øģš”.", + "JsonSchema.tasks.taskSelector.deprecated": "taskSelector ģ†ģ„±ģ€ ģ‚¬ģš©ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ėŒ€ģ‹  ėŖ…ė ¹ģ„ ģøģˆ˜ģ™€ ķ•Øź»˜ ģž‘ģ—…ģ— ģøė¼ģøģœ¼ė”œ ģ‚½ģž…ķ•˜ģ„øģš”. 1.14 릓리스 ė…øķŠøė„¼ ģ°øź³ ķ•˜ģ„øģš”.", "JsonSchema.windows": "Windows ķŠ¹ģ • ėŖ…ė ¹ 구성", "JsonSchema.mac": "Mac ķŠ¹ģ • ėŖ…ė ¹ 구성", "JsonSchema.linux": "Linux ķŠ¹ģ • ėŖ…ė ¹ 구성" diff --git a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 66187c94e82..f423d7950f1 100644 --- a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,30 +5,33 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "ģž‘ģ—…", - "ConfigureTaskRunnerAction.noWorkspace": "ģž‘ģ—…ģ€ ģž‘ģ—… ģ˜ģ—­ ķ“ė”ģ—ģ„œė§Œ ģ‚¬ģš©ķ•  수 ģžˆģŠµė‹ˆė‹¤.", - "ConfigureTaskRunnerAction.quickPick.template": "Task Runner ģ„ ķƒ", - "ConfigureTaskRunnerAction.autoDetecting": "{0} ģž‘ģ—…ģ„ ģžė™ ź²€ģƒ‰ 중", - "ConfigureTaskRunnerAction.autoDetect": "ģž‘ģ—… ģ‹œģŠ¤ķ…œģ„ ģžė™ģœ¼ė”œ ź°ģ§€ķ•˜ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤. źø°ė³ø ķ…œķ”Œė¦æģ„ ģ‚¬ģš©ķ•˜ėŠ” ģ¤‘ģž…ė‹ˆė‹¤. ģžģ„øķ•œ ė‚“ģš©ģ€ ģž‘ģ—… ģ¶œė „ģ„ ģ°øģ”°ķ•˜ģ„øģš”.", - "ConfigureTaskRunnerAction.autoDetectError": "ģž‘ģ—… ģ‹œģŠ¤ķ…œģ„ ģžė™ģœ¼ė”œ ź°ģ§€ķ•˜ėŠ” 중 ģ˜¤ė„˜ź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤. ģžģ„øķ•œ ė‚“ģš©ģ€ ģž‘ģ—… ģ¶œė „ģ„ ģ°øģ”°ķ•˜ģ„øģš”.", - "ConfigureTaskRunnerAction.failed": "'.vscode' ķ“ė” 낓에 'tasks.json' ķŒŒģ¼ģ„ ė§Œė“¤ 수 ģ—†ģŠµė‹ˆė‹¤. ģžģ„øķ•œ ė‚“ģš©ģ€ ģž‘ģ—… ģ¶œė „ģ„ ģ°øģ”°ķ•˜ģ„øģš”.", - "ConfigureTaskRunnerAction.label": "Task Runner 구성", + "ConfigureTaskRunnerAction.label": "ģž‘ģ—… 구성", "ConfigureBuildTaskAction.label": "ė¹Œė“œ ģž‘ģ—… 구성", "CloseMessageAction.label": "ė‹«źø°", "ShowTerminalAction.label": "터미널 볓기", "problems": "문제", "manyMarkers": "99+", + "runningTasks": "실행 ģ¤‘ģø ģž‘ģ—… ķ‘œģ‹œ", "tasks": "ģž‘ģ—…", - "TaskSystem.noHotSwap": "ģž‘ģ—… 실행 ģ—”ģ§„ģ„ ė³€ź²½ķ•˜ė ¤ė©“ VS Code넼 ė‹¤ģ‹œ ģ‹œģž‘ķ•“ģ•¼ ķ•©ė‹ˆė‹¤. ė³€ź²½ģ“ ė¬“ģ‹œė©ė‹ˆė‹¤.", + "TaskSystem.noHotSwap": "실행 ģ¤‘ģø ķ™œģ„± ģž‘ģ—…ģ“ ģžˆėŠ” ģž‘ģ—… 실행 ģ—”ģ§„ģ„ ė³€ź²½ķ•˜ė©“ Window넼 ė‹¤ģ‹œ ė”œė“œķ•“ģ•¼ ķ•©ė‹ˆė‹¤.", "TaskService.noBuildTask1": "ģ •ģ˜ėœ ė¹Œė“œ ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤. tasks.json ķŒŒģ¼ģ—ģ„œ ģž‘ģ—…ģ„ 'isBuildCommand'딜 ķ‘œģ‹œķ•˜ģ„øģš”.", "TaskService.noBuildTask2": "ģ •ģ˜ėœ ė¹Œė“œ ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤. tasks.json ķŒŒģ¼ģ—ģ„œ ģž‘ģ—…ģ„ 'build'딜 ķ‘œģ‹œķ•˜ģ„øģš”.", "TaskService.noTestTask1": "ģ •ģ˜ėœ ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤. tasks.json ķŒŒģ¼ģ—ģ„œ ģž‘ģ—…ģ„ 'isTestCommand'딜 ķ‘œģ‹œķ•˜ģ„øģš”.", "TaskService.noTestTask2": "ģ •ģ˜ėœ ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤. tasks.json ķŒŒģ¼ģ—ģ„œ ģž‘ģ—…ģ„ 'test'딜 ķ‘œģ‹œķ•˜ģ„øģš”.", "TaskServer.noTask": "ģ‹¤ķ–‰ķ•˜ė„ė” ģš”ģ²­ķ•œ ģž‘ģ—… {0}ģ„(넼) ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤.", + "TaskService.associate": "ģ—°ź²°", + "TaskService.attachProblemMatcher.continueWithout": "ģž‘ģ—… ģ¶œė „ģ„ ģŠ¤ģŗ”ķ•˜ģ§€ ģ•Šź³  ź³„ģ†", + "TaskService.attachProblemMatcher.never": "ģž‘ģ—… 출렄 ģŠ¤ģŗ” ģ•ˆ 함", + "TaskService.attachProblemMatcher.learnMoreAbout": "ģž‘ģ—… 출렄 ģŠ¤ģŗ”ģ— ėŒ€ķ•“ ģžģ„øķžˆ ģ•Œģ•„ė³“źø°", + "selectProblemMatcher": "ģž‘ģ—… ģ¶œė „ģ—ģ„œ ģŠ¤ģŗ”ķ•  오넘 ė° 경고 ģœ ķ˜•ģ„ ģ„ ķƒ", "customizeParseErrors": "ķ˜„ģž¬ ģž‘ģ„± 구성에 ģ˜¤ė„˜ź°€ ģžˆģŠµė‹ˆė‹¤. ģž‘ģ—…ģ„ ģ‚¬ģš©ģž ģ§€ģ •ķ•˜źø° 전에 오넘넼 ģˆ˜ģ •ķ•˜ģ„øģš”.\n", "moreThanOneBuildTask": "tasks.json에 ģ—¬ėŸ¬ ė¹Œė“œ ģž‘ģ—…ģ“ ģ •ģ˜ė˜ģ–“ ģžˆģŠµė‹ˆė‹¤. 첫 번째 ģž‘ģ—…ģ„ ģ‹¤ķ–‰ķ•©ė‹ˆė‹¤.\n", + "TaskSystem.activeSame.background": "'{0}' ģž‘ģ—…ģ“ ģ“ėÆø ķ™œģ„± 상태딜 ė°±ź·øė¼ģš“ė“œ ėŖØė“œģ— ģžˆģŠµė‹ˆė‹¤. ģ¢…ė£Œķ•˜ė ¤ė©“ ģž‘ģ—… ė©”ė‰“ģ—ģ„œ 'ģž‘ģ—… ģ¢…ė£Œ'넼 ģ‚¬ģš©ķ•˜ģ„øģš”.", + "TaskSystem.activeSame.noBackground": "'{0}' ģž‘ģ—…ģ“ ģ“ėÆø ķ™œģ„± ģƒķƒœģž…ė‹ˆė‹¤. ģž‘ģ—…ģ„ ģ¢…ė£Œķ•˜ė ¤ė©“ ģž‘ģ—… ė©”ė‰“ģ—ģ„œ 'ģž‘ģ—… ģ¢…ė£Œ'넼 ģ‚¬ģš©ķ•˜ģ„øģš”.", "TaskSystem.active": "ģ“ėÆø 실행 ģ¤‘ģø ģž‘ģ—…ģ“ ģžˆģŠµė‹ˆė‹¤. 다넸 ģž‘ģ—…ģ„ ģ‹¤ķ–‰ķ•˜ė ¤ė©“ 먼저 ģ“ ģž‘ģ—…ģ„ ģ¢…ė£Œķ•˜ģ„øģš”.", "TaskSystem.restartFailed": "{0} ģž‘ģ—…ģ„ ģ¢…ė£Œķ•˜ź³  ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤.", "TaskSystem.configurationErrors": "오넘: ģ œź³µķ•œ ģž‘ģ—… 구성에 ģœ ķšØģ„± 검사 ģ˜¤ė„˜ź°€ ģžˆģœ¼ė©° ģ‚¬ģš©ķ•  수 ģ—†ģŠµė‹ˆė‹¤. 먼저 오넘넼 ģˆ˜ģ •ķ•˜ģ„øģš”.", + "taskService.ignoreingFolder": "ģž‘ģ—… ģ˜ģ—­ ķ“ė” {0}에 ėŒ€ķ•œ ģž‘ģ—… źµ¬ģ„±ģ„ ė¬“ģ‹œķ•©ė‹ˆė‹¤. ģ—¬ėŸ¬ ķ“ė” ģž‘ģ—… ģ˜ģ—­ ģž‘ģ—… ģ§€ģ›ģ€ ėŖØė“  ķ“ė”ź°€ ģž‘ģ—… 버전 2.0.0ģ„ ģ‚¬ģš©ķ•“ģ•¼ ķ•©ė‹ˆė‹¤.\n", "TaskSystem.invalidTaskJson": "오넘: tasks.json ķŒŒģ¼ģ˜ ė‚“ģš©ģ— 구문 ģ˜¤ė„˜ź°€ ģžˆģŠµė‹ˆė‹¤. ģž‘ģ—…ģ„ ģ‹¤ķ–‰ķ•˜źø° 전에 오넘넼 ģ •ģ •ķ•˜ģ„øģš”.\n", "TaskSystem.runningTask": "실행 ģ¤‘ģø ģž‘ģ—…ģ“ ģžˆģŠµė‹ˆė‹¤. ģ“ ģž‘ģ—…ģ„ ģ¢…ė£Œķ• ź¹Œģš”?", "TaskSystem.terminateTask": "ģž‘ģ—… ģ¢…ė£Œ(&&T)", @@ -40,25 +43,37 @@ "recentlyUsed": "ģµœź·¼ģ— ģ‚¬ģš©ķ•œ ģž‘ģ—…", "configured": "źµ¬ģ„±ėœ ģž‘ģ—…", "detected": "ź°ģ§€ėœ ģž‘ģ—…", + "TaskService.ignoredFolder": "ģž‘ģ—… 버전 0.1.0ģ„ ģ‚¬ģš©ķ•˜źø° ė•Œė¬øģ— ė‹¤ģŒ ģž‘ģ—… ģ˜ģ—­ ķ“ė”ėŠ” ė¬“ģ‹œė©ė‹ˆė‹¤.", + "TaskService.notAgain": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", + "TaskService.ok": "ķ™•ģø", + "TaskService.pickRunTask": "실행할 ģž‘ģ—… ģ„ ķƒ", + "TaslService.noEntryToRun": "실행할 ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤. ģž‘ģ—… 구성...", "TaskService.fetchingBuildTasks": "ė¹Œė“œ ģž‘ģ—…ģ„ ķŽ˜ģ¹˜ķ•˜ėŠ” 중...", - "TaskService.noBuildTaskTerminal": "ė¹Œė“œ ģž‘ģ—…ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤. 'ė¹Œė“œ ģž‘ģ—… 구성'ģ„ ėˆŒėŸ¬ģ„œ ė¹Œė“œ ģž‘ģ—…ģ„ ģ •ģ˜ķ•˜ģ„øģš”.", "TaskService.pickBuildTask": "실행할 ė¹Œė“œ ģž‘ģ—… ģ„ ķƒ", + "TaskService.noBuildTask": "실행할 ė¹Œė“œ ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤. ģž‘ģ—… 구성...", "TaskService.fetchingTestTasks": "ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģ„ ķŽ˜ģ¹˜ķ•˜ėŠ” 중...", - "TaskService.noTestTaskTerminal": "ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤. 'Task Runner 구성'ģ„ ėˆŒėŸ¬ģ„œ ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģ„ ģ •ģ˜ķ•˜ģ„øģš”.", "TaskService.pickTestTask": "실행할 ķ…ŒģŠ¤ķŠø ģž‘ģ—… ģ„ ķƒ", - "TaskService.noTaskRunning": "ķ˜„ģž¬ 실행 ģ¤‘ģø ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤.", + "TaskService.noTestTaskTerminal": "실행할 ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤. ģž‘ģ—… 구성...", "TaskService.tastToTerminate": "ģ¢…ė£Œķ•  ģž‘ģ—… ģ„ ķƒ", + "TaskService.noTaskRunning": "ķ˜„ģž¬ 실행 ģ¤‘ģø ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤.", "TerminateAction.noProcess": "ģ‹œģž‘ėœ ķ”„ė”œģ„øģŠ¤ź°€ ė” ģ“ģƒ ģ”“ģž¬ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ģž‘ģ—…ģ—ģ„œ ģƒģ„±ėœ, VS Code넼 ėė‚“ėŠ” ė°±ź·øė¼ģš“ė“œ ģž‘ģ—…ģ“ ė¶„ė¦¬ėœ ķ”„ė”œģ„øģŠ¤ź°€ 될 수 ģžˆģŠµė‹ˆė‹¤.", "TerminateAction.failed": "실행 ģ¤‘ģø ģž‘ģ—…ģ„ ģ¢…ė£Œķ•˜ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤.", - "TaskService.noTaskToRestart": "ė‹¤ģ‹œ ģ‹œģž‘ķ•  ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤.", "TaskService.tastToRestart": "ė‹¤ģ‹œ ģ‹œģž‘ķ•  ģž‘ģ—… ģ„ ķƒ", + "TaskService.noTaskToRestart": "ė‹¤ģ‹œ ģ‹œģž‘ķ•  ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤.", + "TaskService.template": "ģž‘ģ—… ķ…œķ”Œė¦æ ģ„ ķƒ", + "TaskService.createJsonFile": "ķ…œķ”Œė¦æģ—ģ„œ tasks.jsonĀ ķŒŒģ¼ ė§Œė“¤źø°", + "TaskService.openJsonFile": "tasks.json ķŒŒģ¼ ģ—“źø°", + "TaskService.pickTask": "구성할 ģž‘ģ—… ģ„ ķƒ", "TaskService.defaultBuildTaskExists": "{0}ģ€(ėŠ”) ģ“ėÆø źø°ė³ø ė¹Œė“œ ģž‘ģ—…ģœ¼ė”œ ķ‘œģ‹œė˜ģ–“ ģžˆģŠµė‹ˆė‹¤.", "TaskService.pickDefaultBuildTask": "źø°ė³ø ė¹Œė“œ ģž‘ģ—…ģœ¼ė”œ ģ‚¬ģš©ķ•  ģž‘ģ—…ģ„ ģ„ ķƒ", "TaskService.defaultTestTaskExists": "{0}ģ€(ėŠ”) ģ“ėÆø źø°ė³ø ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģœ¼ė”œ ķ‘œģ‹œė˜ģ–“ ģžˆģŠµė‹ˆė‹¤.", "TaskService.pickDefaultTestTask": "źø°ė³ø ķ…ŒģŠ¤ķŠø ģž‘ģ—…ģœ¼ė”œ ģ‚¬ģš©ķ•  ģž‘ģ—… ģ„ ķƒ", + "TaskService.pickShowTask": "ģ¶œė „ģ„ ķ‘œģ‹œķ•  ģž‘ģ—… ģ„ ķƒ", + "TaskService.noTaskIsRunning": "실행 ģ¤‘ģø ģž‘ģ—…ģ“ ģ—†ģŠµė‹ˆė‹¤.", "ShowLogAction.label": "ģž‘ģ—… 딜그 ķ‘œģ‹œ", "RunTaskAction.label": "ģž‘ģ—… 실행", "RestartTaskAction.label": "실행 ģ¤‘ģø ģž‘ģ—… ė‹¤ģ‹œ ģ‹œģž‘", + "ShowTasksAction.label": "실행 ģ¤‘ģø ģž‘ģ—… ķ‘œģ‹œ", "BuildAction.label": "ė¹Œė“œ ģž‘ģ—… 실행", "TestAction.label": "ķ…ŒģŠ¤ķŠø ģž‘ģ—… 실행", "ConfigureDefaultBuildTask.label": "źø°ė³ø ė¹Œė“œ ģž‘ģ—… 구성", diff --git a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 4c053b9817c..b052f09dc9e 100644 --- a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "ģž‘ģ—…ģ„ ģ‹¤ķ–‰ķ•˜ėŠ” ė™ģ•ˆ ģ•Œ 수 ģ—†ėŠ” ģ˜¤ė„˜ź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤. ģžģ„øķ•œ ė‚“ģš©ģ€ ģž‘ģ—… 출렄 딜그넼 ģ°øģ”°ķ•˜ģ„øģš”.", + "dependencyFailed": "ģž‘ģ—… ģ˜ģ—­ ķ“ė” '{1}'ģ—ģ„œ ģ¢…ģ† ģž‘ģ—… '{0}'ģ„(넼) ķ™•ģøķ•  수 ģ—†ģŠµė‹ˆė‹¤. ", "TerminalTaskSystem.terminalName": "ģž‘ģ—… - {0}", "reuseTerminal": "ķ„°ėÆøė„ģ“ ģž‘ģ—…ģ—ģ„œ ė‹¤ģ‹œ ģ‚¬ģš©ė©ė‹ˆė‹¤. ė‹«ģœ¼ė ¤ė©“ 아묓 ķ‚¤ė‚˜ ėˆ„ė„“ģ„øģš”.", "TerminalTaskSystem": "UNC ė“œė¼ģ“ėøŒģ—ģ„œ ģ…ø ėŖ…ė ¹ģ„ 실행할 수 ģ—†ģŠµė‹ˆė‹¤.", diff --git a/i18n/kor/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/kor/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index 840298c5adb..d676ae23acb 100644 --- a/i18n/kor/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,9 +11,12 @@ "ConfigurationParser.unknownMatcherKind": "경고: ģ •ģ˜ėœ 문제 ģ„ ķƒźø°ė„¼ ģ•Œ 수 ģ—†ģŠµė‹ˆė‹¤. ģ§€ģ›ė˜ėŠ” ķ˜•ģ‹ģ€ string | ProblemMatcher |(string | ProblemMatcher)[]ģž…ė‹ˆė‹¤.\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "오넘: ģž˜ėŖ»ėœ problemMatcher ģ°øģ”°: {0}\n", "ConfigurationParser.noTaskType": "오넘: ģž‘ģ—… źµ¬ģ„±ģ€ ģœ ķ˜• ģ†ģ„±ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤. ģ“ źµ¬ģ„±ģ€ ė¬“ģ‹œė©ė‹ˆė‹¤.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "오넘: ė“±ė”ėœ ģž‘ģ—… ķ˜•ģ‹ '{0}'ģ“(ź°€) ģ—†ģŠµė‹ˆė‹¤. ķ•“ė‹¹ķ•˜ėŠ” ģž‘ģ—… ź³µźø‰ģžė„¼ ģ œź³µķ•˜ėŠ” ķ™•ģž„ģ„ ģ„¤ģ¹˜ķ•˜ģ§€ ģ•Šģœ¼ģ…ØģŠµė‹ˆź¹Œ?", + "ConfigurationParser.missingRequiredProperty": "오넘: ģž‘ģ—… 구성 '{0}'에 ķ•„ģš”ķ•œ ģ†ģ„± '{1}'ģ“(ź°€) ģ—†ģŠµė‹ˆė‹¤. ģž‘ģ—… źµ¬ģ„±ģ“ ė¬“ģ‹œė©ė‹ˆė‹¤.", "ConfigurationParser.notCustom": "오넘: ģž‘ģ—…ģ“ ģ‚¬ģš©ģž 지정 ģž‘ģ—…ģœ¼ė”œ ģ„ ģ–øė˜ģ§€ ģ•Šģ•˜ģŠµė‹ˆė‹¤. ģ“ źµ¬ģ„±ģ€ ė¬“ģ‹œė©ė‹ˆė‹¤.\n{0}\n", "ConfigurationParser.noTaskName": "오넘: ģž‘ģ—…ģ—ģ„œ taskName ģ†ģ„±ģ„ ģ œź³µķ•“ģ•¼ ķ•©ė‹ˆė‹¤. ģ“ ģž‘ģ—…ģ€ ė¬“ģ‹œė©ė‹ˆė‹¤.\n{0}\n", "taskConfiguration.shellArgs": "경고: ģž‘ģ—… '{0}'ģ€(ėŠ”) ģ…ø ėŖ…ė ¹ģ“ė©°, ėŖ…ė ¹ ģ“ė¦„ģ“ė‚˜ ģøģˆ˜ 중 ķ•˜ė‚˜ģ— ģ“ģŠ¤ģ¼€ģ“ķ”„ė˜ģ§€ ģ•Šģ€ ź³µė°±ģ“ ģžˆģŠµė‹ˆė‹¤. 명령줄 ģøģš©ģ„ ģ˜¬ė°”ė„“ź²Œ ķ•˜ė ¤ė©“ ģøģˆ˜ė„¼ ėŖ…ė ¹ģœ¼ė”œ ė³‘ķ•©ķ•˜ģ„øģš”.", "taskConfiguration.noCommandOrDependsOn": "오넘: ģž‘ģ—… '{0}'ģ—ģ„œ ėŖ…ė ¹ģ“ė‚˜ dependsOn ģ†ģ„±ģ„ ģ§€ģ •ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ģ“ ģž‘ģ—…ģ€ ė¬“ģ‹œė©ė‹ˆė‹¤. 핓당 ģž‘ģ—…ģ˜ ģ •ģ˜ėŠ” {1}ģž…ė‹ˆė‹¤.", - "taskConfiguration.noCommand": "오넘: ģž‘ģ—… '{0}'ģ—ģ„œ ėŖ…ė ¹ģ„ ģ •ģ˜ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ģ“ ģž‘ģ—…ģ€ ė¬“ģ‹œė©ė‹ˆė‹¤. 핓당 ģž‘ģ—…ģ˜ ģ •ģ˜ėŠ”\n{1}ģž…ė‹ˆė‹¤." + "taskConfiguration.noCommand": "오넘: ģž‘ģ—… '{0}'ģ—ģ„œ ėŖ…ė ¹ģ„ ģ •ģ˜ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ģ“ ģž‘ģ—…ģ€ ė¬“ģ‹œė©ė‹ˆė‹¤. 핓당 ģž‘ģ—…ģ˜ ģ •ģ˜ėŠ”\n{1}ģž…ė‹ˆė‹¤.", + "TaskParse.noOsSpecificGlobalTasks": "ģž‘ģ—… 버전 2.0.0ģ€ źø€ė”œė²Œ OS별 ģž‘ģ—…ģ„ ģ§€ģ›ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. OS별 ėŖ…ė ¹ģ„ ģ‚¬ģš©ķ•˜ģ—¬ ģž‘ģ—…ģœ¼ė”œ ė³€ķ™˜ķ•˜ģ„øģš”. ģ˜ķ–„ģ„ ė°›ėŠ” ģž‘ģ—…::\n{0}" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 8b6ad71cd4e..0c1970cb3cf 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "termEntryAriaLabel": "{0}, 터미널 ģ„ ķƒźø°", + "termCreateEntryAriaLabel": "{0}, 새 터미널 ė§Œė“¤źø°", + "'workbench.action.terminal.newplus": "$(plus) 새 통합 터미널 ė§Œė“¤źø°", + "noTerminalsMatching": "ģ¼ģ¹˜ķ•˜ėŠ” 터미널 ģ—†ģŒ", + "noTerminalsFound": "엓린 터미널 ģ—†ģŒ" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index cd78dbfc40f..3a48f647ff2 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -4,18 +4,19 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "quickOpen.terminal": "ėŖØė“  ģ—“ė ¤ ģžˆėŠ” 터미널 ķ‘œģ‹œ", + "terminal": "터미널", "terminalIntegratedConfigurationTitle": "통합 터미널", "terminal.integrated.shell.linux": "ķ„°ėÆøė„ģ“ Linuxģ—ģ„œ ģ‚¬ģš©ķ•˜ėŠ” ģ…øģ˜ ź²½ė”œģž…ė‹ˆė‹¤.", "terminal.integrated.shellArgs.linux": "Linux 터미널에 ģžˆģ„ ė•Œ ģ‚¬ģš©ķ•  명령줄 ģøģˆ˜ģž…ė‹ˆė‹¤.", "terminal.integrated.shell.osx": "ķ„°ėÆøė„ģ“ OS Xģ—ģ„œ ģ‚¬ģš©ķ•˜ėŠ” ģ…øģ˜ ź²½ė”œģž…ė‹ˆė‹¤.", "terminal.integrated.shellArgs.osx": "OS X 터미널에 ģžˆģ„ ė•Œ ģ‚¬ģš©ķ•  명령줄 ģøģˆ˜ģž…ė‹ˆė‹¤.", + "terminal.integrated.shell.windows": "ķ„°ėÆøė„ģ“ Windowsģ—ģ„œ ģ‚¬ģš©ķ•˜ėŠ” ģ…øģ˜ ź²½ė”œģž…ė‹ˆė‹¤. Windows와 ķ•Øź»˜ ģ œź³µė˜ėŠ” ģ…øģ„ ģ‚¬ģš©ķ•˜ėŠ” 경우(cmd, PowerShell ė˜ėŠ” Ubuntuģ˜ Bash)", "terminal.integrated.shellArgs.windows": "Windows 터미널에 ģžˆģ„ ė•Œ ģ‚¬ģš©ķ•  명령줄 ģøģˆ˜ģž…ė‹ˆė‹¤.", "terminal.integrated.rightClickCopyPaste": "ģ„¤ģ •ķ•˜ėŠ” 경우 터미널 ė‚“ģ—ģ„œ 마우스 오넸쪽 단추넼 큓릭할 ė•Œ ģƒķ™©ģ— ė§žėŠ” 메뉓가 ķ‘œģ‹œė˜ģ§€ ģ•Šź³  ėŒ€ģ‹  ģ„ ķƒ ķ•­ėŖ©ģ“ ģžˆģœ¼ė©“ ė³µģ‚¬ķ•˜ź³  ģ„ ķƒ ķ•­ėŖ©ģ“ ģ—†ģœ¼ė©“ ė¶™ģ—¬ė„£ģŠµė‹ˆė‹¤.", "terminal.integrated.fontFamily": "ķ„°ėÆøė„ģ˜ 글꼓 ķŒØė°€ė¦¬ė„¼ ģ œģ–“ķ•˜ė©°, źø°ė³øź°’ģ€ editor.fontFamilyģ˜ ź°’ģž…ė‹ˆė‹¤.", - "terminal.integrated.fontLigatures": "ķ„°ėÆøė„ģ—ģ„œ 글꼓 ķ•©ģžź°€ ģ‚¬ģš©ė˜ėŠ”ģ§€ė„¼ ģ œģ–“ķ•©ė‹ˆė‹¤.", "terminal.integrated.fontSize": "ķ„°ėÆøė„ģ˜ 글꼓 크기(픽셀)넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "terminal.integrated.lineHeight": "ķ„°ėÆøė„ģ˜ 줄 ė†’ģ“ė„¼ ģ œģ–“ķ•˜ė©°, ģ“ ģˆ«ģžėŠ” 터미널 글꼓 크기넼 ź³±ķ•˜ģ—¬ ģ‹¤ģ œ 줄 ė†’ģ“(픽셀)넼 ģ–»ģŠµė‹ˆė‹¤.", - "terminal.integrated.enableBold": "터미널 ė‚“ģ—ģ„œ źµµģ€ ķ…ģŠ¤ķŠøė„¼ ģ‚¬ģš©ķ•˜ė„ė” 설정할지 ģ—¬ė¶€ģ“ė©°, 터미널 ģ…øģ˜ ģ§€ģ›ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤.", "terminal.integrated.cursorBlinking": "터미널 ģ»¤ģ„œ ź¹œė°•ģž„ 여부넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", "terminal.integrated.cursorStyle": "터미널 ģ»¤ģ„œģ˜ ģŠ¤ķƒ€ģ¼ģ„ ģ œģ–“ķ•©ė‹ˆė‹¤.", "terminal.integrated.scrollback": "ķ„°ėÆøė„ģ—ģ„œ ė²„ķ¼ģ— ģœ ģ§€ķ•˜ėŠ” ģµœėŒ€ 줄 수넼 ģ œģ–“ķ•©ė‹ˆė‹¤.", @@ -23,7 +24,9 @@ "terminal.integrated.cwd": "ķ„°ėÆøė„ģ“ ģ‹œģž‘ė  ėŖ…ģ‹œģ  ģ‹œģž‘ ź²½ė”œģž…ė‹ˆė‹¤. ģ…ø ķ”„ė”œģ„øģŠ¤ģ˜ ķ˜„ģž¬ ģž‘ģ—… 디렉터리(cwd)딜 ģ‚¬ģš©ė©ė‹ˆė‹¤. 루트 디렉터리가 ķŽøė¦¬ķ•œ cwdź°€ ģ•„ė‹Œ 경우 ģž‘ģ—… ģ˜ģ—­ ģ„¤ģ •ģ—ģ„œ ķŠ¹ķžˆ ģœ ģš©ķ•˜ź²Œ ģ‚¬ģš©ķ•  수 ģžˆģŠµė‹ˆė‹¤.", "terminal.integrated.confirmOnExit": "ėė‚¼ ė•Œ ķ™œģ„± 터미널 ģ„øģ…˜ģ“ ģžˆėŠ”ģ§€ ķ™•ģøķ• ģ§€ ģ—¬ė¶€ģž…ė‹ˆė‹¤.", "terminal.integrated.commandsToSkipShell": "키 ė°”ģøė”©ģ“ 셸에 ģ „ģ†”ė˜ģ§€ ģ•Šź³  ķ•­ģƒ Codeģ—ģ„œ ģ²˜ė¦¬ė˜ėŠ” ėŖ…ė ¹ ID ģ§‘ķ•©ģž…ė‹ˆė‹¤. ė”°ė¼ģ„œ ģ…øģ—ģ„œ ģ •ģƒģ ģœ¼ė”œ ģ‚¬ģš©ė˜ģ–“ 터미널에 ķ¬ģ»¤ģŠ¤ź°€ ģ—†ģ„ ė•Œģ™€ ė™ģ¼ķ•˜ź²Œ ģž‘ė™ķ•˜ėŠ” 키 ė°”ģøė”©ģ„ ģ‚¬ģš©ķ•  수 ģžˆģŠµė‹ˆė‹¤(예: 넼 ģ‚¬ģš©ķ•˜ģ—¬ Quick Open ģ‹œģž‘).", - "terminal": "터미널", + "terminal.integrated.env.osx": "OS Xģ˜ ķ„°ėÆøė„ģ“ ģ‚¬ģš©ķ•˜ėŠ” VS Code ķ”„ė”œģ„øģŠ¤ģ— 추가될 ķ™˜ź²½ ė³€ģˆ˜ė„¼ ķ¬ķ•Øķ•œ 개첓", + "terminal.integrated.env.linux": "Linuxģ˜ ķ„°ėÆøė„ģ—ģ„œ ģ‚¬ģš©ķ•  VS Code ķ”„ė”œģ„øģŠ¤ģ— ģ¶”ź°€ė˜ėŠ” ķ™˜ź²½ ė³€ģˆ˜ė„¼ ķ¬ķ•Øķ•œ 개첓", + "terminal.integrated.env.windows": "Windowsģ˜ ķ„°ėÆøė„ģ—ģ„œ ģ‚¬ģš©ķ•  VS Code ķ”„ė”œģ„øģŠ¤ģ— ģ¶”ź°€ė˜ėŠ” ķ™˜ź²½ ė³€ģˆ˜ė„¼ ķ¬ķ•Øķ•œ 개첓", "terminalCategory": "터미널", "viewCategory": "볓기" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 601a8942d55..9415bbb9140 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "통합 터미널 설정/ķ•“ģ œ", "workbench.action.terminal.kill": "ķ™œģ„± 터미널 ģøģŠ¤ķ„“ģŠ¤ ģ¢…ė£Œ", "workbench.action.terminal.kill.short": "터미널 ģ¢…ė£Œ", + "workbench.action.terminal.quickKill": "터미널 ģøģŠ¤ķ„“ģŠ¤ ģ¢…ė£Œ", "workbench.action.terminal.copySelection": "ģ„ ķƒ ģ˜ģ—­ 복사", "workbench.action.terminal.selectAll": "모두 ģ„ ķƒ", + "workbench.action.terminal.deleteWordLeft": "왼쪽 단얓 ģ‚­ģ œ", + "workbench.action.terminal.deleteWordRight": "오넸쪽 단얓 ģ‚­ģ œ", "workbench.action.terminal.new": "새 통합 터미널 ė§Œė“¤źø°", "workbench.action.terminal.new.short": "새 터미널", "workbench.action.terminal.focus": "터미널에 ķ¬ģ»¤ģŠ¤", "workbench.action.terminal.focusNext": "ė‹¤ģŒ 터미널에 ķ¬ģ»¤ģŠ¤", - "workbench.action.terminal.focusAtIndex": "{0} ķ„°ėÆøė„ė”œ ķ¬ģ»¤ģŠ¤ ģ“ė™", "workbench.action.terminal.focusPrevious": "ģ“ģ „ 터미널에 ķ¬ģ»¤ģŠ¤", "workbench.action.terminal.paste": "ķ™œģ„± 터미널에 붙여넣기", "workbench.action.terminal.DefaultShell": "źø°ė³ø ģ…ø ģ„ ķƒ", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "ģ“ė¦„ 바꾸기", "workbench.action.terminal.rename.prompt": "터미널 ģ“ė¦„ ģž…ė „", "workbench.action.terminal.focusFindWidget": "ķŒŒģøė“œ ģœ„ģ Æ ķ¬ģ»¤ģŠ¤", - "workbench.action.terminal.hideFindWidget": "ķŒŒģøė“œ ģœ„ģ Æ 숨기기" + "workbench.action.terminal.hideFindWidget": "ķŒŒģøė“œ ģœ„ģ Æ 숨기기", + "nextTerminalFindTerm": "ė‹¤ģŒ ź²€ģƒ‰ģ–“ ķ‘œģ‹œ", + "previousTerminalFindTerm": "ģ“ģ „ ź²€ģƒ‰ģ–“ ķ‘œģ‹œ", + "quickOpenTerm": "ķ™œģ„± 터미널 ģ „ķ™˜" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 5923a5bf7d5..32869d50216 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -6,5 +6,8 @@ { "terminal.background": "ķ„°ėÆøė„ģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ģ“ ģ„¤ģ •ģ„ ģ‚¬ģš©ķ•˜ė©“ 터미널\n ģƒ‰ģ„ ķŒØė„ź³¼ ė‹¤ė„“ź²Œ 지정할 수 ģžˆģŠµė‹ˆė‹¤.", "terminal.foreground": "ķ„°ėÆøė„ģ˜ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "terminalCursor.foreground": "터미널 ģ»¤ģ„œģ˜ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "terminalCursor.background": "터미널 ģ»¤ģ„œģ˜ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤. ėø”ė” ģ»¤ģ„œģ™€ 겹친 ė¬øģžģ˜ ģƒ‰ģƒģ„ ģ‚¬ģš©ģž ģ •ģ˜ķ•  수 ģžˆģŠµė‹ˆė‹¤.", + "terminal.selectionBackground": "ķ„°ėÆøė„ģ˜ ģ„ ķƒ ģ˜ģ—­ ė°°ź²½ģƒ‰ģž…ė‹ˆė‹¤.", "terminal.ansiColor": "ķ„°ėÆøė„ģ˜ '{0}' ANSI ģƒ‰ģž…ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 9fe74c319a1..08eba97a0dc 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "복사", - "createNewTerminal": "새 터미널", "paste": "붙여넣기", "selectAll": "모두 ģ„ ķƒ", "clear": "ģ§€ģš°źø°" diff --git a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 81c70b66b79..b21bf5b25fa 100644 --- a/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", "terminal.integrated.chooseWindowsShell": "기본으딜 설정할 터미널 ģ…øģ„ ģ„ ķƒķ•˜ģ„øģš”. ė‚˜ģ¤‘ģ— ģ„¤ģ •ģ—ģ„œ ģ“ ģ…øģ„ 변경할 수 ģžˆģŠµė‹ˆė‹¤.", "terminalService.terminalCloseConfirmationSingular": "ķ™œģ„± 터미널 ģ„øģ…˜ģ“ ģžˆģŠµė‹ˆė‹¤. ģ¢…ė£Œķ• ź¹Œģš”?", - "terminalService.terminalCloseConfirmationPlural": "{0}ź°œģ˜ ķ™œģ„± 터미널 ģ„øģ…˜ģ“ ģžˆģŠµė‹ˆė‹¤. ģ¢…ė£Œķ• ź¹Œģš”?", - "yes": "예" + "terminalService.terminalCloseConfirmationPlural": "{0}ź°œģ˜ ķ™œģ„± 터미널 ģ„øģ…˜ģ“ ģžˆģŠµė‹ˆė‹¤. ģ¢…ė£Œķ• ź¹Œģš”?" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 13239987ba2..bb502a90cb6 100644 --- a/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,9 @@ "licenseChanged": "ģ‚¬ģš© ģ”°ź±“ģ“ ė³€ź²½ė˜ģ—ˆģŠµė‹ˆė‹¤. ģžģ„øķžˆ ģ½ģ–“ė³“ģ„øģš”.", "license": "ė¼ģ“ģ„ ģŠ¤ ģ½źø°", "neveragain": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", + "64bitisavailable": "64ė¹„ķŠø Windows용 {0}ģ„(넼) ģ§€źøˆ ģ‚¬ģš©ķ•  수 ģžˆģŠµė‹ˆė‹¤.", "learn more": "ģžģ„øķ•œ 정볓", + "updateIsReady": "새 {0}Ā ģ—…ė°ģ“ķŠøė„¼ ģ‚¬ģš©ķ•  수 ģžˆģŠµė‹ˆė‹¤.", "thereIsUpdateAvailable": "ģ‚¬ģš© ź°€ėŠ„ķ•œ ģ—…ė°ģ“ķŠøź°€ ģžˆģŠµė‹ˆė‹¤.", "updateAvailable": "ė‹¤ģ‹œ ģ‹œģž‘ķ•˜ė©“ {0}ģ“(ź°€) ģ—…ė°ģ“ķŠøė©ė‹ˆė‹¤.", "noUpdatesAvailable": "ķ˜„ģž¬ ģ‚¬ģš© ź°€ėŠ„ķ•œ ģ—…ė°ģ“ķŠøź°€ ģ—†ģŠµė‹ˆė‹¤.", diff --git a/i18n/kor/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/kor/src/vs/workbench/parts/views/browser/views.i18n.json index 8d20ba83c9a..126ed4fd56c 100644 --- a/i18n/kor/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/views/browser/views.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "viewToolbarAriaLabel": "{0} ė™ģž‘" + "viewToolbarAriaLabel": "{0} ė™ģž‘", + "hideView": "ģ‚¬ģ“ė“œė°”ģ—ģ„œ 숨기기" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json b/i18n/kor/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json index abec4dbe7bc..25892e50a69 100644 --- a/i18n/kor/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json @@ -12,5 +12,6 @@ "vscode.extension.contributes.view.when": "ģ“ 볓기넼 ķ‘œģ‹œķ•˜źø° ģœ„ķ•“ true여야 ķ•˜ėŠ” ģ”°ź±“ģž…ė‹ˆė‹¤.", "vscode.extension.contributes.views": "뷰넼 에디터에 ģ ģš©ķ•©ė‹ˆė‹¤.", "views.explorer": "ķƒģƒ‰źø° ė·°", + "views.debug": "디버그 볓기", "locationId.invalid": "`{0}`ģ€(ėŠ”) ģœ ķšØķ•œ ė·° ģœ„ģ¹˜ź°€ ģ•„ė‹™ė‹ˆė‹¤." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index a7a11fff031..5040b38f74d 100644 --- a/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "ģ‹œģž‘", "welcomePage.newFile": "새 ķŒŒģ¼", "welcomePage.openFolder": "ķ“ė” ģ—“źø°...", - "welcomePage.cloneGitRepository": "Git ė¦¬ķ¬ģ§€ķ† ė¦¬ 복제...", + "welcomePage.addWorkspaceFolder": "ģž‘ģ—… ģ˜ģ—­ ķ“ė” 추가...", "welcomePage.recent": "최근 ķ•­ėŖ©", "welcomePage.moreRecent": "ģžģ„øķžˆ...", "welcomePage.noRecentFolders": "최근 ķ“ė” ģ—†ģŒ", diff --git a/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json index 20c6758ebab..375f27f6483 100644 --- a/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json @@ -8,5 +8,6 @@ "workbench.startupEditor.none": "ķŽøģ§‘źø°ė„¼ ģ‚¬ģš©ķ•˜ģ§€ ģ•Šź³  ģ‹œģž‘ķ•©ė‹ˆė‹¤.", "workbench.startupEditor.welcomePage": "ģ‹œģž‘ ķŽ˜ģ“ģ§€ė„¼ ģ—½ė‹ˆė‹¤(źø°ė³øź°’).", "workbench.startupEditor.newUntitledFile": "ģ œėŖ©ģ“ ģ—†ėŠ” 새 ķŒŒģ¼ ģ—“źø°", + "workbench.startupEditor": "ģ‹œģž‘ķ•  ė•Œ ģ“ģ „ ģ„øģ…˜ģ—ģ„œ ė³µźµ¬ķ•˜ģ§€ ģ•Šģ„ 경우 ģ–“ė–¤ ķŽøģ§‘źø°ź°€ ķ‘œģ‹œė ģ§€ ź²°ģ •ķ•©ė‹ˆė‹¤. 'none'ģ„ ģ„ ķƒķ•˜ė©“ ķŽøģ§‘źø° ģ—†ģ“ ģ‹œģž‘ķ•˜ź³  'welcomePage'넼 ģ„ ķƒķ•˜ė©“ Welcome ķŽ˜ģ“ģ§€(źø°ė³øź°’)ź°€ 엓리며 'newUntitledFile'ģ„ ģ„ ķƒķ•˜ė©“ 제목 ģ—†ėŠ” 새 ķŒŒģ¼ģ“ ģ—“ė¦½ė‹ˆė‹¤(빈 ģž‘ģ—… ģ˜ģ—­ģ„ ģ—“ ė•Œė§Œ).", "help": "ė„ģ›€ė§" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 00f16868240..65a67f13f6c 100644 --- a/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Azure ķ™•ģž„ ķ‘œģ‹œ", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/kor/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/kor/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index a60d1663e00..5965ac61642 100644 --- a/i18n/kor/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "ėŒ€ķ™”ķ˜• ģ‹¤ģŠµ", - "editorWalkThrough.title": "ėŒ€ķ™”ķ˜• ģ‹¤ģŠµ" + "editorWalkThrough.title": "ėŒ€ķ™”ķ˜• ģ‹¤ģŠµ", + "editorWalkThrough": "ėŒ€ķ™”ķ˜• ģ‹¤ģŠµ" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/kor/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..4fdc20a33c2 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "ģ„¤ģ •ģ„ ģš”ģ•½ķ•©ė‹ˆė‹¤. ģ“ ė ˆģ“ėø”ģ€ 설정 ķŒŒģ¼ģ—ģ„œ 구분 ģ£¼ģ„ģœ¼ė”œ ģ‚¬ģš©ė©ė‹ˆė‹¤.", + "vscode.extension.contributes.configuration.properties": "구성 ģ†ģ„±ģ— ėŒ€ķ•œ ģ„¤ėŖ…ģž…ė‹ˆė‹¤.", + "scope.window.description": "[ģ‚¬ģš©ģž] 설정 ė˜ėŠ” [ģž‘ģ—… ģ˜ģ—­] ģ„¤ģ •ģ—ģ„œ 구성할 수 ģžˆėŠ” ģ°½ ķŠ¹ģ • źµ¬ģ„±ģž…ė‹ˆė‹¤.", + "scope.resource.description": "ģ‚¬ģš©ģž, ģž‘ģ—… ģ˜ģ—­ ė˜ėŠ” ķ“ė” ģ„¤ģ •ģ—ģ„œ 구성할 수 ģžˆėŠ” ė¦¬ģ†ŒģŠ¤ ķŠ¹ģ • 구성", + "scope.description": "źµ¬ģ„±ģ“ ģ ģš©ė˜ėŠ” ė²”ģœ„ģž…ė‹ˆė‹¤. ģ‚¬ģš© ź°€ėŠ„ ė²”ģœ„ėŠ” 'ģ°½'ź³¼ 'ė¦¬ģ†ŒģŠ¤'ģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.configuration": "구성 ģ„¤ģ •ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", + "invalid.title": "'configuration.title'ģ€ ė¬øģžģ—“ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "vscode.extension.contributes.defaultConfiguration": "ģ–øģ–“ė³„ė”œ źø°ė³ø ķŽøģ§‘źø° 구성 ģ„¤ģ •ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", + "invalid.properties": "'configuration.properties'ėŠ” ź°œģ²“ģ—¬ģ•¼ ķ•©ė‹ˆė‹¤.", + "invalid.allOf": "'configuration.allOf'ėŠ” ģ‚¬ģš©ė˜ģ§€ ģ•Šģœ¼ė©° ė” ģ“ģƒ ģ‚¬ģš©ķ•“ģ„œėŠ” ģ•ˆė©ė‹ˆė‹¤. ėŒ€ģ‹  ģ—¬ėŸ¬ 구성 ģ„¹ģ…˜ģ„ ė°°ģ—“ė”œ 'configuration' źø°ģ—¬ 지점에 ģ „ė‹¬ķ•˜ģ„øģš”.", + "workspaceConfig.folders.description": "ģž‘ģ—… ģ˜ģ—­ģ— ė”œė“œė˜ėŠ” ķ“ė” ėŖ©ė”ģž…ė‹ˆė‹¤.", + "workspaceConfig.path.description": "ķŒŒģ¼ ź²½ė”œģž…ė‹ˆė‹¤. 예: `/root/folderA` ė˜ėŠ” `./folderA`(ģž‘ģ—… ģ˜ģ—­ ķŒŒģ¼ģ˜ ģœ„ģ¹˜ė„¼ źø°ģ¤€ģœ¼ė”œ ķ™•ģøķ•  ģƒėŒ€ ź²½ė”œģø 경우)", + "workspaceConfig.name.description": "ķ“ė”ģ— ėŒ€ķ•œ ģ„ ķƒģ  ģ“ė¦„ģž…ė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json index bea643cae15..96b95e7ea94 100644 --- a/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,11 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "구성 ģ„¤ģ •ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", "vscode.extension.contributes.configuration.title": "ģ„¤ģ •ģ„ ģš”ģ•½ķ•©ė‹ˆė‹¤. ģ“ ė ˆģ“ėø”ģ€ 설정 ķŒŒģ¼ģ—ģ„œ 구분 ģ£¼ģ„ģœ¼ė”œ ģ‚¬ģš©ė©ė‹ˆė‹¤.", "vscode.extension.contributes.configuration.properties": "구성 ģ†ģ„±ģ— ėŒ€ķ•œ ģ„¤ėŖ…ģž…ė‹ˆė‹¤.", - "invalid.type": "ģ„¤ģ •ėœ 경우 'configuration.type'ģ„ '개첓'딜 설정핓야 ķ•©ė‹ˆė‹¤.", + "scope.window.description": "[ģ‚¬ģš©ģž] 설정 ė˜ėŠ” [ģž‘ģ—… ģ˜ģ—­] ģ„¤ģ •ģ—ģ„œ 구성할 수 ģžˆėŠ” ģ°½ ķŠ¹ģ • źµ¬ģ„±ģž…ė‹ˆė‹¤.", + "scope.resource.description": "ģ‚¬ģš©ģž, ģž‘ģ—… ģ˜ģ—­ ė˜ėŠ” ķ“ė” ģ„¤ģ •ģ—ģ„œ 구성할 수 ģžˆėŠ” ė¦¬ģ†ŒģŠ¤ ķŠ¹ģ • 구성", + "scope.description": "źµ¬ģ„±ģ“ ģ ģš©ė˜ėŠ” ė²”ģœ„ģž…ė‹ˆė‹¤. ģ‚¬ģš© ź°€ėŠ„ ė²”ģœ„ėŠ” 'ģ°½'ź³¼ 'ė¦¬ģ†ŒģŠ¤'ģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.configuration": "구성 ģ„¤ģ •ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", "invalid.title": "'configuration.title'ģ€ ė¬øģžģ—“ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", "vscode.extension.contributes.defaultConfiguration": "ģ–øģ–“ė³„ė”œ źø°ė³ø ķŽøģ§‘źø° 구성 ģ„¤ģ •ģ„ ģ ģš©ķ•©ė‹ˆė‹¤.", - "invalid.properties": "'configuration.properties'ėŠ” ź°œģ²“ģ—¬ģ•¼ ķ•©ė‹ˆė‹¤." + "invalid.properties": "'configuration.properties'ėŠ” ź°œģ²“ģ—¬ģ•¼ ķ•©ė‹ˆė‹¤.", + "invalid.allOf": "'configuration.allOf'ėŠ” ģ‚¬ģš©ė˜ģ§€ ģ•Šģœ¼ė©° ė” ģ“ģƒ ģ‚¬ģš©ķ•“ģ„œėŠ” ģ•ˆė©ė‹ˆė‹¤. ėŒ€ģ‹  ģ—¬ėŸ¬ 구성 ģ„¹ģ…˜ģ„ ė°°ģ—“ė”œ 'configuration' źø°ģ—¬ 지점에 ģ „ė‹¬ķ•˜ģ„øģš”.", + "workspaceConfig.folders.description": "ģž‘ģ—… ģ˜ģ—­ģ— ė”œė“œė˜ėŠ” ķ“ė” ėŖ©ė”ģž…ė‹ˆė‹¤.", + "workspaceConfig.path.description": "ķŒŒģ¼ ź²½ė”œģž…ė‹ˆė‹¤. 예: `/root/folderA` ė˜ėŠ” `./folderA`(ģž‘ģ—… ģ˜ģ—­ ķŒŒģ¼ģ˜ ģœ„ģ¹˜ė„¼ źø°ģ¤€ģœ¼ė”œ ķ™•ģøķ•  ģƒėŒ€ ź²½ė”œģø 경우)", + "workspaceConfig.name.description": "ķ“ė”ģ— ėŒ€ķ•œ ģ„ ķƒģ  ģ“ė¦„ģž…ė‹ˆė‹¤.", + "workspaceConfig.uri.description": "ķ“ė”ģ˜ URI", + "workspaceConfig.settings.description": "ģž‘ģ—… ģ˜ģ—­ 설정", + "workspaceConfig.extensions.description": "ģž‘ģ—… ģ˜ģ—­ ķ™•ģž„", + "unknownWorkspaceProperty": "ģ•Œ 수 ģ—†ėŠ” ģž‘ģ—… ģ˜ģ—­ 구성 ģ†ģ„±" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/kor/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index 77aa3c54a29..8eb022003b1 100644 --- a/i18n/kor/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/kor/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "설정 ģ—“źø°", + "openTasksConfiguration": "ģž‘ģ—… 구성 ģ—“źø°", + "openLaunchConfiguration": "ģ‹œģž‘ 구성 ģ—“źø°", "close": "ė‹«źø°", - "saveAndRetry": "설정 ģ €ģž„ ė° ė‹¤ģ‹œ ģ‹œė„", - "errorInvalidConfiguration": "설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģ‚¬ģš©ģž 설정**ģ„ ģ—“ģ–“ ķŒŒģ¼ģ—ģ„œ 오넘/경고넼 ķ•“ź²°ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", - "errorInvalidConfigurationWorkspace": "설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģž‘ģ—… ģ˜ģ—­ 설정**ģ„ ģ—“ģ–“ ķŒŒģ¼ģ—ģ„œ 오넘/경고넼 ķ•“ź²°ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", - "errorConfigurationFileDirty": "ķŒŒģ¼ģ“ ė³€ź²½ė˜ģ–“ 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģ‚¬ģš©ģž 설정** ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", - "errorConfigurationFileDirtyWorkspace": "ķŒŒģ¼ģ“ ė³€ź²½ė˜ģ–“ 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģž‘ģ—… ģ˜ģ—­ 설정** ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "open": "설정 ģ—“źø°", + "saveAndRetry": "ģ €ģž„ ė° ė‹¤ģ‹œ ģ‹œė„", + "errorUnknownKey": "{1}ģ€(ėŠ”) ė“±ė”ėœ źµ¬ģ„±ģ“ ģ•„ė‹ˆėÆ€ė”œ {0}에 쓸 수 ģ—†ģŠµė‹ˆė‹¤.", + "errorInvalidFolderConfiguration": "{0}ģ“(ź°€) ķ“ė” ė¦¬ģ†ŒģŠ¤ ė²”ģœ„ė„¼ ģ§€ģ›ķ•˜ģ§€ ģ•Šģœ¼ėÆ€ė”œ ķ“ė” 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤.", + "errorInvalidUserTarget": "{0}ģ“(ź°€) źø€ė”œė²Œ ė²”ģœ„ė„¼ ģ§€ģ›ķ•˜ģ§€ ģ•Šģœ¼ėÆ€ė”œ ģ‚¬ģš©ģž 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤.", + "errorInvalidFolderTarget": "ė¦¬ģ†ŒģŠ¤ź°€ ģ œź³µė˜ģ§€ ģ•Šģœ¼ėÆ€ė”œ ķ“ė” 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤.", + "errorNoWorkspaceOpened": "ģž‘ģ—… ģ˜ģ—­ģ“ ģ—“ė ¤ ģžˆģ§€ ģ•Šģœ¼ėÆ€ė”œ {0}에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. 먼저 ģž‘ģ—… ģ˜ģ—­ģ„ ģ—“ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorInvalidTaskConfiguration": "ģž‘ģ—… ķŒŒģ¼ģ— 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģž‘ģ—…**Ā ķŒŒģ¼ģ„ ģ—“ģ–“ 오넘/경고넼 ģˆ˜ģ •ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorInvalidLaunchConfiguration": "실행 ķŒŒģ¼ģ— 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **실행** ķŒŒģ¼ģ„ ģ—“ģ–“ 오넘/경고넼 ģˆ˜ģ •ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorInvalidConfiguration": "ģ‚¬ģš©ģž 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģ‚¬ģš©ģž 설정** ķŒŒģ¼ģ„ ģ—“ģ–“ 오넘/경고넼 ģˆ˜ģ •ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorInvalidConfigurationWorkspace": "ģž‘ģ—… ģ˜ģ—­ 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģž‘ģ—… ģ˜ģ—­ 설정** ķŒŒģ¼ģ„ ģ—“ģ–“ 오넘/경고넼 ģˆ˜ģ •ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorInvalidConfigurationFolder": "ķ“ė” 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **{0}** ķ“ė” ģ•„ėž˜ģ˜ **ķ“ė” 설정** ķŒŒģ¼ģ„ ģ—“ģ–“ 오넘/경고넼 ģˆ˜ģ •ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorTasksConfigurationFileDirty": "ķŒŒģ¼ģ“ ė³€ź²½ė˜ģ–“ ģž‘ģ—… ķŒŒģ¼ģ— 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģž‘ģ—… 구성** ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorLaunchConfigurationFileDirty": "ķŒŒģ¼ģ“ ė³€ź²½ė˜ģ–“ ģ‹œģž‘ ķŒŒģ¼ģ— 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģ‹œģž‘ 구성** ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorConfigurationFileDirty": "ķŒŒģ¼ģ“ ė³€ź²½ė˜ģ–“ ģ‚¬ģš©ģž 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģ‚¬ģš©ģž 설정** ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorConfigurationFileDirtyWorkspace": "ķŒŒģ¼ģ“ ė³€ź²½ė˜ģ–“ ģž‘ģ—… ģ˜ģ—­ģ— 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **ģž‘ģ—… ģ˜ģ—­ 설정** ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorConfigurationFileDirtyFolder": "ķŒŒģ¼ģ“ ė³€ź²½ė˜ģ–“ ķ“ė” 설정에 쓸 수 ģ—†ģŠµė‹ˆė‹¤. **{0}** ķ“ė” ģ•„ėž˜ģ˜ **ķ“ė” 설정** ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", "userTarget": "ģ‚¬ģš©ģž 설정", - "workspaceTarget": "ģž‘ģ—… ģ˜ģ—­ 설정" + "workspaceTarget": "ģž‘ģ—… ģ˜ģ—­ 설정", + "folderTarget": "ķ“ė” 설정" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json b/i18n/kor/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json index 8b6ad71cd4e..72bc3a9126b 100644 --- a/i18n/kor/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json +++ b/i18n/kor/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "errorInvalidFile": "ķŒŒģ¼ģ— 쓸 수 ģ—†ģŠµė‹ˆė‹¤. ķŒŒģ¼ģ„ ģ—“ģ–“ 오넘/경고넼 ģˆ˜ģ •ķ•œ 후 ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", + "errorFileDirty": "ķŒŒģ¼ģ“ ģ˜¤ģ—¼ė˜ģ–“ ķŒŒģ¼ģ— 쓸 수 ģ—†ģŠµė‹ˆė‹¤. ķŒŒģ¼ģ„ ģ €ģž„ķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/kor/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/kor/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..49510b9736a --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "ķ™•ģž„ ķ˜øģŠ¤ķŠøź°€ 10쓈 낓에 ģ‹œģž‘ė˜ģ§€ ģ•Šģ•˜ģŠµė‹ˆė‹¤. 첫 번째 ģ¤„ģ—ģ„œ ģ¤‘ģ§€ė˜ģ—ˆģ„ 수 ģžˆģŠµė‹ˆė‹¤. ź³„ģ†ķ•˜ė ¤ė©“ 디버거가 ķ•„ģš”ķ•©ė‹ˆė‹¤.", + "extensionHostProcess.startupFail": "ķ™•ģž„ ķ˜øģŠ¤ķŠøź°€ 10쓈 ģ“ė‚“ģ— ģ‹œģž‘ė˜ģ§€ ģ•Šģ•˜ģŠµė‹ˆė‹¤. ė¬øģ œź°€ ė°œģƒķ–ˆģ„ 수 ģžˆģŠµė‹ˆė‹¤.", + "extensionHostProcess.error": "ķ™•ģž„ ķ˜øģŠ¤ķŠøģ—ģ„œ 오넘 ė°œģƒ: {0}" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..2105771ead9 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "{0}ģ„(넼) 구문 ė¶„ģ„ķ•˜ģ§€ 못함: {1}.", + "fileReadFail": "ķŒŒģ¼ {0}ģ„(넼) ģ½ģ„ 수 ģ—†ģŒ: {1}.", + "jsonsParseFail": "{0} ė˜ėŠ” {1}ģ„(넼) 구문 ė¶„ģ„ķ•˜ģ§€ ėŖ»ķ–ˆģŠµė‹ˆė‹¤. {2}", + "missingNLSKey": "키 {0}에 ėŒ€ķ•œ ė©”ģ‹œģ§€ė„¼ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..6f9c095c667 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "ź°œė°œģž ė„źµ¬", + "restart": "ķ™•ģž„ 호스트 ė‹¤ģ‹œ ģ‹œģž‘", + "extensionHostProcess.crash": "ķ™•ģž„ ķ˜øģŠ¤ķŠøź°€ 예기치 ģ•Šź²Œ ģ¢…ė£Œė˜ģ—ˆģŠµė‹ˆė‹¤.", + "extensionHostProcess.unresponsiveCrash": "ķ™•ģž„ ķ˜øģŠ¤ķŠøź°€ ģ‘ė‹µķ•˜ģ§€ ģ•Šģ•„ģ„œ ģ¢…ė£Œė˜ģ—ˆģŠµė‹ˆė‹¤.", + "overwritingExtension": "ķ™•ģž„ {0}ģ„(넼) {1}(으)딜 ė®ģ–“ģ“°ėŠ” ģ¤‘ģž…ė‹ˆė‹¤.", + "extensionUnderDevelopment": "{0}ģ—ģ„œ 개발 ķ™•ģž„ ė”œė“œ 중" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/kor/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..d48fe3d053e --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "ķŒŒģ¼ģ“ ģ“ģ§„ģø 것 ź°™ģœ¼ėÆ€ė”œ ķ…ŒģŠ¤ķŠøė”œ ģ—“ 수 ģ—†ģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/kor/src/vs/workbench/services/files/node/fileService.i18n.json index 88223fce427..28c96c9fb3d 100644 --- a/i18n/kor/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/kor/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "ģž˜ėŖ»ėœ ķŒŒģ¼ ė¦¬ģ†ŒģŠ¤({0})", - "fileIsDirectoryError": "ķŒŒģ¼ģ“ 디렉터리({0})ģž…ė‹ˆė‹¤.", + "fileIsDirectoryError": "ķŒŒģ¼ģ“ ė””ė ‰ķ„°ė¦¬ģž…ė‹ˆė‹¤.", "fileNotModifiedError": "ķŒŒģ¼ ģˆ˜ģ • ģ•ˆ 됨", "fileTooLargeError": "ķŒŒģ¼ģ“ ė„ˆė¬“ ģ»¤ģ„œ ģ—“ 수 ģ—†ģŒ", "fileBinaryError": "ķŒŒģ¼ģ“ ģ“ģ§„ģø 것 ź°™ģœ¼ėÆ€ė”œ ķ…ŒģŠ¤ķŠøė”œ ģ—“ 수 ģ—†ģŠµė‹ˆė‹¤.", "fileNotFoundError": "ķŒŒģ¼ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤({0}).", + "fileExists": "ė§Œė“œė ¤ėŠ” ķŒŒģ¼ģ“ ģ“ėÆø ģžˆģŒ({0})", "fileMoveConflict": "ģ“ė™/복사할 수 ģ—†ģŠµė‹ˆė‹¤. ėŒ€ģƒģ— ķŒŒģ¼ģ“ ģ“ėÆø ģžˆģŠµė‹ˆė‹¤.", "unableToMoveCopyError": "ģ“ė™/복사할 수 ģ—†ģŠµė‹ˆė‹¤. ķŒŒģ¼ģ“ ķ¬ķ•Øėœ ķ“ė”ė„¼ ķŒŒģ¼ė”œ ėŒ€ģ²“ķ•©ė‹ˆė‹¤.", "foldersCopyError": "ķ“ė”ė„¼ ģž‘ģ—… ģ˜ģ—­ģ— 복사할 수 ģ—†ģŠµė‹ˆė‹¤. ź°œė³„ ķŒŒģ¼ģ„ ģ„ ķƒķ•˜ģ—¬ ė³µģ‚¬ķ•˜ģ„øģš”.", diff --git a/i18n/kor/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/kor/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/kor/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/kor/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/kor/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 9f7e84ad9b4..5195b5ea1f4 100644 --- a/i18n/kor/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/kor/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "ź·œģ¹™ģ˜ 글꼓 ģŠ¤ķƒ€ģ¼: 'źø°ģšøģž„ź¼“, '굵게' ė° '밑줄' 중 ķ•˜ė‚˜ ė˜ėŠ” ģ“ė“¤ģ˜ ģ”°ķ•©", - "schema.colors": "구문 ź°•ģ”° ķ‘œģ‹œė„¼ ģœ„ķ•œ ģƒ‰", - "schema.properties.name": "ź·œģ¹™ģ— ėŒ€ķ•œ 설명", - "schema.tokenColors.path": "tmTheme ķŒŒģ¼ģ˜ 경딜(ķ˜„ģž¬ ķŒŒģ¼ģ˜ ģƒėŒ€ 경딜)" + "schema.token.settings": "ķ† ķ°ģ˜ ģƒ‰ ė° ģŠ¤ķƒ€ģ¼ģž…ė‹ˆė‹¤.", + "schema.token.foreground": "ķ† ķ°ģ˜ ģ „ź²½ģƒ‰ģž…ė‹ˆė‹¤.", + "schema.token.fontStyle": "ź·œģ¹™ģ˜ 글꼓 ģŠ¤ķƒ€ģ¼: 'źø°ģšøģž„ź¼“, '굵게' ė° '밑줄' 중 ķ•˜ė‚˜ ė˜ėŠ” ģ“ė“¤ģ˜ ģ”°ķ•©", + "schema.fontStyle.error": "글꼓 ģŠ¤ķƒ€ģ¼ģ€ 'źø°ģšøģž„ź¼“, '굵게' ė° '밑줄'ģ˜ ģ”°ķ•©ģ“ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "schema.properties.name": "ź·œģ¹™ģ— ėŒ€ķ•œ ģ„¤ėŖ…ģž…ė‹ˆė‹¤.", + "schema.properties.scope": "ģ“ ź·œģ¹™ź³¼ ģ¼ģ¹˜ķ•˜ėŠ” ė²”ģœ„ ģ„ ķƒźø°ģž…ė‹ˆė‹¤.", + "schema.tokenColors.path": "tmTheme ķŒŒģ¼ģ˜ 경딜(ķ˜„ģž¬ ķŒŒģ¼ģ˜ ģƒėŒ€ 경딜)ģž…ė‹ˆė‹¤.", + "schema.colors": "구문 ź°•ģ”° ķ‘œģ‹œė„¼ ģœ„ķ•œ ģƒ‰" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 1acfa7a4ff4..4f7d8d2ef89 100644 --- a/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "JSON ķ…Œė§ˆ ķŒŒģ¼ģ„ 구문 ė¶„ģ„ķ•˜ėŠ” 중 문제 ė°œģƒ: {0}", "error.invalidformat.colors": "ģƒ‰ ķ…Œė§ˆ ķŒŒģ¼ {0}ģ„(넼) 구문 ė¶„ģ„ķ•˜ėŠ” 중 ė¬øģ œź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤. 'colors' ģ†ģ„±ģ“ 'object' ķ˜•ģ‹ģ“ ģ•„ė‹™ė‹ˆė‹¤.", - "error.invalidformat.tokenColors": "ģƒ‰ ķ…Œė§ˆ ķŒŒģ¼ {0}ģ„(넼) 구문 ė¶„ģ„ķ•˜ėŠ” 중 ė¬øģ œź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤. 'tokenColors' ģ†ģ„±ģ“ 'object' ķ˜•ģ‹ģ“ ģ•„ė‹™ė‹ˆė‹¤. 'tokenColors' ģ†ģ„±ģ€ ģƒ‰ģ„ ģ§€ģ •ķ•˜ėŠ” ė°°ģ—“ ė˜ėŠ” ķ…ģŠ¤ķŠø ģ§ ķ…Œė§ˆ ķŒŒģ¼ģ˜ ź²½ė”œģ—¬ģ•¼ ķ•©ė‹ˆė‹¤.", + "error.invalidformat.tokenColors": "ģƒ‰ ķ…Œė§ˆ ķŒŒģ¼ {0}ģ„(넼) 구문 ė¶„ģ„ķ•˜ėŠ” 중 ė¬øģ œź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤. 'tokenColors' ģ†ģ„±ģ“ ģƒ‰ģ„ ģ§€ģ •ķ•˜ėŠ” ė°°ģ—“ ė˜ėŠ” TextMate ķ…Œė§ˆ ķŒŒģ¼ģ˜ ź²½ė”œģ—¬ģ•¼ ķ•©ė‹ˆė‹¤.", "error.plist.invalidformat": "tmTheme ķŒŒģ¼ {0}ģ„(넼) 구문 ė¶„ģ„ķ•˜ėŠ” 중 ė¬øģ œź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤. 'settings'ź°€ ė°°ģ—“ģ“ ģ•„ė‹™ė‹ˆė‹¤.", "error.cannotparse": "tmTheme ķŒŒģ¼ {0}ģ„(넼) 구문 ė¶„ģ„ķ•˜ėŠ” 중 ė¬øģ œź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤.", "error.cannotload": "tmTheme ķŒŒģ¼ {0}ģ„(넼) ė”œė“œķ•˜ėŠ” 중 ė¬øģ œź°€ ė°œģƒķ–ˆģŠµė‹ˆė‹¤. {1}" diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..4bcd1e891d3 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "ģ‚¬ģš©ģž 설정에 ģ‚¬ģš©ėœ ģ•„ģ“ģ½˜ ķ…Œė§ˆģ˜ IDģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.themes.label": "UI에 ķ‘œģ‹œė˜ėŠ” ģƒ‰ ķ…Œė§ˆģ˜ ė ˆģ“ėø”ģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.themes.uiTheme": "ķŽøģ§‘źø° ģ£¼ė³€ģ˜ ģƒ‰ģ„ ģ •ģ˜ķ•˜ėŠ” źø°ė³ø ķ…Œė§ˆģž…ė‹ˆė‹¤. 'vs'ėŠ” ė°ģ€ģƒ‰ ķ…Œė§ˆģ“ź³ , 'vs-dark'ėŠ” ģ–“ė‘ģš“ģƒ‰ ķ…Œė§ˆģž…ė‹ˆė‹¤. 'hc-black'ģ€ ģ–“ė‘ģš“ ź³ ėŒ€ė¹„ ķ…Œė§ˆģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.themes.path": "tmTheme ķŒŒģ¼ģ˜ ź²½ė”œģž…ė‹ˆė‹¤. ķ™•ģž„ ķ“ė”ģ˜ ģƒėŒ€ ź²½ė”œģ“ė©° ģ¼ė°˜ģ ģœ¼ė”œ './themes/themeFile.tmTheme'ģž…ė‹ˆė‹¤.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path`에 ė¬øģžģ—“ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤. 제공된 ź°’: {1}", + "invalid.path.1": "ķ™•ģž„ ķ“ė”({2})에 ķ¬ķ•Øķ•  `contributes.{0}.path`({1})ź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤. ķ™•ģž„ģ“ ģ“ģ‹ ė¶ˆź°€ėŠ„ķ•“ģ§ˆ 수 ģžˆģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..10f74d38b89 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "ģ‚¬ģš©ģž 설정에 ģ‚¬ģš©ėœ ģ•„ģ“ģ½˜ ķ…Œė§ˆģ˜ IDģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.iconThemes.label": "UI에 ķ‘œģ‹œėœ ģ•„ģ“ģ½˜ ķ…Œė§ˆģ˜ ė ˆģ“ėø”ģž…ė‹ˆė‹¤.", + "vscode.extension.contributes.iconThemes.path": "ģ•„ģ“ģ½˜ ķ…Œė§ˆ ģ •ģ˜ ķŒŒģ¼ģ˜ ź²½ė”œģž…ė‹ˆė‹¤. ķ™•ģž„ ķ“ė”ģ˜ ģƒėŒ€ ź²½ė”œģ“ė©° ģ¼ė°˜ģ ģœ¼ė”œ './icons/awesome-icon-theme.json'ģž…ė‹ˆė‹¤.", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "`contributes.{0}.path`에 ė¬øģžģ—“ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤. 제공된 ź°’: {1}", + "reqid": "`contributes.{0}.id`에 ė¬øģžģ—“ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤. 제공된 ź°’: {1}", + "invalid.path.1": "ķ™•ģž„ ķ“ė”({2})에 ķ¬ķ•Øķ•  `contributes.{0}.path`({1})ź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤. ķ™•ģž„ģ“ ģ“ģ‹ ė¶ˆź°€ėŠ„ķ•“ģ§ˆ 수 ģžˆģŠµė‹ˆė‹¤." +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index a617486e76e..c7ed3a3fe46 100644 --- a/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/kor/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,29 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "ģ‚¬ģš©ģž 설정에 ģ‚¬ģš©ėœ ģ•„ģ“ģ½˜ ķ…Œė§ˆģ˜ IDģž…ė‹ˆė‹¤.", - "vscode.extension.contributes.themes.label": "UI에 ķ‘œģ‹œė˜ėŠ” ģƒ‰ ķ…Œė§ˆģ˜ ė ˆģ“ėø”ģž…ė‹ˆė‹¤.", - "vscode.extension.contributes.themes.uiTheme": "ķŽøģ§‘źø° ģ£¼ė³€ģ˜ ģƒ‰ģ„ ģ •ģ˜ķ•˜ėŠ” źø°ė³ø ķ…Œė§ˆģž…ė‹ˆė‹¤. 'vs'ėŠ” ė°ģ€ģƒ‰ ķ…Œė§ˆģ“ź³ , 'vs-dark'ėŠ” ģ–“ė‘ģš“ģƒ‰ ķ…Œė§ˆģž…ė‹ˆė‹¤. 'hc-black'ģ€ ģ–“ė‘ģš“ ź³ ėŒ€ė¹„ ķ…Œė§ˆģž…ė‹ˆė‹¤.", - "vscode.extension.contributes.themes.path": "tmTheme ķŒŒģ¼ģ˜ ź²½ė”œģž…ė‹ˆė‹¤. ķ™•ģž„ ķ“ė”ģ˜ ģƒėŒ€ ź²½ė”œģ“ė©° ģ¼ė°˜ģ ģœ¼ė”œ './themes/themeFile.tmTheme'ģž…ė‹ˆė‹¤.", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "ģ‚¬ģš©ģž 설정에 ģ‚¬ģš©ėœ ģ•„ģ“ģ½˜ ķ…Œė§ˆģ˜ IDģž…ė‹ˆė‹¤.", - "vscode.extension.contributes.iconThemes.label": "UI에 ķ‘œģ‹œėœ ģ•„ģ“ģ½˜ ķ…Œė§ˆģ˜ ė ˆģ“ėø”ģž…ė‹ˆė‹¤.", - "vscode.extension.contributes.iconThemes.path": "ģ•„ģ“ģ½˜ ķ…Œė§ˆ ģ •ģ˜ ķŒŒģ¼ģ˜ ź²½ė”œģž…ė‹ˆė‹¤. ķ™•ģž„ ķ“ė”ģ˜ ģƒėŒ€ ź²½ė”œģ“ė©° ģ¼ė°˜ģ ģœ¼ė”œ './icons/awesome-icon-theme.json'ģž…ė‹ˆė‹¤.", "migration.completed": "새 ķ…Œė§ˆ ģ„¤ģ •ģ“ ģ‚¬ģš©ģž 설정에 ģ¶”ź°€ė˜ģ—ˆģŠµė‹ˆė‹¤. {0}ģ—ģ„œ ė°±ģ—…ģ„ ģ‚¬ģš©ķ•  수 ģžˆģŠµė‹ˆė‹¤.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "`contributes.{0}.path`에 ė¬øģžģ—“ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤. 제공된 ź°’: {1}", - "invalid.path.1": "ķ™•ģž„ ķ“ė”({2})에 ķ¬ķ•Øķ•  `contributes.{0}.path`({1})ź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤. ķ™•ģž„ģ“ ģ“ģ‹ ė¶ˆź°€ėŠ„ķ•“ģ§ˆ 수 ģžˆģŠµė‹ˆė‹¤.", - "reqid": "`contributes.{0}.id`에 ė¬øģžģ—“ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤. 제공된 ź°’: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "ģ›Œķ¬ė²¤ģ¹˜ģ—ģ„œ ģ‚¬ģš©ė˜ėŠ” ģ•„ģ“ģ½˜ ķ…Œė§ˆė„¼ ģ§€ģ •ķ•©ė‹ˆė‹¤. 'null'딜 ģ§€ģ •ķ•˜ė©“ ķŒŒģ¼ ģ•„ģ“ģ½˜ģ„ ķ‘œģ‹œķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "ķ˜„ģž¬ ģ„ ķƒķ•œ ģƒ‰ ķ…Œė§ˆģ—ģ„œ ģƒ‰ģ„ ģž¬ģ •ģ˜ķ•©ė‹ˆė‹¤.", - "workbenchColors.deprecated": "ģ“ ģ„¤ģ •ģ€ ė” ģ“ģƒ ģ‹¤ķ—˜ģ  ģ„¤ģ •ģ“ ģ•„ė‹ˆė©° ģ“ė¦„ģ“\n 'workbench.colorCustomizations'딜 ė³€ź²½ė˜ģ—ˆģŠµė‹ˆė‹¤.", - "workbenchColors.deprecatedDescription": "ėŒ€ģ‹  'workbench.colorCustomizations'넼 ģ‚¬ģš©ķ•©ė‹ˆė‹¤." + "editorColors": "ķ˜„ģž¬ ģ„ ķƒėœ ģƒ‰ ķ…Œė§ˆģ—ģ„œ ķŽøģ§‘źø° ģƒ‰ģƒź³¼ 글꼓 ģŠ¤ķƒ€ģ¼ģ„ ģž¬ģ •ģ˜ķ•©ė‹ˆė‹¤.", + "editorColors.comments": "ģ£¼ģ„ģ˜ ģƒ‰ ė° ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "editorColors.strings": "ė¬øģžģ—“ ė¦¬ķ„°ėŸ“ģ˜ ģƒ‰ ė° ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "editorColors.keywords": "ķ‚¤ģ›Œė“œģ˜ ģƒ‰ź³¼ ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "editorColors.numbers": "ģˆ«ģž ė¦¬ķ„°ėŸ“ģ˜ ģƒ‰ź³¼ ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "editorColors.types": "ķ˜•ģ‹ ģ„ ģ–ø ė° ģ°øģ”°ģ˜ ģƒ‰ ė° ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "editorColors.functions": "ķ•Øģˆ˜ ģ„ ģ–ø ė° ģ°øģ”°ģ˜ ģƒ‰ ė° ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "editorColors.variables": "ė³€ģˆ˜ ģ„ ģ–ø ė° ģ°øģ”°ģ˜ ģƒ‰ ė° ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤.", + "editorColors.textMateRules": "textmate ķ…Œė§ˆ 설정 ź·œģ¹™ģ„ ģ‚¬ģš©ķ•˜ģ—¬ ģƒ‰ ė° ģŠ¤ķƒ€ģ¼ģ„ ģ„¤ģ •ķ•©ė‹ˆė‹¤(ź³ źø‰)." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/kor/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..05a0809b724 --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "openWorkspaceConfigurationFile": "ģž‘ģ—… ģ˜ģ—­ 구성 ķŒŒģ¼ ģ—“źø°", + "close": "ė‹«źø°", + "enterWorkspace.close": "ė‹«źø°", + "enterWorkspace.dontShowAgain": "ė‹¤ģ‹œ ķ‘œģ‹œ ģ•ˆ 함", + "enterWorkspace.moreInfo": "추가 정볓" +} \ No newline at end of file diff --git a/i18n/ptb/extensions/azure-account/out/azure-account.i18n.json b/i18n/ptb/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..be4c29f593c --- /dev/null +++ b/i18n/ptb/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "Copiar e Abrir", + "azure-account.close": "Fechar", + "azure-account.login": "Login", + "azure-account.loginFirst": "NĆ£o estĆ” logado, faƧa o login primeiro", + "azure-account.userCodeFailed": "Falha na aquisição do código do usuĆ”rio.", + "azure-account.tokenFailed": "Adquirindo Token pelo código do dispositivo.", + "azure-account.tokenFromRefreshTokenFailed": "Adquirindo token com token de atualização" +} \ No newline at end of file diff --git a/i18n/ptb/extensions/azure-account/out/extension.i18n.json b/i18n/ptb/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..584e7c82e0f --- /dev/null +++ b/i18n/ptb/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: Login...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index cd70eb29a4f..c86627bbf9c 100644 --- a/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/ptb/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "por exemplo meuArquivo.txt", - "activeEditorMedium": "e.g. minhaPasta/meuArquivo.txt", - "activeEditorLong": "por exemplo /UsuĆ”rios/Desenvolvimento/meuProjeto/minhaPasta/meuArquivo/txt", - "rootName": "por exemplo, myFolder1, myFolder2, myFolder3", - "rootPath": "por exemplo /UsuĆ”rios/desenvolvimento/meuProjeto", - "folderName": "por exemplo, myFolder", - "folderPath": "por exemplo, /Users/Development/myFolder", + "activeEditorShort": "o nome do arquivo (por exemplo, MyFile. txt)", + "activeEditorMedium": "o caminho do arquivo relativo Ć  pasta de trabalho (por exemplo, myFolder/myFile.txt)", + "activeEditorLong": "o caminho completo do arquivo (por exemplo, /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "nome da Ć”rea de trabalho (por exemplo, minhaPasta ou minhaAreadeTrabalho)", + "rootPath": "caminho do arquivo da Ć”rea de trabalho (por exemplo, /Usuarios/Desenvolvimento/minhaAreadeTrabalho)", + "folderName": "nome do diretório da Ć”rea de trabalho onde arquivo estĆ” localizado (por exemplo, myFolder)", + "folderPath": "caminho do arquivo no diretório da Ć”rea de trabalho onde o arquivo estĆ” localizado (por exemplo, /Users/Development/myFolder)", "appName": "e.g. VS Code", "dirty": "Um indicador de alteração se o editor ativo foi alterado", "separator": "um separador condicional (' - ') que somente Ć© mostrado quando envolvido por variĆ”veis com valores", diff --git a/i18n/ptb/extensions/css/package.i18n.json b/i18n/ptb/extensions/css/package.i18n.json index de011d44dce..b0f3195c149 100644 --- a/i18n/ptb/extensions/css/package.i18n.json +++ b/i18n/ptb/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "NĆŗmero invĆ”lido de parĆ¢metros", "css.lint.boxModel.desc": "NĆ£o use largura ou altura ao usar preenchimento ou borda", "css.lint.compatibleVendorPrefixes.desc": "Ao usar um prefixo especĆ­fico de fornecedor, certifique-se de tambĆ©m incluir todas as outras propriedades especĆ­ficas do fornecedor", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "Propriedade especĆ­fica do fornecedor desconhecida.", "css.lint.vendorPrefix.desc": "Ao usar um prefixo especĆ­fico do fornecedor, inclua tambĆ©m a propriedade padrĆ£o", "css.lint.zeroUnits.desc": "Nenhuma unidade para zero Ć© necessĆ”ria", + "css.trace.server.desc": "Rastrear a comunicação entre o VS Code e o servidor de linguagem CSS.", + "css.validate.title": "Controla a validação CSS and a gravidade dos problemas.", "css.validate.desc": "Habilita ou desabilita todas as validaƧƵes", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "NĆŗmero invĆ”lido de parĆ¢metros", "less.lint.boxModel.desc": "NĆ£o use largura ou altura ao usar preenchimento ou borda", "less.lint.compatibleVendorPrefixes.desc": "Ao usar um prefixo especĆ­fico de fornecedor, certifique-se de tambĆ©m incluir todas as outras propriedades especĆ­ficas do fornecedor", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "Propriedade especĆ­fica do fornecedor desconhecida.", "less.lint.vendorPrefix.desc": "Ao usar um prefixo especĆ­fico do fornecedor, inclua tambĆ©m a propriedade padrĆ£o", "less.lint.zeroUnits.desc": "Nenhuma unidade para zero Ć© necessĆ”ria", + "less.validate.title": "Controla MENOS as severidades de validação e problemas.", "less.validate.desc": "Habilita ou desabilita todas as validaƧƵes", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "NĆŗmero invĆ”lido de parĆ¢metros", "scss.lint.boxModel.desc": "NĆ£o use largura ou altura ao usar preenchimento ou borda", "scss.lint.compatibleVendorPrefixes.desc": "Ao usar um prefixo especĆ­fico de fornecedor, certifique-se de tambĆ©m incluir todas as outras propriedades especĆ­ficas do fornecedor", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "Propriedade especĆ­fica do fornecedor desconhecida.", "scss.lint.vendorPrefix.desc": "Ao usar um prefixo especĆ­fico do fornecedor, inclua tambĆ©m a propriedade padrĆ£o", "scss.lint.zeroUnits.desc": "Nenhuma unidade para zero Ć© necessĆ”ria", + "scss.validate.title": "Controla severidades de validação e problemas SCSS.", "scss.validate.desc": "Habilita ou desabilita todas as validaƧƵes", "less.colorDecorators.enable.desc": "Habilita ou desabilita decoradores de cores", "scss.colorDecorators.enable.desc": "Habilita ou desabilita decoradores de cores", - "css.colorDecorators.enable.desc": "Habilita ou desabilita decoradores de cores" + "css.colorDecorators.enable.desc": "Habilita ou desabilita decoradores de cores", + "css.colorDecorators.enable.deprecationMessage": "A configuração 'css.colorDecorators.enable' foi descontinuada em favor de 'editor.colorDecorators'.", + "scss.colorDecorators.enable.deprecationMessage": "A configuração 'scss.colorDecorators.enable' foi descontinuada em favor de 'editor.colorDecorators'.", + "less.colorDecorators.enable.deprecationMessage": "A configuração 'less.colorDecorators.enable' foi descontinuada em favor de 'editor.colorDecorators'." } \ No newline at end of file diff --git a/i18n/ptb/extensions/emmet/package.i18n.json b/i18n/ptb/extensions/emmet/package.i18n.json index d1d286c6e2e..93bb46e1ff4 100644 --- a/i18n/ptb/extensions/emmet/package.i18n.json +++ b/i18n/ptb/extensions/emmet/package.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "Envelope com a abreviatura", + "command.wrapIndividualLinesWithAbbreviation": "Envelopar Linhas Individuais com Abreviatura", "command.removeTag": "Remover Tag", "command.updateTag": "Atualizar Tag", "command.matchTag": "Ir para par de correspondĆŖncia", @@ -24,5 +26,28 @@ "command.incrementNumberByOneTenth": "Incremento de 0.1", "command.decrementNumberByOneTenth": "Decrementar por 0.1", "command.incrementNumberByTen": "Incremento de 10", - "command.decrementNumberByTen": "Decrementar por 10" + "command.decrementNumberByTen": "Decrementar por 10", + "emmetSyntaxProfiles": "Definir o perfil para a sintaxe especificada ou usar seu próprio perfil com regras especĆ­ficas.", + "emmetExclude": "Uma matriz de lĆ­nguas onde abreviaturas Emmet nĆ£o devem ser expandidas.", + "emmetExtensionsPath": "Caminho para uma pasta que contĆ©m os perfis Emmet e trechos de códigos.'", + "emmetShowExpandedAbbreviation": "Mostrar abreviaturas Emmet expandidas como sugestƵes.\nA opção \"inMarkupAndStylesheetFilesOnly\" aplica-se a html, haml, jade, slim, xml, xsl, css, scss, sass, less e stylus.\nA opção \"always\" se aplica a todas as partes do arquivo independentemente de marcação/css.", + "emmetShowAbbreviationSuggestions": "Mostra abreviaƧƵes Emmet possĆ­veis como sugestƵes. NĆ£o aplicĆ”vel em folhas de estilo ou quando emmet.showExpandedAbbreviation Ć© definido como \"never\".", + "emmetIncludeLanguages": "Habilita as abreviaturas Emmet em linguagens que nĆ£o sĆ£o suportados por padrĆ£o. Adicionar um mapeamento aqui entre a linguagem e a linguagem emmet suportada.\n Por exemplo: {\"vue-html\": \"html\", \"javascript\": \"javascriptreact\"}", + "emmetVariables": "VariĆ”veis a serem usadas em trechos de código Emmet", + "emmetTriggerExpansionOnTab": "Quando habilitado, abreviaƧƵes Emmet sĆ£o expandidas ao pressionar TAB.", + "emmetPreferences": "PreferĆŖncias usadas para modificar o comportamento de algumas aƧƵes e resolvedores de Emmet.", + "emmetPreferencesIntUnit": "Unidade padrĆ£o para valores inteiros", + "emmetPreferencesFloatUnit": "Unidade padrĆ£o para valores float", + "emmetPreferencesCssAfter": "SĆ­mbolo a ser colocado no final da propriedade CSS quando expandir abreviaturas CSS", + "emmetPreferencesSassAfter": "SĆ­mbolo a ser colocado no final da propriedade CSS quando expandir abreviaturas CSS em arquivos Sass", + "emmetPreferencesStylusAfter": "SĆ­mbolo a ser colocado no final da propriedade CSS quando expandir abreviaturas CSS em arquivos Stylus", + "emmetPreferencesCssBetween": "SĆ­mbolo a ser colocado entre a propriedade CSS e o valor quando expandir abreviaturas CSS", + "emmetPreferencesSassBetween": "SĆ­mbolo a ser colocado entre a propriedade CSS e o valor quando expandir abreviaturas CSS em arquivos Sass", + "emmetPreferencesStylusBetween": "SĆ­mbolo a ser colocado entre a propriedade CSS e o valor quando expandir abreviaturas CSS em arquivos Stylus", + "emmetShowSuggestionsAsSnippets": "Se verdadeiro, entĆ£o as sugestƵes emmet aparecerĆ£o como trechos, permitindo vocĆŖ requisitĆ”-los conforme a configuração de editor.snippetSuggestions.", + "emmetPreferencesBemElementSeparator": "Separador de elemento usado para classes quando utilizar o filtro BEM", + "emmetPreferencesBemModifierSeparator": "Separador de modificador usado para classes quando utilizar o filtro BEM", + "emmetPreferencesFilterCommentBefore": "Uma definição de comentĆ”rio que deve ser colocado antes de elemento correspondente quando um filtro de comentĆ”rio Ć© aplicado.", + "emmetPreferencesFilterCommentAfter": "Uma definição de comentĆ”rio que deve ser colocado após o elemento correspondente quando um filtro de comentĆ”rio Ć© aplicado.", + "emmetPreferencesFilterCommentTrigger": "Uma lista separada por vĆ­rgulas de nomes de atributo que deve existir em abreviaƧƵes para o filtro de comentĆ”rio a ser aplicado" } \ No newline at end of file diff --git a/i18n/ptb/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/ptb/extensions/extension-editing/out/extensionLinter.i18n.json index 0fee06973c8..4a357211168 100644 --- a/i18n/ptb/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/ptb/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "Imagens devem usar o protocolo HTTPS.", "svgsNotValid": "SVGs nĆ£o sĆ£o uma fonte de imagem vĆ”lida.", "embeddedSvgsNotValid": "SVGs embutidos nĆ£o sĆ£o uma fonte de imagem vĆ”lida.", - "dataUrlsNotValid": "URLs de dados nĆ£o sĆ£o uma fonte de imagem vĆ”lida." + "dataUrlsNotValid": "URLs de dados nĆ£o sĆ£o uma fonte de imagem vĆ”lida.", + "relativeUrlRequiresHttpsRepository": "URLs relativas de Imagem exigem um repositório com o protocolo HTTPS para serem especificadas no pacote .json.", + "relativeIconUrlRequiresHttpsRepository": "Um Ć­cone requer um repositório com o protocolo HTTPS para ser especificado neste package.json.", + "relativeBadgeUrlRequiresHttpsRepository": "URLs relativas de crachĆ” exigem um repositório com o protocolo HTTPS para ser especificado neste package.json." } \ No newline at end of file diff --git a/i18n/ptb/extensions/git/out/commands.i18n.json b/i18n/ptb/extensions/git/out/commands.i18n.json index b33bd9ee59b..d3e314a0e15 100644 --- a/i18n/ptb/extensions/git/out/commands.i18n.json +++ b/i18n/ptb/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "Clonando repositório do Git...", "openrepo": "Abrir Repositório", "proposeopen": "Gostaria de abrir o repositório clonado?", + "init repo": "Inicializar Repositório", + "create repo": "Inicializar Repositório", + "are you sure": "Isto irĆ” criar um repositório Git em '{0}'. Tem certeza que deseja continuar?", "HEAD not available": "VersĆ£o HEAD de '{0}' nĆ£o estĆ” disponĆ­vel.", + "confirm stage files with merge conflicts": "Tem certeza queĀ deseja processarĀ {0} arquivos com conflitos de mesclagem?", + "confirm stage file with merge conflicts": "Tem certeza queĀ deseja processarĀ {0} com conflitos de mesclagem?", + "yes": "Sim", "confirm revert": "Tem certeza que deseja reverter as alteraƧƵes selecionadas em {0}?", "revert": "Reverter as alteraƧƵes", + "discard": "Descartar alteraƧƵes", + "confirm delete": "Tem certeza que deseja EXCLUIR {0}?", + "delete file": "Excluir arquivo", "confirm discard": "Tem certeza que deseja descartar as alteraƧƵes em {0}?", "confirm discard multiple": "Tem certeza que deseja descartar as alteraƧƵes em {0} arquivos?", - "discard": "Descartar alteraƧƵes", - "confirm discard all": "Tem certeza que deseja descartar TODAS as alteraƧƵes? Isso Ć© IRREVERSƍVEL!", - "discardAll": "Descartar TODAS as alteraƧƵes", + "warn untracked": "Isso irĆ” excluir {0} registros nĆ£o rastreados!", + "confirm discard all single": "Tem certeza que deseja descartar as alteraƧƵes em {0}?", + "confirm discard all": "Tem certeza que deseja descartar todas as alteraƧƵes em {0} arquivos?\nIsso Ć© IRREVERSĆ­VEL!\nO conjunto de trabalhando atual serĆ” PERDIDO PARA SEMPRE.", + "discardAll multiple": "Descartar 1 Arquivo", + "discardAll": "Descartar Todos os {0} Arquivos", + "confirm delete multiple": "Tem certeza que deseja excluir {0} arquivos?", + "delete files": "Excluir arquivos", + "there are untracked files single": "O seguinte arquivo nĆ£o controlado serĆ” excluĆ­do do disco se descartado: {0}.", + "there are untracked files": "Existem {0} arquivos nĆ£o controlados que serĆ£o excluĆ­dos do disco se descartados.", + "confirm discard all 2": "{0}\n\n Ć© IRREVERSƍVEL, o conjunto de trabalho atual serĆ” PERDIDO PARA SEMPRE.", + "yes discard tracked": "Descartar 1 arquivo controlado", + "yes discard tracked multiple": "Descartar arquivos {0} controlados", "no staged changes": "NĆ£o hĆ” nenhuma modificação escalonada para confirmar.\n\nGostaria de escalonar automaticamente todas as suas alteraƧƵes e confirmĆ”-las diretamente?", - "yes": "Sim", "always": "Sempre", "no changes": "NĆ£o hĆ” mudanƧas para confirmar.", "commit message": "Confirmar mensagem", @@ -34,16 +51,25 @@ "delete branch": "Excluir ramificação", "select a branch to merge from": "Selecione uma ramificação para mesclar", "merge conflicts": "Existem conflitos de mesclagem. Resolva-os antes de confirmar.", + "tag name": "Nome do rótulo", + "provide tag name": "Por favor, forneƧa um nome de Tag", + "tag message": "Mensagem", + "provide tag message": "Por favor, forneƧa uma mensagem paraĀ comentar o rótulo", "no remotes to pull": "O seu repositório nĆ£o possui remotos configurados para efetuar pull.", "pick remote pull repo": "Selecione um remoto para efeutar o pull da ramificação", "no remotes to push": "O seu repositório nĆ£o possui remotos configurados para efetuar push.", + "push with tags success": "Envio de rótulos finalizado com sucesso.", "nobranch": "Por favor, faƧa checkout em um ramo para fazer push em um remoto.", "pick remote": "Pegue um remoto para publicar o ramo '{0}':", "sync is unpredictable": "Esta ação vai fazer push e pull nos commits de e para '{0}'.", "ok": "OK", "never again": "Ok, Nunca Mostrar Novamente", "no remotes to publish": "Seu repositório nĆ£o possui remotos configurados para publicação.", - "disabled": "Git estĆ” desativado ou nĆ£o Ć© suportado neste espaƧo de trabalho", + "no changes stash": "NĆ£o hĆ” nenhuma mudanƧa para esconder.", + "provide stash message": "Opcionalmente forneƧa uma mensagem para esconder.", + "stash message": "Mensagem oculta", + "no stashes": "NĆ£o hĆ” esconderijos para restaurar.", + "pick stash to pop": "Escolher um esconderijo de pop", "clean repo": "Por favor, limpe sua Ć”rvore de trabalho do repositório antes de fazer check-out.", "cant push": "NĆ£o pode empurrar referĆŖncias para remoto. Execute 'Pull' primeiro para integrar suas alteraƧƵes.", "git error details": "Git: {0}", diff --git a/i18n/ptb/extensions/git/out/model.i18n.json b/i18n/ptb/extensions/git/out/model.i18n.json index 717d2b4364a..05c63b7788a 100644 --- a/i18n/ptb/extensions/git/out/model.i18n.json +++ b/i18n/ptb/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Abrir", - "merge changes": "Mesclar AlteraƧƵes", - "staged changes": "AlteraƧƵes em Etapas", - "changes": "AlteraƧƵes", - "ok": "OK", - "neveragain": "Nunca Mostrar Novamente", - "huge": "O repositório git em '{0}' tem muitas atualizaƧƵes ativas, somente um subconjunto de funcionalidades do Git serĆ” habilitado." + "no repositories": "NĆ£o existem repositórios disponĆ­veis", + "pick repo": "Escolher um repositório" } \ No newline at end of file diff --git a/i18n/ptb/extensions/git/out/repository.i18n.json b/i18n/ptb/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..d9855ba9df2 --- /dev/null +++ b/i18n/ptb/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "Abrir", + "index modified": "ƍndice modificado", + "modified": "Modificado", + "index added": "ƍndice adicionado", + "index deleted": "ƍndice excluĆ­do", + "deleted": "ExcluĆ­do", + "index renamed": "ƍndice renomeado", + "index copied": "ƍndice copiado", + "untracked": "NĆ£o acompanhado", + "ignored": "Ignorado", + "both deleted": "Ambos ExcluĆ­dos", + "added by us": "Adicionado por nós", + "deleted by them": "ExcluĆ­do por eles", + "added by them": "Adicionado por eles", + "deleted by us": "ExcluĆ­do por nós", + "both added": "Ambos adicionados", + "both modified": "Ambos modificados", + "commit": "Confirmar", + "merge changes": "Mesclar AlteraƧƵes", + "staged changes": "AlteraƧƵes em Etapas", + "changes": "AlteraƧƵes", + "ok": "OK", + "neveragain": "Nunca Mostrar Novamente", + "huge": "O repositório git em '{0}' tem muitas atualizaƧƵes ativas, somente um subconjunto de funcionalidades do Git serĆ” habilitado." +} \ No newline at end of file diff --git a/i18n/ptb/extensions/git/package.i18n.json b/i18n/ptb/extensions/git/package.i18n.json index 6a5c2f313f2..8ca31f76ec1 100644 --- a/i18n/ptb/extensions/git/package.i18n.json +++ b/i18n/ptb/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "Clonar", "command.init": "Inicializar Repositório", + "command.close": "Fechar o repositório", "command.refresh": "Atualizar", "command.openChange": "Abrir alteraƧƵes", "command.openFile": "Abrir Arquivo", @@ -14,6 +15,8 @@ "command.stageAll": "Estagiar Todas AlteraƧƵes", "command.stageSelectedRanges": "Estagiar Faixas Selecionadas", "command.revertSelectedRanges": "Reverter Faixas Selecionadas", + "command.stageChange": "MudanƧa de fase", + "command.revertChange": "Reverter a alteração", "command.unstage": "Desestagiar AlteraƧƵes", "command.unstageAll": "Desestagiar Todas AlteraƧƵes", "command.unstageSelectedRanges": "Desestagiar Faixas Selecionadas", @@ -22,22 +25,29 @@ "command.commit": "Confirmar", "command.commitStaged": "Confirmar os preparados", "command.commitStagedSigned": "Confirmar Estagiados (Desconectado)", + "command.commitStagedAmend": "Confirmar estagiado (alterar)", "command.commitAll": "Confirmar tudo", "command.commitAllSigned": "Confirmar Tudo (Desconectado)", + "command.commitAllAmend": "Comitar Tudo (Corrigir)", "command.undoCommit": "Desfazer Ultima Confirmação", "command.checkout": "Fazer checkout para...", "command.branch": "Criar Ramificação...", "command.deleteBranch": "Excluir Ramificação...", "command.merge": "Mesclar ramificação...", + "command.createTag": "Criar Tag", "command.pull": "Efetuar pull", "command.pullRebase": "Efetuar pull (Rebase)", "command.pullFrom": "Fazer pull de...", "command.push": "Enviar por push", "command.pushTo": "Enviar por push para...", + "command.pushWithTags": "Mover com Tags", "command.sync": "Sincronizar", "command.publish": "Publicar Ramo", "command.showOutput": "Mostrar SaĆ­da do Git", "command.ignore": "Adicionar arquivo ao .gitignore", + "command.stash": "Esconder", + "command.stashPop": "Pop Stash...", + "command.stashPopLatest": "Pop mais recente Stash", "config.enabled": "Se o git estiver habilitado", "config.path": "Caminho para o executĆ”vel do git", "config.autorefresh": "Se a atualização automĆ”tica estiver habilitada", @@ -49,5 +59,7 @@ "config.ignoreLegacyWarning": "Ignora o aviso de Git legado", "config.ignoreLimitWarning": "Ignora o aviso quando houver muitas alteraƧƵes em um repositório", "config.defaultCloneDirectory": "O local padrĆ£o onde clonar um repositório git", - "config.enableSmartCommit": "Confirme todas as alteraƧƵes quando nĆ£o hĆ” modificaƧƵes planejadas." + "config.enableSmartCommit": "Confirme todas as alteraƧƵes quando nĆ£o hĆ” modificaƧƵes planejadas.", + "config.enableCommitSigning": "Habilitar Commit assinando com GPG.", + "config.discardAllScope": "Controla as alteraƧƵes que sĆ£o descartadas pelo comando 'Descartar todas as alteraƧƵes'. 'todos' descarta todas as alteraƧƵes. 'rastreados' descarta somente arquivos rastreados. 'prompt' mostra uma caixa de diĆ”logo de alerta cada vez que a ação Ć© executada." } \ No newline at end of file diff --git a/i18n/ptb/extensions/grunt/out/main.i18n.json b/i18n/ptb/extensions/grunt/out/main.i18n.json index 909b68937c6..be0251a24d3 100644 --- a/i18n/ptb/extensions/grunt/out/main.i18n.json +++ b/i18n/ptb/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Auto detecção de Grunt falhou com erro: {0}" + "execFailed": "Auto detecção de Grunt para pasta {0} falhou com erro: {1}" } \ No newline at end of file diff --git a/i18n/ptb/extensions/gulp/out/main.i18n.json b/i18n/ptb/extensions/gulp/out/main.i18n.json index 51b05e4013e..ef8a9dc0891 100644 --- a/i18n/ptb/extensions/gulp/out/main.i18n.json +++ b/i18n/ptb/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Auto detecção de gulp falhou com erro: {0}" + "execFailed": "Auto detecção de gulp para pasta {0} falhou com erro: {1}" } \ No newline at end of file diff --git a/i18n/ptb/extensions/html/package.i18n.json b/i18n/ptb/extensions/html/package.i18n.json index 2f255a02e7f..2772cf08cde 100644 --- a/i18n/ptb/extensions/html/package.i18n.json +++ b/i18n/ptb/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "Ativa/desativa o formatador HTML padrĆ£o (requer reinicialização)", + "html.format.enable.desc": "Ativar/desativar o formatador HTML padrĆ£o", "html.format.wrapLineLength.desc": "Quantidade mĆ”xima de caracteres por linha (0 = desativar).", "html.format.unformatted.desc": "Lista de tags, separados por vĆ­rgula, que nĆ£o deveria ser reformatada. o padrĆ£o Ć© 'nulo' para todas as tags listadas em https://www.w3.org/TR/html5/dom.html#phrasing-content.", "html.format.contentUnformatted.desc": "Lista de tags, separada por vĆ­rgula, onde o conteĆŗdo nĆ£o deve ser reformatado. o padrĆ£o Ć© 'nulo' para a tag 'prĆ©'.", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "Configura se o suporte da linguagem HTML interna sugere rótulos e propriedades do Angular V1.", "html.suggest.ionic.desc": "Configura se o suporte da linguagem HTML interna sugere rótulos, propriedades e valores Ionic.", "html.suggest.html5.desc": "Configura se o suporte da linguagem HTML interna sugere rótulos, propriedades e valores HTML5.", + "html.trace.server.desc": "Rastrear a comunicação entre o VS Code e o servidor de linguagem HTML.", "html.validate.scripts": "Configura se o suporte da linguagem HTML interna valida scripts embutidos.", - "html.validate.styles": "Configura se o suporte da linguagem HTML interna valida estilos embutidos." + "html.validate.styles": "Configura se o suporte da linguagem HTML interna valida estilos embutidos.", + "html.autoClosingTags": "Ativar/desativar o fechamento automĆ”tico de tags HTML." } \ No newline at end of file diff --git a/i18n/ptb/extensions/jake/out/main.i18n.json b/i18n/ptb/extensions/jake/out/main.i18n.json index 4cfc54e5fef..556bbc75d39 100644 --- a/i18n/ptb/extensions/jake/out/main.i18n.json +++ b/i18n/ptb/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Auto detecção de Jake falhou com erro: {0}" + "execFailed": "Auto detecção de Jake para pasta {0} falhou com erro: {1}" } \ No newline at end of file diff --git a/i18n/ptb/extensions/json/package.i18n.json b/i18n/ptb/extensions/json/package.i18n.json index 9d812f5b253..c588df96a2f 100644 --- a/i18n/ptb/extensions/json/package.i18n.json +++ b/i18n/ptb/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "A definição de esquema para o URL dado. O esquema precisa ser fornecido apenas para evitar acessos ao URL do esquema.", "json.format.enable.desc": "Habilitar/desabilitar o formatador JSON padrĆ£o (requer reinicialização)", "json.tracing.desc": "Loga a comunicação entre o VS Code e o servidor de linguagem JSON.", - "json.colorDecorators.enable.desc": "Habilita ou desabilita os decoradores de cor" + "json.colorDecorators.enable.desc": "Habilita ou desabilita os decoradores de cor", + "json.colorDecorators.enable.deprecationMessage": "A configuração 'json.colorDecorators.enable' foi descontinuada em favor de 'editor.colorDecorators'." } \ No newline at end of file diff --git a/i18n/ptb/extensions/markdown/out/extension.i18n.json b/i18n/ptb/extensions/markdown/out/extension.i18n.json index 0f4d1689d7f..8660a23d4f2 100644 --- a/i18n/ptb/extensions/markdown/out/extension.i18n.json +++ b/i18n/ptb/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "NĆ£o foi possĆ­vel carregar o 'markdown.styles': {0}" + "onPreviewStyleLoadError": "NĆ£o foi possĆ­vel carregar o 'markdown.styles': {0}", + "previewTitle": "Visualização {0}" } \ No newline at end of file diff --git a/i18n/ptb/extensions/markdown/out/security.i18n.json b/i18n/ptb/extensions/markdown/out/security.i18n.json index cc2b913b977..c0b18587a31 100644 --- a/i18n/ptb/extensions/markdown/out/security.i18n.json +++ b/i18n/ptb/extensions/markdown/out/security.i18n.json @@ -4,9 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.strictTitle": "Rigoroso. Só carrega conteĆŗdo seguro.", - "preview.showPreviewSecuritySelector.currentSelection": "Configuração atual", - "preview.showPreviewSecuritySelector.insecureContentTitle": "Permite o carregamento de conteĆŗdo via http.", - "preview.showPreviewSecuritySelector.scriptsAndAllContent": "Permite a execução de todo o conteĆŗdo e script. NĆ£o recomendado.", + "strict.title": "Estrita", + "strict.description": "Somente carregar conteĆŗdo seguro", + "insecureContent.title": "Permitir conteĆŗdo inseguro", + "insecureContent.description": "Habilitar o carregamento de conteĆŗdo sobre http", + "disable.title": "Desabilitar", + "disable.description": "Permitir a execução de conteĆŗdo e scripts. NĆ£o recomendado", + "moreInfo.title": "Mais informaƧƵes", "preview.showPreviewSecuritySelector.title": "Selecione as configuraƧƵes de seguranƧa para visualizaƧƵes de Markdown neste espaƧo de trabalho" } \ No newline at end of file diff --git a/i18n/ptb/extensions/markdown/package.i18n.json b/i18n/ptb/extensions/markdown/package.i18n.json index c1f744bf765..789f117448a 100644 --- a/i18n/ptb/extensions/markdown/package.i18n.json +++ b/i18n/ptb/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "Configura como quebras de linha sĆ£o processadas na visualização de markdown. Configurando como 'true' cria um
para cada nova linha.", + "markdown.preview.linkify": "Habilitar ou desabilitar a conversĆ£o de texto URL para links na visualização markdown.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Duplo clique na prĆ©-visualização markdown para alternar para o editor.", "markdown.preview.fontFamily.desc": "Controla a famĆ­lia de fonte usada na prĆ©-visualização de markdown.", "markdown.preview.fontSize.desc": "Controla o tamanho da fonte em pixels usado na prĆ©-visualização de markdown.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "Abre prĆ©-visualização ao lado", "markdown.showSource.title": "Exibir Código-Fonte", "markdown.styles.dec": "Uma lista de URLs ou caminhos locais para folhas de estilo CSS para usar na prĆ©-visualização do markdown. Caminhos relativos sĆ£o interpretados em relação Ć  pasta aberta no explorer. Se nĆ£o houver nenhuma pasta aberta, eles sĆ£o interpretados em relação ao local do arquivo markdown. Todos os ' \\' precisam ser escritos como ' \\ \\ '.", - "markdown.showPreviewSecuritySelector.title": "Alterar as configuraƧƵes de seguranƧa de prĆ©-visualização do Markdown", - "markdown.trace.desc": "Habilitar log de depuração para a extensĆ£o do markdown." + "markdown.showPreviewSecuritySelector.title": "Alterar as configuraƧƵes de seguranƧa de visualização", + "markdown.trace.desc": "Habilitar log de depuração para a extensĆ£o do markdown.", + "markdown.refreshPreview.title": "Atualizar a visualização" } \ No newline at end of file diff --git a/i18n/ptb/extensions/npm/out/main.i18n.json b/i18n/ptb/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/ptb/extensions/npm/out/main.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/ptb/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/ptb/extensions/typescript/out/features/taskProvider.i18n.json index 4b20171e336..1da26ebad76 100644 --- a/i18n/ptb/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/ptb/extensions/typescript/out/features/taskProvider.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "buildAndWatchTscLabel": "monitorar - {0}", - "buildTscLabel": "compilar - {0}" + "buildTscLabel": "compilar - {0}", + "buildAndWatchTscLabel": "monitorar - {0}" } \ No newline at end of file diff --git a/i18n/ptb/extensions/typescript/out/utils/api.i18n.json b/i18n/ptb/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..ea073b54725 --- /dev/null +++ b/i18n/ptb/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "versĆ£o invĆ”lida" +} \ No newline at end of file diff --git a/i18n/ptb/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/ptb/extensions/typescript/out/utils/versionPicker.i18n.json index d7e1e13f4a3..87043e03fd6 100644 --- a/i18n/ptb/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/ptb/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "Usar a VersĆ£o do VS Code", + "useVSCodeVersionOption": "Use a versĆ£o do VS Code", "useWorkspaceVersionOption": "Use a versĆ£o de Ć”rea de trabalho", "learnMore": "Saiba Mais", "selectTsVersion": "Selecione a versĆ£o do TypeScript usada para os recursos de linguagem JavaScript e TypeScript" diff --git a/i18n/ptb/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/ptb/extensions/typescript/out/utils/versionProvider.i18n.json index 62c461cbe8e..e2cf1ea2df5 100644 --- a/i18n/ptb/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/ptb/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "O tsserver do VS Code foi excluĆ­do por outra aplicação, como por exemplo uma ferramenta de detecção de virus mal-comportada. Favor reinstalar o VS Code." + "couldNotLoadTsVersion": "NĆ£o foi possĆ­vel carregar a versĆ£o do TypeScript neste caminho", + "noBundledServerFound": "Tsserver do VSĀ Code foi eliminado por outro aplicativo como uma ferramenta de detecção de vĆ­rus com um comportamento inadequado. Por favor reinstale o VS Code." } \ No newline at end of file diff --git a/i18n/ptb/extensions/typescript/package.i18n.json b/i18n/ptb/extensions/typescript/package.i18n.json index 7f19341f39e..0884bfdaa43 100644 --- a/i18n/ptb/extensions/typescript/package.i18n.json +++ b/i18n/ptb/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "FunƧƵes completas com a assinatura do parĆ¢metro.", "typescript.tsdk.desc": "Especifica o caminho da pasta que contĆ©m os arquivos tsserver e lib*.d.ts para usar.", - "typescript.disableAutomaticTypeAcquisition": "Desabilita a aquisição automĆ”tica de tipo. Requer TypeScript > = 2.0.6 e um reinĆ­cio depois da alteração.", + "typescript.disableAutomaticTypeAcquisition": "Desabilita a aquisição automĆ”tica de tipo. Requer TypeScript > = 2.0.6.", "typescript.tsserver.log": "Habilita o log do servidor TS para um arquivo. Este log pode ser usado para diagnosticar problemas do servidor de TS. O log pode conter caminhos de arquivo, código-fonte e outras informaƧƵes potencialmente confidenciais do seu projeto.", "typescript.tsserver.trace": "Habilita o rastreamento de mensagens enviadas para o servidor de TS. Este rastreamento pode ser usado para diagnosticar problemas do servidor de TS. O rastreamento pode conter caminhos de arquivo, código-fonte e outras informaƧƵes potencialmente confidenciais do seu projeto.", "typescript.validate.enable": "Habilita/Desabilita a validação TypeScript.", @@ -44,7 +44,11 @@ "typescript.npm": "Especifica o caminho para o executĆ”vel do NPM usado para Aquisição de Tipo AutomĆ”tico. Requer TypeScript > = 2.3.4.", "typescript.check.npmIsInstalled": "Verificar se o NPM estĆ” instalado para aquisição automĆ”tica de tipo.", "javascript.nameSuggestions": "Habilitar/desabilitar incluindo nomes exclusivos do arquivo nas listas de sugestĆ£o de JavaScript.", - "typescript.tsc.autoDetect": "Controla se a auto-detecção de tarefas tsc estĆ£o ligadas ou desligadas.", + "typescript.tsc.autoDetect": "Controla a auto deteção das tarefas de tsc. 'off' desativa esse recurso. 'build' só cria tarefas de compilação de execução Ćŗnica. 'watch' cria apenas tarefas de compilação e monitoramento. 'on' cria ambas as tarefas deĀ compilar e monitoramento. PadrĆ£o Ć© 'on'.", "typescript.problemMatchers.tsc.label": "Problemas TypeScript", - "typescript.problemMatchers.tscWatch.label": "Problemas TypeScript (modo observação)" + "typescript.problemMatchers.tscWatch.label": "Problemas TypeScript (modo observação)", + "typescript.quickSuggestionsForPaths": "Ativar/desativar sugestƵes rĆ”pidas quando estiver digitando um caminho de importação.", + "typescript.locale": "Define a localidade usada para relatar erros TypeScript. Requer TypeScript > = 2.6.0. PadrĆ£o 'null' usa a localidade do VS Code para erros TypeScript.", + "javascript.implicitProjectConfig.experimentalDecorators": "Ativar/desativar 'experimentalDecorators' para arquivos JavaScript que nĆ£o fazem parte de um projeto. Os arquivos existentes de jsconfig.json ou tsconfig.json substituem essa configuração. Requer TypeScript >= 2.3.1.", + "typescript.autoImportSuggestions.enabled": "Ativar/desativar sugestƵes de importação automĆ”tica. Requer TypeScript >= 2.6.1" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/base/common/jsonErrorMessages.i18n.json b/i18n/ptb/src/vs/base/common/jsonErrorMessages.i18n.json index d6108586df8..97f0770c0dc 100644 --- a/i18n/ptb/src/vs/base/common/jsonErrorMessages.i18n.json +++ b/i18n/ptb/src/vs/base/common/jsonErrorMessages.i18n.json @@ -8,7 +8,7 @@ "error.invalidNumberFormat": "Formato de nĆŗmero invĆ”lido", "error.propertyNameExpected": "Nome de propriedade esperado", "error.valueExpected": "Valor esperado", - "error.colonExpected": "Dois-pontos esperados", + "error.colonExpected": "Dois-pontos esperado", "error.commaExpected": "VĆ­rgula esperada", "error.closeBraceExpected": "Chave de fechamento esperada", "error.closeBracketExpected": "Colchete de fechamento esperado", diff --git a/i18n/ptb/src/vs/base/common/keybindingLabels.i18n.json b/i18n/ptb/src/vs/base/common/keybindingLabels.i18n.json index bf2baf83906..5977a200f22 100644 --- a/i18n/ptb/src/vs/base/common/keybindingLabels.i18n.json +++ b/i18n/ptb/src/vs/base/common/keybindingLabels.i18n.json @@ -8,7 +8,7 @@ "shiftKey": "Shift", "altKey": "Alt", "windowsKey": "Windows", - "ctrlKey.long": "Controle", + "ctrlKey.long": "Control", "shiftKey.long": "Shift", "altKey.long": "Alt", "cmdKey.long": "Comando", diff --git a/i18n/ptb/src/vs/code/electron-main/menus.i18n.json b/i18n/ptb/src/vs/code/electron-main/menus.i18n.json index 04dffa8a8bd..fa5680aff39 100644 --- a/i18n/ptb/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/ptb/src/vs/code/electron-main/menus.i18n.json @@ -102,6 +102,7 @@ "miHideActivityBar": "Ocultar Barra de &&Atividades", "miShowActivityBar": "Mostrar Barra de &&Atividades", "miToggleWordWrap": "Alternar &&Quebra de Linha", + "miToggleMinimap": "Alternar &&Painel", "miToggleRenderWhitespace": "Alternar &&Renderização de EspaƧos em Branco", "miToggleRenderControlCharacters": "Alternar &&Caracteres de Controle", "miZoomIn": "&&Ampliar", @@ -150,6 +151,10 @@ "mZoom": "Ampliar", "mBringToFront": "Trazer Tudo para a Frente", "miSwitchWindow": "Alternar &&Janela...", + "mShowPreviousTab": "Mostrar a guia anterior", + "mShowNextTab": "Mostrar próxima guia", + "mMoveTabToNewWindow": "Mover guia para nova janela", + "mMergeAllWindows": "Mesclar todas as janelas", "miToggleDevTools": "&&Alternar Ferramentas do Desenvolvedor", "miAccessibilityOptions": "&&OpƧƵes de Acessibilidade", "miReportIssues": "Relatar &&Problemas", @@ -170,8 +175,8 @@ "miRunningTask": "Mostrar &&Tarefas Em Execução...", "miRestartTask": "R&&einiciar Tarefa em Execução", "miTerminateTask": "&&Finalizar Tarefa", - "miConfigureTask": "&&Configurar tarefas", - "miConfigureBuildTask": "Configurar Tarefa de Compilação &&PadrĆ£o", + "miConfigureTask": "&& Configurar Tarefas...", + "miConfigureBuildTask": "Configurar Tarefas PadrĆ£o de Compilação...", "accessibilityOptionsWindowTitle": "OpƧƵes de Acessibilidade", "miRestartToUpdate": "Reinicie para Atualizar...", "miCheckingForUpdates": "Verificando AtualizaƧƵes...", diff --git a/i18n/ptb/src/vs/code/electron-main/windows.i18n.json b/i18n/ptb/src/vs/code/electron-main/windows.i18n.json index c7c535d2dd2..a285320a844 100644 --- a/i18n/ptb/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/ptb/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,24 @@ "ok": "OK", "pathNotExistTitle": "O caminho nĆ£o existe", "pathNotExistDetail": "O caminho '{0}' nĆ£o parece mais existir no disco.", - "reopen": "Reabrir", - "wait": "Continuar Esperando", - "close": "Fechar", + "reopen": "&&Reabrir", + "wait": "&&Continuar Aguardando", + "close": "&&Fechar", "appStalled": "A janela nĆ£o estĆ” mais respondendo", "appStalledDetail": "VocĆŖ pode reabrir, fechar a janela ou continuar esperando.", "appCrashed": "A janela foi fechada inesperadamente", "appCrashedDetail": "Pedimos desculpas pelo inconveniente! VocĆŖ pode reabrir a janela para continuar de onde parou.", + "open": "Abrir", + "openFolder": "Abrir Pasta", "openFile": "Abrir Arquivo", - "openFolder": "Abrir Pasta" + "workspaceOpenedMessage": "NĆ£o Ć© possĆ­vel salvar espaƧo de trabalho '{0}'", + "workspaceOpenedDetail": "O espaƧo de trabalho jĆ” estĆ” aberto em outra janela. Por favor, feche a janela primeiro e tente novamente.", + "openWorkspace": "&&Abrir", + "openWorkspaceTitle": "Abrir o EspaƧo de Trabalho", + "save": "&&Salvar", + "doNotSave": "&&NĆ£o Salvar", + "cancel": "Cancelar", + "saveWorkspaceMessage": "VocĆŖ quer salvar a sua configuração de Ć”rea de trabalho como um arquivo?", + "saveWorkspaceDetail": "Salve seu espaƧo de trabalho se pretende abri-lo novamente.", + "saveWorkspace": "Salvar o espaƧo de trabalho" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/browser/widget/diffReview.i18n.json b/i18n/ptb/src/vs/editor/browser/widget/diffReview.i18n.json index 40b318ab159..d7c36424974 100644 --- a/i18n/ptb/src/vs/editor/browser/widget/diffReview.i18n.json +++ b/i18n/ptb/src/vs/editor/browser/widget/diffReview.i18n.json @@ -6,8 +6,8 @@ { "label.close": "Fechar", "header": "DiferenƧa {0} de {1}: original {2}, {3} linhas, modificado {4}, {5} linhas", - "blankLine": "em branco", - "equalLine": "original {0}, {1} modificados: {2}", + "blankLine": "branco", + "equalLine": "original {0}, modificados {1}: {2}", "insertLine": "+ modificado {0}: {1}", "deleteLine": "-original {0}: {1}", "editor.action.diffReview.next": "Ir para a próxima diferenƧa", diff --git a/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json index dd1475466b3..52d56cf1cda 100644 --- a/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/ptb/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "Controla a altura da linha. Use 0 para computar a altura da linha a partir do tamanho da fonte.", "letterSpacing": "Controla o espaƧamento da letra em pixels.", "lineNumbers": "Controla a exibição de nĆŗmeros de linha. Valores possĆ­veis sĆ£o 'on', 'off' e 'relative'. 'relative' mostra a contagem de linhas a partir da posição atual do cursor.", - "rulers": "Colunas nas quais mostrar rĆ©guas verticais", + "rulers": "Renderiza rĆ©guas verticais após um certo nĆŗmero de caracteres de espaƧo. Use vĆ”rios valores para vĆ”rias rĆ©guas. RĆ©guas nĆ£o serĆ£o desenhadas se a matriz estiver vazia", "wordSeparators": "Caracteres que serĆ£o usados como separadores de palavras ao fazer navegação relacionada a palavras ou operaƧƵes", "tabSize": "O nĆŗmero de espaƧos equivalentes a uma tabulação. Esta configuração Ć© sobreposta no conteĆŗdo do arquivo quando `editor.detectIndentation` estĆ” ligado.", "tabSize.errorMessage": "Esperado 'nĆŗmero'. Note que o valor \"auto\" foi alterado pela configuração 'editor.detectIndentation'.", @@ -20,8 +20,9 @@ "detectIndentation": "Quando um arquivo estĆ” sendo aberto, 'editor.tabSize' e 'editor.insertSpace' serĆ” detectado com base no conteĆŗdo do arquivo.", "roundedSelection": "Controla se as seleƧƵes tĆŖm cantos arredondados", "scrollBeyondLastLine": "Controla se o editor rolarĆ” alĆ©m da Ćŗltima linha", + "smoothScrolling": "Controla se o editor irĆ” rolar usando uma animação", "minimap.enabled": "Controla se o mini mapa Ć© exibido", - "minimap.showSlider": "Controla se o controle deslizante minimap Ć© oculto automaticamente.", + "minimap.showSlider": "Controla se o controle deslizante minimap Ć© automaticamente escondido. Os valores possĆ­veis sĆ£o 'sempre' e 'mouseover'", "minimap.renderCharacters": "Renderizar os caracteres em uma linha (em oposição a blocos de caracteres)", "minimap.maxColumn": "Limitar o tamanho de um mini-mapa para renderizar no mĆ”ximo um nĆŗmero determinado de colunas", "find.seedSearchStringFromSelection": "Controla se nós inicializamos a string de pesquisa na Ferramenta de Pesquisa a partir da seleção do editor", @@ -46,7 +47,7 @@ "autoClosingBrackets": "Controla se o editor deve fechar colchetes automaticamente depois de abri-los", "formatOnType": "Controla se o editor deve formatar automaticamente a linha após a digitação", "formatOnPaste": "Controla se o editor deve formatar automaticamente o conteĆŗdo colado. Um formatador deve estar disponĆ­vel e o formatador deve ser capaz de formatar apenas uma parte do documento.", - "autoIndent": "Controles se o editor deve ajustar automaticamente o recuo, quando os usuĆ”rios digitam, colam ou movem linhas. Regras de recuo da lĆ­ngua devem estar disponĆ­veis. ", + "autoIndent": "Controla se o editor deve ajustar automaticamente o recuo quando os usuĆ”rios digitam, colam ou movem linhas. Regras de recuo da lĆ­ngua devem estar disponĆ­veis.", "suggestOnTriggerCharacters": "Controla se as sugestƵes devem aparecer automaticamente ao digitar caracteres de gatilho", "acceptSuggestionOnEnter": "Controla se as sugestƵes devem ser aceitas com 'Enter' - em adição a 'Tab'. Ajuda a evitar a ambiguidade entre a inserção de novas linhas ou aceitar sugestƵes. O valor 'smart' significa apenas aceitar uma sugestĆ£o com Enter quando ela fizer uma mudanƧa textual", "acceptSuggestionOnCommitCharacter": "Controla se as sugestƵes devem ser aceitas em caracteres de confirmação. Por exemplo, em JavaScript, o ponto-e-vĆ­rgula (';') pode ser um caractere de confirmação que aceita uma sugestĆ£o e digita esse caractere.", @@ -86,6 +87,8 @@ "accessibilitySupport.off": "O editor nunca serĆ” otimizado para o uso de um leitor de tela.", "accessibilitySupport": "Controla quando o editor deve executar em modo otimizado para leitores de tela.", "links": "Controla se o editor deve detectar links e tornĆ”-los clicĆ”veis", + "colorDecorators": "Controla se o editor deve processar os decoradores de cor inline e o seletor de cores.", + "codeActions": "Habilita a ação de código lightbulb", "sideBySide": "Controla se o editor de diff mostra as diff lado a lado ou inline.", "ignoreTrimWhitespace": "Controla se o editor de diff mostra alteraƧƵes nos espaƧos iniciais ou finais como diferenƧas", "renderIndicators": "Controla se o editor de diff mostra indicadores +/- para alteraƧƵes adicionadas/removidas", diff --git a/i18n/ptb/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/ptb/src/vs/editor/common/view/editorColorRegistry.i18n.json index c848a223488..434fe65993d 100644 --- a/i18n/ptb/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/ptb/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "Cor do primeiro plano das linhas onduladas de erro no editor.", "errorBorder": "Cor da borda das linhas onduladas de erro no editor.", "warningForeground": "Cor do primeiro plano de linhas onduladas de aviso no editor.", - "warningBorder": "Cor da borda das linhas onduladas de aviso no editor." + "warningBorder": "Cor da borda das linhas onduladas de aviso no editor.", + "infoForeground": "Cor do primeiro plano das linhas de informação no editor.", + "infoBorder": "Cor da borda das linhas de informação no editor.", + "overviewRulerRangeHighlight": "VisĆ£o geral da cor do marcador da rĆ©gua para intervalos de destaques.", + "overviewRuleError": "VisĆ£o geral da cor do marcador da rĆ©gua para erros.", + "overviewRuleWarning": "VisĆ£o geral da cor do marcador da rĆ©gua para avisos.", + "overviewRuleInfo": "VisĆ£o geral da cor do marcador da rĆ©gua para informaƧƵes." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 473543c0850..1f4f15c5562 100644 --- a/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "Substituir", "label.replaceAllButton": "Substituir Tudo", "label.toggleReplaceButton": "Ativar/desativar modo Substituir", - "title.matchesCountLimit": "Somente os primeiros 999 resultados sĆ£o realƧados, mas todas as operaƧƵes de pesquisa funcionam em todo o texto.", + "title.matchesCountLimit": "Apenas os primeiros {0} resultados serĆ£o destacados, mas todas as operaƧƵes de busca funcionam em todo o texto.", "label.matchesLocation": "{0} de {1}", "label.noResults": "Nenhum resultado" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json index 93f4b43b45c..ce656c20f36 100644 --- a/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Localizar Próxima Seleção", "previousSelectionMatchFindAction": "Localizar Seleção Anterior", "startReplace": "Substituir", - "addSelectionToNextFindMatch": "Adicionar Seleção ao Próximo Localizar CorrespondĆŖncia", - "addSelectionToPreviousFindMatch": "Adicionar Seleção Ć  CorrespondĆŖncia de Localização Anterior", - "moveSelectionToNextFindMatch": "Mover Última Seleção para Próximo Localizar CorrespondĆŖncia", - "moveSelectionToPreviousFindMatch": "Mover Última Seleção para CorrespondĆŖncia de Localização Anterior", - "selectAllOccurrencesOfFindMatch": "Selecionar Todas as OcorrĆŖncias de Localizar CorrespondĆŖncia", - "changeAll.label": "Alterar todas as ocorrĆŖncias", "showNextFindTermAction": "Mostrar Próximo Termo de Busca", "showPreviousFindTermAction": "Mostrar Termo de Busca Anterior" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/ptb/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 4327e5f6744..9dc8bacb232 100644 --- a/i18n/ptb/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "{0} ediƧƵes de formatação feitas na linha {1}", "hint1n": "Feita 1 edição de formatação entre as linhas {0} e {1}", "hintnn": "Feitas {0} ediƧƵes de formatação entre as linhas {1} e {2}", + "no.provider": "Desculpe, mas nĆ£o hĆ” nenhum formatador para '{0}'-arquivos instalados.", "formatDocument.label": "Formatar Documento", "formatSelection.label": "Formatar Seleção" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/ptb/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 0ad65de8863..d05aeee6c34 100644 --- a/i18n/ptb/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "Ir para o Erro ou Aviso Anterior", "editorMarkerNavigationError": "Ferramenta de marcação de edição apresentando error na cor ", "editorMarkerNavigationWarning": "Ferramenta de marcação de edição apresentando adventĆŖncia na cor", + "editorMarkerNavigationInfo": "Cor de informação da ferramenta de navegação do marcador do editor.", "editorMarkerNavigationBackground": "Cor de fundo da ferramenta de marcação de navegação do editor." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index 583be5b3e5c..790c737c8eb 100644 --- a/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Inserir cursor acima", "mutlicursor.insertBelow": "Inserir cursor abaixo", - "mutlicursor.insertAtEndOfEachLineSelected": "Adicionar Cursores ao Final das Linhas" + "mutlicursor.insertAtEndOfEachLineSelected": "Adicionar Cursores ao Final das Linhas", + "addSelectionToNextFindMatch": "Adicionar Seleção ao Próximo Localizar CorrespondĆŖncia", + "addSelectionToPreviousFindMatch": "Adicionar Seleção Ć  CorrespondĆŖncia de Localização Anterior", + "moveSelectionToNextFindMatch": "Mover Última Seleção para Próximo Localizar CorrespondĆŖncia", + "moveSelectionToPreviousFindMatch": "Mover Última Seleção para CorrespondĆŖncia de Localização Anterior", + "selectAllOccurrencesOfFindMatch": "Selecionar Todas as OcorrĆŖncias de Localizar CorrespondĆŖncia", + "changeAll.label": "Alterar todas as ocorrĆŖncias" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/ptb/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..41ad7313b7d --- /dev/null +++ b/i18n/ptb/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "Fechar" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/ptb/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index e8556cb38a8..36476d7e95d 100644 --- a/i18n/ptb/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/ptb/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Cor de fundo de um sĆ­mbolo durante acesso de leitura, como ao ler uma variĆ”vel.", - "wordHighlightStrong": "Cor de fundo de um sĆ­mbolo durante acesso de escrita, como ao escrever uma variĆ”vel." + "wordHighlightStrong": "Cor de fundo de um sĆ­mbolo durante acesso de escrita, como ao escrever uma variĆ”vel.", + "overviewRulerWordHighlightForeground": "VisĆ£o geral da cor do marcador da rĆ©gua para destaques de sĆ­mbolos.", + "overviewRulerWordHighlightStrongForeground": "VisĆ£o geral da cor do marcador da rĆ©gua para gravação de destaques de sĆ­mbolos.", + "wordHighlight.next.label": "Ir para o próximo sĆ­mbolo de destaque", + "wordHighlight.previous.label": "Ir para o sĆ­mbolo de destaque anterior" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index d7ef91038db..28adcb87065 100644 --- a/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "Grupo ao qual pertence este comando", "vscode.extension.contributes.menus": "Contribui itens de menu ao editor", "menus.commandPalette": "Paleta de comandos", + "menus.touchBar": "A barra de toque (somente macOS)", "menus.editorTitle": "Meno do tĆ­tulo editor", "menus.editorContext": "Mostrar o menu de contexto do editor", "menus.explorerContext": "Menu no contexto de explorador de arquivos", "menus.editorTabContext": "Mostrar o menu de contexto do editor", "menus.debugCallstackContext": "O menu de contexto de pilha de chamadas de depuração", "menus.scmTitle": "O menu de tĆ­tulo do controle de fonte", + "menus.scmSourceControl": "O menu do Controle de Código Fonte", "menus.resourceGroupContext": "O menu de contexto do grupo de recursos de controle de fonte", "menus.resourceStateContext": "O menu de contexto de estado de recursos do controle de fonte", "view.viewTitle": "O menu de tĆ­tulo da visualização contribuĆ­da", diff --git a/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json b/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json index 4cec19113d2..0aa4f21b3dd 100644 --- a/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/ptb/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "Argumentos no modo '--goto' deve ser no formato de 'Arquivo(:LINHA(:CARACTERE))'.", - "diff": "Abrir um editor de diff. Requer passar dois caminhos de arquivo como argumentos.", - "goto": "Abra o arquivo no caminho, na linha e caractere (addcionar:linha[:caractere] para o caminho).", + "diff": "Comparar dois arquivos entre si.", + "add": "Adicione pasta(s) para a Ćŗltima janela ativa.", + "goto": "Abra um arquivo no caminho sobre a linha especificada e a posição do caractere.", "locale": "Para localização utilize (ex. en-US ou zh-TW).", "newWindow": "ForƧa uma nova instĆ¢ncia do Código.", "performance": "Comece com o 'Desenvolvedor: Desempenho de inicialização' comando habilitado.", @@ -14,7 +15,7 @@ "reuseWindow": "ForƧar a abertura de um arquivo ou pasta na Ćŗltima janela ativa", "userDataDir": "Especifica o diretório que os dados do usuĆ”rio serĆ£o mantidos, Ćŗtil quando estiver rodando como root.", "verbose": "Imprimir a saĆ­da detalhada (Implica -- esperar).", - "wait": "Aguarde a janela ser fechada antes de retornar.", + "wait": "Espere pelos arquivos a serem fechados antes de retornar.", "extensionHomePath": "Defina o caminho raĆ­z para as extensƵes.", "listExtensions": "Lista de extensƵes instaladas", "showVersions": "Exibir versƵes de extensƵes instaladas, quando estiver usando --list-extension", diff --git a/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index a6c5a37ab05..e90957df5d7 100644 --- a/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "ExtensĆ£o invĆ”lida: pacote.json nao Ć© um arquivo JSON vĆ”lido", - "restartCode": "Por favor reinicie Code antes de reinstalar {0}.", - "installDependeciesConfirmation": "A instalação de '{0}' tambĆ©m inclui suas dependĆŖncias. Gostaria de continuar?", - "install": "Sim", - "doNotInstall": "NĆ£o", + "restartCodeLocal": "Por favor reinicie Code antes de reinstalar {0}.", + "restartCodeGallery": "Por favor reinicie o Code antes de reinstalar.", "uninstallDependeciesConfirmation": "Gostaria de desinstalar '{0}' somente, ou suas dependĆŖncias tambĆ©m?", "uninstallOnly": "Apenas", "uninstallAll": "Todos", diff --git a/i18n/ptb/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/ptb/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 8de8bd11bbf..3f6e49c05ce 100644 --- a/i18n/ptb/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/ptb/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "Eventos de ativação para a extensĆ£o VS Code.", "vscode.extension.activationEvents.onLanguage": "Um evento de ativação emitido sempre que um arquivo que resolve para a linguagem especificada Ć© aberto.", "vscode.extension.activationEvents.onCommand": "Um evento de ativação emitido sempre que o comando especificado for invocado.", - "vscode.extension.activationEvents.onDebug": "Um evento de ativação emitido sempre que uma sessĆ£o de depuração do tipo especificado Ć© iniciada.", + "vscode.extension.activationEvents.onDebug": "Um evento de ativação emitido sempre que um usuĆ”rio estĆ” prestes a iniciar a depuração ou a definir as configuraƧƵes de depuração.", "vscode.extension.activationEvents.workspaceContains": "Um evento de ativação emitido quando uma pasta que contĆ©m pelo menos um arquivo correspondente ao padrĆ£o global especificado Ć© aberta.", "vscode.extension.activationEvents.onView": "Um evento de ativação emitido sempre que o modo de visualização especificado Ć© expandido.", "vscode.extension.activationEvents.star": "Um evento de ativação emitido na inicialização do VS Code. Para garantir uma ótima experiĆŖncia de usuĆ”rio, por favor, use este evento de ativação em sua extensĆ£o somente quando nenhuma outra combinação de eventos de ativação funcionar em seu caso de uso.", diff --git a/i18n/ptb/src/vs/platform/extensions/node/extensionValidator.i18n.json b/i18n/ptb/src/vs/platform/extensions/node/extensionValidator.i18n.json index fe37dd1820f..a49ac3b2df8 100644 --- a/i18n/ptb/src/vs/platform/extensions/node/extensionValidator.i18n.json +++ b/i18n/ptb/src/vs/platform/extensions/node/extensionValidator.i18n.json @@ -17,7 +17,7 @@ "extensionDescription.extensionDependencies": "a propriedade `{0}` pode ser omitida ou deve ser do tipo `string[]`", "extensionDescription.activationEvents1": "a propriedade `{0}` pode ser omitida ou deve ser do tipo `string[]`", "extensionDescription.activationEvents2": "Propriedades '{0}' e '{1}' devem ser especificadas ou devem ambas ser omitidas", - "extensionDescription.main1": "a propriedade `{0}` Ć© opcional ou pode ser do tipo `string`", + "extensionDescription.main1": "a propriedade `{0}` Ć© opcional ou deve ser do tipo `string`", "extensionDescription.main2": "Esperado 'main' ({0}) ser incluĆ­do dentro da pasta da extensĆ£o ({1}). Isto pode fazer a extensĆ£o nĆ£o-portĆ”vel.", "extensionDescription.main3": "propriedades '{0}' e '{1}' devem ser especificadas ou devem ambas ser omitidas", "notSemver": "VersĆ£o da extensĆ£o nĆ£o Ć© compatĆ­vel a semver" diff --git a/i18n/ptb/src/vs/platform/markers/common/problemMatcher.i18n.json b/i18n/ptb/src/vs/platform/markers/common/problemMatcher.i18n.json index 468301da2b6..ccfeff369a4 100644 --- a/i18n/ptb/src/vs/platform/markers/common/problemMatcher.i18n.json +++ b/i18n/ptb/src/vs/platform/markers/common/problemMatcher.i18n.json @@ -33,7 +33,7 @@ "ProblemMatcherParser.noIdentifier": "Erro: a propriedade padrĆ£o se refere a um identificador vazio.", "ProblemMatcherParser.noValidIdentifier": "Erro: a propriedade padrĆ£o {0} nĆ£o Ć© uma variĆ”vel de padrƵes vĆ”lida.", "ProblemMatcherParser.problemPattern.watchingMatcher": "Um problema de correspondĆŖncia deve obrigatoriamente definir padrĆ£o inicial e um padrĆ£o final para monitoramento.", - "ProblemMatcherParser.invalidRegexp": "Erro: a cadeia de caracteres {0} nĆ£o Ć© uma expressĆ£o regular vĆ”lida.\n", + "ProblemMatcherParser.invalidRegexp": "Erro: a cadeia de caracteres {0} nĆ£o Ć© uma expressĆ£o regular vĆ”lida. ", "WatchingPatternSchema.regexp": "A expressĆ£o regular para detectar o inĆ­cio ou o fim de uma tarefa em segundo plano.", "WatchingPatternSchema.file": "O Ć­ndice do grupo de correspondĆŖncia do arquivo. Pode ser omitido.", "PatternTypeSchema.name": "O nome de um padrĆ£o prĆ©-definido ou contribuĆ­do.", diff --git a/i18n/ptb/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/ptb/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..6e7de5809be --- /dev/null +++ b/i18n/ptb/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "Contribui com a extensĆ£o de cores temĆ”ticas definidas", + "contributes.color.id": "O identificador da cor temĆ”tica", + "contributes.color.id.format": "Identificadores devem estar no formato aa [.bb] *", + "contributes.color.description": "A descrição da cor temĆ”tica", + "contributes.defaults.light": "A cor padrĆ£o para temas claros. Um valor de cor em hexadecimal (#RRGGBB[AA]) ou o identificador de uma cor temĆ”tica que fornece o padrĆ£o.", + "contributes.defaults.dark": "A cor padrĆ£o para temas escuros. Um valor de cor em hexadecimal (#RRGGBB[AA]) ou o identificador de uma cor temĆ”tica que fornece o padrĆ£o.", + "contributes.defaults.highContrast": "A cor padrĆ£o para temas de alto contraste. Um valor de cor em hexadecimal (#RRGGBB[AA]) ou o identificador de uma cor temĆ”tica que fornece o padrĆ£o.", + "invalid.colorConfiguration": "'configuration.colors' deve ser uma matriz", + "invalid.default.colorType": "{0} deve ser um valor de cor em hexadecimal (#RRGGBB [AA] ou #RGB[A]) ou o identificador de uma cor temĆ”tica que fornece o padrĆ£o.", + "invalid.id": "'configuration.colors.id' deve ser definido e nĆ£o pode estar vazio", + "invalid.id.format": "'configuration.colors.id' deve seguir a palavra [.word] *", + "invalid.description": "'configuration.colors.description' deve ser definido e nĆ£o pode estar vazio", + "invalid.defaults": "'configuration.colors.defaults' deve ser definido e deve conter 'claro', 'escuro' e 'Alto Contraste'" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json index e692515c186..6f399a88a06 100644 --- a/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/ptb/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "Formato invĆ”lido de cor. Use #RGB, #RGBA, #RRGGBB ou #RRGGBBAA", "schema.colors": "Cores usadas no workbench.", "foreground": "Cor de primeiro plano geral. Essa cor Ć© só usada se nĆ£o for substituĆ­da por um componente.", "errorForeground": "Cor de primeiro plano geral para mensagens de erro. Essa cor Ć© só usada se nĆ£o for substituĆ­da por um componente.", @@ -45,6 +44,7 @@ "listHoverForeground": "Primeiro plano da Lista/Ɓrvoce quando passar sobre itens usando o mouse.", "listDropBackground": "Cor de fundo ao arrastar e soltar de Lista/Ć”rvore quando movendo itens usando o mouse.", "highlight": "Cor de primeiro plano de Lista/Ć”rvore de destaques de correspondĆŖncias ao pesquisar na Ć”rvore/lista.", + "invalidItemForeground": "Cor de primeiro plano da lista/Ć”rvore para itens invĆ”lidos, por exemplo, uma raiz nĆ£o resolvida no explorador.", "pickerGroupForeground": "Seletor rĆ”pido de cor para rótulos de agrupamento.", "pickerGroupBorder": "Seletor rĆ”pido de cor para bordas de agrupamentos.", "buttonForeground": "Cor de primeiro plano do botĆ£o.", @@ -85,5 +85,7 @@ "mergeBorder": "Cor da borda dos cabeƧalhos e separadores estĆ£o em conflito de mesclagem em linha.", "overviewRulerCurrentContentForeground": "Cor de fundo de rĆ©gua de visuaização atual em conflito de mesclagem em linha.", "overviewRulerIncomingContentForeground": "Cor de fundo de rĆ©gua de visuaização de entrada em conflito de mesclagem em linha.", - "overviewRulerCommonContentForeground": "Ancestral comum da cor da rĆ©gua deĀ visĆ£o geral para conflitos de mesclagem inline." + "overviewRulerCommonContentForeground": "Ancestral comum da cor da rĆ©gua deĀ visĆ£o geral para conflitos de mesclagem inline.", + "overviewRulerFindMatchForeground": "VisĆ£o geral da cor do marcador da rĆ©gua para buscas correspondentes.", + "overviewRulerSelectionHighlightForeground": "VisĆ£o geral da cor do marcador da rĆ©gua para a seleção de destaques" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/ptb/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..33e05e1228b --- /dev/null +++ b/i18n/ptb/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Ɓrea de Trabalho de Código", + "untitledWorkspace": "Sem tĆ­tulo (espaƧo de trabalho)", + "workspaceNameVerbose": "{0} (EspaƧo de trabalho)", + "workspaceName": "{0} (EspaƧo de trabalho) " +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/ptb/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..2d1418035ea --- /dev/null +++ b/i18n/ptb/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "visualizaƧƵes devem ser uma matriz", + "requirestring": "a propriedade `{0}` Ć© obrigatória e deve ser do tipo `string`", + "optstring": "a propriedade `{0}` Ć© opcional ou deve ser do tipo `string`", + "vscode.extension.contributes.view.id": "Identificador da visualiozação. Use isto para registrar um provedor de dados atravĆ©s de 'vscode.window.registerTreeDataProviderForView' API. TambĆ©m para acionar ativando sua extensĆ£o registrando o evento 'onView: ${id}' para 'activationEvents'.", + "vscode.extension.contributes.view.name": "O nome legĆ­vel da visualização. SerĆ” mostrado", + "vscode.extension.contributes.view.when": "Condição que deve ser verdadeira para mostrar esta visualização", + "vscode.extension.contributes.views": "Contribui visualizaƧƵes ao editor", + "views.explorer": "Visualização do explorador", + "views.debug": "Visualizar Depurador", + "locationId.invalid": "'{0}' nĆ£o Ć© um local vĆ”lido de visualização", + "duplicateView1": "NĆ£o Ć© possĆ­vel registrar vĆ”rios modos de exibição com a mesma id '{0}' no local '{1}'", + "duplicateView2": "Uma exibição com id '{0}' jĆ” estĆ” registrada no local '{1}'" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/ptb/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..d521fce97ff --- /dev/null +++ b/i18n/ptb/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "ExtensĆ£o '{1}' falhou ao ativar. Motivo: dependĆŖncia desconhecida '{0}'.", + "failedDep1": "ExtensĆ£o '{1}' falhou ao ativar. Motivo: a dependĆŖncia '{0}' falhou ao ativar.", + "failedDep2": "ExtensĆ£o '{0}' falhou ao ativar. Motivo: mais de 10 nĆ­veis de dependĆŖncias (provavelmente um laƧo de dependĆŖncia).", + "activationError": "Ativação da extensĆ£o `{0}` falhou: {1}." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json index cbebd215cb4..18546fb98ab 100644 --- a/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,24 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "Abrir arquivo...", "openFolder": "Abrir Pasta...", "openFileFolder": "Abrir...", - "reload": "&&Recarregar", - "cancel": "Cancelar", - "newWorkspaceFormExisting": "Novo espaƧo de trabalho existentes...", - "select": "&&Selecionar", - "selectWorkspace": "Selecionar pastas para espaƧo de trabalho", - "addSupported": "Para abrir vĆ”rias pastas,Ā Ć© necessĆ”rio recarregarĀ a janela.", "addFolderToWorkspace": "Adicionar pasta ao espaƧo de trabalho...", "add": "&& Adicionar", "addFolderToWorkspaceTitle": "Adicionar pasta ao espaƧo de trabalho", + "globalRemoveFolderFromWorkspace": "Remover pasta da Ć”rea de trabalho", "removeFolderFromWorkspace": "Remover pasta da Ć”rea de trabalho", + "openFolderSettings": "Abrir configuraƧƵes da pasta", "saveWorkspaceAsAction": "Salvar o espaƧo de trabalho como...", - "saveEmptyWorkspaceNotSupported": "Por favor, abra um espaƧo de trabalho antes de salvar.", - "saveNotSupported": "Para salvar umĀ espaƧo de trabalho,Ā \nĆ© necessĆ”rio recarregar a janela.", "save": "&&Salvar", "saveWorkspace": "Salvar o espaƧo de trabalho", "openWorkspaceAction": "Abrir o EspaƧo de Trabalho...", - "newWorkspace": "Novo espaƧo de trabalho...", - "openWorkspaceConfigFile": "Abrir o Arquivo de Configuração do EspaƧo de Trabalho" + "openWorkspaceConfigFile": "Abrir o Arquivo de Configuração do EspaƧo de Trabalho", + "openFolderAsWorkspaceInNewWindow": "Abrir a pasta como espaƧo de trabalho em nova janela", + "workspaceFolderPickerPlaceholder": "Selecione a pasta de trabalho" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 8dab311a65f..5a931aa160b 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "Remover da Barra de Atividades", - "keepInActivityBar": "Manter na Barra de Atividades", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Ocultar da barra de atividade", + "keepInActivityBar": "Manter na Barra de Atividades", "additionalViews": "VisualizaƧƵes Adicionais", "numberBadge": "{0} ({1})", "manageExtension": "Gerenciar ExtensĆ£o", diff --git a/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 577ad33d0b4..f42981ec157 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Ocultar a Barra de Atividades", - "activityBarAriaLabel": "Chave do Modo de exibição Ativo", "globalActions": "AƧƵes globais" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..4a4304f83f0 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "Chave do Modo de exibição Ativo" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..d64f23c4102 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "VisualizaƧƵes Adicionais", + "numberBadge": "{0} ({1})", + "manageExtension": "Gerenciar ExtensĆ£o", + "titleKeybinding": "{0} ({1})", + "hide": "Ocultar", + "keep": "Manter", + "toggle": "Alternar Visualização Fixa" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index dbfae18a9bf..d1d8a425227 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "textEditor": "Editor de texto", + "textEditor": "Editor de Texto", "textDiffEditor": "Editor de Diferentes Textos", "binaryDiffEditor": "Editor de DiferenƧa BinĆ”ria", "sideBySideEditor": "Editor Lado a lado", @@ -12,5 +12,6 @@ "groupTwoPicker": "Mostrar editores no segundo grupo", "groupThreePicker": "Mostrar editores no terceiro grupo", "allEditorsPicker": "Mostrar todos editores abertos", - "view": "Exibir" + "view": "Exibir", + "file": "Arquivo" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index fc5507b3a8c..7c10c0e60fd 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "Abrir editor anterior no grupo", "navigateNext": "AvanƧar", "navigatePrevious": "Voltar", + "navigateLast": "Ir para o Ćŗltimo", "reopenClosedEditor": "Reabrir Editor Fechado", "clearRecentFiles": "Limpar Abertos Recentemente", "showEditorsInFirstGroup": "Mostrar editores no primeiro grupo", @@ -49,8 +50,8 @@ "openPreviousRecentlyUsedEditor": "Abrir o Editor Anterior Recentemente Utilizado", "clearEditorHistory": "Limpar Histórico do Editor", "focusLastEditorInStack": "Abrir Último Editor do Grupo", - "moveEditorLeft": "Mover Editor para Esquerda", - "moveEditorRight": "Mover Editor para Direita", - "moveEditorToPreviousGroup": "Mover Editor para o Grupo Anterior", + "moveEditorLeft": "Mover o Editor para a Esquerda", + "moveEditorRight": "Mover o Editor para a Direita", + "moveEditorToPreviousGroup": "Mover o Editor para o Grupo Anterior", "moveEditorToNextGroup": "Mover o Editor para o Próximo Grupo" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index c6a90d88542..c4530706af9 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -9,6 +9,6 @@ "groupThreeVertical": "Direita", "groupOneHorizontal": "Topo", "groupTwoHorizontal": "Centro", - "groupThreeHorizontal": "Baixo", + "groupThreeHorizontal": "RodapĆ©", "editorOpenError": "NĆ£o foi possĆ­vel abrir '{0}': {1}." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 7ec5ce6904c..fd2c0fd6d01 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "Tabulação Move o Foco", - "screenReaderDetected": "Leitor de Tela Detectado", + "screenReaderDetected": "Leitor de tela otimizado", "screenReaderDetectedExtra": "Se vocĆŖ nĆ£o estiver usando um leitor de tela, por favor altere a configuração `editor.accessibilitySupport` para \"desligado\".", "disableTabMode": "Desativar o modo de acessibilidade", "gotoLine": "Ir para linha", @@ -47,5 +47,11 @@ "reopenWithEncoding": "Reabrir com codificação", "guessedEncoding": "Adivinhado a partir do conteĆŗdo", "pickEncodingForReopen": "Selecione a codificaçãodo arquivo para reabrir o arquivo.", - "pickEncodingForSave": "Selecione a codificação do arquivo para Salvar Com" + "pickEncodingForSave": "Selecione a codificação do arquivo para Salvar Com", + "screenReaderDetectedExplanation.title": "Leitor de tela otimizado", + "screenReaderDetectedExplanation.question": "VocĆŖ estĆ” usando um leitor de tela para operar o VS Code?", + "screenReaderDetectedExplanation.answerYes": "Sim", + "screenReaderDetectedExplanation.answerNo": "NĆ£o", + "screenReaderDetectedExplanation.body1": "O VS Code agora estĆ” otimizado paraĀ uso com um leitor de tela.", + "screenReaderDetectedExplanation.body2": "Alguns recursos do editor terĆ£o comportamento diferente: por exemplo, a palavra envoltura, dobradura, auto fechamento de colchetes, etc." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 1f98f38c47e..7a302129cae 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Fechar Painel", "togglePanel": "Alternar Painel", "focusPanel": "Foco no Painel", + "toggledPanelPosition": "Alternar posição do painel", + "moveToRight": "Mover para direita", + "moveToBottom": "Mover para baixo", "toggleMaximizedPanel": "Alternar Painel Maximizado", "maximizePanel": "Maximizar Tamanho do Painel", "minimizePanel": "Restaurar tamanho do Painel", diff --git a/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 4a2adabf5a6..b997093f4f8 100644 --- a/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "O comando '{0}' nĆ£o estĆ” habilitado e nĆ£o pode ser executado.", "manageExtension": "Gerenciar ExtensĆ£o" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..32207b28d40 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} aƧƵes " +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..d210a742451 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} aƧƵes ", + "hideView": "Ocultar a Barra Lateral" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..b7201e3d4af --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "Uma exibição com id '{0}' jĆ” estĆ” registrada na localização '{1}'" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..a2d4770e337 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "Ocultar a Barra Lateral" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/common/theme.i18n.json b/i18n/ptb/src/vs/workbench/common/theme.i18n.json index f07de120073..6f602a84f32 100644 --- a/i18n/ptb/src/vs/workbench/common/theme.i18n.json +++ b/i18n/ptb/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "Cor de fundo da guia ativa. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editor.", "tabInactiveBackground": "Cor de fundo da guia inativa. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editor.", "tabBorder": "Borda para separar uma guia das outras. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editor.", + "tabActiveBorder": "Borda para destacar guias ativas. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editores.", + "tabActiveUnfocusedBorder": "Borda para destacar guias ativas em um grupo fora de foco. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editores.", "tabActiveForeground": "Cor de primeiro plano da guia ativa em um grupo ativo. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editor.", "tabInactiveForeground": "Cor de primeiro plano da guia inativa em um grupo ativo. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editor.", - "tabUnfocusedActiveForeground": "Cor de primeiro plano da aba ativa em um grupo inativo. As abas sĆ£o recipientes para editores na Ć”rea do editor. VĆ”rias abas podem ser abertas em um grupo de editor. Pode haver vĆ”rios grupos de editor.", - "tabUnfocusedInactiveForeground": "Cor de primeiro plano da aba inativa em um grupo inativo. As abas sĆ£o recipientes para editores na Ć”rea do editor. VĆ”rias abas podem ser abertas em um grupo de editor. Pode haver vĆ”rios grupos de editor.", + "tabUnfocusedActiveForeground": "Cor de primeiro plano da aba ativa em um grupo fora de foco. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editores.", + "tabUnfocusedInactiveForeground": "Cor de primeiro plano da aba inativa em um grupo fora de foco. As guias sĆ£o os recipientes para editores na Ć”rea do editor. VĆ”rias guias podem ser abertas em um grupo de editores. Podem haver vĆ”rios grupos de editores.", "editorGroupBackground": "Cor de fundo de um grupo de editor. Grupos de editor sĆ£o os recipientes dos editores. A cor de fundo Ć© mostrada ao arrastar o editor de grupos ao redor.", "tabsContainerBackground": "Cor de fundo do cabeƧalho do tĆ­tulo do grupo de editor quando as guias sĆ£o habilitadas. Grupos de editor sĆ£o os recipientes dos editores.", "tabsContainerBorder": "Cor da borda do cabeƧalho do tĆ­tulo do grupo de editor quando as guias estĆ£o habilitadas. Grupos de editor sĆ£o os recipientes dos editores.", @@ -18,13 +20,13 @@ "editorGroupBorder": "Cor para separar mĆŗltiplos grupos de editor de outro. Grupos de editor sĆ£o os recipientes dos editores.", "editorDragAndDropBackground": "Cor de fundo ao arrastar editores. A cor deve ter transparĆŖncia para que o conteĆŗdo do editor ainda possa ser visto.", "panelBackground": "Cor de fundo do painel. Os painĆ©is sĆ£o mostrados abaixo da Ć”rea do editor e contĆ©m visualizaƧƵes como saĆ­da e terminal integrado.", - "panelBorder": "Cor da borda do painel no topo separando do editor. Os painĆ©is sĆ£o mostrados abaixo da Ć”rea do editor e contĆ©m visualizaƧƵes como saĆ­da e terminal integrado.", "panelActiveTitleForeground": "Cor do tĆ­tulo para o painel ativo. Os painĆ©is sĆ£o mostrados abaixo da Ć”rea do editor e contĆ©m visualizaƧƵes como saĆ­da e terminal integrado.", "panelInactiveTitleForeground": "Cor do tĆ­tulo para o painel inativo. Os painĆ©is sĆ£o mostrados abaixo da Ć”rea do editor e contĆ©m visualizaƧƵes como saĆ­da e terminal integrado.", "panelActiveTitleBorder": "Cor da borda para o tĆ­tulo do painel ativo. Os painĆ©is sĆ£o mostrados abaixo da Ć”rea do editor e contĆ©m visualizaƧƵes como saĆ­da e terminal integrado.", - "statusBarForeground": "Cor do primeiro plano da barra de status. A barra de status Ć© mostrada na parte inferior da janela.", + "panelDragAndDropBackground": "Cor de resposta ao arrastar e soltar itens de tĆ­tulo de painel. A cor deve possuir transparĆŖncia para que os registros no painel ainda possam brilhar atravĆ©s dela. Os painĆ©is sĆ£o exibidos abaixo da Ć”rea do editor e contĆ©m visualizaƧƵes como a saĆ­da e o terminal integrado.", + "statusBarForeground": "Cor de primeiro plano da barra de status quando um espaƧo de trabalho Ć© aberto. A barra de status Ć© mostrada na parte inferior da janela.", "statusBarNoFolderForeground": "Cor do primeiro plano da barra de status quando nenhuma pasta estĆ” aberta. A barra de status Ć© mostrada na parte inferior da janela.", - "statusBarBackground": "Cor de fundo da barra de status padrĆ£o. A barra de status Ć© mostrada na parte inferior da janela.", + "statusBarBackground": "Cor de fundo da barra de status quando um espaƧo de trabalho Ć© aberto. A barra de status Ć© mostrada na parte inferior da janela.", "statusBarNoFolderBackground": "Cor de fundo da barra de status quando nenhuma pasta estĆ” aberta. A barra de status Ć© mostrada na parte inferior da janela.", "statusBarBorder": "Cor da borda da barra de status que separa a barra lateral e o editor.A barra de status Ć© mostrada na parte inferior da janela.", "statusBarNoFolderBorder": "Cor da borda da barra de status separando para a barra lateral e editor quando nenhuma pasta Ć© aberta. A barra de status Ć© mostrada na parte inferior da janela.", diff --git a/i18n/ptb/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/ptb/src/vs/workbench/electron-browser/actions.i18n.json index adcd512f7bf..ac9c586bc14 100644 --- a/i18n/ptb/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/ptb/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "NavegarĀ para a VisualizaçãoĀ Acima", "navigateDown": "NavegarĀ para a VisualizaçãoĀ Abaixo", "increaseViewSize": "Aumentar o Tamanho da Visualização Atual", - "decreaseViewSize": "Diminuir o Tamanho da Visualização Atual" + "decreaseViewSize": "Diminuir o Tamanho da Visualização Atual", + "showPreviousTab": "Mostrar a guia da janela anterior", + "showNextWindowTab": "Mostrar guia da próxima janela", + "moveWindowTabToNewWindow": "Mover a guia da janela para a nova janela", + "mergeAllWindowTabs": "Mesclar todas as janelas", + "toggleWindowTabsBar": "Alternar a Barra de Guias da Janela" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/ptb/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..80686b2c898 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "Configurar Idioma", + "displayLanguage": "Define o idioma de exibição do VSCode.", + "doc": "Veja {0} para obter uma lista dos idiomas suportados.", + "restart": "Modificar o valor requer reinicialização do VSCode.", + "fail.createSettings": "NĆ£o foi possĆ­vel criar '{0}' ({1}).", + "JsonSchema.locale": "O idioma da interface do usuĆ”rio a ser usada." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json index 3774fceeb1a..296a574f1ad 100644 --- a/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,17 +10,25 @@ "workspaces": "EspaƧos de trabalho", "developer": "Desenvolvedor", "showEditorTabs": "Controla se os editores abertos devem ou nĆ£o serem exibidos em abas.", + "workbench.editor.labelFormat.default": "Mostra o nome do arquivo. Quando guias estiverem ativadas e dois arquivos em um grupo tiverem o mesmo nome, a seção de distinção para cada caminho de arquivo Ć© adicionada. Quando guias estiverem desativadas, o caminho relativo para a pasta do espaƧo de trabalho Ć© exibida se o editor estiver ativo.", + "workbench.editor.labelFormat.short": "Mostrar o nome do arquivo seguido pelo nome do diretório.", + "workbench.editor.labelFormat.medium": "Mostra o nome do arquivo seguido de seu caminho relativo para a pasta de trabalho.", + "workbench.editor.labelFormat.long": "Mostrar o nome do arquivo seguido pelo seu caminho absoluto.", + "tabDescription": "Controla o formato do rótulo para um editor. Alterar essa configuração pode por exemplo tornar mais fĆ”cil entender a localização de um arquivo:\n- curto: 'parent'\n- mĆ©dio: 'workspace/src/parent'\n- longa: '/ home/user/workspace/src/parent'\n- padrĆ£o: '... /parent, quando outra guia compartilha o mesmo tĆ­tulo, ou o caminho relativo do espaƧo de trabalho se as guias estĆ£o desabilitadas", "editorTabCloseButton": "Controla a posição dos botƵes de fechar das abas do editor ou os desabilita quando configurados para 'desligado'.", "showIcons": "Controla se os editores abertos devem ou nĆ£o ser exibidos com um Ć­cone. Requer um tema de Ć­cone para ser habilitado. ", - "enablePreview": "Controla se os editores abertos sĆ£o exibidos como visualização. Editores de visualização sĆ£o reutilizados atĆ© que eles sejam preservados (por exemplo, atravĆ©s de um duplo clique ou edição).", + "enablePreview": "Controla se editores abertos mostram uma visualização. Editores de visualização sĆ£o reutilizados atĆ© que elesĀ sejam mantidos (por exemplo, atravĆ©s do duplo clique ou edição) e aparecerem com um estilo de fonte em itĆ”lico.", "enablePreviewFromQuickOpen": "Controla se os editores abertos da Abertura RĆ”pida sĆ£o exibidos como visualização. Os editores de visualização sĆ£o reutilizados atĆ© serem preservados (por exemplo, atravĆ©s de um duplo clique ou edição).", - "editorOpenPositioning": "Controla onde os editores serĆ£o abertos. Escolha 'esquerda' ou 'direita' para abrir os editores Ć  esquerda ou Ć  direita do \neditor ativo. Selecione 'primeiro' ou 'Ćŗltimo' para abrir os editores independentemente do atual.", + "editorOpenPositioning": "Controla onde os editores serĆ£o abertos. Escolha 'esquerda' ou 'direita' para abrir os editores Ć  esquerda ou Ć  direita do editor ativo. Selecione 'primeiro' ou 'Ćŗltimo' para abrir os editores independentemente do ativo no momento.", "revealIfOpen": "Controla se um editor Ć© exibido em qualquer um dos grupos, se aberto. Se desabilitado, um editor serĆ” aberto preferencialmente no grupo de editores ativo. Se habilitado, um editor jĆ” aberto serĆ” exibido no grupo de editores ativo, ao invĆ©s de ser aberto novamente. Note que hĆ” alguns casos onde esta configuração Ć© ignorada, por exemplo, quando for forƧada a abertura de um editor em um grupo especĆ­fico ou ao lado do grupo atualmente ativo.", - "commandHistory": "Controla o nĆŗmero de comandos recentemente usados mantidos no histórico para a paleta de comandos. Definir como 0 para desativar o histórico de comandos.", + "commandHistory": "Controla o nĆŗmero de comandos usados recentemente a serem mantidos no histórico da paleta de comando. Definir como 0 para desativar o histórico de comandos.", "preserveInput": "Controla seĀ aĀ Ćŗltima entrada digitada na paleta de comandos deve ser restaurada ao abri-la da próxima vez.", "closeOnFocusLost": "Controla se Abertura RĆ”pida deve fechar automaticamente caso perca o foco.", "openDefaultSettings": "Controla se a abertura de configuraƧƵes tambĆ©m abre um editor mostrando todas as configuraƧƵes padrĆ£o.", + "experimentalFuzzySearchEndpoint": "Indica o ponto de extremidade usar para a busca de definiƧƵes experimental.", + "experimentalFuzzySearchKey": "Indica a chave a ser usada para a busca experimental de configuraƧƵes.", "sideBarLocation": "Controla a localização da barra lateral. Ele pode ser exibido Ć  esquerda ou Ć  direita da Ć”rea de trabalho.", + "panelLocation": "Painle de controle de localização. Pode tambĆ©m ser visualizado na parte inferior ou a direita da Ć”rea de trabalho.", "statusBarVisibility": "Controla a visibilidade da barra de status na parte inferior da Ć”rea de trabalho.", "activityBarVisibility": "Controla a visibilidade da barra de atividades na Ć”rea de trabalho.", "closeOnFileDelete": "Controla se os editores que mostram um arquivo devem fechar automaticamente quanto o arquivo Ć© apagado ou renomeado por algum outro processo. Desativar isso manterĆ” o editor aberto como sujo neste evento. Note que apagar do aplicativo sempre fecharĆ” o editor e os arquivos sujos nunca fecharĆ£o para preservar seus dados.", @@ -33,7 +41,7 @@ "window.openFilesInNewWindow.on": "Arquivos serĆ£o abertos em uma nova janela", "window.openFilesInNewWindow.off": "Arquivos serĆ£o abertos em uma nova janela com a pasta de arquivos aberta ou com a Ćŗltima janela ativa.", "window.openFilesInNewWindow.default": "Os arquivos serĆ£o abertos na janela com a pasta de arquivos aberta ou a Ćŗltima janela ativa, a menos que seja aberto atravĆ©s do dock ou do finder (somente macOS)", - "openFilesInNewWindow": "Controla se os arquivos devem ser abertos em uma nova janela\n- padrĆ£o: os arquivos serĆ£o abertos em uma nova janela com a pasta de arquivos aberta ou na Ćŗltima janela ativa, a menos que seja aberta atravĆ©s do dock ou do finder (apenas macOS)\n- ligado: os arquivos serĆ£o abertos em uma nova janela\n- desligado: os arquivos serĆ£o abertos em uma janela com a pasta de arquivos aberta ou a Ćŗltima janela ativa\nNota que ainda podem haver casos em que esta configuração serĆ” ignorada (por exemplo, quando estiver usando as opƧƵes de linha de comando -new-window ou -reuse-window).", + "openFilesInNewWindow": "Controla se os arquivos devem ser abertos em uma nova janela\n- padrĆ£o: os arquivos serĆ£o abertos em uma nova janela com a pasta de arquivos aberta ou na Ćŗltima janela ativa, a menos que seja aberta atravĆ©s do dock ou do finder (apenas macOS)\n- ligado: os arquivos serĆ£o abertos em uma nova janela\n- desligado: os arquivos serĆ£o abertos em uma janela com a pasta de arquivos aberta ou a Ćŗltima janela ativa\nNote que ainda podem haver casos em que esta configuração serĆ” ignorada (por exemplo, quando estiver usando as opƧƵes de linha de comando -new-window ou -reuse-window).", "window.openFoldersInNewWindow.on": "As pastas serĆ£o abertas em uma nova janela", "window.openFoldersInNewWindow.off": "As pastas substituirĆ£o a Ćŗltima janela ativa", "window.openFoldersInNewWindow.default": "As pastas serĆ£o abertas em uma nova janela, a menos que uma pasta seja selecionada dentro do aplicativo (por exemplo, atravĆ©s do menu Arquivo)", @@ -45,7 +53,7 @@ "restoreWindows": "Controla como as janelas serĆ£o reabertas após uma reinicialização. Selecione 'nenhum' para sempre iniciar com uma Ć”rea de trabalho vazia, 'um' para reabrir a Ćŗltima janela que vocĆŖ trabalhou, 'pastas' para reabrir todas as janelas que tinham pastas abertas ou 'todos' para reabrir todas as janelas da sua Ćŗltima sessĆ£o.", "restoreFullscreen": "Controla se uma janela deve ser restaurada em modo de tela cheia se ela foi finalizada em modo de tela cheia.", "zoomLevel": "Ajusta o nĆ­vel de zoom da janela. O tamanho original Ć© 0 e cada aumento (por exemplo, 1) ou redução (por exemplo, -1) representa um zoom 20% maior ou menor. VocĆŖ tambĆ©m pode digitar decimais para ajustar o nĆ­vel de zoom com uma granularidade mais fina.", - "title": "Controla o tĆ­tulo de janela baseado no editor do ativo. VariĆ”veis sĆ£o substituĆ­das com base no contexto:\n${activeEditorShort}: por exemplo, MyFile.txt \n${activeEditorMedium}: por exemplo, myFolder/myFile.txt \n${activeEditorLong}: por exemplo, /Users/Development/myProject/myFolder/myFile.txt \n${folderName}: por exemplo myFolder \n${folderPath}: por exemplo, /Users/Development/myFolder \n${rootName}: por exemplo, myFolder1, myFolder2, myFolder3 \n${rootPath}: por exemplo, /Users/Development/myWorkspace \n${appName}: por exemplo, VS Code \n${dirty}: um indicador que mostra se o editor ativo estĆ” modificado\n${separator}: um separador condicional (\"-\") que Ć© mostrado apenas quando cercado por variĆ”veis com valores", + "title": "Controla o tĆ­tulo de janela baseado no editor ativo. VariĆ”veis sĆ£o substituĆ­das com base no contexto: \n${activeEditorShort}: o nome do arquivo (por exemplo, MyFile txt)\n${activeEditorMedium}: o caminho do arquivo relativo Ć  pasta da Ć”rea de trabalho (por exemplo, myFolder/myFile.txt) \n${activeEditorLong}: o caminho completo do arquivo (por exemplo, /Users/Development/myProject/myFolder/myFile.txt) \n${folderName}: nome da pasta de trabalho em que o arquivo estĆ” contido (por exemplo, myFolder) \n${folderPath}: caminho do arquivo da pasta de trabalho em que o arquivo estĆ” contido (por exemplo, /Users/Development/myFolder) {\n$(rootName}: nome do espaƧo de trabalho (por exemplo, myFolder ou myWorkspace)\n${rootPath}: caminho do espaƧo de trabalho (por exemplo, /Users/Development/myWorkspace) \n${appName}: por exemplo, VS Code\n${dirty}: um indicador se o editor ativo foi modificado\n${separator}: um separador condicional (\"-\") que Ć© mostrado apenas quando cercado por variĆ”veis com valores", "window.newWindowDimensions.default": "Abrir novas janelas no centro da tela.", "window.newWindowDimensions.inherit": "Abrir novas janelas com a mesma dimensĆ£o da Ćŗltima janela ativa.", "window.newWindowDimensions.maximized": "Abrir novas janelas maximizadas.", diff --git a/i18n/ptb/src/vs/workbench/electron-browser/window.i18n.json b/i18n/ptb/src/vs/workbench/electron-browser/window.i18n.json index 0c134329339..8a03ff87882 100644 --- a/i18n/ptb/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/ptb/src/vs/workbench/electron-browser/window.i18n.json @@ -9,7 +9,5 @@ "cut": "Recortar", "copy": "Copiar", "paste": "Colar", - "selectAll": "Selecionar Tudo", - "confirmOpen": "Tem certeza que deseja abrir {0} espaƧos de trabalho?", - "confirmOpenButton": "&&Abrir" + "selectAll": "Selecionar Tudo" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 2426c492d44..952f46dbb83 100644 --- a/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Se uma linha corresponder a esse padrĆ£o, entĆ£o seu recuo nĆ£o deve ser mudado e ela nĆ£o deve ser avaliada contra as outras regras.", "schema.indentationRules.unIndentedLinePattern.pattern": "O padrĆ£o RegExp para unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Os rótulos RegExp para unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Deve corresponder ao padrĆ£o `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Deve corresponder ao padrĆ£o `/^([gimuy]+)$/`.", + "schema.folding": "As configuraƧƵes de dobragem da linguagem.", + "schema.folding.offSide": "O enquadramento para a regra de impedimento se blocos nessa linguagem sĆ£o expressados pela sua identação. Se definido, linhas em branco pertencem ao bloco subsequente.", + "schema.folding.markers": "Linguagem especĆ­fica de marcadores de aninhamento como '#region' e '#endregion'. As expressƵes regulares de inĆ­cio e final serĆ£o testadas contra o conteĆŗdo de todas as linhas e devem ser planejadas de forma eficiente", + "schema.folding.markers.start": "O padrĆ£o RegExp para o marcador de inĆ­cio. O regexp deve comeƧar com '^'.", + "schema.folding.markers.end": "O padrĆ£o RegExp para o marcador final. O regexp deve comeƧar com '^'." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..90537b96001 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "Visualização: Ativar/Desativar Minimapa" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index 217bdf1c04e..2b5be03ac19 100644 --- a/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "Alternar caracteres de controle" + "toggleRenderControlCharacters": "Visualização: Ativar/Desativar Caracteres de Controle" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 453104fcc6d..6ea4f0fca72 100644 --- a/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "Alternar EspaƧo em Branco Renderizado" + "toggleRenderWhitespace": "Visualização: Ativar/Desativar Renderização de EspaƧos em Branco" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 01955c44965..1b924639633 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "depurar {0}", "debugAriaLabel": "Digite um nome de uma configuração de lanƧamento para ser executado.", + "addConfigTo": "Adicionar Configuração ({0})...", + "addConfiguration": "Adicionar Configuração...", "noConfigurationsMatching": "NĆ£o hĆ” configuraƧƵes de depuração correspondentes", "noConfigurationsFound": "ConfiguraƧƵes de depuração nĆ£o encontradas. Por favor, crie um arquivo 'launch.json'." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..86ae4403f16 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "Foco em VariĆ”veis", + "debugFocusWatchView": "Foco em Monitoramento", + "debugFocusCallStackView": "Foco em Pilha de Chamadas", + "debugFocusBreakpointsView": "Foco em Pontos de Interrupção" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 05e76d32185..3908acc5028 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "ConfiguraƧƵes para gerar o 'launch.json' inicial.", "vscode.extension.contributes.debuggers.languages": "Lista de idiomas para os quais a extensĆ£o de depuração pode ser considerada o \"depurador padrĆ£o\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Se especificado VS Code chamarĆ” este comando para determinar o caminho do executĆ”vel do adaptador de depuração e os argumentos para passar.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Se especificado VS Code chamarĆ” este comando para as aƧƵes de \"depurar\" ou \"executar\" direcionadas para esta extensĆ£o.", "vscode.extension.contributes.debuggers.configurationSnippets": "Trechos de código para adicionar novas configuraƧƵes em 'launch.json'.", "vscode.extension.contributes.debuggers.configurationAttributes": "ConfiguraƧƵes de esquema JSON para validar 'launch.json'.", "vscode.extension.contributes.debuggers.windows": "ConfiguraƧƵes especĆ­ficas do Windows.", diff --git a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index bedcd587a9b..4904ae81309 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,14 +12,15 @@ "breakpointRemoved": "Ponto de interrupção removido, linha {0}, arquivo {1}", "compoundMustHaveConfigurations": "Composição deve ter o atributo \"configurations\" definido para iniciar vĆ”rias configuraƧƵes.", "configMissing": "Configuração '{0}' nĆ£o tem 'launch.json'.", + "debugRequestNotSupported": "Atributo '{0}' tem um valor sem suporte '{1}' na configuração de depuração escolhida.", + "debugRequesMissing": "Atributo '{0}' estĆ” faltando para a configuração de depuração escolhida.", "debugTypeNotSupported": "Tipo de depuração configurado '{0}' nĆ£o Ć© suportado.", - "debugTypeMissing": "Falta a propriedade 'type' para a configuração de lanƧamento escolhida.", + "debugTypeMissing": "Falta a propriedade 'tipo' para a configuração de lanƧamento escolhida.", + "debugAnyway": "Depurar mesmo assim", "preLaunchTaskErrors": "Erros de build foram detectados durante a preLaunchTask '{0}'.", "preLaunchTaskError": "Erro de build foi detectado durante a preLaunchTask '{0}'.", "preLaunchTaskExitCode": "A preLaunchTask '{0}' encerrada com código de saĆ­da {1}.", - "debugAnyway": "Depurar mesmo assim", "noFolderWorkspaceDebugError": "O arquivo ativo nĆ£o pode ser depurado. Certifique-se de que ele estĆ” salvo no disco e que tem uma extensĆ£o de depuração instalada para esse tipo de arquivo.", "NewLaunchConfig": "Por favor, configure o arquivo de configuração de lanƧamento para seu aplicativo. {0}", - "DebugTaskNotFound": "NĆ£o foi possĆ­vel encontrar o preLaunchTask '{0}'.", - "differentTaskRunning": "A tarefa '{0}' jĆ” estĆ” em execução. NĆ£o pode executar a tarefa de prĆ©-lanƧamento '{1}'." + "DebugTaskNotFound": "NĆ£o foi possĆ­vel encontrar o preLaunchTask '{0}'." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 4afd6d64d82..5f2a144a70e 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "VariĆ”vel {0} tem valor {1}, ler a impressĆ£o do valor do loop, depurar", "replExpressionAriaLabel": "ExpressĆ£o {0} tem valor {1}, ler o laƧo de avaliação de impressĆ£o, depurar", "replValueOutputAriaLabel": " impressĆ£o da avaliação do laƧo de leitura, depurar", - "replKeyValueOutputAriaLabel": "VariĆ”vel de saĆ­da {0} tem valor {1}, ler o loop de avaliação de impressĆ£o, depurar" + "replRawObjectAriaLabel": "VariĆ”vel repl {0} tem valor {1}, ler o loop de avaliação de impressĆ£o e depuração" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/ptb/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index f0551dfe57b..9ed5fc448b4 100644 --- a/i18n/ptb/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "ExecutĆ”vel do adaptador de depuração '{0}' nĆ£o existe.", "debugAdapterCannotDetermineExecutable": "NĆ£o Ć© possĆ­vel determinar o executĆ”vel para o adaptador de depuração '{0}'.", + "launch.config.comment1": "Use o IntelliSense para aprender sobre possĆ­veis atributos.", + "launch.config.comment2": "Passe o mouse para ver as descriƧƵes dos atributos existentes.", + "launch.config.comment3": "Para obter mais informaƧƵes, visite: {0}", "debugType": "Tipo de configuração.", "debugTypeNotRecognised": "O tipo de depuração nĆ£o Ć© reconhecido. Certifique-se de que vocĆŖ tem uma extensĆ£o de depuração correspondente instalada e que ela estĆ” habilitada.", "node2NotSupported": "\"node2\" nĆ£o Ć© mais suportado, use \"node\" ao invĆ©s e defina o atributo \"protocol\" para \"inspector\".", diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 5e56d61c26b..dfd7672ae26 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "Nome", "view location": "Onde", - "themes": "Temas ({0})", + "colorThemes": "Temas de cores ({0})", + "iconThemes": "Temas de Ć­cones ({0})", + "colors": "Cores ({0})", + "colorId": "Id", + "defaultDark": "PadrĆ£o Escuro", + "defaultLight": "PadrĆ£o Claro", + "defaultHC": "PadrĆ£o de alto contraste", "JSON Validation": "Validação JSON ({0})", "commands": "Comandos ({0})", "command name": "Nome", diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 52a79e4fb67..3e15ba649f8 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,7 +34,6 @@ "postDisableMessage": "Recarregar esta janela para desativar a extensĆ£o '{0}'?", "postUninstallTooltip": "Recarregar para desativar", "postUninstallMessage": "Recarregar esta janela para desativar a extensĆ£o desinstalada '{0}'?", - "reload": "&&Recarregar Janela", "toggleExtensionsViewlet": "Mostrar ExtensƵes", "installExtensions": "Instalar ExtensƵes", "showEnabledExtensions": "Mostrar extensƵes habilitadas", @@ -44,14 +43,19 @@ "showOutdatedExtensions": "Mostrar ExtensƵes Desatualizadas", "showPopularExtensions": "Mostrar ExtensƵes Populares", "showRecommendedExtensions": "Mostrar ExtensƵes Recomendadas", - "showWorkspaceRecommendedExtensions": "Mostrar ExtensƵes Recomendadas para o EspaƧo de Trabalho", + "installWorkspaceRecommendedExtensions": "Instalar todos os espaƧo de trabalho recomendado extensƵes", + "allExtensionsInstalled": "Todas as extensƵes recomendadas para este espaƧo de trabalho jĆ” foram instaladas", + "installRecommendedExtension": "Instalar a extensĆ£o recomendada", + "extensionInstalled": "A extensĆ£o recomendada jĆ” foi instalada", "showRecommendedKeymapExtensions": "Mostrar Mapeamentos de Teclado Recomendados", "showRecommendedKeymapExtensionsShort": "Mapeamentos de Teclado", "showLanguageExtensions": "Mostrar ExtensƵes de Linguagem", "showLanguageExtensionsShort": "ExtensƵes de Linguagem", - "configureWorkspaceRecommendedExtensions": "Configurar ExtensƵes Recomendadas (EspaƧo de Trabalho)", - "ConfigureWorkspaceRecommendations.noWorkspace": "As recomendaƧƵes somente estĆ£o disponĆ­veis em uma pasta do espaƧo de trabalho.", + "showAzureExtensions": "Mostrar extensƵes para o Azure", + "showAzureExtensionsShort": "ExtensƵes do Azure", "OpenExtensionsFile.failed": "NĆ£o foi possĆ­vel criar o arquivo 'extensions.json' na pasta '.vscode' ({0}).", + "configureWorkspaceRecommendedExtensions": "Configurar ExtensƵes Recomendadas (EspaƧo de Trabalho)", + "configureWorkspaceFolderRecommendedExtensions": "Configurar as ExtensƵes Recomendadas (Pasta do EspaƧo de Trabalho)", "builtin": "IntrĆ­nseco", "disableAll": "Desabilitar Todas as ExtensƵes Instaladas", "disableAllWorkspace": "Desabilitar Todas as ExtensƵes Instaladas para este EspaƧo de Trabalho", diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..eb6f8e39a71 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "Recomendado" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index 666a6692179..3e2f2c91d39 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "Pressione Enter para gerenciar suas extensƵes.", + "notfound": "ExtensĆ£o '{0}' nĆ£o encontrada na Loja.", + "install": "Pressione Enter para instalar '{0}' da Loja.", "searchFor": "Pressione Enter para pesquisar por '{0}' na Loja.", "noExtensionsToInstall": "Digite um nome de extensĆ£o" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 663560d4d78..13e01541b3a 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -4,12 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "workspaceRecommendation": "Esta extensĆ£o Ć© recomendada pelos usuĆ”rios da Ć”rea de trabalho atual.", "reallyRecommended2": "A extensĆ£o {0} Ć© recomendada para este tipo de arquivo.", + "reallyRecommendedExtensionPack": "O pacote de extensĆ£o '{0}' Ć© recomendado para este tipo de arquivo.", "showRecommendations": "Mostrar RecomendaƧƵes", + "install": "Instalar", "neverShowAgain": "NĆ£o mostrar novamente", "close": "Fechar", "workspaceRecommended": "Este espaƧo de trabalho possui recomendaƧƵes de extensĆ£o.", - "ignoreExtensionRecommendations": "Deseja ignorar todas as recomendaƧƵes de extensĆ£o?", + "installAll": "Instalar Tudo", + "ignoreExtensionRecommendations": "VocĆŖ quer ignorar todas as recomendaƧƵes de extensĆ£o?", "ignoreAll": "Sim, Ignorar Tudo", "no": "NĆ£o", "cancel": "Cancelar" diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 731e4ef9491..2742e6642e3 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,6 +6,7 @@ { "openExtensionsFolder": "Abrir a Pasta de ExtensƵes", "installVSIX": "Instalar do VSIX...", + "installButton": "&&Instalar", "InstallVSIXAction.success": "A extensĆ£o foi instalada com sucesso. Reinicie para habilitĆ”-la.", "InstallVSIXAction.reloadNow": "Recarregar Agora" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json index 99808cb9a04..6b2a7567483 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json @@ -8,6 +8,8 @@ "installedExtensions": "Instalado", "searchInstalledExtensions": "Instalado", "recommendedExtensions": "Recomendado", + "otherRecommendedExtensions": "Outras recomendaƧƵes", + "workspaceRecommendedExtensions": "RecomendaƧƵes do EspaƧo de Trabalho", "searchExtensions": "Pesquisar ExtensƵes na Loja", "sort by installs": "Ordenar por: Quantidade de InstalaƧƵes", "sort by rating": "Ordenar por: Avaliação", diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 39deecf379b..464da97e4e9 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Arquivos", + "filesCategory": "Arquivo", "revealInSideBar": "Revelar na Barra Lateral", "acceptLocalChanges": "Usar suas alteraƧƵes e substituir o conteĆŗdo do disco", "revertLocalChanges": "Descartar as alteraƧƵesĀ e reverter para o conteĆŗdo no disco" diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 1408051c278..7c51e1cc24f 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "Tem certeza de que deseja excluir '{0}'?", "undoBin": "VocĆŖ pode restaurar da lixeira.", "undoTrash": "VocĆŖ pode restaurar a partir do lixo.", + "doNotAskAgain": "NĆ£o me pergunte novamente", "confirmDeleteMessageFolder": "Tem certeza de que deseja excluir permanentemente '{0}' e seu conteĆŗdo?", "confirmDeleteMessageFile": "Tem certeza de que deseja excluir permanentemente '{0}'?", "irreversible": "Esta ação Ć© irreversĆ­vel!", @@ -37,17 +38,15 @@ "openToSide": "Aberto para o lado", "compareSource": "Selecione para comparar", "globalCompareFile": "Compare o Arquivo Ativo Com...", - "pickHistory": "Selecione um arquivo previamente aberto para comparar com", - "unableToFileToCompare": "O arquivo selecionado nĆ£o pode ser comparado com '{0}'.", "openFileToCompare": "Abrir um arquivo primeiro para comparĆ”-lo com outro arquivo.", - "compareWith": "Comparar com '{0}'", + "compareWith": "Comparar '{0}' com '{1}'", "compareFiles": "Comparar Arquivos", "refresh": "Atualizar", "save": "Salvar", "saveAs": "Salvar como...", "saveAll": "Salvar Todos", "saveAllInGroup": "Salvar Todos no Grupo", - "saveFiles": "Salvar Arquivos Sujos", + "saveFiles": "Salvar todos os arquivos", "revert": "Reverter Arquivo", "focusOpenEditors": "Foco na Visualização dos Editores Abertos", "focusFilesExplorer": "Foco no Explorador de Arquivos", @@ -55,7 +54,6 @@ "openFileToShow": "Abrir um arquivo primeiro para mostrĆ”-lo no explorer", "collapseExplorerFolders": "Esconder Pastas no Explorador", "refreshExplorer": "Atualizar Explorador", - "openFile": "Abrir arquivo...", "openFileInNewWindow": "Abrir o Arquivo Ativo em uma Nova Janela", "openFileToShowInNewWindow": "Abrir um arquivo primeiro para abrir em uma nova janela", "revealInWindows": "Revelar no Explorer", diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 21cedf9a0bd..885e8b63b94 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "Editor de Arquivo de Texto", "binaryFileEditor": "Editor de Arquivo BinĆ”rio", "filesConfigurationTitle": "Arquivos", - "exclude": "Configure os padrƵes glob para excluir arquivos e pastas.", + "exclude": "Configure padrƵes glob para excluir os arquivos e pastas. Por exemplo, o explorador de arquivos decide quais arquivos e pastas mostrar ou ocultar baseado nessa configuração.", "files.exclude.boolean": "O padrĆ£o glob com o qual combinar os caminhos de arquivo. Defina para verdadeiro ou falso para habilitar ou desabilitar o padrĆ£o.", "files.exclude.when": "Verificação adicional nos irmĆ£os de um arquivo correspondente. Use $(basename) como variĆ”vel para o nome do arquivo correspondente.", "associations": "Configurar as associaƧƵes de arquivo para linguagens (por exemplo, \"* Extension\": \"html\"). Estas tĆŖm precedĆŖncia sobre as associaƧƵes padrĆ£o das linguagens instaladas.", - "encoding": "A codificação padrĆ£o do conjunto de caracteres para ser usada ao ler e gravar arquivos.", - "autoGuessEncoding": "Quando habilitado, tentarĆ” adivinhar a codificação do conjunto de caracteres ao abrir arquivos", + "encoding": "O conjunto de codificação de caracteres padrĆ£o a ser usado ao ler e gravar arquivos. Essa configuração tambĆ©m pode ser configurada por linguagem.", + "autoGuessEncoding": "Quando habilitado, tentarĆ” adivinhar o conjunto de codificação de caracteres ao abrir arquivos. Essa configuração tambĆ©m pode ser configurada por linguagem.", "eol": "O caractere padrĆ£o de fim de linha. Use \\n para LF e \\r\\n para CRLF.", "trimTrailingWhitespace": "Quando habilitado, removerĆ” espaƧos em branco Ć  direita ao salvar um arquivo.", "insertFinalNewline": "Quando habilitado, inseririrĆ” uma nova linha no final do arquivo quando salvĆ”-lo.", + "trimFinalNewlines": "Quando habilitado, removerĆ” todas as novas linhas após a nova linha no final do arquivo ao salvĆ”-lo.", "files.autoSave.off": "Um arquivo sujo nunca Ć© automaticamente salvo.", "files.autoSave.afterDelay": "Um arquivo sujo Ć© salvo automaticamente após configurado em 'files.autoSaveDelay'.", "files.autoSave.onFocusChange": "Um arquivo sujo Ć© salvo automaticamente quando o editor perde o foco.", @@ -39,10 +40,13 @@ "dynamicHeight": "Controla se a altura da seção de editores abertos deve adaptar-se dinamicamente para o nĆŗmero de elementos ou nĆ£o.", "autoReveal": "Controla se o explorador deve automaticamente revelar e selecionar arquivos ao abri-los.", "enableDragAndDrop": "Controla se o explorador deve permitir mover arquivos e pastas atravĆ©s de arrastar e soltar.", - "sortOrder.default": "Arquivos e diretórios sĆ£o classificados por seus nomes, em ordem alfabĆ©tica. Diretórios sĆ£o exibidos antes de arquivos.", - "sortOrder.mixed": "Arquivos e diretórios sĆ£o classificados por seus nomes, em ordem alfabĆ©tica. Arquivos sĆ£o entrelaƧados com diretórios.", - "sortOrder.filesFirst": "Arquivos e diretórios sĆ£o classificados por seus nomes, em ordem alfabĆ©tica. Os arquivos sĆ£o exibidos antes de diretórios.", - "sortOrder.type": "Arquivos e diretórios sĆ£o classificados por suas extensƵes, em ordem alfabĆ©tica. Diretórios sĆ£o exibidos antes de arquivos.", - "sortOrder.modified": "Arquivos e diretórios sĆ£o classificados pela data da Ćŗltima modificação, em ordem decrescente. Diretórios sĆ£o exibidos antes de arquivos.", - "sortOrder": "Controla a forma de organização de arquivos e diretórios no explorador." + "confirmDelete": "Controla se o explorador deve pedir a confirmação ao excluir um arquivo por meio do lixo.", + "sortOrder.default": "Arquivos e pastas sĆ£o classificadas por seus nomes, em ordem alfabĆ©tica. Pastas sĆ£o exibidas acima dos arquivos.", + "sortOrder.mixed": "Arquivos e pastas sĆ£o classificadas por seus nomes, em ordem alfabĆ©tica. Arquivos sĆ£o misturados com pastas.", + "sortOrder.filesFirst": "Arquivos e pastas sĆ£o classificadas por seus nomes, em ordem alfabĆ©tica. Os arquivos sĆ£o exibidos acima das pastas.", + "sortOrder.type": "Arquivos e pastas sĆ£o classificadas de acordo com suas extensƵes, em ordem alfabĆ©tica. Pastas sĆ£o exibidas acima dos arquivos.", + "sortOrder.modified": "Arquivos e pastas sĆ£o classificados de acordo com a data da Ćŗltima modificação, em ordem decrescente. Pastas sĆ£o exibidas acima dos arquivos.", + "sortOrder": "Controla a ordem de classificação dos arquivos e pastas no explorador. AlĆ©m da classificação padrĆ£o, vocĆŖ pode definir a ordem para 'mixed' (arquivos e pastas misturados), 'type' (por tipo de arquivo), 'modified' (pela data da Ćŗltima modificação) ou 'filesFirst' (exibe os arquivos acima das pastas).", + "explorer.decorations.colors": "Controles se as decoraƧƵes de arquivo devem usar cores.", + "explorer.decorations.badges": "Controles se as decoraƧƵes de arquivo devem usar identificaƧƵes." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 86ac69a7d68..09a29894643 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "Use as aƧƵes na barra de ferramentas de editor para a direita para **desfazer** suas alteraƧƵes ou **substituir** o conteĆŗdo no disco com as alteraƧƵes", "discard": "Descartar", "overwrite": "Sobrescrever", "retry": "Tentar novamente", @@ -11,6 +12,5 @@ "genericSaveError": "Erro ao salvar '{0}': {1}", "staleSaveError": "Falha ao salvar '{0}': O conteĆŗdo no disco Ć© mais recente. Clique em **Comparar** para comparar a sua versĆ£o com a do disco.", "compareChanges": "Comparar", - "saveConflictDiffLabel": "{0} (no disco) ↔ {1} (em {2}) - Resolver conflitos de salvamento", - "userGuide": "Use as aƧƵes na barra de ferramentas de editor para a direita para **desfazer** suas alteraƧƵes ou **substituir** o conteĆŗdo no disco com as alteraƧƵes" + "saveConflictDiffLabel": "{0} (no disco) ↔ {1} (em {2}) - Resolver conflitos de salvamento" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 38f98ed9420..69f48bde47d 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "Nenhuma Pasta Aberta", "explorerSection": "Seção de Explorador de Arquivos", - "noWorkspaceHelp": "VocĆŖ ainda nĆ£o abriu uma pasta.", + "noWorkspaceHelp": "VocĆŖ ainda nĆ£o adicionou uma pasta no espaƧo de trabalho.", + "addFolder": "Adicionar pasta", + "noFolderHelp": "VocĆŖ ainda nĆ£o abriu uma pasta.", "openFolder": "Abrir Pasta" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..36d4c36aa75 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Explorador", + "canNotResolve": "NĆ£o foi possĆ­vel resolver a pasta da Ć”rea de trabalho" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index c670883e6ac..14fa61ade5f 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,13 @@ { "fileInputAriaLabel": "Digite o Nome do arquivo. Pressione Enter para confirmar ou Escape para cancelar.", "filesExplorerViewerAriaLabel": "{0}, Explorador de Arquivos", + "dropFolders": "VocĆŖ quer adicionar as pastas no espaƧo de trabalho?", + "dropFolder": "VocĆŖ quer adicionar a pasta no espaƧo de trabalho?", + "addFolders": "&& Adicionar pastas", + "addFolder": "&& Adicionar pasta", + "confirmMove": "Tem certeza que deseja mover '{0}'?", + "doNotAskAgain": "NĆ£o me pergunte novamente", + "moveButtonLabel": "&&Mover", "confirmOverwriteMessage": "'{0}' jĆ” existe na pasta de destino. Deseja substituĆ­-lo?", "irreversible": "Esta ação Ć© irreversĆ­vel!", "replaceButtonLabel": "&&Substituir" diff --git a/i18n/ptb/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/ptb/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 9e75b7b2a89..f5b56baf44a 100644 --- a/i18n/ptb/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 arquivo nĆ£o salvo", "dirtyFiles": "{0} arquivos nĆ£o salvos" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/ptb/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..62c14983ac7 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Problemas", + "tooltip.1": "1 problema neste arquivo", + "tooltip.N": "{0} problemas neste arquivo", + "markers.showOnFile": "Mostre erros e avisos no arquivos e pasta." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/ptb/src/vs/workbench/parts/markers/common/messages.i18n.json index 8576955d609..a753fe413e8 100644 --- a/i18n/ptb/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "Exibir", + "problems.view.toggle.label": "Alternar Problemas", "problems.view.show.label": "Mostrar Problemas", + "problems.view.hide.label": "Esconder problemas", "problems.panel.configuration.title": "Visualização de Problemas", "problems.panel.configuration.autoreveal": "Controla se a visaulização de problemas evela os arquivos automaticamente ao abri-los", "markers.panel.title.problems": "Problemas", diff --git a/i18n/ptb/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/ptb/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index 027c80cca30..8ef2eb60289 100644 --- a/i18n/ptb/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "Copiar" + "copyMarker": "Copiar", + "copyMarkerMessage": "Mensagem de cópia" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/nps/electron-browser/nps.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/nps/electron-browser/nps.contribution.i18n.json index 1ec18c632a4..d232299820d 100644 --- a/i18n/ptb/src/vs/workbench/parts/nps/electron-browser/nps.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/nps/electron-browser/nps.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "surveyQuestion": "VocĆŖ deseja responder a uma pequena pesquisa?", + "surveyQuestion": "VocĆŖ se importaria em responder uma rĆ”pida pesquisa?", "takeSurvey": "Responder a pesquisa", "remindLater": "Lembrar mais tarde", "neverAgain": "NĆ£o mostrar novamente" diff --git a/i18n/ptb/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index 5fda62eb168..886f4120ac9 100644 --- a/i18n/ptb/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "Inicialização lenta detectada", - "slow.detail": "Pena que vocĆŖ teve uma inicialização lenta. Por favor reinicie '{0}' com perfil de desempenho habilitado, compartilhe os perfis conosco e nós trabalharemos duro para fazer com que a inicialização fique perfeita novamente.", "prof.message": "Perfis criados com sucesso.", "prof.detail": "Por favor, crie um problema e anexe manualmente os seguintes arquivos:\n{0}", "prof.restartAndFileIssue": "Criar Problema e Reiniciar", diff --git a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 57cd480b3ed..0abf761f3b5 100644 --- a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Abrir Arquivo de Atalhos de Teclado", "openWorkspaceSettings": "Abrir as configuraƧƵes do espaƧo de trabalho", "openFolderSettings": "Abrir configuraƧƵes da pasta", - "pickFolder": "Selecionar a Pasta", "configureLanguageBasedSettings": "Definir ConfiguraƧƵes EspecĆ­ficas de Linguagem...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Selecionar Linguagem" diff --git a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index c41e8578a61..406b00bf2d0 100644 --- a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -13,5 +13,6 @@ "settingsFound": "{0} ConfiguraƧƵes correspondentes", "fileEditorWithInputAriaLabel": "{0}. Editor de Arquivo de Texto.", "fileEditorAriaLabel": "Editor de Arquivo de Texto", + "defaultEditorReadonly": "Editar no editor do lado direito para substituir os padrƵes.", "preferencesAriaLabel": "PreferĆŖncias padrĆ£o. Editor de texto somente leitura." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index ccc14607143..136d71cc546 100644 --- a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,15 +5,15 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Coloque as suas configuraƧƵes aqui para substituir as configuraƧƵes padrĆ£o.", - "errorInvalidConfiguration": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes. Corrija erros/avisos no arquivo e tente novamente.", "emptyWorkspaceSettingsHeader": "Coloque as suas configuraƧƵes aqui para substituir as configuraƧƵes de usuĆ”rio.", "emptyFolderSettingsHeader": "Coloque as suas configuraƧƵes de pasta aqui para substituir aqueles das configuraƧƵes do espaƧo de trabalho.", "defaultFolderSettingsTitle": "ConfiguraƧƵes de pasta padrĆ£o", "defaultSettingsTitle": "ConfiguraƧƵes PadrĆ£o", - "noSettingsFound": "NĆ£o hĆ” configuraƧƵes encontradas.", "editTtile": "Editar", "replaceDefaultValue": "Substituir nas ConfiguraƧƵes", "copyDefaultValue": "Copiar para ConfiguraƧƵes", "unsupportedPHPExecutablePathSetting": "Essa configuração deve ser uma Configuração de UsuĆ”rio. Para configurar o PHP para o espaƧo de trabalho, abra um arquivo PHP e clique em 'Caminho do PHP' na barra de status.", - "unsupportedWorkspaceSetting": "Essa configuração deve ser uma Configuração de UsuĆ”rio." + "unsupportedWorkspaceSetting": "Essa configuração deve ser uma Configuração de UsuĆ”rio.", + "unsupportedWorkbenchSetting": "Essa configuração nĆ£o pode ser aplicada agora. SerĆ” aplicada quando vocĆŖ abrir esta pasta diretamente.", + "unsupportedWorkbenchSettingDevMode": "Essa configuração nĆ£o pode ser aplicada agora. Ela serĆ” aplicada se vocĆŖ definir o seu escopo como 'recurso' durante o registo, ou quando vocĆŖ abrir esta pasta diretamente." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 80038ce0632..77e307a5580 100644 --- a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "folderSettingsDetails": "ConfiguraƧƵes de pasta" + "defaultSettingsFuzzyPrompt": "Tente pesquisa fuzzy!", + "defaultSettings": "Coloque suas configuraƧƵes no editor do lado direito para substituir.", + "noSettingsFound": "NĆ£o hĆ” configuraƧƵes encontradas.", + "folderSettingsDetails": "ConfiguraƧƵes de pasta", + "enableFuzzySearch": "Ative a pesquisa fuzzy experimental" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/ptb/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index 72d00539586..9f80cd79e8b 100644 --- a/i18n/ptb/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "Comumente Utilizado", - "noSettings": "Nenhuma configuração", + "mostRelevant": "Mais Relevante", "defaultKeybindingsHeader": "Substituir as chaves de ligaƧƵes, colocando-os em seu arquivo de chave ligaƧƵes." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index b6d5cdbd2e5..e45b8e421e8 100644 --- a/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "O comando '{0}' nĆ£o estĆ” habilitado no contexto atual.", "recentlyUsed": "usados recentemente", "morecCommands": "outros comandos", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "NĆ£o hĆ” comandos correspondentes" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 0b8f8925f7c..edae0f0f0b2 100644 --- a/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Uma configuração que requer uma reinicialização foi alterada.", "relaunchSettingDetail": "Pressione o botĆ£o de reinicialização para reiniciar {0} e habilitar a configuração.", - "restart": "Reiniciar", - "relaunchWorkspaceMessage": "Esta mudanƧa de espaƧo de trabalho exigeĀ o recarregamento do nosso sistema de extensĆ£o.", - "reload": "Recarregar" + "restart": "&&Reiniciar" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index 1cb8d16e566..2ab571fe333 100644 --- a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0} de {1} mudanƧas", + "change": "{0} de {1} mudanƧa", + "show previous change": "Mostrar a Alteração Anterior", + "show next change": "Mostrar a Próxima Alteração", "editorGutterModifiedBackground": "Cor de fundo da dobra do editor para as linhas que estĆ£o modificadas.", "editorGutterAddedBackground": "Cor de fundo da dobra do editor para as linhas que estĆ£o adicionadas.", - "editorGutterDeletedBackground": "Cor de fundo da dobra do editor para as linhas que estĆ£o excluĆ­das." + "editorGutterDeletedBackground": "Cor de fundo da dobra do editor para as linhas que estĆ£o excluĆ­das.", + "overviewRulerModifiedForeground": "VisĆ£o geral da cor do marcador da rĆ©gua para conteĆŗdo modificado.", + "overviewRulerAddedForeground": "VisĆ£o geral da cor do marcador da rĆ©gua para conteĆŗdo adicionado.", + "overviewRulerDeletedForeground": "VisĆ£o geral da cor do marcador da rĆ©gua para conteĆŗdo excluĆ­do." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index 1b5369ebeea..117ddc11b04 100644 --- a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Mostrar Git", - "installAdditionalSCMProviders": "Instalar provedores de SCM adicionais...", "source control": "Controle de código-fonte", "toggleSCMViewlet": "Mostrar SCM", "view": "Exibir" diff --git a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index c14da801978..4b9c688e07f 100644 --- a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Provedores de Controle de Código Fonte", + "hideRepository": "Ocultar", "commitMessage": "Mensagem (tecle {0} para confirmar)", + "installAdditionalSCMProviders": "Instalar provedores de SCM adicionais...", + "no open repo": "NĆ£o existem provedores controle de código fonte ativos.", "source control": "Controle de código-fonte", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index b14e20a1487..53611fae125 100644 --- a/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "Ir para SĆ­mbolo no EspaƧo de Trabalho...", "name": "Pesquisar", - "showSearchViewlet": "Mostrar Busca", + "search": "Pesquisar", "view": "Exibir", - "findInFiles": "Localizar nos Arquivos", "openAnythingHandlerDescription": "Ir para o Arquivo", "openSymbolDescriptionNormal": "Ir para o SĆ­mbolo em Ɓrea de Trabalho", "searchOutputChannelTitle": "Pesquisar", @@ -16,7 +15,7 @@ "exclude": "Configure os padrƵes glob para excluir arquivos e pastas nas pesquisas. Herda todos os padrƵes glob da configuração files.exclude.", "exclude.boolean": "O padrĆ£o glob com o qual combinar os caminhos de arquivo. Defina para verdadeiro ou falso para habilitar ou desabilitar o padrĆ£o.", "exclude.when": "Verificação adicional nos irmĆ£os de um arquivo correspondente. Use $(basename) como variĆ”vel para o nome do arquivo correspondente.", - "useRipgrep": "Controla se deve utilizar ripgrep na pesquisa de texto", - "useIgnoreFilesByDefault": "Controla se deve utilizar arquivos .gitignore e .ignore por padrĆ£o ao fazer pesquisas em um novo espaƧo de trabalho.", - "search.quickOpen.includeSymbols": "Configurar para incluir resultados de uma pesquisa sĆ­mbolo global nos resultados do arquivo para Abertura RĆ”pida." + "useRipgrep": "Controla se utiliza ripgrep em buscas de texto e de arquivo", + "search.quickOpen.includeSymbols": "Configurar para incluir resultados de uma pesquisa sĆ­mbolo global nos resultados do arquivo para Abertura RĆ”pida.", + "search.followSymlinks": "Controla quando seguir symlinks ao realizar uma busca." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json index cd879d71747..ac001b085b6 100644 --- a/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -12,6 +12,8 @@ "previousSearchTerm": "Mostrar Termo de Pesquisa Anterior", "focusNextInputBox": "Focalizar a Próxima Caixa de Entrada", "focusPreviousInputBox": "Focalizar a Caixa de Entrada Anterior", + "showSearchViewlet": "Mostrar Busca", + "findInFiles": "Localizar nos Arquivos", "replaceInFiles": "Substituir nos Arquivos", "findInWorkspace": "ProcurarĀ no EspaƧo de Trabalho...", "findInFolder": "Procurar na pasta...", @@ -19,7 +21,7 @@ "ClearSearchResultsAction.label": "Limpar os Resultados da Pesquisa", "FocusNextSearchResult.label": "Focalizar o Próximo Resultado da Pesquisa", "FocusPreviousSearchResult.label": "Focalizar o Resultado da Pesquisa Anterior", - "RemoveAction.label": "Remover", + "RemoveAction.label": "Ignorar", "file.replaceAll.label": "Substituir Tudo", "match.replace.label": "Substituir" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 1d50c0f6464..ea69bd497f6 100644 --- a/i18n/ptb/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "arquivos a serem excluĆ­dos", "label.excludes": "Pesquisa de PadrƵes de ExclusĆ£o", "replaceAll.confirmation.title": "Substituir Tudo", - "replaceAll.confirm.button": "Substituir", + "replaceAll.confirm.button": "&&Substituir", "replaceAll.occurrence.file.message": "SubstituĆ­da {0} ocorrĆŖncia no arquivo {1} com '{2}'.", "removeAll.occurrence.file.message": "SubstituĆ­da {0} ocorrĆŖncia no arquivo {1}'.", "replaceAll.occurrence.files.message": "SubstituĆ­da {0} ocorrĆŖncia no arquivo {1} com '{2}'.", @@ -28,28 +28,22 @@ "removeAll.occurrences.files.confirmation.message": "Substituir {0} ocorrĆŖncias nos arquivos {1} com '{2}'?", "replaceAll.occurrences.files.confirmation.message": "Substituir {0} ocorrĆŖncias nos arquivos {1}?", "treeAriaLabel": "Resultados da Pesquisa", + "searchPathNotFoundError": "Caminho de pesquisa nĆ£o encontrado: {0}", "searchMaxResultsWarning": "O conjunto de resultados contĆ©m apenas um subconjunto de todas as correspondĆŖncias. Seja mais especĆ­fico na sua pesquisa para diminuir o nĆŗmero de resultados.", "searchCanceled": "Pesquisa foi cancelada antes de qualquer resultado ser encontrado - ", "noResultsIncludesExcludes": "Nenhum resultado encontrado em '{0}' excluindo '{1}' - ", "noResultsIncludes": "Nenhum resultado encontrado em '{0}' -", "noResultsExcludes": "Nenhum resultado encontrado excluindo '{0}' -", - "noResultsFound": "Nenhum resultado encontrado. Analise as configuraƧƵes para exclusƵes configuradas - ", + "noResultsFound": "Nenhum resultado encontrado. Revise suas configuraƧƵes para exclusƵes configuradas e arquivos ignorados - ", "rerunSearch.message": "Pesquisar novamente", "rerunSearchInAll.message": "Pesquisar novamente em todos os arquivos", "openSettings.message": "Abrir configuraƧƵes", + "openSettings.learnMore": "Saiba Mais", "ariaSearchResultsStatus": "Pesquisa retornou {0} resultados em {1} arquivos", "search.file.result": "{0} resultado no arquivo {1}", "search.files.result": "{0} resultado nos arquivos {1}", "search.file.results": "{0} resultados no arquivo {1}", "search.files.results": "{0} resultados nos arquivos {1}", - "search.folder.file.result": "{0} resultado em {1} arquivo na pasta {2}", - "search.folder.files.result": "{0} resultado em {1} arquivos na pasta {2}", - "search.folder.file.results": "{0} resultados em {1} arquivo na pasta {2}", - "search.folder.files.results": "{0} resultados em {1} arquivos na pasta {2}", - "search.folders.file.result": "{0} resultado em {1} arquivo nas pastas {2}", - "search.folders.files.result": "{0} resultado em {1} arquivos nas pastas {2}", - "search.folders.file.results": "{0} resultados em {1} arquivo nas pastas {2}", - "search.folders.files.results": "{0} resultados em {1} arquivos nas pastas {2}", "searchWithoutFolder": "VocĆŖ ainda nĆ£o abriu uma pasta. Somente arquivos abertos sĆ£o pesquisados - ", "openFolder": "Abrir Pasta" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/search/browser/searchWidget.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/browser/searchWidget.i18n.json index 41178af28cc..7921bba260f 100644 --- a/i18n/ptb/src/vs/workbench/parts/search/browser/searchWidget.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/search/browser/searchWidget.i18n.json @@ -11,5 +11,6 @@ "search.placeHolder": "Pesquisar", "label.Replace": "Substituir: Digite o termo a ser substituĆ­do e pressione Enter para visualizar ou Escape para cancelar", "search.replace.placeHolder": "Substituir", - "regexp.validationFailure": "A expressĆ£o corresponde a tudo" + "regexp.validationFailure": "A expressĆ£o corresponde a tudo", + "regexp.backreferenceValidationFailure": "ReferĆŖncias anteriores nĆ£o sĆ£o suportadas" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/ptb/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..c16ba8d7ba6 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Nenhuma pasta no espaƧo de trabalho com o nome: {0}" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 6c34a620b89..d0ebe51ea9b 100644 --- a/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "Inserir trecho de código" + "snippet.suggestions.label": "Inserir trecho de código", + "sep.userSnippet": "Trecho de código do usuĆ”rio", + "sep.extSnippet": "Trechos de Código de ExtensĆ£o" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 97a09842720..a2c0fbab96a 100644 --- a/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "Linguagem desconhecida em `contributes.{0}.language`. Valor fornecido: {1}", + "invalid.path.0": "Esperada uma string em `contributes.{0}.path`. Valor informado: {1}", + "invalid.path.1": "Ɖ esperado que `contributes.{0}.path` ({1}) seja incluĆ­do na pasta da extensĆ£o ({2}). Isto pode tornar a extensĆ£o nĆ£o portĆ”vel.", + "vscode.extension.contributes.snippets": "Contribui aos trechos de código.", + "vscode.extension.contributes.snippets-language": "Identificador de linguagem para o qual este trecho de código contribui.", + "vscode.extension.contributes.snippets-path": "Caminho do arquivo de trechos de código. O caminho Ć© relativo Ć  pasta de extensĆ£o e normalmente comeƧa com '. /snippets/'.", + "badVariableUse": "Um ou mais trechos da extensĆ£o '{0}' provavelmente se confundem com trechos de código de variĆ”veis e trechos de código de espaƧos reservados (veja https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax para mais detalhes)", + "badFile": "O arquivo de trechos \"{0}\" nĆ£o pĆ“de ser lido.", "source.snippet": "Trecho de código do usuĆ”rio", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index b0419122adc..ea6d0ced6b0 100644 --- a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "Configura o painel que Ć© usado para apresentar a saĆ­da da tarefa e ler sua entrada.", "JsonSchema.tasks.presentation.echo": "Controla se o comando executado Ć© ecoado para o painel. PadrĆ£o Ć© true.", "JsonSchema.tasks.presentation.focus": "Controla se o painel ganha foco. O padrĆ£o Ć© false. Se definido como true, o painel Ć© revelado tambĆ©m.", + "JsonSchema.tasks.presentation.reveal.always": "Sempre revela o terminal quando esta tarefa Ć© executada.", + "JsonSchema.tasks.presentation.reveal.silent": "Só revela o terminal se nenhum problema correspondente estĆ” associado com a tarefa e erros ocorrem aoĀ executĆ”-la.", + "JsonSchema.tasks.presentation.reveal.never": "Nunca revela o terminal quando esta tarefa Ć© executada.", "JsonSchema.tasks.presentation.reveals": "Controla se o painel executando a tarefa Ć© revelado ou nĆ£o. O padrĆ£o Ć© \"always\".", "JsonSchema.tasks.presentation.instance": "Controla se o painel Ć© compartilhado entre tarefas, dedicado a esta tarefa ou um novo Ć© criado em cada execução.", "JsonSchema.tasks.terminal": "A propriedade terminal Ć© obsoleta. Use presentation em seu lugar.", @@ -22,7 +25,8 @@ "JsonSchema.tasks.group.test": "Marca as tarefas como uma tarefa de teste acessĆ­vel atravĆ©s do comando 'Run Test Task'.", "JsonSchema.tasks.group.none": "Atribui a tarefa para nenhum grupo", "JsonSchema.tasks.group": "Define a que grupo de execução desta tarefa pertence. Suporta \"build\" para adicionĆ”-lo ao grupo de compilação e \"test\" para adicionĆ”-lo ao grupo de teste.", - "JsonSchema.tasks.type": "Define se a tarefa Ć© executada como um processo ou como um comando dentro de uma shell. O padrĆ£o Ć© processo.", + "JsonSchema.tasks.type": "Define quando a tarefa Ć© executada como um processo ou como um comando dentro do shell.", + "JsonSchema.tasks.label": "O rótulo da tarefa na interface do usuĆ”rio.", "JsonSchema.version": "O nĆŗmero da versĆ£o do config.", "JsonSchema.tasks.identifier": "Um identificador definido pelo usuĆ”rio para fazer referĆŖncia a tarefa em launch.json ou uma clĆ”usula dependsOn.", "JsonSchema.tasks.taskLabel": "A etiqueta da tarefa", diff --git a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index cf733db0eb3..7841731c435 100644 --- a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Tarefas", - "ConfigureTaskRunnerAction.noWorkspace": "Tarefas somente estĆ£o disponĆ­veis em uma pasta da Ć”rea de trabalho.", - "ConfigureTaskRunnerAction.quickPick.template": "Selecione um gerenciador de tarefa", - "ConfigureTaskRunnerAction.autoDetecting": "Tarefas de auto detecção para {0}", - "ConfigureTaskRunnerAction.autoDetect": "A tarefa de sistema de auto detecção falhou. Usando o modelo padrĆ£o. Consulte a saĆ­da da tarefa para detalhes.", - "ConfigureTaskRunnerAction.autoDetectError": "A tarefa de sistema de auto detecção produziu erros. Consulte a saĆ­da da tarefa para detalhes.", - "ConfigureTaskRunnerAction.failed": "NĆ£o Ć© possĆ­vel criar o arquivo 'tasks.json' na pasta '.vscode'. Consulte a saĆ­da da tarefa para detalhes.", - "ConfigureTaskRunnerAction.label": "Configure o gerenciador de tarefas", + "ConfigureTaskRunnerAction.label": "Configurar a tarefa", "ConfigureBuildTaskAction.label": "Configurar Tarefa de Compilação", "CloseMessageAction.label": "Fechar", "ShowTerminalAction.label": "Terminal Visualização", @@ -19,12 +13,14 @@ "manyMarkers": "99+", "runningTasks": "Mostrar tarefas em execução", "tasks": "Tarefas", - "TaskSystem.noHotSwap": "Alterar o mecanismo de execução de tarefa requer reiniciar o VS Code. A alteração serĆ” ignorada.", + "TaskSystem.noHotSwap": "Alterar o mecanismo de execução da tarefa com uma tarefa ativa executando exige que a janela seja recarregada", + "TaskServer.folderIgnored": "A pasta {0} Ć© ignorada desde que use a versĆ£o de tarefas 0.1.0", "TaskService.noBuildTask1": "Nenhuma tarefa de compilação definida. Marque uma tarefa com 'isBuildCommand' no arquivo tasks.json.", "TaskService.noBuildTask2": "Nenhuma tarefa de compilação definida. Marque uma tarefa como um grupo 'build' no arquivo tasks.json.", "TaskService.noTestTask1": "Nenhuma tarefa de teste definida. Marque uma tarefa com 'isTestCommand' no arquivo tasks.json.", "TaskService.noTestTask2": "Nenhuma tarefa de teste definida. Marque uma tarefa com um grupo 'teste' no arquivo tasks.json.", "TaskServer.noTask": "Tarefa {0} requisitada para execução nĆ£o encontrada.", + "TaskService.associate": "associar", "TaskService.attachProblemMatcher.continueWithout": "Continuar sem examinar a saĆ­da da tarefa", "TaskService.attachProblemMatcher.never": "Nunca verificar a saĆ­da da tarefa", "TaskService.attachProblemMatcher.learnMoreAbout": "Saiba mais sobre como verificar a saĆ­da de uma tarefa", @@ -35,7 +31,9 @@ "TaskSystem.activeSame.noBackground": "A tarefa '{0}' jĆ” estĆ” ativa. Para finalizĆ”-la use 'Finalizar Tarefa' no menu Tarefas.", "TaskSystem.active": "JĆ” existe uma tarefa sendo executada. Finalize-a antes de executar outra tarefa.", "TaskSystem.restartFailed": "Falha ao finalizar e reiniciar a tarefa {0}", + "TaskService.noConfiguration": "Erro: A deteção de tarefa {0} nĆ£o contribuiu para uma tarefa para a seguinte configuração: {1} a tarefa serĆ” ignorada.\n", "TaskSystem.configurationErrors": "Erro: A configuração da tarefa informada possui erros de validação e nĆ£o pode ser utilizada. Por favor, corrija os erros primeiro.", + "taskService.ignoreingFolder": "Ignorar as configuraƧƵes de tarefa para a pasta de trabalho {0}. Suporte a tarefas de espaƧo de trabalho de mĆŗltiplas pastas requer que todas as pastas usem a versĆ£o de tarefas 2.0.0\n", "TaskSystem.invalidTaskJson": "Erro: O conteĆŗdo do arquivo tasks.json possui erros de sintaxe. Por favor, corrija-os antes de executar uma tarefa.\n", "TaskSystem.runningTask": "HĆ” uma tarefa sendo executada. Deseja finalizĆ”-la?", "TaskSystem.terminateTask": "&&Finalizar Tarefa", @@ -47,24 +45,33 @@ "recentlyUsed": "tarefas recentemente utilizadas", "configured": "tarefas configuradas", "detected": "tarefas detectadas", + "TaskService.ignoredFolder": "As seguintes pastas de espaƧo de trabalho serĆ£o ignoradas, uma vez que eles usam versĆ£o de tarefa 0.1.0: ", + "TaskService.notAgain": "NĆ£o mostrar novamente", + "TaskService.ok": "OK", + "TaskService.pickRunTask": "Selecione a tarefa a ser executada", + "TaslService.noEntryToRun": "Nenhuma tarefa para executar foi encontrada. Configure Tarefas...", "TaskService.fetchingBuildTasks": "Buscando tarefas de compilação...", - "TaskService.noBuildTaskTerminal": "Nenhuma tarefa de compilação encontrada. Pressione 'Configurar Tarefa de Compilação' para definir um.", "TaskService.pickBuildTask": "Selecione a tarefa de compilação para executar", + "TaskService.noBuildTask": "Nenhuma tarefa de compilação para executar foi encontrada. Configure Tarefas...", "TaskService.fetchingTestTasks": "Buscando tarefas de teste...", - "TaskService.noTestTaskTerminal": "Nenhuma tarefa de teste encontrada. Pressione 'Configurar Tarefa de Execução' para definir uma.", "TaskService.pickTestTask": "Selecione a tarefa de teste para executar", - "TaskService.noTaskRunning": "Nenhuma tarefa estĆ” sendo executada.", + "TaskService.noTestTaskTerminal": "Nenhuma tarefa de teste para executar foi encontrada. Configure Tarefas...", "TaskService.tastToTerminate": "Selecione a tarefa para terminar", + "TaskService.noTaskRunning": "Nenhuma tarefa estĆ” atualmente em execução", "TerminateAction.noProcess": "O processo executado nĆ£o existe mais. Se a tarefa produziu processos em background, finalizar o VS Code pode resultar em processos órfĆ£os.", "TerminateAction.failed": "Falha ao finalizar a tarefa sendo executada", - "TaskService.noTaskToRestart": "NĆ£o hĆ” tarefa para reiniciar.", "TaskService.tastToRestart": "Selecione a tarefa para reiniciar", - "TaskService.defaultBuildTaskExists": "{0} jĆ” estĆ” marcado como a tarefa de compilação padrĆ£o.", + "TaskService.noTaskToRestart": "Nenhuma tarefa para reiniciar", + "TaskService.template": "Selecione um Modelo de Tarefa", + "TaskService.createJsonFile": "Criar arquivo tasks.json a partir de modelo", + "TaskService.openJsonFile": "Abrir arquivo tasks.json", + "TaskService.pickTask": "Selecione uma tarefa para configurar", + "TaskService.defaultBuildTaskExists": "{0} jĆ” estĆ” marcada como a tarefa de compilação padrĆ£o", "TaskService.pickDefaultBuildTask": "Selecione a tarefa a ser usada como a tarefa de compilação padrĆ£o", "TaskService.defaultTestTaskExists": "{0} jĆ” estĆ” marcado como a tarefa de teste padrĆ£o.", "TaskService.pickDefaultTestTask": "Selecione a tarefa a ser usada como a tarefa de teste padrĆ£o", - "TaskService.noTaskIsRunning": "Nenhuma tarefa em execução.", "TaskService.pickShowTask": "Selecione a tarefa para mostrar sua saĆ­da", + "TaskService.noTaskIsRunning": "Nenhuma tarefa em execução", "ShowLogAction.label": "Visualizar o Log de Tarefas", "RunTaskAction.label": "Executar Tarefa", "RestartTaskAction.label": "Reiniciar Tarefa em Execução", diff --git a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 1421a156ef7..f258ad63adf 100644 --- a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Um erro desconhecido ocorreu durante a execução de uma tarefa. Consulte o log de saĆ­da de tarefa para obter detalhes.", + "dependencyFailed": "NĆ£o foi possĆ­vel resolver a tarefa dependente '{0}' na pasta de espaƧo de trabalho '{1}'", "TerminalTaskSystem.terminalName": "Tarefa - {0}", "reuseTerminal": "Terminal serĆ” reutilizado pelas tarefas, pressione qualquer tecla para fechar.", "TerminalTaskSystem": "NĆ£o Ć© possĆ­vel executar um comando shell em uma unidade UNC.", diff --git a/i18n/ptb/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/ptb/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index ab03cd23ba1..ada7842e796 100644 --- a/i18n/ptb/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,6 +11,8 @@ "ConfigurationParser.unknownMatcherKind": "Aviso: a correspondĆŖncia de problema definido Ć© desconhecido. Tipos suportados sĆ£o string | ProblemMatcher | (string | ProblemMatcher)[].\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "Erro: ProblemMatcher invĆ”lido referĆŖncia: {0}\n", "ConfigurationParser.noTaskType": "Erro: configuração de tarefas deve ter uma propriedade de tipo. A configuração serĆ” ignorada.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "Erro: nĆ£oĀ hĆ” nenhum tipo de tarefa registrado '{0}'. VocĆŖ esqueceu de instalar uma extensĆ£o que fornece um provedor de tarefa correspondente?", + "ConfigurationParser.missingRequiredProperty": "Erro: a configuração de tarefa '{0}' nĆ£o possui a propriedade obrigatória '{1}'. A configuração de tarefa serĆ” ignorada.", "ConfigurationParser.notCustom": "Erro: tarefas nĆ£o estĆ” declarada como uma tarefa personalizada. A configuração serĆ” ignorada.\n{0}\n", "ConfigurationParser.noTaskName": "Erro: tarefas devem fornecer uma propriedade taskName. A tarefa serĆ” ignorada.\n{0}\n", "taskConfiguration.shellArgs": "Aviso: a tarefa '{0}' Ć© um comando do shell e o nome de comando ou um dos seus argumentos tem espaƧos sem escape. Para garantir a linha de comando correta por favor mesclar argumentos no comando.", diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 717cc9a63a0..44762cc06d3 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "entryAriaLabel": "{0}, seletor de terminal", + "termEntryAriaLabel": "{0}, seletor de terminal", + "termCreateEntryAriaLabel": "{0}, criar novo terminal", + "'workbench.action.terminal.newplus": "$(plus) criar novo Terminal Integrado", "noTerminalsMatching": "NĆ£o hĆ” terminais correspondentes", "noTerminalsFound": "NĆ£o hĆ” terminais abertos" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index f46966dd225..f4a78b8d461 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -5,18 +5,19 @@ // Do not edit this file. It is machine generated. { "quickOpen.terminal": "Mostrar Todos os Terminais Abertos", + "terminal": "Terminal", "terminalIntegratedConfigurationTitle": "Terminal Integrado", "terminal.integrated.shell.linux": "O caminho do shell que o terminal usa no Linux.", "terminal.integrated.shellArgs.linux": "Os argumentos de linha de comando a serem usados no terminal do Linux.", "terminal.integrated.shell.osx": "O caminho do shell que o terminal usa no OS X.", "terminal.integrated.shellArgs.osx": "Os argumentos de linha de comando a serem usados no terminal do OS X.", + "terminal.integrated.shell.windows": "O caminho do shell que o terminal utiliza no Windows. Quando estiver usandoĀ shells fornecidos com o Windows (cmd, PowerShell ou Bash no Ubuntu).", "terminal.integrated.shellArgs.windows": "Os argumentos de linha de comando a serem utilizados no terminal do Windows.", "terminal.integrated.rightClickCopyPaste": "Quando configurado, isto evitarĆ” que o menu de contexto apareƧa quando pressionado o botĆ£o direito do mouse dentro do terminal, em vez disso vai copiar quando hĆ” uma seleção e colar quando nĆ£o hĆ” nenhuma seleção.", "terminal.integrated.fontFamily": "Controla a famĆ­lia de fontes do terminal, este padrĆ£o Ć© o valor do editor.fontFamily.", - "terminal.integrated.fontLigatures": "Controla se as ligaƧƵes de fonte sĆ£o habilitadas no terminal.", "terminal.integrated.fontSize": "Controla o tamanho da fonte em pixels do terminal.", "terminal.integrated.lineHeight": "Controles a altura da linha do terminal, este nĆŗmero Ć© multiplicada pelo tamanho da fonte terminal para obter a altura real da linha em pixels.", - "terminal.integrated.enableBold": "Se habilitar o texto em negrito dentro do terminal requer suporte do terminal shell.", + "terminal.integrated.enableBold": "Se deseja habilitar o texto em negrito dentro do terminal, note que isso requer o apoio do shell do terminal.", "terminal.integrated.cursorBlinking": "Controla se o cursor do terminal pisca.", "terminal.integrated.cursorStyle": "Controla o estilo do cursor do terminal.", "terminal.integrated.scrollback": "Controla a quantidade mĆ”xima de linhas que o terminal mantĆ©m em seu buffer.", @@ -27,7 +28,6 @@ "terminal.integrated.env.osx": "Objeto com variĆ”veis de ambiente que serĆ£o adicionadas ao VS Code e utilizadas pelo terminal no Mac OS X", "terminal.integrated.env.linux": "Objeto com variĆ”veis de ambiente que serĆ£o adicionadas ao VS Code e utilizadas pelo terminal no Linux", "terminal.integrated.env.windows": "Objeto com variĆ”veis de ambiente que serĆ£o adicionadas ao VS Code e utilizadas pelo terminal no Windows", - "terminal": "Terminal", "terminalCategory": "Terminal", "viewCategory": "Exibir" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 26e13bbf486..2ee45b6deb3 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,6 +7,7 @@ "workbench.action.terminal.toggleTerminal": "Alternar Terminal Integrado", "workbench.action.terminal.kill": "Finalizar a InstĆ¢ncia de Terminal Ativa", "workbench.action.terminal.kill.short": "Encerrar Terminal", + "workbench.action.terminal.quickKill": "Finalizar a instĆ¢ncia do Terminal", "workbench.action.terminal.copySelection": "Copiar Seleção", "workbench.action.terminal.selectAll": "Selecionar Tudo", "workbench.action.terminal.deleteWordLeft": "Excluir Palavra Ć  Esquerda", @@ -15,7 +16,6 @@ "workbench.action.terminal.new.short": "Novo Terminal", "workbench.action.terminal.focus": "Focalizar Terminal", "workbench.action.terminal.focusNext": "Focalizar Próximo Terminal", - "workbench.action.terminal.focusAtIndex": "Focalizar Terminal {0}", "workbench.action.terminal.focusPrevious": "Focalizar Terminal Anterior", "workbench.action.terminal.paste": "Colar no Terminal Ativo", "workbench.action.terminal.DefaultShell": "Selecionar Shell PadrĆ£o", @@ -35,5 +35,8 @@ "workbench.action.terminal.rename": "Renomear", "workbench.action.terminal.rename.prompt": "Digite o nome do terminal", "workbench.action.terminal.focusFindWidget": "Focalizar Ferramenta de Pesquisa", - "workbench.action.terminal.hideFindWidget": "Ocultar Ferramenta de Pesquisa" + "workbench.action.terminal.hideFindWidget": "Ocultar Ferramenta de Pesquisa", + "nextTerminalFindTerm": "Mostrar Próximo Termo de Busca", + "previousTerminalFindTerm": "Mostrar Termo de Busca Anterior", + "quickOpenTerm": "Alternar o Terminal Ativo" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index deba202bc24..655ae8902e5 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "A cor de primeiro plano do terminal.", "terminalCursor.foreground": "A cor de primeiro plano do cursor do terminal.", "terminalCursor.background": "A cor de fundo do cursor do terminal. Permite personalizar a cor de um personagem sobreposto por um cursor de bloco.", + "terminal.selectionBackground": "A cor de fundo de seleção do terminal.", "terminal.ansiColor": "'{0}' cor ansi no terminal." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 2bbfefe2297..ef05288e718 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Copiar", - "createNewTerminal": "Novo Terminal", "paste": "Colar", "selectAll": "Selecionar Tudo", "clear": "Limpar" diff --git a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 08ec4bd9777..83214ad4be8 100644 --- a/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "Ok, Nunca Mostrar Novamente", "terminal.integrated.chooseWindowsShell": "Selecione o seu terminal shell preferido, vocĆŖ pode alterar isso mais tarde em suas configuraƧƵes", "terminalService.terminalCloseConfirmationSingular": "HĆ” uma sessĆ£o ativa de terminal, vocĆŖ quer finalizĆ”-la?", - "terminalService.terminalCloseConfirmationPlural": "Existem {0} sessƵes ativas de terminal, vocĆŖ quer finalizĆ”-las?", - "yes": "Sim" + "terminalService.terminalCloseConfirmationPlural": "Existem {0} sessƵes ativas de terminal, vocĆŖ quer finalizĆ”-las?" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/ptb/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 2e529470941..6a2cfcb15ab 100644 --- a/i18n/ptb/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,7 @@ "licenseChanged": "Nossos termos de licenƧa mudaram, favor revisĆ”-los.", "license": "Ler LicenƧa", "neveragain": "Nunca Mostrar Novamente", - "64bitisavailable": "{0} para Windows de 64 bits estĆ” disponĆ­vel!", + "64bitisavailable": "{0} para Windows de 64 bits estĆ” agora disponĆ­vel!", "learn more": "Saiba Mais", "updateIsReady": "Nova atualização de {0} disponĆ­vel.", "thereIsUpdateAvailable": "HĆ” uma atualização disponĆ­vel.", diff --git a/i18n/ptb/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/ptb/src/vs/workbench/parts/views/browser/views.i18n.json index 44dd55c2dc0..d210a742451 100644 --- a/i18n/ptb/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/views/browser/views.i18n.json @@ -5,5 +5,5 @@ // Do not edit this file. It is machine generated. { "viewToolbarAriaLabel": "{0} aƧƵes ", - "removeView": "Remover da barra lateral" + "hideView": "Ocultar a Barra Lateral" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index c746085618b..5411c925e8d 100644 --- a/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "InĆ­cio", "welcomePage.newFile": "Novo arquivo", "welcomePage.openFolder": "Abrir pasta...", - "welcomePage.cloneGitRepository": "Clonar repositório Git...", + "welcomePage.addWorkspaceFolder": "Adicionar pasta do espaƧo de trabalho...", "welcomePage.recent": "Recente", "welcomePage.moreRecent": "Mais...", "welcomePage.noRecentFolders": "NĆ£o hĆ” pastas recentes", diff --git a/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index fcdb7c13f8d..5fe2d66f53a 100644 --- a/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Mostrar extensƵes de Azure", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/ptb/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/ptb/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 9c7c7f681fa..26fbe210679 100644 --- a/i18n/ptb/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "Playground Interativo", - "editorWalkThrough.title": "Playground Interativo" + "editorWalkThrough.title": "Playground Interativo", + "editorWalkThrough": "Playground Interativo" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/ptb/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..e274edfe6f1 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Um resumo das configuraƧƵes. Este rótulo serĆ” usado no arquivo de configuraƧƵes como um comentĆ”rio de separação.", + "vscode.extension.contributes.configuration.properties": "Descrição das propriedades de configuração.", + "scope.window.description": "Janela de configuração especĆ­fica que pode ser configurada nas configuraƧƵes do usuĆ”rio ou Ć”rea de trabalho.", + "scope.resource.description": "Configuração especĆ­fica do recurso que pode ser configurada nas configuraƧƵes do usuĆ”rio, espaƧo de trabalho ou pasta.", + "scope.description": "Escopo em que a configuração Ć© aplicĆ”vel. Escopos disponĆ­veis sĆ£o 'window' e 'resource'.", + "vscode.extension.contributes.configuration": "Contribui Ć s definiƧƵes de configuração.", + "invalid.title": "'configuration.title' deve ser um string", + "vscode.extension.contributes.defaultConfiguration": "Contribui Ć s definiƧƵes de configuração padrĆ£o do editor por linguagem.", + "invalid.properties": "'configuration.properties' deve ser um objeto", + "invalid.allOf": "'configuration.allOf' estĆ” obsoleto e nĆ£o deve ser usado. Em vez disso, passe vĆ”rias seƧƵes de configuração como uma matriz para o ponto de contribuição 'configuration'.", + "workspaceConfig.folders.description": "Lista de pastas a serem carregadas no espaƧo de trabalho.", + "workspaceConfig.path.description": "Um caminho para um arquivo. Por exemplo, '/root /pastaA' ou './pastaA' para um caminho relativo que serĆ” determinado de acordo com o local do arquivoĀ no espaƧo de trabalho.", + "workspaceConfig.name.description": "Um nome opcional para a pasta. ", + "workspaceConfig.uri.description": "URI da pasta", + "workspaceConfig.settings.description": "ConfiguraƧƵes de espaƧo de trabalho", + "workspaceConfig.extensions.description": "ExtensƵes para o espaƧo de trabalho", + "unknownWorkspaceProperty": "Propriedade de configuração do espaƧo de trabalho desconhecida" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json index 7655014ffc0..2cd5ff9947e 100644 --- a/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,14 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "Contribui Ć s definiƧƵes de configuração.", "vscode.extension.contributes.configuration.title": "Um resumo das configuraƧƵes. Este rótulo serĆ” usado no arquivo de configuraƧƵes como um comentĆ”rio de separação.", "vscode.extension.contributes.configuration.properties": "Descrição das propriedades de configuração.", - "invalid.type": "Se definido, 'configuration.type' deve ser do tipo 'object'", + "scope.window.description": "Janela de configuração especĆ­fica que pode ser configurada nas configuraƧƵes do usuĆ”rio ou Ć”rea de trabalho.", + "scope.resource.description": "Configuração especĆ­fica do recurso que pode ser configurada nas configuraƧƵes do usuĆ”rio, espaƧo de trabalho ou pasta.", + "scope.description": "Escopo em que a configuração Ć© aplicĆ”vel. Escopos disponĆ­veis sĆ£o 'janela' e 'recurso'.", + "vscode.extension.contributes.configuration": "Contribui Ć s definiƧƵes de configuração.", "invalid.title": "'configuration.title' deve ser um string", "vscode.extension.contributes.defaultConfiguration": "Contribui Ć s definiƧƵes de configuração padrĆ£o do editor por linguagem.", "invalid.properties": "'configuration.properties' deve ser um objeto", - "workspaceConfig.id.description": "Identificador de espaƧo de trabalho. Usado para armazenar o estado interno do espaƧo de trabalho, que pode ser perdido em mudanƧa.", - "workspaceConfig.folders.description": "Lista de pastas a serem carregadas na Ć”rea de trabalho. Deve ser um caminho de arquivo, por exemplo, 'file:///root/folderA'", - "workspaceConfig.settings.description": "ConfiguraƧƵes de espaƧo de trabalho" + "invalid.allOf": "'configuration.allOf' estĆ” obsoleto e nĆ£o deve ser usado. Em vez disso, passe vĆ”rias seƧƵes de configuração como uma matriz para o ponto de contribuição 'configuration'.", + "workspaceConfig.folders.description": "Lista de pastas a serem carregadas no espaƧo de trabalho.", + "workspaceConfig.path.description": "Um caminho para um arquivo. Por exemplo, '/root /pastaA' ou './pastaA' para um caminho relativo que serĆ” determinado de acordo com o local do arquivoĀ no espaƧo de trabalho.", + "workspaceConfig.name.description": "Um nome opcional para a pasta. ", + "workspaceConfig.uri.description": "URI da pasta", + "workspaceConfig.settings.description": "ConfiguraƧƵes de espaƧo de trabalho", + "workspaceConfig.extensions.description": "ExtensƵes para o espaƧo de trabalho", + "unknownWorkspaceProperty": "Propriedade de configuração do espaƧo de trabalho desconhecida" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/ptb/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index 21d2a812bb9..afc18818b0a 100644 --- a/i18n/ptb/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,28 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Abrir configuraƧƵes", + "openTasksConfiguration": "Abrir Configuração de Tarefas", + "openLaunchConfiguration": "Abrir Configuração de Execução", "close": "Fechar", - "saveAndRetry": "Salvar as configuraƧƵes e tentar novamente", - "errorInvalidConfiguration": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes. Por favor abra **User Settings** para corrigir erros/avisos no arquivo e tente novamente.", - "errorInvalidConfigurationWorkspace": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes. Por favor abra **Workspace Settings** para corrigir erros/avisos no arquivo e tente novamente.", - "errorConfigurationFileDirty": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes, porque o arquivo foi alterado. Por favor, salve o arquivo **User Settings** e tente novamente.", - "errorConfigurationFileDirtyWorkspace": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes, porque o arquivo foi alterado. Por favor, salve o arquivo **Workspace Settings** e tente novamente.", + "open": "Abrir configuraƧƵes", + "saveAndRetry": "Salvar e tentar novamente", + "errorUnknownKey": "NĆ£o Ć© possĆ­vel gravar {0} porque {1} nĆ£o Ć© uma configuração registrada.", + "errorInvalidFolderConfiguration": "NĆ£o Ć© possĆ­vel gravar as configuraƧƵes da pasta porque {0} nĆ£o suporta o escopo de recurso de pasta.", + "errorInvalidUserTarget": "NĆ£o Ć© possĆ­vel gravar as configuraƧƵes do usuĆ”rio porque {0} nĆ£o oferece suporte para o escopo global.", + "errorInvalidWorkspaceTarget": "NĆ£o Ć© possĆ­vel gravar as configuraƧƵes do espaƧo de trabalho porque {0} nĆ£o oferece suporte para o escopo de espaƧo de trabalho em um espaƧo de trabalho de mĆŗltiplas pastas.", + "errorInvalidFolderTarget": "NĆ£o Ć© possĆ­vel gravar as configuraƧƵes da pasta porque nenhum recurso Ć© fornecido.", + "errorNoWorkspaceOpened": "NĆ£o Ć© possĆ­vel gravar {0} porque nenhum espaƧo de trabalhoĀ estĆ” aberto. Por favor, abra um espaƧo de trabalho primeiro e tente novamente.", + "errorInvalidTaskConfiguration": "NĆ£o foi possĆ­vel gravar no arquivo de tarefas. Por favor abra o arquivo **Tasks** para corrigir os erros/avisos e tente novamente.", + "errorInvalidLaunchConfiguration": "NĆ£o foi possĆ­vel gravar no arquivo de lanƧamento. Por favor abra o arquivo **Launch** para corrigir os erros/avisos e tente novamente.", + "errorInvalidConfiguration": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes do usuĆ”rio. Por favor abra o arquivo **ConfiguraƧƵes do UsuĆ”rio** para corrigir erros/avisos nele e tente novamente.", + "errorInvalidConfigurationWorkspace": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes de espaƧo de trabalho. Por favor abra o arquivo **ConfiguraƧƵes do EspaƧo de Trabalho** para corrigir erros/avisos no arquivo e tente novamente.", + "errorInvalidConfigurationFolder": "NĆ£o Ć© possĆ­vel gravarĀ nas configuraƧƵes de pasta. Por favor abra o arquivo **ConfiguraƧƵes de Pasta** sob a pasta **{0}** para corrigir erros/avisosĀ no arquivo e tente novamente.", + "errorTasksConfigurationFileDirty": "NĆ£o Ć© possĆ­vel gravar no arquivo de tarefas porque o arquivo estĆ” sujo. Por favor, salve o arquivo **ConfiguraƧƵes de Tarefa** e tente novamente.", + "errorLaunchConfigurationFileDirty": "NĆ£o Ć© possĆ­vel gravar no arquivo de inĆ­cio porque o arquivo estĆ” sujo. Por favor, salve o arquivo **Configuração de LanƧamento** e tente novamente.", + "errorConfigurationFileDirty": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes do usuĆ”rio porque o arquivo estĆ” sujo. Por favor, salveĀ o arquivo **ConfiguraƧƵes do UsuĆ”rio** e tente novamente.", + "errorConfigurationFileDirtyWorkspace": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes de espaƧo de trabalho porque o arquivo estĆ” sujo. Por favor, salve o arquivo **ConfiguraƧƵes do EspaƧo de Trabalho** e tente novamente.", + "errorConfigurationFileDirtyFolder": "NĆ£o Ć© possĆ­vel gravar em configuraƧƵes de pasta porque o arquivo estĆ” sujo. Por favor, salveĀ o arquivo **ConfiguraƧƵes de Pasta** sob na pasta **{0}** e tente novamente.", "userTarget": "ConfiguraƧƵes de UsuĆ”rio", - "workspaceTarget": "ConfiguraƧƵes de EspaƧo de Trabalho" + "workspaceTarget": "ConfiguraƧƵes de EspaƧo de Trabalho", + "folderTarget": "ConfiguraƧƵes de pasta" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/ptb/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..f0518e7f98e --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "bubbleTitle": "contĆ©m itens enfatizados" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/ptb/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..2c775958172 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "O host de extensĆ£o nĆ£o iniciou em 10 segundos, ele pode ser interrompido na primeira linha e precisa de um depurador para continuar.", + "extensionHostProcess.startupFail": "Host de extensĆ£o nĆ£o comeƧou em 10 segundos, isso pode ser um problema.", + "extensionHostProcess.error": "Erro do host de extensĆ£o: {0}" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..18d7b3f26c8 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "Falha ao analisar {0}: {1}.", + "fileReadFail": "NĆ£o foi possĆ­vel ler o arquivo {0}: {1}.", + "jsonsParseFail": "Falha ao analisar {0} ou {1}: {2}.", + "missingNLSKey": "NĆ£o foi possĆ­vel encontrar a mensagem para a chave {0}." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..8b5f44c434a --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "Ferramentas do Desenvolvedor", + "restart": "Reinicie o Host de extensĆ£o", + "extensionHostProcess.crash": "Host de extensĆ£o foi encerrado inesperadamente.", + "extensionHostProcess.unresponsiveCrash": "Host de extensĆ£o encerrado porque nĆ£o foi responsivo.", + "overwritingExtension": "Sobrescrevendo extensĆ£o {0} por {1}.", + "extensionUnderDevelopment": "Carregando extensĆ£o de desenvolvimento em {0}" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/ptb/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..7b91deaec2e --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Arquivo parece ser binĆ”rio e nĆ£o pode ser aberto como texto" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json index cb5fa24e4f0..e6423a5b25c 100644 --- a/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "Recurso de arquivo invĆ”lido ({0})", - "fileIsDirectoryError": "Arquivo Ć© diretório ({0})", + "fileIsDirectoryError": "Arquivo Ć© um diretório", "fileNotModifiedError": "Arquivo nĆ£o modificado desde", "fileTooLargeError": "Arquivo muito grande para abrir", "fileBinaryError": "Arquivo parece ser binĆ”rio e nĆ£o pode ser aberto como texto", "fileNotFoundError": "Arquivo nĆ£o encontrado ({0})", + "fileExists": "Arquivo a ser criado jĆ” existe ({0})", "fileMoveConflict": "NĆ£o Ć© possĆ­vel mover/copiar. Arquivo jĆ” existe no destino.", "unableToMoveCopyError": "NĆ£o Ć© possĆ­vel mover/copiar. Arquivo poderia substituir a pasta em que estĆ” contida.", "foldersCopyError": "Pastas nĆ£o podem ser copiadas para a Ć”rea de trabalho. Por favor selecione arquivos individuais para serem copiados.", diff --git a/i18n/ptb/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/ptb/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/ptb/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 984bc289c85..ca77d82093c 100644 --- a/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "Estilo da fonte da regra: um estilo ou uma combinação de 'itĆ”lico', 'negrito' e 'sublinhado'", - "schema.colors": "Cores para o realce de sintaxe", - "schema.properties.name": "Descrição da regra", - "schema.tokenColors.path": "Caminho para um arquivo tmTheme (relativo ao arquivo atual)" + "schema.token.settings": "Cores e estilos para o token.", + "schema.token.foreground": "Cor do primeiro plano para o token.", + "schema.token.background.warning": "Atualmente as cores de fundo do token nĆ£o sĆ£o suportadas.", + "schema.token.fontStyle": "Estilo da fonte da regra: um estilo ou uma combinação de 'itĆ”lico', 'negrito' e 'sublinhado'", + "schema.fontStyle.error": "O estilo da fonte deve ser uma combinação de 'itĆ”lico', 'negrito' e 'sublinhado'", + "schema.properties.name": "Descrição da regra.", + "schema.properties.scope": "Seletor de escopo que bate com esta regra.", + "schema.tokenColors.path": "Caminho para um arquivo tmTheme (relativo ao arquivo atual).", + "schema.colors": "Cores para o realce de sintaxe" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 3cf20c82de2..ddfc13e6a19 100644 --- a/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Quando estiver utilizando uma fonte: O tamanho da fonte em porcentagem para a fonte de texto. Se nĆ£o for definido, o padrĆ£o Ć© o tamanho na definição de fonte.", "schema.fontId": "Quando estiver utilizando uma fonte: A identificação da fonte. Se nĆ£o for definido, o padrĆ£o Ć© a primeira definição de fonte.", "schema.light": "AssociaƧƵes opcionais para Ć­cones de arquivo em temas de cor clara.", - "schema.highContrast": "AssociaƧƵes opcionais para Ć­cones de arquivo em temas de alto contraste." + "schema.highContrast": "AssociaƧƵes opcionais para Ć­cones de arquivo em temas de alto contraste.", + "schema.hidesExplorerArrows": "Define se as setas do explorador de arquivos devem ser ocultadas quando este tema estĆ” ativo." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index 4ef6944ba73..e7eaddc34c9 100644 --- a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "Problemas ao analisar o arquivo de tema JSON: {0}", "error.invalidformat.colors": "Problema ao analisar o arquivo de tema de cor: {0}. A propriedade 'colors' nĆ£o Ć© do tipo 'object'.", - "error.invalidformat.tokenColors": "Problema ao analisar o arquivo de tema de cor: {0}. A propriedade 'tokenColors' deve ser tambĆ©m uma matriz especificando as cores ou um caminho para um arquivo de texto de tema correspondente", + "error.invalidformat.tokenColors": "Problema ao ler o arquivo do tema de cores: {0}. Propriedade 'tokenColors' deve ser tambĆ©m uma matriz especificando cores ou um caminho para um arquivo de tema do TextMate", "error.plist.invalidformat": "Problema ao analisar o arquivo tmTheme: {0}. 'settings' nĆ£o Ć© uma matriz.", "error.cannotparse": "Problemas ao analisar o arquivo tmTheme: {0}", "error.cannotload": "Problemas ao carregar o arquivo tmTheme {0}: {1}" diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..938c7bbea81 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Contribui com temas de cores do textmate.", + "vscode.extension.contributes.themes.id": "ID do tema do Ć­cone como usado em configuraƧƵes do usuĆ”rio.", + "vscode.extension.contributes.themes.label": "Etiqueta da cor do tema como mostrado na interface do usuĆ”rio.", + "vscode.extension.contributes.themes.uiTheme": "Tema base de definição das cores do editor: 'vs' Ć© o tema de cor clara, 'vs-dark' Ć© o tema de cor escura. 'hc preto' Ć© o tema escuro de alto contraste.", + "vscode.extension.contributes.themes.path": "Caminho do arquivo tmTheme. O caminho Ć© relativo Ć  pasta de extensĆ£o e Ć© normalmente './themes/themeFile.tmTheme'.", + "reqarray": "Ponto de extensĆ£o '{0}' deve ser uma matriz.", + "reqpath": "Esperada uma string em `contributes.{0}.path`. Valor informado: {1}", + "invalid.path.1": "Ɖ esperado que `contributes.{0}.path` ({1}) seja incluĆ­do na pasta da extensĆ£o ({2}). Isto pode tornar a extensĆ£o nĆ£o portĆ”vel." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..f78a56c0249 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Problemas de anĆ”lise do arquivo de Ć­cones: {0}" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..0181b35ac2a --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contribui com temas de Ć­cones de arquivo.", + "vscode.extension.contributes.iconThemes.id": "ID do tema do Ć­cone como usado em configuraƧƵes do usuĆ”rio.", + "vscode.extension.contributes.iconThemes.label": "Etiqueta do tema do Ć­cone como mostrado na interface do usuĆ”rio.", + "vscode.extension.contributes.iconThemes.path": "Caminho do arquivo de definição do tema do Ć­cone. O caminho Ć© relativo Ć  pasta de extensĆ£o e Ć© normalmente './icons/awesome-icon-theme.json'.", + "reqarray": "Ponto de extensĆ£o '{0}' deve ser uma matriz.", + "reqpath": "Esperada uma string em `contributes.{0}.path`. Valor informado: {1}", + "reqid": "Esperada sequĆŖncia em 'contributes.{0}.ID'. Valor fornecido: {1}", + "invalid.path.1": "Ɖ esperado que `contributes.{0}.path` ({1}) seja incluĆ­do na pasta da extensĆ£o ({2}). Isto pode tornar a extensĆ£o nĆ£o portĆ”vel." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 93ae243bc25..d27ccd6f4ab 100644 --- a/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,30 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contribui com temas de cores do textmate.", - "vscode.extension.contributes.themes.id": "ID do tema do Ć­cone conforme usado em configuraƧƵes do usuĆ”rio.", - "vscode.extension.contributes.themes.label": "Etiqueta da cor do tema como mostrado na interface do usuĆ”rio.", - "vscode.extension.contributes.themes.uiTheme": "Tema base de definição das cores do editor: 'vs' Ć© o tema de cor clara, 'vs-dark' Ć© o tema de cor escura. 'hc preto' Ć© o tema escuro de alto contraste.", - "vscode.extension.contributes.themes.path": "Caminho do arquivo tmTheme. O caminho Ć© relativo Ć  pasta de extensĆ£o e Ć© normalmente './themes/themeFile.tmTheme'.", - "vscode.extension.contributes.iconThemes": "Contribui com temas de Ć­cones de arquivo.", - "vscode.extension.contributes.iconThemes.id": "ID do tema do Ć­cone como usado em configuraƧƵes do usuĆ”rio.", - "vscode.extension.contributes.iconThemes.label": "Etiqueta do tema do Ć­cone como mostrado na interface do usuĆ”rio.", - "vscode.extension.contributes.iconThemes.path": "Caminho do arquivo de definição do tema do Ć­cone. O caminho Ć© relativo Ć  pasta de extensĆ£o e Ć© normalmente './icons/awesome-icon-theme.json'.", "migration.completed": "Foram adicionadas novas configuraƧƵes de tema para as configuraƧƵes de usuĆ”rio. Backup estĆ” disponĆ­vel em {0}.", "error.cannotloadtheme": "NĆ£o Ć© possĆ­vel carregar {0}: {1}", - "reqarray": "Ponto de extensĆ£o '{0}' deve ser uma matriz.", - "reqpath": "Esperada uma string em `contributes.{0}.path`. Valor informado: {1}", - "invalid.path.1": "Ɖ esperado que `contributes.{0}.path` ({1}) seja incluĆ­do na pasta da extensĆ£o ({2}). Isto pode tornar a extensĆ£o nĆ£o portĆ”vel.", - "reqid": "Esperada sequĆŖncia em 'contributes.{0}.ID'. Valor fornecido: {1}", "error.cannotloadicontheme": "NĆ£o Ć© possĆ­vel carregar {0}", - "error.cannotparseicontheme": "Problemas de anĆ”lise do arquivo de Ć­cones: {0}", "colorTheme": "Especifica o tema de cores usado no espaƧo de trabalho.", "colorThemeError": "Tema Ć© desconhecido ou nĆ£o estĆ” instalado.", "iconTheme": "Especifica o tema de Ć­cones usado no espaƧo de trabalho ou 'null' para nĆ£o mostrar qualquer arquivo de Ć­cones.", "noIconThemeDesc": "Nenhum arquivo de Ć­cones", "iconThemeError": "Arquivo de tema de Ć­cones Ć© desconhecido ou nĆ£o estĆ” instalado.", "workbenchColors": "Substitui as cores do tema do tema de cores atualmente selecionado.", - "workbenchColors.deprecated": "A configuração nĆ£o Ć© mais experimental e foi renomeada para 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Use 'workbench.colorCustomizations'", - "editorColors": "Substitui as cores e o estilo da fonte do editor do tema de cores atualmente selecionado." + "editorColors": "Substitui as cores e o estilo da fonte do editor do tema de cores atualmente selecionado.", + "editorColors.comments": "Define as cores e estilos para os comentĆ”rios", + "editorColors.strings": "Define as cores e estilos para textos literais.", + "editorColors.keywords": "Define as cores e estilos para palavras-chave.", + "editorColors.numbers": "Define as cores e estilos para literais numĆ©ricos.", + "editorColors.types": "Define as cores e estilos para declaraƧƵes de tipo e referĆŖncias.", + "editorColors.functions": "Define as cores e estilos para declaraƧƵes de funƧƵes e referĆŖncias.", + "editorColors.variables": "Define as cores e estilos para declaraƧƵes de variĆ”veis e referĆŖncias.", + "editorColors.textMateRules": "Define as cores e estilos usando regras de temas textmate (avanƧado)." } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/ptb/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..078a8eb1b7d --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "NĆ£o Ć© possĆ­vel escrever no arquivo de configuração. Por favor, abra o arquivo para corrigir erros/avisos nele e tente novamente.", + "errorWorkspaceConfigurationFileDirty": "NĆ£o Ć© possĆ­vel escrever no arquivo de configuração do espaƧo de trabalho porque o arquivo estĆ” sujo. Por favor, salve-o e tente novamente.", + "openWorkspaceConfigurationFile": "Abrir o Arquivo de Configuração do EspaƧo de Trabalho", + "close": "Fechar", + "enterWorkspace.close": "Fechar", + "enterWorkspace.dontShowAgain": "NĆ£o mostrar novamente", + "enterWorkspace.moreInfo": "Mais informaƧƵes", + "enterWorkspace.prompt": "Saiba mais sobre como trabalhar com vĆ”rias pastas no VS Code." +} \ No newline at end of file diff --git a/i18n/rus/extensions/azure-account/out/azure-account.i18n.json b/i18n/rus/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..d91c6279d44 --- /dev/null +++ b/i18n/rus/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "Š”ŠŗŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ Šø Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ", + "azure-account.close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", + "azure-account.login": "ВхоГ", + "azure-account.loginFirst": "Š’Ń‹ не вошли в ŃŠøŃŃ‚ŠµŠ¼Ńƒ. Дначала войГите в ŃŠøŃŃ‚ŠµŠ¼Ńƒ.", + "azure-account.userCodeFailed": "ŠŠµ уГалось ŠæŠ¾Š»ŃƒŃ‡ŠøŃ‚ŃŒ коГ ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń", + "azure-account.tokenFailed": "ŠŸŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŠµ маркера с коГом ŃƒŃŃ‚Ń€Š¾Š¹ŃŃ‚Š²Š°", + "azure-account.tokenFromRefreshTokenFailed": "ŠŸŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŠµ маркера с маркером Š¾Š±Š½Š¾Š²Š»ŠµŠ½ŠøŃ" +} \ No newline at end of file diff --git a/i18n/rus/extensions/azure-account/out/extension.i18n.json b/i18n/rus/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..d1f24dd3a8c --- /dev/null +++ b/i18n/rus/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: Š²Ń‹ŠæŠ¾Š»Š½ŃŠµŃ‚ŃŃ вхоГ...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index 8760c57e674..a691501ffe0 100644 --- a/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/rus/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "например, myFile.txt", - "activeEditorMedium": "например, myFolder/myFile.txt", - "activeEditorLong": "например, /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "например, myFolder1, myFolder2, myFolder3", - "rootPath": "например, /Users/Development/myProject", - "folderName": "например, myFolder", - "folderPath": "например, /Users/Development/myFolder", "appName": "например, VS Code", "dirty": "инГикатор dirty, если активный реГактор ŃŠ²Š»ŃŠµŃ‚ŃŃ \"Š³Ń€ŃŠ·Š½Ń‹Š¼\"", "separator": "ŃƒŃŠ»Š¾Š²Š½Ń‹Š¹ Ń€Š°Š·Š“ŠµŠ»ŠøŃ‚ŠµŠ»ŃŒ (-), который Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ, Ń‚Š¾Š»ŃŒŠŗŠ¾ если Š¾ŠŗŃ€ŃƒŠ¶ŠµŠ½ переменными со Š·Š½Š°Ń‡ŠµŠ½ŠøŃŠ¼Šø", diff --git a/i18n/rus/extensions/css/package.i18n.json b/i18n/rus/extensions/css/package.i18n.json index a89665ea18b..db66fb21a3c 100644 --- a/i18n/rus/extensions/css/package.i18n.json +++ b/i18n/rus/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "ŠŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾Šµ число параметров", "css.lint.boxModel.desc": "ŠŠµ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŃˆŠøŃ€ŠøŠ½Ńƒ или Š²Ń‹ŃŠ¾Ń‚Ńƒ при использовании ŠæŠ¾Š»Ń или границы", "css.lint.compatibleVendorPrefixes.desc": "ŠŸŃ€Šø использовании Š·Š°Š²ŠøŃŃŃ‰ŠµŠ³Š¾ от поставщика префикса также ŃƒŠŗŠ°Š·Ń‹Š²Š°Š¹Ń‚Šµ все Š¾ŃŃ‚Š°Š»ŃŒŠ½Ń‹Šµ свойства поставщика", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "ŠŠµŠøŠ·Š²ŠµŃŃ‚Š½Š¾Šµ свойство поставщика.", "css.lint.vendorPrefix.desc": "ŠŸŃ€Šø использовании Š·Š°Š²ŠøŃŃŃ‰ŠµŠ³Š¾ от поставщика префикса также ŃƒŠŗŠ°Š·Ń‹Š²Š°Š¹Ń‚Šµ станГартное свойство", "css.lint.zeroUnits.desc": "Š”Š»Ń Š½ŃƒŠ»Ń не Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ еГиница ŠøŠ·Š¼ŠµŃ€ŠµŠ½ŠøŃ", + "css.trace.server.desc": "ŠžŃ‚ŃŠ»ŠµŠ¶ŠøŠ²Š°ŠµŃ‚ обмен Ганными межГу VS Code Šø ŃŠ·Ń‹ŠŗŠ¾Š²Ń‹Š¼ сервером CSS.", + "css.validate.title": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ проверкой CSS Šø ŃŠµŃ€ŃŒŠµŠ·Š½Š¾ŃŃ‚ŃŒŃŽ проблем.", "css.validate.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ все проверки", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "ŠŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾Šµ число параметров", "less.lint.boxModel.desc": "ŠŠµ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŃˆŠøŃ€ŠøŠ½Ńƒ или Š²Ń‹ŃŠ¾Ń‚Ńƒ при использовании ŠæŠ¾Š»Ń или границы", "less.lint.compatibleVendorPrefixes.desc": "ŠŸŃ€Šø использовании Š·Š°Š²ŠøŃŃŃ‰ŠµŠ³Š¾ от поставщика префикса также ŃƒŠŗŠ°Š·Ń‹Š²Š°Š¹Ń‚Šµ все Š¾ŃŃ‚Š°Š»ŃŒŠ½Ń‹Šµ свойства поставщика", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "ŠŠµŠøŠ·Š²ŠµŃŃ‚Š½Š¾Šµ свойство поставщика.", "less.lint.vendorPrefix.desc": "ŠŸŃ€Šø использовании Š·Š°Š²ŠøŃŃŃ‰ŠµŠ³Š¾ от поставщика префикса также ŃƒŠŗŠ°Š·Ń‹Š²Š°Š¹Ń‚Šµ станГартное свойство", "less.lint.zeroUnits.desc": "Š”Š»Ń Š½ŃƒŠ»Ń не Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ еГиница ŠøŠ·Š¼ŠµŃ€ŠµŠ½ŠøŃ", + "less.validate.title": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ проверкой LESS Šø ŃƒŃ€Š¾Š²Š½ŃŠ¼Šø ŃŠµŃ€ŃŒŠµŠ·Š½Š¾ŃŃ‚Šø проблем. ", "less.validate.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ все проверки", + "scss.title": "SCSS (SASS)", "scss.lint.argumentsInColorFunction.desc": "ŠŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾Šµ число параметров", "scss.lint.boxModel.desc": "ŠŠµ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŃˆŠøŃ€ŠøŠ½Ńƒ или Š²Ń‹ŃŠ¾Ń‚Ńƒ при использовании ŠæŠ¾Š»Ń или границы", "scss.lint.compatibleVendorPrefixes.desc": "ŠŸŃ€Šø использовании Š·Š°Š²ŠøŃŃŃ‰ŠµŠ³Š¾ от поставщика префикса также ŃƒŠŗŠ°Š·Ń‹Š²Š°Š¹Ń‚Šµ все Š¾ŃŃ‚Š°Š»ŃŒŠ½Ń‹Šµ свойства поставщика", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "ŠŠµŠøŠ·Š²ŠµŃŃ‚Š½Š¾Šµ свойство поставщика.", "scss.lint.vendorPrefix.desc": "ŠŸŃ€Šø использовании Š·Š°Š²ŠøŃŃŃ‰ŠµŠ³Š¾ от поставщика префикса также ŃƒŠŗŠ°Š·Ń‹Š²Š°Š¹Ń‚Šµ станГартное свойство", "scss.lint.zeroUnits.desc": "Š”Š»Ń Š½ŃƒŠ»Ń не Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ еГиница ŠøŠ·Š¼ŠµŃ€ŠµŠ½ŠøŃ", + "scss.validate.title": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ проверкой SCSS Šø ŃƒŃ€Š¾Š²Š½ŃŠ¼Šø ŃŠµŃ€ŃŒŠµŠ·Š½Š¾ŃŃ‚Šø проблем.", "scss.validate.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ все проверки", "less.colorDecorators.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Гекораторы цвета.", "scss.colorDecorators.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Гекораторы цвета.", - "css.colorDecorators.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Гекораторы цвета." + "css.colorDecorators.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Гекораторы цвета.", + "css.colorDecorators.enable.deprecationMessage": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ \"css.colorDecorators.enable\" ŃƒŃŃ‚Š°Ń€ŠµŠ». Š¢ŠµŠæŠµŃ€ŃŒ вместо него ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся параметр \"editor.colorDecorators\". ", + "scss.colorDecorators.enable.deprecationMessage": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ \"scss.colorDecorators.enable\" ŃƒŃŃ‚Š°Ń€ŠµŠ». Š¢ŠµŠæŠµŃ€ŃŒ вместо него ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся параметр \"editor.colorDecorators\". ", + "less.colorDecorators.enable.deprecationMessage": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ \"less.colorDecorators.enable\" ŃƒŃŃ‚Š°Ń€ŠµŠ». Š¢ŠµŠæŠµŃ€ŃŒ вместо него ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся параметр \"editor.colorDecorators\". " } \ No newline at end of file diff --git a/i18n/rus/extensions/emmet/package.i18n.json b/i18n/rus/extensions/emmet/package.i18n.json index 8b6ad71cd4e..3c7e7099a9d 100644 --- a/i18n/rus/extensions/emmet/package.i18n.json +++ b/i18n/rus/extensions/emmet/package.i18n.json @@ -3,4 +3,38 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "command.wrapWithAbbreviation": "ŠŸŠµŃ€ŠµŠ½ŠµŃŃ‚Šø с сокращением", + "command.wrapIndividualLinesWithAbbreviation": "ŠŸŠµŃ€ŠµŠ½ŠµŃŃ‚Šø Š¾Ń‚Š“ŠµŠ»ŃŒŠ½Ń‹Šµ строки с сокращением", + "command.removeTag": "Š£Š“Š°Š»ŠøŃ‚ŃŒ тег", + "command.updateTag": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ тег", + "command.matchTag": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠµŠ¹ паре", + "command.balanceIn": "Баланс (Š²Ń…Š¾Š“ŃŃ‰ŠøŠ¹)", + "command.balanceOut": "Баланс (ŠøŃŃ…Š¾Š“ŃŃ‰ŠøŠ¹)", + "command.prevEditPoint": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ¹ точке ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "command.nextEditPoint": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¹ точке ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "command.mergeLines": "ŠžŠ±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚ŃŒ строки", + "command.selectPrevItem": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠøŠ¹ ŃŠ»ŠµŠ¼ŠµŠ½Ń‚", + "command.selectNextItem": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠ¹ ŃŠ»ŠµŠ¼ŠµŠ½Ń‚", + "command.splitJoinTag": "Š Š°Š·Š“ŠµŠ»ŠøŃ‚ŃŒ/Š¾Š±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚ŃŒ тег", + "command.toggleComment": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ комментарий", + "command.evaluateMathExpression": "Š’Ń‹Ń‡ŠøŃŠ»ŠøŃ‚ŃŒ математическое выражение", + "command.updateImageSize": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ размер ŠøŠ·Š¾Š±Ń€Š°Š¶ŠµŠ½ŠøŃ", + "command.reflectCSSValue": "ŠžŃ‚Ń€Š°Š¶Š°Ń‚ŃŒ значение CSS", + "command.incrementNumberByOne": "Š£Š²ŠµŠ»ŠøŃ‡ŠøŃ‚ŃŒ значение на 1", + "command.decrementNumberByOne": "Š£Š¼ŠµŠ½ŃŒŃˆŠøŃ‚ŃŒ значение на 1", + "command.incrementNumberByOneTenth": "Š£Š²ŠµŠ»ŠøŃ‡ŠøŃ‚ŃŒ значение на 0.1", + "command.decrementNumberByOneTenth": "Š£Š¼ŠµŠ½ŃŒŃˆŠøŃ‚ŃŒ значение на 0.1", + "command.incrementNumberByTen": "Š£Š²ŠµŠ»ŠøŃ‡ŠøŃ‚ŃŒ значение на 10", + "command.decrementNumberByTen": "Š£Š¼ŠµŠ½ŃŒŃˆŠøŃ‚ŃŒ значение на 10", + "emmetSyntaxProfiles": "ЗаГайте ŠæŃ€Š¾Ń„ŠøŠ»ŃŒ Š“Š»Ń указанного синтаксиса или ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚е свой собственный ŠæŃ€Š¾Ń„ŠøŠ»ŃŒ с опреГеленными правилами.", + "emmetPreferences": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠø, которые ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŃŽŃ‚ся Š“Š»Ń ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ ŠæŠ¾Š²ŠµŠ“ŠµŠ½ŠøŃ некоторых Гействий Šø сопоставителей Emmet.", + "emmetPreferencesIntUnit": "ЕГиница по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ Š“Š»Ń целочисленных значений", + "emmetPreferencesFloatUnit": "ЕГиница по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ Š“Š»Ń значений с ŠæŠ»Š°Š²Š°ŃŽŃ‰ŠµŠ¹ Š·Š°ŠæŃŃ‚Š¾Š¹", + "emmetPreferencesCssAfter": "Димвол, который Š±ŃƒŠ“ет помещен в конце свойства CSS при развертывании сокращений CSS", + "emmetPreferencesSassAfter": "Димвол, который Š±ŃƒŠ“ет помещен в конце свойства CSS при развертывании сокращений CSS в файлах Sass", + "emmetPreferencesStylusAfter": "Димвол, который Š±ŃƒŠ“ет помещен в конце свойства CSS при развертывании сокращений CSS в файлах Stylus", + "emmetPreferencesCssBetween": "Димвол, который Š±ŃƒŠ“ет помещен межГу свойством CSS Šø значением при развертывании сокращений CSS", + "emmetPreferencesSassBetween": "Димвол, который Š±ŃƒŠ“ет помещен межГу свойством CSS Šø значением при развертывании сокращений CSS в файлах Sass", + "emmetPreferencesStylusBetween": "Димвол, который Š±ŃƒŠ“ет помещен межГу свойством CSS Šø значением при развертывании сокращений CSS в файлах Stylus" +} \ No newline at end of file diff --git a/i18n/rus/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/rus/extensions/extension-editing/out/extensionLinter.i18n.json index cde1c4fa500..44fb90bb411 100644 --- a/i18n/rus/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/rus/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "Š˜Š·Š¾Š±Ń€Š°Š¶ŠµŠ½ŠøŃ Голжны ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ протокол HTTPS.", "svgsNotValid": "Файлы SVG не ŃŠ²Š»ŃŃŽŃ‚ŃŃ Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¼ источником изображений.", "embeddedSvgsNotValid": "Встроенные файлы SVG не ŃŠ²Š»ŃŃŽŃ‚ŃŃ Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¼ источником изображений.", - "dataUrlsNotValid": "URL-аГреса Ганных не ŃŠ²Š»ŃŃŽŃ‚ŃŃ Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¼ источником изображений." + "dataUrlsNotValid": "URL-аГреса Ганных не ŃŠ²Š»ŃŃŽŃ‚ŃŃ Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¼ источником изображений.", + "relativeUrlRequiresHttpsRepository": "Š”Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Ń… URL-аГресов изображений необхоГимо ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ в файле package.json репозиторий, обращение Šŗ ŠŗŠ¾Ń‚Š¾Ń€Š¾Š¼Ńƒ Š¾ŃŃƒŃ‰ŠµŃŃ‚Š²Š»ŃŠµŃ‚ŃŃ по ŠæŃ€Š¾Ń‚Š¾ŠŗŠ¾Š»Ńƒ HTTPS.", + "relativeIconUrlRequiresHttpsRepository": "Š”Š»Ń ŃŃ‚Š¾Š³Š¾ значка необхоГимо ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ в файле package.json репозиторий, обращение Šŗ ŠŗŠ¾Ń‚Š¾Ń€Š¾Š¼Ńƒ Š¾ŃŃƒŃ‰ŠµŃŃ‚Š²Š»ŃŠµŃ‚ŃŃ по ŠæŃ€Š¾Ń‚Š¾ŠŗŠ¾Š»Ńƒ HTTPS.", + "relativeBadgeUrlRequiresHttpsRepository": "Š”Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Ń… URL-аГресов ŃŠ¼Š±Š»ŠµŠ¼ необхоГимо ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ в файле package.json репозиторий, обращение Šŗ ŠŗŠ¾Ń‚Š¾Ń€Š¾Š¼Ńƒ Š¾ŃŃƒŃ‰ŠµŃŃ‚Š²Š»ŃŠµŃ‚ŃŃ по ŠæŃ€Š¾Ń‚Š¾ŠŗŠ¾Š»Ńƒ HTTPS. " } \ No newline at end of file diff --git a/i18n/rus/extensions/git/out/commands.i18n.json b/i18n/rus/extensions/git/out/commands.i18n.json index 69f509ebf70..f8b4fce36b0 100644 --- a/i18n/rus/extensions/git/out/commands.i18n.json +++ b/i18n/rus/extensions/git/out/commands.i18n.json @@ -12,16 +12,32 @@ "cloning": "ŠšŠ»Š¾Š½ŠøŃ€ŃƒŠµŃ‚ŃŃ репозиторий Git...", "openrepo": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ репозиторий", "proposeopen": "Š’Ń‹ хотите Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ клонированный репозиторий?", + "init repo": "Š˜Š½ŠøŃ†ŠøŠ°Š»ŠøŠ·ŠøŃ€Š¾Š²Š°Ń‚ŃŒ репозиторий", + "create repo": "Š˜Š½ŠøŃ†ŠøŠ°Š»ŠøŠ·ŠøŃ€Š¾Š²Š°Ń‚ŃŒ репозиторий", "HEAD not available": "Š’ŠµŃ€ŃŠøŃ HEAD '{0}' Š½ŠµŠ“Š¾ŃŃ‚ŃƒŠæŠ½Š°.", + "confirm stage files with merge conflicts": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите перенести в ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚очный ŃŃ‚Š°Šæ файлы с конфликтами ŃŠ»ŠøŃŠ½ŠøŃ ({0})?", + "confirm stage file with merge conflicts": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите перенести в ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚очный ŃŃ‚Š°Šæ файлы с конфликтами ŃŠ»ŠøŃŠ½ŠøŃ ({0})?", + "yes": "Да", "confirm revert": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите Š¾Ń‚Š¼ŠµŠ½ŠøŃ‚ŃŒ выбранные ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в {0}?", "revert": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "discard": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "confirm delete": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите ŃƒŠ“Š°Š»ŠøŃ‚ŃŒ {0}?", + "delete file": "Š£Š“Š°Š»ŠøŃ‚ŃŒ файл", "confirm discard": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите Š¾Ń‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в {0}?", "confirm discard multiple": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите Š¾Ń‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в файлах ({0})?", - "discard": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", - "confirm discard all": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите Š¾Ń‚Š¼ŠµŠ½ŠøŃ‚ŃŒ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ? ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŃŃ‚Š¾ Гействие Š½ŠµŠ»ŃŒŠ·Ń!", - "discardAll": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "warn untracked": "Это привеГет Šŗ ŃƒŠ“Š°Š»ŠµŠ½ŠøŃŽ неотслеживаемых файлов ({0})!", + "confirm discard all single": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите Š¾Ń‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в {0}?", + "confirm discard all": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите Š¾Ń‚Š¼ŠµŠ½ŠøŃ‚ŃŒ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в {0} файлах?\nŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŃŃ‚Šø Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ Š½ŠµŠ»ŃŒŠ·Ń!\nŠ’Š°ŃˆŠø Ń‚ŠµŠŗŃƒŃ‰ŠøŠµ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š±ŃƒŠ“ŃƒŃ‚ ŃƒŃ‚ŠµŃ€ŃŠ½Ń‹.", + "discardAll multiple": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в оГном файле", + "discardAll": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ во всех файлах ({0})", + "confirm delete multiple": "Š’Ń‹ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ хотите ŃƒŠ“Š°Š»ŠøŃ‚ŃŒ файлы ({0})?", + "delete files": "Š£Š“Š°Š»ŠøŃ‚ŃŒ файлы", + "there are untracked files single": "ŠŸŃ€Šø отмене изменений Š“Š»Ń ŃŃ‚Š¾Š³Š¾ неотслеживаемого файла ŃŃ‚Š¾Ń‚ файл Š±ŃƒŠ“ет уГален с Гиска: {0}.", + "there are untracked files": "Š”ŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚ {0} неотслеживаемых файлов, которые Š±ŃƒŠ“ŃƒŃ‚ ŃƒŠ“Š°Š»ŠµŠ½Ń‹ с Гиска в ŃŠ»ŃƒŃ‡Š°Šµ отмены изменений.", + "confirm discard all 2": "{0}\n\nŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŃŃ‚Š¾ Гействие Š½ŠµŠ»ŃŒŠ·Ń, Ń‚ŠµŠŗŃƒŃ‰ŠøŠµ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š±ŃƒŠ“ŃƒŃ‚ ŃƒŃ‚ŠµŃ€ŃŠ½Ń‹.", + "yes discard tracked": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š“Š»Ń отслеживаемого файла", + "yes discard tracked multiple": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š“Š»Ń отслеживаемых файлов ({0})", "no staged changes": "ŠžŃ‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚ ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Ń‹Šµ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š“Š»Ń фиксации.\n\nŠ’Ń‹ хотите ŃŠ“ŠµŠ»Š°Ń‚ŃŒ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Ń‹Š¼Šø Šø Š·Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŠøŃ… Š½Š°ŠæŃ€ŃŠ¼ŃƒŃŽ?", - "yes": "Да", "always": "ВсегГа", "no changes": "ŠŠµŃ‚ изменений Š“Š»Ń фиксации.", "commit message": "Дообщение о фиксации", @@ -34,16 +50,25 @@ "delete branch": "Š£Š“Š°Š»ŠøŃ‚ŃŒ Š²ŠµŃ‚Š²ŃŒ", "select a branch to merge from": "Выберите Š²ŠµŃ‚Š²ŃŒ Š“Š»Ń ŃŠ»ŠøŃŠ½ŠøŃ", "merge conflicts": "ŠžŠ±Š½Š°Ń€ŃƒŠ¶ŠµŠ½Ń‹ конфликты ŃŠ»ŠøŃŠ½ŠøŃ. Устраните ŠøŃ… переГ фиксацией.", + "tag name": "Š˜Š¼Ń тега", + "provide tag name": "Укажите ŠøŠ¼Ń тега", + "tag message": "Дообщение", + "provide tag message": "Укажите сообщение Š“Š»Ń Š°Š½Š½Š¾Ń‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ тега", "no remotes to pull": "Š”Š»Ń вашего Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€ŠøŃ не настроены ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Šµ репозитории Š“Š»Ń ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŃ Ганных.", "pick remote pull repo": "Выберите ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Š¹ ŠŗŠ¾Š¼ŠæŃŒŃŽŃ‚ŠµŃ€, с которого ŃŠ»ŠµŠ“ŃƒŠµŃ‚ Š·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ Š²ŠµŃ‚Š²ŃŒ", "no remotes to push": "Š”Š»Ń вашего Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€ŠøŃ не настроены ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Šµ репозитории Š“Š»Ń отправки Ганных.", + "push with tags success": "Файлы с тегами успешно отправлены.", "nobranch": "Š˜Š·Š²Š»ŠµŠŗŠøŃ‚Šµ Š²ŠµŃ‚Š²ŃŒ, чтобы ŠæŠµŃ€ŠµŠ“Š°Ń‚ŃŒ Ганные в ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Š¹ репозиторий.", "pick remote": "Выберите ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Š¹ сервер, на котором нужно Š¾ŠæŃƒŠ±Š»ŠøŠŗŠ¾Š²Š°Ń‚ŃŒ Š²ŠµŃ‚Š²ŃŒ \"{0}\":", "sync is unpredictable": "Это Гействие Š¾Ń‚ŠæŃ€Š°Š²Š»ŃŠµŃ‚ фиксации в \"{0}\" Šø извлекает ŠøŃ… ŠøŠ· ŃŃ‚Š¾Š³Š¾ Ń€Š°ŃŠæŠ¾Š»Š¾Š¶ŠµŠ½ŠøŃ.", "ok": "ŠžŠš", "never again": "ŠžŠš. Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", "no remotes to publish": "Š”Š»Ń вашего Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€ŠøŃ не настроены ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Šµ репозитории Š“Š»Ń ŠæŃƒŠ±Š»ŠøŠŗŠ°Ń†ŠøŠø.", - "disabled": "GIT Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½ или не ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ в ŃŃ‚Š¾Š¹ рабочей области", + "no changes stash": "ŠžŃ‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ, которые необхоГимо ŃŠæŃ€ŃŃ‚Š°Ń‚ŃŒ.", + "provide stash message": "Укажите сообщение о скрытии", + "stash message": "Дообщение о скрытии", + "no stashes": "ŠžŃ‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚ ŃŠæŃ€ŃŃ‚Š°Š½Š½Ń‹Šµ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ, которые необхоГимо Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ.", + "pick stash to pop": "Выберите ŃŠæŃ€ŃŃ‚Š°Š½Š½Š¾Šµ изменение Š“Š»Ń Š¾Ń‚Š¾Š±Ń€Š°Š¶ŠµŠ½ŠøŃ", "clean repo": "ŠžŃ‡ŠøŃŃ‚ŠøŃ‚Šµ рабочее Герево Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€ŠøŃ переГ извлечением.", "cant push": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š¾Ń‚ŠæŃ€Š°Š²ŠøŃ‚ŃŒ ссылки в ŃƒŠ“Š°Š»ŠµŠ½Š½ŃƒŃŽ Š²ŠµŃ‚Š²ŃŒ. Дначала выберите \"Š˜Š·Š²Š»ŠµŃ‡ŃŒ\", чтобы ŠøŠ½Ń‚ŠµŠ³Ń€ŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ.", "git error details": "Git: {0}", diff --git a/i18n/rus/extensions/git/out/model.i18n.json b/i18n/rus/extensions/git/out/model.i18n.json index c349ed7bde0..00d28dbb017 100644 --- a/i18n/rus/extensions/git/out/model.i18n.json +++ b/i18n/rus/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ", - "merge changes": "ŠžŠ±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", - "staged changes": "ŠŸŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Š¾ сохраненные ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", - "changes": "Š˜Š·Š¼ŠµŠ½ŠµŠ½ŠøŃ", - "ok": "ŠžŠš", - "neveragain": "Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", - "huge": "Репозиторий git в '{0}' имеет Š¾Ń‡ŠµŠ½ŃŒ много активных изменений, Ń‚Š¾Š»ŃŒŠŗŠ¾ Ń‡Š°ŃŃ‚ŃŒ Ń„ŃƒŠ½ŠŗŃ†ŠøŠ¹ Git Š±ŃƒŠ“ŠµŃ‚ Š“Š¾ŃŃ‚ŃƒŠæŠ½Š°." + "no repositories": "Š”Š¾ŃŃ‚ŃƒŠæŠ½Ń‹Šµ репозитории Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚", + "pick repo": "Выберите репозиторий" } \ No newline at end of file diff --git a/i18n/rus/extensions/git/out/repository.i18n.json b/i18n/rus/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..053f8f8b45f --- /dev/null +++ b/i18n/rus/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ", + "index modified": "ИнГекс изменен", + "modified": "Изменено", + "index added": "ИнГекс Гобавлен", + "index deleted": "ИнГекс уГален", + "deleted": "УГалено", + "index renamed": "ИнГекс переименован", + "index copied": "ИнГекс скопирован", + "untracked": "ŠŠµ Š¾Ń‚ŃŠ»ŠµŠ¶ŠøŠ²Š°ŠµŃ‚ŃŃ", + "ignored": "ŠŸŃ€Š¾ŠøŠ³Š½Š¾Ń€ŠøŃ€Š¾Š²Š°Š½Š¾", + "both deleted": "УГалено обеими сторонами", + "added by us": "Добавлено нами", + "deleted by them": "УГалено ими", + "added by them": "Добавлено ими", + "deleted by us": "УГалено нами", + "both added": "Добавлено обеими сторонами", + "both modified": "Изменено обеими сторонами", + "commit": "Commit", + "merge changes": "ŠžŠ±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "staged changes": "ŠŸŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Š¾ сохраненные ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "changes": "Š˜Š·Š¼ŠµŠ½ŠµŠ½ŠøŃ", + "ok": "ŠžŠš", + "neveragain": "Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", + "huge": "Репозиторий git в '{0}' имеет Š¾Ń‡ŠµŠ½ŃŒ много активных изменений, Ń‚Š¾Š»ŃŒŠŗŠ¾ Ń‡Š°ŃŃ‚ŃŒ Ń„ŃƒŠ½ŠŗŃ†ŠøŠ¹ Git Š±ŃƒŠ“ŠµŃ‚ Š“Š¾ŃŃ‚ŃƒŠæŠ½Š°." +} \ No newline at end of file diff --git a/i18n/rus/extensions/git/package.i18n.json b/i18n/rus/extensions/git/package.i18n.json index cfd880ed746..27170f9c192 100644 --- a/i18n/rus/extensions/git/package.i18n.json +++ b/i18n/rus/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "ŠšŠ»Š¾Š½ŠøŃ€Š¾Š²Š°Ń‚ŃŒ", "command.init": "Š˜Š½ŠøŃ†ŠøŠ°Š»ŠøŠ·ŠøŃ€Š¾Š²Š°Ń‚ŃŒ репозиторий", + "command.close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ репозиторий", "command.refresh": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ", "command.openChange": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", "command.openFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл", @@ -22,22 +23,29 @@ "command.commit": "Commit", "command.commitStaged": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Š¾ сохраненные ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ", "command.commitStagedSigned": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Ń‹Šµ ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Ń‹ (Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š¾)", + "command.commitStagedAmend": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Ń‹Šµ (изменение)", "command.commitAll": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ все", "command.commitAllSigned": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ все (Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š¾)", + "command.commitAllAmend": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ все (изменение)", "command.undoCommit": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠæŠ¾ŃŠ»ŠµŠ“Š½ŃŽŃŽ Ń„ŠøŠŗŃŠ°Ń†ŠøŃŽ", "command.checkout": "Š˜Š·Š²Š»ŠµŃ‡ŃŒ в...", "command.branch": "Š”Š¾Š·Š“Š°Ń‚ŃŒ Š²ŠµŃ‚Š²ŃŒ...", "command.deleteBranch": "Š£Š“Š°Š»ŠøŃ‚ŃŒ Š²ŠµŃ‚Š²ŃŒ...", "command.merge": "ŠžŠ±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚ŃŒ Š²ŠµŃ‚Š²ŃŒ...", + "command.createTag": "Š”Š¾Š·Š“Š°Ń‚ŃŒ тег", "command.pull": "ŠŸŠ¾Š»ŃƒŃ‡ŠøŃ‚ŃŒ", "command.pullRebase": "ŠŸŠ¾Š»ŃƒŃ‡ŠøŃ‚ŃŒ (ŠæŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ ŠøŠ· оГной ветви в Š“Ń€ŃƒŠ³ŃƒŃŽ)", "command.pullFrom": "Š—Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ с...", "command.push": "ŠžŃ‚ŠæŃ€Š°Š²ŠøŃ‚ŃŒ", "command.pushTo": "ŠžŃ‚ŠæŃ€Š°Š²ŠøŃ‚ŃŒ в:", + "command.pushWithTags": "ŠžŃ‚ŠæŃ€Š°Š²ŠøŃ‚ŃŒ с тегами", "command.sync": "Š”ŠøŠ½Ń…Ń€Š¾Š½ŠøŠ·Š°Ń†ŠøŃ", "command.publish": "ŠžŠæŃƒŠ±Š»ŠøŠŗŠ¾Š²Š°Ń‚ŃŒ Š²ŠµŃ‚Š²ŃŒ", "command.showOutput": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ выхоГные Ганные GIT", "command.ignore": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ файл в .gitignore", + "command.stash": "Š”ŠæŃ€ŃŃ‚Š°Ń‚ŃŒ", + "command.stashPop": "Š˜Š·Š²Š»ŠµŃ‡ŃŒ ŃŠæŃ€ŃŃ‚Š°Š½Š½Š¾Šµ", + "command.stashPopLatest": "Š˜Š·Š²Š»ŠµŃ‡ŃŒ послеГнее ŃŠæŃ€ŃŃ‚Š°Š½Š½Š¾Šµ", "config.enabled": "Š’ŠŗŠ»ŃŽŃ‡ŠµŠ½ ли GIT", "config.path": "ŠŸŃƒŃ‚ŃŒ Šŗ ŠøŃŠæŠ¾Š»Š½ŃŠµŠ¼Š¾Š¼Ńƒ Ń„Š°Š¹Š»Ńƒ GIT", "config.autorefresh": "Š’ŠŗŠ»ŃŽŃ‡ŠµŠ½Š¾ ли автоматическое обновление", @@ -49,5 +57,7 @@ "config.ignoreLegacyWarning": "Š˜Š³Š½Š¾Ń€ŠøŃ€ŃƒŠµŃ‚ ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠµ об ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠµŠ¹ версии Git", "config.ignoreLimitWarning": "Š˜Š³Š½Š¾Ń€ŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠµ, когГа в репозитории слишком много изменений", "config.defaultCloneDirectory": "Расположение по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ, в которое Š±ŃƒŠ“ет клонирован репозиторий Git", - "config.enableSmartCommit": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ при Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŠøŠø ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Ń‹Ń… изменений." + "config.enableSmartCommit": "Š—Š°Ń„ŠøŠŗŃŠøŃ€Š¾Š²Š°Ń‚ŃŒ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ при Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŠøŠø ŠæŃ€Š¾Š¼ŠµŠ¶ŃƒŃ‚Š¾Ń‡Š½Ń‹Ń… изменений.", + "config.enableCommitSigning": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ поГписывание фиксации с GPG.", + "config.discardAllScope": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, какие ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š¾Ń‚Š¼ŠµŠ½ŃŃŽŃ‚ŃŃ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ команГы \"ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ\". ŠŸŃ€Šø указании Š·Š½Š°Ń‡ŠµŠ½ŠøŃ \"all\" Š¾Ń‚Š¼ŠµŠ½ŃŃŽŃ‚ŃŃ все ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ, при указании Š·Š½Š°Ń‡ŠµŠ½ŠøŃ \"tracked\" Š¾Ń‚Š¼ŠµŠ½ŃŃŽŃ‚ŃŃ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ в отслеживаемых файлах, при указании Š·Š½Š°Ń‡ŠµŠ½ŠøŃ \"prompt\" Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ окно ŠæŠ¾Š“Ń‚Š²ŠµŃ€Š¶Š“ŠµŠ½ŠøŃ кажГый раз при выполнении Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ." } \ No newline at end of file diff --git a/i18n/rus/extensions/grunt/out/main.i18n.json b/i18n/rus/extensions/grunt/out/main.i18n.json index 7d21b8b17d9..2de2f8e2719 100644 --- a/i18n/rus/extensions/grunt/out/main.i18n.json +++ b/i18n/rus/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Дбой автоматического опреГелений заГаний Grunt. ŠžŃˆŠøŠ±ŠŗŠ°: {0}" + "execFailed": "ŠŠµ уГалось автоматически Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ Š·Š°Š“Š°Š½ŠøŃ Grunt Š“Š»Ń папки {0}. ŠžŃˆŠøŠ±ŠŗŠ°: {1}" } \ No newline at end of file diff --git a/i18n/rus/extensions/gulp/out/main.i18n.json b/i18n/rus/extensions/gulp/out/main.i18n.json index 5a72cc93854..21e246af6b3 100644 --- a/i18n/rus/extensions/gulp/out/main.i18n.json +++ b/i18n/rus/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "ŠŠ²Ń‚Š¾Š¾Š±Š½Š°Ń€ŃƒŠ¶ŠµŠ½ŠøŠµ галпа с ошибкой {0}" + "execFailed": "ŠŠµ уГалось автоматически Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ Š·Š°Š“Š°Š½ŠøŃ gulp Š“Š»Ń папки {0}. ŠžŃˆŠøŠ±ŠŗŠ°: {1}" } \ No newline at end of file diff --git a/i18n/rus/extensions/html/package.i18n.json b/i18n/rus/extensions/html/package.i18n.json index 70b47820fce..9600097ae32 100644 --- a/i18n/rus/extensions/html/package.i18n.json +++ b/i18n/rus/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµ Š¼Š¾Š“ŃƒŠ»Ń Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ HTML по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ (Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ ŠæŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠŗŠ°)", + "html.format.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ/Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ моГуль Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ HTML по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", "html.format.wrapLineLength.desc": "Максимальное число символов на ŃŃ‚Ń€Š¾ŠŗŃƒ (0 — Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ).", "html.format.unformatted.desc": "Дписок тегов, которые не ŃŠ»ŠµŠ“ŃƒŠµŃ‚ повторно Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ, с Ń€Š°Š·Š“ŠµŠ»ŠøŃ‚ŠµŠ»ŃŠ¼Šø-Š·Š°ŠæŃŃ‚Ń‹Š¼Šø. Значение \"NULL\" по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ означает все теги, перечисленные на странице https://www.w3.org/TR/html5/dom.html#phrasing-content.", "html.format.contentUnformatted.desc": "РазГеленный Š·Š°ŠæŃŃ‚ыми список тегов, в которых формат соГержимого не Голжен ŠøŠ·Š¼ŠµŠ½ŃŃ‚ŃŒŃŃ. Значение null Š·Š°Š“Š°ŠµŃ‚ŃŃ по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ Š“Š»Ń тега pre.", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š°Ń поГГержка ŃŠ·Ń‹ŠŗŠ° HTML ŠæŃ€ŠµŠ“Š»Š°Š³Š°Ń‚ŃŒ теги Šø свойства AngularĀ 1.", "html.suggest.ionic.desc": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š°Ń поГГержка ŃŠ·Ń‹ŠŗŠ° HTML ŠæŃ€ŠµŠ“Š»Š°Š³Š°Ń‚ŃŒ теги, свойства Šø Š·Š½Š°Ń‡ŠµŠ½ŠøŃ Ionic.", "html.suggest.html5.desc": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š°Ń поГГержка ŃŠ·Ń‹ŠŗŠ° HTML ŠæŃ€ŠµŠ“Š»Š°Š³Š°Ń‚ŃŒ теги, свойства Šø Š·Š½Š°Ń‡ŠµŠ½ŠøŃ HTML5.", + "html.trace.server.desc": "ŠžŃ‚ŃŠ»ŠµŠ¶ŠøŠ²Š°ŠµŃ‚ обмен Ганными межГу VS Code Šø ŃŠ·Ń‹ŠŗŠ¾Š²Ń‹Š¼ сервером HTML. ", "html.validate.scripts": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š°Ń поГГержка ŃŠ·Ń‹ŠŗŠ° HTML ŠæŃ€Š¾Š²ŠµŃ€ŃŃ‚ŃŒ внеГренные сценарии.", - "html.validate.styles": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š°Ń поГГержка ŃŠ·Ń‹ŠŗŠ° HTML ŠæŃ€Š¾Š²ŠµŃ€ŃŃ‚ŃŒ внеГренные стили." + "html.validate.styles": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š°Ń поГГержка ŃŠ·Ń‹ŠŗŠ° HTML ŠæŃ€Š¾Š²ŠµŃ€ŃŃ‚ŃŒ внеГренные стили.", + "html.autoClosingTags": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ автоматическое закрытие тегов HTML. " } \ No newline at end of file diff --git a/i18n/rus/extensions/jake/out/main.i18n.json b/i18n/rus/extensions/jake/out/main.i18n.json index 3f8458b5b98..7a33b80be29 100644 --- a/i18n/rus/extensions/jake/out/main.i18n.json +++ b/i18n/rus/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Дбой автоматического опреГелений заГаний Jake. ŠžŃˆŠøŠ±ŠŗŠ°: {0}" + "execFailed": "ŠŠµ уГалось автоматически Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ Š·Š°Š“Š°Š½ŠøŃ Jake Š“Š»Ń папки {0}. ŠžŃˆŠøŠ±ŠŗŠ°: {1}" } \ No newline at end of file diff --git a/i18n/rus/extensions/json/package.i18n.json b/i18n/rus/extensions/json/package.i18n.json index 468445675ae..14f78a0ce8a 100644 --- a/i18n/rus/extensions/json/package.i18n.json +++ b/i18n/rus/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŠµŠ½ŠøŠµ схемы Š“Š»Ń указанного URL-аГреса. Š”Ń…ŠµŠ¼Ńƒ необхоГимо ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ Ń‚Š¾Š»ŃŒŠŗŠ¾ Š“Š»Ń того, чтобы не Š¾Š±Ń€Š°Ń‰Š°Ń‚ŃŒŃŃ по URL-Š°Š“Ń€ŠµŃŃƒ схемы.", "json.format.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµ Š¼Š¾Š“ŃƒŠ»Ń Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ JSON по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ (Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ ŠæŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠŗŠ°)", "json.tracing.desc": "ŠžŃ‚ŃŠ»ŠµŠ¶ŠøŠ²Š°ŠµŃ‚ ŃŠ²ŃŠ·ŃŒ межГу VS Code Šø ŃŠ·Ń‹ŠŗŠ¾Š²Ń‹Š¼ сервером JSON.", - "json.colorDecorators.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Гекораторы цвета." + "json.colorDecorators.enable.desc": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Гекораторы цвета.", + "json.colorDecorators.enable.deprecationMessage": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ \"json.colorDecorators.enable\" ŃƒŃŃ‚Š°Ń€ŠµŠ». Š¢ŠµŠæŠµŃ€ŃŒ вместо него ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся параметр \"editor.colorDecorators\"." } \ No newline at end of file diff --git a/i18n/rus/extensions/markdown/out/extension.i18n.json b/i18n/rus/extensions/markdown/out/extension.i18n.json index 5c5b3690dc6..5a81b95de6e 100644 --- a/i18n/rus/extensions/markdown/out/extension.i18n.json +++ b/i18n/rus/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "ŠŠµ уГалось Š·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ 'markdown.styles': {0}" + "onPreviewStyleLoadError": "ŠŠµ уГалось Š·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ 'markdown.styles': {0}", + "previewTitle": "ŠŸŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Š¹ просмотр {0}" } \ No newline at end of file diff --git a/i18n/rus/extensions/markdown/out/previewContentProvider.i18n.json b/i18n/rus/extensions/markdown/out/previewContentProvider.i18n.json index 8b6ad71cd4e..62ff186c858 100644 --- a/i18n/rus/extensions/markdown/out/previewContentProvider.i18n.json +++ b/i18n/rus/extensions/markdown/out/previewContentProvider.i18n.json @@ -3,4 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "preview.securityMessage.text": "ŠŠµŠŗŠ¾Ń‚Š¾Ń€Š¾Šµ соГержимое в ŃŃ‚Š¾Š¼ Š“Š¾ŠŗŃƒŠ¼ŠµŠ½Ń‚Šµ было Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½Š¾", + "preview.securityMessage.title": "Š’ ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¼ просмотре Markdown было Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½Š¾ ŠæŠ¾Ń‚ŠµŠ½Ń†ŠøŠ°Š»ŃŒŠ½Š¾ опасное или ненаГежное соГержимое. Чтобы Ń€Š°Š·Ń€ŠµŃˆŠøŃ‚ŃŒ ненаГежное соГержимое или Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ сценарии, измените параметры безопасности ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра Markdown.", + "preview.securityMessage.label": "ŠŸŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠµ безопасности об Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠø соГержимого" +} \ No newline at end of file diff --git a/i18n/rus/extensions/markdown/out/security.i18n.json b/i18n/rus/extensions/markdown/out/security.i18n.json index 9dff589ebb9..11a39b993e2 100644 --- a/i18n/rus/extensions/markdown/out/security.i18n.json +++ b/i18n/rus/extensions/markdown/out/security.i18n.json @@ -4,5 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.currentSelection": "Š¢ŠµŠŗŃƒŃ‰ŠøŠ¹ параметр" + "strict.title": "Дтрогий", + "strict.description": "Š—Š°Š³Ń€ŃƒŠ¶Š°Ń‚ŃŒ Ń‚Š¾Š»ŃŒŠŗŠ¾ безопасное соГержимое", + "insecureContent.title": "Š Š°Š·Ń€ŠµŃˆŠøŃ‚ŃŒ небезопасное соГержимое", + "insecureContent.description": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ Š·Š°Š³Ń€ŃƒŠ·ŠŗŃƒ соГержимого через HTTP", + "disable.title": "ŠžŃ‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ", + "disable.description": "Š Š°Š·Ń€ŠµŃˆŠøŃ‚ŃŒ все соГержимое Šø выполнение сценариев. ŠŠµ Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŃ‚ŃŃ", + "moreInfo.title": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ", + "preview.showPreviewSecuritySelector.title": "Установите параметры безопасности Š“Š»Ń ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра Markdown в ŃŃ‚Š¾Š¹ рабочей области" } \ No newline at end of file diff --git a/i18n/rus/extensions/markdown/package.i18n.json b/i18n/rus/extensions/markdown/package.i18n.json index 6ded2043a7d..bf621b96f2e 100644 --- a/i18n/rus/extensions/markdown/package.i18n.json +++ b/i18n/rus/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, как переносы строк Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ в области ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра файла Markdown. Если ŃƒŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ ŃŃ‚Š¾Ń‚ параметр в значение 'true',
Š±ŃƒŠ“ŃƒŃ‚ ŃŠ¾Š·Š“Š°Š²Š°Ń‚ŃŒŃŃ Š“Š»Ń кажГой новой строки.", + "markdown.preview.linkify": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ преобразование текста в URL Š“Š»Ń ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра Markdown.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Двойной щелчок в области ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра Markdown в реГакторе.", "markdown.preview.fontFamily.desc": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ семейство ŃˆŃ€ŠøŃ„Ń‚Š¾Š², используемое в области ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра файла Markdown.", "markdown.preview.fontSize.desc": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ размер ŃˆŃ€ŠøŃ„Ń‚Š° (в ŠæŠøŠŗŃŠµŠ»ŃŃ…), ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Š¹ в области ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра файла Markdown.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ Š¾Š±Š»Š°ŃŃ‚ŃŒ ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра сбоку", "markdown.showSource.title": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ источник", "markdown.styles.dec": "Дписок URL-аГресов или Š»Š¾ŠŗŠ°Š»ŃŒŠ½Ń‹Ń… ŠæŃƒŃ‚ŠµŠ¹ Šŗ таблицам стилей CSS, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Ń… ŠøŠ· области ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра файла Markdown. ŠžŃ‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŠæŃƒŃ‚Šø ŠøŠ½Ń‚ŠµŃ€ŠæŃ€ŠµŃ‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ папки, открытой в провоГнике. Если папка не открыта, они ŠøŠ½Ń‚ŠµŃ€ŠæŃ€ŠµŃ‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ Ń€Š°ŃŠæŠ¾Š»Š¾Š¶ŠµŠ½ŠøŃ файла Markdown. Все символы '\\' Голжны Š·Š°ŠæŠøŃŃ‹Š²Š°Ń‚ŃŒŃŃ в виГе '\\\\'.", - "markdown.showPreviewSecuritySelector.title": "Š˜Š·Š¼ŠµŠ½ŠøŃ‚ŃŒ параметры безопасности Š“Š»Ń ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра Markdown", - "markdown.trace.desc": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ веГение Š¶ŃƒŃ€Š½Š°Š»Š° отлаГки Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Markdown." + "markdown.showPreviewSecuritySelector.title": "Š˜Š·Š¼ŠµŠ½ŠøŃ‚ŃŒ параметры безопасности Š“Š»Ń ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра", + "markdown.trace.desc": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ веГение Š¶ŃƒŃ€Š½Š°Š»Š° отлаГки Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Markdown.", + "markdown.refreshPreview.title": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Š¹ просмотр" } \ No newline at end of file diff --git a/i18n/rus/extensions/npm/out/main.i18n.json b/i18n/rus/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/rus/extensions/npm/out/main.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/rus/extensions/npm/package.i18n.json b/i18n/rus/extensions/npm/package.i18n.json index 48afb646815..f10d56b2585 100644 --- a/i18n/rus/extensions/npm/package.i18n.json +++ b/i18n/rus/extensions/npm/package.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "config.npm.autoDetect": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ автоматическое опреГеление сценариев npm. Значение по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ — \"Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Š¾\"." + "config.npm.autoDetect": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ автоматическое опреГеление сценариев npm. Значение по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ — \"Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Š¾\".", + "config.npm.runSilent": "Š—Š°ŠæŃƒŃŠŗŠ°Ń‚ŃŒ команГы npm с параметром `--silent`" } \ No newline at end of file diff --git a/i18n/rus/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/rus/extensions/typescript/out/features/taskProvider.i18n.json index 8b6ad71cd4e..2d3a9a08b55 100644 --- a/i18n/rus/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/rus/extensions/typescript/out/features/taskProvider.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "buildTscLabel": "сборка – {0}", + "buildAndWatchTscLabel": "отслеживание – {0}" +} \ No newline at end of file diff --git a/i18n/rus/extensions/typescript/out/utils/api.i18n.json b/i18n/rus/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..1af9a8a0415 --- /dev/null +++ b/i18n/rus/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "ŠŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š°Ń Š²ŠµŃ€ŃŠøŃ" +} \ No newline at end of file diff --git a/i18n/rus/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/rus/extensions/typescript/out/utils/versionPicker.i18n.json index d7e26443046..e545c9ff436 100644 --- a/i18n/rus/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/rus/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "Š˜ŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Š²ŠµŃ€ŃŠøŃŽ VSCode", + "useVSCodeVersionOption": "Š˜ŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Š²ŠµŃ€ŃŠøŃŽ VS Code", "useWorkspaceVersionOption": "Š˜ŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Š²ŠµŃ€ŃŠøŃŽ рабочей области", "learnMore": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ", "selectTsVersion": "Выберите Š²ŠµŃ€ŃŠøŃŽ TypeScript, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼ŃƒŃŽ Š“Š»Ń ŃŠ·Ń‹ŠŗŠ¾Š²Ń‹Ń… Ń„ŃƒŠ½ŠŗŃ†ŠøŠ¹ JavaScript Šø TypeScript." diff --git a/i18n/rus/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/rus/extensions/typescript/out/utils/versionProvider.i18n.json index f97639bb41b..5cc970d9726 100644 --- a/i18n/rus/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/rus/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "couldNotLoadTsVersion": "ŠŠµ уГалось Š·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ Š²ŠµŃ€ŃŠøŃŽ TypeScript по ŃŃ‚Š¾Š¼Ńƒ ŠæŃƒŃ‚Šø", "noBundledServerFound": "Файл tsserver VSCode был уГален Š“Ń€ŃƒŠ³ŠøŠ¼ приложением, например, в Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Šµ Š¾ŃˆŠøŠ±Š¾Ń‡Š½Š¾Š³Š¾ ŃŃ€Š°Š±Š°Ń‚Ń‹Š²Š°Š½ŠøŃ среГства Š¾Š±Š½Š°Ń€ŃƒŠ¶ŠµŠ½ŠøŃ Š²ŠøŃ€ŃƒŃŠ¾Š². ŠŸŠµŃ€ŠµŃƒŃŃ‚Š°Š½Š¾Š²ŠøŃ‚Šµ VSCode." } \ No newline at end of file diff --git a/i18n/rus/extensions/typescript/package.i18n.json b/i18n/rus/extensions/typescript/package.i18n.json index 990537ef568..15940c3fc59 100644 --- a/i18n/rus/extensions/typescript/package.i18n.json +++ b/i18n/rus/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Дополните Ń„ŃƒŠ½ŠŗŃ†ŠøŠø ŃŠøŠ³Š½Š°Ń‚ŃƒŃ€Š°Š¼Šø ŠøŃ… параметров.", "typescript.tsdk.desc": "Указывает ŠæŃƒŃ‚ŃŒ Šŗ папке, соГержащей файлы tsserver Šø lib*.d.ts, которые необхоГимо ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ.", - "typescript.disableAutomaticTypeAcquisition": "ŠžŃ‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ автоматическое ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŠµ типа. Š¢Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ TypeScriptĀ 2.0.6 Šø более позГней версии Šø ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗ после его ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ.", + "typescript.disableAutomaticTypeAcquisition": "ŠžŃ‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ автоматическое ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŠµ типов. Š¢Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ TypeScriptĀ 2.0.6 Šø более позГней версии.", "typescript.tsserver.log": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ веГение Š¶ŃƒŃ€Š½Š°Š»Š° Š“Š»Ń сервера TS. Этот Š¶ŃƒŃ€Š½Š°Š» можно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Š“Š»Ń Гиагностики проблем сервера TS. Š’ Š¶ŃƒŃ€Š½Š°Š»Šµ Š¼Š¾Š³ŃƒŃ‚ ŃŠ¾Š“ŠµŃ€Š¶Š°Ń‚ŃŒŃŃ ŠæŃƒŃ‚Šø Šŗ файлам, исхоГный коГ Šø Š“Ń€ŃƒŠ³ŠøŠµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ ŠøŠ· вашего проекта, в том числе Š½Š¾ŃŃŃ‰ŠøŠµ ŠŗŠ¾Š½Ń„ŠøŠ“ŠµŠ½Ń†ŠøŠ°Š»ŃŒŠ½Ń‹Š¹ характер.", "typescript.tsserver.trace": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Ń‚Ń€Š°ŃŃŠøŃ€Š¾Š²ŠŗŃƒ сообщений, Š¾Ń‚ŠæŃ€Š°Š²Š»ŃŠµŠ¼Ń‹Ń… на сервер TS. Š­Ń‚Ńƒ Ń‚Ń€Š°ŃŃŠøŃ€Š¾Š²ŠŗŃƒ можно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Š“Š»Ń Гиагностики проблем сервера TS. Трассировка может ŃŠ¾Š“ŠµŃ€Š¶Š°Ń‚ŃŒ ŠæŃƒŃ‚Šø Šŗ файлам, исхоГный коГ Šø Š“Ń€ŃƒŠ³ŠøŠµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ ŠøŠ· вашего проекта, в том числе ŠŗŠ¾Š½Ń„ŠøŠ“ŠµŠ½Ń†ŠøŠ°Š»ŃŒŠ½Ń‹Šµ Ганные.", "typescript.validate.enable": "Š’ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµ проверки TypeScript.", @@ -44,7 +44,6 @@ "typescript.npm": "Указывает ŠæŃƒŃ‚ŃŒ Šŗ ŠøŃŠæŠ¾Š»Š½ŃŠµŠ¼Š¾Š¼Ńƒ Ń„Š°Š¹Š»Ńƒ NPM, используемому Š“Š»Ń автоматического ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŃ типа. Š¢Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ TypeScript версии 2.3.4 или более позГней версии.", "typescript.check.npmIsInstalled": "ŠŸŃ€Š¾Š²ŠµŃ€ŃŠµŃ‚, ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ ли NPM Š“Š»Ń автоматического ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŃ типов.", "javascript.nameSuggestions": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ/Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ использование ŃƒŠ½ŠøŠŗŠ°Š»ŃŒŠ½Ń‹Ń… имен ŠøŠ· файла в списках преГложений JavaScript.", - "typescript.tsc.autoDetect": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ автоматическое опреГелние заГаний tsc.", "typescript.problemMatchers.tsc.label": "ŠŸŃ€Š¾Š±Š»ŠµŠ¼Ń‹ TypeScript", "typescript.problemMatchers.tscWatch.label": "ŠŸŃ€Š¾Š±Š»ŠµŠ¼Ń‹ TypeScript (режим Š½Š°Š±Š»ŃŽŠ“ŠµŠ½ŠøŃ)" } \ No newline at end of file diff --git a/i18n/rus/src/vs/code/electron-main/auth.i18n.json b/i18n/rus/src/vs/code/electron-main/auth.i18n.json index 8b6ad71cd4e..a419dfadc51 100644 --- a/i18n/rus/src/vs/code/electron-main/auth.i18n.json +++ b/i18n/rus/src/vs/code/electron-main/auth.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "authRequire": "Š¢Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ проверка поГлинности прокси-сервера", + "proxyauth": "ŠŸŃ€Š¾ŠŗŃŠø-сервер {0} Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ проверки поГлинности." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/code/electron-main/menus.i18n.json b/i18n/rus/src/vs/code/electron-main/menus.i18n.json index 82539b857e7..683007474d8 100644 --- a/i18n/rus/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/rus/src/vs/code/electron-main/menus.i18n.json @@ -22,9 +22,11 @@ "miQuit": "Выйти ŠøŠ· {0}", "miNewFile": "&&ŠŠ¾Š²Ń‹Š¹ файл", "miOpen": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ...", + "miOpenWorkspace": "&&ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ...", "miOpenFolder": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ &&папку...", "miOpenFile": "&&ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл...", "miOpenRecent": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ &&послеГние", + "miSaveWorkspaceAs": "&&Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ как...", "miAddFolderToWorkspace": "&& Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ папку в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ...", "miSave": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ", "miSaveAs": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ &&как...", @@ -32,6 +34,7 @@ "miAutoSave": "Автосохранение", "miRevert": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ &&ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в файле", "miCloseWindow": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ &&окно", + "miCloseWorkspace": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ &&Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ", "miCloseFolder": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ &&папку", "miCloseEditor": "&&Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ реГактор", "miExit": "Š’&&ыхоГ", @@ -44,6 +47,7 @@ "miPreferences": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹", "miReopenClosedEditor": "&&ŠŸŠ¾Š²Ń‚Š¾Ń€Š½Š¾ Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ закрытый реГактор", "miMore": "&&Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ...", + "miClearRecentOpen": "&&ŠžŃ‡ŠøŃŃ‚ŠøŃ‚ŃŒ неГавно открытые", "miUndo": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ", "miRedo": "Š’ŠµŃ€Š½ŃƒŃ‚ŃŒ", "miCut": "Š’Ń‹&&Ń€ŠµŠ·Š°Ń‚ŃŒ", @@ -98,6 +102,7 @@ "miHideActivityBar": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ &&панель Гействий", "miShowActivityBar": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ &&панель Гействий", "miToggleWordWrap": "&&Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ/Š²Ń‹ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ перенос текста", + "miToggleMinimap": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ мини-ŠŗŠ°Ń€Ń‚Ńƒ", "miToggleRenderWhitespace": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ/&&ŃŠŗŃ€Ń‹Ń‚ŃŒ символы пробелов", "miToggleRenderControlCharacters": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ &&ŃƒŠæŃ€Š°Š²Š»ŃŃŽŃ‰ŠøŠµ символы", "miZoomIn": "&&Š£Š²ŠµŠ»ŠøŃ‡ŠøŃ‚ŃŒ", @@ -146,6 +151,10 @@ "mZoom": "Š˜Š·Š¼ŠµŠ½ŠøŃ‚ŃŒ Š¼Š°ŃŃˆŃ‚Š°Š±", "mBringToFront": "ŠŸŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ все на переГний план", "miSwitchWindow": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ &&окно...", + "mShowPreviousTab": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŃƒŃŽ вклаГку", + "mShowNextTab": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŃƒŃŽ вклаГку", + "mMoveTabToNewWindow": "ŠŸŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ вклаГку в новое окно", + "mMergeAllWindows": "ŠžŠ±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚ŃŒ все окна", "miToggleDevTools": "&&ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ/ŃŠŗŃ€Ń‹Ń‚ŃŒ среГства разработчика", "miAccessibilityOptions": "Š”ŠæŠµŃ†ŠøŠ°Š»ŃŒŠ½Ń‹Šµ &&возможности", "miReportIssues": "&&Š”Š¾Š¾Š±Ń‰ŠøŃ‚ŃŒ о проблемах", @@ -163,10 +172,11 @@ "miAbout": "&&Šž программе", "miRunTask": "&&Š—Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ...", "miBuildTask": "Š—Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ &&Š·Š°Š“Š°Ń‡Ńƒ сборки...", + "miRunningTask": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Š²Ń‹ŠæŠ¾Š»Š½ŃŃŽŃ‰&&ŠøŠµŃŃ заГачи...", "miRestartTask": "П&&ŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ Š·Š°ŠæŃƒŃ‰ŠµŠ½Š½ŃƒŃŽ Š·Š°Š“Š°Ń‡Ńƒ...", "miTerminateTask": "&&Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ...", - "miConfigureTask": "&&ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ заГачи", - "miConfigureBuildTask": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки по у&&Š¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", + "miConfigureTask": "&&ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ заГачи...", + "miConfigureBuildTask": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки по у&&Š¼Š¾Š»Ń‡Š°Š½ŠøŃŽ...", "accessibilityOptionsWindowTitle": "Š”ŠæŠµŃ†ŠøŠ°Š»ŃŒŠ½Ń‹Šµ возможности", "miRestartToUpdate": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ ŠæŃ€Š¾Š³Ń€Š°Š¼Š¼Ńƒ Š“Š»Ń Š¾Š±Š½Š¾Š²Š»ŠµŠ½ŠøŃ...", "miCheckingForUpdates": "Š˜Š“ŠµŃ‚ проверка Š½Š°Š»ŠøŃ‡ŠøŃ обновлений...", @@ -174,5 +184,6 @@ "miDownloadingUpdate": "Š”ŠŗŠ°Ń‡ŠøŠ²Š°ŠµŃ‚ŃŃ обновление...", "miInstallingUpdate": "Š˜Š“ŠµŃ‚ ŃƒŃŃ‚Š°Š½Š¾Š²ŠŗŠ° Š¾Š±Š½Š¾Š²Š»ŠµŠ½ŠøŃ...", "miCheckForUpdates": "ŠŸŃ€Š¾Š²ŠµŃ€ŠøŃ‚ŃŒ наличие обновлений...", + "aboutDetail": "\nŠ’ŠµŃ€ŃŠøŃ {0}\nŠ¤ŠøŠŗŃŠ°Ń†ŠøŃ {1}\nДата {2}\nŠžŠ±Š»Š¾Ń‡ŠŗŠ° {3}\nŠžŃ‚Ń€ŠøŃŠ¾Š²Ń‰ŠøŠŗ {4}\nУзел {5}\nŠŃ€Ń…ŠøŃ‚ŠµŠŗŃ‚ŃƒŃ€Š° {6}", "okButton": "ŠžŠš" } \ No newline at end of file diff --git a/i18n/rus/src/vs/code/electron-main/windows.i18n.json b/i18n/rus/src/vs/code/electron-main/windows.i18n.json index eefa41d8a32..50944a8399c 100644 --- a/i18n/rus/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/rus/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,21 @@ "ok": "ŠžŠš", "pathNotExistTitle": "ŠŸŃƒŃ‚ŃŒ не ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚.", "pathNotExistDetail": "ŠŸŃƒŃ‚ŃŒ \"{0}\" больше не ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚ на Гиске.", - "reopen": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ повторно", - "wait": "ŠŸŠ¾Š“Š¾Š¶Š“Š°Ń‚ŃŒ", - "close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", "appStalled": "ŠžŠŗŠ½Š¾ не отвечает", "appStalledDetail": "Š’Ń‹ можете повторно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ окно, Š·Š°ŠŗŃ€Ń‹Ń‚ŃŒ его или ŠæŃ€Š¾Š“Š¾Š»Š¶ŠøŃ‚ŃŒ ожиГание.", "appCrashed": "Дбой окна", "appCrashedDetail": "ŠŸŃ€ŠøŠ½Š¾ŃŠøŠ¼ ŠøŠ·Š²ŠøŠ½ŠµŠ½ŠøŃ за Š½ŠµŃƒŠ“обство! Š’Ń‹ можете повторно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ окно, чтобы ŠæŃ€Š¾Š“Š¾Š»Š¶ŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‚Ńƒ с того места, на котором Š¾ŃŃ‚Š°Š½Š¾Š²ŠøŠ»ŠøŃŃŒ.", + "open": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ", + "openFolder": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ папку", "openFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл", - "openFolder": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ папку" + "workspaceOpenedMessage": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ ŃŠ¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ '{0}'", + "workspaceOpenedDetail": "Эта Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ уже открыта в Š“Ń€ŃƒŠ³Š¾Š¼ окне. Закройте ŃŃ‚Š¾ окно Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "openWorkspace": "&&ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ...", + "openWorkspaceTitle": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ", + "save": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ", + "doNotSave": "&&ŠŠµ ŃŠ¾Ń…Ń€Š°Š½ŃŃ‚ŃŒ", + "cancel": "ŠžŃ‚Š¼ŠµŠ½Š°", + "saveWorkspaceMessage": "Š’Ń‹ хотите ŃŠ¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ рабочей области в файле?", + "saveWorkspaceDetail": "Дохраните Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ, если хотите Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ ее позже.", + "saveWorkspace": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json index 56a590f35d9..8914d592cb8 100644 --- a/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ высотой строк. Укажите 0 Š“Š»Ń Š²Ń‹Ń‡ŠøŃŠ»ŠµŠ½ŠøŃ высоты строки по Ń€Š°Š·Š¼ŠµŃ€Ńƒ ŃˆŃ€ŠøŃ„Ń‚Š°.", "letterSpacing": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ интервалом межГу буквами в ŠæŠøŠŗŃŠµŠ»ŃŃ….", "lineNumbers": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ Š²ŠøŠ“ŠøŠ¼Š¾ŃŃ‚ŃŒŃŽ номеров строк. Возможные Š·Š½Š°Ń‡ŠµŠ½ŠøŃ: \"on\", \"off\" Šø \"relative\". Значение \"relative\" показывает количество строк, Š½Š°Ń‡ŠøŠ½Š°Ń с Ń‚ŠµŠŗŃƒŃ‰ŠµŠ³Š¾ ŠæŠ¾Š»Š¾Š¶ŠµŠ½ŠøŃ ŠŗŃƒŃ€ŃŠ¾Ń€Š°.", - "rulers": "Дтолбцы, в которых Голжны Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ Š²ŠµŃ€Ń‚ŠøŠŗŠ°Š»ŃŒŠ½Ń‹Šµ линейки", + "rulers": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ Š²ŠµŃ€Ń‚ŠøŠŗŠ°Š»ŃŒŠ½Ń‹Šµ линейки после опреГеленного числа Š¼Š¾Š½Š¾ŃˆŠøŃ€ŠøŠ½Š½Ń‹Ń… символов. Š”Š»Ń Š¾Ń‚Š¾Š±Ń€Š°Š¶ŠµŠ½ŠøŃ Š½ŠµŃŠŗŠ¾Š»ŃŒŠŗŠøŃ… линеек ŃƒŠŗŠ°Š¶ŠøŃ‚Šµ несколько значений. Если не указано ни оГного Š·Š½Š°Ń‡ŠµŠ½ŠøŃ, Š²ŠµŃ€Ń‚ŠøŠŗŠ°Š»ŃŒŠ½Ń‹Šµ линейки Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ не Š±ŃƒŠ“ŃƒŃ‚.", "wordSeparators": "Димволы, которые Š±ŃƒŠ“ŃƒŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒŃŃ как разГелители слов при выполнении навигации или Š“Ń€ŃƒŠ³ŠøŃ… операций, ŃŠ²ŃŠ·Š°Š½Š½Ń‹Ń… со словами.", "tabSize": "Число пробелов в Ń‚Š°Š±ŃƒŠ»ŃŃ†ŠøŠø. Эта настройка ŠæŠµŃ€ŠµŠ¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ŃŃ на основании соГержимого файла, когГа Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ параметр \"editor.detectIndentation\".", "tabSize.errorMessage": "ŠžŠ¶ŠøŠ“Š°ŠµŃ‚ŃŃ число. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что значение auto заменено параметром editor.detectIndentation.", @@ -20,8 +20,9 @@ "detectIndentation": "ŠŸŃ€Šø открытии файла editor.tabSize Šø editor.insertSpaces Š±ŃƒŠ“ŃƒŃ‚ Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŃ‚ŃŒŃŃ на основе соГержимого файла.", "roundedSelection": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŃƒŃ‚ ли Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ ŠøŠ¼ŠµŃ‚ŃŒ ŃŠŗŃ€ŃƒŠ³Š»ŠµŠ½Š½Ń‹Šµ ŃƒŠ³Š»Ń‹.", "scrollBeyondLastLine": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли соГержимое реГактора ŠæŃ€Š¾ŠŗŃ€ŃƒŃ‡ŠøŠ²Š°Ń‚ŃŒŃŃ за ŠæŠ¾ŃŠ»ŠµŠ“Š½ŃŽŃŽ ŃŃ‚Ń€Š¾ŠŗŃƒ.", + "smoothScrolling": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒŃŃ Š°Š½ŠøŠ¼Š°Ń†ŠøŃ при ŠæŃ€Š¾ŠŗŃ€ŃƒŃ‚ке соГержимого реГактора", "minimap.enabled": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ ли мини-карта", - "minimap.showSlider": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли автоматически ŃŠŗŃ€Ń‹Š²Š°Ń‚ŃŒŃŃ ползунок мини-карты", + "minimap.showSlider": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли автоматически ŃŠŗŃ€Ń‹Š²Š°Ń‚ŃŒŃŃ ползунок мини-карты. Возможные Š·Š½Š°Ń‡ŠµŠ½ŠøŃ: 'always' (всегГа) Šø 'mouseover' (при навеГении ŠŗŃƒŃ€ŃŠ¾Ń€Š° Š¼Ń‹ŃˆŠø)", "minimap.renderCharacters": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ фактические символы в строке вместо цветных блоков.", "minimap.maxColumn": "ŠžŠ³Ń€Š°Š½ŠøŃ‡ŠøŠ²Š°ŠµŃ‚ ŃˆŠøŃ€ŠøŠ½Ńƒ мини-карты Š“Š»Ń Š¾Ń‚Š¾Š±Ń€Š°Š¶ŠµŠ½ŠøŃ числа столбцов не больше опреГеленного.", "find.seedSearchStringFromSelection": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, можно ли ŠæŠµŃ€ŠµŠ“Š°Ń‚ŃŒ ŃŃ‚Ń€Š¾ŠŗŃƒ поиска в мини-приложение поиска ŠøŠ· текста, выГеленного в реГакторе", @@ -46,10 +47,13 @@ "autoClosingBrackets": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжен ли реГактор автоматически Š·Š°ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ скобки после Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŠøŃ.", "formatOnType": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ параметром, Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŃŽŃ‰ŠøŠ¼, Голжен ли реГактор автоматически Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŃŃ‚Ń€Š¾ŠŗŃƒ после ввоГа.", "formatOnPaste": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли реГактор автоматически Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ вставленное соГержимое. МоГуль Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ Голжен Š±Ń‹Ń‚ŃŒ Š“Š¾ŃŃ‚ŃƒŠæŠµŠ½ Šø ŠøŠ¼ŠµŃ‚ŃŒ Š²Š¾Š·Š¼Š¾Š¶Š½Š¾ŃŃ‚ŃŒ Ń„Š¾Ń€Š¼Š°Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ Гиапазон в Š“Š¾ŠŗŃƒŠ¼ŠµŠ½Ń‚Šµ.", - "autoIndent": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжен ли реГактор автоматически ŠøŠ·Š¼ŠµŠ½ŃŃ‚ŃŒ Š¾Ń‚ŃŃ‚ŃƒŠæ при ввоГе текста, вставке текста или перемещении строк. Š”Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ ŃŃ‚Š¾Š³Š¾ параметра Голжны Š±Ń‹Ń‚ŃŒ Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹ правила Š¾Ń‚ŃŃ‚ŃƒŠæŠ°.", "suggestOnTriggerCharacters": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжны ли при ввоГе триггерных символов автоматически Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ.", "acceptSuggestionOnEnter": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŃƒŃ‚ ли ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ ŠæŃ€ŠøŠ½ŠøŠ¼Š°Ń‚ŃŒŃŃ клавишей Š’Š’ŠžŠ” в Гополнение Šŗ клавише TAB. Это помогает ŠøŠ·Š±ŠµŠ¶Š°Ń‚ŃŒ неоГнозначности межГу вставкой новых строк Šø ŠæŃ€ŠøŠ½ŃŃ‚ŠøŠµŠ¼ преГложений. Значение \"smart\" означает, что при изменении текста ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ Š±ŃƒŠ“ŃƒŃ‚ ŠæŃ€ŠøŠ½ŠøŠ¼Š°Ń‚ŃŒŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ при нажатии клавиши Š’Š’ŠžŠ”.", "acceptSuggestionOnCommitCharacter": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŃƒŃ‚ ли ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ ŠæŃ€ŠøŠ½ŠøŠ¼Š°Ń‚ŃŒŃŃ символами фиксации. ŠŠ°ŠæŃ€ŠøŠ¼ŠµŃ€, в JavaScript точка с Š·Š°ŠæŃŃ‚Š¾Š¹ (\";\") может Š±Ń‹Ń‚ŃŒ символом фиксации, ŠæŃ€ŠøŠ½ŠøŠ¼Š°ŃŽŃ‰ŠøŠ¼ преГложение Šø Š²Š²Š¾Š“ŃŃ‰ŠøŠ¼ Ганный символ.", + "snippetSuggestions.top": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ фрагментов поверх Š“Ń€ŃƒŠ³ŠøŃ… преГложений.", + "snippetSuggestions.bottom": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ фрагментов поГ Š“Ń€ŃƒŠ³ŠøŠ¼Šø ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃŠ¼Šø.", + "snippetSuggestions.inline": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ фрагментов Ń€ŃŠ“Š¾Š¼ с Š“Ń€ŃƒŠ³ŠøŠ¼Šø ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃŠ¼Šø.", + "snippetSuggestions.none": "ŠŠµ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃ фрагментов.", "snippetSuggestions": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ отображением фрагментов вместе с Š“Ń€ŃƒŠ³ŠøŠ¼Šø ŠæŃ€ŠµŠ“Š»Š¾Š¶ŠµŠ½ŠøŃŠ¼Šø Šø ŠøŃ… сортировкой.", "emptySelectionClipboard": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ тем, ŠŗŠ¾ŠæŠøŃ€ŃƒŠµŃ‚ŃŃ ли Ń‚ŠµŠŗŃƒŃ‰Š°Ń строка при копировании без Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ.", "wordBasedSuggestions": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ли Š¾Ń†ŠµŠ½ŠøŠ²Š°Ń‚ŃŒ Š·Š°Š²ŠµŃ€ŃˆŠµŠ½ŠøŃ на основе слов в Š“Š¾ŠŗŃƒŠ¼ŠµŠ½Ń‚Šµ.", @@ -82,6 +86,8 @@ "accessibilitySupport.off": "РеГактор никогГа не Š±ŃƒŠ“ет Š¾ŠæŃ‚ŠøŠ¼ŠøŠ·ŠøŃ€Š¾Š²Š°Ń‚ŃŒŃŃ Š“Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ со среГством Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š°.", "accessibilitySupport": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ли Š·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ реГактор в режиме оптимизации Š“Š»Ń среГства Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š°.", "links": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжен ли реГактор Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŃ‚ŃŒ ссылки Šø Š“ŠµŠ»Š°Ń‚ŃŒ ŠøŃ… Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹Š¼Šø Š“Š»Ń щелчка", + "colorDecorators": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжны ли в реГакторе Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ Š²Š½ŃƒŃ‚Ń€ŠµŠ½Š½ŠøŠµ Гекораторы цвета Šø среГство выбора цвета.", + "codeActions": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ инГикатор Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ коГа", "sideBySide": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, как реГактор несовпаГений отображает Š¾Ń‚Š»ŠøŃ‡ŠøŃ: Ń€ŃŠ“Š¾Š¼ или в тексте.", "ignoreTrimWhitespace": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжен ли реГактор несовпаГений Ń‚Ń€Š°ŠŗŃ‚Š¾Š²Š°Ń‚ŃŒ Š½ŠµŃŠ¾Š²ŠæŠ°Š“ŠµŠ½ŠøŃ символов-разГелителей как Ń€Š°Š·Š»ŠøŃ‡ŠøŃ.", "renderIndicators": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ отображение реГактором несовпаГений инГикаторов +/- Š“Š»Ń Гобавленных или ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Ń… изменений", diff --git a/i18n/rus/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/rus/src/vs/editor/common/view/editorColorRegistry.i18n.json index fbad34f6ea8..4801d2ec386 100644 --- a/i18n/rus/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/rus/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "Цвет волнистой линии Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ ошибок в реГакторе.", "errorBorder": "Цвет границ волнистой линии Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ ошибок в реГакторе.", "warningForeground": "Цвет волнистой линии Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠ¹ в реГакторе.", - "warningBorder": "Цвет границ волнистой линии Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠ¹ в реГакторе." + "warningBorder": "Цвет границ волнистой линии Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠ¹ в реГакторе.", + "infoForeground": "Цвет волнистой линии Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ информационных сообщений в реГакторе.", + "infoBorder": "Цвет границ волнистой линии Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ информационных сообщений в реГакторе. ", + "overviewRulerRangeHighlight": "Цвет метки линейки в окне просмотра Š“Š»Ń выГелений Гиапазонов.", + "overviewRuleError": "Цвет метки линейки в окне просмотра Š“Š»Ń ошибок.", + "overviewRuleWarning": "Цвет метки линейки в окне просмотра Š“Š»Ń ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠ¹.", + "overviewRuleInfo": "Цвет метки линейки в окне просмотра Š“Š»Ń информационных сообщений." } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json index 56455258496..32fb3e012c8 100644 --- a/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,6 @@ "label.replaceButton": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ", "label.replaceAllButton": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ все", "label.toggleReplaceButton": "Режим \"ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµ замены\"", - "title.matchesCountLimit": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ первые 999 Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š², но все операции поиска Š²Ń‹ŠæŠ¾Š»Š½ŃŃŽŃ‚ся со всем текстом.", "label.matchesLocation": "{0} ŠøŠ· {1}", "label.noResults": "ŠŠµŃ‚ Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š²" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json index fbe127a6eb4..5c6f87afd29 100644 --- a/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,10 +10,6 @@ "nextSelectionMatchFindAction": "ŠŠ°Š¹Ń‚Šø ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ выГеление", "previousSelectionMatchFindAction": "ŠŠ°Š¹Ń‚Šø ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠµ выГеление", "startReplace": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ", - "addSelectionToNextFindMatch": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ выГеление в ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ найГенное совпаГение", - "addSelectionToPreviousFindMatch": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ выГеленный фрагмент в ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠµ найГенное совпаГение", - "moveSelectionToNextFindMatch": "ŠŸŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ послеГнее выГеление в ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ найГенное совпаГение", - "moveSelectionToPreviousFindMatch": "ŠŸŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ послеГний выГеленный фрагмент в ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠµ найГенное совпаГение", - "selectAllOccurrencesOfFindMatch": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ все Š²Ń…Š¾Š¶Š“ŠµŠ½ŠøŃ найГенных совпаГений", - "changeAll.label": "Š˜Š·Š¼ŠµŠ½ŠøŃ‚ŃŒ все Š²Ń…Š¾Š¶Š“ŠµŠ½ŠøŃ" + "showNextFindTermAction": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠ¹ найГенный термин", + "showPreviousFindTermAction": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠøŠ¹ найГенный термин" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/rus/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 3e7c8375e65..5ca181d11bd 100644 --- a/i18n/rus/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ¹ ошибке или ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃŽ", "editorMarkerNavigationError": "Цвет ошибки в мини-приложении навигации по меткам реГактора.", "editorMarkerNavigationWarning": "Цвет ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ в мини-приложении навигации по меткам реГактора.", + "editorMarkerNavigationInfo": "Цвет информационного ŃŠ¾Š¾Š±Ń‰ŠµŠ½ŠøŃ в мини-приложении навигации по меткам реГактора.", "editorMarkerNavigationBackground": "Фон мини-ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ навигации по меткам реГактора." } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/links/browser/links.i18n.json b/i18n/rus/src/vs/editor/contrib/links/browser/links.i18n.json index 9260a3d4367..0e2b04db373 100644 --- a/i18n/rus/src/vs/editor/contrib/links/browser/links.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/links/browser/links.i18n.json @@ -6,7 +6,10 @@ { "links.navigate.mac": "Щелкните с нажатой клавишей Cmd, чтобы перейти по ссылке", "links.navigate": "Щелкните с нажатой клавишей Ctrl, чтобы перейти по ссылке", + "links.command.mac": "Š”Š»Ń Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ команГы щелкните ее, ŃƒŠ“ŠµŃ€Š¶ŠøŠ²Š°Ń нажатой клавишу CMD", + "links.command": "Š”Š»Ń Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ команГы щелкните ее, ŃƒŠ“ŠµŃ€Š¶ŠøŠ²Š°Ń нажатой клавишу CTRL", "links.navigate.al": "Щелкните с нажатой клавишей ALT, чтобы перейти по ссылке.", + "links.command.al": "Š”Š»Ń Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ команГы щелкните ее, ŃƒŠ“ŠµŃ€Š¶ŠøŠ²Š°Ń нажатой клавишу ALT", "invalid.url": "ŠŠµ уГалось Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ ŃŃŃ‹Š»ŠŗŃƒ, так как она имеет Š½ŠµŠæŃ€Š°Š²ŠøŠ»ŃŒŠ½Ń‹Š¹ формат: {0}", "missing.url": "ŠŠµ уГалось Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ ŃŃŃ‹Š»ŠŗŃƒ, у нее Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŠµŃ‚ целевой Š¾Š±ŃŠŠµŠŗŃ‚.", "label": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ ŃŃŃ‹Š»ŠŗŃƒ" diff --git a/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index de410095204..660193a943e 100644 --- a/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŃƒŃ€ŃŠ¾Ń€ Š²Ń‹ŃˆŠµ", "mutlicursor.insertBelow": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŃƒŃ€ŃŠ¾Ń€ ниже", - "mutlicursor.insertAtEndOfEachLineSelected": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŃƒŃ€ŃŠ¾Ń€Ń‹ Šŗ Š¾ŠŗŠ¾Š½Ń‡Š°Š½ŠøŃŠ¼ строк" + "mutlicursor.insertAtEndOfEachLineSelected": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŃƒŃ€ŃŠ¾Ń€Ń‹ Šŗ Š¾ŠŗŠ¾Š½Ń‡Š°Š½ŠøŃŠ¼ строк", + "addSelectionToNextFindMatch": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ выГеление в ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ найГенное совпаГение", + "addSelectionToPreviousFindMatch": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ выГеленный фрагмент в ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠµ найГенное совпаГение", + "moveSelectionToNextFindMatch": "ŠŸŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ послеГнее выГеление в ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ найГенное совпаГение", + "moveSelectionToPreviousFindMatch": "ŠŸŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ послеГний выГеленный фрагмент в ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠµ найГенное совпаГение", + "selectAllOccurrencesOfFindMatch": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ все Š²Ń…Š¾Š¶Š“ŠµŠ½ŠøŃ найГенных совпаГений", + "changeAll.label": "Š˜Š·Š¼ŠµŠ½ŠøŃ‚ŃŒ все Š²Ń…Š¾Š¶Š“ŠµŠ½ŠøŃ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/rus/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..6f6dde161df --- /dev/null +++ b/i18n/rus/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/rus/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index b025e34a7bd..94eb8720432 100644 --- a/i18n/rus/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,7 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Цвет фона символа при Š“Š¾ŃŃ‚ŃƒŠæŠµ на чтение, например считывании переменной.", - "wordHighlightStrong": "Цвет фона символа при Š“Š¾ŃŃ‚ŃƒŠæŠµ на запись, например записи переменной." + "wordHighlightStrong": "Цвет фона символа при Š“Š¾ŃŃ‚ŃƒŠæŠµ на запись, например записи переменной.", + "overviewRulerWordHighlightForeground": "Цвет метки линейки в окне просмотра Š“Š»Ń выГелений символов.", + "overviewRulerWordHighlightStrongForeground": "Цвет метки линейки в окне просмотра Š“Š»Ń выГелений символов, Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹Ń… Š“Š»Ń записи. " } \ No newline at end of file diff --git a/i18n/rus/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/rus/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 6b77834c391..b8216927851 100644 --- a/i18n/rus/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/rus/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "Š“Ń€ŃƒŠæŠæŠ°, Šŗ которой принаГлежит ŃŃ‚Š° команГа", "vscode.extension.contributes.menus": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Ń‹ Š¼ŠµŠ½ŃŽ в реГактор", "menus.commandPalette": "ŠŸŠ°Š»ŠøŃ‚Ń€Š° команГ", + "menus.touchBar": "Š”ŠµŠ½ŃŠ¾Ń€Š½Š°Ń панель (Ń‚Š¾Š»ŃŒŠŗŠ¾ Š“Š»Ń macOS)", "menus.editorTitle": "Главное Š¼ŠµŠ½ŃŽ реГактора", "menus.editorContext": "ŠšŠ¾Š½Ń‚ŠµŠŗŃŃ‚Š½Š¾Šµ Š¼ŠµŠ½ŃŽ реГактора", "menus.explorerContext": "ŠšŠ¾Š½Ń‚ŠµŠŗŃŃ‚Š½Š¾Šµ Š¼ŠµŠ½ŃŽ провоГника", "menus.editorTabContext": "ŠšŠ¾Š½Ń‚ŠµŠŗŃŃ‚Š½Š¾Šµ Š¼ŠµŠ½ŃŽ вклаГок реГактора", "menus.debugCallstackContext": "ŠšŠ¾Š½Ń‚ŠµŠŗŃŃ‚Š½Š¾Šµ Š¼ŠµŠ½ŃŽ стека вызовов при отлаГке", "menus.scmTitle": "ŠœŠµŠ½ŃŽ заголовков Š“Š»Ń системы ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø", + "menus.scmSourceControl": "ŠœŠµŠ½ŃŽ \"Дистема ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø\"", "menus.resourceGroupContext": "ŠšŠ¾Š½Ń‚ŠµŠŗŃŃ‚Š½Š¾Šµ Š¼ŠµŠ½ŃŽ Š³Ń€ŃƒŠæŠæŃ‹ Ń€ŠµŃŃƒŃ€ŃŠ¾Š² Š“Š»Ń системы ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø", "menus.resourceStateContext": "ŠšŠ¾Š½Ń‚ŠµŠŗŃŃ‚Š½Š¾Šµ Š¼ŠµŠ½ŃŽ ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Ń€ŠµŃŃƒŃ€ŃŠ¾Š² Š“Š»Ń системы ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø", "view.viewTitle": "ŠœŠµŠ½ŃŽ заголовка Š“Š»Ń окна ŃƒŃ‡Š°ŃŃ‚Š½ŠøŠŗŠ¾Š²", diff --git a/i18n/rus/src/vs/platform/environment/node/argv.i18n.json b/i18n/rus/src/vs/platform/environment/node/argv.i18n.json index 962ca99076b..eb6770aa30b 100644 --- a/i18n/rus/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/rus/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "ŠŃ€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń‹ в режиме \"--goto\" Голжны Š±Ń‹Ń‚ŃŒ в формате \"ФАЙЛ(:Š”Š¢Š ŠžŠšŠ(:Š”Š˜ŠœŠ’ŠžŠ›))\".", - "diff": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ реГактор несовпаГений. Š¢Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ Гва ŠæŃƒŃ‚Šø Šŗ файлам в качестве Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ов.", - "goto": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл по ŠæŃƒŃ‚Šø, указанному в опреГеленной строке Šø символе (Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ Š“Š¾Š±Š°Š²ŠøŃ‚ŃŒ \":строка[:символ]\" в ŠæŃƒŃ‚ŃŒ).", + "diff": "Дравнение Š“Š²ŃƒŃ… файлов Š“Ń€ŃƒŠ³ с Š“Ń€ŃƒŠ³Š¾Š¼", + "add": "Добавление папок в послеГнее активное окно.", + "goto": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŠøŠµ файла по указанному ŠæŃƒŃ‚Šø с выГелением указанного символа в указанной строке.", "locale": "Языковой станГарт, который ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ (например, en-US или zh-TW).", "newWindow": "ŠŸŃ€ŠøŠ½ŃƒŠ“ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ Š·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ новый ŃŠŗŠ·ŠµŠ¼ŠæŠ»ŃŃ€ Code.", "performance": "Š—Š°ŠæŃƒŃŃ‚ŠøŃ‚Šµ с Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Š½Š¾Š¹ команГой \"Developer: Startup Performance\".", @@ -14,7 +15,7 @@ "reuseWindow": "ŠŸŃ€ŠøŠ½ŃƒŠ“ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ файл или папку в послеГнем активном окне.", "userDataDir": "Указывает каталог, в котором Ń…Ń€Š°Š½ŃŃ‚ŃŃ Ганные ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŠµŠ¹, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ в ŃŠ»ŃƒŃ‡Š°Šµ Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ от имени привилегированного ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń.", "verbose": "ŠŸŠµŃ‡Š°Ń‚ŃŒ поГробного вывоГа (ŠæŠ¾Š“Ń€Š°Š·ŃƒŠ¼ŠµŠ²Š°ŠµŃ‚ использование параметра \"--wait\").", - "wait": "Š”Š¾Š¶Š“Š°Ń‚ŃŒŃŃ Š·Š°ŠŗŃ€Ń‹Ń‚ŠøŃ окна, прежГе чем Š²ŠµŃ€Š½ŃƒŃ‚ŃŒ Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚.", + "wait": "Š”Š¾Š¶Š“Š°Ń‚ŃŒŃŃ Š·Š°ŠŗŃ€Ń‹Ń‚ŠøŃ файлов переГ возвратом.", "extensionHomePath": "ЗаГайте корневой ŠæŃƒŃ‚ŃŒ Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹.", "listExtensions": "ŠŸŠµŃ€ŠµŃ‡ŠøŃŠ»ŠøŃ‚ŃŒ ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŃŽŃ‰ŠøŠµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ.", "showVersions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ версии ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń‹Ń… Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹ при указании параметра --list-extension.", diff --git a/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 60652be3521..16024062ff7 100644 --- a/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "ŠŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ: package.json не ŃŠ²Š»ŃŠµŃ‚ŃŃ файлом JSON.", - "restartCode": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚Šµ коГ переГ ŠæŠµŃ€ŠµŃƒŃŃ‚Š°Š½Š¾Š²ŠŗŠ¾Š¹ {0}.", - "installDependeciesConfirmation": "ŠŸŃ€Šø ŃƒŃŃ‚Š°Š½Š¾Š²ŠŗŠµ \"{0}\" также ŃƒŃŃ‚Š°Š½Š°Š²Š»ŠøŠ²Š°ŃŽŃ‚ŃŃ зависимости. Š’Ń‹ хотите ŠæŃ€Š¾Š“Š¾Š»Š¶ŠøŃ‚ŃŒ?", - "install": "Да", - "doNotInstall": "ŠŠµŃ‚", + "restartCodeLocal": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚Šµ коГ переГ ŠæŠµŃ€ŠµŃƒŃŃ‚Š°Š½Š¾Š²ŠŗŠ¾Š¹ {0}.", + "restartCodeGallery": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚Šµ Code переГ повторной ŃƒŃŃ‚Š°Š½Š¾Š²ŠŗŠ¾Š¹.", "uninstallDependeciesConfirmation": "Š’Ń‹ хотите ŃƒŠ“Š°Š»ŠøŃ‚ŃŒ \"{0}\" Š¾Ń‚Š“ŠµŠ»ŃŒŠ½Š¾ или вместе с Š·Š°Š²ŠøŃŠøŠ¼Š¾ŃŃ‚ŃŠ¼Šø?", "uninstallOnly": "Только", "uninstallAll": "Все", diff --git a/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 1cc3bfcebce..c5f432f019c 100644 --- a/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "Š”Š¾Š±Ń‹Ń‚ŠøŃ активации Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ коГа VS Code.", "vscode.extension.activationEvents.onLanguage": "Добытие активации Š²Ń‹Š“Š°ŠµŃ‚ŃŃ кажГый раз, когГа Š¾Ń‚ŠŗŃ€Ń‹Š²Š°ŠµŃ‚ŃŃ файл, который Ń€Š°Š·Ń€ŠµŃˆŠ°ŠµŃ‚ŃŃ Šŗ указанному ŃŠ·Ń‹ŠŗŃƒ.", "vscode.extension.activationEvents.onCommand": "Добытие активации Š²Ń‹Š“Š°ŠµŃ‚ŃŃ кажГый раз при вызове указанной команГы.", - "vscode.extension.activationEvents.onDebug": "Добытие активации Š²Ń‹Š“Š°ŠµŃ‚ŃŃ кажГый раз при запуске сеанса отлаГки указанного типа.", + "vscode.extension.activationEvents.onDebug": "Добытие активации Š²Ń‹Š“Š°ŠµŃ‚ŃŃ кажГый раз, когГа ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒ Š·Š°ŠæŃƒŃŠŗŠ°ŠµŃ‚ Š¾Ń‚Š»Š°Š“ŠŗŃƒ или ŃŠ¾Š±ŠøŃ€Š°ŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ отлаГки.", "vscode.extension.activationEvents.workspaceContains": "Добытие активации Š²Ń‹Š“Š°ŠµŃ‚ŃŃ кажГый раз при открытии папки, соГержащей по крайней мере оГин файл, который ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŠµŃ‚ указанной станГартной маске.", "vscode.extension.activationEvents.onView": "Добытие активации Š²Ń‹Š“Š°ŠµŃ‚ŃŃ кажГый раз при развертывании указанного окна.", "vscode.extension.activationEvents.star": "Добытие активации Š²Ń‹Š“Š°ŠµŃ‚ŃŃ при запуске VS Code. Š”Š»Ń ŃƒŠ“Š¾Š±ŃŃ‚Š²Š° ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ ŃŃ‚Š¾ событие в своем Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠø Ń‚Š¾Š»ŃŒŠŗŠ¾ в том ŃŠ»ŃƒŃ‡Š°Šµ, если Š“Ń€ŃƒŠ³ŠøŠµ ŃŠ¾Ń‡ŠµŃ‚Š°Š½ŠøŃ событий не ŠæŠ¾Š“Ń…Š¾Š“ŃŃ‚.", diff --git a/i18n/rus/src/vs/platform/history/electron-main/historyMainService.i18n.json b/i18n/rus/src/vs/platform/history/electron-main/historyMainService.i18n.json index 1281d5e53dc..891764b5aee 100644 --- a/i18n/rus/src/vs/platform/history/electron-main/historyMainService.i18n.json +++ b/i18n/rus/src/vs/platform/history/electron-main/historyMainService.i18n.json @@ -6,5 +6,7 @@ { "newWindow": "ŠŠ¾Š²Š¾Šµ окно", "newWindowDesc": "ŠžŃ‚ŠŗŃ€Ń‹Š²Š°ŠµŃ‚ новое окно", - "folderDesc": "{0} {1}" + "recentFolders": "ПослеГние рабочие области", + "folderDesc": "{0} {1}", + "codeWorkspace": "Š Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ коГа" } \ No newline at end of file diff --git a/i18n/rus/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/rus/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..651ebfe5a8d --- /dev/null +++ b/i18n/rus/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ цвета тем, Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŠ¼Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµŠ¼ ", + "contributes.color.id": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€ цвета темы", + "contributes.color.id.format": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€Ń‹ необхоГимо ŃƒŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ в форме aa [.bb]*", + "contributes.color.description": "ŠžŠæŠøŃŠ°Š½ŠøŠµ цвета темы", + "contributes.defaults.light": "Цвет по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ Š“Š»Ń светлых тем. Укажите значение цвета в ŃˆŠµŃŃ‚Š½Š°Š“Ń†Š°Ń‚ŠµŃ€ŠøŃ‡Š½Š¾Š¼ формате (#RRGGBB[AA]) или иГентификатор цвета темы.", + "contributes.defaults.dark": "Цвет по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ Š“Š»Ń темных тем. Укажите значение цвета в ŃˆŠµŃŃ‚Š½Š°Š“Ń†Š°Ń‚ŠµŃ€ŠøŃ‡Š½Š¾Š¼ формате (#RRGGBB[AA]) или иГентификатор цвета темы.", + "contributes.defaults.highContrast": "Цвет по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ Š“Š»Ń тем с высоким контрастом. Укажите значение цвета в ŃˆŠµŃŃ‚Š½Š°Š“Ń†Š°Ń‚ŠµŃ€ŠøŃ‡Š½Š¾Š¼ формате (#RRGGBB[AA]) или иГентификатор цвета темы.", + "invalid.colorConfiguration": "'configuration.colors' Голжен Š±Ń‹Ń‚ŃŒ массивом", + "invalid.default.colorType": "{0} Голжен ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŃŃ‚ŃŒ собой значение цвета в ŃˆŠµŃŃ‚Š½Š°Š“Ń†Š°Ń‚ŠµŃ€ŠøŃ‡Š½Š¾Š¼ формате (#RRGGBB[AA] или #RGB[A]) или иГентификатор цвета темы.", + "invalid.id": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ 'configuration.colors.id' Голжен Š±Ń‹Ń‚ŃŒ указан Šø не может Š±Ń‹Ń‚ŃŒ ŠæŃƒŃŃ‚Ń‹Š¼", + "invalid.id.format": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ 'configuration.colors.id' Голжен ŃŠ»ŠµŠ“Š¾Š²Š°Ń‚ŃŒ за word[.word]*", + "invalid.description": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ 'configuration.colors.description' Голжен Š±Ń‹Ń‚ŃŒ указан Šø не может Š±Ń‹Ń‚ŃŒ ŠæŃƒŃŃ‚Ń‹Š¼", + "invalid.defaults": "'configuration.colors.defaults' может Š±Ń‹Ń‚ŃŒ указан Šø может ŃŠ¾Š“ŠµŃ€Š¶Š°Ń‚ŃŒ Š·Š½Š°Ń‡ŠµŠ½ŠøŃ 'light', 'dark' Šø 'highContrast'" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json index bf1ce6c7711..4de61ec7ef4 100644 --- a/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/rus/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "ŠŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¹ формат цвета. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ #RGB, #RGBA, #RRGGBB или #RRGGBBAA", "schema.colors": "Цвета, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Šµ на рабочем месте.", "foreground": "ŠžŠ±Ń‰ŠøŠ¹ цвет переГнего плана. Этот цвет ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ, Ń‚Š¾Š»ŃŒŠŗŠ¾ если его не переопреГелит компонент.", "errorForeground": "ŠžŠ±Ń‰ŠøŠ¹ цвет переГнего плана Š“Š»Ń сообщений об Š¾ŃˆŠøŠ±ŠŗŠ°Ń…. Этот цвет ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ если его не ŠæŠµŃ€ŠµŠ¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ компонент.", @@ -54,6 +53,8 @@ "badgeForeground": "Цвет текста Š±ŃŠ“жа. Š‘ŃŠ“Š¶Šø - небольшие информационные ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Ń‹, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‰ŠøŠµ количество, например, Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š² поиска.", "scrollbarShadow": "Цвет тени полосы ŠæŃ€Š¾ŠŗŃ€ŃƒŃ‚ŠŗŠø, ŠŗŠ¾Ń‚Š¾Ń€Š°Ń ŃŠ²ŠøŠ“ŠµŃ‚ŠµŠ»ŃŒŃŃ‚Š²ŃƒŠµŃ‚ о том, что соГержимое ŠæŃ€Š¾ŠŗŃ€ŃƒŃ‡ŠøŠ²Š°ŠµŃ‚ся.", "scrollbarSliderBackground": "Цвет фона ползунка полосы ŠæŃ€Š¾ŠŗŃ€ŃƒŃ‚ŠŗŠø.", + "scrollbarSliderHoverBackground": "Цвет фона ползунка полосы ŠæŃ€Š¾ŠŗŃ€ŃƒŃ‚ŠŗŠø при навеГении ŠŗŃƒŃ€ŃŠ¾Ń€Š°.", + "scrollbarSliderActiveBackground": "Цвет фона активного ползунка полосы ŠæŃ€Š¾ŠŗŃ€ŃƒŃ‚ŠŗŠø.", "progressBarBackground": "Цвет фона инГикатора Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ, который может Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ Š“Š»Ń Š“Š»ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Ń… операций.", "editorBackground": "Цвет фона реГактора.", "editorForeground": "Цвет переГнего плана реГактора по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ.", @@ -83,5 +84,7 @@ "mergeBorder": "Цвет границы заголовков Šø Ń€Š°Š·Š“ŠµŠ»ŠøŃ‚ŠµŠ»Ń во Š²Š½ŃƒŃ‚ренних конфликтах ŃŠ»ŠøŃŠ½ŠøŃ.", "overviewRulerCurrentContentForeground": "Цвет переГнего плана линейки Ń‚ŠµŠŗŃƒŃ‰ŠµŠ³Š¾ окна во Š²Š½ŃƒŃ‚ренних конфликтах ŃŠ»ŠøŃŠ½ŠøŃ.", "overviewRulerIncomingContentForeground": "Цвет переГнего плана линейки Š²Ń…Š¾Š“ŃŃ‰ŠµŠ³Š¾ окна во Š²Š½ŃƒŃ‚ренних конфликтах ŃŠ»ŠøŃŠ½ŠøŃ.", - "overviewRulerCommonContentForeground": "Цвет переГнего плана Š“Š»Ń обзорной линейки Š“Š»Ń общего преГка во Š²Š½ŃƒŃ‚ренних конфликтах ŃŠ»ŠøŃŠ½ŠøŃ. " + "overviewRulerCommonContentForeground": "Цвет переГнего плана Š“Š»Ń обзорной линейки Š“Š»Ń общего преГка во Š²Š½ŃƒŃ‚ренних конфликтах ŃŠ»ŠøŃŠ½ŠøŃ. ", + "overviewRulerFindMatchForeground": "Цвет метки линейки в окне просмотра Š“Š»Ń Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š² поиска.", + "overviewRulerSelectionHighlightForeground": "Цвет метки линейки в окне просмотра Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ." } \ No newline at end of file diff --git a/i18n/rus/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/rus/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..08cd26e159a --- /dev/null +++ b/i18n/rus/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Š Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ коГа", + "untitledWorkspace": "(Š Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ) без Š½Š°Š·Š²Š°Š½ŠøŃ", + "workspaceNameVerbose": "{0} (Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ)", + "workspaceName": "{0} (Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ)" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/rus/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..56be368eede --- /dev/null +++ b/i18n/rus/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ Голжны Š±Ń‹Ń‚ŃŒ массивом", + "requirestring": "свойство \"{0}\" ŃŠ²Š»ŃŠµŃ‚ŃŃ Š¾Š±ŃŠ·Š°Ń‚ŠµŠ»ŃŒŠ½Ń‹Š¼ Šø Голжно ŠøŠ¼ŠµŃ‚ŃŒ тип string", + "optstring": "свойство \"{0}\" может Š±Ń‹Ń‚ŃŒ Š¾ŠæŃƒŃ‰ŠµŠ½Š¾ или Голжно ŠøŠ¼ŠµŃ‚ŃŒ тип string", + "vscode.extension.contributes.view.id": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ его Š“Š»Ń регистрации поставщика Ганных с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ API-интерфейса \"vscode.window.registerTreeDataProviderForView\", а также Š“Š»Ń активации Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ регистрации ŃŠ¾Š±Ń‹Ń‚ŠøŃ \"onView:${id}\" в \"activationEvents\".", + "vscode.extension.contributes.view.name": "ŠŸŠ¾Š½ŃŃ‚Š½Š¾Šµ ŠøŠ¼Ń ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ. Š‘ŃƒŠ“ŠµŃ‚ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ на ŃŠŗŃ€Š°Š½Šµ", + "vscode.extension.contributes.view.when": "Условие, которое Голжно ŠøŠ¼ŠµŃ‚ŃŒ значение 'true', чтобы Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Š»Š¾ŃŃŒ ŃŃ‚Š¾ преГставление", + "vscode.extension.contributes.views": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ в реГактор", + "views.explorer": "ŠŸŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŠµ провоГника", + "views.debug": "ŠŸŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŠµ отлаГки", + "locationId.invalid": "\"{0}\" не ŃŠ²Š»ŃŠµŃ‚ŃŃ Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¼ расположением ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ", + "duplicateView1": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°Ń€ŠµŠ³ŠøŃŃ‚Ń€ŠøŃ€Š¾Š²Š°Ń‚ŃŒ несколько преГставлений с оГинаковым иГентификатором '{0}' в расположении '{1}'", + "duplicateView2": "ŠŸŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŠµ с иГентификатором '{0}' уже зарегистрировано в расположении '{1}'" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/rus/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..6dd5f17dccf --- /dev/null +++ b/i18n/rus/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "ŠŠµ уГалось Š°ŠŗŃ‚ŠøŠ²ŠøŃ€Š¾Š²Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ \"{1}\". ŠŸŃ€ŠøŃ‡ŠøŠ½Š°: неизвестный зависимый компонент \"{0}\".", + "failedDep1": "ŠŠµ уГалось Š°ŠŗŃ‚ŠøŠ²ŠøŃ€Š¾Š²Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ \"{1}\". ŠŸŃ€ŠøŃ‡ŠøŠ½Š°: ошибка активации зависимого компонента \"{0}\".", + "failedDep2": "ŠŠµ уГалось Š°ŠŗŃ‚ŠøŠ²ŠøŃ€Š¾Š²Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ \"{0}\". ŠŸŃ€ŠøŃ‡ŠøŠ½Š°: более 10 ŃƒŃ€Š¾Š²Š½ŠµŠ¹ зависимостей (скорее всего, цикл зависимостей).", + "activationError": "ŠžŃˆŠøŠ±ŠŗŠ° активации Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ \"{0}\": {1}." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 77f0bdb5c2b..13d8031327f 100644 --- a/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,11 +4,18 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл...", "openFolder": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ папку...", "openFileFolder": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ...", - "cancel": "ŠžŃ‚Š¼ŠµŠ½Š°", "addFolderToWorkspace": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ папку в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ...", + "add": "&&Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ", "addFolderToWorkspaceTitle": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ папку в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ", "removeFolderFromWorkspace": "Š£Š“Š°Š»ŠøŃ‚ŃŒ папку ŠøŠ· рабочей области", - "save": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ" + "openFolderSettings": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ параметры папок", + "saveWorkspaceAsAction": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ как...", + "save": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ", + "saveWorkspace": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ", + "openWorkspaceAction": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ...", + "openWorkspaceConfigFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø рабочей области", + "workspaceFolderPickerPlaceholder": "Выберите папку рабочей области" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 6ac555ac896..8339670f4f7 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "Š£Š“Š°Š»ŠøŃ‚ŃŒ ŠøŠ· панели Гействий", - "keepInActivityBar": "Š„Ń€Š°Š½ŠøŃ‚ŃŒ в панели Гействий", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ с панели Гействий", + "keepInActivityBar": "Š„Ń€Š°Š½ŠøŃ‚ŃŒ в панели Гействий", "additionalViews": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ", "numberBadge": "{0} ({1})", "manageExtension": "Управление Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃŠ¼Šø", diff --git a/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index cdc81741e9e..946bb84393f 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ панель Гействий", - "activityBarAriaLabel": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡Š°Ń‚ŠµŠ»ŃŒ активного ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ", "globalActions": "Š“Š»Š¾Š±Š°Š»ŃŒŠ½Ń‹Šµ Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..c9f39eaf3a5 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡Š°Ń‚ŠµŠ»ŃŒ активного ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..0e338824c87 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ", + "numberBadge": "{0} ({1})", + "manageExtension": "Управление Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃŠ¼Šø", + "titleKeybinding": "{0} ({1})", + "toggle": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ закрепленное преГставление" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 75bbb3e9519..3c123d9ce41 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ реГакторы во второй Š³Ń€ŃƒŠæŠæŠµ", "groupThreePicker": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ реГакторы в Ń‚Ń€ŠµŃ‚ŃŒŠµŠ¹ Š³Ń€ŃƒŠæŠæŠµ", "allEditorsPicker": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ все открытые реГакторы", - "view": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€" + "view": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€", + "file": "Файл" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 38dfb4e1703..86a745f5204 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,7 +35,9 @@ "openPreviousEditorInGroup": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠøŠ¹ реГактор в Š³Ń€ŃƒŠæŠæŠµ", "navigateNext": "Далее", "navigatePrevious": "ŠŠ°Š·Š°Š“", + "navigateLast": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ послеГнему", "reopenClosedEditor": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ закрытый реГактор", + "clearRecentFiles": "ŠžŃ‡ŠøŃŃ‚ŠøŃ‚ŃŒ неГавно открытые", "showEditorsInFirstGroup": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ реГакторы в первой Š³Ń€ŃƒŠæŠæŠµ", "showEditorsInSecondGroup": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ реГакторы во второй Š³Ń€ŃƒŠæŠæŠµ", "showEditorsInThirdGroup": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ реГакторы в Ń‚Ń€ŠµŃ‚ŃŒŠµŠ¹ Š³Ń€ŃƒŠæŠæŠµ", diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index a848aecfc21..c38e7f9a12a 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "Клавиша TAB перемещает Ń„Š¾ŠŗŃƒŃ", - "screenReaderDetected": "ДреГство Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š° Š¾Š±Š½Š°Ń€ŃƒŠ¶ŠµŠ½Š¾", + "screenReaderDetected": "ДреГство Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š° оптимизировано", "screenReaderDetectedExtra": "Если вы не ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚е среГство Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š°, измените значение параметра \"editor.accessibilitySupport\" на \"off\".", "disableTabMode": "ŠžŃ‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ режим ŃŠæŠµŃ†ŠøŠ°Š»ŃŒŠ½Ń‹Ń… возможностей", "gotoLine": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ строке", @@ -47,5 +47,11 @@ "reopenWithEncoding": "ŠŸŠ¾Š²Ń‚Š¾Ń€Š½Š¾ Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ в коГировке", "guessedEncoding": "ŠŸŃ€ŠµŠ“ŠæŠ¾Š»Š¾Š¶ŠµŠ½ŠøŠµ на основе соГержимого", "pickEncodingForReopen": "Выберите ŠŗŠ¾Š“ŠøŃ€Š¾Š²ŠŗŃƒ файла Š“Š»Ń его повторного Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŠøŃ", - "pickEncodingForSave": "Выберите ŠŗŠ¾Š“ŠøŃ€Š¾Š²ŠŗŃƒ файла Š“Š»Ń его ŃŠ¾Ń…Ń€Š°Š½ŠµŠ½ŠøŃ" + "pickEncodingForSave": "Выберите ŠŗŠ¾Š“ŠøŃ€Š¾Š²ŠŗŃƒ файла Š“Š»Ń его ŃŠ¾Ń…Ń€Š°Š½ŠµŠ½ŠøŃ", + "screenReaderDetectedExplanation.title": "ДреГство Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š° оптимизировано", + "screenReaderDetectedExplanation.question": "Š’Ń‹ ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚Šµ среГство Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š° в VS Code?", + "screenReaderDetectedExplanation.answerYes": "Да", + "screenReaderDetectedExplanation.answerNo": "ŠŠµŃ‚", + "screenReaderDetectedExplanation.body1": "Š¢ŠµŠæŠµŃ€ŃŒ среГа VS Code оптимизирована Š“Š»Ń среГства Ń‡Ń‚ŠµŠ½ŠøŃ с ŃŠŗŃ€Š°Š½Š°.", + "screenReaderDetectedExplanation.body2": "ŠŠµŠŗŠ¾Ń‚Š¾Ń€Ń‹Šµ Ń„ŃƒŠ½ŠŗŃ†ŠøŠø реГактора (например, перенос слов, сворачивание, Š°Š²Ń‚Š¾Š¼Š°Ń‚ŠøŃ‡ŠµŃŠŗŠ°Ń вставка Š·Š°ŠŗŃ€Ń‹Š²Š°ŃŽŃ‰ŠøŃ… скобок Šø т.Š“.) Š±ŃƒŠ“ŃƒŃ‚ Ń€Š°Š±Š¾Ń‚Š°Ń‚ŃŒ по-Š“Ń€ŃƒŠ³Š¾Š¼Ńƒ." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index e0cde36cb0c..f2324759354 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ панель", "togglePanel": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ панель", "focusPanel": "Фокус на панель", diff --git a/i18n/rus/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json index 1db923803c4..3a5b37bf67a 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/sidebar/sidebarPart.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "compositePart.hideSideBarLabel": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ Š±Š¾ŠŗŠ¾Š²ŃƒŃŽ панель", "focusSideBar": "ŠŸŠµŃ€ŠµŠ²ŠµŃŃ‚Šø Ń„Š¾ŠŗŃƒŃ на Š±Š¾ŠŗŠ¾Š²ŃƒŃŽ панель", "viewCategory": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index 000e440a7b7..2fc29a94bab 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "КоманГа \"{0}\" сейчас неактивна, Šø ее невозможно Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ.", "manageExtension": "Управление Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃŠ¼Šø" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..761072edd67 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "Действий: {0}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..b0fa6d5e7e3 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "Действий: {0}", + "hideView": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ ŠøŠ· боковой панели" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..2feabab41e5 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "ŠŸŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŠµ с иГентификатором '{0}' уже зарегистрировано в расположении '{1}'" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..6dd99f557bc --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ ŠøŠ· боковой панели" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/common/theme.i18n.json b/i18n/rus/src/vs/workbench/common/theme.i18n.json index 190db792a17..81b50af396e 100644 --- a/i18n/rus/src/vs/workbench/common/theme.i18n.json +++ b/i18n/rus/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "Цвет фона активной вклаГки. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. ŠœŠ¾Š¶ŠµŃ‚ ŠæŃ€ŠøŃŃƒŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", "tabInactiveBackground": "Цвет фона неактивной вклаГки. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. ŠœŠ¾Š¶ŠµŃ‚ ŠæŃ€ŠøŃŃƒŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", "tabBorder": "Граница Š“Š»Ń Ń€Š°Š·Š“ŠµŠ»ŠµŠ½ŠøŃ вклаГок. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГакторов. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. ŠœŠ¾Š¶ŠµŃ‚ Š±Ń‹Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", + "tabActiveBorder": "Граница Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ активных вклаГок. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГакторов. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. Также можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов. ", + "tabActiveUnfocusedBorder": "Граница Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ активных вклаГок в Š³Ń€ŃƒŠæŠæŠµ, не ŠøŠ¼ŠµŃŽŃ‰ŠµŠ¹ Ń„Š¾ŠŗŃƒŃŠ°. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГакторов. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. Также можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", "tabActiveForeground": "Цвет переГнего плана активной вклаГки в активной Š³Ń€ŃƒŠæŠæŠµ. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. ŠœŠ¾Š¶ŠµŃ‚ ŠæŃ€ŠøŃŃƒŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", "tabInactiveForeground": "Цвет переГнего плана неактивной вклаГки в активной Š³Ń€ŃƒŠæŠæŠµ. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. ŠœŠ¾Š¶ŠµŃ‚ ŠæŃ€ŠøŃŃƒŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", - "tabUnfocusedActiveForeground": "Цвет переГнего плана активной вклаГки в неактивной Š³Ń€ŃƒŠæŠæŠµ. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. ŠœŠ¾Š¶ŠµŃ‚ ŠæŃ€ŠøŃŃƒŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", - "tabUnfocusedInactiveForeground": "Цвет переГнего плана неактивной вклаГки в неактивной Š³Ń€ŃƒŠæŠæŠµ. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. ŠœŠ¾Š¶ŠµŃ‚ ŠæŃ€ŠøŃŃƒŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", + "tabUnfocusedActiveForeground": "Цвет переГнего плана активной вклаГки в Š³Ń€ŃƒŠæŠæŠµ, не ŠøŠ¼ŠµŃŽŃ‰ŠµŠ¹ Ń„Š¾ŠŗŃƒŃŠ°. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. Также можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", + "tabUnfocusedInactiveForeground": "Цвет переГнего плана неактивной вклаГки в Š³Ń€ŃƒŠæŠæŠµ, не ŠøŠ¼ŠµŃŽŃ‰ŠµŠ¹ Ń„Š¾ŠŗŃƒŃŠ°. ВклаГки — ŃŃ‚Š¾ контейнеры Š“Š»Ń реГакторов в области реГактора. Š’ оГной Š³Ń€ŃƒŠæŠæŠµ реГакторов можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько вклаГок. Также можно Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ несколько Š³Ń€ŃƒŠæŠæ реГакторов.", "editorGroupBackground": "Цвет фона Š³Ń€ŃƒŠæŠæŃ‹ реГакторов. Š“Ń€ŃƒŠæŠæŃ‹ реГакторов ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŃŃŽŃ‚ собой контейнеры реГакторов. Цвет фона Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ при перетаскивании Š³Ń€ŃƒŠæŠæ реГакторов.", "tabsContainerBackground": "Цвет фона Š“Š»Ń заголовка Š³Ń€ŃƒŠæŠæŃ‹ реГакторов, когГа вклаГки Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Ń‹. Š“Ń€ŃƒŠæŠæŃ‹ реГакторов ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŃŃŽŃ‚ собой контейнеры реГакторов.", "tabsContainerBorder": "Цвет границы Š“Š»Ń заголовка Š³Ń€ŃƒŠæŠæŃ‹ реГакторов, когГа вклаГки Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Ń‹. Š“Ń€ŃƒŠæŠæŃ‹ реГакторов ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŃŃŽŃ‚ собой контейнеры реГакторов.", @@ -18,15 +20,15 @@ "editorGroupBorder": "Цвет Š“Š»Ń Ń€Š°Š·Š“ŠµŠ»ŠµŠ½ŠøŃ Š½ŠµŃŠŗŠ¾Š»ŃŒŠŗŠøŃ… Š³Ń€ŃƒŠæŠæ реГакторов. Š“Ń€ŃƒŠæŠæŃ‹ реГакторов — ŃŃ‚Š¾ контейнеры реГакторов.", "editorDragAndDropBackground": "Цвет фона при перетаскивании реГакторов. Этот цвет Голжен Š¾Š±Š»Š°Š“Š°Ń‚ŃŒ ŠæŃ€Š¾Š·Ń€Š°Ń‡Š½Š¾ŃŃ‚ŃŒŃŽ, чтобы соГержимое реГактора Š¾ŃŃ‚Š°Š²Š°Š»Š¾ŃŃŒ виГимым.", "panelBackground": "Цвет фона панели. Панели показаны поГ Š¾Š±Š»Š°ŃŃ‚ŃŒŃŽ реГактора Šø соГержат такие ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ, как выхоГные Ганные Šø встроенный терминал.", - "panelBorder": "Цвет верхней границы панели, Š¾Ń‚Š“ŠµŠ»ŃŃŽŃ‰ŠµŠ¹ ее от реГактора. Панели показаны поГ Š¾Š±Š»Š°ŃŃ‚ŃŒŃŽ реГактора Šø соГержат такие ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ, как выхоГные Ганные Šø встроенный терминал.", "panelActiveTitleForeground": "Цвет заголовка Š“Š»Ń активной панели. Панели Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ поГ Š¾Š±Š»Š°ŃŃ‚ŃŒŃŽ реГактора Šø соГержат такие ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ, как окно вывоГа Šø встроенный терминал.", "panelInactiveTitleForeground": "Цвет заголовка Š“Š»Ń неактивной панели. Панели Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ поГ Š¾Š±Š»Š°ŃŃ‚ŃŒŃŽ реГактора Šø соГержат такие ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ, как окно вывоГа Šø встроенный терминал.", "panelActiveTitleBorder": "Цвет границ Š“Š»Ń заголовка активной панели. Панели Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ поГ Š¾Š±Š»Š°ŃŃ‚ŃŒŃŽ реГактора Šø соГержат такие ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ, как окно вывоГа Šø встроенный терминал.", - "statusBarForeground": "Цвет переГнего плана панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ. Панель ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ внизу окна.", + "statusBarForeground": "Цвет переГнего плана строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, когГа открыта Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ в нижней части окна.", "statusBarNoFolderForeground": "Цвет переГнего плана строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, если папка не открыта. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ в нижней части окна.", - "statusBarBackground": "Цвет фона станГартной панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ. Панель ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ внизу окна.", + "statusBarBackground": "Цвет фона строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, когГа открыта Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ в нижней части окна.", "statusBarNoFolderBackground": "Цвет фона панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, если папка не открыта. Панель ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ внизу окна.", "statusBarBorder": "Цвет границы строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, который Ń€Š°ŃŠæŃ€Š¾ŃŃ‚Ń€Š°Š½ŃŠµŃ‚ŃŃ на Š±Š¾ŠŗŠ¾Š²ŃƒŃŽ панель Šø реГактор. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ расположена в нижней части окна.", + "statusBarNoFolderBorder": "Цвет границы строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, который Ń€Š°ŃŠæŃ€Š¾ŃŃ‚Ń€Š°Š½ŃŠµŃ‚ŃŃ на Š±Š¾ŠŗŠ¾Š²ŃƒŃŽ панель Šø реГактор, когГа открытые папки Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ расположена в нижней части окна.", "statusBarItemActiveBackground": "Цвет фона ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ при щелчке. Панель ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ внизу окна.", "statusBarItemHoverBackground": "Цвет фона ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ при навеГении. Панель ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ внизу окна.", "statusBarProminentItemBackground": "Цвет фона приоритетных ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ. ŠŸŃ€ŠøŠ¾Ń€ŠøŃ‚ŠµŃ‚Š½Ń‹Šµ ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Ń‹ Š²Ń‹Š“ŠµŠ»ŃŃŽŃ‚ŃŃ на фоне Š“Ń€ŃƒŠ³ŠøŃ… ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, чтобы ŠæŠ¾Š“Ń‡ŠµŃ€ŠŗŠ½ŃƒŃ‚ŃŒ ŠøŃ… значение. Панель ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ в нижней части окна.", @@ -41,12 +43,14 @@ "sideBarForeground": "Цвет переГнего плана боковой панели. Š‘Š¾ŠŗŠ¾Š²Š°Ń ŠæŠ°Š½ŠµŠ»ŃŒĀ ā€” ŃŃ‚Š¾ контейнер Š“Š»Ń таких преГставлений, как провоГник Šø поиск.", "sideBarBorder": "Цвет границы боковой панели со стороны реГактора. Š‘Š¾ŠŗŠ¾Š²Š°Ń панель — ŃŃ‚Š¾ контейнер Š“Š»Ń таких преГставлений, как провоГник Šø поиск.", "sideBarTitleForeground": "Цвет переГнего плана заголовка боковой панели. Š‘Š¾ŠŗŠ¾Š²Š°Ń ŠæŠ°Š½ŠµŠ»ŃŒĀ ā€” ŃŃ‚Š¾ контейнер Š“Š»Ń таких преГставлений, как провоГник Šø поиск.", + "sideBarDragAndDropBackground": "Цвет ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² боковой панели при перетаскивании. Цвет Голжен Š¾Š±Š»Š°Š“Š°Ń‚ŃŒ ŠæŃ€Š¾Š·Ń€Š°Ń‡Š½Š¾ŃŃ‚ŃŒŃŽ, чтобы соГержимое ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² боковой панели Š¾ŃŃ‚Š°Š²Š°Š»Š¾ŃŃŒ виГимым. Š‘Š¾ŠŗŠ¾Š²Š°Ń панель ŠæŃ€ŠµŠ“Š¾ŃŃ‚Š°Š²Š»ŃŠµŃ‚ собой контейнер Š“Š»Ń таких преГставлений как провоГник Šø поиск.", "sideBarSectionHeaderBackground": "Цвет фона Š“Š»Ń заголовка разГела боковой панели. Š‘Š¾ŠŗŠ¾Š²Š°Ń ŠæŠ°Š½ŠµŠ»ŃŒĀ ā€” ŃŃ‚Š¾ контейнер Š“Š»Ń таких преГставлений, как провоГник Šø поиск.", "sideBarSectionHeaderForeground": "Цвет переГнего плана Š“Š»Ń заголовка разГела боковой панели. Š‘Š¾ŠŗŠ¾Š²Š°Ń ŠæŠ°Š½ŠµŠ»ŃŒĀ ā€” ŃŃ‚Š¾ контейнер Š“Š»Ń таких преГставлений, как провоГник Šø поиск.", "titleBarActiveForeground": "ŠŸŠµŃ€ŠµŠ“Š½ŠøŠ¹ план панели заголовка, если окно активно. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что ŃŃ‚Š¾Ń‚ цвет сейчас ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ в macOS.", "titleBarInactiveForeground": "ŠŸŠµŃ€ŠµŠ“Š½ŠøŠ¹ план панели заголовка, если окно неактивно. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что ŃŃ‚Š¾Ń‚ цвет сейчас ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ в macOS.", "titleBarActiveBackground": "Фон панели заголовка, если окно активно. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что ŃŃ‚Š¾Ń‚ цвет сейчас ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ в macOS.", "titleBarInactiveBackground": "Фон панели заголовка, если окно неактивно. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что ŃŃ‚Š¾Ń‚ цвет сейчас ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ в macOS.", + "titleBarBorder": "Цвет границы панели заголовка. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что ŃŃ‚Š¾Ń‚ цвет сейчас ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ в macOS.", "notificationsForeground": "Цвет переГнего плана Š“Š»Ń увеГомлений. Š£Š²ŠµŠ“Š¾Š¼Š»ŠµŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ в верхней части окна.", "notificationsBackground": "Цвет фона Š“Š»Ń увеГомлений. Š£Š²ŠµŠ“Š¾Š¼Š»ŠµŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ в верхней части окна.", "notificationsButtonBackground": "Цвет фона кнопки Š“Š»Ń увеГомлений. Š£Š²ŠµŠ“Š¾Š¼Š»ŠµŠ½ŠøŃ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ в верхней части окна.", diff --git a/i18n/rus/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/rus/src/vs/workbench/electron-browser/actions.i18n.json index 5140913c988..be259940bc0 100644 --- a/i18n/rus/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/rus/src/vs/workbench/electron-browser/actions.i18n.json @@ -6,6 +6,8 @@ { "closeActiveEditor": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ реГактор", "closeWindow": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ окно", + "closeWorkspace": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ", + "noWorkspaceOpened": "Š’ ŃŃ‚Š¾Š¼ ŃŠŗŠ·ŠµŠ¼ŠæŠ»ŃŃ€Šµ Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚ открытые рабочие области.", "newWindow": "ŠŠ¾Š²Š¾Šµ окно", "toggleFullScreen": "ŠŸŠ¾Š»Š½Š¾ŃŠŗŃ€Š°Š½Š½Ń‹Š¹ режим", "toggleMenuBar": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ ŃŃ‚Ń€Š¾ŠŗŃƒ Š¼ŠµŠ½ŃŽ", @@ -20,7 +22,11 @@ "close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ окно", "switchWindow": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ окно...", "quickSwitchWindow": "Быстро ŠæŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ окно...", + "workspaces": "рабочие области", "files": "файлы", + "openRecentPlaceHolderMac": "Выберите, чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ (чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ в новом окне, ŃƒŠ“ŠµŃ€Š¶ŠøŠ²Š°Š¹Ń‚Šµ клавишу CMD)", + "openRecentPlaceHolder": "Выберите, чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ (чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ в новом окне, ŃƒŠ“ŠµŃ€Š¶ŠøŠ²Š°Š¹Ń‚Šµ клавишу CTRL)", + "remove": "Š£Š“Š°Š»ŠøŃ‚ŃŒ ŠøŠ· послеГних открытых", "openRecent": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ послеГние...", "quickOpenRecent": "Быстро Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ послеГние...", "closeMessages": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ ŃƒŠ²ŠµŠ“Š¾Š¼Š»ŠµŠ½ŠøŃ", @@ -36,5 +42,10 @@ "navigateUp": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃŽ Š²Š²ŠµŃ€Ń…Ńƒ", "navigateDown": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃŽ внизу", "increaseViewSize": "Š£Š²ŠµŠ»ŠøŃ‡ŠøŃ‚ŃŒ размер Ń‚ŠµŠŗŃƒŃ‰ŠµŠ³Š¾ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ", - "decreaseViewSize": "Š£Š¼ŠµŠ½ŃŒŃˆŠøŃ‚ŃŒ размер Ń‚ŠµŠŗŃƒŃ‰ŠµŠ³Š¾ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ" + "decreaseViewSize": "Š£Š¼ŠµŠ½ŃŒŃˆŠøŃ‚ŃŒ размер Ń‚ŠµŠŗŃƒŃ‰ŠµŠ³Š¾ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ", + "showPreviousTab": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŃƒŃŽ вклаГку в окне", + "showNextWindowTab": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŃƒŃŽ вклаГку в окне", + "moveWindowTabToNewWindow": "ŠŸŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ вклаГку окна в новое окно", + "mergeAllWindowTabs": "ŠžŠ±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚ŃŒ все окна", + "toggleWindowTabsBar": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ панель вклаГок окна" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/rus/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..b6db31f0ebd --- /dev/null +++ b/i18n/rus/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ ŃŠ·Ń‹Šŗ", + "displayLanguage": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ ŃŠ·Ń‹Šŗ интерфейса VSCode.", + "doc": "Дписок поГГерживаемых ŃŠ·Ń‹ŠŗŠ¾Š² см. в {0}.", + "restart": "Š”Š»Ń ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š·Š½Š°Ń‡ŠµŠ½ŠøŃ Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗ VSCode.", + "fail.createSettings": "ŠŠµŠ²Š¾Š·Š¼Š¾Š¶Š½Š¾ ŃŠ¾Š·Š“Š°Ń‚ŃŒ \"{0}\" ({1}).", + "JsonSchema.locale": "Язык ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠ¾Š³Š¾ интерфейса." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json index 73686d72848..6887c80a117 100644 --- a/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -7,15 +7,17 @@ "view": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ", "help": "Дправка", "file": "Файл", + "workspaces": "Рабочие области", "developer": "Разработчик", "showEditorTabs": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжны ли открытые реГакторы Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ на вклаГках или нет.", + "workbench.editor.labelFormat.short": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ ŠøŠ¼Ń файла Šø ŠøŠ¼Ń каталога.", + "workbench.editor.labelFormat.long": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ ŠøŠ¼Ń файла Šø Š°Š±ŃŠ¾Š»ŃŽŃ‚Š½Ń‹Š¹ ŠæŃƒŃ‚ŃŒ.", + "tabDescription": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ формат метки реГактора. Изменив ŃŃ‚Š¾Ń‚ параметр, можно ŃŠ“ŠµŠ»Š°Ń‚ŃŒ более Š½Š°Š³Š»ŃŠ“ным расположение файла:\n- короткий формат: 'parent'\n- среГний формат: 'workspace/src/parent'\n- Глинный формат: '/home/user/workspace/src/parent'\n- по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ: '.../parent', если Š“Ń€ŃƒŠ³Š°Ń вклаГка имеет такой же заголовок или Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Š¹ ŠæŃƒŃ‚ŃŒ Šŗ рабочей области, если вклаГки Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½Ń‹", "editorTabCloseButton": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ положение кнопок Š·Š°ŠŗŃ€Ń‹Ń‚ŠøŃ вклаГок реГактора или Š¾Ń‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ ŠøŃ…, если заГано значение off.", "showIcons": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжны ли открытые реГакторы Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ со значком. Š¢Ń€ŠµŠ±ŃƒŠµŃ‚ Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ Ń‚ŠµŠ¼Ńƒ значков.", - "enablePreview": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ ли открытые реГакторы в режиме ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра. РеГакторы с ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Š¼ просмотром повторно ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŃŽŃ‚ся Го ŃŠ¾Ń…Ń€Š°Š½ŠµŠ½ŠøŃ (например, с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Гвойного щелчка или ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ).", + "enablePreview": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ ли открытые реГакторы в режиме ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра. РеГакторы в режиме ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра можно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ, пока они открыты (например, с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Гвойного щелчка Š¼Ń‹ŃˆŠø или ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ). Текст в таких реГакторах Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ ŠŗŃƒŃ€ŃŠøŠ²Š¾Š¼.", "enablePreviewFromQuickOpen": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ ли реГакторы ŠøŠ· Quick Open в режиме ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра. РеГакторы в режиме ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š³Š¾ просмотра повторно ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŃŽŃ‚ся Го ŃŠ¾Ń…Ń€Š°Š½ŠµŠ½ŠøŃ (например, с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Гвойного щелчка или ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ).", - "editorOpenPositioning": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ место Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŠøŃ реГакторов. Выберите \"Длева\" или \"Дправа\", чтобы Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ реГакторы слева или справа от активного сейчас реГактора. Выберите \"ŠŸŠµŃ€Š²Ń‹Š¹\" или \"ПослеГний\", чтобы Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ реГакторы независимо от активного сейчас реГактора.", "revealIfOpen": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ ли реГактор в какой-либо ŠøŠ· виГимых Š³Ń€ŃƒŠæŠæ при открытии. Если Ń„ŃƒŠ½ŠŗŃ†ŠøŃ Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½Š°, реГактор Š¾Ń‚ŠŗŃ€Ń‹Š²Š°ŠµŃ‚ŃŃ в Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¹ активной Š³Ń€ŃƒŠæŠæŠµ реГакторов. Если Ń„ŃƒŠ½ŠŗŃ†ŠøŃ Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Š°, вместо Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŠøŃ уже открытый реГактор Š±ŃƒŠ“ŠµŃ‚ отображен в Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¹ активной Š³Ń€ŃƒŠæŠæŠµ реГакторов. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что в некоторых ŃŠ»ŃƒŃ‡Š°ŃŃ… ŃŃ‚Š¾Ń‚ параметр ŠøŠ³Š½Š¾Ń€ŠøŃ€ŃƒŠµŃ‚ŃŃ, например при ŠæŃ€ŠøŠ½ŃƒŠ“ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¼ открытии реГактора в опреГеленной Š³Ń€ŃƒŠæŠæŠµ или сбоку от Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¹ активной Š³Ń€ŃƒŠæŠæŃ‹ реГакторов.", - "commandHistory": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ количество неГавно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½Š½Ń‹Ń… команГ, которые ŃŠ»ŠµŠ“ŃƒŠµŃ‚ Ń…Ń€Š°Š½ŠøŃ‚ŃŒ в Š¶ŃƒŃ€Š½Š°Š»Šµ палитры команГ. Установите значение 0, чтобы Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ Š¶ŃƒŃ€Š½Š°Š» команГ.", "preserveInput": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ли Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ ŠæŠ¾ŃŠ»ŠµŠ“Š½ŃŽŃŽ Š²Š²ŠµŠ“ŠµŠ½Š½ŃƒŃŽ команГу в палитре команГ при ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼ открытии палитры.", "closeOnFocusLost": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ автоматическим закрытием Quick Open при потере Ń„Š¾ŠŗŃƒŃŠ°.", "openDefaultSettings": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ открытием реГактора с отображением всех настроек по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ при открытии настроек.", @@ -23,6 +25,10 @@ "statusBarVisibility": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ Š²ŠøŠ“ŠøŠ¼Š¾ŃŃ‚ŃŒŃŽ строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ в нижней части рабочего места.", "activityBarVisibility": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ Š²ŠøŠ“ŠøŠ¼Š¾ŃŃ‚ŃŒŃŽ панели Гействий на рабочем месте.", "closeOnFileDelete": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ли автоматически Š·Š°ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ реГакторы, когГа отображаемый в них файл уГален или переименован Š“Ń€ŃƒŠ³ŠøŠ¼ процессом. ŠŸŃ€Šø Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠø ŃŃ‚Š¾Š¹ Ń„ŃƒŠ½ŠŗŃ†ŠøŠø реГактор Š¾ŃŃ‚Š°ŠµŃ‚ŃŃ открытым в качестве черновика. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что при уГалении ŠøŠ· ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ реГактор Š·Š°ŠŗŃ€Ń‹Š²Š°ŠµŃ‚ŃŃ всегГа Šø что файлы черновиков никогГа не Š·Š°ŠŗŃ€Ń‹Š²Š°ŃŽŃ‚ся Š“Š»Ń ŃŠ¾Ń…Ń€Š°Š½ŠµŠ½ŠøŃ Ганных.", + "fontAliasing": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ метоГом ŃŠ³Š»Š°Š¶ŠøŠ²Š°Š½ŠøŃ ŃˆŃ€ŠøŃ„Ń‚Š¾Š² в рабочей области.-по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ: субпиксельное сглаживание ŃˆŃ€ŠøŃ„Ń‚Š¾Š²; позволит Š“Š¾Š±ŠøŃ‚ŃŒŃŃ максимальной четкости текста на Š±Š¾Š»ŃŒŃˆŠøŠ½ŃŃ‚ве Гисплеев за ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµŠ¼ Retina - сглаживание: сглаживание ŃˆŃ€ŠøŃ„Ń‚Š¾Š² на ŃƒŃ€Š¾Š²Š½Šµ пикселей, в отличие от субпиксельного ŃŠ³Š»Š°Š¶ŠøŠ²Š°Š½ŠøŃ; позволит ŃŠ“ŠµŠ»Š°Ń‚ŃŒ ŃˆŃ€ŠøŃ„Ń‚ более светлым в целом - нет: сглаживание ŃˆŃ€ŠøŃ„Ń‚Š¾Š² Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½Š¾; текст Š±ŃƒŠ“ŠµŃ‚ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ с неровными острыми ŠŗŃ€Š°ŃŠ¼Šø ", + "workbench.fontAliasing.default": "Дубпиксельное сглаживание ŃˆŃ€ŠøŃ„Ń‚Š¾Š²; позволит Š“Š¾Š±ŠøŃ‚ŃŒŃŃ максимальной четкости текста на Š±Š¾Š»ŃŒŃˆŠøŠ½ŃŃ‚ве Гисплеев за ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµŠ¼ Retina.", + "workbench.fontAliasing.antialiased": "Дглаживание ŃˆŃ€ŠøŃ„Ń‚Š¾Š² на ŃƒŃ€Š¾Š²Š½Šµ пикселей, в отличие от субпиксельного ŃŠ³Š»Š°Š¶ŠøŠ²Š°Š½ŠøŃ. ŠœŠ¾Š¶ŠµŃ‚ ŃŠ“ŠµŠ»Š°Ń‚ŃŒ ŃˆŃ€ŠøŃ„Ń‚ светлее в целом.", + "workbench.fontAliasing.none": "ŠžŃ‚ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ сглаживание ŃˆŃ€ŠøŃ„Ń‚Š¾Š²; текст Š±ŃƒŠ“ŠµŃ‚ Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒŃŃ с неровными острыми ŠŗŃ€Š°ŃŠ¼Šø.", "swipeToNavigate": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡Š°Š¹Ń‚ŠµŃŃŒ межГу открытыми файлами, ŠæŃ€Š¾Š²Š¾Š“Ń по ŃŠŗŃ€Š°Š½Ńƒ по горизонтали Ń‚Ń€ŠµŠ¼Ń ŠæŠ°Š»ŃŒŃ†Š°Š¼Šø.", "workbenchConfigurationTitle": "Workbench", "window.openFilesInNewWindow.on": "Файлы Š±ŃƒŠ“ŃƒŃ‚ Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒŃŃ в новом окне.", @@ -34,16 +40,18 @@ "window.openFoldersInNewWindow.default": "Папки Š±ŃƒŠ“ŃƒŃ‚ Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒŃŃ в новом окне, если папка не выбрана в приложении (например, в Š¼ŠµŠ½ŃŽ \"Файл\").", "openFoldersInNewWindow": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŃƒŃ‚ ли папки Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒŃŃ в новом окне или Š·Š°Š¼ŠµŠ½ŃŃ‚ŃŒ послеГнее активное окно.\n- default: папки Š±ŃƒŠ“ŃƒŃ‚ Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒŃŃ в новом окне, если папка не выбрана ŠøŠ· ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ (например, ŠøŠ· Š¼ŠµŠ½ŃŽ \"Файл\").\n- on: папки Š±ŃƒŠ“ŃƒŃ‚ Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒŃŃ в новом окне.\n- off: папки Š±ŃƒŠ“ŃƒŃ‚ Š·Š°Š¼ŠµŠ½ŃŃ‚ŃŒ послеГнее активное окно.\nŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что возможны ŃŠ»ŃƒŃ‡Š°Šø, когГа ŃŃ‚Š¾Ń‚ параметр ŠøŠ³Š½Š¾Ń€ŠøŃ€ŃƒŠµŃ‚ŃŃ (например, при использовании параметра команГной строки -new-window или -reuse-window).", "window.reopenFolders.all": "ŠŸŠ¾Š²Ń‚Š¾Ń€Š½Š¾ Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ все окна.", + "window.reopenFolders.folders": "ŠŸŠ¾Š²Ń‚Š¾Ń€Š½Š¾ откройте все папки. ŠŸŃƒŃŃ‚Ń‹Šµ рабочие области не Š±ŃƒŠ“ŃƒŃ‚ восстановлены.", "window.reopenFolders.one": "ŠŸŠ¾Š²Ń‚Š¾Ń€Š½Š¾ Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ послеГнее активное окно.", "window.reopenFolders.none": "ŠŠøŠŗŠ¾Š³Š“Š° не Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ окно повторно. ВсегГа Š½Š°Ń‡ŠøŠ½Š°Ń‚ŃŒ с ŠæŃƒŃŃ‚Š¾Š³Š¾ окна.", + "restoreWindows": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ повторным открытием окон после ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗŠ°. Выберите 'none', чтобы всегГа Š½Š°Ń‡ŠøŠ½Š°Ń‚ŃŒ с ŠæŃƒŃŃ‚Š¾Š¹ рабочей области; 'one', чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ послеГнее окно, с которым вы работали; 'folders', чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ все окна с открытыми папками, Šø 'all', чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ все окна послеГнего сеанса.", "restoreFullscreen": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Голжно ли окно Š²Š¾ŃŃŃ‚Š°Š½Š°Š²Š»ŠøŠ²Š°Ń‚ŃŒŃŃ в ŠæŠ¾Š»Š½Š¾ŃŠŗŃ€Š°Š½Š½Š¾Š¼ режиме, если оно было закрыто в ŠæŠ¾Š»Š½Š¾ŃŠŗŃ€Š°Š½Š½Š¾Š¼ режиме.", "zoomLevel": "ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ Š¼Š°ŃŃˆŃ‚Š°Š± окна. Š˜ŃŃ…Š¾Š“Š½Ń‹Š¹ размер равен 0. Увеличение или уменьшение Š·Š½Š°Ń‡ŠµŠ½ŠøŃ на 1 означает ŃƒŠ²ŠµŠ»ŠøŃ‡ŠµŠ½ŠøŠµ или уменьшение окна на 20 %. Чтобы более точно Š·Š°Š“Š°Ń‚ŃŒ Š¼Š°ŃŃˆŃ‚Š°Š±, можно также ввести Š“ŠµŃŃŃ‚ŠøŃ‡Š½Š¾Šµ число.", - "title": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ заголовок окна в зависимости от активного реГактора. ŠŸŠ¾Š“ŃŃ‚Š°Š½Š¾Š²ŠŗŠ° переменных Š²Ń‹ŠæŠ¾Š»Š½ŃŠµŃ‚ŃŃ на основе контекста:\n${activeEditorShort}: например, myFile.txt\n${activeEditorMedium}: например, myFolder/myFile.txt\n${activeEditorLong}: например, /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: например, myFolder\n${folderPath}: например, /Users/Development/myFolder\n${rootName}: например, myFolder1, myFolder2, myFolder3\n${rootPath}: например, /Users/Development/myWorkspace\n${appName}: например, VS Code\n${dirty}: инГикатор dirty, если активный реГактор ŃŠ²Š»ŃŠµŃ‚ŃŃ \"Š³Ń€ŃŠ·Š½Ń‹Š¼\"\n${separator}: ŃƒŃŠ»Š¾Š²Š½Ń‹Š¹ Ń€Š°Š·Š“ŠµŠ»ŠøŃ‚ŠµŠ»ŃŒ (\" - \"), который Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ, Ń‚Š¾Š»ŃŒŠŗŠ¾ если Š¾ŠŗŃ€ŃƒŠ¶ŠµŠ½ переменными со Š·Š½Š°Ń‡ŠµŠ½ŠøŃŠ¼Šø ", "window.newWindowDimensions.default": "ŠžŃ‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ новые окна в центре ŃŠŗŃ€Š°Š½Š°.", "window.newWindowDimensions.inherit": "ŠžŃ‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ новые окна того же размера, что Šø послеГнее активное окно.", "window.newWindowDimensions.maximized": "ŠžŃ‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ новые окна в Ń€Š°Š·Š²ŠµŃ€Š½ŃƒŃ‚Š¾Š¼ ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŠø.", "window.newWindowDimensions.fullscreen": "ŠžŃ‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ новые окна в ŠæŠ¾Š»Š½Š¾ŃŠŗŃ€Š°Š½Š½Š¾Š¼ режиме.", "newWindowDimensions": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ размеры нового Š¾Ń‚ŠŗŃ€Ń‹Š²Š°ŃŽŃ‰ŠµŠ³Š¾ŃŃ окна, если по крайней мере оГно окно уже открыто. По ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ новое окно Š±ŃƒŠ“ет открыто в центре ŃŠŗŃ€Š°Š½Š° в уменьшенном размере. Если указано значение \"inherit\", размеры нового окна Š±ŃƒŠ“ŃƒŃ‚ равны размерам послеГнего активного окна. Если указано значение \"maximized\", окно Š±ŃƒŠ“ет открыто в максимальном размере, а если указано значение \"fullscreen\", окно Š±ŃƒŠ“ет открыто в ŠæŠ¾Š»Š½Š¾ŃŠŗŃ€Š°Š½Š½Š¾Š¼ режиме. ŠžŠ±Ń€Š°Ń‚ŠøŃ‚Šµ внимание, что ŃŃ‚Š¾Ń‚ параметр не Š²Š»ŠøŃŠµŃ‚ на первое открываемое окно. Размеры Šø расположение первого окна всегГа Š±ŃƒŠ“ŃƒŃ‚ ŃŠ¾Š²ŠæŠ“Š°Š°Ń‚ŃŒ с размерами Šø расположением ŃŃ‚Š¾Š³Š¾ окна переГ закрытием.", + "closeWhenEmpty": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ли Š·Š°ŠŗŃ€Ń‹Ń‚ŃŒ окно при закрытии послеГнего реГактора. Этот параметр ŠæŃ€ŠøŠ¼ŠµŠ½ŃŠµŃ‚ŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ Šŗ окнам, в которых нет открытых папок.", "window.menuBarVisibility.default": "ŠœŠµŠ½ŃŽ скрыто Ń‚Š¾Š»ŃŒŠŗŠ¾ в ŠæŠ¾Š»Š½Š¾ŃŠŗŃ€Š°Š½Š½Š¾Š¼ режиме.", "window.menuBarVisibility.visible": "ŠœŠµŠ½ŃŽ всегГа виГимо, Гаже в ŠæŠ¾Š»Š½Š¾ŃŠŗŃ€Š°Š½Š½Š¾Š¼ режиме.", "window.menuBarVisibility.toggle": "ŠœŠµŠ½ŃŽ скрыто, но его можно вывести с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ клавиши ALT.", diff --git a/i18n/rus/src/vs/workbench/electron-browser/window.i18n.json b/i18n/rus/src/vs/workbench/electron-browser/window.i18n.json index 8b4be6fe00b..dde4ab1d228 100644 --- a/i18n/rus/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/rus/src/vs/workbench/electron-browser/window.i18n.json @@ -9,6 +9,5 @@ "cut": "Š’Ń‹Ń€ŠµŠ·Š°Ń‚ŃŒ", "copy": "ŠšŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ", "paste": "Š’ŃŃ‚Š°Š²ŠøŃ‚ŃŒ", - "selectAll": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ все", - "confirmOpenButton": "&&ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ..." + "selectAll": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ все" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 177e66e9e73..b42f22c8880 100644 --- a/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Если строка ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŠµŃ‚ шаблону, то Š¾Ń‚ŃŃ‚ŃƒŠæ Š“Š»Ń ŃŃ‚Š¾Š¹ строки не ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ŠøŠ·Š¼ŠµŠ½ŃŃ‚ŃŒ Šø ŠæŃ€Š¾Š²ŠµŃ€ŃŃ‚ŃŒ на соответствие Š“Ń€ŃƒŠ³ŠøŠ¼ правилам.", "schema.indentationRules.unIndentedLinePattern.pattern": "Шаблон Ń€ŠµŠ³ŃƒŠ»ŃŃ€Š½Š¾Š³Š¾ Š²Ń‹Ń€Š°Š¶ŠµŠ½ŠøŃ Š“Š»Ń unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Флаги Ń€ŠµŠ³ŃƒŠ»ŃŃ€Š½Š¾Š³Š¾ Š²Ń‹Ń€Š°Š¶ŠµŠ½ŠøŃ Š“Š»Ń unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Должно ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ шаблону \"/^([gimuy]+)$/\"." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Должно ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ шаблону \"/^([gimuy]+)$/\".", + "schema.folding": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ ŃŠ²Š¾Ń€Š°Ń‡ŠøŠ²Š°Š½ŠøŃ ŃŠ·Ń‹ŠŗŠ°.", + "schema.folding.offSide": "Язык ŠæŃ€ŠøŠ“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ правила Š¾Ń‚ŃŃ‚ŃƒŠæŠ¾Š², если блоки в ŃŃ‚Š¾Š¼ ŃŠ·Ń‹ŠŗŠµ Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŃŽŃ‚ŃŃ Š¾Ń‚ŃŃ‚ŃƒŠæŠ°Š¼Šø. Если ŃŃ‚Š¾Ń‚ параметр ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½, ŠæŃƒŃŃ‚Ń‹Šµ строки Š±ŃƒŠ“ŃƒŃ‚ ŠæŃ€ŠøŠ½Š°Š“Š»ŠµŠ¶Š°Ń‚ŃŒ ŠæŠ¾ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼Ńƒ блоку.", + "schema.folding.markers": "ŠœŠµŃ‚ŠŗŠø ŃŠ²ŠµŃ€Ń‚Ń‹Š²Š°Š½ŠøŃ Š“Š»Ń конкретного ŃŠ·Ń‹ŠŗŠ°, например, '#region' Šø '#endregion'. Š ŠµŠ³ŃƒŠ»ŃŃ€Š½Ń‹Šµ Š²Ń‹Ń€Š°Š¶ŠµŠ½ŠøŃ начала Šø Š¾ŠŗŠ¾Š½Ń‡Š°Š½ŠøŃ Š±ŃƒŠ“ŃƒŃ‚ применены Šŗ ŃŠ¾Š“ŠµŃ€Š¶ŠøŠ¼Š¾Š¼Ńƒ всех строк. Š˜Ń… ŃŠ»ŠµŠ“ŃƒŠµŃ‚ Ń‚Ń‰Š°Ń‚ŠµŠ»ŃŒŠ½Š¾ ŠæŃ€Š¾Š“ŃƒŠ¼Š°Ń‚ŃŒ.", + "schema.folding.markers.start": "Шаблон Ń€ŠµŠ³ŃƒŠ»ŃŃ€Š½Š¾Š³Š¾ Š²Ń‹Ń€Š°Š¶ŠµŠ½ŠøŃ Š“Š»Ń метки начала. Š ŠµŠ³ŃƒŠ»ŃŃ€Š½Š¾Šµ выражение Голжно Š½Š°Ń‡ŠøŠ½Š°Ń‚ŃŒŃŃ с '^'.", + "schema.folding.markers.end": "Шаблон Ń€ŠµŠ³ŃƒŠ»ŃŃ€Š½Š¾Š³Š¾ Š²Ń‹Ń€Š°Š¶ŠµŠ½ŠøŃ Š“Š»Ń метки Š¾ŠŗŠ¾Š½Ń‡Š°Š½ŠøŃ. Š ŠµŠ³ŃƒŠ»ŃŃ€Š½Š¾Šµ выражение Голжно Š½Š°Ń‡ŠøŠ½Š°Ń‚ŃŒŃŃ с '^'. " } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..0c3fb07d4dd --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "Š’ŠøŠ“: ŠæŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ мини-ŠŗŠ°Ń€Ń‚Ńƒ" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index e6eb87730f7..926bc748b56 100644 --- a/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ ŃƒŠæŃ€Š°Š²Š»ŃŃŽŃ‰ŠøŠµ символы" + "toggleRenderControlCharacters": "Š’ŠøŠ“: ŠæŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ ŃƒŠæŃ€Š°Š²Š»ŃŃŽŃ‰ŠøŠµ символы" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index d3464613b1a..2c3e4867a49 100644 --- a/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ отображение пробелов" + "toggleRenderWhitespace": "Š’ŠøŠ“: Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ вывоГ пробелов" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json index 575548ac1c8..e0979b26953 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugActionItems.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "noConfigurations": "ŠŠµŃ‚ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠ¹", + "addConfigTo": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ ({0})...", "addConfiguration": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ..." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 820bfa6a8c8..4c4a6981903 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "ŠžŃ‚Š»Š°Š“ŠŗŠ°: {0}", "debugAriaLabel": "ВвеГите ŠøŠ¼Ń используемой ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø запуска.", + "addConfigTo": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ ({0})...", + "addConfiguration": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ...", "noConfigurationsMatching": "ŠŠµŃ‚ ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠøŃ… ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠ¹ отлаГки.", "noConfigurationsFound": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø отлаГки не найГены. ДозГайте файл \"launch.json\"." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 7574689b0ef..63d876aca0d 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø Š“Š»Ń ŃŠ¾Š·Š“Š°Š½ŠøŃ ŠæŠµŃ€Š²Š¾Š½Š°Ń‡Š°Š»ŃŒŠ½Š¾Š³Š¾ файла launch.json.", "vscode.extension.contributes.debuggers.languages": "Дписок ŃŠ·Ń‹ŠŗŠ¾Š², Š“Š»Ń которых Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ отлаГки может ŃŃ‡ŠøŃ‚Š°Ń‚ŃŒŃŃ \"отлаГчиком по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ\".", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Если заГано, VS Code Š±ŃƒŠ“ŠµŃ‚ Š²Ń‹Š·Ń‹Š²Š°Ń‚ŃŒ эту команГу, чтобы Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ ŠæŃƒŃ‚ŃŒ Šŗ ŠøŃŠæŠ¾Š»Š½ŃŠµŠ¼Š¾Š¼Ńƒ Ń„Š°Š¹Š»Ńƒ аГаптера отлаГки Šø переГаваемые Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń‹.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Если заГано, VS Code Š±ŃƒŠ“ŠµŃ‚ Š²Ń‹Š·Ń‹Š²Š°Ń‚ŃŒ эту команГу Š“Š»Ń Гействий \"отлаГка\" или \"запуск\", преГназначенных Š“Š»Ń ŃŃ‚Š¾Š³Š¾ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ.", "vscode.extension.contributes.debuggers.configurationSnippets": "Фрагменты Š“Š»Ń Š“Š¾Š±Š°Š²Š»ŠµŠ½ŠøŃ новых ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠ¹ в launch.json.", "vscode.extension.contributes.debuggers.configurationAttributes": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø схемы JSON Š“Š»Ń проверки launch.json.", "vscode.extension.contributes.debuggers.windows": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹, ŃŠ²ŃŠ·Š°Š½Š½Ń‹Šµ с Windows.", diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index ee52447b162..24d857f0862 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -13,11 +13,10 @@ "compoundMustHaveConfigurations": "Š”Š»Ń составного ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š° Голжен Š±Ń‹Ń‚ŃŒ заГан Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚ configurations Š“Š»Ń запуска Š½ŠµŃŠŗŠ¾Š»ŃŒŠŗŠøŃ… ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠ¹.", "configMissing": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ \"{0}\" Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŠµŃ‚ в launch.json.", "debugTypeNotSupported": "ŠŠ°ŃŃ‚Ń€Š¾ŠµŠ½Š½Ń‹Š¹ тип отлаГки \"{0}\" не ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ.", - "debugTypeMissing": "ŠžŃ‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŠµŃ‚ свойство \"type\" Š“Š»Ń выбранной ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø запуска.", + "debugAnyway": "ŠŸŃ€ŠøŠ½ŃƒŠ“ŠøŃ‚ŠµŠ»ŃŒŠ½Š°Ń отлаГка", "preLaunchTaskErrors": "ŠŸŃ€Šø выполнении ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¹ заГачи \"{0}\" Š¾Š±Š½Š°Ń€ŃƒŠ¶ŠµŠ½Ń‹ ошибки.", "preLaunchTaskError": "ŠŸŃ€Šø выполнении ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¹ заГачи \"{0}\" Š¾Š±Š½Š°Ń€ŃƒŠ¶ŠµŠ½Š° ошибка.", "preLaunchTaskExitCode": "Выполнение ŠæŃ€ŠµŠ“Š²Š°Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¹ заГачи \"{0}\" Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š¾ с коГом выхоГа {1}.", - "debugAnyway": "ŠŸŃ€ŠøŠ½ŃƒŠ“ŠøŃ‚ŠµŠ»ŃŒŠ½Š°Ń отлаГка", "noFolderWorkspaceDebugError": "ŠŠµŠ»ŃŒŠ·Ń Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ Š¾Ń‚Š»Š°Š“ŠŗŃƒ активного файла. Š£Š±ŠµŠ“ŠøŃ‚ŠµŃŃŒ, что файл сохранен на Гиске Šø ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š¾ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ отлаГки Š“Š»Ń ŃŃ‚Š¾Š³Š¾ типа файла.", "NewLaunchConfig": "ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ файл ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø запуска Š“Š»Ń вашего ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ. {0}", "DebugTaskNotFound": "ŠŠµ уГалось найти Š·Š°Š“Š°Ń‡Ńƒ preLaunchTask \"{0}\"." diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 4c742d270df..c7556643f1a 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -7,6 +7,5 @@ "stateCapture": "Š”Š¾ŃŃ‚Š¾ŃŠ½ŠøŠµ Š¾Š±ŃŠŠµŠŗŃ‚Š° Š·Š°ŠæŠøŃŃ‹Š²Š°ŠµŃ‚ŃŃ после первого Š²Ń‹Ń‡ŠøŃŠ»ŠµŠ½ŠøŃ", "replVariableAriaLabel": "ŠŸŠµŃ€ŠµŠ¼ŠµŠ½Š½Š°Ń \"{0}\" имеет значение \"{1}\", read–eval–print loop, отлаГка", "replExpressionAriaLabel": "Выражение \"{0}\" имеет значение \"{1}\", read–eval–print loop, отлаГка", - "replValueOutputAriaLabel": "{0}, read–eval–print loop, отлаГка", - "replKeyValueOutputAriaLabel": "Š’Ń‹Ń…Š¾Š“Š½Š°Ń ŠæŠµŃ€ŠµŠ¼ŠµŠ½Š½Š°Ń \"{0}\" имеет значение \"{1}\", read–eval–print loop, отлаГка" + "replValueOutputAriaLabel": "{0}, read–eval–print loop, отлаГка" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json index bf63a86ed4a..775b1ec66d2 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "statusBarDebuggingBackground": "Цвет фона панели ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ при отлаГке программы. Панель ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ показана внизу окна.", - "statusBarDebuggingForeground": "Цвет переГнего плана строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ при отлаГке программы. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ расположена в нижней части окна." + "statusBarDebuggingForeground": "Цвет переГнего плана строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ при отлаГке программы. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ расположена в нижней части окна.", + "statusBarDebuggingBorder": "Цвет границы строки ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ, который Ń€Š°ŃŠæŃ€Š¾ŃŃ‚Ń€Š°Š½ŃŠµŃ‚ŃŃ на Š±Š¾ŠŗŠ¾Š²ŃƒŃŽ панель Šø реГактор при отлаГке программы. Дтрока ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ расположена в нижней части окна." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 109e9178c2d..fc11e0ac507 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "Š˜ŃŠæŠ¾Š»Š½ŃŠµŠ¼Ń‹Š¹ файл аГаптера отлаГки \"{0}\" не ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚.", "debugAdapterCannotDetermineExecutable": "ŠŠµŠ²Š¾Š·Š¼Š¾Š¶Š½Š¾ Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ ŠøŃŠæŠ¾Š»Š½ŃŠµŠ¼Ń‹Š¹ файл Š“Š»Ń аГаптера отлаГки \"{0}\".", + "launch.config.comment1": "Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ IntelliSense, чтобы ŃƒŠ·Š½Š°Ń‚ŃŒ о возможных Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š°Ń….", + "launch.config.comment2": "ŠŠ°Š²ŠµŠ“ŠøŃ‚Šµ ŃƒŠŗŠ°Š·Š°Ń‚ŠµŠ»ŃŒ Š¼Ń‹ŃˆŠø, чтобы ŠæŃ€Š¾ŃŠ¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ Š¾ŠæŠøŃŠ°Š½ŠøŃ ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŃŽŃ‰ŠøŃ… Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š¾Š².", + "launch.config.comment3": "Š”Š»Ń ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŃ Š“Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¹ информации посетите: {0}", "debugType": "Тип ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø.", "debugTypeNotRecognised": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Ń€Š°ŃŠæŠ¾Š·Š½Š°Ń‚ŃŒ тип отлаГки. Š£Š±ŠµŠ“ŠøŃ‚ŠµŃŃŒ, что ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠµŠµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ отлаГки ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š¾ Šø Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Š¾.", "node2NotSupported": "Значение \"node2\" больше не ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ; ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ \"node\" Šø заГайте Š“Š»Ń Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š° \"protocol\" значение \"inspector\".", diff --git a/i18n/rus/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json index 5d0c8aac610..4671a2c1d23 100644 --- a/i18n/rus/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/execution/electron-browser/execution.contribution.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "terminalConfigurationTitle": "Š’Š½ŠµŃˆŠ½ŠøŠ¹ терминал", + "explorer.openInTerminalKind": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ тип терминала, который ŃŠ»ŠµŠ“ŃƒŠµŃ‚ Š·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ.", "terminal.external.windowsExec": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° терминала, который Š±ŃƒŠ“ет Š·Š°ŠæŃƒŃ‰ŠµŠ½ в Windows.", "terminal.external.osxExec": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ терминала Š“Š»Ń запуска в OS X.", "terminal.external.linuxExec": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° терминала Š“Š»Ń запуска в Linux.", diff --git a/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 87974585442..00a5bd00b41 100644 --- a/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€", "view name": "Š˜Š¼Ń", "view location": "ГГе", - "themes": "Темы ({0})", + "colorThemes": "Цветовые темы ({0})", + "iconThemes": "Темы значков ({0})", + "colors": "Цвета ({0})", + "colorId": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€", + "defaultDark": "Š¢ŠµŠ¼Š½Š°Ń по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", + "defaultLight": "Š”Š²ŠµŃ‚Š»Š°Ń по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", + "defaultHC": "Š” высоким контрастом по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", "JSON Validation": "ŠŸŃ€Š¾Š²ŠµŃ€ŠŗŠ° JSON ({0})", "commands": "ŠšŠ¾Š¼Š°Š½Š“Ń‹ ({0})", "command name": "Š˜Š¼Ń", diff --git a/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index b01a2493859..321eafa78fd 100644 --- a/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,23 +34,24 @@ "postDisableMessage": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ ŃŃ‚Š¾ окно, чтобы Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ \"{0}\"?", "postUninstallTooltip": "ŠŸŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠŗŠ° Š“Š»Ń Геактивации", "postUninstallMessage": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ ŃŃ‚Š¾ окно, чтобы Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ уГаленное Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ \"{0}\"?", - "reload": "&&ŠŸŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ окно", "toggleExtensionsViewlet": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", "installExtensions": "Š£ŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", + "showEnabledExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Š½Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", "showInstalledExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", "showDisabledExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½Š½Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", "clearExtensionsInput": "ŠžŃ‡ŠøŃŃ‚ŠøŃ‚ŃŒ вхоГные Ганные Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹", "showOutdatedExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", "showPopularExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŠ¾ŠæŃƒŠ»ŃŃ€Š½Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", "showRecommendedExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŠ¼Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", - "showWorkspaceRecommendedExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŠ¼Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ рабочей области", "showRecommendedKeymapExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŠ¼Ń‹Šµ расклаГки ŠŗŠ»Š°Š²ŠøŠ°Ń‚ŃƒŃ€Ń‹", "showRecommendedKeymapExtensionsShort": "РасклаГки ŠŗŠ»Š°Š²ŠøŠ°Ń‚ŃƒŃ€Ń‹", "showLanguageExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ ŃŠ·Ń‹ŠŗŠ°", "showLanguageExtensionsShort": "Š Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ ŃŠ·Ń‹ŠŗŠ°", - "configureWorkspaceRecommendedExtensions": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŠ¼Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ (Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ)", - "ConfigureWorkspaceRecommendations.noWorkspace": "РекоменГации Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹ Ń‚Š¾Š»ŃŒŠŗŠ¾ Š“Š»Ń папки рабочей области.", + "showAzureExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Azure", + "showAzureExtensionsShort": "Š Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Azure", "OpenExtensionsFile.failed": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ ŃŠ¾Š·Š“Š°Ń‚ŃŒ файл \"extensions.json\" в папке \".vscode\" ({0}).", + "configureWorkspaceRecommendedExtensions": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŠ¼Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ (Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ)", + "configureWorkspaceFolderRecommendedExtensions": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŠ¼Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ (папка рабочей области)", "builtin": "Встроенное", "disableAll": "ŠžŃ‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ все ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ", "disableAllWorkspace": "ŠžŃ‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ все ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń‹Šµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Š“Š»Ń ŃŃ‚Š¾Š¹ рабочей области", diff --git a/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..7c1105b7ad4 --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "РекоменГуемое" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index e02b293c576..49881279b56 100644 --- a/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "reallyRecommended2": "Š”Š»Ń ŃŃ‚Š¾Š³Š¾ типа файлов Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŃ‚ŃŃ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ '{0}'.", + "reallyRecommendedExtensionPack": "Š”Š»Ń ŃŃ‚Š¾Š³Š¾ типа файлов Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŃ‚ŃŃ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ пакет Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹ '{0}'.", "showRecommendations": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ рекоменГации", + "install": "Š£ŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ", "neverShowAgain": "Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", "close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", "workspaceRecommended": "Эта Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ Š²ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ рекоменГации по Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃŠ¼.", diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index 61dde35c093..821930bfc87 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Файлы", - "revealInSideBar": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ в боковой панели" + "filesCategory": "Файл", + "revealInSideBar": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ в боковой панели", + "acceptLocalChanges": "Š˜ŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Šø ŠæŠµŃ€ŠµŠ·Š°ŠæŠøŃŠ°Ń‚ŃŒ соГержимое Гиска", + "revertLocalChanges": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Šø Š²ŠµŃ€Š½ŃƒŃ‚ŃŒŃŃ Šŗ ŃŠ¾Š“ŠµŃ€Š¶ŠøŠ¼Š¾Š¼Ńƒ на Гиске" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json index eab30252ca8..742697232e5 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -37,17 +37,14 @@ "openToSide": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ сбоку", "compareSource": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ Š“Š»Ń ŃŃ€Š°Š²Š½ŠµŠ½ŠøŃ", "globalCompareFile": "Š”Ń€Š°Š²Š½ŠøŃ‚ŃŒ активный файл с...", - "pickHistory": "Выберите ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠøŠ¹ открытый файл Š“Š»Ń ŃŃ€Š°Š²Š½ŠµŠ½ŠøŃ.", - "unableToFileToCompare": "Выбранный файл Š½ŠµŠ»ŃŒŠ·Ń ŃŃ€Š°Š²Š½ŠøŃ‚ŃŒ с \"{0}\".", "openFileToCompare": "Чтобы ŃŃ€Š°Š²Š½ŠøŃ‚ŃŒ файл с Š“Ń€ŃƒŠ³ŠøŠ¼ файлом, сначала откройте его.", - "compareWith": "Š”Ń€Š°Š²Š½ŠøŃ‚ŃŒ с \"{0}\"", + "compareWith": "Š”Ń€Š°Š²Š½ŠøŃ‚ŃŒ '{0}' с '{1}'", "compareFiles": "Š”Ń€Š°Š²Š½ŠøŃ‚ŃŒ файлы", "refresh": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ", "save": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ", "saveAs": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ как...", "saveAll": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ все", "saveAllInGroup": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ все в Š³Ń€ŃƒŠæŠæŠµ", - "saveFiles": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ файлы с ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃŠ¼Šø", "revert": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в файле", "focusOpenEditors": "Фокус на преГставлении открытых реГакторов", "focusFilesExplorer": "Фокус на провоГнике", @@ -55,7 +52,6 @@ "openFileToShow": "Дначала откройте файл Š“Š»Ń Š¾Ń‚Š¾Š±Ń€Š°Š¶ŠµŠ½ŠøŃ в обозревателе.", "collapseExplorerFolders": "Š”Š²ŠµŃ€Š½ŃƒŃ‚ŃŒ папки в провоГнике", "refreshExplorer": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ окно провоГника", - "openFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл...", "openFileInNewWindow": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ активный файл в новом окне", "openFileToShowInNewWindow": "Чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ файл в новом окне, сначала откройте его.", "revealInWindows": "ŠžŃ‚Š¾Š±Ń€Š°Š·ŠøŃ‚ŃŒ в провоГнике", @@ -69,5 +65,7 @@ "emptyFileNameError": "ŠŠµŠ¾Š±Ń…Š¾Š“ŠøŠ¼Š¾ ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ ŠøŠ¼Ń файла или папки.", "fileNameExistsError": "Файл или папка **{0}** уже ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚ в Ганном расположении. Выберите Š“Ń€ŃƒŠ³Š¾Šµ ŠøŠ¼Ń.", "invalidFileNameError": "Š˜Š¼Ń **{0}** Š½ŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š¾ Š“Š»Ń файла или папки. Выберите Š“Ń€ŃƒŠ³Š¾Šµ ŠøŠ¼Ń.", - "filePathTooLongError": "Из-за ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ имени **{0}** ŠæŃƒŃ‚ŃŒ слишком Глинный. Выберите более короткое ŠøŠ¼Ń." + "filePathTooLongError": "Из-за ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ имени **{0}** ŠæŃƒŃ‚ŃŒ слишком Глинный. Выберите более короткое ŠøŠ¼Ń.", + "compareWithSaved": "Š”Ń€Š°Š²Š½ŠøŃ‚ŃŒ активный файл с сохраненным", + "modifiedLabel": "{0} (на Гиске) ↔ {1}" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index e3d342df049..7f5602d1266 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "РеГактор текстовых файлов", "binaryFileEditor": "РеГактор Гвоичных файлов", "filesConfigurationTitle": "Файлы", - "exclude": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° станГартных масок Š“Š»Ń ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ файлов Šø папок.", + "exclude": "ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ станГартные маски Š“Š»Ń ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ файлов Šø папок. Этот параметр Š²Š»ŠøŃŠµŃ‚, например, на скрытые Šø отображаемые файлы в провоГнике.", "files.exclude.boolean": "Š”Ń‚Š°Š½Š“Š°Ń€Ń‚Š½Š°Ń маска, ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰Š°Ń ŠæŃƒŃ‚ŃŠ¼ Šŗ файлам. ЗаГайте значение true или false, чтобы Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ маску.", "files.exclude.when": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Š°Ń проверка ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² того же ŃƒŃ€Š¾Š²Š½Ń ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠµŠ³Š¾ файла. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ $(basename) в качестве переменной Š“Š»Ń ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠµŠ³Š¾ имени файла.", "associations": "ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ ŃŠ¾ŠæŠ¾ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ файлов с ŃŠ·Ń‹ŠŗŠ°Š¼Šø (например, \"*.extension\": \"html\"). Š£ них Š±ŃƒŠ“ŠµŃ‚ приоритет переГ заГанными по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ ŃŠ¾ŠæŠ¾ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃŠ¼Šø ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń‹Ń… ŃŠ·Ń‹ŠŗŠ¾Š².", - "encoding": "ŠšŠ¾Š“ŠøŃ€Š¾Š²ŠŗŠ° набора символов по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Š°Ń при чтении Šø записи файлов", - "autoGuessEncoding": "Если параметр Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½, ŠæŃ€Š¾ŠøŠ·Š²Š¾Š“ŠøŃ‚ŃŃ попытка Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ ŠŗŠ¾Š“ŠøŃ€Š¾Š²ŠŗŃƒ набора символов при открытии файлов", + "encoding": "ŠšŠ¾Š“ŠøŃ€Š¾Š²ŠŗŠ° по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Š°Ń при чтении Šø записи файлов. Этот параметр также можно Š½Š°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š“Š»Ń Š¾Ń‚Š“ŠµŠ»ŃŒŠ½Ń‹Ń… ŃŠ·Ń‹ŠŗŠ¾Š².", + "autoGuessEncoding": "Если ŃŃ‚Š¾Ń‚ параметр ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½, то при открытии файла Š±ŃƒŠ“ет ŠæŃ€ŠµŠ“ŠæŃ€ŠøŠ½ŃŃ‚Š° попытка Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ ŠŗŠ¾Š“ŠøŃ€Š¾Š²ŠŗŃƒ символов. Этот параметр также можно Š½Š°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š“Š»Ń Š¾Ń‚Š“ŠµŠ»ŃŒŠ½Ń‹Ń… ŃŠ·Ń‹ŠŗŠ¾Š².", "eol": "Димвол конца строки по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ \\n Š“Š»Ń LF Šø \\r\\n Š“Š»Ń CRLF.", "trimTrailingWhitespace": "Если ŃŃ‚Š¾Ń‚ параметр Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½, при сохранении файла Š±ŃƒŠ“ŃƒŃ‚ ŃƒŠ“Š°Š»ŠµŠ½Ń‹ концевые пробелы.", "insertFinalNewline": "Если ŃŃ‚Š¾Ń‚ параметр Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½, при сохранении файла в его конец Š²ŃŃ‚Š°Š²Š»ŃŠµŃ‚ŃŃ Ń„ŠøŠ½Š°Š»ŃŒŠ½Š°Ń Š½Š¾Š²Š°Ń строка.", + "trimFinalNewlines": "Если ŃŃ‚Š¾Ń‚ параметр ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½, то при сохранении файла Š±ŃƒŠ“ŃƒŃ‚ ŃƒŠ“Š°Š»ŠµŠ½Ń‹ все новые строки за послеГней новой строкой в конце файла.", "files.autoSave.off": "\"Š“Ń€ŃŠ·Š½Ń‹Š¹\" файл не ŃŠ¾Ń…Ń€Š°Š½ŃŠµŃ‚ŃŃ автоматически.", "files.autoSave.afterDelay": "\"Š“Ń€ŃŠ·Š½Ń‹Š¹\" файл автоматически ŃŠ¾Ń…Ń€Š°Š½ŃŠµŃ‚ŃŃ по истечении срока \"files.autoSaveDelay\".", "files.autoSave.onFocusChange": "\"Š“Ń€ŃŠ·Š½Ń‹Š¹\" файл автоматически ŃŠ¾Ń…Ń€Š°Š½ŃŠµŃ‚ŃŃ при потере Ń„Š¾ŠŗŃƒŃŠ° реГактором.", @@ -38,5 +39,11 @@ "openEditorsVisible": "Число реГакторов, отображаемых на панели открытых реГакторов. ЗаГайте значение 0, чтобы ŃŠŗŃ€Ń‹Ń‚ŃŒ панель.", "dynamicHeight": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли высота разГела открытых реГакторов Гинамически Š°Š“Š°ŠæŃ‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒŃŃ Šŗ ŠŗŠ¾Š»ŠøŃ‡ŠµŃŃ‚Š²Ńƒ ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š².", "autoReveal": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŠµŃ‚ ли провоГник автоматически Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ Šø Š²Ń‹Š±ŠøŃ€Š°Ń‚ŃŒ файлы при ŠøŃ… открытии.", - "enableDragAndDrop": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Ń€Š°Š·Ń€ŠµŃˆŠµŠ½Š¾ ли перемещение файлов Šø папок перетаскиванием в провоГнике." + "enableDragAndDrop": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Ń€Š°Š·Ń€ŠµŃˆŠµŠ½Š¾ ли перемещение файлов Šø папок перетаскиванием в провоГнике.", + "sortOrder.default": "Файлы Šø папки ŃŠ¾Ń€Ń‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ по именам в алфавитном ŠæŠ¾Ń€ŃŠ“ŠŗŠµ. Папки Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ переГ файлами.", + "sortOrder.mixed": "Файлы Šø папки ŃŠ¾Ń€Ń‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ по именам в алфавитном ŠæŠ¾Ń€ŃŠ“ŠŗŠµ. Файлы Ń‡ŠµŃ€ŠµŠ“ŃƒŃŽŃ‚ŃŃ с папками.", + "sortOrder.filesFirst": "Файлы Šø папки ŃŠ¾Ń€Ń‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ по именам в алфавитном ŠæŠ¾Ń€ŃŠ“ŠŗŠµ. Файлы Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ переГ папками. ", + "sortOrder.type": "Файлы Šø папки ŃŠ¾Ń€Ń‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ по Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃŠ¼ в алфавитном ŠæŠ¾Ń€ŃŠ“ŠŗŠµ. Папки Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ переГ файлами.", + "sortOrder.modified": "Файлы Šø папки ŃŠ¾Ń€Ń‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ по Гате послеГнего ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ в ŠæŠ¾Ń€ŃŠ“ŠŗŠµ ŃƒŠ±Ń‹Š²Š°Š½ŠøŃ. Папки Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŃŽŃ‚ŃŃ переГ файлами.", + "sortOrder": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ ŠæŠ¾Ń€ŃŠ“ŠŗŠ¾Š¼ сортировки файлов Šø папок в провоГнике. ŠŠ°Ń€ŃŠ“Ńƒ с сортировкой по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ можно ŃƒŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠµ варианты сортировки: 'mixed' (файлы Šø папки ŃŠ¾Ń€Ń‚ŠøŃ€ŃƒŃŽŃ‚ŃŃ вместе), 'type' (по Ń‚ŠøŠæŃƒ файла), 'modified' (по Гате послеГнего ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ) Šø 'filesFirst' (ŃŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ файлы переГ папками)." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 990a276ce35..d5622eec39a 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ команГы на панели ŠøŠ½ŃŃ‚Ń€ŃƒŠ¼ŠµŠ½Ń‚Š¾Š² реГактора справа Š“Š»Ń **отмены** изменений или **перезаписи** соГержимого на Гиске с ŃƒŃ‡ŠµŃ‚Š¾Š¼ ŃŃ‚ŠøŃ… изменений", "discard": "ŠžŃ‚Š¼ŠµŠ½Š°", "overwrite": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŠøŃŠ°Ń‚ŃŒ", "retry": "ŠŸŠ¾Š²Ń‚Š¾Ń€ŠøŃ‚ŃŒ ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ", diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index 5eb9bd6927b..5c9b67b2669 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,6 @@ { "noWorkspace": "ŠŠµŃ‚ открытой папки", "explorerSection": "РазГел провоГника", - "noWorkspaceHelp": "Š’Ń‹ еще не открыли папку.", + "noFolderHelp": "Š’Ń‹ еще не открыли папку.", "openFolder": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ папку" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..64dac8b7abc --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "ŠŸŃ€Š¾Š²Š¾Š“Š½ŠøŠŗ" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 21887e5d781..af609366aa5 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,10 @@ { "fileInputAriaLabel": "ВвеГите ŠøŠ¼Ń файла. ŠŠ°Š¶Š¼ŠøŃ‚Šµ клавишу Š’Š’ŠžŠ”, чтобы ŠæŠ¾Š“Ń‚Š²ŠµŃ€Š“ŠøŃ‚ŃŒ ввеГенные Ганные, или ESCAPE Š“Š»Ń отмены.", "filesExplorerViewerAriaLabel": "{0}, ŠŸŃ€Š¾Š²Š¾Š“Š½ŠøŠŗ", + "dropFolders": "Š’Ń‹ хотите Š“Š¾Š±Š°Š²ŠøŃ‚ŃŒ папки в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ?", + "dropFolder": "Š’Ń‹ хотите Š“Š¾Š±Š°Š²ŠøŃ‚ŃŒ папку в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ?", + "addFolders": "&&Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ папки", + "addFolder": "&&Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ папку", "confirmOverwriteMessage": "{0} уже ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚ в целевой папке. Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ его?", "irreversible": "Это Гействие необратимо!", "replaceButtonLabel": "&&Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ" diff --git a/i18n/rus/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json b/i18n/rus/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json index 73ddd2e2b05..863c0a79ec8 100644 --- a/i18n/rus/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/browser/views/openEditorsViewer.i18n.json @@ -9,6 +9,7 @@ "saveAll": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ все", "closeAllUnmodified": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ без изменений", "closeAll": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ все", + "compareWithSaved": "Š”Ń€Š°Š²Š½ŠøŃ‚ŃŒ с сохраненным", "close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", "closeOthers": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ Š“Ń€ŃƒŠ³ŠøŠµ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/rus/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 83ec78cab1e..b2007310ead 100644 --- a/i18n/rus/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 несохраненный файл", "dirtyFiles": "ŠŠµŃŠ¾Ń…Ń€Š°Š½ŠµŠ½Š½Ń‹Ń… файлов: {0}" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/rus/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..1ffd1cf8897 --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "ŠŸŃ€Š¾Š±Š»ŠµŠ¼Ń‹" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index c5024f1f1d0..e53e26469ea 100644 --- a/i18n/rus/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "ŠžŠ±Š½Š°Ń€ŃƒŠ¶ŠµŠ½ замеГленный запуск.", - "slow.detail": "Дожалеем, что у вас ŠæŃ€Š¾ŠøŠ·Š¾ŃˆŠµŠ» замеГленный запуск. ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚Šµ \"{0}\" с Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Š½Ń‹Š¼ профилированием Šø Š¾Ń‚ŠæŃ€Š°Š²ŃŒŃ‚Šµ профили нам, чтобы мы могли ŃƒŃŠŗŠ¾Ń€ŠøŃ‚ŃŒ Š·Š°Š³Ń€ŃƒŠ·ŠŗŃƒ.", "prof.message": "ŠŸŃ€Š¾Ń„ŠøŠ»Šø успешно созГаны.", "prof.detail": "ДозГайте ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ Šø Š²Ń€ŃƒŃ‡Š½ŃƒŃŽ вложите ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠµ файлы:\n{0}", "prof.restartAndFileIssue": "Š”Š¾Š·Š“Š°Ń‚ŃŒ ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ Šø Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗ", diff --git a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index b82ad2f758e..db8d5850260 100644 --- a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -8,6 +8,7 @@ "openGlobalKeybindings": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ ŃŠ¾Ń‡ŠµŃ‚Š°Š½ŠøŃ клавиш", "openGlobalKeybindingsFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл сочетаний клавиш", "openWorkspaceSettings": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ параметры рабочей области", + "openFolderSettings": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ параметры папок", "configureLanguageBasedSettings": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ параметры ŃŠ·Ń‹ŠŗŠ°...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ ŃŠ·Ń‹Šŗ" diff --git a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index dd141cde1c5..6a867369b14 100644 --- a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorInvalidConfiguration": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры. Устраните ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ в файле Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "emptyUserSettingsHeader": "Укажите параметры зГесь, чтобы ŠæŠµŃ€ŠµŠ·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ.", + "emptyWorkspaceSettingsHeader": "Укажите параметры зГесь, чтобы ŠæŠµŃ€ŠµŠ·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŠµŠ¹.", + "emptyFolderSettingsHeader": "Укажите параметры папок зГесь, чтобы ŠæŠµŃ€ŠµŠ·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры рабочих областей.", + "defaultFolderSettingsTitle": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ папок по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", "defaultSettingsTitle": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", - "noSettingsFound": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ не найГены.", "editTtile": "Š˜Š·Š¼ŠµŠ½ŠøŃ‚ŃŒ", "replaceDefaultValue": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ в параметрах", "copyDefaultValue": "ŠšŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ в параметры", "unsupportedPHPExecutablePathSetting": "Этот параметр Голжен Š±Ń‹Ń‚ŃŒ параметром ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń. Чтобы Š½Š°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ в рабочей области PHP, откройте PHP-файл Šø щелкните \"ŠŸŃƒŃ‚ŃŒ PHP\" в строке ŃŠ¾ŃŃ‚Š¾ŃŠ½ŠøŃ.", - "unsupportedWorkspaceSetting": "Этот параметр Голжен Š±Ń‹Ń‚ŃŒ параметром ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń." + "unsupportedWorkspaceSetting": "Этот параметр Голжен Š±Ń‹Ń‚ŃŒ параметром ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń.", + "unsupportedWorkbenchSetting": "Дейчас ŠæŃ€ŠøŠ¼ŠµŠ½ŠøŃ‚ŃŒ ŃŃ‚Š¾Ń‚ параметр Š½ŠµŠ»ŃŒŠ·Ń. ŠžŠ½ Š±ŃƒŠ“ŠµŃ‚ применен, когГа вы откроете эту папку Š½Š°ŠæŃ€ŃŠ¼ŃƒŃŽ." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json index d90a4e6c80b..870d1342665 100644 --- a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesService.i18n.json @@ -7,5 +7,6 @@ "openFolderFirst": "Чтобы ŃŠ¾Š·Š“Š°Ń‚ŃŒ параметры рабочей области, сначала откройте папку", "emptyKeybindingsHeader": "ŠŸŠ¾Š¼ŠµŃŃ‚ŠøŃ‚Šµ настраиваемые ŃŠ¾Ń‡ŠµŃ‚Š°Š½ŠøŃ клавиш в ŃŃ‚Š¾Ń‚ файл, чтобы ŠæŠµŃ€ŠµŠ·Š°ŠæŠøŃŠ°Ń‚ŃŒ клавиши по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ.", "defaultKeybindings": "ŠŠ°ŃŃ‚Ń€Š°ŠøŠ²Š°ŠµŠ¼Ń‹Šµ ŃŠ¾Ń‡ŠµŃ‚Š°Š½ŠøŃ клавиш по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", + "folderSettingsName": "{0} (ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ папок)", "fail.createSettings": "ŠŠµŠ²Š¾Š·Š¼Š¾Š¶Š½Š¾ ŃŠ¾Š·Š“Š°Ń‚ŃŒ \"{0}\" ({1})." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 8b6ad71cd4e..d17cc5fa1fe 100644 --- a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "noSettingsFound": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ не найГены.", + "folderSettingsDetails": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ папок" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/rus/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index 1eec3215d51..3305d6aa84d 100644 --- a/i18n/rus/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "Часто ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Šµ", - "noSettings": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚", "defaultKeybindingsHeader": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŠøŃˆŠøŃ‚Šµ настраиваемое сочетание клавиш, поместив ŠøŃ… в файл настраиваемых сочетаний клавиш." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index 631ee068c6b..a7528085d74 100644 --- a/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "КоманГа {0} не Ń€Š°Š·Ń€ŠµŃˆŠµŠ½Š° в Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¼ контексте.", "recentlyUsed": "неГавно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½Š½Ń‹Šµ", "morecCommands": "Š“Ń€ŃƒŠ³ŠøŠµ команГы", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "ŠŠµŃ‚ ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠøŃ… команГ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 155d4022b8e..3e5d8e50bd2 100644 --- a/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -5,7 +5,5 @@ // Do not edit this file. It is machine generated. { "relaunchSettingMessage": "После ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ параметра необхоГима Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ ŠæŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠŗŃƒ, чтобы ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ Š²ŃŃ‚ŃƒŠæŠøŠ»Šø в силу.", - "relaunchSettingDetail": "ŠŠ°Š¶Š¼ŠøŃ‚Šµ кнопку \"ŠŸŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ\", чтобы ŠæŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ {0} Šø Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ параметр.", - "restart": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ", - "reload": "ŠŸŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠŗŠ°" + "relaunchSettingDetail": "ŠŠ°Š¶Š¼ŠøŃ‚Šµ кнопку \"ŠŸŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ\", чтобы ŠæŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ {0} Šø Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ параметр." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/rus/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index ce6c4c198e5..5e4642ba704 100644 --- a/i18n/rus/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -6,5 +6,8 @@ { "editorGutterModifiedBackground": "Цвет фона полей реГактора Š“Š»Ń измененных строк.", "editorGutterAddedBackground": "Цвет фона полей реГактора Š“Š»Ń Гобавленных строк.", - "editorGutterDeletedBackground": "Цвет фона полей реГактора Š“Š»Ń ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Ń… строк." + "editorGutterDeletedBackground": "Цвет фона полей реГактора Š“Š»Ń ŃƒŠ“Š°Š»ŠµŠ½Š½Ń‹Ń… строк.", + "overviewRulerModifiedForeground": "Цвет метки линейки в окне просмотра Š“Š»Ń измененного соГержимого.", + "overviewRulerAddedForeground": "Цвет метки линейки в окне просмотра Š“Š»Ń Гобавленного соГержимого. ", + "overviewRulerDeletedForeground": "Цвет метки линейки в окне просмотра Š“Š»Ń уГаленного соГержимого. " } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index ba48b09e263..029a91dd121 100644 --- a/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ GIT", - "installAdditionalSCMProviders": "Š£ŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ Š“Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Ń… поставщиков SCM...", "source control": "Дистема ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø", "toggleSCMViewlet": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ SCM", "view": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ" diff --git a/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 9e37c37510e..d61548e8be2 100644 --- a/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "ŠŸŠ¾ŃŃ‚Š°Š²Ń‰ŠøŠŗŠø систем ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø", + "hideRepository": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ", "commitMessage": "Message (press {0} to commit)", + "installAdditionalSCMProviders": "Š£ŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ Š“Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Ń… поставщиков SCM...", + "no open repo": "ŠžŃ‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚ активные поставщики систем ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø.", "source control": "Дистема ŃƒŠæŃ€Š°Š²Š»ŠµŠ½ŠøŃ Š²ŠµŃ€ŃŠøŃŠ¼Šø", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index a7795c75dba..5ce1c60d270 100644 --- a/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ символу в рабочей области...", "name": "Поиск", - "showSearchViewlet": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ среГство поиска", + "search": "Поиск", "view": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€", - "findInFiles": "ŠŠ°Š¹Ń‚Šø в файлах", "openAnythingHandlerDescription": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ Ń„Š°Š¹Š»Ńƒ", "openSymbolDescriptionNormal": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ символу в рабочей области", "searchOutputChannelTitle": "Поиск", @@ -16,7 +15,5 @@ "exclude": "ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ станГартные маски Š“Š»Ń ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ файлов Šø папок при поиске. Все станГартные маски Š½Š°ŃŠ»ŠµŠ“ŃƒŃŽŃ‚ŃŃ от параметра file.exclude.", "exclude.boolean": "Š”Ń‚Š°Š½Š“Š°Ń€Ń‚Š½Š°Ń маска, ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰Š°Ń ŠæŃƒŃ‚ŃŠ¼ Šŗ файлам. ЗаГайте значение true или false, чтобы Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ или Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ маску.", "exclude.when": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Š°Ń проверка ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š² того же ŃƒŃ€Š¾Š²Š½Ń ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠµŠ³Š¾ файла. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ $(basename) в качестве переменной Š“Š»Ń ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠµŠ³Š¾ имени файла.", - "useRipgrep": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ли ripgrep в текстовом поиске", - "useIgnoreFilesByDefault": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ли ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ GITIGNORE- Šø IGNORE-файлы по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ при поиске в новой рабочей области.", "search.quickOpen.includeSymbols": "ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ Š“Š»Ń Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š² поиска Š³Š»Š¾Š±Š°Š»ŃŒŠ½Ń‹Ń… символов в файлы по Š·Š°ŠæŃ€Š¾ŃŃƒ Š“Š»Ń Quick Open." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json index e5f21d40d06..544b826c68e 100644 --- a/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -4,16 +4,23 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "nextSearchIncludePattern": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠ¹ шаблон Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ в поиск", + "previousSearchIncludePattern": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠøŠ¹ шаблон Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ в поиск ", + "nextSearchExcludePattern": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠ¹ шаблон ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ ŠøŠ· поиска", + "previousSearchExcludePattern": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠøŠ¹ шаблон ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ ŠøŠ· поиска", "nextSearchTerm": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠµ условие поиска", "previousSearchTerm": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠµ условие поиска", "focusNextInputBox": "Фокус на ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼ поле ввоГа", "focusPreviousInputBox": "Фокус на ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ¼ поле ввоГа", + "showSearchViewlet": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ среГство поиска", + "findInFiles": "ŠŠ°Š¹Ń‚Šø в файлах", "replaceInFiles": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ в файлах", + "findInWorkspace": "ŠŠ°Š¹Ń‚Šø в рабочей области...", + "findInFolder": "ŠŠ°Š¹Ń‚Šø в папке...", "RefreshAction.label": "ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ", "ClearSearchResultsAction.label": "ŠžŃ‡ŠøŃŃ‚ŠøŃ‚ŃŒ Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń‹ поиска", "FocusNextSearchResult.label": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼Ńƒ Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ńƒ поиска.", "FocusPreviousSearchResult.label": "ŠŸŠµŃ€ŠµŠ¹Ń‚Šø Šŗ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ¼Ńƒ Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ńƒ поиска.", - "RemoveAction.label": "Š£Š“Š°Š»ŠøŃ‚ŃŒ", "file.replaceAll.label": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ все", "match.replace.label": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json b/i18n/rus/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json index cd394a2c256..9d483c5df77 100644 --- a/i18n/rus/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/search/browser/searchResultsView.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "searchFolderMatch.other.label": "Š”Ń€ŃƒŠ³ŠøŠµ файлы", + "searchFileMatches": "ŠŠ°Š¹Š“ŠµŠ½Š¾ файлов: {0}", + "searchFileMatch": "ŠŠ°Š¹Š“ŠµŠ½ {0} файл", "searchMatches": "ŠŠ°Š¹Š“ŠµŠ½Š¾ соответствий: {0}", "searchMatch": "ŠŠ°Š¹Š“ŠµŠ½Š¾ соответствие: {0}", + "folderMatchAriaLabel": "ДовпаГений в корневой папке {1}: {0}, Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚ поиска", "fileMatchAriaLabel": "ДовпаГений в файле {1} папки {2}: {0}, Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚ поиска", "replacePreviewResultAria": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ термин {0} на {1} в столбце {2} Šø строке {3}", "searchResultAria": "ŠžŠ±Š½Š°Ń€ŃƒŠ¶ŠµŠ½ термин {0} в столбце {1} Šø строке {2}" diff --git a/i18n/rus/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/rus/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 39d234e38ac..1359328df0c 100644 --- a/i18n/rus/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -28,15 +28,17 @@ "removeAll.occurrences.files.confirmation.message": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ Š²Ń…Š¾Š¶Š“ŠµŠ½ŠøŃ ({0}) на \"{2}\" в ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼ числе файлов: {1}?", "replaceAll.occurrences.files.confirmation.message": "Š—Š°Š¼ŠµŠ½ŠøŃ‚ŃŒ Š²Ń…Š¾Š¶Š“ŠµŠ½ŠøŃ ({0}) в ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼ числе файлов: {1}?", "treeAriaLabel": "Š ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń‹ поиска", + "searchPathNotFoundError": "ŠŸŃƒŃ‚ŃŒ поиска не найГен: {0}", "searchMaxResultsWarning": "Š ŠµŠ·ŃƒŠ»ŃŒŃ‚ŠøŃ€ŃƒŃŽŃ‰ŠøŠ¹ набор Š²ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ Ń‚Š¾Š»ŃŒŠŗŠ¾ поГмножество всех соответствий. Чтобы ŃƒŠ¼ŠµŠ½ŃŒŃˆŠøŃ‚ŃŒ число Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š², ŃŃƒŠ·ŃŒŃ‚Šµ ŃƒŃŠ»Š¾Š²ŠøŃ поиска.", "searchCanceled": "Поиск был отменен Го того, как были найГены какие-либо Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń‹ — ", "noResultsIncludesExcludes": "ŠŠµ найГено Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š² в \"{0}\", ŠøŃŠŗŠ»ŃŽŃ‡Š°Ń \"{1}\", — ", "noResultsIncludes": "Š ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń‹ в \"{0}\" не найГены — ", "noResultsExcludes": "Š ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń‹ не найГены за ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠµŠ¼ \"{0}\" — ", - "noResultsFound": "Š ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń‹ не найГены. ŠŸŃ€Š¾Š²ŠµŃ€ŃŒŃ‚Šµ параметры настроенных ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠ¹ — ", + "noResultsFound": "ŠŠøŃ‡ŠµŠ³Š¾ не найГено. ŠŸŃ€Š¾Š²ŠµŃ€ŃŒŃ‚Šµ параметры ŠøŃŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŠ¹ Šø ŠæŃ€Š¾ŠæŃƒŃŠŗŠ° файлов.", "rerunSearch.message": "Š’Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ поиск еще раз", "rerunSearchInAll.message": "Выполните поиск во всех файлах", "openSettings.message": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ параметры", + "openSettings.learnMore": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ", "ariaSearchResultsStatus": "Поиск Š²ŠµŃ€Š½ŃƒŠ» Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Š¾Š²: {0} в файлах: {1}", "search.file.result": "{0} Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚ в {1} файле", "search.files.result": "{0} Ń€ŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚ в ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼ числе файлов: {1}", diff --git a/i18n/rus/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/rus/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..6ab5238739e --- /dev/null +++ b/i18n/rus/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Š’ рабочей области Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚ папки с ŃƒŠŗŠ°Š·Š°Š½Š½Ń‹Š¼ именем: {0}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 8c220bbce30..9c6c8d802ca 100644 --- a/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "Š’ŃŃ‚Š°Š²ŠøŃ‚ŃŒ фрагмент коГа" + "snippet.suggestions.label": "Š’ŃŃ‚Š°Š²ŠøŃ‚ŃŒ фрагмент коГа", + "sep.userSnippet": "Фрагменты коГа ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń", + "sep.extSnippet": "Фрагменты коГа Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 0b174ce00f9..5ec0ad21eef 100644 --- a/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "ŠŠµŠøŠ·Š²ŠµŃŃ‚Š½Ń‹Š¹ ŃŠ·Ń‹Šŗ в contributes.{0}.language. Указанное значение: {1}", + "invalid.path.0": "Š’ contributes.{0}.path Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ строка. Указанное значение: {1}", + "invalid.path.1": "contributes.{0}.path ({1}) Голжен был Š±Ń‹Ń‚ŃŒ Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ в папку Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ ({2}). Это может ŃŠ“ŠµŠ»Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ непереносимым.", + "vscode.extension.contributes.snippets": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ фрагменты.", + "vscode.extension.contributes.snippets-language": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€ ŃŠ·Ń‹ŠŗŠ°, Š“Š»Ń которого Š“Š¾Š±Š°Š²Š»ŃŠµŃ‚ŃŃ ŃŃ‚Š¾Ń‚ фрагмент.", + "vscode.extension.contributes.snippets-path": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ фрагментов. ŠŸŃƒŃ‚ŃŒ ŃƒŠŗŠ°Š·Ń‹Š²Š°ŠµŃ‚ŃŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ папки Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Šø обычно Š½Š°Ń‡ŠøŠ½Š°ŠµŃ‚ся с \"./snippets/\".", + "badFile": "ŠŠµ уГалось ŠæŃ€Š¾Ń‡ŠøŃ‚Š°Ń‚ŃŒ файл фрагмента \"{0}\".", "source.snippet": "Фрагмент коГа ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index 8892c40326e..1588977370e 100644 --- a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "ŠŠ°ŃŃ‚Ń€Š°ŠøŠ²Š°ŠµŃ‚ панель, ŠŗŠ¾Ń‚Š¾Ń€Š°Ń ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ Š“Š»Ń ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ выхоГных Ганных заГачи Šø считывает вхоГные Ганные заГачи.", "JsonSchema.tasks.presentation.echo": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, стоит ли Š¾Ń‚ŠæŃ€Š°Š²Š»ŃŃ‚ŃŒ выхоГные Ганные Š²Ń‹ŠæŠ¾Š»Š½ŃŠµŠ¼Š¾Š¹ команГы на панель. Значение по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ — true.", "JsonSchema.tasks.presentation.focus": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, принимает ли панель Ń„Š¾ŠŗŃƒŃ. По ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ — false. Если ŃƒŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š¾ значение true, панель также Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ.", + "JsonSchema.tasks.presentation.reveal.always": "ВсегГа Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ окно терминала при выполнении ŃŃ‚Š¾Š¹ заГачи.", + "JsonSchema.tasks.presentation.reveal.silent": "ŠžŃ‚Š¾Š±Ń€Š°Š¶Š°Ń‚ŃŒ окно терминала Ń‚Š¾Š»ŃŒŠŗŠ¾ в том ŃŠ»ŃƒŃ‡Š°Šµ, если с ŃŃ‚Š¾Š¹ заГачей не ŃŠ²ŃŠ·Š°Š½ ŃŠ¾ŠæŠ¾ŃŃ‚Š°Š²ŠøŃ‚ŠµŠ»ŃŒ проблем Šø при выполнении заГачи возникли ошибки.", + "JsonSchema.tasks.presentation.reveal.never": "ŠŠøŠŗŠ¾Š³Š“Š° не Š¾Ń‚ŠŗŃ€Ń‹Š²Š°Ń‚ŃŒ окно терминала при выполнении ŃŃ‚Š¾Š¹ заГачи.", "JsonSchema.tasks.presentation.reveals": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ ли панель, на которой Š·Š°ŠæŃƒŃ‰ŠµŠ½Š° заГача. Значение по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ — \"always\".", "JsonSchema.tasks.presentation.instance": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, ŃŠ²Š»ŃŠµŃ‚ŃŃ ли панель общей Š“Š»Ń Š½ŠµŃŠŗŠ¾Š»ŃŒŠŗŠøŃ… заГач, ограничена ли она Ń‚Š¾Š»ŃŒŠŗŠ¾ оГной заГачей или ŃŠ¾Š·Š“Š°ŠµŃ‚ŃŃ Š¾Ń‚Š“ŠµŠ»ŃŒŠ½Š¾ Š“Š»Ń кажГого запуска заГачи.", "JsonSchema.tasks.terminal": "Двойство terminal ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ свойство presentation", @@ -22,7 +25,6 @@ "JsonSchema.tasks.group.test": "ŠžŃ‚Š¼ŠµŃ‡Š°ŠµŃ‚ Š·Š°Š“Š°Ń‡Ńƒ как Š·Š°Š“Š°Ń‡Ńƒ Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ, Š“Š¾ŃŃ‚ŃƒŠæ Šŗ которой Š¾ŃŃƒŃ‰ŠµŃŃ‚Š²Š»ŃŠµŃ‚ŃŃ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ команГы \"Š—Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ\".", "JsonSchema.tasks.group.none": "ŠžŃ‚Š¼ŠµŠ½ŃŠµŃ‚ ŃŠ²ŃŠ·ŃŒ заГачи со всеми Š³Ń€ŃƒŠæŠæŠ°Š¼Šø", "JsonSchema.tasks.group": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Šŗ какой Š³Ń€ŃƒŠæŠæŠµ Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ принаГлежит ŃŃ‚Š° заГача. ŠŸŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŠ¼Ń‹Šµ Š·Š½Š°Ń‡ŠµŠ½ŠøŃ: \"build\" Š“Š»Ń Š“Š¾Š±Š°Š²Š»ŠµŠ½ŠøŃ заГачи Šŗ Š³Ń€ŃƒŠæŠæŠµ сборки Šø \"test\" Š“Š»Ń Š“Š¾Š±Š°Š²Š»ŠµŠ½ŠøŃ заГачи Šŗ Š³Ń€ŃƒŠæŠæŠµ Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ.", - "JsonSchema.tasks.type": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š²Ń‹ŠæŠ¾Š»Š½ŃŠµŃ‚ŃŃ ли заГача в виГе процесса или в виГе команГы оболочки. Значение по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ — \"процесс\".", "JsonSchema.version": "ŠŠ¾Š¼ŠµŃ€ версии ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø.", "JsonSchema.tasks.identifier": "ŠŸŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠøŠ¹ иГентификатор заГачи в файле launch.json или в преГложении dependsOn.", "JsonSchema.tasks.taskLabel": "ŠœŠµŃ‚ŠŗŠ° заГачи", @@ -35,8 +37,10 @@ "JsonSchema.tasks.customize.deprecated": "Двойство customize ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Š”Š²ŠµŠ“ŠµŠ½ŠøŃ о том, как перейти на новый поГхоГ Šŗ ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃŽ заГач, см. в заметках о Š²Ń‹ŠæŃƒŃŠŗŠµ Š“Š»Ń версии 1.14.", "JsonSchema.tasks.showOputput.deprecated": "Двойство showOutput ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ свойство reveal в свойстве presentation вместо ŃŃ‚Š¾Š³Š¾ свойства. Также см. заметки о Š²Ń‹ŠæŃƒŃŠŗŠµ Š“Š»Ń версии 1.14.", "JsonSchema.tasks.echoCommand.deprecated": "Двойство echoCommand ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ свойство echo в свойстве presentation вместо ŃŃ‚Š¾Š³Š¾ свойства. Также см. заметки о Š²Ń‹ŠæŃƒŃŠŗŠµ Š“Š»Ń версии 1.14.", + "JsonSchema.tasks.suppressTaskName.deprecated": "Двойство suppressTaskName ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Вместо ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ ŃŃ‚Š¾Š³Š¾ свойства Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚е команГу с Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Š°Š¼Šø в Š·Š°Š“Š°Ń‡Ńƒ. Также см. заметки о Š²Ń‹ŠæŃƒŃŠŗŠµ Š“Š»Ń версии 1.14.", "JsonSchema.tasks.isBuildCommand.deprecated": "Двойство isBuildCommand ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ свойство group вместо ŃŃ‚Š¾Š³Š¾ свойства. Также см. заметки о Š²Ń‹ŠæŃƒŃŠŗŠµ Š“Š»Ń версии 1.14. ", "JsonSchema.tasks.isTestCommand.deprecated": "Двойство isTestCommand ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ свойство group вместо ŃŃ‚Š¾Š³Š¾ свойства. Также см. заметки о Š²Ń‹ŠæŃƒŃŠŗŠµ Š“Š»Ń версии 1.14. ", + "JsonSchema.tasks.taskSelector.deprecated": "Двойство taskSelector ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼. Вместо ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ ŃŃ‚Š¾Š³Š¾ свойства Š²ŠŗŠ»ŃŽŃ‡ŠøŃ‚е команГу с Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Š°Š¼Šø в Š·Š°Š“Š°Ń‡Ńƒ. Также см. заметки о Š²Ń‹ŠæŃƒŃŠŗŠµ Š“Š»Ń версии 1.14.", "JsonSchema.windows": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° команГ Windows", "JsonSchema.mac": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° команГ Mac", "JsonSchema.linux": "ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° команГ Linux" diff --git a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index b8738833fa7..6e4e63c216e 100644 --- a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,30 +5,33 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "ЗаГачи", - "ConfigureTaskRunnerAction.noWorkspace": "ЗаГачи Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹ Ń‚Š¾Š»ŃŒŠŗŠ¾ в папке рабочей области.", - "ConfigureTaskRunnerAction.quickPick.template": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ среГство Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ заГач", - "ConfigureTaskRunnerAction.autoDetecting": "ŠŠ²Ń‚Š¾Š¾Š±Š½Š°Ń€ŃƒŠ¶ŠµŠ½ŠøŠµ заГач Š“Š»Ń {0}", - "ConfigureTaskRunnerAction.autoDetect": "ŠŠµ уГалось автоматически Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ ŃŠøŃŃ‚ŠµŠ¼Ńƒ заГачи, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ шаблон по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ. ŠŸŠ¾Š“Ń€Š¾Š±Š½Š¾ŃŃ‚Šø см. в выхоГных Ганных заГачи.", - "ConfigureTaskRunnerAction.autoDetectError": "ŠŸŃ€Šø опреГелении системы заГачи возникли ошибки. Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ см. в выхоГных Ганных заГачи.", - "ConfigureTaskRunnerAction.failed": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ ŃŠ¾Š·Š“Š°Ń‚ŃŒ файл tasks.json в папке .vscode. ŠŸŠ¾Š“Ń€Š¾Š±Š½Š¾ŃŃ‚Šø см. в выхоГных Ганных заГачи.", - "ConfigureTaskRunnerAction.label": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ среГство Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ заГач", + "ConfigureTaskRunnerAction.label": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ", "ConfigureBuildTaskAction.label": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки", "CloseMessageAction.label": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", "ShowTerminalAction.label": "ŠžŠ·Š½Š°ŠŗŠ¾Š¼ŠøŃ‚ŃŒŃŃ с терминалом", "problems": "ŠŸŃ€Š¾Š±Š»ŠµŠ¼Ń‹", "manyMarkers": "99+", + "runningTasks": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Š²Ń‹ŠæŠ¾Š»Š½ŃŠµŠ¼Ń‹Šµ заГачи", "tasks": "ЗаГачи", - "TaskSystem.noHotSwap": "Чтобы ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠæŠ¾Š“ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ заГач, нужно ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ VS Code. Изменение ŠøŠ³Š½Š¾Ń€ŠøŃ€ŃƒŠµŃ‚ся.", + "TaskSystem.noHotSwap": "Чтобы ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ ŠæŠ¾Š“ŃŠøŃŃ‚ŠµŠ¼Ńƒ Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ заГач, в которой Š·Š°ŠæŃƒŃ‰ŠµŠ½Š° Š°ŠŗŃ‚ŠøŠ²Š½Š°Ń заГача, необхоГимо ŠæŠµŃ€ŠµŠ·Š°Š³Ń€ŃƒŠ·ŠøŃ‚ŃŒ окно", "TaskService.noBuildTask1": "ЗаГача сборки не опреГелена. ŠžŃ‚Š¼ŠµŃ‚ŃŒŃ‚Šµ Š·Š°Š“Š°Ń‡Ńƒ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ \"isBuildCommand\" в файле tasks.json.", "TaskService.noBuildTask2": "ЗаГача сборки не опреГелена. ŠžŃ‚Š¼ŠµŃ‚ŃŒŃ‚Šµ Š·Š°Š“Š°Ń‡Ńƒ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Š³Ń€ŃƒŠæŠæŃ‹ 'build' в файле tasks.json.", "TaskService.noTestTask1": "ЗаГача теста не опреГелена. ŠžŃ‚Š¼ŠµŃ‚ŃŒŃ‚Šµ Š·Š°Š“Š°Ń‡Ńƒ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ \"isTestCommand\" в файле tasks.json.", "TaskService.noTestTask2": "ЗаГача теста не опреГелена. ŠžŃ‚Š¼ŠµŃ‚ŃŒŃ‚Šµ Š·Š°Š“Š°Ń‡Ńƒ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ Š³Ń€ŃƒŠæŠæŃ‹ 'test' в файле tasks.json.", "TaskServer.noTask": "Š—Š°ŠæŃ€Š¾ŃˆŠµŠ½Š½Š°Ń заГача {0} Š“Š»Ń Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ не найГена.", + "TaskService.associate": "ŃŠ²ŃŠ·Š°Ń‚ŃŒ", + "TaskService.attachProblemMatcher.continueWithout": "ŠŸŃ€Š¾Š“Š¾Š»Š¶ŠøŃ‚ŃŒ без проверки выхоГных Ганных заГачи", + "TaskService.attachProblemMatcher.never": "ŠŠøŠŗŠ¾Š³Š“Š° не ŠæŃ€Š¾Š²ŠµŃ€ŃŃ‚ŃŒ выхоГные Ганные заГачи", + "TaskService.attachProblemMatcher.learnMoreAbout": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ о проверке выхоГных Ганных заГачи", + "selectProblemMatcher": "Выберите, на какие ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ŠæŃ€Š¾Š²ŠµŃ€ŃŃ‚ŃŒ выхоГные Ганные заГачи", "customizeParseErrors": "Š’ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¹ заГачи ŠµŃŃ‚ŃŒ ошибки. Š˜ŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ошибки переГ изменением заГачи.", "moreThanOneBuildTask": "Š’ файле tasks.json опреГелено несколько заГач сборки. Š’Ń‹ŠæŠ¾Š»Š½ŃŠµŃ‚ŃŃ ŠæŠµŃ€Š²Š°Ń заГача.\n", + "TaskSystem.activeSame.background": "ЗаГача '{0}' уже активна Šø Š½Š°Ń…Š¾Š“ŠøŃ‚ŃŃ в фоновом режиме. Чтобы Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ, выберите \"Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ\" в Š¼ŠµŠ½ŃŽ \"ЗаГачи\".", + "TaskSystem.activeSame.noBackground": "ЗаГача '{0}' уже активна. Чтобы Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ, выберите \"Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ\" ŠøŠ· Š¼ŠµŠ½ŃŽ \"ЗаГачи\".", "TaskSystem.active": "Уже Š²Ń‹ŠæŠ¾Š»Š½ŃŠµŃ‚ся заГача. Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚Šµ ее, прежГе чем Š²Ń‹ŠæŠ¾Š»Š½ŃŃ‚ŃŒ Š“Ń€ŃƒŠ³ŃƒŃŽ Š·Š°Š“Š°Ń‡Ńƒ.", "TaskSystem.restartFailed": "ŠŠµ уГалось Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Šø ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ {0}", "TaskSystem.configurationErrors": "ŠžŃˆŠøŠ±ŠŗŠ°: в ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø указанной заГачи при проверке были Š²Ń‹ŃŠ²Š»ŠµŠ½Ń‹ ошибки, Šø ее невозможно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ. Дначала ŃƒŃŃ‚Ń€Š°Š½ŠøŃ‚Šµ ошибки.", + "taskService.ignoreingFolder": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø заГач Š“Š»Ń папки рабочей области {0} Š±ŃƒŠ“ŃƒŃ‚ проигнорированы. Š”Š»Ń заГач рабочей области с несколькими папками необхоГимо, чтобы во всех папках использовалась Š²ŠµŃ€ŃŠøŃ заГачи 2.0.0\n", "TaskSystem.invalidTaskJson": "ŠžŃˆŠøŠ±ŠŗŠ°: в соГержимом файла tasks.json ŠµŃŃ‚ŃŒ синтаксические ошибки. Š˜ŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ŠøŃ…, прежГе чем Š²Ń‹ŠæŠ¾Š»Š½ŃŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ.\n", "TaskSystem.runningTask": "Š˜Š¼ŠµŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŃŃŽŃ‰Š°ŃŃŃ заГача. Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ ее?", "TaskSystem.terminateTask": "&&Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ", @@ -40,25 +43,37 @@ "recentlyUsed": "неГавно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½Š½Ń‹Šµ заГачи", "configured": "настроенные заГачи", "detected": "Š¾Š±Š½Š°Ń€ŃƒŠ¶ŠµŠ½Š½Ń‹Šµ заГачи", + "TaskService.ignoredFolder": "Š”Š»ŠµŠ“ŃƒŃŽŃ‰ŠøŠµ папки рабочей области Š±ŃƒŠ“ŃƒŃ‚ проигнорированы, так как в них ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ Š²ŠµŃ€ŃŠøŃ заГач 0.1.0:", + "TaskService.notAgain": "Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", + "TaskService.ok": "ŠžŠš", + "TaskService.pickRunTask": "Выберите Š·Š°Š“Š°Ń‡Ńƒ Š“Š»Ń запуска", + "TaslService.noEntryToRun": "ЗаГача Š“Š»Ń запуска не найГена. ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ заГачи...", "TaskService.fetchingBuildTasks": "ŠŸŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŠµ заГач сборки...", - "TaskService.noBuildTaskTerminal": "ЗаГача сборки не найГена. ŠŠ°Š¶Š¼ŠøŃ‚Šµ кнопку \"ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки\", чтобы Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки.", "TaskService.pickBuildTask": "Выберите Š·Š°Š“Š°Ń‡Ńƒ сборки Š“Š»Ń запуска", + "TaskService.noBuildTask": "ЗаГача сборки не найГена. ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ заГачи... ", "TaskService.fetchingTestTasks": "ŠŸŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŠµ заГач Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ...", - "TaskService.noTestTaskTerminal": "ЗаГача Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ не найГена. ŠŠ°Š¶Š¼ŠøŃ‚Šµ кнопку \"ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ\", чтобы Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки. ", "TaskService.pickTestTask": "Выберите Š·Š°Š“Š°Ń‡Ńƒ Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ Š“Š»Ń запуска", - "TaskService.noTaskRunning": "ŠŠø оГной заГачи не Š·Š°ŠæŃƒŃ‰ŠµŠ½Š¾.", + "TaskService.noTestTaskTerminal": "Š¢ŠµŃŃ‚Š¾Š²Š°Ń заГача Š“Š»Ń запуска не найГена. ŠŠ°ŃŃ‚Ń€Š¾Š¹Ń‚Šµ заГачи...", "TaskService.tastToTerminate": "Выберите заГачи Š“Š»Ń Š·Š°Š²ŠµŃ€ŃˆŠµŠ½ŠøŃ", + "TaskService.noTaskRunning": "ŠŠø оГной заГачи не Š·Š°ŠæŃƒŃ‰ŠµŠ½Š¾", "TerminateAction.noProcess": "Š—Š°ŠæŃƒŃ‰ŠµŠ½Š½Ń‹Š¹ процесс больше не ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚. Если заГача пороГила фоновые заГачи, выхоГ ŠøŠ· Visual Studio Code может привести Šŗ ŠæŠ¾ŃŠ²Š»ŠµŠ½ŠøŃŽ ŠæŠ¾Ń‚ŠµŃ€ŃŠ½Š½Ń‹Ń… процессов.", "TerminateAction.failed": "ŠŠµ уГалось Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Š·Š°ŠæŃƒŃ‰ŠµŠ½Š½ŃƒŃŽ Š·Š°Š“Š°Ń‡Ńƒ", - "TaskService.noTaskToRestart": "ЗаГачи Š“Š»Ń ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗŠ° не найГены.", "TaskService.tastToRestart": "Выберите Š·Š°Š“Š°Ń‡Ńƒ Š“Š»Ń ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗŠ°", - "TaskService.defaultBuildTaskExists": "{0} уже помечена как заГача сборки по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ.", + "TaskService.noTaskToRestart": "ЗаГачи Š“Š»Ń ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗŠ° не найГены", + "TaskService.template": "Выберите шаблон заГачи", + "TaskService.createJsonFile": "Š”Š¾Š·Š“Š°Ń‚ŃŒ файл tasks.json ŠøŠ· шаблона", + "TaskService.openJsonFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл tasks.json", + "TaskService.pickTask": "Выберите Š·Š°Š“Š°Ń‡Ńƒ Š“Š»Ń настройки", + "TaskService.defaultBuildTaskExists": "ЗаГача {0} уже помечена как заГача сборки по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", "TaskService.pickDefaultBuildTask": "Выберите Š·Š°Š“Š°Ń‡Ńƒ, ŠŗŠ¾Ń‚Š¾Ń€Š°Ń Š±ŃƒŠ“ŠµŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒŃŃ в качестве заГачи сборки по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ.", "TaskService.defaultTestTaskExists": "{0} уже помечена как заГача сборки по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ. ", "TaskService.pickDefaultTestTask": "Выберите Š·Š°Š“Š°Ń‡Ńƒ, ŠŗŠ¾Ń‚Š¾Ń€Š°Ń Š±ŃƒŠ“ŠµŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒŃŃ в качестве заГачи Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ. ", + "TaskService.pickShowTask": "Выберите Š·Š°Š“Š°Ń‡Ńƒ, выхоГные Ганные Š“Š»Ń которой нужно Š¾Ń‚Š¾Š±Ń€Š°Š·ŠøŃ‚ŃŒ", + "TaskService.noTaskIsRunning": "ŠŠø оГной заГачи не Š·Š°ŠæŃƒŃ‰ŠµŠ½Š¾", "ShowLogAction.label": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Š¶ŃƒŃ€Š½Š°Š» заГач", "RunTaskAction.label": "Š’Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ", "RestartTaskAction.label": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ Š·Š°ŠæŃƒŃ‰ŠµŠ½Š½ŃƒŃŽ Š·Š°Š“Š°Ń‡Ńƒ", + "ShowTasksAction.label": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Š²Ń‹ŠæŠ¾Š»Š½ŃŃŽŃ‰ŠøŠµŃŃ заГачи", "BuildAction.label": "Š’Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки", "TestAction.label": "Š’Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ Ń‚ŠµŃŃ‚ŠøŃ€Š¾Š²Š°Š½ŠøŃ", "ConfigureDefaultBuildTask.label": "ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Š·Š°Š“Š°Ń‡Ńƒ сборки по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", diff --git a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 922550c51cb..05102c96f17 100644 --- a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "ŠŸŃ€Šø выполнении заГачи ŠæŃ€Š¾ŠøŠ·Š¾ŃˆŠ»Š° Š½ŠµŠøŠ·Š²ŠµŃŃ‚Š½Š°Ń ошибка. ŠŸŠ¾Š“Ń€Š¾Š±Š½Š¾ŃŃ‚Šø см. в Š¶ŃƒŃ€Š½Š°Š»Šµ выхоГных Ганных заГач.", + "dependencyFailed": "ŠŠµ уГалось Ń€Š°Š·Ń€ŠµŃˆŠøŃ‚ŃŒ Š·Š°Š²ŠøŃŠøŠ¼ŃƒŃŽ Š·Š°Š“Š°Ń‡Ńƒ '{0}' в папке рабочей области '{1}'", "TerminalTaskSystem.terminalName": "ЗаГача — {0}", "reuseTerminal": "Терминал Š±ŃƒŠ“ет повторно ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒŃŃ заГачами. Чтобы Š·Š°ŠŗŃ€Ń‹Ń‚ŃŒ его, нажмите Š»ŃŽŠ±ŃƒŃŽ клавишу.", "TerminalTaskSystem": "ŠŠµŠ²Š¾Š·Š¼Š¾Š¶Š½Š¾ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ команГу оболочки на Гиске UNC.", diff --git a/i18n/rus/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/rus/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index 5f9a68cdb97..a317034d2a3 100644 --- a/i18n/rus/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,9 +11,12 @@ "ConfigurationParser.unknownMatcherKind": "ŠŸŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠµ: опреГелен неизвестный ŃŠ¾ŠæŠ¾ŃŃ‚Š°Š²ŠøŃ‚ŠµŠ»ŃŒ проблем. ŠŸŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŠ¼Ń‹Šµ типы: строка | Š”Š¾ŠæŠ¾ŃŃ‚Š°Š²ŠøŃ‚ŠµŠ»ŃŒŠŸŃ€Š¾Š±Š»ŠµŠ¼ | (строка | Š”Š¾ŠæŠ¾ŃŃ‚Š°Š²ŠøŃ‚ŠµŠ»ŃŒŠŸŃ€Š¾Š±Š»ŠµŠ¼)[].\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "ŠžŃˆŠøŠ±ŠŗŠ°: Š½ŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Š°Ń ссылка на problemMatcher: {0}\n", "ConfigurationParser.noTaskType": "ŠžŃˆŠøŠ±ŠŗŠ°: в ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø заГач Голжно ŠæŃ€ŠøŃŃƒŃ‚ŃŃ‚Š²Š¾Š²Š°Ń‚ŃŒ свойство типа. ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ Š±ŃƒŠ“ŠµŃ‚ проигнорирована.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "ŠžŃˆŠøŠ±ŠŗŠ°: тип заГачи '{0}' не зарегистрирован. Возможно, вы не ŃƒŃŃ‚Š°Š½Š¾Š²ŠøŠ»Šø Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ, которое ŠæŃ€ŠµŠ“Š¾ŃŃ‚Š°Š²Š»ŃŠµŃ‚ ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠøŠ¹ поставщик заГач.", + "ConfigurationParser.missingRequiredProperty": "ŠžŃˆŠøŠ±ŠŗŠ°: в ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø заГачи '{0}' Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŠµŃ‚ необхоГимое свойство '{1}'. ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ заГачи Š±ŃƒŠ“ет проигнорирована.", "ConfigurationParser.notCustom": "ŠžŃˆŠøŠ±ŠŗŠ°: заГачи не Š¾Š±ŃŠŃŠ²Š»ŠµŠ½Ń‹ в качестве ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠ¾Š¹ заГачи. ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ Š±ŃƒŠ“ŠµŃ‚ проигнорирована.\n{0}\n", "ConfigurationParser.noTaskName": "ŠžŃˆŠøŠ±ŠŗŠ°: заГачи Голжны ŠæŃ€ŠµŠ“Š¾ŃŃ‚Š°Š²Š»ŃŃ‚ŃŒ свойство taskName. ЗаГача Š±ŃƒŠ“ет проигнорирована.\n{0}\n", "taskConfiguration.shellArgs": "ŠŸŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŠµ: заГача \"{0}\" ŃŠ²Š»ŃŠµŃ‚ŃŃ команГой оболочки, Šø ŠøŠ¼Ń команГы или оГного ŠøŠ· ее Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ов Š²ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ пробелы без escape-ŠæŠ¾ŃŠ»ŠµŠ“Š¾Š²Š°Ń‚ŠµŠ»ŃŒŠ½Š¾ŃŃ‚Šø. Чтобы Š¾Š±ŠµŃŠæŠµŃ‡ŠøŃ‚ŃŒ ŠæŃ€Š°Š²ŠøŠ»ŃŒŠ½ŃƒŃŽ Ń€Š°ŃŃŃ‚Š°Š½Š¾Š²ŠŗŃƒ кавычек в команГной строке, Š¾Š±ŃŠŠµŠ“ŠøŠ½ŠøŃ‚Šµ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń‹ в команГе.", "taskConfiguration.noCommandOrDependsOn": "ŠžŃˆŠøŠ±ŠŗŠ°: в заГаче \"{0}\" не ŃƒŠŗŠ°Š·Š°Š½Ń‹ ни команГа, ни свойство dependsOn. ЗаГача Š±ŃƒŠ“ет проигнорирована. ŠžŠæŃ€ŠµŠ“ŠµŠ»ŠµŠ½ŠøŠµ заГачи:\n{1}", - "taskConfiguration.noCommand": "ŠžŃˆŠøŠ±ŠŗŠ°: заГача \"{0}\" не Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ команГу. ЗаГача Š±ŃƒŠ“ет ŠøŠ³Š½Š¾Ń€ŠøŃ€Š¾Š²Š°Ń‚ŃŒŃŃ. Ее опреГеление:\n{1}" + "taskConfiguration.noCommand": "ŠžŃˆŠøŠ±ŠŗŠ°: заГача \"{0}\" не Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ команГу. ЗаГача Š±ŃƒŠ“ет ŠøŠ³Š½Š¾Ń€ŠøŃ€Š¾Š²Š°Ń‚ŃŒŃŃ. Ее опреГеление:\n{1}", + "TaskParse.noOsSpecificGlobalTasks": "Š’ŠµŃ€ŃŠøŃ заГач 2.0.0 не поГГерживает Š³Š»Š¾Š±Š°Š»ŃŒŠ½Ń‹Šµ заГачи Š“Š»Ń конкретных ŠžŠ”. ŠŸŃ€ŠµŠ¾Š±Ń€Š°Š·ŃƒŠ¹Ń‚Šµ ŠøŃ… в заГачи с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ команГ Š“Š»Ń конкретных ŠžŠ”.\nŠ—Š°Ń‚Ń€Š¾Š½ŃƒŃ‚Ń‹Šµ заГачи: {0}" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index 8b6ad71cd4e..bc758f05704 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -3,4 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "termEntryAriaLabel": "{0}, среГство выбора терминалов", + "termCreateEntryAriaLabel": "{0}, ŃŠ¾Š·Š“Š°Ń‚ŃŒ новый терминал", + "'workbench.action.terminal.newplus": "$(plus) Š”Š¾Š·Š“Š°Ń‚ŃŒ новый интегрированный терминал", + "noTerminalsMatching": "Терминалы, ŃŠ¾Š¾Ń‚Š²ŠµŃ‚ŃŃ‚Š²ŃƒŃŽŃ‰ŠøŠµ ŃƒŃŠ»Š¾Š²ŠøŃŽ, Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚", + "noTerminalsFound": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚Ń‹Šµ терминалы Š¾Ń‚ŃŃƒŃ‚ŃŃ‚Š²ŃƒŃŽŃ‚" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index ffbac2eb99e..33131ec5a92 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -4,18 +4,19 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "quickOpen.terminal": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ все открытые терминалы", + "terminal": "Терминал", "terminalIntegratedConfigurationTitle": "Š˜Š½Ń‚ŠµŠ³Ń€ŠøŃ€Š¾Š²Š°Š½Š½Ń‹Š¹ терминал", "terminal.integrated.shell.linux": "ŠŸŃƒŃ‚ŃŒ оболочки, который ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся терминалом в Linux.", "terminal.integrated.shellArgs.linux": "ŠŃ€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń‹ команГной строки, которые ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ в терминале Linux.", "terminal.integrated.shell.osx": "ŠŸŃƒŃ‚ŃŒ оболочки, который ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся терминалом в OS X.", "terminal.integrated.shellArgs.osx": "ŠŃ€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń‹ команГной строки, которые ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ в терминале OS X.", + "terminal.integrated.shell.windows": "ŠŸŃƒŃ‚ŃŒ Šŗ оболочке, который ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся терминалом в Windows. Š”Š»Ń оболочек, Š²Ń…Š¾Š“ŃŃ‰ŠøŃ… в состав ŠžŠ” Windows (cmd, PowerShell или Bash в Ubuntu).", "terminal.integrated.shellArgs.windows": "ŠŃ€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń‹ команГной строки, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼Ń‹Šµ в терминале Windows.", "terminal.integrated.rightClickCopyPaste": "Если заГано, Š±Š»Š¾ŠŗŠøŃ€ŃƒŠµŃ‚ отображение контекстного Š¼ŠµŠ½ŃŽ при щелчке правой кнопкой Š¼Ń‹ŃˆŠø в терминале. Вместо ŃŃ‚Š¾Š³Š¾ Š±ŃƒŠ“ŠµŃ‚ Š²Ń‹ŠæŠ¾Š»Š½ŃŃ‚ŃŒŃŃ копирование выбранного ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š° Šø вставка в Š¾Š±Š»Š°ŃŃ‚ŃŒ, в которой нет выбранных ŃŠ»ŠµŠ¼ŠµŠ½Ń‚Š¾Š².", "terminal.integrated.fontFamily": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ семейство ŃˆŃ€ŠøŃ„Ń‚Š¾Š² терминала, значение по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ — editor.fontFamily.", - "terminal.integrated.fontLigatures": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, Š±ŃƒŠ“ŃƒŃ‚ ли Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½Ń‹ Š»ŠøŠ³Š°Ń‚ŃƒŃ€Ń‹ ŃˆŃ€ŠøŃ„Ń‚Š¾Š² Š“Š»Ń терминала.", "terminal.integrated.fontSize": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ размер ŃˆŃ€ŠøŃ„Ń‚Š° (в ŠæŠøŠŗŃŠµŠ»ŃŃ…) Š“Š»Ń терминала.", "terminal.integrated.lineHeight": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ Š²Ń‹ŃŠ¾Ń‚Ńƒ строки терминала; ŃŃ‚Š¾ число ŃƒŠ¼Š½Š¾Š¶Š°ŠµŃ‚ŃŃ на размер ŃˆŃ€ŠøŃ„Ń‚Š° терминала, что Гает Ń„Š°ŠŗŃ‚ŠøŃ‡ŠµŃŠŗŃƒŃŽ Š²Ń‹ŃŠ¾Ń‚Ńƒ строки в ŠæŠøŠŗŃŠµŠ»ŃŃ….", - "terminal.integrated.enableBold": "Š”Š»ŠµŠ“ŃƒŠµŃ‚ ли Ń€Š°Š·Ń€ŠµŃˆŠøŃ‚ŃŒ ŠæŠ¾Š»ŃƒŠ¶ŠøŃ€Š½Ń‹Š¹ текст в терминале. Эта Ń„ŃƒŠ½ŠŗŃ†ŠøŃ Голжна ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°Ń‚ŃŒŃŃ оболочкой терминала.", "terminal.integrated.cursorBlinking": "Š£ŠæŃ€Š°Š²Š»ŃŠµŃ‚ миганием ŠŗŃƒŃ€ŃŠ¾Ń€Š° терминала.", "terminal.integrated.cursorStyle": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ ŃŃ‚ŠøŠ»ŃŒ ŠŗŃƒŃ€ŃŠ¾Ń€Š° терминала.", "terminal.integrated.scrollback": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ ŠæŃ€ŠµŠ“ŠµŠ»ŃŒŠ½Š¾Šµ число строк в Š±ŃƒŃ„ере терминала.", @@ -23,7 +24,9 @@ "terminal.integrated.cwd": "ŠŸŃƒŃ‚ŃŒ ŃŠ²Š½Š¾Š³Š¾ запуска, по ŠŗŠ¾Ń‚Š¾Ń€Š¾Š¼Ńƒ Š±ŃƒŠ“ŠµŃ‚ Š·Š°ŠæŃƒŃ‰ŠµŠ½ терминал. Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ в качестве Ń‚ŠµŠŗŃƒŃ‰ŠµŠ³Š¾ рабочего каталога (cwd) Š“Š»Ń процесса оболочки. Это может Š±Ń‹Ń‚ŃŒ особенно уГобно в параметрах рабочей области, если корневой каталог не ŃŠ²Š»ŃŠµŃ‚ŃŃ ŠæŠ¾Š“Ń…Š¾Š“ŃŃ‰ŠøŠ¼ каталогом cwd.", "terminal.integrated.confirmOnExit": "Указывает, ŃŠ»ŠµŠ“ŃƒŠµŃ‚ ли при выхоГе Š²Ń‹Š²Š¾Š“ŠøŃ‚ŃŒ поГтвержГение об ŠøŠ¼ŠµŃŽŃ‰ŠøŃ…ся активных сеансах терминала.", "terminal.integrated.commandsToSkipShell": "ŠŠ°Š±Š¾Ń€ иГентификаторов команГ, настраиваемые ŃŠ¾Ń‡ŠµŃ‚Š°Š½ŠøŃ клавиш которых не Š±ŃƒŠ“ŃƒŃ‚ ŠæŠµŃ€ŠµŠ“Š°Š²Š°Ń‚ŃŒŃŃ в Š¾Š±Š¾Š»Š¾Ń‡ŠŗŃƒ, а вместо ŃŃ‚Š¾Š³Š¾ Š±ŃƒŠ“ŃƒŃ‚ всегГа Š¾Š±Ń€Š°Š±Š°Ń‚Ń‹Š²Š°Ń‚ŃŒŃŃ Code. Это ŠæŠ¾Š·Š²Š¾Š»ŃŠµŃ‚ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ настраиваемые ŃŠ¾Ń‡ŠµŃ‚Š°Š½ŠøŃ клавиш, которые при обычных ŃƒŃŠ»Š¾Š²ŠøŃŃ… были бы ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½Ń‹ оболочкой Šø работали бы так же, как если бы терминал не имел Ń„Š¾ŠŗŃƒŃŠ°, например клавиши CTRL+P запускали бы Quick Open.", - "terminal": "Терминал", + "terminal.integrated.env.osx": "ŠžŠ±ŃŠŠµŠŗŃ‚ с переменными среГы, которые Š±ŃƒŠ“ŃƒŃ‚ Гобавлены Šŗ ŠæŃ€Š¾Ń†ŠµŃŃŃƒ VS Code Š“Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ в терминале OS X", + "terminal.integrated.env.linux": "ŠžŠ±ŃŠŠµŠŗŃ‚ с переменными среГы, которые Š±ŃƒŠ“ŃƒŃ‚ Гобавлены Šŗ ŠæŃ€Š¾Ń†ŠµŃŃŃƒ VS Code Š“Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ в терминале Linux ", + "terminal.integrated.env.windows": "ŠžŠ±ŃŠŠµŠŗŃ‚ с переменными среГы, которые Š±ŃƒŠ“ŃƒŃ‚ Гобавлены Šŗ ŠæŃ€Š¾Ń†ŠµŃŃŃƒ VS Code Š“Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ в терминале Windows", "terminalCategory": "Терминал", "viewCategory": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 32aa44547c4..18331d6a712 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,13 +7,15 @@ "workbench.action.terminal.toggleTerminal": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ интегрированный терминал", "workbench.action.terminal.kill": "Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ активный ŃŠŗŠ·ŠµŠ¼ŠæŠ»ŃŃ€ терминала", "workbench.action.terminal.kill.short": "Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‚Ńƒ терминала", + "workbench.action.terminal.quickKill": "Š—Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ Ń€Š°Š±Š¾Ń‚Ńƒ ŃŠŗŠ·ŠµŠ¼ŠæŠ»ŃŃ€Š° терминала", "workbench.action.terminal.copySelection": "Š”ŠŗŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ выГеление", "workbench.action.terminal.selectAll": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ все", + "workbench.action.terminal.deleteWordLeft": "Š£Š“Š°Š»ŠøŃ‚ŃŒ слово слева", + "workbench.action.terminal.deleteWordRight": "Š£Š“Š°Š»ŠøŃ‚ŃŒ слово справа", "workbench.action.terminal.new": "ДозГание нового интегрированного терминала", "workbench.action.terminal.new.short": "ŠŠ¾Š²Ń‹Š¹ терминал", "workbench.action.terminal.focus": "Фокус на терминале", "workbench.action.terminal.focusNext": "Фокус на ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠµŠ¼ терминале", - "workbench.action.terminal.focusAtIndex": "Фокус на терминале {0}", "workbench.action.terminal.focusPrevious": "Фокус на ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ¼ терминале", "workbench.action.terminal.paste": "Š’ŃŃ‚Š°Š²ŠøŃ‚ŃŒ в активный терминал", "workbench.action.terminal.DefaultShell": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ Š¾Š±Š¾Š»Š¾Ń‡ŠŗŃƒ по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ", @@ -33,5 +35,8 @@ "workbench.action.terminal.rename": "ŠŸŠµŃ€ŠµŠøŠ¼ŠµŠ½Š¾Š²Š°Ń‚ŃŒ", "workbench.action.terminal.rename.prompt": "ВвеГите название терминала", "workbench.action.terminal.focusFindWidget": "Š’Ń‹Š“ŠµŠ»ŠøŃ‚ŃŒ мини-приложение поиска", - "workbench.action.terminal.hideFindWidget": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ мини-приложение поиска" + "workbench.action.terminal.hideFindWidget": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ мини-приложение поиска", + "nextTerminalFindTerm": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠ¹ найГенный термин", + "previousTerminalFindTerm": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠøŠ¹ найГенный термин", + "quickOpenTerm": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ активный терминал" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index a43d3077cff..fc208588fb0 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -6,5 +6,8 @@ { "terminal.background": "Цвет фона терминала. Š” его ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ можно ŃƒŠŗŠ°Š·Š°Ń‚ŃŒ цвет терминала, отличный от цвета панели.", "terminal.foreground": "Цвет переГнего плана терминала.", + "terminalCursor.foreground": "Цвет переГнего плана ŠŗŃƒŃ€ŃŠ¾Ń€Š° терминала.", + "terminalCursor.background": "Цвет фона ŠŗŃƒŃ€ŃŠ¾Ń€Š° терминала. ŠŸŠ¾Š·Š²Š¾Š»ŃŠµŃ‚ Š²Ń‹Š±Ń€Š°Ń‚ŃŒ цвет символа, который ŠæŠµŃ€ŠµŠŗŃ€Ń‹Š²Š°ŠµŃ‚ŃŃ блочным ŠŗŃƒŃ€ŃŠ¾Ń€Š¾Š¼.", + "terminal.selectionBackground": "Цвет фона Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ терминала.", "terminal.ansiColor": "Цвет ANSI \"{0}\" в терминале." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index 92eaeea4fb9..80ae6596199 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "ŠšŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ", - "createNewTerminal": "ŠŠ¾Š²Ń‹Š¹ терминал", "paste": "Š’ŃŃ‚Š°Š²ŠøŃ‚ŃŒ", "selectAll": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ все", "clear": "ŠžŃ‡ŠøŃŃ‚ŠøŃ‚ŃŒ" diff --git a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 77b64a5be2d..440d374ef82 100644 --- a/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "ŠžŠš. Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", "terminal.integrated.chooseWindowsShell": "Выберите ŠæŃ€ŠµŠ“ŠæŠ¾Ń‡ŠøŃ‚Š°ŠµŠ¼ŃƒŃŽ Š¾Š±Š¾Š»Š¾Ń‡ŠŗŃƒ терминала. Ее можно позже ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ в параметрах", "terminalService.terminalCloseConfirmationSingular": "Š•ŃŃ‚ŃŒ активный сеанс терминала, Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ его?", - "terminalService.terminalCloseConfirmationPlural": "Š•ŃŃ‚ŃŒ несколько активных сеансов терминала ({0}), Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ ŠøŃ…?", - "yes": "Да" + "terminalService.terminalCloseConfirmationPlural": "Š•ŃŃ‚ŃŒ несколько активных сеансов терминала ({0}), Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ ŠøŃ…?" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json index e74084f3686..baeaa62ec04 100644 --- a/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,9 @@ "licenseChanged": "Š£ŃŠ»Š¾Š²ŠøŃ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ лицензии изменились, Š¾Š·Š½Š°ŠŗŠ¾Š¼ŃŒŃ‚ŠµŃŃŒ с ними.", "license": "ŠŸŃ€Š¾Ń‡ŠøŃ‚Š°Ń‚ŃŒ ŃƒŃŠ»Š¾Š²ŠøŃ лицензии", "neveragain": "Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", + "64bitisavailable": "{0} Š“Š»Ń 64-Ń€Š°Š·Ń€ŃŠ“Š½Š¾Š¹ версии Windows Ń‚ŠµŠæŠµŃ€ŃŒ Š“Š¾ŃŃ‚ŃƒŠæŠµŠ½!", "learn more": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ", + "updateIsReady": "Š”Š¾ŃŃ‚ŃƒŠæŠ½Š¾ новое обновление {0}.", "thereIsUpdateAvailable": "Š”Š¾ŃŃ‚ŃƒŠæŠ½Š¾ обновление.", "updateAvailable": "{0} Š±ŃƒŠ“ŠµŃ‚ обновлен после ŠæŠµŃ€ŠµŠ·Š°ŠæŃƒŃŠŗŠ°.", "noUpdatesAvailable": "Š’ Š½Š°ŃŃ‚Š¾ŃŃ‰ŠµŠµ Š²Ń€ŠµŠ¼Ń нет Š“Š¾ŃŃ‚ŃƒŠæŠ½Ń‹Ń… обновлений.", diff --git a/i18n/rus/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/rus/src/vs/workbench/parts/views/browser/views.i18n.json index 761072edd67..b0fa6d5e7e3 100644 --- a/i18n/rus/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/views/browser/views.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "viewToolbarAriaLabel": "Действий: {0}" + "viewToolbarAriaLabel": "Действий: {0}", + "hideView": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ ŠøŠ· боковой панели" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json b/i18n/rus/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json index c2f0f211adc..1ad62d4bc9b 100644 --- a/i18n/rus/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/views/browser/viewsExtensionPoint.i18n.json @@ -12,5 +12,6 @@ "vscode.extension.contributes.view.when": "Условие, которое Голжно ŠøŠ¼ŠµŃ‚ŃŒ значение 'true', чтобы Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Š»Š¾ŃŃŒ ŃŃ‚Š¾ преГставление", "vscode.extension.contributes.views": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ в реГактор", "views.explorer": "ŠŸŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŠµ провоГника", + "views.debug": "ŠŸŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŠµ отлаГки", "locationId.invalid": "\"{0}\" не ŃŠ²Š»ŃŠµŃ‚ŃŃ Š“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¼ расположением ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŠµŠ½ŠøŃ" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index a9a867d8cd5..ecf6b925d61 100644 --- a/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "Š—Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ", "welcomePage.newFile": "Š”Š¾Š·Š“Š°Ń‚ŃŒ файл", "welcomePage.openFolder": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ папку...", - "welcomePage.cloneGitRepository": "ŠšŠ»Š¾Š½ŠøŃ€Š¾Š²Š°Ń‚ŃŒ репозиторий Git...", + "welcomePage.addWorkspaceFolder": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ папку в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ...", "welcomePage.recent": "ПослеГние", "welcomePage.moreRecent": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ...", "welcomePage.noRecentFolders": "ŠŠµŃ‚ послеГних папок.", diff --git a/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json index 23cea88a1ce..d11a8867da1 100644 --- a/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.i18n.json @@ -8,5 +8,6 @@ "workbench.startupEditor.none": "Š—Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ без реГактора.", "workbench.startupEditor.welcomePage": "ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ ŃŃ‚Ń€Š°Š½ŠøŃ†Ńƒ ŠæŃ€ŠøŠ²ŠµŃ‚ŃŃ‚Š²ŠøŃ (по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ).", "workbench.startupEditor.newUntitledFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ новый файл без Š½Š°Š·Š²Š°Š½ŠøŃ.", + "workbench.startupEditor": "ŠžŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚, какой реГактор Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ при запуске, если реГактор не был восстановлен ŠøŠ· ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠ³Š¾ сеанса. Укажите 'none', чтобы не Š·Š°ŠæŃƒŃŠŗŠ°Ń‚ŃŒ реГактор, 'welcomePage', чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ ŃŃ‚Ń€Š°Š½ŠøŃ†Ńƒ ŠæŃ€ŠøŠ²ŠµŃ‚ŃŃ‚Š²ŠøŃ (по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ), Šø 'newUntitledFile', чтобы Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ новый файл без Š½Š°Š·Š²Š°Š½ŠøŃ (Ń‚Š¾Š»ŃŒŠŗŠ¾ при открытии ŠæŃƒŃŃ‚ой рабочей области).", "help": "Дправка" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index 47a6fd1a229..83a72146fa4 100644 --- a/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Azure", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/rus/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/rus/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index d5a3ca1e7d7..3f6384ee226 100644 --- a/i18n/rus/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "Š˜Š½Ń‚ŠµŃ€Š°ŠŗŃ‚ŠøŠ²Š½Š°Ń площаГка", - "editorWalkThrough.title": "Š˜Š½Ń‚ŠµŃ€Š°ŠŗŃ‚ŠøŠ²Š½Š°Ń площаГка" + "editorWalkThrough.title": "Š˜Š½Ń‚ŠµŃ€Š°ŠŗŃ‚ŠøŠ²Š½Š°Ń площаГка", + "editorWalkThrough": "Š˜Š½Ń‚ŠµŃ€Š°ŠŗŃ‚ŠøŠ²Š½Š°Ń площаГка" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/rus/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..42442e0f21a --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "ŠšŃ€Š°Ń‚ŠŗŠ°Ń своГка параметров. Эта метка Š±ŃƒŠ“ет ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒŃŃ в файле параметров в качестве Ń€Š°Š·Š“ŠµŠ»ŃŃŽŃ‰ŠµŠ³Š¾ ŠŗŠ¾Š¼Š¼ŠµŠ½Ń‚Š°Ń€ŠøŃ.", + "vscode.extension.contributes.configuration.properties": "ŠžŠæŠøŃŠ°Š½ŠøŠµ свойств ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø.", + "scope.window.description": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ окна, ŠŗŠ¾Ń‚Š¾Ń€Š°Ń может Š±Ń‹Ń‚ŃŒ заГана в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń или рабочей области.", + "scope.resource.description": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø Ń€ŠµŃŃƒŃ€ŃŠ¾Š², которые Š¼Š¾Š³ŃƒŃ‚ Š±Ń‹Ń‚ŃŒ заГаны в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŠµŠ¹, рабочих областей или папок.", + "scope.description": "ŠžŠ±Š»Š°ŃŃ‚ŃŒ, в которой ŠæŃ€ŠøŠ¼ŠµŠ½ŃŠµŃ‚ся ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ. Š”Š¾ŃŃ‚ŃƒŠæŠ½Ń‹Šµ области — 'window' Šø 'resource'.", + "vscode.extension.contributes.configuration": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ параметры ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø.", + "invalid.title": "configuration.title Голжно Š±Ń‹Ń‚ŃŒ строкой", + "vscode.extension.contributes.defaultConfiguration": "ŠŸŃ€ŠµŠ“Š¾ŃŃ‚Š°Š²Š»ŃŠµŃ‚ параметры ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø реГактора по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ в соответствии с ŃŠ·Ń‹ŠŗŠ¾Š¼.", + "invalid.properties": "configuration.properties Голжно Š±Ń‹Ń‚ŃŒ Š¾Š±ŃŠŠµŠŗŃ‚Š¾Š¼", + "invalid.allOf": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ 'configuration.allOf' ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼, Šø ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ его не Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŃ‚ŃŃ. Вместо ŃŃ‚Š¾Š³Š¾ переГайте несколько параметров в виГе массива в Ń‚Š¾Ń‡ŠŗŃƒ вклаГа 'configuration'.", + "workspaceConfig.folders.description": "Дписок папок, которые Š±ŃƒŠ“ŃƒŃ‚ Š·Š°Š³Ń€ŃƒŠ¶ŠµŠ½Ń‹ в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ.", + "workspaceConfig.path.description": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ, например, \"/root/folderA\" или \"./folderA\" Š“Š»Ń ŠæŃƒŃ‚Šø по Š¾Ń‚Š½Š¾ŃˆŠµŠ½ŠøŃŽ Šŗ Ń„Š°Š¹Š»Ńƒ рабочей области.", + "workspaceConfig.name.description": "ŠŠµŠ¾Š±ŃŠ·Š°Ń‚ŠµŠ»ŃŒŠ½Š¾Šµ ŠøŠ¼Ń папки.", + "workspaceConfig.extensions.description": "Š Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ рабочей области", + "unknownWorkspaceProperty": "ŠŠµŠøŠ·Š²ŠµŃŃ‚Š½Š¾Šµ свойство рабочей области" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json index a74bc2f57d9..8915524eb9b 100644 --- a/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,11 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ параметры ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø.", "vscode.extension.contributes.configuration.title": "ŠšŃ€Š°Ń‚ŠŗŠ°Ń своГка параметров. Эта метка Š±ŃƒŠ“ет ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒŃŃ в файле параметров в качестве Ń€Š°Š·Š“ŠµŠ»ŃŃŽŃ‰ŠµŠ³Š¾ ŠŗŠ¾Š¼Š¼ŠµŠ½Ń‚Š°Ń€ŠøŃ.", "vscode.extension.contributes.configuration.properties": "ŠžŠæŠøŃŠ°Š½ŠøŠµ свойств ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø.", - "invalid.type": "Если тип configuration.type заГан, то он Голжен ŠøŠ¼ŠµŃ‚ŃŒ значение object", + "scope.window.description": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ окна, ŠŗŠ¾Ń‚Š¾Ń€Š°Ń может Š±Ń‹Ń‚ŃŒ заГана в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń или рабочей области.", + "scope.resource.description": "ŠšŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø Ń€ŠµŃŃƒŃ€ŃŠ¾Š², которые Š¼Š¾Š³ŃƒŃ‚ Š±Ń‹Ń‚ŃŒ заГаны в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŠµŠ¹, рабочих областей или папок.", + "scope.description": "ŠžŠ±Š»Š°ŃŃ‚ŃŒ, в которой ŠæŃ€ŠøŠ¼ŠµŠ½ŃŠµŃ‚ся ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃ. Š”Š¾ŃŃ‚ŃƒŠæŠ½Ń‹Šµ области — 'window' Šø 'resource'.", + "vscode.extension.contributes.configuration": "Š”Š¾Š±Š°Š²Š»ŃŠµŃ‚ параметры ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø.", "invalid.title": "configuration.title Голжно Š±Ń‹Ń‚ŃŒ строкой", "vscode.extension.contributes.defaultConfiguration": "ŠŸŃ€ŠµŠ“Š¾ŃŃ‚Š°Š²Š»ŃŠµŃ‚ параметры ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø реГактора по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ в соответствии с ŃŠ·Ń‹ŠŗŠ¾Š¼.", - "invalid.properties": "configuration.properties Голжно Š±Ń‹Ń‚ŃŒ Š¾Š±ŃŠŠµŠŗŃ‚Š¾Š¼" + "invalid.properties": "configuration.properties Голжно Š±Ń‹Ń‚ŃŒ Š¾Š±ŃŠŠµŠŗŃ‚Š¾Š¼", + "invalid.allOf": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ 'configuration.allOf' ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŃŃ‚Š°Ń€ŠµŠ²ŃˆŠøŠ¼, Šø ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ его не Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŃ‚ŃŃ. Вместо ŃŃ‚Š¾Š³Š¾ переГайте несколько параметров в виГе массива в Ń‚Š¾Ń‡ŠŗŃƒ вклаГа 'configuration'.", + "workspaceConfig.folders.description": "Дписок папок, которые Š±ŃƒŠ“ŃƒŃ‚ Š·Š°Š³Ń€ŃƒŠ¶ŠµŠ½Ń‹ в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ.", + "workspaceConfig.path.description": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ, например, \"/root/folderA\" или \"./folderA\" Š“Š»Ń ŠæŃƒŃ‚Šø по Š¾Ń‚Š½Š¾ŃˆŠµŠ½ŠøŃŽ Šŗ Ń„Š°Š¹Š»Ńƒ рабочей области.", + "workspaceConfig.name.description": "ŠŠµŠ¾Š±ŃŠ·Š°Ń‚ŠµŠ»ŃŒŠ½Š¾Šµ ŠøŠ¼Ń папки.", + "workspaceConfig.uri.description": "URI папки", + "workspaceConfig.settings.description": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ рабочей области", + "workspaceConfig.extensions.description": "Š Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ рабочей области", + "unknownWorkspaceProperty": "ŠŠµŠøŠ·Š²ŠµŃŃ‚Š½Š¾Šµ свойство рабочей области" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/rus/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index 0d0c909172d..6d87ae00932 100644 --- a/i18n/rus/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/rus/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,13 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ параметры", + "openTasksConfiguration": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ заГач", + "openLaunchConfiguration": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŃŽ запуска", "close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", - "saveAndRetry": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ параметры Šø ŠæŠ¾Š²Ń‚Š¾Ń€ŠøŃ‚ŃŒ ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ", - "errorInvalidConfiguration": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл **User Settings**, ŃƒŃŃ‚Ń€Š°Š½ŠøŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ в файле Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", - "errorInvalidConfigurationWorkspace": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл **Workspace Settings**, ŃƒŃŃ‚Ń€Š°Š½ŠøŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ в файле Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", - "errorConfigurationFileDirty": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры, так как файл был изменен. Дохраните файл **User Settings** Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", - "errorConfigurationFileDirtyWorkspace": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры, так как файл был изменен. Дохраните файл **Workspace Settings** Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "open": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ параметры", + "saveAndRetry": "Š”Š¾Ń…Ń€Š°Š½ŠøŃ‚ŃŒ Šø ŠæŠ¾Š²Ń‚Š¾Ń€ŠøŃ‚ŃŒ", + "errorUnknownKey": "ŠŠµ уГалось Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ в {0}, так как {1} не ŃŠ²Š»ŃŠµŃ‚ŃŃ зарегистрированной ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠµŠ¹.", + "errorInvalidFolderConfiguration": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ параметры папок, так как {0} не поГГерживает Š¾Š±Š»Š°ŃŃ‚ŃŒ Ń€ŠµŃŃƒŃ€ŃŠ¾Š² папок. ", + "errorInvalidUserTarget": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ параметры ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŠµŠ¹, так как {0} не поГГерживает Š³Š»Š¾Š±Š°Š»ŃŒŠ½ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ.", + "errorInvalidFolderTarget": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ параметры папок, так как Ń€ŠµŃŃƒŃ€Ń не указан.", + "errorNoWorkspaceOpened": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ в {0}, так как не открыта ни оГна Ń€Š°Š±Š¾Ń‡Š°Ń Š¾Š±Š»Š°ŃŃ‚ŃŒ. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "errorInvalidTaskConfiguration": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись в файл заГач. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл **Tasks**, ŠøŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "errorInvalidLaunchConfiguration": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись в файл запуска. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл **Launch**, ŠøŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ. ", + "errorInvalidConfiguration": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись в файл параметров ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл **User Settings**, ŠøŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ. ", + "errorInvalidConfigurationWorkspace": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись в файл параметров рабочей области. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл **Workspace Settings**, ŠøŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ. ", + "errorInvalidConfigurationFolder": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись в файл параметров папок. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл **Folder Settings** в папке **{0}**, ŠøŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ. ", + "errorTasksConfigurationFileDirty": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись параметров в файл заГач, так как файл был изменен. Дохраните файл **Tasks Configuration** Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "errorLaunchConfigurationFileDirty": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись в файл запуска, так как файл был изменен. Дохраните файл **Launch Configuration** Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "errorConfigurationFileDirty": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń, так как файл был изменен. Дохраните файл **User Settings** Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "errorConfigurationFileDirtyWorkspace": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры рабочей области, так как файл был изменен. Дохраните файл **Workspace Settings** Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ. ", + "errorConfigurationFileDirtyFolder": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ параметры папок, так как файл был изменен. Дохраните файл **Folder Settings** в папке **{0}** Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ. ", "userTarget": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń", - "workspaceTarget": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ рабочей области" + "workspaceTarget": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ рабочей области", + "folderTarget": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Ń‹ папок" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json b/i18n/rus/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json index 8b6ad71cd4e..8463d1762c1 100644 --- a/i18n/rus/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json +++ b/i18n/rus/src/vs/workbench/services/configuration/node/jsonEditingService.i18n.json @@ -3,4 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "errorInvalidFile": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š²Ń‹ŠæŠ¾Š»Š½ŠøŃ‚ŃŒ запись в файл. ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ файл, ŠøŃŠæŃ€Š°Š²ŃŒŃ‚Šµ ошибки Šø ŠæŃ€ŠµŠ“ŃƒŠæŃ€ŠµŠ¶Š“ŠµŠ½ŠøŃ в файле Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", + "errorFileDirty": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š·Š°ŠæŠøŃŠ°Ń‚ŃŒ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ в файл, так как файл был изменен. Дохраните файл Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/rus/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/rus/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..34e6efd6686 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "Єост-процесс Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹ не был Š·Š°ŠæŃƒŃ‰ŠµŠ½ в течение 10 секунГ. Возможно, он был остановлен в первой строке, а Š“Š»Ń ŠæŃ€Š¾Š“Š¾Š»Š¶ŠµŠ½ŠøŃ Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ отлаГчик.", + "extensionHostProcess.startupFail": "Єост-процесс Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹ не Š·Š°ŠæŃƒŃŃ‚ŠøŠ»ŃŃ ŃŠæŃƒŃŃ‚Ń 10 секунГ. Возможно, ŠæŃ€Š¾ŠøŠ·Š¾ŃˆŠ»Š° ошибка.", + "extensionHostProcess.error": "ŠžŃˆŠøŠ±ŠŗŠ° в хост-процессе Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹: {0}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..b3a07f32520 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "ŠŠµ уГалось ŠæŃ€Š¾Š°Š½Š°Š»ŠøŠ·ŠøŃ€Š¾Š²Š°Ń‚ŃŒ {0}: {1}.", + "fileReadFail": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ ŠæŃ€Š¾Ń‡ŠøŃ‚Š°Ń‚ŃŒ файл {0}: {1}.", + "jsonsParseFail": "ŠŠµ уГалось ŠæŃ€Š¾Š°Š½Š°Š»ŠøŠ·ŠøŃ€Š¾Š²Š°Ń‚ŃŒ {0} или {1}: {2}.", + "missingNLSKey": "ŠŠµ уГалось найти сообщение Š“Š»Ń ŠŗŠ»ŃŽŃ‡Š° {0}." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..592a962b099 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "ДреГства разработчика", + "restart": "ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ хост-процесс Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹", + "extensionHostProcess.crash": "Єост-процесс Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹ неожиГанно Š·Š°Š²ŠµŃ€ŃˆŠøŠ» Ń€Š°Š±Š¾Ń‚Ńƒ.", + "extensionHostProcess.unresponsiveCrash": "Работа хост-процесса Š“Š»Ń Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠ¹ была Š·Š°Š²ŠµŃ€ŃˆŠµŠ½Š°, так как он перестал Š¾Ń‚Š²ŠµŃ‡Š°Ń‚ŃŒ на запросы.", + "overwritingExtension": "Š˜Š“ŠµŃ‚ ŠæŠµŃ€ŠµŠ·Š°ŠæŠøŃŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ {0} на {1}.", + "extensionUnderDevelopment": "Š˜Š“ŠµŃ‚ Š·Š°Š³Ń€ŃƒŠ·ŠŗŠ° Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ разработки в {0}." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/rus/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..54fbd1ada7b --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "ŠŸŠ¾Ń…Š¾Š¶Šµ, файл ŃŠ²Š»ŃŠµŃ‚ŃŃ Гвоичным, Šø его Š½ŠµŠ»ŃŒŠ·Ń Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ как текстовый." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/rus/src/vs/workbench/services/files/node/fileService.i18n.json index e3ae0bc304d..6e032cd3874 100644 --- a/i18n/rus/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/rus/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "ŠŠµŠ“Š¾ŠæŃƒŃŃ‚ŠøŠ¼Ń‹Š¹ Ń€ŠµŃŃƒŃ€Ń файла ({0})", - "fileIsDirectoryError": "Файл ŃŠ²Š»ŃŠµŃ‚ŃŃ каталогом ({0})", + "fileIsDirectoryError": "Файл ŃŠ²Š»ŃŠµŃ‚ŃŃ каталогом", "fileNotModifiedError": "undefined", "fileTooLargeError": "ŠŠµ ŃƒŠ“Š°ŠµŃ‚ŃŃ Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ файл, так как он имеет слишком большой размер", "fileBinaryError": "ŠŸŠ¾Ń…Š¾Š¶Šµ, файл ŃŠ²Š»ŃŠµŃ‚ŃŃ Гвоичным, Šø его Š½ŠµŠ»ŃŒŠ·Ń Š¾Ń‚ŠŗŃ€Ń‹Ń‚ŃŒ как текстовый.", "fileNotFoundError": "Файл не найГен ({0})", + "fileExists": "ДозГаваемый файл уже ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚ ({0})", "fileMoveConflict": "ŠŠµŠ²Š¾Š·Š¼Š¾Š¶Š½Š¾ ŠæŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ или ŃŠŗŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ файл, так как он уже ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŠµŃ‚ в папке Š½Š°Š·Š½Š°Ń‡ŠµŠ½ŠøŃ.", "unableToMoveCopyError": "ŠŠµŠ²Š¾Š·Š¼Š¾Š¶Š½Š¾ ŠæŠµŃ€ŠµŠ¼ŠµŃŃ‚ŠøŃ‚ŃŒ или ŃŠŗŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ файл, так как он заменил бы папку, в которой ŃŠ¾Š“ŠµŃ€Š¶ŠøŃ‚ŃŃ.", "foldersCopyError": "Папки Š½ŠµŠ»ŃŒŠ·Ń ŠŗŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ в Ń€Š°Š±Š¾Ń‡ŃƒŃŽ Š¾Š±Š»Š°ŃŃ‚ŃŒ. Выберите Š¾Ń‚Š“ŠµŠ»ŃŒŠ½Ń‹Šµ файлы, чтобы ŃŠŗŠ¾ŠæŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŠøŃ….", diff --git a/i18n/rus/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/rus/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/rus/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/rus/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/rus/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index 63c693a5849..16f8c52e622 100644 --- a/i18n/rus/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/rus/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "ŠŠ°Ń‡ŠµŃ€Ń‚Š°Š½ŠøŠµ ŃˆŃ€ŠøŃ„Ń‚Š° Š“Š»Ń правила: оГин либо сочетание ŠŗŃƒŃ€ŃŠøŠ²Š°, ŠæŠ¾Š»ŃƒŠ¶ŠøŃ€Š½Š¾Š³Š¾ Šø ŠæŠ¾Š“Ń‡ŠµŃ€ŠŗŠøŠ²Š°Š½ŠøŃ.", - "schema.colors": "Цвета Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ синтаксических ŠŗŠ¾Š½ŃŃ‚Ń€ŃƒŠŗŃ†ŠøŠ¹", - "schema.properties.name": "ŠžŠæŠøŃŠ°Š½ŠøŠµ правила", - "schema.tokenColors.path": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ tmTheme (по Š¾Ń‚Š½Š¾ŃˆŠµŠ½ŠøŃŽ Šŗ Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¼Ńƒ Ń„Š°Š¹Š»Ńƒ)" + "schema.token.settings": "Цвета Šø стили Š“Š»Ń маркера.", + "schema.token.foreground": "Цвет переГнего плана Š“Š»Ń маркера.", + "schema.token.fontStyle": "ŠŠ°Ń‡ŠµŃ€Ń‚Š°Š½ŠøŠµ ŃˆŃ€ŠøŃ„Ń‚Š° Š“Š»Ń правила: оГин либо сочетание ŠŗŃƒŃ€ŃŠøŠ²Š°, ŠæŠ¾Š»ŃƒŠ¶ŠøŃ€Š½Š¾Š³Š¾ Šø ŠæŠ¾Š“Ń‡ŠµŃ€ŠŗŠøŠ²Š°Š½ŠøŃ.", + "schema.fontStyle.error": "Š”Ń‚ŠøŠ»ŃŒ ŃˆŃ€ŠøŃ„Ń‚Š° Голжен ŠæŃ€ŠµŠ“ŃŃ‚Š°Š²Š»ŃŃ‚ŃŒ собой сочетание свойств 'italic', 'bold' Šø 'underline'", + "schema.properties.name": "ŠžŠæŠøŃŠ°Š½ŠøŠµ правила.", + "schema.properties.scope": "ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡Š°Ń‚ŠµŠ»ŃŒ области, Š“Š»Ń которой ŠæŃ€Š¾Š²ŠµŃ€ŃŠµŃ‚ся ŃŃ‚Š¾ правило.", + "schema.tokenColors.path": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ tmTheme (Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ Ń‚ŠµŠŗŃƒŃ‰ŠµŠ³Š¾ файла).", + "schema.colors": "Цвета Š“Š»Ń Š²Ń‹Š“ŠµŠ»ŠµŠ½ŠøŃ синтаксических ŠŗŠ¾Š½ŃŃ‚Ń€ŃƒŠŗŃ†ŠøŠ¹" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index ac6d9076357..b5a06fd68d0 100644 --- a/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "Возникли проблемы при анализе файла JSON THEME: {0}.", "error.invalidformat.colors": "ŠžŃˆŠøŠ±ŠŗŠ° при анализе файла цветовой темы: {0}. Двойство 'colors' не имеет тип 'object'.", - "error.invalidformat.tokenColors": "ŠžŃˆŠøŠ±ŠŗŠ° при анализе файла цветовой темы: {0}. Двойство 'tokenColors' Голжно ŃŠ¾Š“ŠµŃ€Š¶Š°Ń‚ŃŒ массив цветов или ŠæŃƒŃ‚ŃŒ Šŗ Ń‚ŠµŠŗŃŃ‚Š¾Š²Š¾Š¼Ńƒ Ń„Š°Š¹Š»Ńƒ цветовой темы", + "error.invalidformat.tokenColors": "ŠžŃˆŠøŠ±ŠŗŠ° при анализе файла цветовой темы: {0}. Двойство 'tokenColors' Голжно ŃŠ¾Š“ŠµŃ€Š¶Š°Ń‚ŃŒ массив цветов или ŠæŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ темы TextMate", "error.plist.invalidformat": "ŠžŃˆŠøŠ±ŠŗŠ° при анализе файла tmTheme: {0}. 'settings' не ŃŠ²Š»ŃŠµŃ‚ŃŃ массивом.", "error.cannotparse": "ŠžŃˆŠøŠ±ŠŗŠ° при анализе файла tmTheme: {0}", "error.cannotload": "ŠžŃˆŠøŠ±ŠŗŠ° при Š·Š°Š³Ń€ŃƒŠ·ŠŗŠµ файла tmTheme {0}: {1}" diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..c91d95429ee --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Contributes textmate color themes.", + "vscode.extension.contributes.themes.id": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€ темы значка, как ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń.", + "vscode.extension.contributes.themes.label": "ŠœŠµŃ‚ŠŗŠ° цветовой схемы, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŠ¼Š°Ń в ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠ¾Š¼ интерфейсе.", + "vscode.extension.contributes.themes.uiTheme": "Š‘Š°Š·Š¾Š²Š°Ń тема, Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŃŽŃ‰Š°Ń цвета Š¾Ń„Š¾Ń€Š¼Š»ŠµŠ½ŠøŃ реГактора: \"vs\" — ŃŠ²ŠµŃ‚Š»Š°Ń Ń†Š²ŠµŃ‚Š¾Š²Š°Ń тема, \"vs-dark\" — Ń‚ŠµŠ¼Š½Š°Ń Ń†Š²ŠµŃ‚Š¾Š²Š°Ń тема. \"hc-black\" — Ń‚ŠµŠ¼Š½Š°Ń Š²Ń‹ŃŠ¾ŠŗŠ¾ŠŗŠ¾Š½Ń‚Ń€Š°ŃŃ‚Š½Š°Ń тема.", + "vscode.extension.contributes.themes.path": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ tmTheme. ŠŸŃƒŃ‚ŃŒ ŃƒŠŗŠ°Š·Ń‹Š²Š°ŠµŃ‚ŃŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ папки Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Šø имеет виГ \"./themes/themeFile.tmTheme\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Š’ contributes.{0}.path Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ строка. Указанное значение: {1}", + "invalid.path.1": "contributes.{0}.path ({1}) Голжен был Š±Ń‹Ń‚ŃŒ Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ в папку Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ ({2}). Это может ŃŠ“ŠµŠ»Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ непереносимым." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..b0f9faf6b52 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Problems parsing file icons file: {0}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..d03dc07b9a9 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", + "vscode.extension.contributes.iconThemes.id": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€ темы значка, как ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń.", + "vscode.extension.contributes.iconThemes.label": "ŠœŠµŃ‚ŠŗŠ° темы значка, как Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ в ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠ¾Š¼ интерфейсе.", + "vscode.extension.contributes.iconThemes.path": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠµŠ½ŠøŃ темы значка. ŠŸŃƒŃ‚ŃŒ Š·Š°Š“Š°ŠµŃ‚ŃŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ папки Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Šø, как правило, имеет ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠ¹ виГ: \"./icons/awesome-icon-theme.json\".", + "reqarray": "Extension point `{0}` must be an array.", + "reqpath": "Š’ contributes.{0}.path Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ строка. Указанное значение: {1}", + "reqid": "ŠžŠ¶ŠøŠ“Š°Š»Š°ŃŃŒ строка в \"contributes.{0}.id\". Указанное значение: {1}", + "invalid.path.1": "contributes.{0}.path ({1}) Голжен был Š±Ń‹Ń‚ŃŒ Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ в папку Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ ({2}). Это может ŃŠ“ŠµŠ»Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ непереносимым." +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index 9a03e746560..e2aef412ef5 100644 --- a/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/rus/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,29 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Contributes textmate color themes.", - "vscode.extension.contributes.themes.id": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€ темы значка, как ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń.", - "vscode.extension.contributes.themes.label": "ŠœŠµŃ‚ŠŗŠ° цветовой схемы, Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŠ¼Š°Ń в ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠ¾Š¼ интерфейсе.", - "vscode.extension.contributes.themes.uiTheme": "Š‘Š°Š·Š¾Š²Š°Ń тема, Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŃŽŃ‰Š°Ń цвета Š¾Ń„Š¾Ń€Š¼Š»ŠµŠ½ŠøŃ реГактора: \"vs\" — ŃŠ²ŠµŃ‚Š»Š°Ń Ń†Š²ŠµŃ‚Š¾Š²Š°Ń тема, \"vs-dark\" — Ń‚ŠµŠ¼Š½Š°Ń Ń†Š²ŠµŃ‚Š¾Š²Š°Ń тема. \"hc-black\" — Ń‚ŠµŠ¼Š½Š°Ń Š²Ń‹ŃŠ¾ŠŗŠ¾ŠŗŠ¾Š½Ń‚Ń€Š°ŃŃ‚Š½Š°Ń тема.", - "vscode.extension.contributes.themes.path": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ tmTheme. ŠŸŃƒŃ‚ŃŒ ŃƒŠŗŠ°Š·Ń‹Š²Š°ŠµŃ‚ŃŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ папки Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Šø имеет виГ \"./themes/themeFile.tmTheme\".", - "vscode.extension.contributes.iconThemes": "Contributes file icon themes.", - "vscode.extension.contributes.iconThemes.id": "Š˜Š“ŠµŠ½Ń‚ŠøŃ„ŠøŠŗŠ°Ń‚Š¾Ń€ темы значка, как ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ся в параметрах ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń.", - "vscode.extension.contributes.iconThemes.label": "ŠœŠµŃ‚ŠŗŠ° темы значка, как Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°ŠµŃ‚ŃŃ в ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠ¾Š¼ интерфейсе.", - "vscode.extension.contributes.iconThemes.path": "ŠŸŃƒŃ‚ŃŒ Šŗ Ń„Š°Š¹Š»Ńƒ Š¾ŠæŃ€ŠµŠ“ŠµŠ»ŠµŠ½ŠøŃ темы значка. ŠŸŃƒŃ‚ŃŒ Š·Š°Š“Š°ŠµŃ‚ŃŃ Š¾Ń‚Š½Š¾ŃŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ папки Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ Šø, как правило, имеет ŃŠ»ŠµŠ“ŃƒŃŽŃ‰ŠøŠ¹ виГ: \"./icons/awesome-icon-theme.json\".", "migration.completed": "Š’ параметры ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»Ń были Гобавлены новые параметры темы. Š ŠµŠ·ŠµŃ€Š²Š½Š°Ń ŠŗŠ¾ŠæŠøŃ Š“Š¾ŃŃ‚ŃƒŠæŠ½Š° в {0}.", "error.cannotloadtheme": "Unable to load {0}: {1}", - "reqarray": "Extension point `{0}` must be an array.", - "reqpath": "Š’ contributes.{0}.path Ń‚Ń€ŠµŠ±ŃƒŠµŃ‚ŃŃ строка. Указанное значение: {1}", - "invalid.path.1": "contributes.{0}.path ({1}) Голжен был Š±Ń‹Ń‚ŃŒ Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½ в папку Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŃ ({2}). Это может ŃŠ“ŠµŠ»Š°Ń‚ŃŒ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ непереносимым.", - "reqid": "ŠžŠ¶ŠøŠ“Š°Š»Š°ŃŃŒ строка в \"contributes.{0}.id\". Указанное значение: {1}", "error.cannotloadicontheme": "Unable to load {0}", - "error.cannotparseicontheme": "Problems parsing file icons file: {0}", "colorTheme": "Specifies the color theme used in the workbench.", "colorThemeError": "Theme is unknown or not installed.", "iconTheme": "Указывает Ń‚ŠµŠ¼Ńƒ значков, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŠ¼ŃƒŃŽ в рабочей области. Чтобы значки файлов не Š¾Ń‚Š¾Š±Ń€Š°Š¶Š°Š»ŠøŃŃŒ, ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ значение 'null'.", "noIconThemeDesc": "No file icons", "iconThemeError": "File icon theme is unknown or not installed.", "workbenchColors": "ŠŸŠµŃ€ŠµŠ¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ цвета ŠøŠ· выбранной цветовой темы.", - "workbenchColors.deprecated": "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€ больше не ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃŠŗŃŠæŠµŃ€ŠøŠ¼ŠµŠ½Ń‚Š°Š»ŃŒŠ½Ń‹Š¼ Šø был переименован в 'workbench.colorCustomizations'", - "workbenchColors.deprecatedDescription": "Š˜ŃŠæŠ¾Š»ŃŒŠ·ŃƒŠ¹Ń‚Šµ параметр 'workbench.colorCustomizations'" + "editorColors": "ŠŸŠµŃ€ŠµŠ¾ŠæŃ€ŠµŠ“ŠµŠ»ŃŠµŃ‚ цвета реГактора Šø ŃŃ‚ŠøŠ»ŃŒ ŃˆŃ€ŠøŃ„Ń‚Š° ŠøŠ· Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¹ выбранной цветовой темы.", + "editorColors.comments": "ЗаГает цвета Šø стили Š“Š»Ń комментариев", + "editorColors.strings": "ЗаГает цвета Šø стили Š“Š»Ń строковых литералов.", + "editorColors.keywords": "ЗаГает цвета Šø стили Š“Š»Ń ŠŗŠ»ŃŽŃ‡ŠµŠ²Ń‹Ń… слов.", + "editorColors.numbers": "ЗаГает цвета Šø стили Š“Š»Ń числовых литералов. ", + "editorColors.types": "ЗаГает цвета Šø стили Š“Š»Ń Š¾Š±ŃŠŃŠ²Š»ŠµŠ½ŠøŠ¹ типов Šø ссылок. ", + "editorColors.functions": "ЗаГает цвета Šø стили Š“Š»Ń Š¾Š±ŃŠŃŠ²Š»ŠµŠ½ŠøŠ¹ Ń„ŃƒŠ½ŠŗŃ†ŠøŠ¹ Šø ссылок. ", + "editorColors.variables": "ЗаГает цвета Šø стили Š“Š»Ń Š¾Š±ŃŠŃŠ²Š»ŠµŠ½ŠøŠ¹ переменных Šø Š“Š»Ń ссылок. ", + "editorColors.textMateRules": "ЗаГает цвета Šø стили с использованием правил Š¾Ń„Š¾Ń€Š¼Š»ŠµŠ½ŠøŃ textmate (Ń€Š°ŃŃˆŠøŃ€ŠµŠ½Š½Ń‹Š¹ параметр)." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/rus/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..27cc6bcc674 --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "openWorkspaceConfigurationFile": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ файл ŠŗŠ¾Š½Ń„ŠøŠ³ŃƒŃ€Š°Ń†ŠøŠø рабочей области", + "close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", + "enterWorkspace.close": "Š—Š°ŠŗŃ€Ń‹Ń‚ŃŒ", + "enterWorkspace.dontShowAgain": "Š‘Š¾Š»ŃŒŃˆŠµ не ŠæŠ¾ŠŗŠ°Š·Ń‹Š²Š°Ń‚ŃŒ", + "enterWorkspace.moreInfo": "Š”Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Šµ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ" +} \ No newline at end of file diff --git a/i18n/trk/extensions/azure-account/out/azure-account.i18n.json b/i18n/trk/extensions/azure-account/out/azure-account.i18n.json new file mode 100644 index 00000000000..83a29fc7089 --- /dev/null +++ b/i18n/trk/extensions/azure-account/out/azure-account.i18n.json @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.copyAndOpen": "Kopyala & AƧ", + "azure-account.close": "Kapat", + "azure-account.login": "Oturum AƧ", + "azure-account.loginFirst": "Oturum aƧılmamış, ilk olarak oturum aƧın.", + "azure-account.userCodeFailed": "Kullanıcı kodu alımı başarısız oldu", + "azure-account.tokenFailed": "Cihaz kodu ile anahtar alınıyor", + "azure-account.tokenFromRefreshTokenFailed": "Yenileme anahtarı ile anahtar alınıyor" +} \ No newline at end of file diff --git a/i18n/trk/extensions/azure-account/out/extension.i18n.json b/i18n/trk/extensions/azure-account/out/extension.i18n.json new file mode 100644 index 00000000000..68e607e17d3 --- /dev/null +++ b/i18n/trk/extensions/azure-account/out/extension.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "azure-account.loggingIn": "Azure: Oturum aƧılıyor...", + "azure-account.loggedIn": "Azure: {0}" +} \ No newline at end of file diff --git a/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json b/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json index cffb38fa05c..b536f2a04c4 100644 --- a/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json +++ b/i18n/trk/extensions/configuration-editing/out/settingsDocumentHelper.i18n.json @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "activeEditorShort": "ƶr. myFile.txt", - "activeEditorMedium": "ƶr. myFolder/myFile.txt", - "activeEditorLong": "ƶr. /Users/Development/myProject/myFolder/myFile.txt", - "rootName": "ƶr: myFolder1, myFolder2, myFolder3", - "rootPath": "ƶr. /Users/Development/myProject", - "folderName": "ƶr: myFolder", - "folderPath": "ƶr: /Users/Development/myFolder", + "activeEditorShort": "dosya adı (ƶr. dosyam.txt)", + "activeEditorMedium": "Ƨalışma alanı klasƶrüne gƶreli dosyanın yolu (ƶr. klasorum/dosyam.txt)", + "activeEditorLong": "dosyanın tam yolu (ƶr. /Users/Development/myProject/myFolder/myFile.txt)", + "rootName": "Ƨalışma alanının adı (ƶr. klasorum veya calismaAlanim)", + "rootPath": "Ƨalışma alanının yolu (ƶr. /Users/Development/myWorkspace)", + "folderName": "dosyayı iƧeren Ƨalışma alanı klasƶrünün adı (ƶr. myFolder)", + "folderPath": "dosyayı iƧeren Ƨalışma alanı klasƶrünün yolu (ƶr. /Users/Development/myFolder)", "appName": "ƶr. VS Code", "dirty": "değişiklik gƶstergesi, aktif düzenleyici kaydedilmemiş değişiklikler iƧeriyorsa", "separator": "koşullu ayırıcı ('-') sadece değişkenler tarafından değerlerle Ƨevrildiğinde gƶsterir", diff --git a/i18n/trk/extensions/css/package.i18n.json b/i18n/trk/extensions/css/package.i18n.json index 215750e00ed..c3c20d04321 100644 --- a/i18n/trk/extensions/css/package.i18n.json +++ b/i18n/trk/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "GeƧersiz sayıda parametre", "css.lint.boxModel.desc": "Doldurma veya kenarlık kullanırken genişlik veya yükseklik kullanmayın", "css.lint.compatibleVendorPrefixes.desc": "Satıcıya ƶzgü bir ƶn ek kullanırken satıcıya ƶzgü diğer tüm ƶzellikleri de dahil ettiğinizden emin olun", @@ -22,7 +23,10 @@ "css.lint.unknownVendorSpecificProperties.desc": "Bilinmeyen satıcıya ƶzel ƶzellik.", "css.lint.vendorPrefix.desc": "Satıcıya ƶzgü bir ƶn ek kullanırken standart ƶzelliği de dahil edin", "css.lint.zeroUnits.desc": "Sıfır iƧin birim gerekmez", + "css.trace.server.desc": "VS Code ve CSS dil sunucusu arasındaki iletişimi izler.", + "css.validate.title": "CSS doğrulamasını ve sorunların ƶnem derecelerini denetler.", "css.validate.desc": "Tüm doğrulamaları etkinleştirir veya devre dışı bırakır", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "GeƧersiz sayıda parametre", "less.lint.boxModel.desc": "Doldurma veya kenarlık kullanırken genişlik veya yükseklik kullanmayın", "less.lint.compatibleVendorPrefixes.desc": "Satıcıya ƶzgü bir ƶn ek kullanırken satıcıya ƶzgü diğer tüm ƶzellikleri de dahil ettiğinizden emin olun", @@ -41,7 +45,9 @@ "less.lint.unknownVendorSpecificProperties.desc": "Bilinmeyen satıcıya ƶzel ƶzellik.", "less.lint.vendorPrefix.desc": "Satıcıya ƶzgü bir ƶn ek kullanırken standart ƶzelliği de dahil edin", "less.lint.zeroUnits.desc": "Sıfır iƧin birim gerekmez", + "less.validate.title": "LESS doğrulamasını ve sorunların ƶnem derecelerini denetler.", "less.validate.desc": "Tüm doğrulamaları etkinleştirir veya devre dışı bırakır", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "GeƧersiz sayıda parametre", "scss.lint.boxModel.desc": "Doldurma veya kenarlık kullanırken genişlik veya yükseklik kullanmayın", "scss.lint.compatibleVendorPrefixes.desc": "Satıcıya ƶzgü bir ƶn ek kullanırken satıcıya ƶzgü diğer tüm ƶzellikleri de dahil ettiğinizden emin olun", @@ -60,8 +66,12 @@ "scss.lint.unknownVendorSpecificProperties.desc": "Bilinmeyen satıcıya ƶzel ƶzellik.", "scss.lint.vendorPrefix.desc": "Satıcıya ƶzgü bir ƶn ek kullanırken standart ƶzelliği de dahil edin", "scss.lint.zeroUnits.desc": "Sıfır iƧin birim gerekmez", + "scss.validate.title": "SCSS doğrulamasını ve sorunların ƶnem derecelerini denetler.", "scss.validate.desc": "Tüm doğrulamaları etkinleştirir veya devre dışı bırakır", "less.colorDecorators.enable.desc": "Renk dekoratƶrlerini etkinleştirir veya devre dışı bırakır", "scss.colorDecorators.enable.desc": "Renk dekoratƶrlerini etkinleştirir veya devre dışı bırakır", - "css.colorDecorators.enable.desc": "Renk dekoratƶrlerini etkinleştirir veya devre dışı bırakır" + "css.colorDecorators.enable.desc": "Renk dekoratƶrlerini etkinleştirir veya devre dışı bırakır", + "css.colorDecorators.enable.deprecationMessage": "`css.colorDecorators.enable` ayarı, `editor.colorDecorators` yüzünden kullanım dışıdır.", + "scss.colorDecorators.enable.deprecationMessage": "`scss.colorDecorators.enable` ayarı, `editor.colorDecorators` yüzünden kullanım dışıdır.", + "less.colorDecorators.enable.deprecationMessage": "`less.colorDecorators.enable` ayarı, `editor.colorDecorators` yüzünden kullanım dışıdır." } \ No newline at end of file diff --git a/i18n/trk/extensions/emmet/package.i18n.json b/i18n/trk/extensions/emmet/package.i18n.json index bd568a64488..6ce7f81e59f 100644 --- a/i18n/trk/extensions/emmet/package.i18n.json +++ b/i18n/trk/extensions/emmet/package.i18n.json @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "command.wrapWithAbbreviation": "Kısaltma ile Sarmala", + "command.wrapIndividualLinesWithAbbreviation": "Her Bir Satırı Kısaltma ile Sarmala", "command.removeTag": "Etiketi Kaldır", "command.updateTag": "Etiketi Güncelle", "command.matchTag": "Eşleşen Ƈifte Git", @@ -24,5 +26,28 @@ "command.incrementNumberByOneTenth": "0.1 Arttır", "command.decrementNumberByOneTenth": "0.1 Azalt", "command.incrementNumberByTen": "10 Arttır", - "command.decrementNumberByTen": "10 Azalt" + "command.decrementNumberByTen": "10 Azalt", + "emmetSyntaxProfiles": "Belirtilen sentaks iƧin profil tanımlayın veya kendi profilinizi belirli kurallarla kullanın.", + "emmetExclude": "Emmet kısaltmalarının genişletilmeyeceği bir diller dizisi.", + "emmetExtensionsPath": "Emmet profileri ve parƧacıklarını iƧeren bir klasƶr yolu.'", + "emmetShowExpandedAbbreviation": "Genişletilmiş Emmet kısaltmalarını ƶneriler olarak gƶsterir.\n\"inMarkupAndStylesheetFilesOnly\" seƧeneği\" html, haml, jade, xml, xsl, css, scss, sass, less ve stylus'a uygulanır.\n\"always\" seƧeneği işaretleme/css'den bağımsız olarak dosyanın tüm bƶlümlerine uygulanır.", + "emmetShowAbbreviationSuggestions": "Olası Emmet kısaltmalarını ƶneriler olarak gƶsterir. Stil dosyalarında veya emmet.showExpandedAbbreviation, \"never\" olarak ayarlandığında uygulanamaz.", + "emmetIncludeLanguages": "Varsayılan olarak desteklenmeyen dillerde Emmet kısaltmalarını etkinleştirin. Burada dil ile desteklenen emmet destekli dil arasında eşleme ekleyin.", + "emmetVariables": "Emmet parƧacıklarında kullanılacak değişkenler", + "emmetTriggerExpansionOnTab": "Etkinleştirildiğinde, Emmet kısaltmaları TAB tuşuna basıldığında genişletilir.", + "emmetPreferences": "Emmet'in bazı eylemleri ve Ƨƶzümleyicilerinin davranışını değiştirmek iƧin kullanılacak tercihler.", + "emmetPreferencesIntUnit": "Tam sayı değerleri iƧin varsayılan birim", + "emmetPreferencesFloatUnit": "Ondalık sayı değerleri iƧin varsayılan birim", + "emmetPreferencesCssAfter": "CSS kısaltmaları genişletilirken CSS ƶzelliğinin sonuna koyulacak sembol", + "emmetPreferencesSassAfter": "Sass dosyalarında CSS kısaltmaları genişletilirken CSS ƶzelliğinin sonuna koyulacak sembol", + "emmetPreferencesStylusAfter": "Stylus dosyalarında CSS kısaltmaları genişletilirken CSS ƶzelliğinin sonuna koyulacak sembol", + "emmetPreferencesCssBetween": "CSS kısaltmaları genişletilirken CSS ƶzelliği ve değerinin arasına koyulacak sembol", + "emmetPreferencesSassBetween": "Sass dosyalarında CSS kısaltmaları genişletilirken CSS ƶzelliği ve değerinin arasına koyulacak sembol", + "emmetPreferencesStylusBetween": "Stylus dosyalarında CSS kısaltmaları genişletilirken CSS ƶzelliği ve değerinin arasına koyulacak sembol", + "emmetShowSuggestionsAsSnippets": "Doğru ise, Emmet ƶnerileri, editor.snippetSuggestions ayarı ile sıralayabilmenizi sağlayan parƧacıklar olarak gƶsterilir.", + "emmetPreferencesBemElementSeparator": "BEM filtresi kullanırken sınıflar iƧin kullanılacak öğe ayrıcı", + "emmetPreferencesBemModifierSeparator": "BEM filtresi kullanırken sınıflar iƧin kullanılacak niteleyici ayrıcı", + "emmetPreferencesFilterCommentBefore": "Yorum filtresi uygulandığında eşleşen öğenin ƶnüne yerleştirilmesi gereken yorumun tanımı.", + "emmetPreferencesFilterCommentAfter": "Yorum filtresi uygulandığında eşleşen öğenin ardına yerleştirilmesi gereken yorumun tanımı.", + "emmetPreferencesFilterCommentTrigger": "Yorum filterinin uygulanması iƧin kısaltmada bulunması gereken virgülle ayrılmış ƶznitelik adları listesi" } \ No newline at end of file diff --git a/i18n/trk/extensions/extension-editing/out/extensionLinter.i18n.json b/i18n/trk/extensions/extension-editing/out/extensionLinter.i18n.json index 3f17e74fb40..12dd37bc72b 100644 --- a/i18n/trk/extensions/extension-editing/out/extensionLinter.i18n.json +++ b/i18n/trk/extensions/extension-editing/out/extensionLinter.i18n.json @@ -7,5 +7,8 @@ "httpsRequired": "Resimler HTTPS protokolünü kullanmalıdır.", "svgsNotValid": "SVG'ler geƧerli bir resim kaynağı değil.", "embeddedSvgsNotValid": "Gƶmülü SVG'ler geƧerli bir resim kaynağı değil.", - "dataUrlsNotValid": "Veri URL'leri geƧerli bir resim kaynağı değil." + "dataUrlsNotValid": "Veri URL'leri geƧerli bir resim kaynağı değil.", + "relativeUrlRequiresHttpsRepository": "Gƶreli gƶrüntü URL'leri, HTTPS protokollü bir deponun bu package.json'da belirtilmesini gerektiriyor.", + "relativeIconUrlRequiresHttpsRepository": "Bir simge, HTTPS protokollü bir deponun bu package.json'da belirtilmesini gerektiriyor.", + "relativeBadgeUrlRequiresHttpsRepository": "Gƶreli gƶsterge URL'leri, HTTPS protokollü bir deponun bu package.json'da belirtilmesini gerektiriyor." } \ No newline at end of file diff --git a/i18n/trk/extensions/git/out/commands.i18n.json b/i18n/trk/extensions/git/out/commands.i18n.json index 631b43cf4f2..91a6f890483 100644 --- a/i18n/trk/extensions/git/out/commands.i18n.json +++ b/i18n/trk/extensions/git/out/commands.i18n.json @@ -12,16 +12,33 @@ "cloning": "Git deposu kopyalanıyor...", "openrepo": "Depoyu AƧ", "proposeopen": "Kopyalanan depoyu aƧmak ister misiniz?", + "init repo": "Depo Oluştur", + "create repo": "Depo Oluştur", + "are you sure": "Bu, '{0}' dizininde bir Git deposu oluşturacak. Devam etmek istediğinizden emin misiniz?", "HEAD not available": "'{0}'e ait HEAD sürümü mevcut değil.", + "confirm stage files with merge conflicts": "Birleştirme Ƨakışmaları bulunan {0} dosyayı hazırlamak istediğinizden emin misiniz?", + "confirm stage file with merge conflicts": "Birleştirme Ƨakışmaları bulunan {0} klasƶrünü hazırlamak istediğinizden emin misiniz?", + "yes": "Evet", "confirm revert": "{0} üzerindeki seƧili değişiklikleri geri almak istediğinizden emin misiniz?", "revert": "Değişiklikleri Geri Al", + "discard": "Değişiklikleri Gƶz Ardı Et", + "confirm delete": "{0} dosyasını SİLMEK istediğinizden emin misiniz?", + "delete file": "Dosyayı Sil", "confirm discard": "{0} üzerindeki seƧili değişiklikleri gƶz ardı etmek istediğinizden emin misiniz?", "confirm discard multiple": "{0} dosyadaki değişiklikleri gƶz ardı etmek istediğinizden emin misiniz?", - "discard": "Değişiklikleri Gƶz Ardı Et", - "confirm discard all": "TÜM değişiklikleri gƶz ardı etmek istediğinizden emin misiniz? Bu, GERİ DƖNDÜRÜLEMEZ!", - "discardAll": "TÜM Değişiklikleri Gƶz Ardı Et", + "warn untracked": "Bu, izlenmeyen {0} dosyayı SİLECEK!", + "confirm discard all single": "{0} üzerindeki seƧili değişiklikleri gƶz ardı etmek istediğinizden emin misiniz?", + "confirm discard all": "{0} dosyadaki TÜM değişiklikleri gƶz ardı etmek istediğinizden emin misiniz?\nBu GERİ DƖNDÜRÜLEMEZ!\nMevcut Ƨalışma grubunuz TAMAMEN KAYBOLACAK.", + "discardAll multiple": "1 Dosyayı Gƶz Ardı Et", + "discardAll": "{0} Dosyanın Tamamını Gƶz Ardı Et", + "confirm delete multiple": "{0} dosyayı SİLMEK istediğinizden emin misiniz?", + "delete files": "Dosyaları Sil", + "there are untracked files single": "Şu izlenmeyen dosya gƶz ardı edilirse DİSKTEN SİLİNECEK: {0}.", + "there are untracked files": "Gƶz ardı edilirse DİSKTEN SİLİNECEK {0} izlenmeyen dosya var.", + "confirm discard all 2": "{0}\n\nBu GERİ DƖNDÜRÜLEMEZ, mevcut Ƨalışma grubunuz TAMAMEN KAYBOLACAK.", + "yes discard tracked": "İzlenen 1 Dosyayı Gƶz Ardı Et", + "yes discard tracked multiple": "İzlenen {0} Dosyayı Gƶz Ardı Et", "no staged changes": "Commit'lenecek hazırlanmış değişiklik yok.\n\nTüm değişikliklerinizi otomatik olarak hazırlamak ve direkt olarak commit'lemek ister misiniz?", - "yes": "Evet", "always": "Her Zaman", "no changes": "Commit'lenecek değişiklik yok.", "commit message": "Commit mesajı", @@ -34,16 +51,25 @@ "delete branch": "Dalı Sil", "select a branch to merge from": "Birleştirilmesi iƧin bir dal seƧin", "merge conflicts": "Birleştirme Ƨakışmaları var. Commit'lemeden ƶnce bunları Ƨƶzün.", + "tag name": "Etiket adı", + "provide tag name": "Lütfen bir etiket adı belirtin", + "tag message": "Mesaj", + "provide tag message": "Lütfen etikete aƧıklama yapmak iƧin bir mesaj belirtin", "no remotes to pull": "Deponuzda Ƨekme işleminin yapılacağı hiƧbir uzak uƧbirim yapılandırılmamış.", "pick remote pull repo": "Dalın Ƨekileceği bir uzak uƧbirim seƧin", "no remotes to push": "Deponuzda gƶnderimin yapılacağı hiƧbir uzak uƧbirim yapılandırılmamış.", + "push with tags success": "Başarılı bir şekilde etiketlerle gƶnderildi.", "nobranch": "Lütfen uzak uƧbirime gƶnderilecek dala geƧiş yapın.", "pick remote": "'{0}' dalının yayınlanacağı bir uzak uƧbirim seƧin:", "sync is unpredictable": "Bu eylem, '{0}' esas projesine commitleri gƶnderecek ve alacaktır.", "ok": "Tamam", "never again": "Tamam, Tekrar Gƶsterme", "no remotes to publish": "Deponuzda yayınlamanın yapılacağı hiƧbir uzak uƧbirim yapılandırılmamış.", - "disabled": "Git, ya devre dışı bırakılmış ya da bu Ƨalışma alanında desteklenmiyor", + "no changes stash": "GeƧici olarak saklanacak bir değişiklik yok.", + "provide stash message": "İsteğe bağlı olarak bir geƧici olarak saklama mesajı belirtin", + "stash message": "GeƧici olarak saklama mesajı", + "no stashes": "Geri yüklenecek geƧici değişiklik yok.", + "pick stash to pop": "Geri yüklenecek ƶgeyi seƧin", "clean repo": "GeƧiş yapmadan ƶnce deponuzdaki Ƨalışma ağacınızı temizleyin.", "cant push": "Başvurular uzak uƧbirime gƶnderilemiyor. Değişikliklerinizi entegre etmeden, ilk olarak 'Ƈek'i Ƨalıştırın. ", "git error details": "Git: {0}", diff --git a/i18n/trk/extensions/git/out/model.i18n.json b/i18n/trk/extensions/git/out/model.i18n.json index 282a283d443..9bc54bdfe7a 100644 --- a/i18n/trk/extensions/git/out/model.i18n.json +++ b/i18n/trk/extensions/git/out/model.i18n.json @@ -4,11 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "AƧ", - "merge changes": "Değişiklikleri Birleştir", - "staged changes": "Hazırlanmış Değişiklikler", - "changes": "Değişiklikler", - "ok": "Tamam", - "neveragain": "Tekrar Gƶsterme", - "huge": "'{0}' yolundaki git deposunda Ƨok fazla aktif değişikliklik var, Git ƶzelliklerinin yalnızca bir alt kümesi etkinleştirilecektir." + "no repositories": "Mevcut depo yok", + "pick repo": "Bir depo seƧin" } \ No newline at end of file diff --git a/i18n/trk/extensions/git/out/repository.i18n.json b/i18n/trk/extensions/git/out/repository.i18n.json new file mode 100644 index 00000000000..4f0f8a1a395 --- /dev/null +++ b/i18n/trk/extensions/git/out/repository.i18n.json @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "open": "AƧ", + "index modified": "Dizin Değiştirildi", + "modified": "Değiştirilmiş", + "index added": "Dizin Eklendi", + "index deleted": "Dizin Silindi", + "deleted": "Silindi", + "index renamed": "Dizin Yeniden Adlandırıldı", + "index copied": "Dizin Kopyalandı", + "untracked": "İzlenmedi", + "ignored": "Yok Sayıldı", + "both deleted": "Her İkimiz de Sildik", + "added by us": "Bizim Tarafımızdan Eklendi", + "deleted by them": "Onlar Tarafından Silindi", + "added by them": "Onlar Tarafından Eklendi", + "deleted by us": "Bizim Tarafımızdan Silindi", + "both added": "Her İkimiz de Ekledik", + "both modified": "Her İkimiz de Değiştirdik", + "commit": "Commit'le", + "merge changes": "Değişiklikleri Birleştir", + "staged changes": "Hazırlanmış Değişiklikler", + "changes": "Değişiklikler", + "ok": "Tamam", + "neveragain": "Tekrar Gƶsterme", + "huge": "'{0}' yolundaki git deposunda Ƨok fazla aktif değişikliklik var, Git ƶzelliklerinin yalnızca bir alt kümesi etkinleştirilecektir." +} \ No newline at end of file diff --git a/i18n/trk/extensions/git/package.i18n.json b/i18n/trk/extensions/git/package.i18n.json index ce903ba9374..42373afee86 100644 --- a/i18n/trk/extensions/git/package.i18n.json +++ b/i18n/trk/extensions/git/package.i18n.json @@ -6,6 +6,7 @@ { "command.clone": "Klonla", "command.init": "Depo Oluştur", + "command.close": "Depoyu Kapat", "command.refresh": "Yenile", "command.openChange": "Değişiklikleri AƧ", "command.openFile": "Dosya AƧ", @@ -14,6 +15,8 @@ "command.stageAll": "Tüm Değişiklikleri Hazırla", "command.stageSelectedRanges": "SeƧili Aralığı Hazırla", "command.revertSelectedRanges": "SeƧili Aralığı Geri Al", + "command.stageChange": "Değişikliği Hazırla", + "command.revertChange": "Değişikliği Geri Al", "command.unstage": "Değişiklikleri Hazırlık Alanından Geri Al", "command.unstageAll": "Tüm Değişiklikleri Hazırlık Alanından Geri Al", "command.unstageSelectedRanges": "SeƧili Alanı Hazırlık Alanından Geri Al", @@ -22,22 +25,29 @@ "command.commit": "Commit'le", "command.commitStaged": "Hazırlananları Commit'le", "command.commitStagedSigned": "Hazırlananları Commit'le (İmzalı)", + "command.commitStagedAmend": "Hazırlananları Commit'le (Değiştir)", "command.commitAll": "Tümünü Commit'le", "command.commitAllSigned": "Tümünü Commit'le (İmzalı)", + "command.commitAllAmend": "Tümünü Commit'le (Değiştir)", "command.undoCommit": "Son Commit'i Geri Al", "command.checkout": "GeƧiş yap...", "command.branch": "Dal Oluştur...", "command.deleteBranch": "Dalı Sil...", "command.merge": "Dalı Birleştir...", + "command.createTag": "Etiket Oluştur", "command.pull": "Ƈek", "command.pullRebase": "Ƈek (Yeniden Adresle)", "command.pullFrom": "Şuradan Ƈek...", "command.push": "Gƶnder", "command.pushTo": "Gƶnder...", + "command.pushWithTags": "Etiketlerle Gƶnder", "command.sync": "Senkronize Et", "command.publish": "Dalı Yayınla", "command.showOutput": "Git Ƈıktısını Gƶster", "command.ignore": ".gitignore'a Dosya Ekle", + "command.stash": "GeƧici Olarak Sakla", + "command.stashPop": "GeƧici Olarak Saklananı Geri Yükle...", + "command.stashPopLatest": "En Son GeƧici Olarak Saklananı Geri Yükle", "config.enabled": "Git'in etkinleştirilip etkinleştirilmediği", "config.path": "Ƈalıştırılabilir Git dosyasının yolu", "config.autorefresh": "Otomatik yenilemenin etkinleştirilip etkinleştirilmediği", @@ -49,5 +59,7 @@ "config.ignoreLegacyWarning": "Eski Git uyarısını gƶrmezden gelir", "config.ignoreLimitWarning": "Bir depoda Ƨok fazla değişiklik var uyarısını gƶrmezden gelir", "config.defaultCloneDirectory": "Bir git deposunun kopyalanacağı varsayılan konum", - "config.enableSmartCommit": "Hazırlanan değişiklik yoksa tüm değişiklikleri commit'le." + "config.enableSmartCommit": "Hazırlanan değişiklik yoksa tüm değişiklikleri commit'le.", + "config.enableCommitSigning": "GPG ile commit imzalamayı etkinleştirir.", + "config.discardAllScope": "`Tüm Değişiklikleri Gƶz Ardı Et` komutuyla hangi değişikliklerin gƶz ardı edileceğini denetler. `all` tüm değişiklikleri gƶz ardı eder. `tracked` sadece izlenen dosyaları gƶz ardı eder. `prompt` eylem her Ƨalıştığında bir onay penceresi gƶsterir." } \ No newline at end of file diff --git a/i18n/trk/extensions/grunt/out/main.i18n.json b/i18n/trk/extensions/grunt/out/main.i18n.json index a379bb7fabe..1a6d51e7ba0 100644 --- a/i18n/trk/extensions/grunt/out/main.i18n.json +++ b/i18n/trk/extensions/grunt/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Grunt otomatik tespiti hata ile sonuƧlandı: {0}" + "execFailed": "{0} klasƶrü iƧin Grunt otomatik tespiti hata ile sonuƧlandı: {1}" } \ No newline at end of file diff --git a/i18n/trk/extensions/gulp/out/main.i18n.json b/i18n/trk/extensions/gulp/out/main.i18n.json index 419e64b90d8..9baacfba3fb 100644 --- a/i18n/trk/extensions/gulp/out/main.i18n.json +++ b/i18n/trk/extensions/gulp/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Gulp otomatik tespiti hata ile sonuƧlandı: {0}" + "execFailed": "{0} klasƶrü iƧin gulp otomatik tespiti hata ile sonuƧlandı: {1}" } \ No newline at end of file diff --git a/i18n/trk/extensions/html/package.i18n.json b/i18n/trk/extensions/html/package.i18n.json index ee68938c898..e2bf2407d3d 100644 --- a/i18n/trk/extensions/html/package.i18n.json +++ b/i18n/trk/extensions/html/package.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "html.format.enable.desc": "Varsayılan HTML biƧimlendiricisini etkinleştirin/devre dışı bırakın (yeniden başlatma gerektirir)", + "html.format.enable.desc": "Varsayılan HTML biƧimlendiricisini etkinleştirin/devre dışı bırakın", "html.format.wrapLineLength.desc": "Satır başına en fazla karakter miktarı (0 = devre dışı bırak)", "html.format.unformatted.desc": "Yeniden biƧimlendirilmeyecek virgülle ayrılmış etiketler listesi. 'null' değeri, https://www.w3.org/TR/html5/dom.html#phrasing-content adresinde listelenen tüm etiketleri varsayılan olarak belirler.", "html.format.contentUnformatted.desc": "İƧeriğin yeniden biƧimlendirilmeyeceği virgülle ayrılmış etiketler listesi. 'null' değeri, 'pre' etiketini varsayılan olarak belirler.", @@ -22,6 +22,8 @@ "html.suggest.angular1.desc": "Yerleşik HTML dili desteğinin Angular V1 etiketlerini ve ƶzelliklerini ƶnerip ƶnermeyeceğini yapılandırır.", "html.suggest.ionic.desc": "Yerleşik HTML dili desteğinin Ionic etiketlerini, ƶzelliklerini ve değerlerini ƶnerip ƶnermeyeceğini yapılandırır.", "html.suggest.html5.desc": "Yerleşik HTML dili desteğinin HTML5 etiketlerini, ƶzelliklerini ve değerlerini ƶnerip ƶnermeyeceğini yapılandırır.", + "html.trace.server.desc": "VS Code ve HTML dil sunucusu arasındaki iletişimi izler.", "html.validate.scripts": "Yerleşik HTML dili desteğinin HTML5 gƶmülü betikleri doğrulayıp doğrulamayacağını yapılandırır.", - "html.validate.styles": "Yerleşik HTML dili desteğinin HTML5 gƶmülü stilleri doğrulayıp doğrulamayacağını yapılandırır." + "html.validate.styles": "Yerleşik HTML dili desteğinin HTML5 gƶmülü stilleri doğrulayıp doğrulamayacağını yapılandırır.", + "html.autoClosingTags": "HTML etiketlerinin otomatik kapatılmasını etkinleştirin/devre dışı bırakın" } \ No newline at end of file diff --git a/i18n/trk/extensions/jake/out/main.i18n.json b/i18n/trk/extensions/jake/out/main.i18n.json index c94980eca2f..0f9fe99820a 100644 --- a/i18n/trk/extensions/jake/out/main.i18n.json +++ b/i18n/trk/extensions/jake/out/main.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "execFailed": "Jake otomatik tespiti hata ile sonuƧlandı: {0}" + "execFailed": "{0} klasƶrü iƧin Jake otomatik tespiti hata ile sonuƧlandı: {1}" } \ No newline at end of file diff --git a/i18n/trk/extensions/json/package.i18n.json b/i18n/trk/extensions/json/package.i18n.json index bc1296fa6f9..746d1a4acc7 100644 --- a/i18n/trk/extensions/json/package.i18n.json +++ b/i18n/trk/extensions/json/package.i18n.json @@ -11,5 +11,6 @@ "json.schemas.schema.desc": "Verilen URL iƧin şema tanımı. Şema, yalnızca şema URL'sine erişimi ƶnlemek iƧin sağlanmalıdır.", "json.format.enable.desc": "Varsayılan JSON biƧimlendiricisini etkinleştirin/devre dışı bırakın (yeniden başlatma gerektirir)", "json.tracing.desc": "VS Code ve JSON dil sunucusu arasındaki iletişimi izler.", - "json.colorDecorators.enable.desc": "Renk dekoratƶrlerini etkinleştirir veya devre dışı bırakır" + "json.colorDecorators.enable.desc": "Renk dekoratƶrlerini etkinleştirir veya devre dışı bırakır", + "json.colorDecorators.enable.deprecationMessage": "`json.colorDecorators.enable` ayarı, `editor.colorDecorators` yüzünden kullanım dışıdır." } \ No newline at end of file diff --git a/i18n/trk/extensions/markdown/out/extension.i18n.json b/i18n/trk/extensions/markdown/out/extension.i18n.json index de26700eac4..6579d484719 100644 --- a/i18n/trk/extensions/markdown/out/extension.i18n.json +++ b/i18n/trk/extensions/markdown/out/extension.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "onPreviewStyleLoadError": "'markdown.styles' yüklenemedi: {0}" + "onPreviewStyleLoadError": "'markdown.styles' yüklenemedi: {0}", + "previewTitle": "Ɩnizleme {0}" } \ No newline at end of file diff --git a/i18n/trk/extensions/markdown/out/security.i18n.json b/i18n/trk/extensions/markdown/out/security.i18n.json index 5b2f136351d..fa3ecf1c124 100644 --- a/i18n/trk/extensions/markdown/out/security.i18n.json +++ b/i18n/trk/extensions/markdown/out/security.i18n.json @@ -4,9 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "preview.showPreviewSecuritySelector.strictTitle": "Katı. Sadece güvenli iƧeriği yükle.", - "preview.showPreviewSecuritySelector.currentSelection": "GeƧerli ayar", - "preview.showPreviewSecuritySelector.insecureContentTitle": "Http üzerinden iƧerik yüklemeye izin ver.", - "preview.showPreviewSecuritySelector.scriptsAndAllContent": "Tüm iƧeriğe ve betik yürütmeye izin ver. Tavsiye edilmez.", + "strict.title": "Katı", + "strict.description": "Sadece güvenli iƧeriği yükle", + "insecureContent.title": "Güvenli olmayan iƧeriğe izin ver", + "insecureContent.description": "Http üzerinden iƧerik yüklemeyi etkinleştir", + "disable.title": "Devre Dışı Bırak", + "disable.description": "Tüm iƧeriğe ve betik yürütmeye izin ver. Tavsiye edilmez", + "moreInfo.title": "Daha Fazla Bilgi", "preview.showPreviewSecuritySelector.title": "Bu Ƨalışma alanında Markdown ƶnizlemeleri iƧin güvenlik ayarlarını seƧin" } \ No newline at end of file diff --git a/i18n/trk/extensions/markdown/package.i18n.json b/i18n/trk/extensions/markdown/package.i18n.json index abaac8b698c..7918c3811b0 100644 --- a/i18n/trk/extensions/markdown/package.i18n.json +++ b/i18n/trk/extensions/markdown/package.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "markdown.preview.breaks.desc": "Markdown ƶnizlemesinde satır sonlarının nasıl gƶsterileceğini ayarlar. 'true' olarak ayarlamak, her yeni satırda bir
oluşturur.", + "markdown.preview.linkify": "Markdown ƶnizlemesinde URL benzeri metinlerin bağlantıya Ƨevrilmesini etkinleştir veya devre dışı bırak.", "markdown.preview.doubleClickToSwitchToEditor.desc": "Düzenleyiciye geƧiş yapmak iƧin Markdown ƶnizlemesine Ƨift tıklayın.", "markdown.preview.fontFamily.desc": "Markdown ƶnizlemesinde kullanılan yazı tipi ailesini denetler.", "markdown.preview.fontSize.desc": "Markdown ƶnizlemesinde kullanılan yazı tipi boyutunu piksel olarak denetler.", @@ -17,6 +18,7 @@ "markdown.previewSide.title": "Ɩnizlemeyi Yana AƧ", "markdown.showSource.title": "Kaynağı Gƶster", "markdown.styles.dec": "Markdown ƶnizlemesinde kullanılmak üzere CSS stil dosyalarını işaret eden bir URL'ler veya yerel yollar listesi. Gƶreli yollar, gezginde aƧılan klasƶre gƶreli olarak yorumlanır.", - "markdown.showPreviewSecuritySelector.title": "Markdown Ɩnizleme Güvenlik Ayarlarını Değiştir", - "markdown.trace.desc": "Markdown eklentisi iƧin hata ayıklama günlüğünü etkinleştir." + "markdown.showPreviewSecuritySelector.title": "Ɩnizleme Güvenlik Ayarlarını Değiştir", + "markdown.trace.desc": "Markdown eklentisi iƧin hata ayıklama günlüğünü etkinleştir.", + "markdown.refreshPreview.title": "Ɩnizlemeyi Yenile" } \ No newline at end of file diff --git a/i18n/trk/extensions/npm/out/main.i18n.json b/i18n/trk/extensions/npm/out/main.i18n.json new file mode 100644 index 00000000000..76d363a5138 --- /dev/null +++ b/i18n/trk/extensions/npm/out/main.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "npm.parseError": "Npm gƶrev algılama: {0} dosyası ayrıştırılamadı" +} \ No newline at end of file diff --git a/i18n/trk/extensions/npm/package.i18n.json b/i18n/trk/extensions/npm/package.i18n.json index d408aee6213..b84a1d0fe9f 100644 --- a/i18n/trk/extensions/npm/package.i18n.json +++ b/i18n/trk/extensions/npm/package.i18n.json @@ -5,5 +5,6 @@ // Do not edit this file. It is machine generated. { "config.npm.autoDetect": "Npm betiklerinin otomatik olarak algılanıp algılanmayacağını denetler. Varsayılan olarak aƧıktır.", - "config.npm.runSilent": "npm komutlarını `--silent` seƧeneğiyle Ƨalıştır" + "config.npm.runSilent": "npm komutlarını `--silent` seƧeneğiyle Ƨalıştır", + "npm.parseError": "Npm gƶrev algılama: {0} dosyası ayrıştırılamadı" } \ No newline at end of file diff --git a/i18n/trk/extensions/typescript/out/features/taskProvider.i18n.json b/i18n/trk/extensions/typescript/out/features/taskProvider.i18n.json index 11ae6297a69..48a801d9937 100644 --- a/i18n/trk/extensions/typescript/out/features/taskProvider.i18n.json +++ b/i18n/trk/extensions/typescript/out/features/taskProvider.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "buildAndWatchTscLabel": "izleme - {0}", - "buildTscLabel": "derleme - {0}" + "buildTscLabel": "derleme - {0}", + "buildAndWatchTscLabel": "izleme - {0}" } \ No newline at end of file diff --git a/i18n/trk/extensions/typescript/out/utils/api.i18n.json b/i18n/trk/extensions/typescript/out/utils/api.i18n.json new file mode 100644 index 00000000000..c4d4b0caae8 --- /dev/null +++ b/i18n/trk/extensions/typescript/out/utils/api.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "invalidVersion": "geƧersiz sürüm" +} \ No newline at end of file diff --git a/i18n/trk/extensions/typescript/out/utils/versionPicker.i18n.json b/i18n/trk/extensions/typescript/out/utils/versionPicker.i18n.json index 455ef6e2cd6..bd757dc3901 100644 --- a/i18n/trk/extensions/typescript/out/utils/versionPicker.i18n.json +++ b/i18n/trk/extensions/typescript/out/utils/versionPicker.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "useVSCodeVersionOption": "VSCode'un Sürümünü Kullan", + "useVSCodeVersionOption": "VS Code'un Sürümünü Kullan", "useWorkspaceVersionOption": "Ƈalışma Alanı Sürümünü Kullan", "learnMore": "Daha Fazla Bilgi Edin", "selectTsVersion": "JavaScript ve TypeScript dil ƶzellikleri iƧin kullanılacak TypeScript sürümünü seƧin" diff --git a/i18n/trk/extensions/typescript/out/utils/versionProvider.i18n.json b/i18n/trk/extensions/typescript/out/utils/versionProvider.i18n.json index 56d26c0c0e9..639b0c30529 100644 --- a/i18n/trk/extensions/typescript/out/utils/versionProvider.i18n.json +++ b/i18n/trk/extensions/typescript/out/utils/versionProvider.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "noBundledServerFound": "VSCode'un tsserver'ı hatalı bir virüs tespit aracı gibi bir uygulama tarafından silindi. Lütfen VS Code'u yeniden yükleyin" + "couldNotLoadTsVersion": "Bu yolda TypeScript sürümü yüklenemedi", + "noBundledServerFound": "VS Code'un tsserver'ı hatalı bir virüs tespit aracı gibi bir uygulama tarafından silindi. Lütfen VS Code'u yeniden yükleyin." } \ No newline at end of file diff --git a/i18n/trk/extensions/typescript/package.i18n.json b/i18n/trk/extensions/typescript/package.i18n.json index e8c103349d0..27309eac057 100644 --- a/i18n/trk/extensions/typescript/package.i18n.json +++ b/i18n/trk/extensions/typescript/package.i18n.json @@ -9,7 +9,7 @@ "configuration.typescript": "TypeScript", "typescript.useCodeSnippetsOnMethodSuggest.dec": "İşlevleri parametre imzalarıyla tamamlayın.", "typescript.tsdk.desc": "Kullanılacak tsserver ve lib*.d.ts dosyalarını iƧeren klasƶr yolunu belirtir.", - "typescript.disableAutomaticTypeAcquisition": "Otomatik tür kazanımını devre dışı bırakır. TypeScript >= 2.0.6 ve değiştirildikten sonra yeniden başlatma gerektirir.", + "typescript.disableAutomaticTypeAcquisition": "Otomatik tür kazanımını devre dışı bırakır. TypeScript >= 2.0.6 gerektirir.", "typescript.tsserver.log": "TS sunucusunun bir dosyaya günlük yazmasını etkinleştirir. Bu günlük, TS Sunucu sorunlarını teşhis etmek iƧin kullanılabilir. Günlük dosya yollarını, kaynak kodunu ve projenizdeki diğer muhtemel hassas bilgileri iƧerebilir.", "typescript.tsserver.trace": "TS sunucusuna gƶnderilen mesajları izlemeyi etkinleştirir. Bu izleme, TS Sunucu sorunlarını teşhis etmek iƧin kullanılabilir. İzleme; dosya yollarını, kaynak kodunu ve projenizdeki diğer muhtemel hassas bilgileri iƧerebilir.", "typescript.validate.enable": "TypeScript doğrulamasını etkinleştir veya devre dışı bırak.", @@ -44,7 +44,11 @@ "typescript.npm": "Otomatik Tür Kazanımı iƧin kullanılacak NPM yürütülebilir dosyasının yolunu belirtir. TypeScript >= 2.3.4 gerektirir.", "typescript.check.npmIsInstalled": "Otomatik Tür Kazanımı iƧin NPM'in yüklü olup olmadığını kontrol et.", "javascript.nameSuggestions": "JavaScript ƶneri listelerindeki dosyadan benzersiz adları eklemeyi etkinleştir veya devre dışı bırak.", - "typescript.tsc.autoDetect": "Tsc gƶrevlerinin otomatik olarak algılanıp algılanmayacağını denetler. Varsayılan olarak aƧıktır.", + "typescript.tsc.autoDetect": "tsc gƶrevlerinin otomatik algılanmasını denetler. 'off' bu ƶzelliği devre dışı bırakır. 'build' sadece bir kez Ƨalışan derleme gƶrevleri oluşturur. 'watch' sadece derleme ve izleme gƶrevleri oluşturur. 'on' derleme ve izleme gƶrevlerinin her ikisini de oluşturur. Varsayılan 'on'dur. ", "typescript.problemMatchers.tsc.label": "TypeScript sorunları", - "typescript.problemMatchers.tscWatch.label": "TypeScript sorunları (izleme modu)" + "typescript.problemMatchers.tscWatch.label": "TypeScript sorunları (izleme modu)", + "typescript.quickSuggestionsForPaths": "Bir iƧe aktarım yolu girerken hızlı ƶnerileri etkinleştir/devre dışı bırak.", + "typescript.locale": "TypeScript hatalarını bildirirken kullanılarak dili(bƶlgeyi) ayarlar. TypeScript >= 2.6.0 gerektirir. 'null' varsayılanı, TypeScript hataları iƧin VS Code'un dil(bƶlge) ayarlarını kullanır.", + "javascript.implicitProjectConfig.experimentalDecorators": "Bir projenin parƧası olmayan JavaScript dosyaları iƧin deneysel dekoratƶrler ('experimentalDecorators') ƶzelliğini etkinleştir veya devre dışı bırak. Mevcut jsconfig.json veya tsconfig.json dosyaları bu ayarı geƧersiz kılar. TypeScript >= 2.3.1 gerektirir.", + "typescript.autoImportSuggestions.enabled": "Otomatik iƧe aktarım ƶnerilerini etkinleştir/devre dışı bırak. TypeScript >= 2.6.1 gerektirir." } \ No newline at end of file diff --git a/i18n/trk/src/vs/code/electron-main/menus.i18n.json b/i18n/trk/src/vs/code/electron-main/menus.i18n.json index c54714a1c61..245e33677c8 100644 --- a/i18n/trk/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/trk/src/vs/code/electron-main/menus.i18n.json @@ -102,6 +102,7 @@ "miHideActivityBar": "Etkinlik Ƈ&&ubuğunu Gizle", "miShowActivityBar": "Etkinlik Ƈ&&ubuğunu Gƶster", "miToggleWordWrap": "&&Sƶzcük Kaydırmasını AƧ/Kapat", + "miToggleMinimap": "&&Mini Haritayı AƧ/Kapat", "miToggleRenderWhitespace": "&&Boşlukları Gƶrüntülemeyi AƧ/Kapat", "miToggleRenderControlCharacters": "&&Kontrol Karakterlerini AƧ/Kapat", "miZoomIn": "&&Yakınlaştır", @@ -150,6 +151,10 @@ "mZoom": "Yakınlaştırma", "mBringToFront": "Tümünü Ɩne Getir", "miSwitchWindow": "&&Pencere Değiştir...", + "mShowPreviousTab": "Ɩnceki Sekmeyi Gƶster", + "mShowNextTab": "Sonraki Sekmeyi Gƶster", + "mMoveTabToNewWindow": "Sekmeyi Yeni Pencereye Taşı", + "mMergeAllWindows": "Tüm Pencereleri Birleştir", "miToggleDevTools": "&&Geliştirici AraƧlarını AƧ/Kapat", "miAccessibilityOptions": "&&Erişilebilirlik SeƧenekleri", "miReportIssues": "So&&run Bildir", @@ -170,8 +175,8 @@ "miRunningTask": "Ƈa&&lışan Gƶrevleri Gƶster...", "miRestartTask": "Ƈalışan Gƶrevi &&Yeniden Başlat...", "miTerminateTask": "&&Gƶrevi Sonlandır...", - "miConfigureTask": "Gƶrevleri Ya&&pılandır", - "miConfigureBuildTask": "&&Varsayılan Derleme Gƶrevini Yapılandır", + "miConfigureTask": "Gƶrevleri Ya&&pılandır...", + "miConfigureBuildTask": "&&Varsayılan Derleme Gƶrevini Yapılandır...", "accessibilityOptionsWindowTitle": "Erişilebilirlik SeƧenekleri", "miRestartToUpdate": "Güncelleştirmek iƧin Yeniden Başlat...", "miCheckingForUpdates": "Güncelleştirmeler Denetleniyor...", diff --git a/i18n/trk/src/vs/code/electron-main/windows.i18n.json b/i18n/trk/src/vs/code/electron-main/windows.i18n.json index 1113da7233f..8a10865f751 100644 --- a/i18n/trk/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/trk/src/vs/code/electron-main/windows.i18n.json @@ -7,13 +7,24 @@ "ok": "Tamam", "pathNotExistTitle": "Yol yok", "pathNotExistDetail": "'{0}' yolu artık diskte değil.", - "reopen": "Yeniden AƧ", - "wait": "Beklemeye Devam Et", - "close": "Kapat", + "reopen": "&&Yeniden AƧ", + "wait": "&&Beklemeye Devam Et", + "close": "&&Kapat", "appStalled": "Pencere artık yanıt vermiyor", "appStalledDetail": "Pencereyi yeniden aƧabilir, kapatabilir veya bekleyebilirsiniz.", "appCrashed": "Pencere kilitlendi", "appCrashedDetail": "Verdiğimiz rahatsızlıktan dolayı ƶzür dileriz! Pencereyi yeniden aƧıp kaldığınız yerden devam edebilirsiniz.", + "open": "AƧ", + "openFolder": "Klasƶr AƧ", "openFile": "Dosya AƧ", - "openFolder": "Klasƶr AƧ" + "workspaceOpenedMessage": "Ƈalışma alanı '{0}' kaydedilemiyor", + "workspaceOpenedDetail": "Ƈalışma alanı zaten başka bir pencerede aƧılmış. Lütfen ilk olarak o pencereyi kapatın ve tekrar deneyin.", + "openWorkspace": "&&AƧ", + "openWorkspaceTitle": "Ƈalışma Alanı AƧ", + "save": "&&Kaydet", + "doNotSave": "Kaydet&&me", + "cancel": "İptal", + "saveWorkspaceMessage": "Ƈalışma alanı yapılandırmanızı bir dosya olarak kaydetmek istiyor musunuz?", + "saveWorkspaceDetail": "Yeniden aƧmayı planlıyorsanız, Ƨalışma alanınızı kaydedin.", + "saveWorkspace": "Ƈalışma Alanını Kaydet" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json index 018257d1f22..8936db41305 100644 --- a/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,7 +11,7 @@ "lineHeight": "Satır yüksekliğini denetler. lineHeight değerini, fontSize değeri kullanarak hesaplamak iƧin 0 girin.", "letterSpacing": "Harfler arası boşluğu pixel olarak denetler.", "lineNumbers": "Satır numaralarının gƶrüntülenmesini denetler. Olası değerler 'on', 'off' ve 'relative'dir. 'relative' satırların geƧerli imleƧ konumundan uzaklıklarını gƶsterir.", - "rulers": "Dikey cetvellerin gƶsterileceği sütunlar", + "rulers": "Belirli bir eşit genişlikli karakterlerden sonra dikey cetveller gƶster. Birden Ƨok cetvel iƧin birden Ƨok değer kullanın. Dizi boş ise cetvel gƶsterilmez", "wordSeparators": "Sƶzcüklerle ilgili gezinti veya işlem yaparken kelime ayırıcı olarak kullanılacak karakterler", "tabSize": "Bir sekmenin eşit olduğu boşluk sayısı. Bu ayar, `editor.detectIndentation` aƧıkken dosya iƧeriğine bağlı olarak geƧersiz kılınır.", "tabSize.errorMessage": "'sayı' bekleniyor. \"auto\" değerinin `editor.detectIndentation` ile değiştirildiğini unutmayın.", @@ -20,8 +20,9 @@ "detectIndentation": "Bir dosyayı aƧarken, `editor.tabSize` ve `editor.insertSpaces` dosya iƧeriğine bağlı olarak algılanır.", "roundedSelection": "SeƧimlerin köşelerinin yuvarlak olup olmayacağını denetler", "scrollBeyondLastLine": "Düzenleyicinin son satırın ƶtesine ilerleyip ilerlemeyeceğini denetler", + "smoothScrolling": "Düzenleyicinin bir animasyon kullanarak kaydırıp kaydırmayacağını denetler", "minimap.enabled": "Mini haritanın gƶsterilip gƶsterilmeyeceğini denetler", - "minimap.showSlider": "Mini harita kaydıracının otomatik olarak gizlenip gizlenmeyeceğini denetler.", + "minimap.showSlider": "Mini harita kaydıracının otomatik olarak gizlenip gizlenmeyeceğini denetler. Alabileceği değerler 'always' ve 'mouseover'dır.", "minimap.renderCharacters": "(Renk blokları yerine) Bir satırdaki gerƧek harfleri gƶster", "minimap.maxColumn": "Hazırlanacak mini haritanın azami genişliğini belirli sayıda sütunla sınırla", "find.seedSearchStringFromSelection": "Bulma AraƧ Ƈubuğu'ndaki arama metninin, düzenleyicideki seƧili alandan beslenmesini denetler", @@ -86,6 +87,8 @@ "accessibilitySupport.off": "Düzenleyici hiƧbir zaman bir Ekran Okuyucu ile kullanılmak üzere optimize edilmeyecektir.", "accessibilitySupport": "Düzenleyicinin ekran okuyucular iƧin optimize edilmiş bir modda Ƨalışıp Ƨalışmayacağını denetler.", "links": "Düzenleyicinin bağlantıları otomatik algılayıp, onları tıklanabilir yapıp yapmayacağını denetler", + "colorDecorators": "Düzenleyicinin satır iƧi renk dekoratƶrlerini ve renk seƧiciyi gƶsterip gƶstermemesini denetler.", + "codeActions": "Kod eylemleri ampulunu etkinleştirir", "sideBySide": "Karşılaştırma düzenleyicisinin farklılıkları yan yana mı yoksa satır iƧinde mi gƶstereceğini denetler", "ignoreTrimWhitespace": "Karşılaştırma düzenleyicisinin baştaki veya sondaki boşluklardaki değişmeleri farklılık olarak gƶsterip gƶstermemesini denetler", "renderIndicators": "Karşılaştırma düzenleyicisinin ekleme/Ƨıkarma değişiklikleri iƧin +/- gƶstergeleri gƶsterip gƶstermemesini denetler.", diff --git a/i18n/trk/src/vs/editor/common/view/editorColorRegistry.i18n.json b/i18n/trk/src/vs/editor/common/view/editorColorRegistry.i18n.json index dba4219b1f7..6022a86b6cc 100644 --- a/i18n/trk/src/vs/editor/common/view/editorColorRegistry.i18n.json +++ b/i18n/trk/src/vs/editor/common/view/editorColorRegistry.i18n.json @@ -21,5 +21,11 @@ "errorForeground": "Düzenleyicideki hata karalamalarının ƶn plan rengi.", "errorBorder": "Düzenleyicideki hata karalamalarının kenarlık rengi.", "warningForeground": "Düzenleyicideki uyarı karalamalarının ƶn plan rengi.", - "warningBorder": "Düzenleyicideki uyarı karalamalarının kenarlık rengi." + "warningBorder": "Düzenleyicideki uyarı karalamalarının kenarlık rengi.", + "infoForeground": "Düzenleyicideki bilgilendirme karalamalarının ƶn plan rengi.", + "infoBorder": "Düzenleyicideki bilgilendirme karalamalarının kenarlık rengi.", + "overviewRulerRangeHighlight": "Aralık vurguları iƧin genel bakış cetvelinin işaretleyici rengi.", + "overviewRuleError": "Hatalar iƧin genel bakış cetvelinin işaretleyici rengi.", + "overviewRuleWarning": "Uyarılar iƧin genel bakış cetvelinin işaretleyici rengi.", + "overviewRuleInfo": "Bilgilendirmeler iƧin genel bakış cetvelinin işaretleyici rengi." } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json b/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json index e483c295f19..265b74d65a5 100644 --- a/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/find/browser/findWidget.i18n.json @@ -15,7 +15,7 @@ "label.replaceButton": "Değiştir", "label.replaceAllButton": "Tümünü Değiştir", "label.toggleReplaceButton": "Değiştirme modunu değiştir", - "title.matchesCountLimit": "Yalnızca ilk 999 sonuƧ vurgulandı, ancak tüm bulma işlemleri metnin tamamı üzerinde Ƨalışıyor.", + "title.matchesCountLimit": "Sadece ilk {0} sonuƧ vurgulandı, fakat metnin tamamında tüm arama işlemleri Ƨalışıyor.", "label.matchesLocation": "{0}/{1}", "label.noResults": "SonuƧ Yok" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json b/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json index e30fbb8a6d5..d6d3fc6ccf3 100644 --- a/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/find/common/findController.i18n.json @@ -10,12 +10,6 @@ "nextSelectionMatchFindAction": "Sonraki SeƧimi Bul", "previousSelectionMatchFindAction": "Ɩnceki SeƧimi Bul", "startReplace": "Değiştir", - "addSelectionToNextFindMatch": "SeƧimi Sonraki Bulunan Eşleşmeye Ekle", - "addSelectionToPreviousFindMatch": "SeƧimi Ɩnceki Bulunan Eşleşmeye Ekle", - "moveSelectionToNextFindMatch": "Son SeƧimi Sonraki Bulunan Eşleşmeye Taşı", - "moveSelectionToPreviousFindMatch": "Son SeƧimi Ɩnceki Bulunan Eşleşmeye Taşı", - "selectAllOccurrencesOfFindMatch": "Bulunan Eşleşmenin Tüm Tekrarlamalarını SeƧ", - "changeAll.label": "Tüm Tekrarlamaları Değiştir", "showNextFindTermAction": "Sonraki Arama Terimini Gƶster", "showPreviousFindTermAction": "Ɩnceki Arama Terimini Gƶster" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/format/browser/formatActions.i18n.json b/i18n/trk/src/vs/editor/contrib/format/browser/formatActions.i18n.json index 265248d706c..52d2abe3a3d 100644 --- a/i18n/trk/src/vs/editor/contrib/format/browser/formatActions.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/format/browser/formatActions.i18n.json @@ -8,6 +8,7 @@ "hintn1": "{1}. satırda {0} biƧimlendirme düzenlemesi yapıldı", "hint1n": "{0} ve {1} satırları arasında 1 biƧimlendirme düzenlemesi yapıldı", "hintnn": "{1} ve {2} satırları arasında {0} biƧimlendirme düzenlemesi yapıldı", + "no.provider": "Maalesef, '{0}' dosyaları iƧin yüklenmiş bir biƧimlendirici yok.", "formatDocument.label": "Belgeyi BiƧimlendir", "formatSelection.label": "SeƧimi BiƧimlendir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json b/i18n/trk/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json index 715f05193c2..6bc3935d6f4 100644 --- a/i18n/trk/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/gotoError/browser/gotoError.i18n.json @@ -9,5 +9,6 @@ "markerAction.previous.label": "Ɩnceki Hata veya Uyarıya Git", "editorMarkerNavigationError": "Düzenleyicinin işaretƧi gezinti aracının hata rengi.", "editorMarkerNavigationWarning": "Düzenleyicinin işaretƧi gezinti aracının uyarı rengi.", + "editorMarkerNavigationInfo": "Düzenleyicinin işaretƧi gezinti aracının bilgilendirme rengi.", "editorMarkerNavigationBackground": "Düzenleyicinin işaretƧi gezinti aracının arka planı." } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json b/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json index f3fa18b4184..899e10e4b02 100644 --- a/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/multicursor/common/multicursor.i18n.json @@ -6,5 +6,11 @@ { "mutlicursor.insertAbove": "Yukarıya İmleƧ Ekle", "mutlicursor.insertBelow": "Aşağıya İmleƧ Ekle", - "mutlicursor.insertAtEndOfEachLineSelected": "Satır Sonlarına İmleƧ Ekle" + "mutlicursor.insertAtEndOfEachLineSelected": "Satır Sonlarına İmleƧ Ekle", + "addSelectionToNextFindMatch": "SeƧimi Sonraki Bulunan Eşleşmeye Ekle", + "addSelectionToPreviousFindMatch": "SeƧimi Ɩnceki Bulunan Eşleşmeye Ekle", + "moveSelectionToNextFindMatch": "Son SeƧimi Sonraki Bulunan Eşleşmeye Taşı", + "moveSelectionToPreviousFindMatch": "Son SeƧimi Ɩnceki Bulunan Eşleşmeye Taşı", + "selectAllOccurrencesOfFindMatch": "Bulunan Eşleşmenin Tüm Tekrarlamalarını SeƧ", + "changeAll.label": "Tüm Tekrarlamaları Değiştir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json b/i18n/trk/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json new file mode 100644 index 00000000000..8a312782515 --- /dev/null +++ b/i18n/trk/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label.close": "Kapat" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json b/i18n/trk/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json index 25e86b185b8..6faf663326d 100644 --- a/i18n/trk/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json +++ b/i18n/trk/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.i18n.json @@ -5,5 +5,9 @@ // Do not edit this file. It is machine generated. { "wordHighlight": "Bir değişkeni okumak gibi, okuma-erişimi sırasındaki bir sembolün arka plan rengi.", - "wordHighlightStrong": "Bir değişkene yazmak gibi, yazma-erişimi sırasındaki bir sembolün arka plan rengi." + "wordHighlightStrong": "Bir değişkene yazmak gibi, yazma-erişimi sırasındaki bir sembolün arka plan rengi.", + "overviewRulerWordHighlightForeground": "Sembol vurguları iƧin genel bakış cetvelinin işaretleyici rengi.", + "overviewRulerWordHighlightStrongForeground": "Yazma erişimli sembol vurguları iƧin genel bakış cetvelinin işaretleyici rengi.", + "wordHighlight.next.label": "Sonraki Sembol Vurgusuna Git", + "wordHighlight.previous.label": "Ɩnceki Sembol Vurgusuna Git" } \ No newline at end of file diff --git a/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 1fc7a735690..5ddafd4b6b9 100644 --- a/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,12 +13,14 @@ "vscode.extension.contributes.menuItem.group": "Bu komutun ait olduğu gruba ekle", "vscode.extension.contributes.menus": "Düzenleyiciye menü ƶgeleri ekler", "menus.commandPalette": "Komut Paleti", + "menus.touchBar": "Touch bar (sadece macOS)", "menus.editorTitle": "Düzenleyici başlık menüsü", "menus.editorContext": "Düzenleyici bağlam menüsü", "menus.explorerContext": "Dosya gezgini bağlam menüsü", "menus.editorTabContext": "Düzenleyici sekmeleri bağlam menüsü", "menus.debugCallstackContext": "Hata ayıklama Ƨağrı yığını bağlam menüsü", "menus.scmTitle": "Kaynak Denetimi başlık menüsü", + "menus.scmSourceControl": "Kaynak Denetimi menüsü", "menus.resourceGroupContext": "Kaynak Denetimi kaynak grubu bağlam menüsü", "menus.resourceStateContext": "Kaynak Denetimi kaynak durumu bağlam menüsü", "view.viewTitle": "Katkıda bulunan gƶrünümü başlık menüsü", diff --git a/i18n/trk/src/vs/platform/environment/node/argv.i18n.json b/i18n/trk/src/vs/platform/environment/node/argv.i18n.json index f3d197dfba2..0e8cbe0d850 100644 --- a/i18n/trk/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/trk/src/vs/platform/environment/node/argv.i18n.json @@ -5,8 +5,9 @@ // Do not edit this file. It is machine generated. { "gotoValidation": "`--goto` modundaki argümanlar `FILE(:LINE(:CHARACTER))` biƧiminde olmalıdır.", - "diff": "Bir karşılaştırma düzenleyicisi aƧ. İki dosya yolu argüman olarak iletilmelidir.", - "goto": "Yoldaki dosyayı satırda ve sütunda aƧ (yola :line[:character] ekleyin).", + "diff": "İki dosyayı birbiriyle karşılaştır.", + "add": "Son aktif pencereye klasƶr(ler) ekle.", + "goto": "Konumdaki bir dosyayı belirtilen satır ve sütunda aƧ.", "locale": "Kullanılacak yerel dil (ƶrnek: en-US veya zh-TW).", "newWindow": "Yeni bir Code ƶrneğini zorla.", "performance": "'Geliştirici: BaşlangıƧ Performansı' komutu etkinleştirilmiş olarak başlat.", @@ -14,7 +15,7 @@ "reuseWindow": "Bir dosya veya klasƶrü son etkin pencerede aƧmaya zorlayın.", "userDataDir": "Kullanıcı verilerinin tutulacağı klasƶrü belirtir, root olarak Ƨalışırken yararlıdır.", "verbose": "Ayrıntılı Ƨıktı oluştur (--wait anlamına gelir).", - "wait": "Geri dƶnmeden ƶnce pencerenin kapanmasını bekle.", + "wait": "Geri dƶnmeden ƶnce dosyaların kapanmasını bekle.", "extensionHomePath": "Eklentilerin kƶk dizinini belirle.", "listExtensions": "Yüklü eklentileri listele.", "showVersions": "--list-extensions'u kullanırken, yüklü eklentilerin sürümlerini gƶsterir.", diff --git a/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 46113aaf483..c32c5815cff 100644 --- a/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Eklenti geƧersiz: package.json bir JSON dosyası değil.", - "restartCode": "{0} eklentisini yeniden yüklemeden ƶnce lütfen Code'u yeniden başlatın.", - "installDependeciesConfirmation": "'{0}' eklentisini yüklediğinizde onun bağımlılıkları da yüklenir. Devam etmek istiyor musunuz?", - "install": "Evet", - "doNotInstall": "Hayır", + "restartCodeLocal": "{0} eklentisini yeniden yüklemeden ƶnce lütfen Code'u yeniden başlatın.", + "restartCodeGallery": "Yeniden yüklemeden ƶnce lütfen Code'u yeniden başlatın.", "uninstallDependeciesConfirmation": "Yalnızca '{0}' eklentisini mi yoksa bağımlılıklarını da kaldırmak ister misiniz?", "uninstallOnly": "Sadece Eklenti", "uninstallAll": "Tümü", diff --git a/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index c156b75da26..bf95a5cb19e 100644 --- a/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,7 +16,7 @@ "vscode.extension.activationEvents": "VS Code eklentisi iƧin etkinleştirme olayları.", "vscode.extension.activationEvents.onLanguage": "Belirtilen dilde Ƨƶzümlenen bir dosya her aƧıldığında bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.onCommand": "Belirtilen komut her Ƨağrıldığında bir etkinleştirme olayı yayınlanır.", - "vscode.extension.activationEvents.onDebug": "Belirtilen türde bir hata ayıklama oturumu her başladığında bir etkinleştirme olayı yayınlanır.", + "vscode.extension.activationEvents.onDebug": "Bir kullanıcının hata ayıklamaya başlamak veya hata ayıklama yapılandırmasını ayarlamak üzere olduğu her an bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.workspaceContains": "Belirtilen glob deseni ile eşleşen en az bir dosya iƧeren bir klasƶr her aƧıldığında bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.onView": "Belirtilen gƶrünüm her genişletildiğinde bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.star": "VS Code başlatıldığında yayılan etkinleştirme olayı. Mükemmel bir son kullanıcı deneyimi sağlandığından emin olmak iƧin, lütfen bu etkinleştirme olayını eklentinizde sadece kullanım durumunuzda başka hiƧbir aktivasyon olayı kombinasyonu Ƨalışmıyorsa kullanın.", diff --git a/i18n/trk/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/trk/src/vs/platform/theme/common/colorExtensionPoint.i18n.json new file mode 100644 index 00000000000..bf71ff9729b --- /dev/null +++ b/i18n/trk/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "contributes.color": "Eklenti tarafından tanımlanan tema olarak kullanılabilir renklere ekleme yapar", + "contributes.color.id": "Tema olarak kullanılabilir rengin tanımlayıcısı", + "contributes.color.id.format": "Tanımlayıcılar aa[.bb]* biƧiminde olmalıdır", + "contributes.color.description": "Tema olarak kullanılabilir rengin aƧıklaması", + "contributes.defaults.light": "AƧık temaların varsayılan rengi. Ya hex biƧiminde bir renk değeri (#RRGGBB[AA]) ya da varsayılanı sağlayan bir tema olarak kullanılabilir rengin tanımlayıcısı olabilir.", + "contributes.defaults.dark": "Koyu temaların varsayılan rengi. Ya hex biƧiminde bir renk değeri (#RRGGBB[AA]) ya da varsayılanı sağlayan bir tema olarak kullanılabilir rengin tanımlayıcısı olabilir.", + "contributes.defaults.highContrast": "Yüksek karşıtlık temalarının varsayılan rengi. Ya hex biƧiminde bir renk değeri (#RRGGBB[AA]) ya da varsayılanı sağlayan bir tema olarak kullanılabilir rengin tanımlayıcısı olabilir.", + "invalid.colorConfiguration": "'configuration.colors' bir dizi olmalıdır", + "invalid.default.colorType": "{0}, ya hex biƧiminde bir renk değeri (#RRGGBB[AA] veya #RGB[A]) ya da varsayılanı sağlayan bir tema olarak kullanılabilir rengin tanımlayıcısı olabilir.", + "invalid.id": "'configuration.colors.id' tanımlanmalı ve boş olmamalıdır", + "invalid.id.format": "'configuration.colors.id' sƶzcük[.sƶzcük]* şeklinde olmalıdır", + "invalid.description": "'configuration.colors.description' tanımlanmalı ve boş olmamalıdır", + "invalid.defaults": "'configuration.colors.defaults' tanımlanmalı ve 'light', 'dark' ve 'highContrast' değerlerini iƧermelidir" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json b/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json index ee6263e3e7e..d6e0e3db142 100644 --- a/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json +++ b/i18n/trk/src/vs/platform/theme/common/colorRegistry.i18n.json @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "invalid.color": "GeƧersiz renk biƧimi. #RGB, #RGBA, #RRGGBB veya #RRGGBBAA kullanın", "schema.colors": "Ƈalışma ekranında kullanılan renkler.", "foreground": "Genel ƶn plan rengi. Bu renk, bir bileşen tarafından geƧersiz kılınmadıkƧa kullanılır.", "errorForeground": "Hata mesajları iƧin genel ƶn plan rengi. Bu renk, bir bileşen tarafından geƧersiz kılınmadıkƧa kullanılır.", @@ -45,6 +44,7 @@ "listHoverForeground": "Fare ile ƶgelerin üzerine gelindiğinde Liste/AğaƧ ƶn planı.", "listDropBackground": "Fare ile ƶgeler taşınırken Liste/AğaƧ sürükle ve bırak arka planı.", "highlight": "Liste/AğaƧ iƧinde arama yaparken eşleşme vurgularının Liste/AğaƧ ƶn plan rengi.", + "invalidItemForeground": "Gezginde Ƨƶzümlenmemiş bir kƶk klasƶr gibi geƧersiz ƶgeler iƧin Liste/AğaƧ ƶn plan rengi.", "pickerGroupForeground": "Gruplama etiketleri iƧin hızlı seƧici rengi.", "pickerGroupBorder": "Gruplama kenarlıkları iƧin hızlı seƧici rengi.", "buttonForeground": "Buton ƶn plan rengi.", @@ -85,5 +85,7 @@ "mergeBorder": "Satır iƧi birleştirme Ƨakışmalarında üst bilgi ve ayırıcıdaki kenarlık rengi.", "overviewRulerCurrentContentForeground": "Satır iƧi birleştirme Ƨakışmalarında geƧerli genel bakış cetveli ƶn planı.", "overviewRulerIncomingContentForeground": "Satır iƧi birleştirme Ƨakışmalarında gelen genel bakış cetveli ƶn planı.", - "overviewRulerCommonContentForeground": "Satır iƧi birleştirme Ƨakışmalarında ortak ata genel bakış cetveli ƶn planı." + "overviewRulerCommonContentForeground": "Satır iƧi birleştirme Ƨakışmalarında ortak ata genel bakış cetveli ƶn planı.", + "overviewRulerFindMatchForeground": "Bulunan eşler iƧin genel bakış cetvelinin işaretleyici rengi.", + "overviewRulerSelectionHighlightForeground": "SeƧim vurguları iƧin genel bakış cetvelinin işaretleyici rengi." } \ No newline at end of file diff --git a/i18n/trk/src/vs/platform/workspaces/common/workspaces.i18n.json b/i18n/trk/src/vs/platform/workspaces/common/workspaces.i18n.json new file mode 100644 index 00000000000..2492d86a344 --- /dev/null +++ b/i18n/trk/src/vs/platform/workspaces/common/workspaces.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "codeWorkspace": "Code Ƈalışma Alanı", + "untitledWorkspace": "İsimsiz (Ƈalışma Alanı)", + "workspaceNameVerbose": "{0} (Ƈalışma Alanı)", + "workspaceName": "{0} (Ƈalışma Alanı)" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json b/i18n/trk/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json new file mode 100644 index 00000000000..e786294f130 --- /dev/null +++ b/i18n/trk/src/vs/workbench/api/browser/viewsExtensionPoint.i18n.json @@ -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. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "requirearray": "gƶrünümler bir dizi olmalıdır", + "requirestring": "`{0}` ƶzelliği zorunludur ve `string` türünde olmalıdır", + "optstring": "`{0}` ƶzelliği atlanabilir veya `string` türünde olmalıdır", + "vscode.extension.contributes.view.id": "Gƶrünümün tanımlayıcısı. Bunu, `vscode.window.registerTreeDataProviderForView` API ile bir veri sağlayıcısı kaydetmek iƧin kullanın. Ayrıca `onView:${id}` olayını `activationEvents` ƶgesine kaydederek eklentinizi etkinleştirmeyi tetikleyin.", + "vscode.extension.contributes.view.name": "Gƶrünümün insanlar tarafından okunabilir adı. Gƶsterilecektir", + "vscode.extension.contributes.view.when": "Bu gƶrünümü gƶstermek iƧin doğru olması gereken koşul", + "vscode.extension.contributes.views": "Gƶrünümleri düzenleyiciye ekler.", + "views.explorer": "Gezgin Gƶrünümü", + "views.debug": "Hata Ayıklama Gƶrünümü", + "locationId.invalid": "`{0}` geƧerli bir gƶrünüm konumu değil", + "duplicateView1": "`{1}` konumunda aynı `{0}` kimliğine sahip birden Ƨok gƶrünüm kaydedilemiyor", + "duplicateView2": "`{0}` kimliğine sahip bir gƶrünüm `{1}` konumunda zaten kayıtlı" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json b/i18n/trk/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json new file mode 100644 index 00000000000..f48bbd60795 --- /dev/null +++ b/i18n/trk/src/vs/workbench/api/node/extHostExtensionActivator.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "unknownDep": "`{1}` eklentisi etkinleştirilemedi. Neden: bilinmeyen bağımlılık `{0}`.", + "failedDep1": "`{1}` eklentisi etkinleştirilemedi. Neden: bağımlılık `{0}` etkinleştirilemedi.", + "failedDep2": "`{0}` eklentisi etkinleştirilemedi. Neden: 10'dan fazla bağımlılık düzeyi (büyük olasılıkla bağımlılık dƶngüsü).", + "activationError": "`{0}` eklentisi etkinleştirilemedi: {1}." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json index bb4ce8a484d..a8ba8956df1 100644 --- a/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -4,24 +4,20 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "openFile": "Dosya AƧ...", "openFolder": "Klasƶr AƧ...", "openFileFolder": "AƧ...", - "reload": "&&Yeniden Yükle", - "cancel": "İptal", - "newWorkspaceFormExisting": "Var Olandan Yeni Ƈalışma Alanı...", - "select": "&&SeƧ", - "selectWorkspace": "Ƈalışma Alanı İƧin Klasƶrleri SeƧin", - "addSupported": "Birden Ƨok klasƶr aƧmak iƧin, pencereyi yeniden yüklemek gerekir.", "addFolderToWorkspace": "Ƈalışma Alanına Klasƶr Ekle...", "add": "&&Ekle", "addFolderToWorkspaceTitle": "Ƈalışma Alanına Klasƶr Ekle", + "globalRemoveFolderFromWorkspace": "Ƈalışma Alanından Klasƶr Kaldır...", "removeFolderFromWorkspace": "Ƈalışma Alanından Klasƶr Kaldır", + "openFolderSettings": "Klasƶr Ayarlarını AƧ", "saveWorkspaceAsAction": "Ƈalışma Alanını Farklı Kaydet...", - "saveEmptyWorkspaceNotSupported": "Lütfen kaydetmek iƧin ilk olarak bir Ƨalışma alanı aƧın.", - "saveNotSupported": "Ƈalışma alanını kaydetmek iƧin pencereyi yeniden yüklemek gerekir.", "save": "&&Kaydet", "saveWorkspace": "Ƈalışma Alanını Kaydet", "openWorkspaceAction": "Ƈalışma Alanı AƧ...", - "newWorkspace": "Yeni Ƈalışma Alanı...", - "openWorkspaceConfigFile": "Ƈalışma Alanı Yapılandırma Dosyasını AƧ" + "openWorkspaceConfigFile": "Ƈalışma Alanı Yapılandırma Dosyasını AƧ", + "openFolderAsWorkspaceInNewWindow": "Klasƶrü Yeni Pencerede Ƈalışma Alanı Olarak AƧ", + "workspaceFolderPickerPlaceholder": "Ƈalışma alanı klasƶrü seƧin" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index eaa011efe7e..4dac5bcdce6 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -4,9 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "removeFromActivityBar": "Etkinlik Ƈubuğundan Kaldır", - "keepInActivityBar": "Etkinlik Ƈubuğunda Tut", + "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Etkinlik Ƈubuğunda Gizle", + "keepInActivityBar": "Etkinlik Ƈubuğunda Tut", "additionalViews": "Ek Gƶrünümler", "numberBadge": "{0} ({1})", "manageExtension": "Eklentiyi Yƶnet", diff --git a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json index 32c2c08ce4c..832ee472cb0 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarPart.i18n.json @@ -5,6 +5,5 @@ // Do not edit this file. It is machine generated. { "hideActivitBar": "Etkinlik Ƈubuğunu Gizle", - "activityBarAriaLabel": "Aktif Gƶrünüm Değiştirici", "globalActions": "Global Eylemler" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json new file mode 100644 index 00000000000..99a95a1980c --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBar.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "activityBarAriaLabel": "Aktif Gƶrünüm Değiştirici" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json new file mode 100644 index 00000000000..d031a47b23a --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/compositebar/compositeBarActions.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "badgeTitle": "{0} - {1}", + "additionalViews": "Ek Gƶrünümler", + "numberBadge": "{0} ({1})", + "manageExtension": "Eklentiyi Yƶnet", + "titleKeybinding": "{0} ({1})", + "hide": "Gizle", + "keep": "Yerinde Tut", + "toggle": "Gƶrünüm Sabitlemeyi AƧ/Kapat" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 9059d7f92c9..5ff77e04882 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -12,5 +12,6 @@ "groupTwoPicker": "İkinci Gruptaki Düzenleyicileri Gƶster", "groupThreePicker": "Üçüncü Gruptaki Düzenleyicileri Gƶster", "allEditorsPicker": "AƧık Tüm Düzenleyicileri Gƶster", - "view": "Gƶrüntüle" + "view": "Gƶrüntüle", + "file": "Dosya" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 54fedd4e20f..a5fd9ca0033 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "Gruptaki Ɩnceki Düzenleyiciyi AƧ", "navigateNext": "İleri Git", "navigatePrevious": "Geri Dƶn", + "navigateLast": "Bir Ɩncekine Git", "reopenClosedEditor": "Kapatılan Düzenleyiciyi Yeniden AƧ", "clearRecentFiles": "Son AƧılanları Temizle", "showEditorsInFirstGroup": "İlk Gruptaki Düzenleyicileri Gƶster", diff --git a/i18n/trk/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index d03a6b69b6a..915f4052355 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -11,7 +11,7 @@ "endOfLineLineFeed": "LF", "endOfLineCarriageReturnLineFeed": "CRLF", "tabFocusModeEnabled": "Tab Odak Değiştirir", - "screenReaderDetected": "Ekran Okuyucu Algılandı", + "screenReaderDetected": "Ekran Okuyucu En İyi Duruma Getirildi", "screenReaderDetectedExtra": "Bir Ekran Okuyucu kullanmıyorsanız, lütfen `editor.accessibilitySupport` ayarını \"off\" olarak değiştirin", "disableTabMode": "Erişilebilirlik Modunu Devre Dışı Bırak", "gotoLine": "Satıra Git", @@ -47,5 +47,11 @@ "reopenWithEncoding": "Kodlama ile Yeniden AƧ", "guessedEncoding": "İƧerikten tahmin edildi", "pickEncodingForReopen": "Dosyayı Yeniden AƧmak İƧin Dosya Kodlaması SeƧin", - "pickEncodingForSave": "Kaydedilecek Dosya Kodlamasını SeƧin" + "pickEncodingForSave": "Kaydedilecek Dosya Kodlamasını SeƧin", + "screenReaderDetectedExplanation.title": "Ekran Okuyucu En İyi Duruma Getirildi", + "screenReaderDetectedExplanation.question": "VS Code'u Ƨalıştırmak iƧin ekran okuyucu kullanıyor musunuz?", + "screenReaderDetectedExplanation.answerYes": "Evet", + "screenReaderDetectedExplanation.answerNo": "Hayır", + "screenReaderDetectedExplanation.body1": "VS Code, ekran okuyucu ile kullanılmak iƧin uygun hale getirilmiştir.", + "screenReaderDetectedExplanation.body2": "Bazı düzenleyici ƶzellikleri farklı bir davranış sergileyecektir: ƶr. sƶzcük kaydırma, katlama, ayraƧları otomatik kapatma, vb." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/panel/panelActions.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/panel/panelActions.i18n.json index 82be0726e3e..674a0efef67 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/panel/panelActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/panel/panelActions.i18n.json @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "panelActionTooltip": "{0} ({1})", "closePanel": "Paneli Kapat", "togglePanel": "Paneli AƧ/Kapat", "focusPanel": "Panele Odakla", + "toggledPanelPosition": "Panel Konumunu Değiştir", + "moveToRight": "Sağa Taşı", + "moveToBottom": "En Alta Taşı", "toggleMaximizedPanel": "Panelin Ekranı Kaplamasını AƧ/Kapat", "maximizePanel": "Panel Boyutunu Olabildiğince Genişlet", "minimizePanel": "Panel Boyutunu Geri Al", diff --git a/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json index ea87cdb6229..38591433f64 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/statusbar/statusbarPart.i18n.json @@ -4,6 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "canNotRun": "'{0}' komutu şu an etkin değildir ve Ƨalıştırılamaz.", "manageExtension": "Eklentiyi Yƶnet" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..13520a7bd48 --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} eylem" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/views/views.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/views/views.i18n.json new file mode 100644 index 00000000000..fe27ce7154b --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/views/views.i18n.json @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} eylem", + "hideView": "Kenar Ƈubuğunda Gizle" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json new file mode 100644 index 00000000000..d412455fd99 --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/views/viewsRegistry.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "duplicateId": "`{0}` kimliğine sahip bir gƶrünüm `{1}` konumunda zaten kayıtlı" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json new file mode 100644 index 00000000000..d61355ad2f9 --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/views/viewsViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "hideView": "Kenar Ƈubuğunda Gizle" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/common/theme.i18n.json b/i18n/trk/src/vs/workbench/common/theme.i18n.json index 0cfde9b6a69..16c90f38ecc 100644 --- a/i18n/trk/src/vs/workbench/common/theme.i18n.json +++ b/i18n/trk/src/vs/workbench/common/theme.i18n.json @@ -7,10 +7,12 @@ "tabActiveBackground": "Aktif sekme arka plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", "tabInactiveBackground": "Pasif sekme arka plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", "tabBorder": "Sekmeleri birbirinden ayıran kenarlığın rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", + "tabActiveBorder": "Aktif sekmeleri vurgulayacak kenarlık. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", + "tabActiveUnfocusedBorder": "Odaklanılmamış bir gruptaki aktif sekmeleri vurgulayacak kenarlık. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", "tabActiveForeground": "Aktif bir gruptaki aktif sekmenin ƶn plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", "tabInactiveForeground": "Aktif bir gruptaki pasif sekmenin ƶn plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", - "tabUnfocusedActiveForeground": "Pasif bir gruptaki aktif sekmenin ƶn plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", - "tabUnfocusedInactiveForeground": "Pasif bir gruptaki pasif sekmenin ƶn plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", + "tabUnfocusedActiveForeground": "Odaklanılmamış bir gruptaki aktif sekmenin ƶn plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", + "tabUnfocusedInactiveForeground": "Odaklanılmamış bir gruptaki pasif sekmenin ƶn plan rengi. Sekmeler, düzenleyici alanındaki düzenleyicilerin kapsayıcılarıdır. Bir düzenleyici grubunda birden fazla sekme aƧılabilir. Birden fazla düzenleyici grupları var olabilir.", "editorGroupBackground": "Bir düzenleyici grubunun arka plan rengi. Düzenleyici grupları, düzenleyicilerin kapsayıcılarıdır. Arka plan rengi, düzenleyici grubunu sürüklerken gƶsterilir.", "tabsContainerBackground": "Sekmeler etkinleştirilmiş durumdayken, düzenleyici grubu başlık üstbilgisi arka plan rengi. Düzenleyici grupları, düzenleyicilerin kapsayıcılarıdır.Ā ", "tabsContainerBorder": "Sekmeler etkinleştirilmiş durumdayken, düzenleyici grubu başlık üstbilgisi kenarlık rengi. Düzenleyici grupları, düzenleyicilerin kapsayıcılarıdır.Ā ", @@ -18,13 +20,13 @@ "editorGroupBorder": "Birden fazla düzenleyici grubunu birbirinden ayıracak renk. Düzenleyici grupları, düzenleyicilerin kapsayıcılarıdır. ", "editorDragAndDropBackground": "Düzenleyici grubunu sürüklerken gƶsterilecek arka plan rengi. Düzenleyici iƧeriğinin hĆ¢lĆ¢ iyi gƶrünmeye devam edebilmesi iƧin renk şeffaf olmalıdır.", "panelBackground": "Panel arka plan rengi. Paneller düzenleyici alanının altında gƶsterilir ve Ƨıktı ve entegre terminal gibi gƶrünümler iƧerir.", - "panelBorder": "Paneli düzenleyiciden ayıran üstteki kenarlık rengi. Paneller düzenleyici alanının altında gƶsterilir ve Ƨıktı ve entegre terminal gibi gƶrünümler iƧerir.", "panelActiveTitleForeground": "Aktif panelin başlık rengi. Paneller düzenleyici alanının altında gƶsterilir ve Ƨıktı ve entegre terminal gibi gƶrünümler iƧerir.", "panelInactiveTitleForeground": "Pasif panelin başlık rengi. Paneller düzenleyici alanının altında gƶsterilir ve Ƨıktı ve entegre terminal gibi gƶrünümler iƧerir.", "panelActiveTitleBorder": "Aktif başlığının kenarlık rengi. Paneller düzenleyici alanının altında gƶsterilir ve Ƨıktı ve entegre terminal gibi gƶrünümler iƧerir.", - "statusBarForeground": "Durum Ƨubuğu ƶn plan rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", + "panelDragAndDropBackground": "Panel başlığı ƶgeleri iƧin sürükle bırak geri bildirim rengi. Panel ƶgelerinin hĆ¢lĆ¢ iyi gƶrünmeye devam edebilmesi iƧin renk şeffaf olmalıdır. Paneller, düzenleyici alanının altında gƶsterilir, Ƨıktı ve entegre terminal gibi gƶrünümler iƧerir.", + "statusBarForeground": "Bir Ƨalışma alanı aƧıkken durum Ƨubuğu ƶn plan rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", "statusBarNoFolderForeground": "HiƧbir klasƶr aƧık değilken durum Ƨubuğu ƶn plan rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", - "statusBarBackground": "Standart durum Ƨubuğu arka plan rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", + "statusBarBackground": "Bir Ƨalışma alanı aƧıkken durum Ƨubuğu arka plan rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", "statusBarNoFolderBackground": "HiƧbir klasƶr aƧık değilken durum Ƨubuğu arka plan rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", "statusBarBorder": "Durum Ƨubuğunu kenar Ƨubuğundan ve düzenleyiciden ayıran kenarlık rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", "statusBarNoFolderBorder": "HiƧbir klasƶr aƧık olmadığında durum Ƨubuğunu kenar Ƨubuğundan ve düzenleyiciden ayıran kenarlık rengi. Durum Ƨubuğu, pencerenin alt kısmında gƶsterilir.", diff --git a/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json index 6e119bd4a9c..84919f4ec14 100644 --- a/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "Üstteki Gƶrünüme Git", "navigateDown": "Alttaki Gƶrünüme Git", "increaseViewSize": "GeƧerli Gƶrünüm Boyutunu Artır", - "decreaseViewSize": "GeƧerli Gƶrünüm Boyutunu Azalt" + "decreaseViewSize": "GeƧerli Gƶrünüm Boyutunu Azalt", + "showPreviousTab": "Ɩnceki Pencere Sekmesini Gƶster", + "showNextWindowTab": "Sonraki Pencere Sekmesini Gƶster", + "moveWindowTabToNewWindow": "Pencere Sekmesini Yeni Pencereye Taşı", + "mergeAllWindowTabs": "Tüm Pencereleri Birleştir", + "toggleWindowTabsBar": "Pencere Sekmeleri Ƈubuğunu Gizle/Gƶster" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/electron-browser/configureLocale.i18n.json b/i18n/trk/src/vs/workbench/electron-browser/configureLocale.i18n.json new file mode 100644 index 00000000000..d7620dc687c --- /dev/null +++ b/i18n/trk/src/vs/workbench/electron-browser/configureLocale.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "configureLocale": "Dili Yapılandır", + "displayLanguage": "VSCode'un gƶrüntüleme dilini tanımlar.", + "doc": "Desteklenen dillerin listesi iƧin gƶz atın: {0}", + "restart": "Değeri değiştirirseniz VSCode'u yeniden başlatmanız gerekir.", + "fail.createSettings": "Ā '{0}' oluşturulamadı ({1}).", + "JsonSchema.locale": "Kullanılacak Kullanıcı Arayüzü Dili." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json index 9681d8dffc6..d7ac2198d90 100644 --- a/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,17 +10,25 @@ "workspaces": "Ƈalışma Alanları", "developer": "Geliştirici", "showEditorTabs": "AƧık düzenleyicilerin sekmelerde gƶsterilip gƶsterilmeyeceğini denetler", + "workbench.editor.labelFormat.default": "Dosyanın adını gƶster. Sekmeler etkinleştirilmiş ve bir grupta iki dosya aynı ada sahiplerse, her dosyanın yolundaki ayırt edici bƶlümler eklenir. Sekmeler devre dışı ve düzenleyici aktifse, Ƨalışma alanı klasƶrüne gƶreli yol gƶsterilir.", + "workbench.editor.labelFormat.short": "Dosyanın adını ve ardından dizin adını gƶster.", + "workbench.editor.labelFormat.medium": "Dosyanın adını ve ardından Ƨalışma alanı klasƶrüne gƶreli yolunu gƶster.", + "workbench.editor.labelFormat.long": "Dosyanın adını ve ardından mutlak yolunu gƶster.", + "tabDescription": "Bir düzenleyici iƧin etiketin biƧimini denetler. Bu ayarı değiştirmek; ƶrneğin, bir dosyanın konumunun daha kolay anlaşılmasını sağlar:\n- short: 'ustklasor'\n- medium: 'calismaalani/src/ustklasor'\n- long: '/home/user/calismaalani/src/ustklasor'\n- default: diğer bir sekme aynı başlığı paylaşıyorsa '.../ustklasor' veya sekmeler devre dışı ise gƶreli Ƨalışma alanı yolu", "editorTabCloseButton": "Düzenleyici sekmelerinin kapat butonlarının konumunu denetler veya 'off' olarak ayarlandığında devre dışı bırakır.", "showIcons": "AƧık düzenleyicilerin bir simge ile gƶsterilip gƶsterilmemelerini denetler. Bu, bir simge temasının etkinleştirilmesini de gerektirir.", - "enablePreview": "AƧık düzenleyicilerin ƶnizleme olarak gƶsterilip gƶsterilmeyeceğini denetler. Ɩnizleme düzenleyicileri kalıcı olarak aƧılana kadar (ƶr. Ƨift tıklama veya düzenleme ile) tekrar kullanılırlar.", + "enablePreview": "AƧık düzenleyicilerin ƶnizleme olarak gƶsterilip gƶsterilmeyeceğini denetler. Ɩnizleme düzenleyicileri kalıcı olarak aƧılana kadar (ƶr. Ƨift tıklama veya düzenleme ile) tekrar kullanılırlar ve italik yazı tipiyle gƶsterilirler.", "enablePreviewFromQuickOpen": "Hızlı AƧ'taki aƧık düzenleyicilerin ƶnizleme olarak gƶsterilip gƶsterilmeyeceğini denetler. Ɩnizleme düzenleyicileri kalıcı olarak aƧılana kadar (ƶr. Ƨift tıklama veya düzenleme ile) tekrar kullanılırlar.", - "editorOpenPositioning": "Düzenleyicilerin nerede aƧılacağını denetler. Düzenleyicileri, geƧerli olanın soluna veya sağına aƧmak iƧin 'left' veya 'right' seƧeneklerinden birini seƧin. Düzenleyicileri, geƧerli olandan bağımsız bir şekilde aƧmak iƧin 'first' veya 'last' seƧeneklerinden birini seƧin.", + "editorOpenPositioning": "Düzenleyicilerin nerede aƧılacağını denetler. Düzenleyicileri, şu an geƧerli olanın soluna veya sağına aƧmak iƧin 'left' veya 'right' seƧeneklerinden birini seƧin. Düzenleyicileri, geƧerli olandan bağımsız bir şekilde aƧmak iƧin 'first' veya 'last' seƧeneklerinden birini seƧin.", "revealIfOpen": "Düzenleyicinin gƶrünen gruplardan herhangi birinde aƧıldıysa ortaya Ƨıkarılıp Ƨıkarılmayacağını denetler. Devre dışı bırakılırsa; bir düzenleyici, o an aktif düzenleyici grubunda aƧılmayı tercih edecektir. Etkinleştirilirse; o an aktif düzenleyici grubunda tekrar aƧılmak yerine, zaten aƧık olan düzenleyici ortaya Ƨıkarılacaktır. Bu ayarın yok sayılacağı bazı durumların olduğunu unutmayın, ƶr. bir düzenleyiciyi, belirli bir grupta veya o an aktif grubun yanına aƧmaya zorladığınızda. ", "commandHistory": "Komut paleti geƧmişinde tutulacak son kullanılan komutların sayısını denetler. Komut geƧmişini kapatmak iƧin 0 olarak ayarlayın.", "preserveInput": "Komut paletine son girilen girdinin, bir sonraki aƧılışta tekrar yer alıp almayacağını denetler.", "closeOnFocusLost": "Hızlı AƧ'ın odağını kaybettiğinde otomatik olarak kapanıp kapanmayacağını denetler.", "openDefaultSettings": "Ayarları aƧmanın ayrıca tüm varsayılan ayarları gƶsteren bir düzenleyici aƧıp aƧmayacağını denetler.", + "experimentalFuzzySearchEndpoint": "Deneysel ayar araması iƧin kullanılacak uƧbirimi belirtir.", + "experimentalFuzzySearchKey": "Deneysel ayar araması iƧin kullanılacak anahtarı belirtir.", "sideBarLocation": "Kenar Ƨubuğunun konumunu denetler. Ƈalışma ekranının ya solunda ya da sağında gƶsterilebilir.", + "panelLocation": "Panelin konumunu denetler. Ƈalışma ekranının ya altında ya da sağında gƶsterilebilir.", "statusBarVisibility": "Ƈalışma ekranının altındaki durum Ƨubuğunun gƶrünürlüğünü denetler.", "activityBarVisibility": "Ƈalışma ekranındaki etkinlik Ƨubuğunun gƶrünürlüğünü denetler.", "closeOnFileDelete": "Düzenleyicinin gƶsterdiği bir dosyanın, başka bir işlem tarafından silinmesi veya yeniden adlandırması durumunda dosyayı otomatik olarak kapatıp kapatmamasını denetler. Bunu devre dışı bırakmak, bƶyle bir durumda düzenleyicinin kaydedilmemiş değişiklikler iƧeriyor durumunda kalmasını sağlar. Uygulama iƧinde silmek, düzenleyiciyi her zaman kapatır ve kaydedilmemiş değişiklikler iƧeren dosyalar, verilerinizin korunması iƧin otomatik olarak kapatılmaz.", @@ -45,7 +53,7 @@ "restoreWindows": "Pencerelerin, bir yeniden başlatma sonrası nasıl yeniden aƧılacağını denetler. Her zaman boş bir Ƨalışma alanı ile başlamak iƧin 'none', üzerinde Ƨalıştığınız son pencereyi yeniden aƧmak iƧin 'one', aƧık klasƶr bulunduran tüm pencereleri yeniden aƧmak iƧin 'folders' veya son oturumunuzdaki tüm pencereleri yeniden aƧmak iƧin 'all' seƧeneğini seƧin.", "restoreFullscreen": "Bir pencere tam ekran modundayken Ƨıkıldıysa, bu pencerenin tam ekran moduna geri dƶnüp dƶnmeyeceğini denetler.", "zoomLevel": "Pencerenin yakınlaştırma düzeyini ayarlayın. Orijinal boyut 0'dır ve üstündeki (ƶr. 1) veya altındaki (ƶr. -1) her artırma 20% daha fazla veya az yakınlaştırmayı temsil eder. Yakınlaştırma düzeyini daha ince ayrıntılarla ayarlamak iƧin ondalık değerler de girebilirsiniz.", - "title": "Pencere başlığını aktif düzenleyiciye bağlı olarak denetler. Değişkenler, bağlama gƶre değiştirilir:\n${activeEditorShort}: ƶr. myFile.txt\n${activeEditorMedium}: ƶr. myFolder/myFile.txt\n${activeEditorLong}: ƶr. /Users/Development/myProject/myFolder/myFile.txt\n${folderName}: ƶr. myFolder\n${folderPath}: ƶr. /Users/Development/myFolder\n${rootName}: ƶr. myFolder1, myFolder2, myFolder3\n${rootPath}: ƶr. /Users/Development/myWorkspace\n${appName}: ƶr. VS Code\n${dirty}: etkin düzenleyici kaydedilmemiş değişiklikler iƧeriyorsa, değişiklik gƶstergesi\n${separator}: şartlı ayırıcı (\" - \") yalnızca değer iƧeren değişkenlerle Ƨevrili olduğunda gƶsterilir", + "title": "Pencere başlığını aktif düzenleyiciye bağlı olarak denetler. Değişkenler, bağlama gƶre değiştirilir:\n${activeEditorShort}: dosyanın adı (ƶr. myFile.txt)\n${activeEditorMedium}: Ƨalışma alanı klasƶrüne gƶreli dosyanın yolu (ƶr. myFolder/myFile.txt)\n${activeEditorLong}: dosyanın tam yolu (ƶr. /Users/Development/myProject/myFolder/myFile.txt)\n${folderName}: dosyayı iƧeren Ƨalışma alanı klasƶrünün adı (ƶr. myFolder)\n${folderPath}: dosyayı iƧeren Ƨalışma alanı klasƶrünün yolu (ƶr. /Users/Development/myFolder)\n${rootName}: Ƨalışma alanının adı (ƶr. myFolder veya myWorkspace)\n${rootPath}: Ƨalışma alanının yolu (ƶr. /Users/Development/myWorkspace)\n${appName}: ƶr. VS Code\n${dirty}: etkin düzenleyici kaydedilmemiş değişiklikler iƧeriyorsa, değişiklik gƶstergesi\n${separator}: şartlı ayırıcı (\" - \") yalnızca değer iƧeren değişkenlerle Ƨevrili olduğunda gƶsterilir", "window.newWindowDimensions.default": "Yeni pencereleri ekranın ortasında aƧın.", "window.newWindowDimensions.inherit": "Yeni pencereleri son aktif pencere ile aynı ƶlçülerde aƧın.", "window.newWindowDimensions.maximized": "Yeni pencereleri ekranı kapla modunda aƧın.", diff --git a/i18n/trk/src/vs/workbench/electron-browser/window.i18n.json b/i18n/trk/src/vs/workbench/electron-browser/window.i18n.json index 0be0914e872..c583af8e7cc 100644 --- a/i18n/trk/src/vs/workbench/electron-browser/window.i18n.json +++ b/i18n/trk/src/vs/workbench/electron-browser/window.i18n.json @@ -9,7 +9,5 @@ "cut": "Kes", "copy": "Kopyala", "paste": "Yapıştır", - "selectAll": "Tümünü SeƧ", - "confirmOpen": "{0} Ƨalışma alanını aƧmak istediğinizden emin misiniz?", - "confirmOpenButton": "&&AƧ" + "selectAll": "Tümünü SeƧ" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index efc71dc00cf..7cff16c1455 100644 --- a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,10 @@ "schema.indentationRules.unIndentedLinePattern": "Bir satır bu kalıpla eşleşirse, o satırın girintisi değiştirilmemelidir ve diğer kurallara karşı değerlendirilmemelidir.", "schema.indentationRules.unIndentedLinePattern.pattern": "unIndentedLinePattern iƧin Düzenli İfade.", "schema.indentationRules.unIndentedLinePattern.flags": "unIndentedLinePattern iƧin Düzenli İfade işaretleri.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` kalıbı ile eşleşmelidir." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` kalıbı ile eşleşmelidir.", + "schema.folding": "Dilin katlama ayarları.", + "schema.folding.offSide": "Bir dildeki bloklar girintilendirmeleriyle ifade edilirse, o dil iƧin off-side kuralı uygulanır. Eğer ayarlanırsa, boş satırlar sonraki bloğa ait olur.", + "schema.folding.markers": "'#region' ve '#endregion' gibi dile ƶzgü katlama işaretƧileri. BaşlangıƧ ve bitiş düzenli ifadeleri tüm satırlardaki iƧeriklere karşı test edilecektir ve verimli olacak şekilde tasarlanmalıdır", + "schema.folding.markers.start": "BaşlangıƧ işaretƧisi iƧin Düzenli İfade kalıbı. Düzenli ifade '^' ile başlamalıdır.", + "schema.folding.markers.end": "Bitiş işaretƧisi iƧin Düzenli İfade kalıbı. Düzenli ifade '^' ile başlamalıdır." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json new file mode 100644 index 00000000000..e7efe6a01b2 --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "toggleMinimap": "Gƶrünüm: Mini Haritayı AƧ/Kapat" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json index 5c757ea1565..001627659e1 100644 --- a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderControlCharacters": "Kontrol Karakterlerini AƧ/Kapat" + "toggleRenderControlCharacters": "Gƶrünüm: Kontrol Karakterlerini AƧ/Kapat" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json index 87c50ce4488..7910538f5d2 100644 --- a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "toggleRenderWhitespace": "Boşlukları Gƶrüntülemeyi AƧ/Kapat" + "toggleRenderWhitespace": "Gƶrünüm: Boşlukları Gƶrüntülemeyi AƧ/Kapat" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json index 6a22d71e97d..480910c4883 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/browser/debugQuickOpen.i18n.json @@ -6,6 +6,8 @@ { "entryAriaLabel": "{0}, hata ayıklama", "debugAriaLabel": "Ƈalıştırılacak bir başlatma yapılandırması adı girin.", + "addConfigTo": "Yapılandırma Ekle ({0})...", + "addConfiguration": "Yapı&&landırma Ekle...", "noConfigurationsMatching": "Eşleyen hata ayıklama yapılandırması yok", "noConfigurationsFound": "HiƧbir hata ayıklama yapılandırması bulunamadı. Lütfen bir 'launch.json'Ā dosyası oluşturun." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/debug/browser/debugStatus.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json new file mode 100644 index 00000000000..e0b86b943a2 --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/debug/browser/debugViewlet.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "debugFocusVariablesView": "Değişkenlere Odakla", + "debugFocusWatchView": "İzlemeye Odakla", + "debugFocusCallStackView": "Ƈağrı Yığınına Odakla", + "debugFocusBreakpointsView": "Kesme Noktalarına Odakla" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json index 0fbc09f8cc1..ea94460b89a 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.i18n.json @@ -15,7 +15,6 @@ "vscode.extension.contributes.debuggers.initialConfigurations": "İlk 'launch.json' dosyasının üretimi iƧin yapılandırmalar.", "vscode.extension.contributes.debuggers.languages": "Hata ayıklama eklentisinin, \"varsayılan hata ayıklayıcı\" olarak değerlendirilebileceği diller listesi.", "vscode.extension.contributes.debuggers.adapterExecutableCommand": "Belirtilirse; VS Code, hata ayıklama bağdaştırıcısı yürütülebilir dosyasının yolunu ve ona gƶnderilecek argümanları belirlemek iƧin bu komutu Ƨağırır.", - "vscode.extension.contributes.debuggers.startSessionCommand": "Belirtilirse; VS Code, bu eklenti iƧin hedeflenen \"hata ayıklama\" ve \"Ƨalıştır\" eylemleri iƧin bu komutu Ƨağırır.", "vscode.extension.contributes.debuggers.configurationSnippets": "'launch.json' dosyasına yeni yapılandırmalar ekleme parƧacıkları.", "vscode.extension.contributes.debuggers.configurationAttributes": "'launch.json' dosyasını doğrulayacak JSON şema yapılandırmaları.", "vscode.extension.contributes.debuggers.windows": "Windows'a ƶzel ayarlar.", diff --git a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 3769ac4ce31..52318e59059 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,14 +12,14 @@ "breakpointRemoved": "Kesme noktası kaldırıldı, {0}. satır, {1} dosyası", "compoundMustHaveConfigurations": "Bileşik, birden Ƨok yapılandırmayı başlatmak iƧin \"configurations\" ƶzniteliği bulundurmalıdır.", "configMissing": "'launch.json' dosyasında '{0}' yapılandırması eksik.", + "debugRequestNotSupported": "SeƧilen hata ayıklama yapılandırılmasındaki `{0}` ƶzniteliğiĀ desteklenmeyen `{1}` değeri iƧeriyor.", "debugTypeNotSupported": "Yapılandırılan hata ayıklama türü '{0}', desteklenmiyor.", - "debugTypeMissing": "SeƧilen başlatma yapılandırması iƧin 'type' ƶzelliği eksik.", + "debugTypeMissing": "SeƧilen başlatma yapılandırmasında `type` ƶzelliği eksik.", + "debugAnyway": "Yine de Hata Ayıkla", "preLaunchTaskErrors": "'{0}' ƶn başlatma gƶrevi sırasında derleme hataları algılandı.", "preLaunchTaskError": "'{0}' ƶn başlatma gƶrevi sırasında derleme hatası algılandı.", "preLaunchTaskExitCode": "'{0}' ƶn başlatma gƶrevi {1} Ƨıkış koduyla sonlandı.", - "debugAnyway": "Yine de Hata Ayıkla", "noFolderWorkspaceDebugError": "Aktif dosyada hata ayıklama yapılamıyor. Lütfen, dosyanın diskte kayıtlı olduğundan ve bu dosya türü iƧin hata ayıklama eklentinizin olduğundan emin olun.", "NewLaunchConfig": "Lütfen uygulamanızın başlatma yapılandırması dosyasını ayarlayın. {0}", - "DebugTaskNotFound": "'{0}' ƶn başlatma gƶrevi bulunamadı.", - "differentTaskRunning": "'{0}' gƶrevi zaten Ƨalışıyor. Ɩn başlatma gƶrevi '{1}' Ƨalıştırılamıyor." + "DebugTaskNotFound": "'{0}' ƶn başlatma gƶrevi bulunamadı." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json index 3ee7a241566..a53a32385dc 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/replViewer.i18n.json @@ -8,5 +8,5 @@ "replVariableAriaLabel": "{0} değişkeni, {1} değerine sahip, oku değerlendir yaz dƶngüsü, hata ayıklama", "replExpressionAriaLabel": "{0} ifadesi, {1} değerine sahip, oku değerlendir yaz dƶngüsü, hata ayıklama", "replValueOutputAriaLabel": "{0}, oku değerlendir yaz dƶngüsü, hata ayıklama", - "replKeyValueOutputAriaLabel": "{0} Ƨıktı değişkeni, {1} değerine sahip, oku değerlendir yaz dƶngüsü, hata ayıklama" + "replRawObjectAriaLabel": "{0} repl değişkeni, {1} değerine sahip, oku değerlendir yaz dƶngüsü, hata ayıklama" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 6d21fb46e92..5e977fb511d 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -6,6 +6,9 @@ { "debugAdapterBinNotFound": "Hata ayıklama bağdaştırıcısı yürütülebilir dosyası '{0}', mevcut değil.", "debugAdapterCannotDetermineExecutable": "Hata ayıklama bağdaştırıcısı yürütülebilir dosyası '{0}' belirlenemedi.", + "launch.config.comment1": "Olası ƶznitelikler hakkında bilgi edinmek iƧin IntelliSense kullanın.", + "launch.config.comment2": "Mevcut ƶzniteliklerin aƧıklamalarını gƶrmek iƧin fare ile üzerine gelin.", + "launch.config.comment3": "Daha fazla bilgi iƧin ziyaret edin: {0}", "debugType": "Yapılandırma türü.", "debugTypeNotRecognised": "Hata ayıklama türü tanınmıyor. Karşılık gelen hata ayıklama uzantısı yüklemiş olduğunuzdan ve etkinleştirildiğinden emin olun.", "node2NotSupported": "\"node2\" artık desteklenmiyor, bunun yerine \"node\" kullanın ve \"protocol\" ƶzniteliğini \"inspector\" olarak ayarlayın.", diff --git a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 99ab8e650ad..4c3d5d2ef5f 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "Adı", "view location": "Yeri", - "themes": "Temalar ({0})", + "colorThemes": "Renk Temaları ({0})", + "iconThemes": "Simge Temaları ({0})", + "colors": "Renkler ({0})", + "colorId": "Kimlik", + "defaultDark": "Koyu Varsayılan", + "defaultLight": "AƧık Varsayılan", + "defaultHC": "Yüksek Karşıtlık Varsayılan", "JSON Validation": "JSON Doğrulama ({0})", "commands": "Komutlar ({0})", "command name": "Adı", diff --git a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 8deac17c2e0..14daf8309bd 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -34,7 +34,6 @@ "postDisableMessage": "'{0}' eklentisini devre dışı bırakmak iƧin bu pencere yeniden yüklensin mi?", "postUninstallTooltip": "Devre dışı bırakmak iƧin yeniden yükleyin", "postUninstallMessage": "Kaldırılan '{0}' eklentisini devre dışı bırakmak iƧin bu pencere yeniden yüklensin mi?", - "reload": "Pencereyi &&Yeniden Yükle", "toggleExtensionsViewlet": "Eklentileri Gƶster", "installExtensions": "Eklenti Yükle", "showEnabledExtensions": "Etkinleştirilmiş Eklentileri Gƶster", @@ -44,14 +43,19 @@ "showOutdatedExtensions": "Eski Eklentileri Gƶster", "showPopularExtensions": "Popüler Eklentileri Gƶster", "showRecommendedExtensions": "Tavsiye Edilen Eklentileri Gƶster", - "showWorkspaceRecommendedExtensions": "Ƈalışma Alanının Tavsiye Ettiği Eklentileri Gƶster", + "installWorkspaceRecommendedExtensions": "Ƈalışma Alanının Tavsiye Ettiği Tüm Eklentileri Yükle", + "allExtensionsInstalled": "Bu Ƨalışma alanı iƧin tavsiye edilen tüm eklentiler zaten yüklü", + "installRecommendedExtension": "Tavsiye Edilen Eklentiyi Yükle", + "extensionInstalled": "Tavsiye edilen eklenti zaten yüklü", "showRecommendedKeymapExtensions": "Tavsiye Edilen Tuş Haritalarını Gƶster", "showRecommendedKeymapExtensionsShort": "Tuş Haritaları", "showLanguageExtensions": "Dil Eklentilerini Gƶster", "showLanguageExtensionsShort": "Dil Eklentileri", - "configureWorkspaceRecommendedExtensions": "Tavsiye Edilen Eklentileri Yapılandır (Ƈalışma Alanı)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Tavsiyeler, sadece Ƨalışma alanı klasƶründe mevcuttur.", + "showAzureExtensions": "Azure Eklentilerini Gƶster", + "showAzureExtensionsShort": "Azure Eklentileri", "OpenExtensionsFile.failed": "Ā '.vscode' klasƶrü iƧinde 'extensions.json' dosyası oluşturulamıyor ({0}).", + "configureWorkspaceRecommendedExtensions": "Tavsiye Edilen Eklentileri Yapılandır (Ƈalışma Alanı)", + "configureWorkspaceFolderRecommendedExtensions": "Tavsiye Edilen Eklentileri Yapılandır (Ƈalışma Alanı Klasƶrü)", "builtin": "Yerleşik", "disableAll": "Yüklü Tüm Eklentileri Devre Dışı Bırak", "disableAllWorkspace": "Bu Ƈalışma Alanı iƧin Yüklü Tüm Eklentileri Devre Dışı Bırak", diff --git a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json new file mode 100644 index 00000000000..cb67809c37e --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsList.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "recommended": "Tavsiye Edilen" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json index 1ac44b7c83d..9681c472547 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.i18n.json @@ -5,6 +5,8 @@ // Do not edit this file. It is machine generated. { "manage": "Eklentilerinizi yƶnetmek iƧin Enter'a basın.", + "notfound": "'{0}' eklentisi markette bulunamadı.", + "install": "Marketten '{0}' eklentisini yüklemek iƧin Enter'a basın.", "searchFor": "Markette '{0}' iƧin arama yapmak iƧin Enter'a basın.", "noExtensionsToInstall": "Bir eklenti adı girin" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json index 640d11588c6..5b9f87d7032 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.i18n.json @@ -4,11 +4,16 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "fileBasedRecommendation": "Bu eklenti yakınlarda aƧtığınız dosyalara dayanarak tavsiye ediliyor.", + "workspaceRecommendation": "Bu eklenti geƧerli Ƨalışma alanı kullanıcıları tarafından tavsiye ediliyor.", "reallyRecommended2": "'{0}' eklentisi bu dosya türü iƧin tavsiye edilir.", + "reallyRecommendedExtensionPack": "'{0}' eklenti paketi bu dosya türü iƧin tavsiye edilir.", "showRecommendations": "Tavsiyeleri Gƶster", + "install": "Yükle", "neverShowAgain": "Tekrar gƶsterme", "close": "Kapat", "workspaceRecommended": "Bu Ƨalışma alanı bazı eklentileri tavsiye ediyor.", + "installAll": "Tümünü Yükle", "ignoreExtensionRecommendations": "Tüm eklenti tavsiyelerini yok saymak istiyor musunuz?", "ignoreAll": "Evet, Tümünü Yok Say", "no": "Hayır", diff --git a/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 25237bc8ead..99b81498259 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,6 +6,8 @@ { "openExtensionsFolder": "Eklentiler Klasƶrünü AƧ", "installVSIX": "VSIX'ten yükle...", + "installFromVSIX": "VSIX'den Yükle", + "installButton": "&&Yükle", "InstallVSIXAction.success": "Eklenti başarıyla yüklendi. Etkinleştirmek iƧin yeniden başlatın.", "InstallVSIXAction.reloadNow": "Şimdi Yeniden Yükle" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json index 0c3e5b0c422..fb8de282efa 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.i18n.json @@ -8,6 +8,8 @@ "installedExtensions": "Yüklü", "searchInstalledExtensions": "Yüklü", "recommendedExtensions": "Tavsiye Edilen", + "otherRecommendedExtensions": "Diğer Tavsiyeler", + "workspaceRecommendedExtensions": "Ƈalışma Alanı Tavsiyeleri", "searchExtensions": "Markette Eklenti Ara", "sort by installs": "Sırala: Yüklenme Sayısına Gƶre", "sort by rating": "Sırala: Derecelendirmeye Gƶre", diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json index c907a874d19..09b50f5c819 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.contribution.i18n.json @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "filesCategory": "Dosyalar", + "filesCategory": "Dosya", "revealInSideBar": "Kenar Ƈubuğunda Ortaya Ƈıkar", "acceptLocalChanges": "Değişikliklerinizi kullanın ve diskteki iƧeriklerin üzerine yazın", "revertLocalChanges": "Değişikliklerinizi gƶz ardı edin ve diskteki iƧeriğe geri dƶnün" diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json index 55a64a319b8..c6dceab7516 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/fileActions.i18n.json @@ -23,6 +23,7 @@ "confirmMoveTrashMessageFile": "'{0}' öğesini silmek istediğinize emin misiniz?", "undoBin": "Geri dƶnüşüm kutusundan geri alabilirsiniz.", "undoTrash": "Ƈƶp kutusundan geri alabilirsiniz.", + "doNotAskAgain": "Bir daha sorma", "confirmDeleteMessageFolder": "'{0}' öğesini ve iƧindekileri kalıcı olarak silmek istediğinizden emin misiniz?", "confirmDeleteMessageFile": "'{0}' öğesini kalıcı olarak silmek istediğinizden emin misiniz?", "irreversible": "Bu eylem geri dƶndürülemez!", @@ -37,17 +38,15 @@ "openToSide": "Yana AƧ", "compareSource": "Karşılaştırma İƧin SeƧ", "globalCompareFile": "Aktif Dosyayı Karşılaştır...", - "pickHistory": "Karşılaştırmak iƧin daha ƶnce aƧılan bir dosyayı seƧin", - "unableToFileToCompare": "SeƧtiğiniz dosya, '{0}' ile karşılaştırılamaz.", "openFileToCompare": "Bir başka dosya ile karşılaştırmak iƧin ilk olarak bir dosya aƧın.", - "compareWith": "'{0}' ile karşılaştır", + "compareWith": "'{0}' dosyasını '{1}' ile karşılaştır", "compareFiles": "Dosyaları Karşılaştır", "refresh": "Yenile", "save": "Kaydet", "saveAs": "Farklı Kaydet...", "saveAll": "Tümünü Kaydet", "saveAllInGroup": "Gruptaki Tümünü Kadet", - "saveFiles": "Kaydedilmemiş Değişiklikler İƧeren Dosyaları Kaydet", + "saveFiles": "Tüm Dosyaları Kaydet", "revert": "Dosyayı Geri Dƶndür", "focusOpenEditors": "AƧık Düzenleyiciler Gƶrünümüne Odakla", "focusFilesExplorer": "Dosya Gezginine Odakla", @@ -55,7 +54,6 @@ "openFileToShow": "Gezginde gƶstermek iƧin ilk olarak bir dosya aƧın", "collapseExplorerFolders": "Gezgindeki Klasƶrleri Daralt", "refreshExplorer": "Gezgini Yenile", - "openFile": "Dosya AƧ...", "openFileInNewWindow": "Aktif Dosyayı Yeni Pencerede AƧ", "openFileToShowInNewWindow": "Yeni pencerede aƧmak iƧin ilk olarak bir dosya aƧın", "revealInWindows": "Gezginde Ortaya Ƈıkar", diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 80d061c3da2..3607c85a9e2 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -10,15 +10,16 @@ "textFileEditor": "Metin Dosyası Düzenleyicisi", "binaryFileEditor": "İkili Dosya Düzenleyicisi", "filesConfigurationTitle": "Dosyalar", - "exclude": "Dosya ve klasƶrleri hariƧ tutmak iƧin glob desenlerini yapılandırın.", + "exclude": "Dosyaları ve klasƶrleri hariƧ tutmak iƧin glob desenlerini yapılandırın. Ɩrnek olarak, dosya gezgini bu ayara bağlı olarak hangi dosya ve klasƶrlerin gƶsterileceğine karar verir.", "files.exclude.boolean": "Dosya yollarının eşleştirileceği glob deseni. Deseni etkinleştirmek veya devre dışı bırakmak iƧin true veya false olarak ayarlayın.", "files.exclude.when": "Eşleşen bir dosyanın eşdüzey dosyalarında ek denetim. Eşleşen dosya adı iƧin değişken olarak $(basename) kullanın.", "associations": "Dillerle dosya ilişkilendirmelerini yapılandırın (ƶr. \"*.uzanti\": \"html\"). Bunların, kurulu olan dillerin varsayılan ilişkilendirmeleri karşısında ƶnceliği vardır.", - "encoding": "Dosyalar okunurken ve yazılırken kullanılacak varsayılan karakter kümesi kodlaması.", - "autoGuessEncoding": "Etkinleştirildiğinde, dosyaları aƧarken karakter kümesini tahmin etmeye Ƨalışır", + "encoding": "Dosyalar okunurken ve yazılırken kullanılacak varsayılan karakter kümesi kodlaması. Bu ayar her bir dil iƧin de yapılandırılabilir.", + "autoGuessEncoding": "Etkinleştirildiğinde, dosyaları aƧarken karakter kümesini tahmin etmeye Ƨalışır. Bu ayar her bir dil iƧin de yapılandırılabilir.", "eol": "Varsayılan satır sonu karakteri. LF iƧin \\n ve CRLF iƧin \\r\\n kullan.", "trimTrailingWhitespace": "Etkinleştirildiğinde, bir dosyayı kaydettiğinizde sondaki boşluk kırpılır.", "insertFinalNewline": "Etkinleştirildiğinde, bir dosyayı kaydederken dosya sonuna bir boş satır ekler.", + "trimFinalNewlines": "Etkinleştirildiğinde, bir dosyayı kaydederken dosya sonundaki birden fazla boş satırı kırparak tek boş satıra Ƨevirir", "files.autoSave.off": "Kaydedilmemiş değişiklikler iƧeren bir dosya hiƧbir zaman otomatik olarak kaydedilmez.", "files.autoSave.afterDelay": "Kaydedilmemiş değişiklikler iƧeren bir dosya, 'files.autoSaveDelay' ayarlandıktan sonra otomatik olarak kaydedilir.", "files.autoSave.onFocusChange": "Kaydedilmemiş değişiklikler iƧeren bir dosya, düzenleyici odaktan Ƨıktığı an otomatik olarak kaydedilir.", @@ -39,10 +40,13 @@ "dynamicHeight": "AƧık düzenleyiciler bƶlümü yüksekliğinin ƶge sayısına gƶre dinamik olarak uyarlanıp uyarlanmayacağını denetler.", "autoReveal": "Gezginin dosyaları aƧarken, onları otomatik olarak ortaya Ƨıkartmasını ve seƧmesini denetler.", "enableDragAndDrop": "Gezgeinin sürükle bırak ile dosyaları ve klasƶrleri taşımaya izin verip vermeyeceğini denetler.", + "confirmDelete": "Gezginin, geri dƶnüşüm kutusu ile dosya silineceği zaman onay isteyip istemeyeceğini denetler.", "sortOrder.default": "Dosya ve klasƶrler adlarına gƶre, alfabetik olarak sıralanırlar. Klasƶrler dosyalardan ƶnce gƶrüntülenir.", "sortOrder.mixed": "Dosya ve klasƶrler adlarına gƶre, alfabetik olarak sıralanırlar. Dosyalar ve klasƶrler iƧ iƧe bulunur.", "sortOrder.filesFirst": "Dosya ve klasƶrler adlarına gƶre, alfabetik olarak sıralanırlar. Dosyalar klasƶrlerden ƶnce gƶrüntülenir.", "sortOrder.type": "Dosya ve klasƶrler uzantılarına gƶre, alfabetik olarak sıralanırlar. Klasƶrler dosyalardan ƶnce gƶrüntülenir.", "sortOrder.modified": "Dosya ve klasƶrler son değiştirilme tarihine gƶre, azalan düzende sıralanırlar. Klasƶrler dosyalardan ƶnce gƶrüntülenir.", - "sortOrder": "Dosyaların ve klasƶrlerin gezginde nasıl sıralanacağını denetler." + "sortOrder": "Gezginde dosya ve klasƶrlerin sıralamasını denetler. Varsayılan sıralamaya ek olarak, sıralamayı; 'mixed' (dosya ve klasƶrler karışık olarak sıralanır), 'type' (dosya türüne gƶre), 'modified' (son düzenlenme tarihine gƶre) veya 'filesFirst' (dosyaları klasƶrlerden ƶnce sırala) olarak ayarlayabilirsiniz.", + "explorer.decorations.colors": "Dosya süslemelerinin renkleri kullanıp kullanmayacağını denetler.", + "explorer.decorations.badges": "Dosya süslemelerinin gƶstergeleri kullanıp kullanmayacağını denetler." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json index 09d9b7607bd..660d16789d0 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/saveErrorHandler.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "userGuide": "Değişikliklerinizi **geri al**mak veya diskteki iƧeriğin **üzerine yaz**mak iƧin düzenleyicideki araƧ Ƨubuğunu kullanabilirsiniz", "discard": "At", "overwrite": "Üzerine Yaz", "retry": "Yeniden Dene", @@ -11,6 +12,5 @@ "genericSaveError": "'{0}' kaydedilemedi: ({1}).", "staleSaveError": "'{0}' kaydedilemedi: Diskteki iƧerik daha yeni. Sizdeki sürüm ile disktekini karşılaştırmak iƧin **Karşılaştır**a tıklayın.", "compareChanges": "Karşılaştır", - "saveConflictDiffLabel": "{0} (diskte) ↔ {1} ({2} uygulamasında) - Kaydetme Ƨakışmasını Ƨƶz", - "userGuide": "Değişikliklerinizi **geri al**mak veya diskteki iƧeriğin **üzerine yaz**mak iƧin düzenleyicideki araƧ Ƨubuğunu kullanabilirsiniz" + "saveConflictDiffLabel": "{0} (diskte) ↔ {1} ({2} uygulamasında) - Kaydetme Ƨakışmasını Ƨƶz" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json index d14973027f7..78cbb2f07ff 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/views/emptyView.i18n.json @@ -6,6 +6,8 @@ { "noWorkspace": "AƧık Klasƶr Yok", "explorerSection": "Dosya Gezgini Bƶlümü", - "noWorkspaceHelp": "Henüz bir klasƶr aƧmadınız.", + "noWorkspaceHelp": "Ƈalışma alanına hĆ¢lĆ¢ bir klasƶr eklemediniz.", + "addFolder": "Klasƶr Ekle", + "noFolderHelp": "Henüz bir klasƶr aƧmadınız.", "openFolder": "Klasƶr AƧ" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json new file mode 100644 index 00000000000..8d72fc4a3bf --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Gezgin" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json index 9dff53f0852..c2e160be13c 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/views/explorerViewer.i18n.json @@ -6,6 +6,13 @@ { "fileInputAriaLabel": "Dosya adı girin. Onaylamak iƧin Enter'a, iptal etmek iƧin Escape tuşuna basın.", "filesExplorerViewerAriaLabel": "{0}, Dosya Gezgini", + "dropFolders": "Ƈalışma alanına klasƶrleri eklemek istiyor musunuz?", + "dropFolder": "Klasƶrü Ƨalışma alanına eklemek istiyor musunuz?", + "addFolders": "Klasƶrleri &&Ekle", + "addFolder": "Klasƶrü &&Ekle", + "confirmMove": "'{0}' ƶgesini taşımak istediğinizden emin misiniz?", + "doNotAskAgain": "Bir daha sorma", + "moveButtonLabel": "&&Taşı", "confirmOverwriteMessage": "'{0}' hedef klasƶrde zaten mevcut. Değiştirmek istiyor musunuz?", "irreversible": "Bu eylem geri dƶndürülemez!", "replaceButtonLabel": "&&Değiştir" diff --git a/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 0f88a5b2332..1a8d190f659 100644 --- a/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 kaydedilmemiş dosya", "dirtyFiles": "{0} kaydedilmemiş dosya" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json b/i18n/trk/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json new file mode 100644 index 00000000000..af3ce226e62 --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/markers/browser/markersFileDecorations.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "label": "Sorunlar", + "tooltip.1": "Bu dosyada 1 sorun var", + "tooltip.N": "Bu dosyada {0} sorun var", + "markers.showOnFile": "Dosya ve klasƶrlerde Hata & Uyarıları gƶster." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/markers/common/messages.i18n.json b/i18n/trk/src/vs/workbench/parts/markers/common/messages.i18n.json index 80f988e1d75..16978d67428 100644 --- a/i18n/trk/src/vs/workbench/parts/markers/common/messages.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/markers/common/messages.i18n.json @@ -5,7 +5,9 @@ // Do not edit this file. It is machine generated. { "viewCategory": "Gƶrüntüle", + "problems.view.toggle.label": "Sorunları AƧ/Kapat", "problems.view.show.label": "Sorunları Gƶster", + "problems.view.hide.label": "Sorunları Gizle", "problems.panel.configuration.title": "Sorunlar Gƶrünümü", "problems.panel.configuration.autoreveal": "Sorunlar gƶrünümünün; dosyalar aƧılırken, dosyaları otomatik olarak ortaya Ƨıkarıp Ƨıkarmayacağını denetler.", "markers.panel.title.problems": "Sorunlar", diff --git a/i18n/trk/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json b/i18n/trk/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json index 22387f166cb..3adbd7eb544 100644 --- a/i18n/trk/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "copyMarker": "Kopyala" + "copyMarker": "Kopyala", + "copyMarkerMessage": "Mesajı Kopyala" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json index dc3e6110e34..af8637daeca 100644 --- a/i18n/trk/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/performance/electron-browser/performance.contribution.i18n.json @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "slow": "Yavaş başlangıƧ tespit edildi", - "slow.detail": "Az ƶnce yavaş başlangıƧ yaşadığınız iƧin üzgünüz. Lütfen '{0}' uygulamasını profil oluşturucu etkinleştirilmiş olarak başlatın, profilleri bizle paylaşın, ve biz de başlangıcı yeniden harika yapmak iƧin Ƨok Ƨalışalım.", "prof.message": "Profiller başarıyla oluşturuldu.", "prof.detail": "Lütfen bir sorun (bildirimi) oluşturun ve aşağıdaki dosyaları manuel olarak ekleyin:\n{0}", "prof.restartAndFileIssue": "Sorun Oluştur ve Yeniden Başlat", diff --git a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 37e5169f3a8..fad9ab4f40b 100644 --- a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Klavye Kısayolları Dosyasını AƧ", "openWorkspaceSettings": "Ƈalışma Alanı Ayarlarını AƧ", "openFolderSettings": "Klasƶr Ayarlarını AƧ", - "pickFolder": "Klasƶr SeƧ", "configureLanguageBasedSettings": "Dile Ɩzel Ayarları Yapılandır...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Dili SeƧ" diff --git a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json index 4ad7bc7c2d8..5fa332cf96c 100644 --- a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesEditor.i18n.json @@ -13,5 +13,6 @@ "settingsFound": "{0} ayar eşleşti", "fileEditorWithInputAriaLabel": "{0}. Metin dosyası düzenleyici.", "fileEditorAriaLabel": "Metin dosyası düzenleyici.", + "defaultEditorReadonly": "Varsayılan ayarları geƧersiz kılmak iƧin sağ taraftaki düzeyicide düzenleme yapın.", "preferencesAriaLabel": "Varsayılan tercihler. Salt okunabilir metin editƶrü." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json index 5992f38bfb5..94a6b10edb2 100644 --- a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesRenderers.i18n.json @@ -5,16 +5,15 @@ // Do not edit this file. It is machine generated. { "emptyUserSettingsHeader": "Varsayılan ayarların üzerine yazmak iƧin ayarlarınızı buraya yerleştirin.", - "errorInvalidConfiguration": "Ayarlara yazılamıyor. Lütfen dosyadaki hataları/uyarıları düzeltin ve tekrar deneyin.", "emptyWorkspaceSettingsHeader": "Varsayılan kullanıcı ayarlarının üzerine yazmak iƧin ayarlarınızı buraya yerleştirin.", "emptyFolderSettingsHeader": "Ƈalışma alanı ayarlarındakilerin üzerine yazmak iƧin klasƶr ayarlarınızı buraya yerleştirin.", "defaultFolderSettingsTitle": "Varsayılan Klasƶr Ayarları", "defaultSettingsTitle": "Varsayılan Ayarlar", - "noSettingsFound": "HiƧbir Ayar Bulunamadı.", "editTtile": "Düzenle", "replaceDefaultValue": "Ayarlarda Değiştir", "copyDefaultValue": "Ayarlara Kopyala", "unsupportedPHPExecutablePathSetting": "Bu ayar, bir Kullanıcı Ayarı olmalıdır. PHP'yi Ƨalışma alanı iƧin yapılandırmak iƧin bir PHP dosyasını aƧın ve durum Ƨubuğundaki 'PHP Yolu'na tıklayın.", "unsupportedWorkspaceSetting": "Bu ayar, bir Kullanıcı Ayarı olmalıdır.", - "unsupportedWorkbenchSetting": "Bu ayar şu an uygulanamıyor. Ayar, bu klasƶrü aƧtığınızda uygulanacaktır." + "unsupportedWorkbenchSetting": "Bu ayar şu an uygulanamıyor. Ayar, bu klasƶrü aƧtığınızda uygulanacaktır.", + "unsupportedWorkbenchSettingDevMode": "Bu ayar şu an uygulanamıyor. Ayar, kaydederken kapsamını 'resource' olarak tanımladığınızda veya bu klasƶrü direkt olarak aƧtığınızda uygulanacaktır." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json index 53aacb0bd26..e5a6991d06e 100644 --- a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesWidgets.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "folderSettingsDetails": "Klasƶr Ayarları" + "defaultSettingsFuzzyPrompt": "Bulanık aramayı deneyin!", + "defaultSettings": "GeƧersiz kılmak iƧin ayarlarınızı sağ taraftaki düzeyiciye ekleyin.", + "noSettingsFound": "HiƧbir Ayar Bulunamadı.", + "folderSettingsDetails": "Klasƶr Ayarları", + "enableFuzzySearch": "Deneysel bulanık aramayı etkinleştir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json b/i18n/trk/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json index c618c0f3b12..ad4ed40e889 100644 --- a/i18n/trk/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/preferences/common/preferencesModels.i18n.json @@ -5,6 +5,6 @@ // Do not edit this file. It is machine generated. { "commonlyUsed": "Yaygın Olarak Kullanılan", - "noSettings": "Ayar Yok", + "mostRelevant": "En Uygun", "defaultKeybindingsHeader": "Tuş bağları dosyanıza yerleştirerek tuş bağlarının üzerine yazın." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json b/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json index bef4db281ad..3164aed2f83 100644 --- a/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/quickopen/browser/commandsHandler.i18n.json @@ -13,7 +13,6 @@ "actionNotEnabled": "'{0}' komutu geƧerli bağlamda etkin değil.", "recentlyUsed": "yakınlarda kullanıldı", "morecCommands": "diğer komutlar", - "commandLabel": "{0}: {1}", "cat.title": "{0}: {1}", "noCommandsMatching": "Eşleşen komut yok" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 31778d735c7..6d7913a19be 100644 --- a/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Yürürlüğe girmesi iƧin yeniden başlatma gerektiren bir ayar değişti.", "relaunchSettingDetail": "{0} uygulamasını yeniden başlatmak ve bu ayarı etkinleştirmek iƧin lütfen yeniden başlat butonuna basın.", - "restart": "Yeniden Başlat", - "relaunchWorkspaceMessage": "Bu Ƨalışma alanı değişikliği eklenti sistemimizi yeniden başlatmayı gerektirir.", - "reload": "Yeniden Yükle" + "restart": "&&Yeniden Başlat" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json index bc11b3fbd68..b3ff58f4005 100644 --- a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.i18n.json @@ -4,7 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "changes": "{0}/{1} değişiklik", + "change": "{0}/{1} değişiklik", + "show previous change": "Ɩnceki Değişikliği Gƶster", + "show next change": "Sonraki Değişikliği Gƶster", "editorGutterModifiedBackground": "Değiştirilen satırlar iƧin düzenleyici oluğu arka plan rengi.", "editorGutterAddedBackground": "Eklenen satırlar iƧin düzenleyici oluğu arka plan rengi.", - "editorGutterDeletedBackground": "Silinen satırlar iƧin düzenleyici oluğu arka plan rengi." + "editorGutterDeletedBackground": "Silinen satırlar iƧin düzenleyici oluğu arka plan rengi.", + "overviewRulerModifiedForeground": "Değiştirilen iƧerik iƧin genel bakış cetvelinin işaretleyici rengi.", + "overviewRulerAddedForeground": "Eklenen iƧerik iƧin genel bakış cetvelinin işaretleyici rengi.", + "overviewRulerDeletedForeground": "Silinen iƧerik iƧin genel bakış cetvelinin işaretleyici rengi." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json index 2fc322d2c8b..06bd99d62b1 100644 --- a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scm.contribution.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "toggleGitViewlet": "Git'i Gƶster", - "installAdditionalSCMProviders": "Ek SCM Sağlayıcıları Yükle...", "source control": "Kaynak Kontrolü", "toggleSCMViewlet": "SCM'yi Gƶster", "view": "Gƶrüntüle" diff --git a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index cd21a41cb42..7d7165d58a6 100644 --- a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,7 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Kaynak Kontrolü Sağlayıcıları", + "hideRepository": "Gizle", "commitMessage": "Mesaj (commit'lemek iƧin {0} tuşlarına basın)", + "installAdditionalSCMProviders": "Ek SCM Sağlayıcıları Yükle...", + "no open repo": "Aktif bir kaynak kontrolü sağlayıcısı yok.", "source control": "Kaynak Kontrolü", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json index 31355023a76..ad47c6f0e14 100644 --- a/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/search/browser/search.contribution.i18n.json @@ -6,9 +6,8 @@ { "showTriggerActions": "Ƈalışma Alanında Sembole Git...", "name": "Ara", - "showSearchViewlet": "Aramayı Gƶster", + "search": "Ara", "view": "Gƶrüntüle", - "findInFiles": "Dosyalarda Bul", "openAnythingHandlerDescription": "Dosyaya Git", "openSymbolDescriptionNormal": "Ƈalışma Alanında Sembole Git", "searchOutputChannelTitle": "Ara", @@ -16,7 +15,7 @@ "exclude": "Aramalarda dosyaları ve klasƶrleri hariƧ tutmak iƧin glob desenlerini yapılandırın. files.exclude ayarından, tüm glob desenlerini devralır.", "exclude.boolean": "Dosya yollarının eşleştirileceği glob deseni. Deseni etkinleştirmek veya devre dışı bırakmak iƧin true veya false olarak ayarlayın.", "exclude.when": "Eşleşen bir dosyanın eşdüzey dosyalarında ek denetim. Eşleşen dosya adı iƧin değişken olarak $(basename) kullanın.", - "useRipgrep": "Metin aramasında Ripgrep kullanılıp kullanılmayacağını denetler", - "useIgnoreFilesByDefault": "Yeni bir Ƨalışma alanında arama yaparken .gitignore ve .ignore dosyalarının varsayılan olarak kullanılıp kullanılmayacağını denetler.", - "search.quickOpen.includeSymbols": "Dosya sonuƧlarındaki bir global sembol aramasının sonuƧlarının Hızlı AƧ'a dahil edilip edilmeyeceğini yapılandırın." + "useRipgrep": "Metin ve dosya aramasında Ripgrep kullanılıp kullanılmayacağını denetler", + "search.quickOpen.includeSymbols": "Dosya sonuƧlarındaki bir global sembol aramasının sonuƧlarının Hızlı AƧ'a dahil edilip edilmeyeceğini yapılandırın.", + "search.followSymlinks": "Arama yaparken sembolik linklerin takip edilip edilmeyeceğini denetler." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json b/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json index 0af6fe9976d..416275aedbf 100644 --- a/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/search/browser/searchActions.i18n.json @@ -12,14 +12,18 @@ "previousSearchTerm": "Ɩnceki Arama Terimini Gƶster", "focusNextInputBox": "Sonraki Girdi Kutusuna Odakla", "focusPreviousInputBox": "Ɩnceki Girdi Kutusuna Odakla", + "showSearchViewlet": "Aramayı Gƶster", + "findInFiles": "Dosyalarda Bul", + "findInFilesWithSelectedText": "SeƧili Metni Dosyalarda Bul", "replaceInFiles": "Dosyalardakileri Değiştir", + "replaceInFilesWithSelectedText": "Dosyalardaki SeƧili Metni Değiştir", "findInWorkspace": "Ƈalışma Alanında Bul...", "findInFolder": "Klasƶrde Bul...", "RefreshAction.label": "Yenile", "ClearSearchResultsAction.label": "Arama SonuƧlarını Temizle", "FocusNextSearchResult.label": "Sonraki Arama Sonucuna Odakla", "FocusPreviousSearchResult.label": "Ɩnceki Arama Sonucuna Odakla", - "RemoveAction.label": "Kaldır", + "RemoveAction.label": "Sonlandır", "file.replaceAll.label": "Tümünü Değiştir", "match.replace.label": "Değiştir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json b/i18n/trk/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json index 29aaafa9f7d..c5778287f7d 100644 --- a/i18n/trk/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/search/browser/searchViewlet.i18n.json @@ -10,7 +10,7 @@ "searchScope.excludes": "hariƧ tutulacak klasƶrler", "label.excludes": "Aramada HariƧ Tutulan Kalıplar", "replaceAll.confirmation.title": "Tümünü Değiştir", - "replaceAll.confirm.button": "Değiştir", + "replaceAll.confirm.button": "&&Değiştir", "replaceAll.occurrence.file.message": "{1} dosyadaki {0} tekrarlama '{2}' ile değiştirildi.", "removeAll.occurrence.file.message": "{1} dosyadaki {0} tekrarlama değiştirildi.", "replaceAll.occurrence.files.message": "{1} dosyadaki {0} tekrarlama '{2}' ile değiştirildi.", @@ -28,28 +28,22 @@ "removeAll.occurrences.files.confirmation.message": "{1} dosyadaki {0} tekralama '{2}' ile değiştirilsin mi?", "replaceAll.occurrences.files.confirmation.message": "{1} dosyadaki {0} tekrarlama değiştirilsin mi?", "treeAriaLabel": "Arama SonuƧları", + "searchPathNotFoundError": "Arama yolu bulunamadı: {0}", "searchMaxResultsWarning": "SonuƧ kümesi yalnızca tüm eşleşmelerin bir alt kümesini iƧerir. Lütfen sonuƧları daraltmak iƧin aramanızda daha fazla ayrıntı belirtin.", "searchCanceled": "Arama, hiƧbir sonuƧ bulunamadan iptal edildi - ", "noResultsIncludesExcludes": "'{0}' iƧinde '{1}' hariƧ tutularak sonuƧ bulunamadı - ", "noResultsIncludes": "'{0}' iƧinde sonuƧ bulunamadı - ", "noResultsExcludes": "'{0}' hariƧ tutularak sonuƧ bulunamadı - ", - "noResultsFound": "SonuƧ bulunamadı. Yapılandırılan hariƧ tutmalar iƧin ayarlarınızı gƶzden geƧirin - ", + "noResultsFound": "SonuƧ bulunamadı. Yapılandırılan hariƧ tutmalar ve yok sayma dosyaları iƧin ayarlarınızı gƶzden geƧirin - ", "rerunSearch.message": "Yeniden ara", "rerunSearchInAll.message": "Tüm dosyalarda yeniden ara", "openSettings.message": "Ayarları AƧ", + "openSettings.learnMore": "Daha Fazla Bilgi Edin", "ariaSearchResultsStatus": "Arama ile {1} dosyada {0} sonuƧ bulundu", "search.file.result": "{1} dosyada {0} sonuƧ", "search.files.result": "{1} dosyada {0} sonuƧ", "search.file.results": "{1} dosyada {0} sonuƧ", "search.files.results": "{1} dosyada {0} sonuƧ", - "search.folder.file.result": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", - "search.folder.files.result": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", - "search.folder.file.results": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", - "search.folder.files.results": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", - "search.folders.file.result": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", - "search.folders.files.result": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", - "search.folders.file.results": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", - "search.folders.files.results": "{2} klasƶrdeki {1} dosyada {0} sonuƧ", "searchWithoutFolder": "Henüz bir klasƶr aƧmadınız. Şu an sadece aƧık dosyalar aranıyor - ", "openFolder": "Klasƶr AƧ" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/browser/searchWidget.i18n.json b/i18n/trk/src/vs/workbench/parts/search/browser/searchWidget.i18n.json index ed5a49ea8ea..3e1d9044099 100644 --- a/i18n/trk/src/vs/workbench/parts/search/browser/searchWidget.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/search/browser/searchWidget.i18n.json @@ -11,5 +11,6 @@ "search.placeHolder": "Ara", "label.Replace": "Değiştir: Değiştirme terimini girin ve ƶnizlemek iƧin Enter'a, iptal etmek iƧin Escape tuşuna basın", "search.replace.placeHolder": "Değiştir", - "regexp.validationFailure": "İfade her öğe ile eşleşiyor" + "regexp.validationFailure": "İfade her öğe ile eşleşiyor", + "regexp.backreferenceValidationFailure": "Geribaşvurular desteklenmiyor" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/search/common/queryBuilder.i18n.json b/i18n/trk/src/vs/workbench/parts/search/common/queryBuilder.i18n.json new file mode 100644 index 00000000000..096f6087c99 --- /dev/null +++ b/i18n/trk/src/vs/workbench/parts/search/common/queryBuilder.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "search.noWorkspaceWithName": "Ƈalışma alanında belirtilen isimde klasƶr yok: {0}" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index c8734bde48f..e8d5b2a4732 100644 --- a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "ParƧacık Ekle" + "snippet.suggestions.label": "ParƧacık Ekle", + "sep.userSnippet": "Kullanıcı ParƧacıkları", + "sep.extSnippet": "Eklenti ParƧacıkları" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 852c53c7188..ebad445a20b 100644 --- a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -4,6 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.language": "`contributes.{0}.language` ƶgesinde bilinmeyen dil. Sağlanan değer: {1}", + "invalid.path.0": "`contributes.{0}.path` ƶgesinde dize bekleniyor. Sağlanan değer: {1}", + "invalid.path.1": "`contributes.{0}.path` ƶgesinin ({1}) eklentinin klasƶründe ({2}) yer alması bekleniyor. Bu, eklentiyi taşınamaz yapabilir.", + "vscode.extension.contributes.snippets": "ParƧacıklara ekleme yapar.", + "vscode.extension.contributes.snippets-language": "Bu parƧacığın ekleneceği dilin tanımlayıcısı.", + "vscode.extension.contributes.snippets-path": "ParƧacıklar dosyasının yolu. Yol, eklenti klasƶrüne gƶrecelidir ve genellikle './snippets/' ile başlar.", + "badVariableUse": "'{0}' eklentisindeki bir veya daha Ƨok parƧacık yüksek olasılıkla parƧacık değişkenleri ile parƧacık yer tutucularını karıştırıyor (daha fazla bilgi iƧin https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax adresini ziyaret edin).", + "badFile": "ParƧacık dosyası \"{0}\" okunamadı.", "source.snippet": "Kullanıcı ParƧacığı", "detail.snippet": "{0} ({1})", "snippetSuggest.longLabel": "{0}, {1}" diff --git a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json index ae1ee31d459..4dd0be7f4ee 100644 --- a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.i18n.json @@ -11,6 +11,9 @@ "JsonSchema.tasks.presentation": "Gƶrevin Ƨıktısını gƶsterip, girdisini okumak iƧin kullanılacak paneli yapılandırır.", "JsonSchema.tasks.presentation.echo": "Ƈalıştırılan komutun panele yazdırılıp yazdırılmayacağını denetler. Varsayılan olarak aƧıktır.", "JsonSchema.tasks.presentation.focus": "Panelin, kendisine odaklanmaya izin verip vermeyeceğini denetler. Varsayılan olarak kapalıdır. Eğer \"true\" olarak ayarlanırsa panel de açığa Ƨıkar.", + "JsonSchema.tasks.presentation.reveal.always": "Bu gƶrev yürütülürken terminali her zaman ortaya Ƨıkarır.", + "JsonSchema.tasks.presentation.reveal.silent": "Sadece hiƧbir sorun eşleştiricisi gƶrevle ilişkilendirilmemiş ve gƶrev Ƨalıştırılırken hata oluşuyorsa terminali ortaya Ƨıkar.", + "JsonSchema.tasks.presentation.reveal.never": "Bu gƶrev yürütülürken terminali hiƧbir zaman ortaya Ƨıkarmaz.", "JsonSchema.tasks.presentation.reveals": "Panelin Ƨalıştırdığı gƶrevin ortaya Ƨıkarılıp Ƨıkarılmayacağını denetler. Varsayılan \"always\"tir.", "JsonSchema.tasks.presentation.instance": "Panelin gƶrevler arasında paylaşılacağı mı, bu gƶreve mi tahsis edileceği yoksa her Ƨalıştırmada yeni bir panel mi oluşturulacağını denetler.", "JsonSchema.tasks.terminal": "'terminal' ƶzelliği kullanım dışıdır. Bunun yerine 'presentation' ƶzelliğini kullanın.", @@ -22,7 +25,8 @@ "JsonSchema.tasks.group.test": "Gƶrevleri 'Test Gƶrevini Ƈalıştır' komutu ile ulaşılabilecek şekilde bir test gƶrevi olarak işaretler.", "JsonSchema.tasks.group.none": "Gƶrevi grupsuz olarak atar", "JsonSchema.tasks.group": "Bu gƶrevin ait olduğu Ƨalıştırma grubunu tanımlar. Derleme grubuna eklemek iƧin \"build\"ı ve test grubuna eklemek iƧin \"test\"i destekler.", - "JsonSchema.tasks.type": "Gƶrevin bir işlem olarak veya bir kabukta komut olarak Ƨalıştırılıp Ƨalıştırılmayacağını tanımlar. Varsayılan işlem olarak Ƨalıştırmaktır.", + "JsonSchema.tasks.type": "Gƶrevin bir işlem olarak veya bir kabukta komut olarak Ƨalıştırılıp Ƨalıştırılmayacağını tanımlar.", + "JsonSchema.tasks.label": "Gƶrevin kullanıcı arayüzü etiketi", "JsonSchema.version": "Yapılandırmanın sürüm numarası.", "JsonSchema.tasks.identifier": "launch.json veya dependsOn maddesindeki gƶreve atıfta başvuracak, kullanıcı tanımlı bir tanımlayıcı.", "JsonSchema.tasks.taskLabel": "Gƶrevin etiketi", diff --git a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index dc3290986ba..38414621301 100644 --- a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Gƶrevler", - "ConfigureTaskRunnerAction.noWorkspace": "Gƶrevler, sadece Ƨalışma alanı klasƶründe mevcuttur.", - "ConfigureTaskRunnerAction.quickPick.template": "Bir Gƶrev Ƈalıştırıcısı SeƧ", - "ConfigureTaskRunnerAction.autoDetecting": "{0} gƶrevleri otomatik algılanıyor", - "ConfigureTaskRunnerAction.autoDetect": "Gƶrev sisteminin otomatik algılanması başarısız oldu. Varsayılan şablon kullanılıyor. Ayrıntılar iƧin gƶrev Ƨıktısına bakın.", - "ConfigureTaskRunnerAction.autoDetectError": "Gƶrev sisteminin otomatik algılanması sırasında hatalar oluştu. Ayrıntılar iƧin gƶrev Ƨıktısına bakın.", - "ConfigureTaskRunnerAction.failed": "Ā '.vscode' klasƶrü iƧinde 'tasks.json' dosyası oluşturulamıyor. Ayrıntılar iƧin gƶrev Ƨıktısına bakın.", - "ConfigureTaskRunnerAction.label": "Gƶrev Ƈalıştırıcısını Yapılandır", + "ConfigureTaskRunnerAction.label": "Gƶrevi Yapılandır", "ConfigureBuildTaskAction.label": "Derleme Gƶrevini Yapılandır", "CloseMessageAction.label": "Kapat", "ShowTerminalAction.label": "Terminali Gƶrüntüle", @@ -19,12 +13,14 @@ "manyMarkers": "99+", "runningTasks": "Ƈalışan Gƶrevleri Gƶster", "tasks": "Gƶrevler", - "TaskSystem.noHotSwap": "Gƶrev yürütme motorunu değiştirmek VS Code'u yeniden başlatmayı gerektirir. Değişiklik yok sayıldı.", + "TaskSystem.noHotSwap": "Aktif bir gƶrev Ƨalıştıran gƶrev yürütme motorunu değiştirmek pencereyi yeniden yüklemeyi gerektirir", + "TaskServer.folderIgnored": "{0} klasƶrü, 0.1.0 gƶrev sürümünü kullandığı iƧin yok sayıldı.", "TaskService.noBuildTask1": "Derleme gƶrevi tanımlanmamış. tasks.json dosyasındaki bir gƶrevi 'isBuildCommand' ile işaretleyin.", "TaskService.noBuildTask2": "Derleme gƶrevi tanımlanmamış. tasks.json dosyasındaki bir gƶrevi, bir 'build' grubu olarak işaretleyin.", "TaskService.noTestTask1": "Test gƶrevi tanımlanmamış. tasks.json dosyasındaki bir testi 'isTestCommand' ile işaretleyin.", "TaskService.noTestTask2": "Test gƶrevi tanımlanmamış. tasks.json dosyasındaki bir gƶrevi, bir 'test' grubu olarak işaretleyin.", "TaskServer.noTask": " Ƈalıştırılmak istenen {0} gƶrevi bulunamadı.", + "TaskService.associate": "ilişkili", "TaskService.attachProblemMatcher.continueWithout": "Gƶrev Ƨıktısını taramadan devam et", "TaskService.attachProblemMatcher.never": "HiƧbir zaman gƶrev Ƨıktısını tarama", "TaskService.attachProblemMatcher.learnMoreAbout": "Gƶrev Ƨıktısını tarama hakkında daha fazla bilgi edin", @@ -35,7 +31,9 @@ "TaskSystem.activeSame.noBackground": " '{0}' gƶrevi zaten aktif. Gƶrevi sonlandırmak iƧin Gƶrevler menüsünden `Gƶrevi Sonlandır...`ı kullanın.", "TaskSystem.active": "Ƈalışan bir gƶrev zaten var. Bir başkasını Ƨalıştırmadan ƶnce bu gƶrevi sonlandırın.", "TaskSystem.restartFailed": "{0} gƶrevini sonlandırma ve yeniden başlatma başarısız oldu", + "TaskService.noConfiguration": "Hata: {0} gƶrev algılaması aşağıdaki yapılandırma iƧin bir gƶrev eklemesi yapmıyor:\n{1}\nYapılandırma yok sayılacaktır.\n", "TaskSystem.configurationErrors": "Hata: belirtilen gƶrev yapılandırmasında doğrulama hataları var ve kullanılamıyor. Lütfen ilk olarak hataları düzeltin.", + "taskService.ignoreingFolder": "{0} Ƨalışma alanı klasƶrü iƧin gƶrev yapılandırmaları yok sayılıyor. Birden Ƨok klasƶrlü Ƨalışma alanı gƶrevi desteği, tüm klasƶrlerin 2.0.0 gƶrev sürümünü kullanmasını gerektirir\n", "TaskSystem.invalidTaskJson": "Hata: tasks.json dosyasının iƧeriğinde sentaks hataları var. Lütfen, bir gƶrevi Ƨalıştırmadan ƶnce hataları düzeltin.\n", "TaskSystem.runningTask": "Ƈalışan bir gƶrev var. Bu gƶrevi sonlandırmak istiyor musunuz?", "TaskSystem.terminateTask": "&&Gƶrevi Sonlandır", @@ -47,24 +45,33 @@ "recentlyUsed": "yakınlarda kullanılan gƶrevler", "configured": "yapılandırılmış gƶrevler", "detected": "algılanan gƶrevler", + "TaskService.ignoredFolder": "Aşağıdaki Ƨalışma alanı klasƶrleri, 0.1.0 gƶrev sürümünü kullandıkları iƧin yok sayıldı.", + "TaskService.notAgain": "Tekrar Gƶsterme", + "TaskService.ok": "Tamam", + "TaskService.pickRunTask": "Ƈalıştırılacak gƶrevi seƧin", + "TaslService.noEntryToRun": "Ƈalıştırılacak hiƧbir gƶrev bulunamadı. Gƶrevleri Yapılandır...", "TaskService.fetchingBuildTasks": "Derleme gƶrevleri alınıyor...", - "TaskService.noBuildTaskTerminal": "Derleme gƶrevi bulunamadı. Yeni bir tane tanımlamak iƧin 'Derleme Gƶrevini Yapılandır'a basın.", "TaskService.pickBuildTask": "Ƈalıştırılacak derleme gƶrevini seƧin", + "TaskService.noBuildTask": "Ƈalıştırılacak hiƧbir derleme gƶrevi bulunamadı. Gƶrevleri Yapılandır...", "TaskService.fetchingTestTasks": "Test gƶrevleri alınıyor...", - "TaskService.noTestTaskTerminal": "Test gƶrevi bulunamadı. Yeni bir tane tanımlamak iƧin 'Gƶrev Ƈalıştırıcısını Yapılandır'a basın.", "TaskService.pickTestTask": "Ƈalıştırılacak test gƶrevini seƧin", - "TaskService.noTaskRunning": "Şu an Ƨalışan bir gƶrev yok.", + "TaskService.noTestTaskTerminal": "Ƈalıştırılacak hiƧbir test gƶrevi bulunamadı. Gƶrevleri Yapılandır...", "TaskService.tastToTerminate": "Sonlandırılacak gƶrevi seƧin", + "TaskService.noTaskRunning": "Şu an Ƨalışan bir gƶrev yok", "TerminateAction.noProcess": "Başlatılan işlem artık mevcut değil. Eğer gƶrev arka plan gƶrevleri oluşturduysa, VS Code'dan Ƨıkmak işlemlerin sahipsiz kalmasına neden olabilir.", "TerminateAction.failed": "Ƈalışan gƶrevi sonlandırma başarısız oldu.", - "TaskService.noTaskToRestart": "Yeniden başlatılacak bir gƶrev yok.", "TaskService.tastToRestart": "Yeniden başlatılacak gƶrevi seƧin", - "TaskService.defaultBuildTaskExists": "{0} zaten varsayılan derleme gƶrevi olarak işaretlenmiş.", + "TaskService.noTaskToRestart": "Yeniden başlatılacak bir gƶrev yok", + "TaskService.template": "Bir Gƶrev Şablonu SeƧin", + "TaskService.createJsonFile": "Şablondan tasks.json dosyası oluştur", + "TaskService.openJsonFile": "tasks.json dosyasını aƧ", + "TaskService.pickTask": "Yapılandırmak iƧin bir gƶrev seƧin", + "TaskService.defaultBuildTaskExists": "{0} zaten varsayılan derleme gƶrevi olarak işaretlenmiş", "TaskService.pickDefaultBuildTask": "Varsayılan derleme gƶrevi olarak kullanılacak gƶrevi seƧin", "TaskService.defaultTestTaskExists": "{0} zaten varsayılan test gƶrevi olarak işaretlenmiş.", "TaskService.pickDefaultTestTask": "Varsayılan test gƶrevi olarak kullanılacak gƶrevi seƧin", - "TaskService.noTaskIsRunning": "Ƈalışan bir gƶrev yok.", "TaskService.pickShowTask": "Ƈıktısını gƶstermek iƧin gƶrev seƧin", + "TaskService.noTaskIsRunning": "Ƈalışan bir gƶrev yok", "ShowLogAction.label": "Gƶrev Günlüğünü Gƶster", "RunTaskAction.label": "Gƶrevi Ƈalıştır", "RestartTaskAction.label": "Ƈalışan Gƶrevi Yeniden Başlat", diff --git a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index d3492257f35..2e339c2d029 100644 --- a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Gƶrev Ƨalıştırılırken bir hata oluştu. Detaylar iƧin gƶrev Ƨıktısı günlüğüne bakın.", + "dependencyFailed": "'{1}' Ƨalışma alanı klasƶründe, '{0}' bağımlı gƶrevi Ƨƶzümlenemiyor", "TerminalTaskSystem.terminalName": "Gƶrev - {0}", "reuseTerminal": "Terminal gƶrevler tarafından tekrar kullanılacak, kapatmak iƧin herhangi bir tuşa basın.", "TerminalTaskSystem": "UNC sürücüsünde kabuk komutu yürütülemez.", diff --git a/i18n/trk/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json b/i18n/trk/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json index 0c8941a88db..fc4afcade92 100644 --- a/i18n/trk/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/tasks/node/taskConfiguration.i18n.json @@ -11,6 +11,8 @@ "ConfigurationParser.unknownMatcherKind": "Uyarı: tanımlanan sorun eşleştirici bilinmiyor. Desteklenen türler: dize | ProblemMatcher | (dize | ProblemMatcher)[].\n{0}\n", "ConfigurationParser.invalidVaraibleReference": "Hata: GeƧersiz problemMatcher başvusu: {0}\n", "ConfigurationParser.noTaskType": "Hata: 'tasks' yapılandırması bir 'type' ƶzelliğine sahip olmalıdır. Yapılandırma yok sayılacaktır.\n{0}\n", + "ConfigurationParser.noTypeDefinition": "Hata: '{0}' olarak kayıtlı bir gƶrev türü yok. İlgili gƶrev sağlayıcısını iƧeren bir eklentiyi yüklemeyi mi unuttunuz?", + "ConfigurationParser.missingRequiredProperty": "Hata: ihtiyaƧ duyulan '{1}' ƶzelliği, '{0}' gƶrev yapılandırmasında eksik. Gƶrev yapılandırması yok sayılacaktır.", "ConfigurationParser.notCustom": "Hata: 'tasks' bir ƶzel gƶrev olarak tanımlanmamış. Yapılandırma yok sayılacaktır.\n{0}\n", "ConfigurationParser.noTaskName": "Hata: 'tasks' bir 'taskName' ƶzelliği belirtmelidir. Gƶrev yok sayılacaktır.\n{0}\n", "taskConfiguration.shellArgs": "Uyarı: '{0}' gƶrevi bir kabuk komutudur ve komut adı veya argümanlarından biri kaçış karakteri iƧermeyen boşluklar iƧeriyor. Doğru komut satırı alıntılamasını sağlamak iƧin lütfen argümanları komutlarla birleştirin.", diff --git a/i18n/trk/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json index e7ce1ac11db..82b1bdbdd46 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.i18n.json @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "entryAriaLabel": "{0}, terminal seƧici", + "termEntryAriaLabel": "{0}, terminal seƧici", + "termCreateEntryAriaLabel": "{0}, yeni terminal oluştur", + "'workbench.action.terminal.newplus": "$(plus) Yeni Entegre Terminal Oluştur", "noTerminalsMatching": "Eşleşen terminal yok", "noTerminalsFound": "AƧık terminal yok" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json index 4965ec13e6b..40915bbf5c9 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "quickOpen.terminal": "Tüm AƧık Terminalleri Gƶster", + "terminal": "Terminal", "terminalIntegratedConfigurationTitle": "Entegre Terminal", "terminal.integrated.shell.linux": "Terminalin Linux'da kullandığı kabuğun yolu.", "terminal.integrated.shellArgs.linux": "Linux terminalindeyken kullanılacak komut satırı argümanları.", @@ -14,7 +15,6 @@ "terminal.integrated.shellArgs.windows": "Windows terminalindeyken kullanılacak komut satırı argümanları.", "terminal.integrated.rightClickCopyPaste": "Ayarlandığında, terminal iƧinde sağ tıklandığında bağlam menüsünün gƶrünmesini engeller, onun yerine bir seƧim varsa kopyalama yapar, bir seƧim yoksa yapıştırma yapar.", "terminal.integrated.fontFamily": "Terminalin yazı tipi ailesini denetler; bu, varsayılan olarak editor.fontFamily'nin değeridir.", - "terminal.integrated.fontLigatures": "Terminalde yazı tipi ligatürlerinin etkinleştirilip etkinleştirilmeyeceğini denetler.", "terminal.integrated.fontSize": "Terminaldeki yazı tipi boyutunu piksel olarak denetler.", "terminal.integrated.lineHeight": "Terminalin satır yüksekliğini denetler, bu sayı gerƧek satır yüksekliğini piksel olarak elde etmek iƧin terminal yazı tipi boyutu ile Ƨarpılır.", "terminal.integrated.enableBold": "Terminalde kalın yazının etkinleştirilip etkinleştirilmeyeceği; bu, terminal kabuğunun desteğini gerektirir.", @@ -28,7 +28,6 @@ "terminal.integrated.env.osx": "OS X'deki terminal tarafından kullanılacak VS Code işlemine eklenecek ortam değişkenlerini iƧeren nesne", "terminal.integrated.env.linux": "Linux'daki terminal tarafından kullanılacak VS Code işlemine eklenecek ortam değişkenlerini iƧeren nesne", "terminal.integrated.env.windows": "Windows'daki terminal tarafından kullanılacak VS Code işlemine eklenecek ortam değişkenlerini iƧeren nesne", - "terminal": "Terminal", "terminalCategory": "Terminal", "viewCategory": "Gƶrüntüle" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 7ba23fb595c..539713491df 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -7,6 +7,7 @@ "workbench.action.terminal.toggleTerminal": "Entegre Terminali AƧ/Kapat", "workbench.action.terminal.kill": "Aktif Terminal Ɩrneğini Sonlandır", "workbench.action.terminal.kill.short": "Terminali Sonlandır", + "workbench.action.terminal.quickKill": "Terminal Ɩrneğini Sonlandır", "workbench.action.terminal.copySelection": "SeƧimi Kopyala", "workbench.action.terminal.selectAll": "Tümünü SeƧ", "workbench.action.terminal.deleteWordLeft": "Soldaki Sƶzcüğü Sil", @@ -15,7 +16,6 @@ "workbench.action.terminal.new.short": "Yeni Terminal", "workbench.action.terminal.focus": "Terminale Odakla", "workbench.action.terminal.focusNext": "Sonraki Terminale Odakla", - "workbench.action.terminal.focusAtIndex": "{0}. Terminale Odakla", "workbench.action.terminal.focusPrevious": "Ɩnceki Terminale Odakla", "workbench.action.terminal.paste": "Aktif Terminale Yapıştır", "workbench.action.terminal.DefaultShell": "Varsayılan Kabuğu SeƧ", @@ -35,5 +35,8 @@ "workbench.action.terminal.rename": "Yeniden Adlandır", "workbench.action.terminal.rename.prompt": "Terminal adını girin", "workbench.action.terminal.focusFindWidget": "Bulma Aracına Odakla", - "workbench.action.terminal.hideFindWidget": "Bulma Aracını Gizle" + "workbench.action.terminal.hideFindWidget": "Bulma Aracını Gizle", + "nextTerminalFindTerm": "Sonraki Arama Terimini Gƶster", + "previousTerminalFindTerm": "Ɩnceki Arama Terimini Gƶster", + "quickOpenTerm": "Aktif Terminali Değiştir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 69009eea2db..a994ebe0909 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "Terminalin ƶn plan rengi.", "terminalCursor.foreground": "Terminal imlecinin ƶn plan rengi.", "terminalCursor.background": "Terminal imlecinin arka plan rengi. Bir blok imlecinin kapladığı bir karakterin rengini ƶzelleştirmeyi sağlar.", + "terminal.selectionBackground": "Terminalin seƧim arkaplanı rengi.", "terminal.ansiColor": "Terminalde '{0}' ANSI rengi." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json index be9f370adec..92d6df37712 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.i18n.json @@ -5,7 +5,6 @@ // Do not edit this file. It is machine generated. { "copy": "Kopyala", - "createNewTerminal": "Yeni Terminal", "paste": "Yapıştır", "selectAll": "Tümünü SeƧ", "clear": "Temizle" diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json index 28fa93d323a..a30794054e1 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalService.i18n.json @@ -10,6 +10,5 @@ "never again": "Tamam, Tekrar Gƶsterme", "terminal.integrated.chooseWindowsShell": "Tercih ettiğiniz terminal kabuğunu seƧin, bunu daha sonra ayarlarınızdan değiştirebilirsiniz", "terminalService.terminalCloseConfirmationSingular": "Aktif bir terminal oturumu var, sonlandırmak istiyor musunuz?", - "terminalService.terminalCloseConfirmationPlural": "{0} aktif terminal oturumu var, bunları sonlandırmak istiyor musunuz?", - "yes": "Evet" + "terminalService.terminalCloseConfirmationPlural": "{0} aktif terminal oturumu var, bunları sonlandırmak istiyor musunuz?" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/trk/src/vs/workbench/parts/update/electron-browser/update.i18n.json index a0c1e2f9685..61ebe35f50c 100644 --- a/i18n/trk/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -14,7 +14,7 @@ "licenseChanged": "Lisans koşullarımız değişti, lütfen inceleyin.", "license": "Lisansı Oku", "neveragain": "Tekrar Gƶsterme", - "64bitisavailable": "Windows 64 bit iƧin {0} şu an mevcut!", + "64bitisavailable": "64-bit Windows iƧin {0} şu an mevcut!", "learn more": "Daha Fazla Bilgi Edin", "updateIsReady": "Yeni {0} güncellemesi var.", "thereIsUpdateAvailable": "Bir güncelleştirme var.", diff --git a/i18n/trk/src/vs/workbench/parts/views/browser/views.i18n.json b/i18n/trk/src/vs/workbench/parts/views/browser/views.i18n.json index feb0e4ce24b..fe27ce7154b 100644 --- a/i18n/trk/src/vs/workbench/parts/views/browser/views.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/views/browser/views.i18n.json @@ -5,5 +5,5 @@ // Do not edit this file. It is machine generated. { "viewToolbarAriaLabel": "{0} eylem", - "removeView": "Kenar Ƈubuğundan Kaldır" + "hideView": "Kenar Ƈubuğunda Gizle" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 8098995a486..0cde8865979 100644 --- a/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -9,7 +9,7 @@ "welcomePage.start": "BaşlangıƧ", "welcomePage.newFile": "Yeni dosya", "welcomePage.openFolder": "Klasƶr aƧ...", - "welcomePage.cloneGitRepository": "Git deposu kopyala...", + "welcomePage.addWorkspaceFolder": "Ƈalışma alanı klasƶrü ekle...", "welcomePage.recent": "Son Kullanılanlar", "welcomePage.moreRecent": "Diğerleri...", "welcomePage.noRecentFolders": "Son kullanılan klasƶr yok", diff --git a/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json b/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json index faac6bda704..2b1dfd41f12 100644 --- a/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.i18n.json @@ -9,6 +9,8 @@ "welcomePage.typeScript": "TypeScript", "welcomePage.python": "Python", "welcomePage.php": "PHP", + "welcomePage.azure": "Azure", + "welcomePage.showAzureExtensions": "Azure eklentilerini gƶster", "welcomePage.docker": "Docker", "welcomePage.vim": "Vim", "welcomePage.sublime": "Sublime", diff --git a/i18n/trk/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json b/i18n/trk/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json index 80ad1bc8870..ca2222963ff 100644 --- a/i18n/trk/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "editorWalkThrough": "İnteraktif Oyun Alanı", - "editorWalkThrough.title": "İnteraktif Oyun Alanı" + "editorWalkThrough.title": "İnteraktif Oyun Alanı", + "editorWalkThrough": "İnteraktif Oyun Alanı" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json b/i18n/trk/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json new file mode 100644 index 00000000000..4c2ceda75b6 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/configuration/common/configurationExtensionPoint.i18n.json @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.configuration.title": "Ayarların bir ƶzeti. Bu etiket ayar dosyasında ayırıcı yorum olarak kullanılacaktır.", + "vscode.extension.contributes.configuration.properties": "Yapılandırma ƶzelliklerinin aƧıklaması.", + "scope.window.description": "Kullanıcı veya Ƨalışma alanında yapılandırılabilen Windows'a ƶzel yapılandırma.", + "scope.resource.description": "Kullanıcı veya Ƨalışma alanında yapılandırılabilen kaynağa ƶzel yapılandırma.", + "scope.description": "Yapılandırmanın uygulanabilir olduğu kapsam. Mevcut kapsamlar 'window' ve 'resource'tır.", + "vscode.extension.contributes.configuration": "Yapılandırma ayarlarına ekleme yapar.", + "invalid.title": "'configuration.title' bir dize olmalıdır", + "vscode.extension.contributes.defaultConfiguration": "Varsayılan düzenleyici yapılandırma ayarlarına dil bazında ekleme yapar.", + "invalid.properties": "'configuration.properties' bir nesne olmalıdır", + "invalid.allOf": "'configuration.allOf' kullanım dışıdır ve artık kullanılmamalıdır. Bunun yerine, birden Ƨok yapılandırma bƶlümlerini bir dizi olarak 'configuration' ekleme noktasına geƧirin.", + "workspaceConfig.folders.description": "Ƈalışma alanına yüklenecek klasƶrler listesi.", + "workspaceConfig.path.description": "Bir dosya yolu. ƶr. `/root/folderA` veya Ƨalışma alanı dosyasının konumuna karşı Ƨƶzümlenecek gƶreceli bir yol iƧin `./folderA`.", + "workspaceConfig.name.description": "Klasƶr iƧin isteğe bağlı bir ad.", + "workspaceConfig.uri.description": "Klasƶrün URI'si", + "workspaceConfig.settings.description": "Ƈalışma alanı ayarları", + "workspaceConfig.extensions.description": "Ƈalışma alanı eklentileri", + "unknownWorkspaceProperty": "Bilinmeyen Ƨalışma alanı yapılandırması ƶzelliği" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json index 49c5097a73f..4c2ceda75b6 100644 --- a/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -4,17 +4,21 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.configuration": "Yapılandırma ayarlarına ekleme yapar.", "vscode.extension.contributes.configuration.title": "Ayarların bir ƶzeti. Bu etiket ayar dosyasında ayırıcı yorum olarak kullanılacaktır.", "vscode.extension.contributes.configuration.properties": "Yapılandırma ƶzelliklerinin aƧıklaması.", "scope.window.description": "Kullanıcı veya Ƨalışma alanında yapılandırılabilen Windows'a ƶzel yapılandırma.", "scope.resource.description": "Kullanıcı veya Ƨalışma alanında yapılandırılabilen kaynağa ƶzel yapılandırma.", "scope.description": "Yapılandırmanın uygulanabilir olduğu kapsam. Mevcut kapsamlar 'window' ve 'resource'tır.", - "invalid.type": "eğer ayarlanırsa, 'configuration.type' ƶgesi 'object' olarak ayarlanmalıdır", + "vscode.extension.contributes.configuration": "Yapılandırma ayarlarına ekleme yapar.", "invalid.title": "'configuration.title' bir dize olmalıdır", "vscode.extension.contributes.defaultConfiguration": "Varsayılan düzenleyici yapılandırma ayarlarına dil bazında ekleme yapar.", "invalid.properties": "'configuration.properties' bir nesne olmalıdır", - "workspaceConfig.id.description": "Ƈalışma Alanı Tanımlayıcısı. Değiştirilirken kaybolabilecek dahili Ƨalışma alanı durumunu depolamak iƧin kullanılır.", - "workspaceConfig.folders.description": "Ƈalışma alanında yüklenecek klasƶrler listesi. Bir dosya yolu olmalıdır. ƶr. `file:///root/folderA`", - "workspaceConfig.settings.description": "Ƈalışma alanı ayarları" + "invalid.allOf": "'configuration.allOf' kullanım dışıdır ve artık kullanılmamalıdır. Bunun yerine, birden Ƨok yapılandırma bƶlümlerini bir dizi olarak 'configuration' ekleme noktasına geƧirin.", + "workspaceConfig.folders.description": "Ƈalışma alanına yüklenecek klasƶrler listesi.", + "workspaceConfig.path.description": "Bir dosya yolu. ƶr. `/root/folderA` veya Ƨalışma alanı dosyasının konumuna karşı Ƨƶzümlenecek gƶreceli bir yol iƧin `./folderA`.", + "workspaceConfig.name.description": "Klasƶr iƧin isteğe bağlı bir ad.", + "workspaceConfig.uri.description": "Klasƶrün URI'si", + "workspaceConfig.settings.description": "Ƈalışma alanı ayarları", + "workspaceConfig.extensions.description": "Ƈalışma alanı eklentileri", + "unknownWorkspaceProperty": "Bilinmeyen Ƨalışma alanı yapılandırması ƶzelliği" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json b/i18n/trk/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json index f92e145a115..cb3f2725bc7 100644 --- a/i18n/trk/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json +++ b/i18n/trk/src/vs/workbench/services/configuration/node/configurationEditingService.i18n.json @@ -4,18 +4,27 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "open": "Ayarları AƧ", + "openTasksConfiguration": "Gƶrev Yapılandırmasını AƧ", + "openLaunchConfiguration": "Başlatma Yapılandırmasını AƧ", "close": "Kapat", - "saveAndRetry": "Ayarları Kaydet ve Yeniden Dene", + "open": "Ayarları AƧ", + "saveAndRetry": "Kaydet ve Yeniden Dene", "errorUnknownKey": "{0} dosyasına, {1} kayıtlı bir yapılandırma olmadığı iƧin yazılamıyor.", "errorInvalidFolderConfiguration": "{0}, klasƶr kaynak kapsamını desteklemediği iƧin klasƶr ayarlarına yazılamıyor.", "errorInvalidUserTarget": "{0}, global kapsamı desteklemediği iƧin kullanıcı ayarlarına yazılamıyor.", + "errorInvalidWorkspaceTarget": "{0}, birden Ƨok klasƶrlü Ƨalışma alanında Ƨalışma alanı kapsamını desteklemediği iƧin Ƈalışma Alanı Ayarları'na yazılamıyor.", "errorInvalidFolderTarget": "HiƧbir kaynak belirtilmediği iƧin klasƶr ayarlarına yazılamıyor.", "errorNoWorkspaceOpened": "HiƧbir Ƨalışma alanı aƧık olmadığı iƧin {0}'a yazılamıyor. Lütfen ilk olarak bir Ƨalışma alanı aƧın ve tekrar deneyin.", - "errorInvalidConfiguration": "Ayarlara yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin **Kullanıcı Ayarları'nı** aƧın ve tekrar deneyin.", - "errorInvalidConfigurationWorkspace": "Ayarlara yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin **Ƈalışma Alanı Ayarları'nı** aƧın ve tekrar deneyin.", - "errorConfigurationFileDirty": "Dosya kaydedilmemiş değişiklikler iƧerdiği iƧin ayarlara yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin **Kullanıcı Ayarları'nı** aƧın ve tekrar deneyin.", - "errorConfigurationFileDirtyWorkspace": "Dosya kaydedilmemiş değişiklikler iƧerdiği iƧin ayarlara yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin **Ƈalışma Alanı Ayarları'nı** aƧın ve tekrar deneyin.", + "errorInvalidTaskConfiguration": "Gƶrevler dosyasına yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin **Gƶrevler** dosyasını aƧın ve tekrar deneyin.", + "errorInvalidLaunchConfiguration": "Başlatma dosyasına yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin **Başlatma** dosyasını aƧın ve tekrar deneyin.", + "errorInvalidConfiguration": "Kullanıcı ayarlarına yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin **Kullanıcı Ayarları** dosyasını aƧın ve tekrar deneyin.", + "errorInvalidConfigurationWorkspace": "Ƈalışma alanı ayarlarına yazılamıyor. Lütfen hata/uyarıları düzeltmek iƧin **Ƈalışma Alanı Ayarları** dosyasını aƧın ve tekrar deneyin.", + "errorInvalidConfigurationFolder": "Klasƶr ayarlarına yazılamıyor. Lütfen hata/uyarıları düzeltmek iƧin **{0}** klasƶrü altındaki **Klasƶr Ayarları** dosyasını kaydedin ve tekrar deneyin.", + "errorTasksConfigurationFileDirty": "Gƶrevler dosyası kaydedilmemiş değişiklikler iƧerdiği iƧin bu dosyaya yazılamıyor. Lütfen **Gƶrev Yapılandırması** dosyasını kaydedin ve tekrar deneyin.", + "errorLaunchConfigurationFileDirty": "Başlatma dosyası kaydedilmemiş değişiklikler iƧerdiği iƧin bu dosyaya yazılamıyor. Lütfen **Başlatma Yapılandırması** dosyasını kaydedin ve tekrar deneyin.", + "errorConfigurationFileDirty": "Dosya kaydedilmemiş değişiklikler iƧerdiği iƧin kullanıcı ayarlarına yazılamıyor. Lütfen **Kullanıcı Ayarları** dosyasını kaydedin ve tekrar deneyin.", + "errorConfigurationFileDirtyWorkspace": "Dosya kaydedilmemiş değişiklikler iƧerdiği iƧin Ƨalışma alanı ayarlarına yazılamıyor. Lütfen **Ƈalışma Alanı Ayarları** dosyasını kaydedin ve tekrar deneyin.", + "errorConfigurationFileDirtyFolder": "Dosya kaydedilmemiş değişiklikler iƧerdiği iƧin klasƶr ayarlarına yazılamıyor. Lütfen **{0}** klasƶrü altındaki **Klasƶr Ayarları** dosyasını kaydedin ve tekrar deneyin.", "userTarget": "Kullanıcı Ayarları", "workspaceTarget": "Ƈalışma Alanı Ayarları", "folderTarget": "Klasƶr Ayarları" diff --git a/i18n/trk/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json b/i18n/trk/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json new file mode 100644 index 00000000000..8b6ad71cd4e --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/decorations/browser/decorationsService.i18n.json @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/editor/common/editorService.i18n.json b/i18n/trk/src/vs/workbench/services/editor/common/editorService.i18n.json new file mode 100644 index 00000000000..50e968f8ee3 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/editor/common/editorService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "compareLabels": "{0} ↔ {1}" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json b/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json new file mode 100644 index 00000000000..bdf4e95d8a0 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionHost.i18n.json @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "extensionHostProcess.startupFailDebug": "Eklenti sunucusu 10 saniye iƧinde başlamadı, ilk satırda durdurulmuş olabilir ve devam etmesi iƧin bir hata ayıklayıcıya ihtiyacı olabilir.", + "extensionHostProcess.startupFail": "Eklenti sunucusu 10 saniye iƧinde başlamadı, bu bir sorun olabilir.", + "extensionHostProcess.error": "Eklenti sunucusundan hata: {0}" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json b/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json new file mode 100644 index 00000000000..17cb5965e96 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionPoints.i18n.json @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "jsonParseFail": "{0} ayrıştırılamadı: {1}.", + "fileReadFail": "{0} dosyası okunamadı: {1}.", + "jsonsParseFail": "{0} veya {1} ayrıştırılamadı: {2}.", + "missingNLSKey": "{0} anahtarı iƧin mesaj bulunamadı." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json b/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json new file mode 100644 index 00000000000..f94d7e7d32f --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/extensions/electron-browser/extensionService.i18n.json @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "devTools": "Geliştirici AraƧları", + "restart": "Eklenti Sunucusunu Yeniden Başlat", + "extensionHostProcess.crash": "Eklenti sunucusu beklenmeyen biƧimde sonlandırıldı.", + "extensionHostProcess.unresponsiveCrash": "Eklenti sunucusu yanıt vermediğinden sonlandırıldı.", + "overwritingExtension": "{0} eklentisinin üzerine {1} yazılıyor.", + "extensionUnderDevelopment": "{0} konumundaki geliştirme eklentisi yükleniyor" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/trk/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..320c074b5d2 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Dosya ikili olarak gƶrünüyor ve metin olarak aƧılamıyor" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json index d5fcdc041a1..0c8d70cb473 100644 --- a/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,11 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "GeƧersiz dosya kaynağı ({0})", - "fileIsDirectoryError": "Dosya bir dizindir ({0})", + "fileIsDirectoryError": "Dosya bir dizindir", "fileNotModifiedError": "Dosya şu tarihten beri değiştirilmemiş:", "fileTooLargeError": "Dosya, aƧmak iƧin Ƨok büyük", "fileBinaryError": "Dosya ikili olarak gƶrünüyor ve metin olarak aƧılamıyor", "fileNotFoundError": "Dosya bulunamadı ({0})", + "fileExists": "Oluşturulacak dosya zaten mevcut ({0})", "fileMoveConflict": "Taşıma/kopyalama yapılamadı. Dosya, hedefte zaten mevcut.", "unableToMoveCopyError": "Taşıma/kopyalama yapılamadı. Dosya, iƧinde bulunduğu klasƶrü değiştiriyor.", "foldersCopyError": "Klasƶrler Ƨalışma alanına kopyalanamaz. Lütfen kopyalamak iƧin dosyaları tek tek seƧin.", diff --git a/i18n/trk/src/vs/workbench/services/progress/browser/progressService2.i18n.json b/i18n/trk/src/vs/workbench/services/progress/browser/progressService2.i18n.json index 6db7d6aae51..dbcd7381ae2 100644 --- a/i18n/trk/src/vs/workbench/services/progress/browser/progressService2.i18n.json +++ b/i18n/trk/src/vs/workbench/services/progress/browser/progressService2.i18n.json @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "progress.text": "{0} - {1}", + "progress.subtitle": "{0} - {1}", "progress.title": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json b/i18n/trk/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json index f126fe535aa..cc339668775 100644 --- a/i18n/trk/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json +++ b/i18n/trk/src/vs/workbench/services/themes/common/colorThemeSchema.i18n.json @@ -4,8 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "schema.fontStyle": "Kuralın yazı tipi stili: 'italic', 'bold' ve 'underline' kombinasyonu veya bunlardan bir tanesi", - "schema.colors": "Sentaks vurgulaması renkleri", - "schema.properties.name": "Kuralın aƧıklaması", - "schema.tokenColors.path": "Bir tmTheme dosyasının yolu (geƧerli dosyaya gƶreli)" + "schema.token.settings": "BelirteƧ renkleri ve stilleri.", + "schema.token.foreground": "BelirteƧ ƶn plan rengi.", + "schema.token.background.warning": "BelirteƧ arka plan renkleri şu anda desteklenmiyor.", + "schema.token.fontStyle": "Kuralın yazı tipi stili: 'italic', 'bold' ve 'underline' kombinasyonu veya bunlardan bir tanesi", + "schema.fontStyle.error": "Yazı tipi stili; 'italic', 'bold' ve 'underline' kombinasyonu olmalıdır", + "schema.properties.name": "Kural aƧıklaması.", + "schema.properties.scope": "Bu kural karşısında eşleşecek kapsam seƧicisi.", + "schema.tokenColors.path": "Bir tmTheme dosyasının yolu (geƧerli dosyaya gƶreli).", + "schema.colors": "Sentaks vurgulaması renkleri" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json b/i18n/trk/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json index 93ef7b84d63..cbd41cd45bb 100644 --- a/i18n/trk/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json +++ b/i18n/trk/src/vs/workbench/services/themes/common/fileIconThemeSchema.i18n.json @@ -33,5 +33,6 @@ "schema.fontSize": "Yazı tipi kullanırken: Metin yazı tipi yüzdesine gƶre yazı tipi boyutu. Ayarlanmazsa, yazı tipi tanımındaki boyut kullanılır.", "schema.fontId": "Yazı tipi kullanırken: Yazı tipinin kimliği. Ayarlanmazsa, ilk yazı tipi tanımı varsayılan olarak kullanılır.", "schema.light": "AƧık renk temalarındaki dosya simgeleri iƧin isteğe bağlı ilişkilendirmeler.", - "schema.highContrast": "Yüksek karşıtlık renk temalarındaki dosya simgeleri iƧin isteğe bağlı ilişkilendirmeler." + "schema.highContrast": "Yüksek karşıtlık renk temalarındaki dosya simgeleri iƧin isteğe bağlı ilişkilendirmeler.", + "schema.hidesExplorerArrows": "Bu tema aktif olduğunda dosya gezgini ok işaretlerinin gizli olup olmayacağını yapılandırır." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json index d00686b6cdd..60d2a29126d 100644 --- a/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeData.i18n.json @@ -6,7 +6,7 @@ { "error.cannotparsejson": "JSON tema dosyasını ayrıştırma sorunları: {0}", "error.invalidformat.colors": "Renk teması dosyasını ayrıştırma sorunu: {0}. 'colors' ƶzelliği 'nesne' türünde değil.", - "error.invalidformat.tokenColors": "Renk teması dosyasını ayrıştırma sorunu: {0}. 'tokenColors' ƶzelliği ya renkleri belirten bir dizi ya da bir text mate tema dosyasının yolunu iƧermelidir", + "error.invalidformat.tokenColors": "Renk teması dosyasını ayrıştırma sorunu: {0}. 'tokenColors' ƶzelliği ya renkleri belirten bir dizi ya da bir TextMate tema dosyasının yolunu iƧermelidir", "error.plist.invalidformat": "tmTheme tema dosyasını ayrıştırma sorunları: {0}. 'settings' dizi değil", "error.cannotparse": "tmTheme tema dosyasını ayrıştırma sorunları: {0}", "error.cannotload": "{0} tmTheme tema dosyasını yükleme sorunları: {1}" diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json new file mode 100644 index 00000000000..ab403ef3493 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/colorThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.themes": "Textmate renk temalarına ekleme yapar.", + "vscode.extension.contributes.themes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", + "vscode.extension.contributes.themes.label": "Kullanıcı arayüzünde gƶrünen renk temasının etiketi.", + "vscode.extension.contributes.themes.uiTheme": "Editƶrdeki renkleri tanımlayan temel tema: 'vs' aƧık renk temasıdır, 'vs-dark' koyu renk temasıdır. 'hc-black' ise yüksek kontrast temasıdır.", + "vscode.extension.contributes.themes.path": "tmLanguage dosyasının yolu. Yol, eklenti klasƶrüne gƶrecelidir ve genellikle './themes/themeFile.tmTheme'dir.", + "reqarray": "Eklenti noktası `{0}` bir dizi olmalıdır.", + "reqpath": "`contributes.{0}.path` ƶgesinde dize bekleniyor. Sağlanan değer: {1}", + "invalid.path.1": "`contributes.{0}.path` ƶgesinin ({1}) eklentinin klasƶründe ({2}) yer alması bekleniyor. Bu, eklentiyi taşınamaz yapabilir." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json new file mode 100644 index 00000000000..c7286a77b94 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "error.cannotparseicontheme": "Dosya simgeleri dosyasını ayrıştırma sorunları: {0}" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json new file mode 100644 index 00000000000..65e81b3fdbf --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "vscode.extension.contributes.iconThemes": "Dosya simgesi temalarına ekleme yapar.", + "vscode.extension.contributes.iconThemes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", + "vscode.extension.contributes.iconThemes.label": "Kullanıcı arayüzünde gƶrünen simge temasının etiketi.", + "vscode.extension.contributes.iconThemes.path": "Simge teması tanımlama dosyasının yolu. Yol, eklenti klasƶrüne gƶrecelidir ve genellikle './icons/awesome-icon-theme.json'dur.", + "reqarray": "Eklenti noktası `{0}` bir dizi olmalıdır.", + "reqpath": "`contributes.{0}.path` ƶgesinde dize bekleniyor. Sağlanan değer: {1}", + "reqid": "`contributes.{0}.id` ƶgesinde dize bekleniyordu. Belirtilen değer: {1}", + "invalid.path.1": "`contributes.{0}.path` ƶgesinin ({1}) eklentinin klasƶründe ({2}) yer alması bekleniyor. Bu, eklentiyi taşınamaz yapabilir." +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json b/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json index e6b44a70518..6715de58332 100644 --- a/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json +++ b/i18n/trk/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.i18n.json @@ -4,30 +4,22 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "vscode.extension.contributes.themes": "Textmate renk temalarına ekleme yapar.", - "vscode.extension.contributes.themes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", - "vscode.extension.contributes.themes.label": "Kullanıcı arayüzünde gƶrünen renk temasının etiketi.", - "vscode.extension.contributes.themes.uiTheme": "Editƶrdeki renkleri tanımlayan temel tema: 'vs' aƧık renk temasıdır, 'vs-dark' koyu renk temasıdır. 'hc-black' ise yüksek kontrast temasıdır.", - "vscode.extension.contributes.themes.path": "tmLanguage dosyasının yolu. Yol, eklenti klasƶrüne gƶrecelidir ve genellikle './themes/themeFile.tmTheme'dir.", - "vscode.extension.contributes.iconThemes": "Dosya simgesi temalarına ekleme yapar.", - "vscode.extension.contributes.iconThemes.id": "Kullanıcı ayarlarında kullanılan simge teması Id'si.", - "vscode.extension.contributes.iconThemes.label": "Kullanıcı arayüzünde gƶrünen simge temasının etiketi.", - "vscode.extension.contributes.iconThemes.path": "Simge teması tanımlama dosyasının yolu. Yol, eklenti klasƶrüne gƶrecelidir ve genellikle './icons/awesome-icon-theme.json'dur.", "migration.completed": "Yeni tema ayarları kullanıcı ayarlarına eklendi. Yedek, {0} konumunda mevcuttur.", "error.cannotloadtheme": "{0} yüklenemedi: {1}", - "reqarray": "Eklenti noktası `{0}` bir dizi olmalıdır.", - "reqpath": "`contributes.{0}.path` ƶgesinde dize bekleniyor. Sağlanan değer: {1}", - "invalid.path.1": "`contributes.{0}.path` ƶgesinin ({1}) eklentinin klasƶründe ({2}) yer alması bekleniyor. Bu, eklentiyi taşınamaz yapabilir.", - "reqid": "`contributes.{0}.id` ƶgesinde dize bekleniyordu. Belirtilen değer: {1}", "error.cannotloadicontheme": "{0} yüklenemedi", - "error.cannotparseicontheme": "Dosya simgeleri dosyasını ayrıştırma sorunları: {0}", "colorTheme": "Ƈalışma ekranında kullanılan renk temasını belirtir.", "colorThemeError": "Tema bilinmiyor veya yüklenmemiş.", "iconTheme": "Ƈalışma ekranında kullanılan simge temasını veya hiƧbir dosya simgesi gƶstermemek iƧin 'null' belirtir.", "noIconThemeDesc": "Dosya simgesi yok", "iconThemeError": "Dosya simgesi teması bilinmiyor veya yüklenmemiş.", "workbenchColors": "Şu an seƧili renk temasındaki renkleri geƧersiz kılar.", - "workbenchColors.deprecated": "Ayar, artık deneysel değildir ve 'workbench.colorCustomizations' olarak yeniden adlandırılmıştır", - "workbenchColors.deprecatedDescription": "Bunun yerine 'workbench.colorCustomizations' kullanın", - "editorColors": "Şu an seƧili renk temasındaki düzenleyici renklerini ve yazı tipi stilini geƧersiz kılar." + "editorColors": "Şu an seƧili renk temasındaki düzenleyici renklerini ve yazı tipi stilini geƧersiz kılar.", + "editorColors.comments": "Yorumların rengini ve stillerini ayarlar", + "editorColors.strings": "Dizelerin rengini ve stillerini ayarlar.", + "editorColors.keywords": "Anahtar sƶzcüklerin rengini ve stillerini ayarlar.", + "editorColors.numbers": "Numaraların rengini ve stillerini ayarlar.", + "editorColors.types": "Tür bildirimi ve başvurularının rengini ve stillerini ayarlar.", + "editorColors.functions": "Fonksiyon bildirimi ve başvurularının rengini ve stillerini ayarlar.", + "editorColors.variables": "Değişken bildirimi ve başvurularının rengini ve stillerini ayarlar.", + "editorColors.textMateRules": "Textmate tema kurallarını kullanarak renkleri ve stilleri ayarlar (gelişmiş)." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json b/i18n/trk/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json new file mode 100644 index 00000000000..38e103f1ee8 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/workspace/node/workspaceEditingService.i18n.json @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "errorInvalidTaskConfiguration": "Ƈalışma alanı yapılandırma dosyasına yazılamıyor. Lütfen dosyadaki hata/uyarıları düzeltmek iƧin dosyayı aƧın ve tekrar deneyin.", + "errorWorkspaceConfigurationFileDirty": "Kaydedilmemiş değişiklikler iƧerdiği iƧin Ƨalışma alanı yapılandırma dosyasına yazılamıyor. Lütfen dosyayı kaydedin ve tekrar deneyin.", + "openWorkspaceConfigurationFile": "Ƈalışma Alanı Yapılandırma Dosyasını AƧ", + "close": "Kapat", + "enterWorkspace.close": "Kapat", + "enterWorkspace.dontShowAgain": "Tekrar Gƶsterme", + "enterWorkspace.moreInfo": "Daha Fazla Bilgi", + "enterWorkspace.prompt": "VS Code'da birden Ƨok klasƶrle Ƨalışmak hakkında daha fazla bilgi edinin." +} \ No newline at end of file diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index da67d4348ce..c7ff262ecec 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -179,9 +179,9 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-0.3.6.tgz" }, "iconv-lite": { - "version": "0.4.15", - "from": "iconv-lite@0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz" + "version": "0.4.19", + "from": "iconv-lite@0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz" }, "inherits": { "version": "2.0.1", @@ -249,14 +249,14 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" }, "jschardet": { - "version": "1.5.1", - "from": "jschardet@>=1.5.1 <2.0.0", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz" + "version": "1.6.0", + "from": "jschardet@>=1.6.0 <2.0.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.6.0.tgz" }, "keytar": { - "version": "4.0.3", + "version": "4.0.5", "from": "keytar@latest", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.0.3.tgz", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.0.5.tgz", "dependencies": { "nan": { "version": "2.5.1", @@ -301,9 +301,9 @@ "resolved": "https://registry.npmjs.org/native-watchdog/-/native-watchdog-0.3.0.tgz" }, "node-pty": { - "version": "0.7.0", - "from": "node-pty@0.7.0", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.7.0.tgz", + "version": "0.7.2", + "from": "node-pty@0.7.2", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.7.2.tgz", "dependencies": { "nan": { "version": "2.5.0", @@ -547,34 +547,51 @@ "resolved": "git://github.com/jrieken/v8-profiler.git#5e4a336693e1d5b079c7aecd286a1abcfbc10421" }, "vscode-debugprotocol": { - "version": "1.23.0", - "from": "vscode-debugprotocol@1.23.0", - "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.23.0.tgz" + "version": "1.24.0", + "from": "vscode-debugprotocol@1.24.0", + "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.24.0.tgz" }, "vscode-ripgrep": { - "version": "0.0.25", - "from": "vscode-ripgrep@0.0.25", - "resolved": "https://registry.npmjs.org/vscode-ripgrep/-/vscode-ripgrep-0.0.25.tgz" + "version": "0.6.0-patch.0", + "from": "vscode-ripgrep@0.6.0-patch.0", + "resolved": "https://registry.npmjs.org/vscode-ripgrep/-/vscode-ripgrep-0.6.0-patch.0.tgz" }, "vscode-textmate": { - "version": "3.1.5", - "from": "vscode-textmate@3.1.5", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-3.1.5.tgz" + "version": "3.2.0", + "from": "vscode-textmate@3.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-3.2.0.tgz" }, - "winreg": { - "version": "1.2.0", - "from": "winreg@1.2.0", - "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.0.tgz" + "windows-foreground-love": { + "version": "0.1.0", + "from": "windows-foreground-love@0.1.0", + "resolved": "https://registry.npmjs.org/windows-foreground-love/-/windows-foreground-love-0.1.0.tgz" + }, + "windows-mutex": { + "version": "0.2.0", + "from": "windows-mutex@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/windows-mutex/-/windows-mutex-0.2.0.tgz", + "dependencies": { + "bindings": { + "version": "1.3.0", + "from": "bindings@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz" + }, + "nan": { + "version": "2.7.0", + "from": "nan@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz" + } + } }, "windows-process-tree": { - "version": "0.1.3", - "from": "windows-process-tree@0.1.3", - "resolved": "https://registry.npmjs.org/windows-process-tree/-/windows-process-tree-0.1.3.tgz" + "version": "0.1.6", + "from": "windows-process-tree@0.1.6", + "resolved": "https://registry.npmjs.org/windows-process-tree/-/windows-process-tree-0.1.6.tgz" }, "xterm": { "version": "2.9.1", - "from": "Tyriar/xterm.js#vscode-release/1.16", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#d383d25c4e879578a2dabc3381f039b246abb34b" + "from": "Tyriar/xterm.js#vscode-release/1.19", + "resolved": "git+https://github.com/Tyriar/xterm.js.git#d242c552cb5c88125ac257ccaebed7fe336d9266" }, "yauzl": { "version": "2.8.0", @@ -582,4 +599,4 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz" } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index de428b55237..97d41337a00 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "code-oss-dev", - "version": "1.17.0", - "electronVersion": "1.7.3", - "distro": "9484fa9cab7f33e7948756e42cca0c3369331a54", + "version": "1.19.0", + "electronVersion": "1.7.9", + "distro": "6be5539c8022d6e13554fe648525c1a8bff700d9", "author": { "name": "Microsoft Corporation" }, @@ -20,7 +20,7 @@ "gulp": "gulp --max_old_space_size=4096", "7z": "7z", "update-grammars": "node build/npm/update-all-grammars.js", - "smoketest": "cd test/smoke ; mocha" + "smoketest": "cd test/smoke && mocha" }, "dependencies": { "applicationinsights": "0.17.1", @@ -31,31 +31,29 @@ "graceful-fs": "4.1.11", "http-proxy-agent": "0.2.7", "https-proxy-agent": "0.3.6", - "iconv-lite": "0.4.15", - "jschardet": "^1.5.1", - "keytar": "^4.0.3", + "iconv-lite": "0.4.19", + "jschardet": "1.6.0", + "keytar": "^4.0.5", "minimist": "1.2.0", "native-keymap": "1.2.5", "native-watchdog": "0.3.0", - "node-pty": "0.7.0", + "node-pty": "0.7.2", "nsfw": "1.0.16", "semver": "4.3.6", "v8-profiler": "jrieken/v8-profiler#vscode", - "vscode-debugprotocol": "1.23.0", - "vscode-ripgrep": "0.0.25", - "vscode-textmate": "^3.1.5", - "winreg": "1.2.0", - "xterm": "Tyriar/xterm.js#vscode-release/1.16", + "vscode-debugprotocol": "1.24.0", + "vscode-ripgrep": "0.6.0-patch.0", + "vscode-textmate": "^3.2.0", + "xterm": "Tyriar/xterm.js#vscode-release/1.19", "yauzl": "2.8.0" }, "devDependencies": { "7zip": "0.0.6", - "@types/keytar": "^4.0.0", - "@types/minimist": "^1.2.0", - "@types/mocha": "^2.2.39", - "@types/semver": "^5.3.30", - "@types/sinon": "^1.16.34", - "@types/winreg": "^1.2.30", + "@types/keytar": "4.0.1", + "@types/minimist": "1.2.0", + "@types/mocha": "2.2.39", + "@types/semver": "5.3.30", + "@types/sinon": "1.16.34", "azure-storage": "^0.3.1", "clean-css": "3.4.6", "coveralls": "^2.11.11", @@ -86,8 +84,8 @@ "gulp-replace": "^0.5.4", "gulp-shell": "^0.5.2", "gulp-sourcemaps": "^1.11.0", - "gulp-tsb": "^2.0.4", - "gulp-tslint": "^7.0.1", + "gulp-tsb": "2.0.4", + "gulp-tslint": "^8.1.2", "gulp-uglify": "^3.0.0", "gulp-util": "^3.0.6", "gulp-vinyl-zip": "^1.2.2", @@ -109,8 +107,8 @@ "rimraf": "^2.2.8", "sinon": "^1.17.2", "source-map": "^0.4.4", - "tslint": "^4.3.1", - "typescript": "2.5.2", + "tslint": "^5.8.0", + "typescript": "2.6.1", "typescript-formatter": "4.0.1", "uglify-es": "^3.0.18", "underscore": "^1.8.2", @@ -127,9 +125,9 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "optionalDependencies": { - "windows-process-tree": "0.1.3", + "windows-process-tree": "0.1.6", "windows-foreground-love": "0.1.0", "windows-mutex": "^0.2.0", "fsevents": "0.3.8" } -} \ No newline at end of file +} diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index 99a1189a0fe..af3d2967d3d 100644 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -3,25 +3,16 @@ Name=@@NAME_LONG@@ Comment=Code Editing. Redefined. GenericName=Text Editor Exec=/usr/share/@@NAME@@/@@NAME@@ --unity-launch %F -Icon=@@NAME@@ +Icon=@@ICON@@ Type=Application StartupNotify=true StartupWMClass=@@NAME_SHORT@@ Categories=Utility;TextEditor;Development;IDE; MimeType=text/plain;inode/directory; -Actions=new-window; +Actions=new-empty-window; Keywords=vscode; -[Desktop Action new-window] -Name=New Window -Name[de]=Neues Fenster -Name[es]=Nueva ventana -Name[fr]=Nouvelle fenĆŖtre -Name[it]=Nuova finestra -Name[ja]=ę–°č¦ć‚¦ć‚¤ćƒ³ćƒ‰ć‚¦ -Name[ko]=새 ģ°½ -Name[ru]=ŠŠ¾Š²Š¾Šµ окно -Name[zh_CN]=ę–°å»ŗēŖ—å£ -Name[zh_TW]=開新視窗 +[Desktop Action new-empty-window] +Name=New Empty Window Exec=/usr/share/@@NAME@@/@@NAME@@ --new-window %F Icon=@@NAME@@ diff --git a/resources/linux/debian/postinst.template b/resources/linux/debian/postinst.template index 6bb1edc7a4d..c4fbfcac16e 100755 --- a/resources/linux/debian/postinst.template +++ b/resources/linux/debian/postinst.template @@ -24,17 +24,11 @@ if [ "@@NAME@@" != "code-oss" ]; then fi # Register apt repository - get_apt_config_value() { - echo $(apt-config dump | grep "$1 " | sed -e "s/$1 \"//" -e "s/\";$//") - } + eval $(apt-config shell APT_SOURCE_PARTS Dir::Etc::sourceparts/d) + CODE_SOURCE_PART=${APT_SOURCE_PARTS}vscode.list - APT_DIR=$(get_apt_config_value Dir) - APT_ETC=$APT_DIR$(get_apt_config_value Dir::Etc) - APT_SOURCE_PARTS=$APT_ETC/$(get_apt_config_value Dir::Etc::sourceparts) - CODE_SOURCE_PART=$APT_SOURCE_PARTS/vscode.list - - APT_TRUSTED_PARTS=$APT_ETC/$(get_apt_config_value Dir::Etc::trustedparts) - CODE_TRUSTED_PART=$APT_TRUSTED_PARTS/microsoft.gpg + eval $(apt-config shell APT_TRUSTED_PARTS Dir::Etc::trustedparts/d) + CODE_TRUSTED_PART=${APT_TRUSTED_PARTS}microsoft.gpg # Sourced from https://packages.microsoft.com/keys/microsoft.asc if [ ! -f $CODE_TRUSTED_PART ]; then diff --git a/resources/linux/snap/electron-launch b/resources/linux/snap/electron-launch new file mode 100644 index 00000000000..aa403d5e072 --- /dev/null +++ b/resources/linux/snap/electron-launch @@ -0,0 +1,30 @@ +#!/bin/sh + +if test "$1" = "classic"; then + shift + case $SNAP_ARCH in + amd64) + TRIPLET="x86_64-linux-gnu" + ;; + armhf) + TRIPLET="arm-linux-gnueabihf" + ;; + arm64) + TRIPLET="aarch64-linux-gnu" + ;; + *) + TRIPLET="$(uname -p)-linux-gnu" + ;; + esac + + # TODO: Swap LD lib paths whenever processes are launched + export LD_LIBRARY_PATH_OLD=$LD_LIBRARY_PATH + export LD_LIBRARY_PATH=$SNAP/usr/lib:$SNAP/usr/lib/$TRIPLET:$LD_LIBRARY_PATH + export LD_LIBRARY_PATH=$SNAP/lib:$SNAP/lib/$TRIPLET:$LD_LIBRARY_PATH +fi + +# Correct the TMPDIR path for Chromium Framework/Electron to ensure +# libappindicator has readable resources. +export TMPDIR=$XDG_RUNTIME_DIR + +exec ${SNAP}/bin/desktop-launch $@ diff --git a/resources/linux/snap/snapcraft.yaml b/resources/linux/snap/snapcraft.yaml new file mode 100644 index 00000000000..3b5daa2a8c5 --- /dev/null +++ b/resources/linux/snap/snapcraft.yaml @@ -0,0 +1,42 @@ +name: @@NAME@@ +version: @@VERSION@@ +summary: Code editing. Redefined. +description: | + Visual Studio Code is a new choice of tool that combines the + simplicity of a code editor with what developers need for the core + edit-build-debug cycle. + +grade: stable +confinement: classic + +parts: + code: + plugin: dump + source: . + after: + - desktop-gtk2 + stage-packages: + - gconf2 + - libasound2 + - libnotify4 + - libnspr4 + - libnss3 + - libpulse0 + - libxss1 + - libxtst6 + prime: + - -usr/share/dh-python + electron-launch: + plugin: dump + source: . + organize: + electron-launch: bin/electron-launch + prime: + - -monitor.sh + - -OLD_VERSION + - -*.bz2 + +apps: + @@NAME@@: + command: bin/electron-launch classic ${SNAP}/usr/share/@@NAME@@/bin/@@NAME@@ + desktop: usr/share/applications/@@NAME@@.desktop \ No newline at end of file diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 31e14284571..0a2b92e00d7 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -12,7 +12,7 @@ set VSCODEUSERDATADIR=%TMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,5% .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out --disableExtensions --user-data-dir=%VSCODEUSERDATADIR% .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --user-data-dir=%VSCODEUSERDATADIR% .\scripts\test-int-mocha.bat -.\scripts\code.bat $ROOT\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disableExtensions --user-data-dir=%VSCODEUSERDATADIR% +.\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disableExtensions --user-data-dir=%VSCODEUSERDATADIR% rmdir /s /q %VSCODEUSERDATADIR% diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index d0154a4101d..0a9eea1b077 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -13,9 +13,9 @@ fi cd $ROOT # Integration Tests -./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out --disableExtensions --user-data-dir=$VSCODEUSERDATADIR -./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --user-data-dir=$VSCODEUSERDATADIR +./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started +./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started ./scripts/test-int-mocha.sh -./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR +./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started rm -r $VSCODEUSERDATADIR diff --git a/scripts/test.sh b/scripts/test.sh index 0812c9345fd..ce1e5e11856 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -28,6 +28,7 @@ test -d node_modules || ./scripts/npm.sh install (test -f "$CODE" && [ $INTENDED_VERSION == $INSTALLED_VERSION ]) || ./node_modules/.bin/gulp electron # Unit Tests +export ELECTRON_ENABLE_LOGGING=1 if [[ "$OSTYPE" == "darwin"* ]]; then cd $ROOT ; ulimit -n 4096 ; \ "$CODE" \ diff --git a/src/bootstrap.js b/src/bootstrap.js index dad68bf5c80..af713da7509 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -14,10 +14,11 @@ process.noAsar = true; if (!!process.send && process.env.PIPE_LOGGING === 'true') { var MAX_LENGTH = 100000; - // Prevent circular stringify - function safeStringify(args) { + // Prevent circular stringify and convert arguments to real array + function safeToArray(args) { var seen = []; var res; + var argsArray = []; // Massage some arguments with special treatment if (args.length) { @@ -40,11 +41,20 @@ if (!!process.send && process.env.PIPE_LOGGING === 'true') { args[i] = errorObj.toString(); } } + + argsArray.push(args[i]); } } + // Add the stack trace as payload if we are told so. We remove the message and the 2 top frames + // to start the stacktrace where the console message was being written + if (process.env.VSCODE_LOG_STACK === 'true') { + const stack = new Error().stack; + argsArray.push({ __$stack: stack.split('\n').slice(3).join('\n') }); + } + try { - res = JSON.stringify(args, function (key, value) { + res = JSON.stringify(argsArray, function (key, value) { // Objects get special treatment to prevent circles if (value && Object.prototype.toString.call(value) === '[object Object]') { @@ -78,16 +88,16 @@ if (!!process.send && process.env.PIPE_LOGGING === 'true') { // Pass console logging to the outside so that we have it in the main side if told so if (process.env.VERBOSE_LOGGING === 'true') { - console.log = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeStringify(arguments) }); }; - console.info = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeStringify(arguments) }); }; - console.warn = function () { safeSend({ type: '__$console', severity: 'warn', arguments: safeStringify(arguments) }); }; + console.log = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeToArray(arguments) }); }; + console.info = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeToArray(arguments) }); }; + console.warn = function () { safeSend({ type: '__$console', severity: 'warn', arguments: safeToArray(arguments) }); }; } else { console.log = function () { /* ignore */ }; console.warn = function () { /* ignore */ }; console.info = function () { /* ignore */ }; } - console.error = function () { safeSend({ type: '__$console', severity: 'error', arguments: safeStringify(arguments) }); }; + console.error = function () { safeSend({ type: '__$console', severity: 'error', arguments: safeToArray(arguments) }); }; } if (!process.env['VSCODE_ALLOW_IO']) { diff --git a/src/main.js b/src/main.js index 3c6611e36aa..7b31fc5dcab 100644 --- a/src/main.js +++ b/src/main.js @@ -12,6 +12,9 @@ if (process.argv.indexOf('--prof-startup') >= 0) { profiler.startProfiling('main', true); } +var perf = require('./vs/base/common/performance'); +perf.mark('main:started'); + // Perf measurements global.perfStartTime = Date.now(); @@ -218,6 +221,7 @@ var nodeCachedDataDir = getNodeCachedDataDir().then(function (value) { // Load our code once ready app.once('ready', function () { + perf.mark('main:appReady'); global.perfAppReady = Date.now(); var nlsConfig = getNLSConfiguration(); process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); diff --git a/src/tsconfig.json b/src/tsconfig.json index ed888ce8a0f..2d516dd2313 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -10,6 +10,8 @@ "experimentalDecorators": true, "declaration": true, "noImplicitReturns": true, + "noUnusedLocals": true, + "noImplicitThis": true, "baseUrl": ".", "typeRoots": [ "typings" diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index c4c8a73ecf3..ce604fb1bf0 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,697 +1,5874 @@ -// Type definitions for Electron v1.4.6 +// Type definitions for Electron 1.7.9 // Project: http://electron.atom.io/ -// Definitions by: jedmao , rhysd , Milan Burda , aliib -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// Definitions by: The Electron Team +// Definitions: https://github.com/electron/electron-typescript-definitions /// +type GlobalEvent = Event; + declare namespace Electron { - - interface Event { - preventDefault: Function; - sender: NodeJS.EventEmitter; + class EventEmitter { + addListener(event: string, listener: Function): this; + on(event: string, listener: Function): this; + once(event: string, listener: Function): this; + removeListener(event: string, listener: Function): this; + removeAllListeners(event?: string): this; + setMaxListeners(n: number): this; + getMaxListeners(): number; + listeners(event: string): Function[]; + emit(event: string, ...args: any[]): boolean; + listenerCount(type: string): number; + prependListener(event: string, listener: Function): this; + prependOnceListener(event: string, listener: Function): this; + eventNames(): string[]; } - type Point = { - x: number; - y: number; + class Accelerator extends String { + } - type Size = { - width: number; - height: number; + interface Event extends GlobalEvent { + preventDefault: () => void; + sender: WebContents; + returnValue: any; + ctrlKey?: boolean; + metaKey?: boolean; + shiftKey?: boolean; + altKey?: boolean; } - type Rectangle = { - x: number; - y: number; - width: number; - height: number; + interface CommonInterface { + clipboard: Clipboard; + crashReporter: CrashReporter; + nativeImage: typeof NativeImage; + screen: Screen; + shell: Shell; } - interface Destroyable { - /** - * Destroys the object. - */ - destroy(): void; - /** - * @returns Whether the object is destroyed. - */ - isDestroyed(): boolean; + interface MainInterface extends CommonInterface { + app: App; + autoUpdater: AutoUpdater; + BrowserView: typeof BrowserView; + BrowserWindow: typeof BrowserWindow; + ClientRequest: typeof ClientRequest; + contentTracing: ContentTracing; + Cookies: typeof Cookies; + Debugger: typeof Debugger; + dialog: Dialog; + DownloadItem: typeof DownloadItem; + globalShortcut: GlobalShortcut; + IncomingMessage: typeof IncomingMessage; + ipcMain: IpcMain; + Menu: typeof Menu; + MenuItem: typeof MenuItem; + net: Net; + Notification: typeof Notification; + powerMonitor: PowerMonitor; + powerSaveBlocker: PowerSaveBlocker; + protocol: Protocol; + session: typeof Session; + systemPreferences: SystemPreferences; + TouchBar: typeof TouchBar; + Tray: typeof Tray; + webContents: typeof WebContents; + WebRequest: typeof WebRequest; } - // https://github.com/electron/electron/blob/master/docs/api/app.md + interface RendererInterface extends CommonInterface { + BrowserWindowProxy: typeof BrowserWindowProxy; + desktopCapturer: DesktopCapturer; + ipcRenderer: IpcRenderer; + remote: Remote; + webFrame: WebFrame; + webviewTag: WebviewTag; + } + + interface AllElectron extends MainInterface, RendererInterface { } + + const app: App; + const autoUpdater: AutoUpdater; + const clipboard: Clipboard; + const contentTracing: ContentTracing; + const crashReporter: CrashReporter; + const desktopCapturer: DesktopCapturer; + const dialog: Dialog; + const globalShortcut: GlobalShortcut; + const ipcMain: IpcMain; + const ipcRenderer: IpcRenderer; + type nativeImage = NativeImage; + const nativeImage: typeof NativeImage; + const net: Net; + const powerMonitor: PowerMonitor; + const powerSaveBlocker: PowerSaveBlocker; + const protocol: Protocol; + const remote: Remote; + const screen: Screen; + type session = Session; + const session: typeof Session; + const shell: Shell; + const systemPreferences: SystemPreferences; + type webContents = WebContents; + const webContents: typeof WebContents; + const webFrame: WebFrame; + const webviewTag: WebviewTag; + + interface App extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/app - /** - * The app module is responsible for controlling the application's lifecycle. - */ - interface App extends NodeJS.EventEmitter { /** - * Emitted when the application has finished basic startup. - * On Windows and Linux, the will-finish-launching event - * is the same as the ready event; on macOS, this event represents - * the applicationWillFinishLaunching notification of NSApplication. - * You would usually set up listeners for the open-file and open-url events here, - * and start the crash reporter and auto updater. - * - * In most cases, you should just do everything in the ready event handler. + * Emitted when Chrome's accessibility support changes. This event fires when + * assistive technologies, such as screen readers, are enabled or disabled. See + * https://www.chromium.org/developers/design-documents/accessibility for more + * details. */ - on(event: 'will-finish-launching', listener: Function): this; + on(event: 'accessibility-support-changed', listener: (event: Event, + /** + * `true` when Chrome's accessibility support is enabled, `false` otherwise. + */ + accessibilitySupportEnabled: boolean) => void): this; + once(event: 'accessibility-support-changed', listener: (event: Event, + /** + * `true` when Chrome's accessibility support is enabled, `false` otherwise. + */ + accessibilitySupportEnabled: boolean) => void): this; + addListener(event: 'accessibility-support-changed', listener: (event: Event, + /** + * `true` when Chrome's accessibility support is enabled, `false` otherwise. + */ + accessibilitySupportEnabled: boolean) => void): this; + removeListener(event: 'accessibility-support-changed', listener: (event: Event, + /** + * `true` when Chrome's accessibility support is enabled, `false` otherwise. + */ + accessibilitySupportEnabled: boolean) => void): this; /** - * Emitted when Electron has finished initialization. + * Emitted when the application is activated. Various actions can trigger this + * event, such as launching the application for the first time, attempting to + * re-launch the application when it's already running, or clicking on the + * application's dock or taskbar icon. */ - on(event: 'ready', listener: (event: Event, launchInfo: Object) => void): this; + on(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; + once(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; + addListener(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; + removeListener(event: 'activate', listener: (event: Event, + hasVisibleWindows: boolean) => void): this; /** - * Emitted when all windows have been closed. - * - * If you do not subscribe to this event and all windows are closed, - * the default behavior is to quit the app; however, if you subscribe, - * you control whether the app quits or not. - * If the user pressed Cmd + Q, or the developer called app.quit(), - * Electron will first try to close all the windows and then emit the will-quit event, - * and in this case the window-all-closed event would not be emitted. - */ - on(event: 'window-all-closed', listener: Function): this; - /** - * Emitted before the application starts closing its windows. - * Calling event.preventDefault() will prevent the default behaviour, which is terminating the application. + * Emitted before the application starts closing its windows. Calling + * event.preventDefault() will prevent the default behaviour, which is terminating + * the application. Note: If application quit was initiated by + * autoUpdater.quitAndInstall() then before-quit is emitted after emitting close + * event on all windows and closing them. */ on(event: 'before-quit', listener: (event: Event) => void): this; - /** - * Emitted when all windows have been closed and the application will quit. - * Calling event.preventDefault() will prevent the default behaviour, which is terminating the application. - */ - on(event: 'will-quit', listener: (event: Event) => void): this; - /** - * Emitted when the application is quitting. - */ - on(event: 'quit', listener: (event: Event, exitCode: number) => void): this; - /** - * Emitted when the user wants to open a file with the application. - * The open-file event is usually emitted when the application is already open - * and the OS wants to reuse the application to open the file. - * open-file is also emitted when a file is dropped onto the dock and the application - * is not yet running. Make sure to listen for the open-file event very early - * in your application startup to handle this case (even before the ready event is emitted). - * - * You should call event.preventDefault() if you want to handle this event. - * - * Note: This is only implemented on macOS. - */ - on(event: 'open-file', listener: (event: Event, url: string) => void): this; - /** - * Emitted when the user wants to open a URL with the application. - * The URL scheme must be registered to be opened by your application. - * - * You should call event.preventDefault() if you want to handle this event. - * - * Note: This is only implemented on macOS. - */ - on(event: 'open-url', listener: (event: Event, url: string) => void): this; - /** - * Emitted when the application is activated, which usually happens when clicks on the applications’s dock icon. - * Note: This is only implemented on macOS. - */ - on(event: 'activate', listener: Function): this; - /** - * Emitted during Handoff when an activity from a different device wants to be resumed. - * You should call event.preventDefault() if you want to handle this event. - */ - on(event: 'continue-activity', listener: (event: Event, type: string, userInfo: Object) => void): this; + once(event: 'before-quit', listener: (event: Event) => void): this; + addListener(event: 'before-quit', listener: (event: Event) => void): this; + removeListener(event: 'before-quit', listener: (event: Event) => void): this; /** * Emitted when a browserWindow gets blurred. */ - on(event: 'browser-window-blur', listener: (event: Event, browserWindow: BrowserWindow) => void): this; - /** - * Emitted when a browserWindow gets focused. - */ - on(event: 'browser-window-focus', listener: (event: Event, browserWindow: BrowserWindow) => void): this; + on(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; + once(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; + addListener(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; + removeListener(event: 'browser-window-blur', listener: (event: Event, + window: BrowserWindow) => void): this; /** * Emitted when a new browserWindow is created. */ - on(event: 'browser-window-created', listener: (event: Event, browserWindow: BrowserWindow) => void): this; + on(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; + once(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; + addListener(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; + removeListener(event: 'browser-window-created', listener: (event: Event, + window: BrowserWindow) => void): this; /** - * Emitted when a new webContents is created. + * Emitted when a browserWindow gets focused. */ - on(event: 'web-contents-created', listener: (event: Event, webContents: WebContents) => void): this; + on(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; + once(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; + addListener(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; + removeListener(event: 'browser-window-focus', listener: (event: Event, + window: BrowserWindow) => void): this; /** * Emitted when failed to verify the certificate for url, to trust the certificate - * you should prevent the default behavior with event.preventDefault() and call callback(true). + * you should prevent the default behavior with event.preventDefault() and call + * callback(true). */ on(event: 'certificate-error', listener: (event: Event, webContents: WebContents, url: string, + /** + * The error code + */ error: string, certificate: Certificate, - callback: (trust: boolean) => void - ) => void): this; + callback: (isTrusted: boolean) => void) => void): this; + once(event: 'certificate-error', listener: (event: Event, + webContents: WebContents, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void) => void): this; + addListener(event: 'certificate-error', listener: (event: Event, + webContents: WebContents, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void) => void): this; + removeListener(event: 'certificate-error', listener: (event: Event, + webContents: WebContents, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void) => void): this; /** - * Emitted when a client certificate is requested. - * - * The url corresponds to the navigation entry requesting the client certificate - * and callback needs to be called with an entry filtered from the list. - * Using event.preventDefault() prevents the application from using the first certificate from the store. + * Emitted during Handoff when an activity from a different device wants to be + * resumed. You should call event.preventDefault() if you want to handle this + * event. A user activity can be continued only in an app that has the same + * developer Team ID as the activity's source app and that supports the activity's + * type. Supported activity types are specified in the app's Info.plist under the + * NSUserActivityTypes key. + */ + on(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to . + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: any) => void): this; + once(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to . + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: any) => void): this; + addListener(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to . + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: any) => void): this; + removeListener(event: 'continue-activity', listener: (event: Event, + /** + * A string identifying the activity. Maps to . + */ + type: string, + /** + * Contains app-specific state stored by the activity on another device. + */ + userInfo: any) => void): this; + /** + * Emitted when the gpu process crashes or is killed. + */ + on(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + once(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + addListener(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + removeListener(event: 'gpu-process-crashed', listener: (event: Event, + killed: boolean) => void): this; + /** + * Emitted when webContents wants to do basic auth. The default behavior is to + * cancel all authentications, to override this you should prevent the default + * behavior with event.preventDefault() and call callback(username, password) with + * the credentials. + */ + on(event: 'login', listener: (event: Event, + webContents: WebContents, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + once(event: 'login', listener: (event: Event, + webContents: WebContents, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + addListener(event: 'login', listener: (event: Event, + webContents: WebContents, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + removeListener(event: 'login', listener: (event: Event, + webContents: WebContents, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + /** + * Emitted when the user clicks the native macOS new tab button. The new tab button + * is only visible if the current BrowserWindow has a tabbingIdentifier + */ + on(event: 'new-window-for-tab', listener: (event: Event) => void): this; + once(event: 'new-window-for-tab', listener: (event: Event) => void): this; + addListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; + removeListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; + /** + * Emitted when the user wants to open a file with the application. The open-file + * event is usually emitted when the application is already open and the OS wants + * to reuse the application to open the file. open-file is also emitted when a file + * is dropped onto the dock and the application is not yet running. Make sure to + * listen for the open-file event very early in your application startup to handle + * this case (even before the ready event is emitted). You should call + * event.preventDefault() if you want to handle this event. On Windows, you have to + * parse process.argv (in the main process) to get the filepath. + */ + on(event: 'open-file', listener: (event: Event, + path: string) => void): this; + once(event: 'open-file', listener: (event: Event, + path: string) => void): this; + addListener(event: 'open-file', listener: (event: Event, + path: string) => void): this; + removeListener(event: 'open-file', listener: (event: Event, + path: string) => void): this; + /** + * Emitted when the user wants to open a URL with the application. Your + * application's Info.plist file must define the url scheme within the + * CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication. You should + * call event.preventDefault() if you want to handle this event. + */ + on(event: 'open-url', listener: (event: Event, + url: string) => void): this; + once(event: 'open-url', listener: (event: Event, + url: string) => void): this; + addListener(event: 'open-url', listener: (event: Event, + url: string) => void): this; + removeListener(event: 'open-url', listener: (event: Event, + url: string) => void): this; + /** + * Emitted when the application is quitting. + */ + on(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + once(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + addListener(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + removeListener(event: 'quit', listener: (event: Event, + exitCode: number) => void): this; + /** + * Emitted when Electron has finished initializing. On macOS, launchInfo holds the + * userInfo of the NSUserNotification that was used to open the application, if it + * was launched from Notification Center. You can call app.isReady() to check if + * this event has already fired. + */ + on(event: 'ready', listener: (launchInfo: any) => void): this; + once(event: 'ready', listener: (launchInfo: any) => void): this; + addListener(event: 'ready', listener: (launchInfo: any) => void): this; + removeListener(event: 'ready', listener: (launchInfo: any) => void): this; + /** + * Emitted when a client certificate is requested. The url corresponds to the + * navigation entry requesting the client certificate and callback can be called + * with an entry filtered from the list. Using event.preventDefault() prevents the + * application from using the first certificate from the store. */ on(event: 'select-client-certificate', listener: (event: Event, webContents: WebContents, url: string, certificateList: Certificate[], - callback: (certificate: Certificate) => void - ) => void): this; - /** - * Emitted when webContents wants to do basic auth. - * - * The default behavior is to cancel all authentications, to override this - * you should prevent the default behavior with event.preventDefault() - * and call callback(username, password) with the credentials. - */ - on(event: 'login', listener: (event: Event, + callback: (certificate?: Certificate) => void) => void): this; + once(event: 'select-client-certificate', listener: (event: Event, webContents: WebContents, - request: LoginRequest, - authInfo: LoginAuthInfo, - callback: (username: string, password: string) => void - ) => void): this; + url: string, + certificateList: Certificate[], + callback: (certificate?: Certificate) => void) => void): this; + addListener(event: 'select-client-certificate', listener: (event: Event, + webContents: WebContents, + url: string, + certificateList: Certificate[], + callback: (certificate?: Certificate) => void) => void): this; + removeListener(event: 'select-client-certificate', listener: (event: Event, + webContents: WebContents, + url: string, + certificateList: Certificate[], + callback: (certificate?: Certificate) => void) => void): this; /** - * Emitted when the gpu process crashes. + * Emitted when a new webContents is created. */ - on(event: 'gpu-process-crashed', listener: (event: Event, killed: boolean) => void): this; + on(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; + once(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; + addListener(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; + removeListener(event: 'web-contents-created', listener: (event: Event, + webContents: WebContents) => void): this; /** - * Emitted when Chrome's accessibility support changes. - * - * Note: This API is only available on macOS and Windows. + * Emitted when the application has finished basic startup. On Windows and Linux, + * the will-finish-launching event is the same as the ready event; on macOS, this + * event represents the applicationWillFinishLaunching notification of + * NSApplication. You would usually set up listeners for the open-file and open-url + * events here, and start the crash reporter and auto updater. In most cases, you + * should just do everything in the ready event handler. */ - on(event: 'accessibility-support-changed', listener: (event: Event, accessibilitySupportEnabled: boolean) => void): this; - on(event: string, listener: Function): this; + on(event: 'will-finish-launching', listener: Function): this; + once(event: 'will-finish-launching', listener: Function): this; + addListener(event: 'will-finish-launching', listener: Function): this; + removeListener(event: 'will-finish-launching', listener: Function): this; /** - * Try to close all windows. The before-quit event will first be emitted. - * If all windows are successfully closed, the will-quit event will be emitted - * and by default the application would be terminated. - * - * This method guarantees all beforeunload and unload handlers are correctly - * executed. It is possible that a window cancels the quitting by returning - * false in beforeunload handler. + * Emitted when all windows have been closed and the application will quit. Calling + * event.preventDefault() will prevent the default behaviour, which is terminating + * the application. See the description of the window-all-closed event for the + * differences between the will-quit and window-all-closed events. */ - quit(): void; + on(event: 'will-quit', listener: (event: Event) => void): this; + once(event: 'will-quit', listener: (event: Event) => void): this; + addListener(event: 'will-quit', listener: (event: Event) => void): this; + removeListener(event: 'will-quit', listener: (event: Event) => void): this; /** - * Exits immediately with exitCode. - * All windows will be closed immediately without asking user - * and the before-quit and will-quit events will not be emitted. + * Emitted when all windows have been closed. If you do not subscribe to this event + * and all windows are closed, the default behavior is to quit the app; however, if + * you subscribe, you control whether the app quits or not. If the user pressed Cmd + * + Q, or the developer called app.quit(), Electron will first try to close all + * the windows and then emit the will-quit event, and in this case the + * window-all-closed event would not be emitted. */ - exit(exitCode?: number): void; + on(event: 'window-all-closed', listener: Function): this; + once(event: 'window-all-closed', listener: Function): this; + addListener(event: 'window-all-closed', listener: Function): this; + removeListener(event: 'window-all-closed', listener: Function): this; /** - * Relaunches the app when current instance exits. - * - * By default the new instance will use the same working directory - * and command line arguments with current instance. - * When args is specified, the args will be passed as command line arguments instead. - * When execPath is specified, the execPath will be executed for relaunch instead of current app. - * - * Note that this method does not quit the app when executed, you have to call app.quit - * or app.exit after calling app.relaunch to make the app restart. - * - * When app.relaunch is called for multiple times, multiple instances - * will be started after current instance exited. - */ - relaunch(options?: { - args?: string[], - execPath?: string - }): void; - /** - * @returns Whether Electron has finished initializing. - */ - isReady(): boolean; - /** - * On Linux, focuses on the first visible window. - * On macOS, makes the application the active app. - * On Windows, focuses on the application’s first window. - */ - focus(): void; - /** - * Hides all application windows without minimizing them. - * Note: This is only implemented on macOS. - */ - hide(): void; - /** - * Shows application windows after they were hidden. Does not automatically focus them. - * Note: This is only implemented on macOS. - */ - show(): void; - /** - * Returns the current application directory. - */ - getAppPath(): string; - /** - * @returns The path to a special directory or file associated with name. - * On failure an Error would throw. - */ - getPath(name: AppPathName): string; - /** - * Overrides the path to a special directory or file associated with name. - * If the path specifies a directory that does not exist, the directory will - * be created by this method. On failure an Error would throw. - * - * You can only override paths of names defined in app.getPath. - * - * By default web pages' cookies and caches will be stored under userData - * directory, if you want to change this location, you have to override the - * userData path before the ready event of app module gets emitted. - */ - setPath(name: AppPathName, path: string): void; - /** - * @returns The version of loaded application, if no version is found in - * application's package.json, the version of current bundle or executable. - */ - getVersion(): string; - /** - * @returns The current application's name, the name in package.json would be used. - * Usually the name field of package.json is a short lowercased name, according to - * the spec of npm modules. So usually you should also specify a productName field, - * which is your application's full capitalized name, and it will be preferred over - * name by Electron. - */ - getName(): string; - /** - * Overrides the current application's name. - */ - setName(name: string): void; - /** - * @returns The current application locale. - */ - getLocale(): string; - /** - * Adds path to recent documents list. - * - * This list is managed by the system, on Windows you can visit the list from - * task bar, and on macOS you can visit it from dock menu. - * - * Note: This is only implemented on macOS and Windows. + * Adds path to the recent documents list. This list is managed by the OS. On + * Windows you can visit the list from the task bar, and on macOS you can visit it + * from dock menu. */ addRecentDocument(path: string): void; /** * Clears the recent documents list. - * - * Note: This is only implemented on macOS and Windows. */ clearRecentDocuments(): void; /** - * Sets the current executable as the default handler for a protocol (aka URI scheme). - * Once registered, all links with your-protocol:// will be opened with the current executable. - * The whole link, including protocol, will be passed to your application as a parameter. - * - * On Windows you can provide optional parameters path, the path to your executable, - * and args, an array of arguments to be passed to your executable when it launches. - * - * @param protocol The name of your protocol, without ://. - * @param path Defaults to process.execPath. - * @param args Defaults to an empty array. - * - * Note: This is only implemented on macOS and Windows. - * On macOS, you can only register protocols that have been added to your app's info.plist. + * By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per domain + * basis if the GPU processes crashes too frequently. This function disables that + * behaviour. This method can only be called before app is ready. */ - setAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; + disableDomainBlockingFor3DAPIs(): void; /** - * Removes the current executable as the default handler for a protocol (aka URI scheme). - * - * @param protocol The name of your protocol, without ://. - * @param path Defaults to process.execPath. - * @param args Defaults to an empty array. - * - * Note: This is only implemented on macOS and Windows. + * Disables hardware acceleration for current app. This method can only be called + * before app is ready. */ - removeAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; + disableHardwareAcceleration(): void; /** - * @param protocol The name of your protocol, without ://. - * @param path Defaults to process.execPath. - * @param args Defaults to an empty array. - * - * @returns Whether the current executable is the default handler for a protocol (aka URI scheme). - * - * Note: This is only implemented on macOS and Windows. + * Enables mixed sandbox mode on the app. This method can only be called before app + * is ready. */ - isDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; + enableMixedSandbox(): void; /** - * Adds tasks to the Tasks category of JumpList on Windows. - * - * Note: This API is only available on Windows. + * Exits immediately with exitCode. exitCode defaults to 0. All windows will be + * closed immediately without asking user and the before-quit and will-quit events + * will not be emitted. */ - setUserTasks(tasks: Task[]): boolean; + exit(exitCode?: number): void; /** - * Note: This API is only available on Windows. + * On Linux, focuses on the first visible window. On macOS, makes the application + * the active app. On Windows, focuses on the application's first window. */ + focus(): void; + getAppMemoryInfo(): ProcessMetric[]; + getAppMetrics(): ProcessMetric[]; + getAppPath(): string; + getBadgeCount(): number; + getCurrentActivityType(): string; + /** + * Fetches a path's associated icon. On Windows, there a 2 kinds of icons: On Linux + * and macOS, icons depend on the application associated with file mime type. + */ + getFileIcon(path: string, options: FileIconOptions, callback: (error: Error, icon: NativeImage) => void): void; + /** + * Fetches a path's associated icon. On Windows, there a 2 kinds of icons: On Linux + * and macOS, icons depend on the application associated with file mime type. + */ + getFileIcon(path: string, callback: (error: Error, icon: NativeImage) => void): void; + getGpuFeatureStatus(): GPUFeatureStatus; getJumpListSettings(): JumpListSettings; /** - * Sets or removes a custom Jump List for the application. - * - * If categories is null the previously set custom Jump List (if any) will be replaced - * by the standard Jump List for the app (managed by Windows). - * - * Note: This API is only available on Windows. + * Note: When distributing your packaged app, you have to also ship the locales + * folder. Note: On Windows you have to call it after the ready events gets + * emitted. */ - setJumpList(categories: JumpListCategory[]): SetJumpListResult; + getLocale(): string; /** - * This method makes your application a Single Instance Application instead of allowing - * multiple instances of your app to run, this will ensure that only a single instance - * of your app is running, and other instances signal this instance and exit. + * If you provided path and args options to app.setLoginItemSettings then you need + * to pass the same arguments here for openAtLogin to be set correctly. Note: This + * API has no effect on MAS builds. */ - makeSingleInstance(callback: (args: string[], workingDirectory: string) => void): boolean; + getLoginItemSettings(options?: LoginItemSettingsOptions): LoginItemSettings; + /** + * Usually the name field of package.json is a short lowercased name, according to + * the npm modules spec. You should usually also specify a productName field, which + * is your application's full capitalized name, and which will be preferred over + * name by Electron. + */ + getName(): string; + /** + * You can request the following paths by the name: + */ + getPath(name: string): string; + getVersion(): string; + /** + * Hides all application windows without minimizing them. + */ + hide(): void; + /** + * Imports the certificate in pkcs12 format into the platform certificate store. + * callback is called with the result of import operation, a value of 0 indicates + * success while any other value indicates failure according to chromium + * net_error_list. + */ + importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; + isAccessibilitySupportEnabled(): boolean; + /** + * This method checks if the current executable is the default handler for a + * protocol (aka URI scheme). If so, it will return true. Otherwise, it will return + * false. Note: On macOS, you can use this method to check if the app has been + * registered as the default protocol handler for a protocol. You can also verify + * this by checking ~/Library/Preferences/com.apple.LaunchServices.plist on the + * macOS machine. Please refer to Apple's documentation for details. The API uses + * the Windows Registry and LSCopyDefaultHandlerForURLScheme internally. + */ + isDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; + isReady(): boolean; + isUnityRunning(): boolean; + /** + * This method makes your application a Single Instance Application - instead of + * allowing multiple instances of your app to run, this will ensure that only a + * single instance of your app is running, and other instances signal this instance + * and exit. callback will be called by the first instance with callback(argv, + * workingDirectory) when a second instance has been executed. argv is an Array of + * the second instance's command line arguments, and workingDirectory is its + * current working directory. Usually applications respond to this by making their + * primary window focused and non-minimized. The callback is guaranteed to be + * executed after the ready event of app gets emitted. This method returns false if + * your process is the primary instance of the application and your app should + * continue loading. And returns true if your process has sent its parameters to + * another instance, and you should immediately quit. On macOS the system enforces + * single instance automatically when users try to open a second instance of your + * app in Finder, and the open-file and open-url events will be emitted for that. + * However when users start your app in command line the system's single instance + * mechanism will be bypassed and you have to use this method to ensure single + * instance. An example of activating the window of primary instance when a second + * instance starts: + */ + makeSingleInstance(callback: (argv: string[], workingDirectory: string) => void): boolean; + /** + * Try to close all windows. The before-quit event will be emitted first. If all + * windows are successfully closed, the will-quit event will be emitted and by + * default the application will terminate. This method guarantees that all + * beforeunload and unload event handlers are correctly executed. It is possible + * that a window cancels the quitting by returning false in the beforeunload event + * handler. + */ + quit(): void; + /** + * Relaunches the app when current instance exits. By default the new instance will + * use the same working directory and command line arguments with current instance. + * When args is specified, the args will be passed as command line arguments + * instead. When execPath is specified, the execPath will be executed for relaunch + * instead of current app. Note that this method does not quit the app when + * executed, you have to call app.quit or app.exit after calling app.relaunch to + * make the app restart. When app.relaunch is called for multiple times, multiple + * instances will be started after current instance exited. An example of + * restarting current instance immediately and adding a new command line argument + * to the new instance: + */ + relaunch(options?: RelaunchOptions): void; /** * Releases all locks that were created by makeSingleInstance. This will allow * multiple instances of the application to once again run side by side. */ releaseSingleInstance(): void; /** - * Creates an NSUserActivity and sets it as the current activity. - * The activity is eligible for Handoff to another device afterward. - * - * @param type Uniquely identifies the activity. Maps to NSUserActivity.activityType. - * @param userInfo App-specific state to store for use by another device. - * @param webpageURL The webpage to load in a browser if no suitable app is - * installed on the resuming device. The scheme must be http or https. - * - * Note: This API is only available on macOS. + * This method checks if the current executable as the default handler for a + * protocol (aka URI scheme). If so, it will remove the app as the default handler. */ - setUserActivity(type: string, userInfo: Object, webpageURL?: string): void; + removeAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; /** - * @returns The type of the currently running activity. - * - * Note: This API is only available on macOS. + * Set the about panel options. This will override the values defined in the app's + * .plist file. See the Apple docs for more details. */ - getCurrentActivityType(): string; + setAboutPanelOptions(options: AboutPanelOptionsOptions): void; /** * Changes the Application User Model ID to id. - * - * Note: This is only implemented on Windows. */ setAppUserModelId(id: string): void; /** - * Imports the certificate in pkcs12 format into the platform certificate store. - * @param callback Called with the result of import operation, a value of 0 indicates success - * while any other value indicates failure according to chromium net_error_list. - * - * Note: This API is only available on Linux. + * This method sets the current executable as the default handler for a protocol + * (aka URI scheme). It allows you to integrate your app deeper into the operating + * system. Once registered, all links with your-protocol:// will be opened with the + * current executable. The whole link, including protocol, will be passed to your + * application as a parameter. On Windows you can provide optional parameters path, + * the path to your executable, and args, an array of arguments to be passed to + * your executable when it launches. Note: On macOS, you can only register + * protocols that have been added to your app's info.plist, which can not be + * modified at runtime. You can however change the file with a simple text editor + * or script during build time. Please refer to Apple's documentation for details. + * The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme + * internally. */ - importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; + setAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; /** - * Disables hardware acceleration for current app. - * This method can only be called before app is ready. - */ - disableHardwareAcceleration(): void; - /** - * @returns whether current desktop environment is Unity launcher. (Linux) - * - * Note: This API is only available on Linux. - */ - isUnityRunning(): boolean; - /** - * Returns a Boolean, true if Chrome's accessibility support is enabled, false otherwise. - * This API will return true if the use of assistive technologies, such as screen readers, - * has been detected. - * See https://www.chromium.org/developers/design-documents/accessibility for more details. - * - * Note: This API is only available on macOS and Windows. - */ - isAccessibilitySupportEnabled(): boolean; - /** - * @returns an Object with the login item settings of the app. - * - * Note: This API is only available on macOS and Windows. - */ - getLoginItemSettings(): LoginItemSettings; - /** - * Set the app's login item settings. - * - * Note: This API is only available on macOS and Windows. - */ - setLoginItemSettings(settings: LoginItemSettings): void; - /** - * Set the about panel options. This will override the values defined in the app's .plist file. - * See the Apple docs for more details. - * - * Note: This API is only available on macOS. - */ - setAboutPanelOptions(options: AboutPanelOptions): void; - commandLine: CommandLine; - /** - * Note: This API is only available on macOS. - */ - dock: Dock; - } - - type AppPathName = 'home' | 'appData' | 'userData' | 'temp' | 'exe' | 'module' | 'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos' | 'pepperFlashSystemPlugin'; - - interface ImportCertificateOptions { - /** - * Path for the pkcs12 file. - */ - certificate: string; - /** - * Passphrase for the certificate. - */ - password: string; - } - - interface CommandLine { - /** - * Append a switch [with optional value] to Chromium's command line. - * - * Note: This will not affect process.argv, and is mainly used by developers - * to control some low-level Chromium behaviors. - */ - appendSwitch(_switch: string, value?: string): void; - /** - * Append an argument to Chromium's command line. The argument will quoted properly. - * - * Note: This will not affect process.argv. - */ - appendArgument(value: string): void; - } - - interface Dock { - /** - * When critical is passed, the dock icon will bounce until either the - * application becomes active or the request is canceled. - * - * When informational is passed, the dock icon will bounce for one second. - * However, the request remains active until either the application becomes - * active or the request is canceled. - * - * @param type The default is informational. - * @returns An ID representing the request. - */ - bounce(type?: 'critical' | 'informational'): number; - /** - * Cancel the bounce of id. - * - * Note: This API is only available on macOS. - */ - cancelBounce(id: number): void; - /** - * Bounces the Downloads stack if the filePath is inside the Downloads folder. - * - * Note: This API is only available on macOS. - */ - downloadFinished(filePath: string): void; - /** - * Sets the string to be displayed in the dock’s badging area. - * - * Note: This API is only available on macOS. - */ - setBadge(text: string): void; - /** - * Returns the badge string of the dock. - * - * Note: This API is only available on macOS. - */ - getBadge(): string; - /** - * Sets the counter badge for current app. Setting the count to 0 will hide the badge. - * - * @returns True when the call succeeded, otherwise returns false. - * - * Note: This API is only available on macOS and Linux. + * Sets the counter badge for current app. Setting the count to 0 will hide the + * badge. On macOS it shows on the dock icon. On Linux it only works for Unity + * launcher, Note: Unity launcher requires the existence of a .desktop file to + * work, for more information please read Desktop Environment Integration. */ setBadgeCount(count: number): boolean; /** - * @returns The current value displayed in the counter badge. - * - * Note: This API is only available on macOS and Linux. + * Sets or removes a custom Jump List for the application, and returns one of the + * following strings: If categories is null the previously set custom Jump List (if + * any) will be replaced by the standard Jump List for the app (managed by + * Windows). Note: If a JumpListCategory object has neither the type nor the name + * property set then its type is assumed to be tasks. If the name property is set + * but the type property is omitted then the type is assumed to be custom. Note: + * Users can remove items from custom categories, and Windows will not allow a + * removed item to be added back into a custom category until after the next + * successful call to app.setJumpList(categories). Any attempt to re-add a removed + * item to a custom category earlier than that will result in the entire custom + * category being omitted from the Jump List. The list of removed items can be + * obtained using app.getJumpListSettings(). Here's a very simple example of + * creating a custom Jump List: */ - getBadgeCount(): number; + setJumpList(categories: JumpListCategory[]): void; /** - * Hides the dock icon. - * - * Note: This API is only available on macOS. + * Set the app's login item settings. To work with Electron's autoUpdater on + * Windows, which uses Squirrel, you'll want to set the launch path to Update.exe, + * and pass arguments that specify your application name. For example: Note: This + * API has no effect on MAS builds. + */ + setLoginItemSettings(settings: Settings): void; + /** + * Overrides the current application's name. + */ + setName(name: string): void; + /** + * Overrides the path to a special directory or file associated with name. If the + * path specifies a directory that does not exist, the directory will be created by + * this method. On failure an Error is thrown. You can only override paths of a + * name defined in app.getPath. By default, web pages' cookies and caches will be + * stored under the userData directory. If you want to change this location, you + * have to override the userData path before the ready event of the app module is + * emitted. + */ + setPath(name: string, path: string): void; + /** + * Creates an NSUserActivity and sets it as the current activity. The activity is + * eligible for Handoff to another device afterward. + */ + setUserActivity(type: string, userInfo: any, webpageURL?: string): void; + /** + * Adds tasks to the Tasks category of the JumpList on Windows. tasks is an array + * of Task objects. Note: If you'd like to customize the Jump List even more use + * app.setJumpList(categories) instead. + */ + setUserTasks(tasks: Task[]): boolean; + /** + * Shows application windows after they were hidden. Does not automatically focus + * them. + */ + show(): void; + commandLine: CommandLine; + dock: Dock; + } + + interface AutoUpdater extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/auto-updater + + /** + * Emitted when checking if an update has started. + */ + on(event: 'checking-for-update', listener: Function): this; + once(event: 'checking-for-update', listener: Function): this; + addListener(event: 'checking-for-update', listener: Function): this; + removeListener(event: 'checking-for-update', listener: Function): this; + /** + * Emitted when there is an error while updating. + */ + on(event: 'error', listener: (error: Error) => void): this; + once(event: 'error', listener: (error: Error) => void): this; + addListener(event: 'error', listener: (error: Error) => void): this; + removeListener(event: 'error', listener: (error: Error) => void): this; + /** + * Emitted when there is an available update. The update is downloaded + * automatically. + */ + on(event: 'update-available', listener: Function): this; + once(event: 'update-available', listener: Function): this; + addListener(event: 'update-available', listener: Function): this; + removeListener(event: 'update-available', listener: Function): this; + /** + * Emitted when an update has been downloaded. On Windows only releaseName is + * available. + */ + on(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + once(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + addListener(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + removeListener(event: 'update-downloaded', listener: (event: Event, + releaseNotes: string, + releaseName: string, + releaseDate: Date, + updateURL: string) => void): this; + /** + * Emitted when there is no available update. + */ + on(event: 'update-not-available', listener: Function): this; + once(event: 'update-not-available', listener: Function): this; + addListener(event: 'update-not-available', listener: Function): this; + removeListener(event: 'update-not-available', listener: Function): this; + /** + * Asks the server whether there is an update. You must call setFeedURL before + * using this API. + */ + checkForUpdates(): void; + getFeedURL(): string; + /** + * Restarts the app and installs the update after it has been downloaded. It should + * only be called after update-downloaded has been emitted. Note: + * autoUpdater.quitAndInstall() will close all application windows first and only + * emit before-quit event on app after that. This is different from the normal quit + * event sequence. + */ + quitAndInstall(): void; + /** + * Sets the url and initialize the auto updater. + */ + setFeedURL(url: string, requestHeaders?: any): void; + } + + interface BluetoothDevice { + + // Docs: http://electron.atom.io/docs/api/structures/bluetooth-device + + deviceId: string; + deviceName: string; + } + + class BrowserView extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/browser-view + + constructor(options?: BrowserViewConstructorOptions); + static fromId(id: number): BrowserView; + setAutoResize(options: AutoResizeOptions): void; + setBackgroundColor(color: string): void; + /** + * Resizes and moves the view to the supplied bounds relative to the window. + */ + setBounds(bounds: Rectangle): void; + id: number; + webContents: WebContents; + } + + class BrowserWindow extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/browser-window + + /** + * Emitted when an App Command is invoked. These are typically related to keyboard + * media keys or browser commands, as well as the "Back" button built into some + * mice on Windows. Commands are lowercased, underscores are replaced with hyphens, + * and the APPCOMMAND_ prefix is stripped off. e.g. APPCOMMAND_BROWSER_BACKWARD is + * emitted as browser-backward. + */ + on(event: 'app-command', listener: (event: Event, + command: string) => void): this; + once(event: 'app-command', listener: (event: Event, + command: string) => void): this; + addListener(event: 'app-command', listener: (event: Event, + command: string) => void): this; + removeListener(event: 'app-command', listener: (event: Event, + command: string) => void): this; + /** + * Emitted when the window loses focus. + */ + on(event: 'blur', listener: Function): this; + once(event: 'blur', listener: Function): this; + addListener(event: 'blur', listener: Function): this; + removeListener(event: 'blur', listener: Function): this; + /** + * Emitted when the window is going to be closed. It's emitted before the + * beforeunload and unload event of the DOM. Calling event.preventDefault() will + * cancel the close. Usually you would want to use the beforeunload handler to + * decide whether the window should be closed, which will also be called when the + * window is reloaded. In Electron, returning any value other than undefined would + * cancel the close. For example: + */ + on(event: 'close', listener: (event: Event) => void): this; + once(event: 'close', listener: (event: Event) => void): this; + addListener(event: 'close', listener: (event: Event) => void): this; + removeListener(event: 'close', listener: (event: Event) => void): this; + /** + * Emitted when the window is closed. After you have received this event you should + * remove the reference to the window and avoid using it any more. + */ + on(event: 'closed', listener: Function): this; + once(event: 'closed', listener: Function): this; + addListener(event: 'closed', listener: Function): this; + removeListener(event: 'closed', listener: Function): this; + /** + * Emitted when the window enters a full-screen state. + */ + on(event: 'enter-full-screen', listener: Function): this; + once(event: 'enter-full-screen', listener: Function): this; + addListener(event: 'enter-full-screen', listener: Function): this; + removeListener(event: 'enter-full-screen', listener: Function): this; + /** + * Emitted when the window enters a full-screen state triggered by HTML API. + */ + on(event: 'enter-html-full-screen', listener: Function): this; + once(event: 'enter-html-full-screen', listener: Function): this; + addListener(event: 'enter-html-full-screen', listener: Function): this; + removeListener(event: 'enter-html-full-screen', listener: Function): this; + /** + * Emitted when the window gains focus. + */ + on(event: 'focus', listener: Function): this; + once(event: 'focus', listener: Function): this; + addListener(event: 'focus', listener: Function): this; + removeListener(event: 'focus', listener: Function): this; + /** + * Emitted when the window is hidden. + */ + on(event: 'hide', listener: Function): this; + once(event: 'hide', listener: Function): this; + addListener(event: 'hide', listener: Function): this; + removeListener(event: 'hide', listener: Function): this; + /** + * Emitted when the window leaves a full-screen state. + */ + on(event: 'leave-full-screen', listener: Function): this; + once(event: 'leave-full-screen', listener: Function): this; + addListener(event: 'leave-full-screen', listener: Function): this; + removeListener(event: 'leave-full-screen', listener: Function): this; + /** + * Emitted when the window leaves a full-screen state triggered by HTML API. + */ + on(event: 'leave-html-full-screen', listener: Function): this; + once(event: 'leave-html-full-screen', listener: Function): this; + addListener(event: 'leave-html-full-screen', listener: Function): this; + removeListener(event: 'leave-html-full-screen', listener: Function): this; + /** + * Emitted when window is maximized. + */ + on(event: 'maximize', listener: Function): this; + once(event: 'maximize', listener: Function): this; + addListener(event: 'maximize', listener: Function): this; + removeListener(event: 'maximize', listener: Function): this; + /** + * Emitted when the window is minimized. + */ + on(event: 'minimize', listener: Function): this; + once(event: 'minimize', listener: Function): this; + addListener(event: 'minimize', listener: Function): this; + removeListener(event: 'minimize', listener: Function): this; + /** + * Emitted when the window is being moved to a new position. Note: On macOS this + * event is just an alias of moved. + */ + on(event: 'move', listener: Function): this; + once(event: 'move', listener: Function): this; + addListener(event: 'move', listener: Function): this; + removeListener(event: 'move', listener: Function): this; + /** + * Emitted once when the window is moved to a new position. + */ + on(event: 'moved', listener: Function): this; + once(event: 'moved', listener: Function): this; + addListener(event: 'moved', listener: Function): this; + removeListener(event: 'moved', listener: Function): this; + /** + * Emitted when the native new tab button is clicked. + */ + on(event: 'new-window-for-tab', listener: Function): this; + once(event: 'new-window-for-tab', listener: Function): this; + addListener(event: 'new-window-for-tab', listener: Function): this; + removeListener(event: 'new-window-for-tab', listener: Function): this; + /** + * Emitted when the document changed its title, calling event.preventDefault() will + * prevent the native window's title from changing. + */ + on(event: 'page-title-updated', listener: (event: Event, + title: string) => void): this; + once(event: 'page-title-updated', listener: (event: Event, + title: string) => void): this; + addListener(event: 'page-title-updated', listener: (event: Event, + title: string) => void): this; + removeListener(event: 'page-title-updated', listener: (event: Event, + title: string) => void): this; + /** + * Emitted when the web page has been rendered (while not being shown) and window + * can be displayed without a visual flash. + */ + on(event: 'ready-to-show', listener: Function): this; + once(event: 'ready-to-show', listener: Function): this; + addListener(event: 'ready-to-show', listener: Function): this; + removeListener(event: 'ready-to-show', listener: Function): this; + /** + * Emitted when the window is being resized. + */ + on(event: 'resize', listener: Function): this; + once(event: 'resize', listener: Function): this; + addListener(event: 'resize', listener: Function): this; + removeListener(event: 'resize', listener: Function): this; + /** + * Emitted when the unresponsive web page becomes responsive again. + */ + on(event: 'responsive', listener: Function): this; + once(event: 'responsive', listener: Function): this; + addListener(event: 'responsive', listener: Function): this; + removeListener(event: 'responsive', listener: Function): this; + /** + * Emitted when the window is restored from a minimized state. + */ + on(event: 'restore', listener: Function): this; + once(event: 'restore', listener: Function): this; + addListener(event: 'restore', listener: Function): this; + removeListener(event: 'restore', listener: Function): this; + /** + * Emitted when scroll wheel event phase has begun. + */ + on(event: 'scroll-touch-begin', listener: Function): this; + once(event: 'scroll-touch-begin', listener: Function): this; + addListener(event: 'scroll-touch-begin', listener: Function): this; + removeListener(event: 'scroll-touch-begin', listener: Function): this; + /** + * Emitted when scroll wheel event phase filed upon reaching the edge of element. + */ + on(event: 'scroll-touch-edge', listener: Function): this; + once(event: 'scroll-touch-edge', listener: Function): this; + addListener(event: 'scroll-touch-edge', listener: Function): this; + removeListener(event: 'scroll-touch-edge', listener: Function): this; + /** + * Emitted when scroll wheel event phase has ended. + */ + on(event: 'scroll-touch-end', listener: Function): this; + once(event: 'scroll-touch-end', listener: Function): this; + addListener(event: 'scroll-touch-end', listener: Function): this; + removeListener(event: 'scroll-touch-end', listener: Function): this; + /** + * Emitted when window session is going to end due to force shutdown or machine + * restart or session log off. + */ + on(event: 'session-end', listener: Function): this; + once(event: 'session-end', listener: Function): this; + addListener(event: 'session-end', listener: Function): this; + removeListener(event: 'session-end', listener: Function): this; + /** + * Emitted when the window opens a sheet. + */ + on(event: 'sheet-begin', listener: Function): this; + once(event: 'sheet-begin', listener: Function): this; + addListener(event: 'sheet-begin', listener: Function): this; + removeListener(event: 'sheet-begin', listener: Function): this; + /** + * Emitted when the window has closed a sheet. + */ + on(event: 'sheet-end', listener: Function): this; + once(event: 'sheet-end', listener: Function): this; + addListener(event: 'sheet-end', listener: Function): this; + removeListener(event: 'sheet-end', listener: Function): this; + /** + * Emitted when the window is shown. + */ + on(event: 'show', listener: Function): this; + once(event: 'show', listener: Function): this; + addListener(event: 'show', listener: Function): this; + removeListener(event: 'show', listener: Function): this; + /** + * Emitted on 3-finger swipe. Possible directions are up, right, down, left. + */ + on(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + once(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + addListener(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + removeListener(event: 'swipe', listener: (event: Event, + direction: string) => void): this; + /** + * Emitted when the window exits from a maximized state. + */ + on(event: 'unmaximize', listener: Function): this; + once(event: 'unmaximize', listener: Function): this; + addListener(event: 'unmaximize', listener: Function): this; + removeListener(event: 'unmaximize', listener: Function): this; + /** + * Emitted when the web page becomes unresponsive. + */ + on(event: 'unresponsive', listener: Function): this; + once(event: 'unresponsive', listener: Function): this; + addListener(event: 'unresponsive', listener: Function): this; + removeListener(event: 'unresponsive', listener: Function): this; + constructor(options?: BrowserWindowConstructorOptions); + /** + * Adds DevTools extension located at path, and returns extension's name. The + * extension will be remembered so you only need to call this API once, this API is + * not for programming use. If you try to add an extension that has already been + * loaded, this method will not return and instead log a warning to the console. + * The method will also not return if the extension's manifest is missing or + * incomplete. Note: This API cannot be called before the ready event of the app + * module is emitted. + */ + static addDevToolsExtension(path: string): void; + /** + * Adds Chrome extension located at path, and returns extension's name. The method + * will also not return if the extension's manifest is missing or incomplete. Note: + * This API cannot be called before the ready event of the app module is emitted. + */ + static addExtension(path: string): void; + static fromId(id: number): BrowserWindow; + static fromWebContents(webContents: WebContents): BrowserWindow; + static getAllWindows(): BrowserWindow[]; + /** + * To check if a DevTools extension is installed you can run the following: Note: + * This API cannot be called before the ready event of the app module is emitted. + */ + static getDevToolsExtensions(): DevToolsExtensions; + /** + * Note: This API cannot be called before the ready event of the app module is + * emitted. + */ + static getExtensions(): Extensions; + static getFocusedWindow(): BrowserWindow; + /** + * Remove a DevTools extension by name. Note: This API cannot be called before the + * ready event of the app module is emitted. + */ + static removeDevToolsExtension(name: string): void; + /** + * Remove a Chrome extension by name. Note: This API cannot be called before the + * ready event of the app module is emitted. + */ + static removeExtension(name: string): void; + /** + * Removes focus from the window. + */ + blur(): void; + blurWebView(): void; + /** + * Same as webContents.capturePage([rect, ]callback). + */ + capturePage(callback: (image: NativeImage) => void): void; + /** + * Same as webContents.capturePage([rect, ]callback). + */ + capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; + /** + * Moves window to the center of the screen. + */ + center(): void; + /** + * Try to close the window. This has the same effect as a user manually clicking + * the close button of the window. The web page may cancel the close though. See + * the close event. + */ + close(): void; + /** + * Closes the currently open Quick Look panel. + */ + closeFilePreview(): void; + /** + * Force closing the window, the unload and beforeunload event won't be emitted for + * the web page, and close event will also not be emitted for this window, but it + * guarantees the closed event will be emitted. + */ + destroy(): void; + /** + * Starts or stops flashing the window to attract user's attention. + */ + flashFrame(flag: boolean): void; + /** + * Focuses on the window. + */ + focus(): void; + focusOnWebView(): void; + getBounds(): Rectangle; + getChildWindows(): BrowserWindow[]; + getContentBounds(): Rectangle; + getContentSize(): number[]; + getMaximumSize(): number[]; + getMinimumSize(): number[]; + /** + * The native type of the handle is HWND on Windows, NSView* on macOS, and Window + * (unsigned long) on Linux. + */ + getNativeWindowHandle(): Buffer; + getParentWindow(): BrowserWindow; + getPosition(): number[]; + getRepresentedFilename(): string; + getSize(): number[]; + /** + * Note: The title of web page can be different from the title of the native + * window. + */ + getTitle(): string; + /** + * On Windows and Linux always returns true. + */ + hasShadow(): boolean; + /** + * Hides the window. */ hide(): void; /** - * Shows the dock icon. - * - * Note: This API is only available on macOS. + * Hooks a windows message. The callback is called when the message is received in + * the WndProc. + */ + hookWindowMessage(message: number, callback: Function): void; + isAlwaysOnTop(): boolean; + /** + * On Linux always returns true. + */ + isClosable(): boolean; + isDestroyed(): boolean; + isDocumentEdited(): boolean; + isFocused(): boolean; + isFullScreen(): boolean; + isFullScreenable(): boolean; + isKiosk(): boolean; + /** + * On Linux always returns true. + */ + isMaximizable(): boolean; + isMaximized(): boolean; + isMenuBarAutoHide(): boolean; + isMenuBarVisible(): boolean; + /** + * On Linux always returns true. + */ + isMinimizable(): boolean; + isMinimized(): boolean; + isModal(): boolean; + /** + * On Linux always returns true. + */ + isMovable(): boolean; + isResizable(): boolean; + isVisible(): boolean; + /** + * Note: This API always returns false on Windows. + */ + isVisibleOnAllWorkspaces(): boolean; + isWindowMessageHooked(message: number): boolean; + /** + * Same as webContents.loadURL(url[, options]). The url can be a remote address + * (e.g. http://) or a path to a local HTML file using the file:// protocol. To + * ensure that file URLs are properly formatted, it is recommended to use Node's + * url.format method: You can load a URL using a POST request with URL-encoded data + * by doing the following: + */ + loadURL(url: string, options?: LoadURLOptions): void; + /** + * Maximizes the window. This will also show (but not focus) the window if it isn't + * being displayed already. + */ + maximize(): void; + /** + * Minimizes the window. On some platforms the minimized window will be shown in + * the Dock. + */ + minimize(): void; + /** + * Uses Quick Look to preview a file at a given path. + */ + previewFile(path: string, displayName?: string): void; + /** + * Same as webContents.reload. + */ + reload(): void; + /** + * Restores the window from minimized state to its previous state. + */ + restore(): void; + /** + * Sets whether the window should show always on top of other windows. After + * setting this, the window is still a normal window, not a toolbox window which + * can not be focused on. + */ + setAlwaysOnTop(flag: boolean, level?: 'normal' | 'floating' | 'torn-off-menu' | 'modal-panel' | 'main-menu' | 'status' | 'pop-up-menu' | 'screen-saver', relativeLevel?: number): void; + /** + * Sets the properties for the window's taskbar button. Note: relaunchCommand and + * relaunchDisplayName must always be set together. If one of those properties is + * not set, then neither will be used. + */ + setAppDetails(options: AppDetailsOptions): void; + /** + * This will make a window maintain an aspect ratio. The extra size allows a + * developer to have space, specified in pixels, not included within the aspect + * ratio calculations. This API already takes into account the difference between a + * window's size and its content size. Consider a normal window with an HD video + * player and associated controls. Perhaps there are 15 pixels of controls on the + * left edge, 25 pixels of controls on the right edge and 50 pixels of controls + * below the player. In order to maintain a 16:9 aspect ratio (standard aspect + * ratio for HD @1920x1080) within the player itself we would call this function + * with arguments of 16/9 and [ 40, 50 ]. The second argument doesn't care where + * the extra width and height are within the content view--only that they exist. + * Just sum any extra width and height areas you have within the overall content + * view. + */ + setAspectRatio(aspectRatio: number, extraSize: Size): void; + /** + * Controls whether to hide cursor when typing. + */ + setAutoHideCursor(autoHide: boolean): void; + /** + * Sets whether the window menu bar should hide itself automatically. Once set the + * menu bar will only show when users press the single Alt key. If the menu bar is + * already visible, calling setAutoHideMenuBar(true) won't hide it immediately. + */ + setAutoHideMenuBar(hide: boolean): void; + /** + * Resizes and moves the window to the supplied bounds + */ + setBounds(bounds: Rectangle, animate?: boolean): void; + /** + * Note: The BrowserView API is currently experimental and may change or be removed + * in future Electron releases. + */ + setBrowserView(browserView: BrowserView): void; + /** + * Sets whether the window can be manually closed by user. On Linux does nothing. + */ + setClosable(closable: boolean): void; + /** + * Resizes and moves the window's client area (e.g. the web page) to the supplied + * bounds. + */ + setContentBounds(bounds: Rectangle, animate?: boolean): void; + /** + * Prevents the window contents from being captured by other apps. On macOS it sets + * the NSWindow's sharingType to NSWindowSharingNone. On Windows it calls + * SetWindowDisplayAffinity with WDA_MONITOR. + */ + setContentProtection(enable: boolean): void; + /** + * Resizes the window's client area (e.g. the web page) to width and height. + */ + setContentSize(width: number, height: number, animate?: boolean): void; + /** + * Specifies whether the window’s document has been edited, and the icon in title + * bar will become gray when set to true. + */ + setDocumentEdited(edited: boolean): void; + /** + * Changes whether the window can be focused. + */ + setFocusable(focusable: boolean): void; + /** + * Sets whether the window should be in fullscreen mode. + */ + setFullScreen(flag: boolean): void; + /** + * Sets whether the maximize/zoom window button toggles fullscreen mode or + * maximizes the window. + */ + setFullScreenable(fullscreenable: boolean): void; + /** + * Sets whether the window should have a shadow. On Windows and Linux does nothing. + */ + setHasShadow(hasShadow: boolean): void; + /** + * Changes window icon. + */ + setIcon(icon: NativeImage): void; + /** + * Makes the window ignore all mouse events. All mouse events happened in this + * window will be passed to the window below this window, but if this window has + * focus, it will still receive keyboard events. + */ + setIgnoreMouseEvents(ignore: boolean): void; + /** + * Enters or leaves the kiosk mode. + */ + setKiosk(flag: boolean): void; + /** + * Sets whether the window can be manually maximized by user. On Linux does + * nothing. + */ + setMaximizable(maximizable: boolean): void; + /** + * Sets the maximum size of window to width and height. + */ + setMaximumSize(width: number, height: number): void; + /** + * Sets the menu as the window's menu bar, setting it to null will remove the menu + * bar. + */ + setMenu(menu: Menu | null): void; + /** + * Sets whether the menu bar should be visible. If the menu bar is auto-hide, users + * can still bring up the menu bar by pressing the single Alt key. + */ + setMenuBarVisibility(visible: boolean): void; + /** + * Sets whether the window can be manually minimized by user. On Linux does + * nothing. + */ + setMinimizable(minimizable: boolean): void; + /** + * Sets the minimum size of window to width and height. + */ + setMinimumSize(width: number, height: number): void; + /** + * Sets whether the window can be moved by user. On Linux does nothing. + */ + setMovable(movable: boolean): void; + /** + * Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to + * convey some sort of application status or to passively notify the user. + */ + setOverlayIcon(overlay: NativeImage, description: string): void; + /** + * Sets parent as current window's parent window, passing null will turn current + * window into a top-level window. + */ + setParentWindow(parent: BrowserWindow): void; + /** + * Moves window to x and y. + */ + setPosition(x: number, y: number, animate?: boolean): void; + /** + * Sets progress value in progress bar. Valid range is [0, 1.0]. Remove progress + * bar when progress < 0; Change to indeterminate mode when progress > 1. On Linux + * platform, only supports Unity desktop environment, you need to specify the + * *.desktop file name to desktopName field in package.json. By default, it will + * assume app.getName().desktop. On Windows, a mode can be passed. Accepted values + * are none, normal, indeterminate, error, and paused. If you call setProgressBar + * without a mode set (but with a value within the valid range), normal will be + * assumed. + */ + setProgressBar(progress: number, options?: ProgressBarOptions): void; + /** + * Sets the pathname of the file the window represents, and the icon of the file + * will show in window's title bar. + */ + setRepresentedFilename(filename: string): void; + /** + * Sets whether the window can be manually resized by user. + */ + setResizable(resizable: boolean): void; + /** + * Changes the attachment point for sheets on macOS. By default, sheets are + * attached just below the window frame, but you may want to display them beneath a + * HTML-rendered toolbar. For example: + */ + setSheetOffset(offsetY: number, offsetX?: number): void; + /** + * Resizes the window to width and height. + */ + setSize(width: number, height: number, animate?: boolean): void; + /** + * Makes the window not show in the taskbar. + */ + setSkipTaskbar(skip: boolean): void; + /** + * Add a thumbnail toolbar with a specified set of buttons to the thumbnail image + * of a window in a taskbar button layout. Returns a Boolean object indicates + * whether the thumbnail has been added successfully. The number of buttons in + * thumbnail toolbar should be no greater than 7 due to the limited room. Once you + * setup the thumbnail toolbar, the toolbar cannot be removed due to the platform's + * limitation. But you can call the API with an empty array to clean the buttons. + * The buttons is an array of Button objects: The flags is an array that can + * include following Strings: + */ + setThumbarButtons(buttons: ThumbarButton[]): boolean; + /** + * Sets the region of the window to show as the thumbnail image displayed when + * hovering over the window in the taskbar. You can reset the thumbnail to be the + * entire window by specifying an empty region: {x: 0, y: 0, width: 0, height: 0}. + */ + setThumbnailClip(region: Rectangle): void; + /** + * Sets the toolTip that is displayed when hovering over the window thumbnail in + * the taskbar. + */ + setThumbnailToolTip(toolTip: string): void; + /** + * Changes the title of native window to title. + */ + setTitle(title: string): void; + /** + * Sets the touchBar layout for the current window. Specifying null or undefined + * clears the touch bar. This method only has an effect if the machine has a touch + * bar and is running on macOS 10.12.1+. Note: The TouchBar API is currently + * experimental and may change or be removed in future Electron releases. + */ + setTouchBar(touchBar: TouchBar): void; + /** + * Adds a vibrancy effect to the browser window. Passing null or an empty string + * will remove the vibrancy effect on the window. + */ + setVibrancy(type: 'appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark'): void; + /** + * Sets whether the window should be visible on all workspaces. Note: This API does + * nothing on Windows. + */ + setVisibleOnAllWorkspaces(visible: boolean): void; + /** + * Shows and gives focus to the window. */ show(): void; /** - * @returns Whether the dock icon is visible. - * The app.dock.show() call is asynchronous so this method might not return true immediately after that call. - * - * Note: This API is only available on macOS. + * Same as webContents.showDefinitionForSelection(). */ - isVisible(): boolean; + showDefinitionForSelection(): void; /** - * Sets the application dock menu. - * - * Note: This API is only available on macOS. + * Shows the window but doesn't focus on it. */ - setMenu(menu: Menu): void; + showInactive(): void; /** - * Sets the image associated with this dock icon. - * - * Note: This API is only available on macOS. + * Unhooks all of the window messages. */ - setIcon(icon: NativeImage | string): void; + unhookAllWindowMessages(): void; + /** + * Unhook the window message. + */ + unhookWindowMessage(message: number): void; + /** + * Unmaximizes the window. + */ + unmaximize(): void; + id: number; + webContents: WebContents; } - interface Task { + class BrowserWindowProxy extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/browser-window-proxy + /** - * Path of the program to execute, usually you should specify process.execPath - * which opens current program. + * Removes focus from the child window. */ - program: string; + blur(): void; /** - * The arguments of command line when program is executed. + * Forcefully closes the child window without calling its unload event. */ - arguments: string; + close(): void; /** - * The string to be displayed in a JumpList. + * Evaluates the code in the child window. */ - title: string; + eval(code: string): void; /** - * Description of this task. + * Focuses the child window (brings the window to front). */ - description?: string; + focus(): void; /** - * The absolute path to an icon to be displayed in a JumpList, it can be - * arbitrary resource file that contains an icon, usually you can specify - * process.execPath to show the icon of the program. + * Sends a message to the child window with the specified origin or * for no origin + * preference. In addition to these methods, the child window implements + * window.opener object with no properties and a single method. */ - iconPath: string; + postMessage(message: string, targetOrigin: string): void; /** - * The icon index in the icon file. If an icon file consists of two or more - * icons, set this value to identify the icon. If an icon file consists of - * one icon, this value is 0. + * Invokes the print dialog on the child window. */ - iconIndex?: number; + print(): void; + closed: boolean; } - /** - * ok - Nothing went wrong. - * error - One or more errors occured, enable runtime logging to figure out the likely cause. - * invalidSeparatorError - An attempt was made to add a separator to a custom category in the Jump List. - * Separators are only allowed in the standard Tasks category. - * fileTypeRegistrationError - An attempt was made to add a file link to the Jump List - * for a file type the app isn't registered to handle. - * customCategoryAccessDeniedError - Custom categories can't be added to the Jump List - * due to user privacy or group policy settings. - */ - type SetJumpListResult = 'ok' | 'error' | 'invalidSeparatorError' | 'fileTypeRegistrationError' | 'customCategoryAccessDeniedError'; + interface Certificate { + + // Docs: http://electron.atom.io/docs/api/structures/certificate - interface JumpListSettings { /** - * The minimum number of items that will be shown in the Jump List. + * PEM encoded data */ - minItems: number; + data: string; /** - * Items that the user has explicitly removed from custom categories in the Jump List. + * Fingerprint of the certificate */ - removedItems: JumpListItem[]; + fingerprint: string; + /** + * Issuer principal + */ + issuer: CertificatePrincipal; + /** + * Issuer certificate (if not self-signed) + */ + issuerCert: Certificate; + /** + * Issuer's Common Name + */ + issuerName: string; + /** + * Hex value represented string + */ + serialNumber: string; + /** + * Subject principal + */ + subject: CertificatePrincipal; + /** + * Subject's Common Name + */ + subjectName: string; + /** + * End date of the certificate being valid in seconds + */ + validExpiry: number; + /** + * Start date of the certificate being valid in seconds + */ + validStart: number; + } + + interface CertificatePrincipal { + + // Docs: http://electron.atom.io/docs/api/structures/certificate-principal + + /** + * Common Name + */ + commonName: string; + /** + * Country or region + */ + country: string; + /** + * Locality + */ + locality: string; + /** + * Organization names + */ + organizations: string[]; + /** + * Organization Unit names + */ + organizationUnits: string[]; + /** + * State or province + */ + state: string; + } + + class ClientRequest extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/client-request + + /** + * Emitted when the request is aborted. The abort event will not be fired if the + * request is already closed. + */ + on(event: 'abort', listener: Function): this; + once(event: 'abort', listener: Function): this; + addListener(event: 'abort', listener: Function): this; + removeListener(event: 'abort', listener: Function): this; + /** + * Emitted as the last event in the HTTP request-response transaction. The close + * event indicates that no more events will be emitted on either the request or + * response objects. + */ + on(event: 'close', listener: Function): this; + once(event: 'close', listener: Function): this; + addListener(event: 'close', listener: Function): this; + removeListener(event: 'close', listener: Function): this; + /** + * Emitted when the net module fails to issue a network request. Typically when the + * request object emits an error event, a close event will subsequently follow and + * no response object will be provided. + */ + on(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + once(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + addListener(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + removeListener(event: 'error', listener: ( + /** + * an error object providing some information about the failure. + */ + error: Error) => void): this; + /** + * Emitted just after the last chunk of the request's data has been written into + * the request object. + */ + on(event: 'finish', listener: Function): this; + once(event: 'finish', listener: Function): this; + addListener(event: 'finish', listener: Function): this; + removeListener(event: 'finish', listener: Function): this; + /** + * Emitted when an authenticating proxy is asking for user credentials. The + * callback function is expected to be called back with user credentials: Providing + * empty credentials will cancel the request and report an authentication error on + * the response object: + */ + on(event: 'login', listener: (authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + once(event: 'login', listener: (authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + addListener(event: 'login', listener: (authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + removeListener(event: 'login', listener: (authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + /** + * Emitted when there is redirection and the mode is manual. Calling + * request.followRedirect will continue with the redirection. + */ + on(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: any) => void): this; + once(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: any) => void): this; + addListener(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: any) => void): this; + removeListener(event: 'redirect', listener: (statusCode: number, + method: string, + redirectUrl: string, + responseHeaders: any) => void): this; + on(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + once(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + addListener(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + removeListener(event: 'response', listener: ( + /** + * An object representing the HTTP response message. + */ + response: IncomingMessage) => void): this; + constructor(options: any | string); + /** + * Cancels an ongoing HTTP transaction. If the request has already emitted the + * close event, the abort operation will have no effect. Otherwise an ongoing event + * will emit abort and close events. Additionally, if there is an ongoing response + * object,it will emit the aborted event. + */ + abort(): void; + /** + * Sends the last chunk of the request data. Subsequent write or end operations + * will not be allowed. The finish event is emitted just after the end operation. + */ + end(chunk?: string | Buffer, encoding?: string, callback?: Function): void; + /** + * Continues any deferred redirection request when the redirection mode is manual. + */ + followRedirect(): void; + getHeader(name: string): Header; + /** + * Removes a previously set extra header name. This method can be called only + * before first write. Trying to call it after the first write will throw an error. + */ + removeHeader(name: string): void; + /** + * Adds an extra HTTP header. The header name will issued as it is without + * lowercasing. It can be called only before first write. Calling this method after + * the first write will throw an error. If the passed value is not a String, its + * toString() method will be called to obtain the final value. + */ + setHeader(name: string, value: any): void; + /** + * callback is essentially a dummy function introduced in the purpose of keeping + * similarity with the Node.js API. It is called asynchronously in the next tick + * after chunk content have been delivered to the Chromium networking layer. + * Contrary to the Node.js implementation, it is not guaranteed that chunk content + * have been flushed on the wire before callback is called. Adds a chunk of data to + * the request body. The first write operation may cause the request headers to be + * issued on the wire. After the first write operation, it is not allowed to add or + * remove a custom header. + */ + write(chunk: string | Buffer, encoding?: string, callback?: Function): void; + chunkedEncoding: boolean; + } + + interface Clipboard extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/clipboard + + availableFormats(type?: string): string[]; + /** + * Clears the clipboard content. + */ + clear(type?: string): void; + has(format: string, type?: string): boolean; + read(format: string): string; + /** + * Returns an Object containing title and url keys representing the bookmark in the + * clipboard. The title and url values will be empty strings when the bookmark is + * unavailable. + */ + readBookmark(): ReadBookmark; + readBuffer(format: string): Buffer; + readFindText(): string; + readHTML(type?: string): string; + readImage(type?: string): NativeImage; + readRTF(type?: string): string; + readText(type?: string): string; + /** + * Writes data to the clipboard. + */ + write(data: Data, type?: string): void; + /** + * Writes the title and url into the clipboard as a bookmark. Note: Most apps on + * Windows don't support pasting bookmarks into them so you can use clipboard.write + * to write both a bookmark and fallback text to the clipboard. + */ + writeBookmark(title: string, url: string, type?: string): void; + /** + * Writes the buffer into the clipboard as format. + */ + writeBuffer(format: string, buffer: Buffer, type?: string): void; + /** + * Writes the text into the find pasteboard as plain text. This method uses + * synchronous IPC when called from the renderer process. + */ + writeFindText(text: string): void; + /** + * Writes markup to the clipboard. + */ + writeHTML(markup: string, type?: string): void; + /** + * Writes image to the clipboard. + */ + writeImage(image: NativeImage, type?: string): void; + /** + * Writes the text into the clipboard in RTF. + */ + writeRTF(text: string, type?: string): void; + /** + * Writes the text into the clipboard as plain text. + */ + writeText(text: string, type?: string): void; + } + + interface ContentTracing extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/content-tracing + + /** + * Get the current monitoring traced data. Child processes typically cache trace + * data and only rarely flush and send trace data back to the main process. This is + * because it may be an expensive operation to send the trace data over IPC and we + * would like to avoid unneeded runtime overhead from tracing. So, to end tracing, + * we must asynchronously ask all child processes to flush any pending trace data. + * Once all child processes have acknowledged the captureMonitoringSnapshot request + * the callback will be called with a file that contains the traced data. + */ + captureMonitoringSnapshot(resultFilePath: string, callback: (resultFilePath: string) => void): void; + /** + * Get a set of category groups. The category groups can change as new code paths + * are reached. Once all child processes have acknowledged the getCategories + * request the callback is invoked with an array of category groups. + */ + getCategories(callback: (categories: string[]) => void): void; + /** + * Get the maximum usage across processes of trace buffer as a percentage of the + * full state. When the TraceBufferUsage value is determined the callback is + * called. + */ + getTraceBufferUsage(callback: (value: number, percentage: number) => void): void; + /** + * Start monitoring on all processes. Monitoring begins immediately locally and + * asynchronously on child processes as soon as they receive the startMonitoring + * request. Once all child processes have acknowledged the startMonitoring request + * the callback will be called. + */ + startMonitoring(options: StartMonitoringOptions, callback: Function): void; + /** + * Start recording on all processes. Recording begins immediately locally and + * asynchronously on child processes as soon as they receive the EnableRecording + * request. The callback will be called once all child processes have acknowledged + * the startRecording request. categoryFilter is a filter to control what category + * groups should be traced. A filter can have an optional - prefix to exclude + * category groups that contain a matching category. Having both included and + * excluded category patterns in the same list is not supported. Examples: + * traceOptions controls what kind of tracing is enabled, it is a comma-delimited + * list. Possible options are: The first 3 options are trace recording modes and + * hence mutually exclusive. If more than one trace recording modes appear in the + * traceOptions string, the last one takes precedence. If none of the trace + * recording modes are specified, recording mode is record-until-full. The trace + * option will first be reset to the default option (record_mode set to + * record-until-full, enable_sampling and enable_systrace set to false) before + * options parsed from traceOptions are applied on it. + */ + startRecording(options: StartRecordingOptions, callback: Function): void; + /** + * Stop monitoring on all processes. Once all child processes have acknowledged the + * stopMonitoring request the callback is called. + */ + stopMonitoring(callback: Function): void; + /** + * Stop recording on all processes. Child processes typically cache trace data and + * only rarely flush and send trace data back to the main process. This helps to + * minimize the runtime overhead of tracing since sending trace data over IPC can + * be an expensive operation. So, to end tracing, we must asynchronously ask all + * child processes to flush any pending trace data. Once all child processes have + * acknowledged the stopRecording request, callback will be called with a file that + * contains the traced data. Trace data will be written into resultFilePath if it + * is not empty or into a temporary file. The actual file path will be passed to + * callback if it's not null. + */ + stopRecording(resultFilePath: string, callback: (resultFilePath: string) => void): void; + } + + interface Cookie { + + // Docs: http://electron.atom.io/docs/api/structures/cookie + + /** + * The domain of the cookie. + */ + domain?: string; + /** + * The expiration date of the cookie as the number of seconds since the UNIX epoch. + * Not provided for session cookies. + */ + expirationDate?: number; + /** + * Whether the cookie is a host-only cookie. + */ + hostOnly?: boolean; + /** + * Whether the cookie is marked as HTTP only. + */ + httpOnly?: boolean; + /** + * The name of the cookie. + */ + name: string; + /** + * The path of the cookie. + */ + path?: string; + /** + * Whether the cookie is marked as secure. + */ + secure?: boolean; + /** + * Whether the cookie is a session cookie or a persistent cookie with an expiration + * date. + */ + session?: boolean; + /** + * The value of the cookie. + */ + value: string; + } + + class Cookies extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/cookies + + /** + * Emitted when a cookie is changed because it was added, edited, removed, or + * expired. + */ + on(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + once(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + addListener(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + removeListener(event: 'changed', listener: (event: Event, + /** + * The cookie that was changed + */ + cookie: Cookie, + /** + * The cause of the change with one of the following values: + */ + cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), + /** + * `true` if the cookie was removed, `false` otherwise. + */ + removed: boolean) => void): this; + /** + * Writes any unwritten cookies data to disk. + */ + flushStore(callback: Function): void; + /** + * Sends a request to get all cookies matching details, callback will be called + * with callback(error, cookies) on complete. + */ + get(filter: Filter, callback: (error: Error, cookies: Cookie[]) => void): void; + /** + * Removes the cookies matching url and name, callback will called with callback() + * on complete. + */ + remove(url: string, name: string, callback: Function): void; + /** + * Sets a cookie with details, callback will be called with callback(error) on + * complete. + */ + set(details: Details, callback: (error: Error) => void): void; + } + + interface CPUUsage { + + // Docs: http://electron.atom.io/docs/api/structures/cpu-usage + + /** + * The number of average idle cpu wakeups per second since the last call to + * getCPUUsage. First call returns 0. + */ + idleWakeupsPerSecond: number; + /** + * Percentage of CPU used since the last call to getCPUUsage. First call returns 0. + */ + percentCPUUsage: number; + } + + interface CrashReport { + + // Docs: http://electron.atom.io/docs/api/structures/crash-report + + date: string; + ID: number; + } + + interface CrashReporter extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/crash-reporter + + /** + * Returns the date and ID of the last crash report. If no crash reports have been + * sent or the crash reporter has not been started, null is returned. + */ + getLastCrashReport(): CrashReport; + /** + * Returns all uploaded crash reports. Each report contains the date and uploaded + * ID. + */ + getUploadedReports(): CrashReport[]; + /** + * Note: This API can only be called from the main process. + */ + getUploadToServer(): boolean; + /** + * Set an extra parameter to be sent with the crash report. The values specified + * here will be sent in addition to any values set via the extra option when start + * was called. This API is only available on macOS, if you need to add/update extra + * parameters on Linux and Windows after your first call to start you can call + * start again with the updated extra options. + */ + setExtraParameter(key: string, value: string): void; + /** + * This would normally be controlled by user preferences. This has no effect if + * called before start is called. Note: This API can only be called from the main + * process. + */ + setUploadToServer(uploadToServer: boolean): void; + /** + * You are required to call this method before using any other crashReporter APIs + * and in each process (main/renderer) from which you want to collect crash + * reports. You can pass different options to crashReporter.start when calling from + * different processes. Note Child processes created via the child_process module + * will not have access to the Electron modules. Therefore, to collect crash + * reports from them, use process.crashReporter.start instead. Pass the same + * options as above along with an additional one called crashesDirectory that + * should point to a directory to store the crash reports temporarily. You can test + * this out by calling process.crash() to crash the child process. Note: To collect + * crash reports from child process in Windows, you need to add this extra code as + * well. This will start the process that will monitor and send the crash reports. + * Replace submitURL, productName and crashesDirectory with appropriate values. + * Note: If you need send additional/updated extra parameters after your first call + * start you can call setExtraParameter on macOS or call start again with the + * new/updated extra parameters on Linux and Windows. Note: On macOS, Electron uses + * a new crashpad client for crash collection and reporting. If you want to enable + * crash reporting, initializing crashpad from the main process using + * crashReporter.start is required regardless of which process you want to collect + * crashes from. Once initialized this way, the crashpad handler collects crashes + * from all processes. You still have to call crashReporter.start from the renderer + * or child process, otherwise crashes from them will get reported without + * companyName, productName or any of the extra information. + */ + start(options: CrashReporterStartOptions): void; + } + + class Debugger extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/debugger + + /** + * Emitted when debugging session is terminated. This happens either when + * webContents is closed or devtools is invoked for the attached webContents. + */ + on(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + once(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + addListener(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + removeListener(event: 'detach', listener: (event: Event, + /** + * Reason for detaching debugger. + */ + reason: string) => void): this; + /** + * Emitted whenever debugging target issues instrumentation event. + */ + on(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any) => void): this; + once(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any) => void): this; + addListener(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any) => void): this; + removeListener(event: 'message', listener: (event: Event, + /** + * Method name. + */ + method: string, + /** + * Event parameters defined by the 'parameters' attribute in the remote debugging + * protocol. + */ + params: any) => void): this; + /** + * Attaches the debugger to the webContents. + */ + attach(protocolVersion?: string): void; + /** + * Detaches the debugger from the webContents. + */ + detach(): void; + isAttached(): boolean; + /** + * Send given command to the debugging target. + */ + sendCommand(method: string, commandParams?: any, callback?: (error: any, result: any) => void): void; + } + + interface DesktopCapturer extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/desktop-capturer + + /** + * Starts gathering information about all available desktop media sources, and + * calls callback(error, sources) when finished. sources is an array of + * DesktopCapturerSource objects, each DesktopCapturerSource represents a screen or + * an individual window that can be captured. + */ + getSources(options: SourcesOptions, callback: (error: Error, sources: DesktopCapturerSource[]) => void): void; + } + + interface DesktopCapturerSource { + + // Docs: http://electron.atom.io/docs/api/structures/desktop-capturer-source + + /** + * The identifier of a window or screen that can be used as a chromeMediaSourceId + * constraint when calling [navigator.webkitGetUserMedia]. The format of the + * identifier will be window:XX or screen:XX, where XX is a random generated + * number. + */ + id: string; + /** + * A screen source will be named either Entire Screen or Screen , while the + * name of a window source will match the window title. + */ + name: string; + /** + * A thumbnail image. There is no guarantee that the size of the thumbnail is the + * same as the thumbnailSize specified in the options passed to + * desktopCapturer.getSources. The actual size depends on the scale of the screen + * or window. + */ + thumbnail: NativeImage; + } + + interface Dialog extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/dialog + + /** + * On macOS, this displays a modal dialog that shows a message and certificate + * information, and gives the user the option of trusting/importing the + * certificate. If you provide a browserWindow argument the dialog will be attached + * to the parent window, making it modal. On Windows the options are more limited, + * due to the Win32 APIs used: + */ + showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions, callback: Function): void; + /** + * On macOS, this displays a modal dialog that shows a message and certificate + * information, and gives the user the option of trusting/importing the + * certificate. If you provide a browserWindow argument the dialog will be attached + * to the parent window, making it modal. On Windows the options are more limited, + * due to the Win32 APIs used: + */ + showCertificateTrustDialog(options: CertificateTrustDialogOptions, callback: Function): void; + /** + * On macOS, this displays a modal dialog that shows a message and certificate + * information, and gives the user the option of trusting/importing the + * certificate. If you provide a browserWindow argument the dialog will be attached + * to the parent window, making it modal. On Windows the options are more limited, + * due to the Win32 APIs used: + */ + showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions, callback: Function): void; + /** + * Displays a modal dialog that shows an error message. This API can be called + * safely before the ready event the app module emits, it is usually used to report + * errors in early stage of startup. If called before the app readyevent on Linux, + * the message will be emitted to stderr, and no GUI dialog will appear. + */ + showErrorBox(title: string, content: string): void; + /** + * Shows a message box, it will block the process until the message box is closed. + * It returns the index of the clicked button. The browserWindow argument allows + * the dialog to attach itself to a parent window, making it modal. If a callback + * is passed, the dialog will not block the process. The API call will be + * asynchronous and the result will be passed via callback(response). + */ + showMessageBox(browserWindow: BrowserWindow, options: MessageBoxOptions, callback?: (response: number, checkboxChecked: boolean) => void): number; + /** + * Shows a message box, it will block the process until the message box is closed. + * It returns the index of the clicked button. The browserWindow argument allows + * the dialog to attach itself to a parent window, making it modal. If a callback + * is passed, the dialog will not block the process. The API call will be + * asynchronous and the result will be passed via callback(response). + */ + showMessageBox(options: MessageBoxOptions, callback?: (response: number, checkboxChecked: boolean) => void): number; + /** + * The browserWindow argument allows the dialog to attach itself to a parent + * window, making it modal. The filters specifies an array of file types that can + * be displayed or selected when you want to limit the user to a specific type. For + * example: The extensions array should contain extensions without wildcards or + * dots (e.g. 'png' is good but '.png' and '*.png' are bad). To show all files, use + * the '*' wildcard (no other wildcard is supported). If a callback is passed, the + * API call will be asynchronous and the result will be passed via + * callback(filenames) Note: On Windows and Linux an open dialog can not be both a + * file selector and a directory selector, so if you set properties to ['openFile', + * 'openDirectory'] on these platforms, a directory selector will be shown. + */ + showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: (filePaths: string[]) => void): string[]; + /** + * The browserWindow argument allows the dialog to attach itself to a parent + * window, making it modal. The filters specifies an array of file types that can + * be displayed or selected when you want to limit the user to a specific type. For + * example: The extensions array should contain extensions without wildcards or + * dots (e.g. 'png' is good but '.png' and '*.png' are bad). To show all files, use + * the '*' wildcard (no other wildcard is supported). If a callback is passed, the + * API call will be asynchronous and the result will be passed via + * callback(filenames) Note: On Windows and Linux an open dialog can not be both a + * file selector and a directory selector, so if you set properties to ['openFile', + * 'openDirectory'] on these platforms, a directory selector will be shown. + */ + showOpenDialog(options: OpenDialogOptions, callback?: (filePaths: string[]) => void): string[]; + /** + * The browserWindow argument allows the dialog to attach itself to a parent + * window, making it modal. The filters specifies an array of file types that can + * be displayed, see dialog.showOpenDialog for an example. If a callback is passed, + * the API call will be asynchronous and the result will be passed via + * callback(filename) + */ + showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (filename: string) => void): string; + /** + * The browserWindow argument allows the dialog to attach itself to a parent + * window, making it modal. The filters specifies an array of file types that can + * be displayed, see dialog.showOpenDialog for an example. If a callback is passed, + * the API call will be asynchronous and the result will be passed via + * callback(filename) + */ + showSaveDialog(options: SaveDialogOptions, callback?: (filename: string) => void): string; + } + + interface Display { + + // Docs: http://electron.atom.io/docs/api/structures/display + + bounds: Rectangle; + /** + * Unique identifier associated with the display. + */ + id: number; + /** + * Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. + */ + rotation: number; + /** + * Output device's pixel scale factor. + */ + scaleFactor: number; + size: Size; + /** + * Can be available, unavailable, unknown. + */ + touchSupport: ('available' | 'unavailable' | 'unknown'); + workArea: Rectangle; + workAreaSize: Size; + } + + class DownloadItem extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/download-item + + /** + * Emitted when the download is in a terminal state. This includes a completed + * download, a cancelled download (via downloadItem.cancel()), and interrupted + * download that can't be resumed. The state can be one of following: + */ + on(event: 'done', listener: (event: Event, + state: string) => void): this; + once(event: 'done', listener: (event: Event, + state: string) => void): this; + addListener(event: 'done', listener: (event: Event, + state: string) => void): this; + removeListener(event: 'done', listener: (event: Event, + state: string) => void): this; + /** + * Emitted when the download has been updated and is not done. The state can be one + * of following: + */ + on(event: 'updated', listener: (event: Event, + state: string) => void): this; + once(event: 'updated', listener: (event: Event, + state: string) => void): this; + addListener(event: 'updated', listener: (event: Event, + state: string) => void): this; + removeListener(event: 'updated', listener: (event: Event, + state: string) => void): this; + /** + * Cancels the download operation. + */ + cancel(): void; + /** + * Resumes Boolean - Whether the download can resume. + */ + canResume(): void; + getContentDisposition(): string; + getETag(): string; + /** + * Note: The file name is not always the same as the actual one saved in local + * disk. If user changes the file name in a prompted download saving dialog, the + * actual name of saved file will be different. + */ + getFilename(): string; + getLastModifiedTime(): string; + getMimeType(): string; + getReceivedBytes(): number; + getSavePath(): string; + getStartTime(): number; + /** + * Note: The following methods are useful specifically to resume a cancelled item + * when session is restarted. + */ + getState(): ('progressing' | 'completed' | 'cancelled' | 'interrupted'); + /** + * If the size is unknown, it returns 0. + */ + getTotalBytes(): number; + getURL(): string; + getURLChain(): string[]; + hasUserGesture(): boolean; + isPaused(): boolean; + /** + * Pauses the download. + */ + pause(): void; + /** + * Resumes the download that has been paused. Note: To enable resumable downloads + * the server you are downloading from must support range requests and provide both + * Last-Modified and ETag header values. Otherwise resume() will dismiss previously + * received bytes and restart the download from the beginning. + */ + resume(): void; + /** + * The API is only available in session's will-download callback function. If user + * doesn't set the save path via the API, Electron will use the original routine to + * determine the save path(Usually prompts a save dialog). + */ + setSavePath(path: string): void; + } + + interface FileFilter { + + // Docs: http://electron.atom.io/docs/api/structures/file-filter + + extensions: string[]; + name: string; + } + + interface GlobalShortcut extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/global-shortcut + + /** + * When the accelerator is already taken by other applications, this call will + * still return false. This behavior is intended by operating systems, since they + * don't want applications to fight for global shortcuts. + */ + isRegistered(accelerator: Accelerator): boolean; + /** + * Registers a global shortcut of accelerator. The callback is called when the + * registered shortcut is pressed by the user. When the accelerator is already + * taken by other applications, this call will silently fail. This behavior is + * intended by operating systems, since they don't want applications to fight for + * global shortcuts. + */ + register(accelerator: Accelerator, callback: Function): void; + /** + * Unregisters the global shortcut of accelerator. + */ + unregister(accelerator: Accelerator): void; + /** + * Unregisters all of the global shortcuts. + */ + unregisterAll(): void; + } + + interface GPUFeatureStatus { + + // Docs: http://electron.atom.io/docs/api/structures/gpu-feature-status + + /** + * Canvas + */ + '2d_canvas': string; + /** + * Flash + */ + flash_3d: string; + /** + * Flash Stage3D + */ + flash_stage3d: string; + /** + * Flash Stage3D Baseline profile + */ + flash_stage3d_baseline: string; + /** + * Compositing + */ + gpu_compositing: string; + /** + * Multiple Raster Threads + */ + multiple_raster_threads: string; + /** + * Native GpuMemoryBuffers + */ + native_gpu_memory_buffers: string; + /** + * Rasterization + */ + rasterization: string; + /** + * Video Decode + */ + video_decode: string; + /** + * Video Encode + */ + video_encode: string; + /** + * VPx Video Decode + */ + vpx_decode: string; + /** + * WebGL + */ + webgl: string; + /** + * WebGL2 + */ + webgl2: string; + } + + class IncomingMessage extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/incoming-message + + /** + * Emitted when a request has been canceled during an ongoing HTTP transaction. + */ + on(event: 'aborted', listener: Function): this; + once(event: 'aborted', listener: Function): this; + addListener(event: 'aborted', listener: Function): this; + removeListener(event: 'aborted', listener: Function): this; + /** + * The data event is the usual method of transferring response data into + * applicative code. + */ + on(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + once(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + addListener(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + removeListener(event: 'data', listener: ( + /** + * A chunk of response body's data. + */ + chunk: Buffer) => void): this; + /** + * Indicates that response body has ended. + */ + on(event: 'end', listener: Function): this; + once(event: 'end', listener: Function): this; + addListener(event: 'end', listener: Function): this; + removeListener(event: 'end', listener: Function): this; + /** + * error Error - Typically holds an error string identifying failure root cause. + * Emitted when an error was encountered while streaming response data events. For + * instance, if the server closes the underlying while the response is still + * streaming, an error event will be emitted on the response object and a close + * event will subsequently follow on the request object. + */ + on(event: 'error', listener: Function): this; + once(event: 'error', listener: Function): this; + addListener(event: 'error', listener: Function): this; + removeListener(event: 'error', listener: Function): this; + headers: any; + httpVersion: string; + httpVersionMajor: number; + httpVersionMinor: number; + statusCode: number; + statusMessage: string; + } + + interface IOCounters { + + // Docs: http://electron.atom.io/docs/api/structures/io-counters + + /** + * Then number of I/O other operations. + */ + otherOperationCount: number; + /** + * Then number of I/O other transfers. + */ + otherTransferCount: number; + /** + * The number of I/O read operations. + */ + readOperationCount: number; + /** + * The number of I/O read transfers. + */ + readTransferCount: number; + /** + * The number of I/O write operations. + */ + writeOperationCount: number; + /** + * The number of I/O write transfers. + */ + writeTransferCount: number; + } + + interface IpcMain extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/ipc-main + + /** + * Listens to channel, when a new message arrives listener would be called with + * listener(event, args...). + */ + on(channel: string, listener: Function): this; + /** + * Adds a one time listener function for the event. This listener is invoked only + * the next time a message is sent to channel, after which it is removed. + */ + once(channel: string, listener: Function): this; + /** + * Removes listeners of the specified channel. + */ + removeAllListeners(channel: string): this; + /** + * Removes the specified listener from the listener array for the specified + * channel. + */ + removeListener(channel: string, listener: Function): this; + } + + interface IpcRenderer extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/ipc-renderer + + /** + * Listens to channel, when a new message arrives listener would be called with + * listener(event, args...). + */ + on(channel: string, listener: Function): this; + /** + * Adds a one time listener function for the event. This listener is invoked only + * the next time a message is sent to channel, after which it is removed. + */ + once(channel: string, listener: Function): this; + /** + * Removes all listeners, or those of the specified channel. + */ + removeAllListeners(channel?: string): this; + /** + * Removes the specified listener from the listener array for the specified + * channel. + */ + removeListener(channel: string, listener: Function): this; + /** + * Send a message to the main process asynchronously via channel, you can also send + * arbitrary arguments. Arguments will be serialized in JSON internally and hence + * no functions or prototype chain will be included. The main process handles it by + * listening for channel with ipcMain module. + */ + send(channel: string, ...args: any[]): void; + /** + * Send a message to the main process synchronously via channel, you can also send + * arbitrary arguments. Arguments will be serialized in JSON internally and hence + * no functions or prototype chain will be included. The main process handles it by + * listening for channel with ipcMain module, and replies by setting + * event.returnValue. Note: Sending a synchronous message will block the whole + * renderer process, unless you know what you are doing you should never use it. + */ + sendSync(channel: string, ...args: any[]): any; + /** + * Like ipcRenderer.send but the event will be sent to the element in the + * host page instead of the main process. + */ + sendToHost(channel: string, ...args: any[]): void; } interface JumpListCategory { + + // Docs: http://electron.atom.io/docs/api/structures/jump-list-category + /** - * tasks - Items in this category will be placed into the standard Tasks category. - * frequent - Displays a list of files frequently opened by the app, the name of the category and its items are set by Windows. - * recent - Displays a list of files recently opened by the app, the name of the category and its items are set by Windows. - * custom - Displays tasks or file links, name must be set by the app. + * Array of objects if type is tasks or custom, otherwise it should be omitted. */ - type?: 'tasks' | 'frequent' | 'recent' | 'custom'; + items?: JumpListItem[]; /** * Must be set if type is custom, otherwise it should be omitted. */ name?: string; /** - * Array of JumpListItem objects if type is tasks or custom, otherwise it should be omitted. + * One of the following: */ - items?: JumpListItem[]; + type?: ('tasks' | 'frequent' | 'recent' | 'custom'); } interface JumpListItem { + + // Docs: http://electron.atom.io/docs/api/structures/jump-list-item + /** - * task - A task will launch an app with specific arguments. - * separator - Can be used to separate items in the standard Tasks category. - * file - A file link will open a file using the app that created the Jump List. + * The command line arguments when program is executed. Should only be set if type + * is task. */ - type: 'task' | 'separator' | 'file'; + args?: string; + /** + * Description of the task (displayed in a tooltip). Should only be set if type is + * task. + */ + description?: string; + /** + * The index of the icon in the resource file. If a resource file contains multiple + * icons this value can be used to specify the zero-based index of the icon that + * should be displayed for this task. If a resource file contains only one icon, + * this property should be set to zero. + */ + iconIndex?: number; + /** + * The absolute path to an icon to be displayed in a Jump List, which can be an + * arbitrary resource file that contains an icon (e.g. .ico, .exe, .dll). You can + * usually specify process.execPath to show the program icon. + */ + iconPath?: string; /** * Path of the file to open, should only be set if type is file. */ path?: string; /** - * Path of the program to execute, usually you should specify process.execPath which opens the current program. - * Should only be set if type is task. + * Path of the program to execute, usually you should specify process.execPath + * which opens the current program. Should only be set if type is task. */ program?: string; /** - * The command line arguments when program is executed. Should only be set if type is task. - */ - args?: string; - /** - * The text to be displayed for the item in the Jump List. Should only be set if type is task. + * The text to be displayed for the item in the Jump List. Should only be set if + * type is task. */ title?: string; /** - * Description of the task (displayed in a tooltip). Should only be set if type is task. + * One of the following: + */ + type?: ('task' | 'separator' | 'file'); + } + + interface MemoryInfo { + + // Docs: http://electron.atom.io/docs/api/structures/memory-info + + /** + * The maximum amount of memory that has ever been pinned to actual physical RAM. + * On macOS its value will always be 0. + */ + peakWorkingSetSize: number; + /** + * Process id of the process. + */ + pid: number; + /** + * The amount of memory not shared by other processes, such as JS heap or HTML + * content. + */ + privateBytes: number; + /** + * The amount of memory shared between processes, typically memory consumed by the + * Electron code itself + */ + sharedBytes: number; + /** + * The amount of memory currently pinned to actual physical RAM. + */ + workingSetSize: number; + } + + interface MemoryUsageDetails { + + // Docs: http://electron.atom.io/docs/api/structures/memory-usage-details + + count: number; + liveSize: number; + size: number; + } + + class Menu { + + // Docs: http://electron.atom.io/docs/api/menu + + constructor(); + /** + * Generally, the template is just an array of options for constructing a MenuItem. + * The usage can be referenced above. You can also attach other fields to the + * element of the template and they will become properties of the constructed menu + * items. + */ + static buildFromTemplate(template: MenuItemConstructorOptions[]): Menu; + /** + * Note: The returned Menu instance doesn't support dynamic addition or removal of + * menu items. Instance properties can still be dynamically modified. + */ + static getApplicationMenu(): Menu; + /** + * Sends the action to the first responder of application. This is used for + * emulating default macOS menu behaviors. Usually you would just use the role + * property of a MenuItem. See the macOS Cocoa Event Handling Guide for more + * information on macOS' native actions. + */ + static sendActionToFirstResponder(action: string): void; + /** + * Sets menu as the application menu on macOS. On Windows and Linux, the menu will + * be set as each window's top menu. Passing null will remove the menu bar on + * Windows and Linux but has no effect on macOS. Note: This API has to be called + * after the ready event of app module. + */ + static setApplicationMenu(menu: Menu): void; + /** + * Appends the menuItem to the menu. + */ + append(menuItem: MenuItem): void; + /** + * Closes the context menu in the browserWindow. + */ + closePopup(browserWindow?: BrowserWindow): void; + /** + * Inserts the menuItem to the pos position of the menu. + */ + insert(pos: number, menuItem: MenuItem): void; + /** + * Pops up this menu as a context menu in the browserWindow. + */ + popup(browserWindow?: BrowserWindow, options?: PopupOptions): void; + items: MenuItem[]; + } + + class MenuItem { + + // Docs: http://electron.atom.io/docs/api/menu-item + + constructor(options: MenuItemConstructorOptions); + checked: boolean; + click: Function; + enabled: boolean; + label: string; + visible: boolean; + } + + interface MimeTypedBuffer { + + // Docs: http://electron.atom.io/docs/api/structures/mime-typed-buffer + + /** + * The actual Buffer content + */ + data: Buffer; + /** + * The mimeType of the Buffer that you are sending + */ + mimeType: string; + } + + class NativeImage { + + // Docs: http://electron.atom.io/docs/api/native-image + + /** + * Creates an empty NativeImage instance. + */ + static createEmpty(): NativeImage; + /** + * Creates a new NativeImage instance from buffer. + */ + static createFromBuffer(buffer: Buffer, options?: CreateFromBufferOptions): NativeImage; + /** + * Creates a new NativeImage instance from dataURL. + */ + static createFromDataURL(dataURL: string): NativeImage; + /** + * Creates a new NativeImage instance from a file located at path. This method + * returns an empty image if the path does not exist, cannot be read, or is not a + * valid image. + */ + static createFromPath(path: string): NativeImage; + /** + * Add an image representation for a specific scale factor. This can be used to + * explicitly add different scale factor representations to an image. This can be + * called on empty images. + */ + addRepresentation(options: AddRepresentationOptions): void; + crop(rect: Rectangle): NativeImage; + getAspectRatio(): number; + /** + * The difference between getBitmap() and toBitmap() is, getBitmap() does not copy + * the bitmap data, so you have to use the returned Buffer immediately in current + * event loop tick, otherwise the data might be changed or destroyed. + */ + getBitmap(options?: BitmapOptions): Buffer; + /** + * Notice that the returned pointer is a weak pointer to the underlying native + * image instead of a copy, so you must ensure that the associated nativeImage + * instance is kept around. + */ + getNativeHandle(): Buffer; + getSize(): Size; + isEmpty(): boolean; + isTemplateImage(): boolean; + /** + * If only the height or the width are specified then the current aspect ratio will + * be preserved in the resized image. + */ + resize(options: ResizeOptions): NativeImage; + /** + * Marks the image as a template image. + */ + setTemplateImage(option: boolean): void; + toBitmap(options?: ToBitmapOptions): Buffer; + toDataURL(options?: ToDataURLOptions): string; + toJPEG(quality: number): Buffer; + toPNG(options?: ToPNGOptions): Buffer; + } + + interface Net extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/net + + /** + * Creates a ClientRequest instance using the provided options which are directly + * forwarded to the ClientRequest constructor. The net.request method would be used + * to issue both secure and insecure HTTP requests according to the specified + * protocol scheme in the options object. + */ + request(options: any | string): ClientRequest; + } + + class Notification extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/notification + + on(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated + */ + index: number) => void): this; + once(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated + */ + index: number) => void): this; + addListener(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated + */ + index: number) => void): this; + removeListener(event: 'action', listener: (event: Event, + /** + * The index of the action that was activated + */ + index: number) => void): this; + /** + * Emitted when the notification is clicked by the user. + */ + on(event: 'click', listener: (event: Event) => void): this; + once(event: 'click', listener: (event: Event) => void): this; + addListener(event: 'click', listener: (event: Event) => void): this; + removeListener(event: 'click', listener: (event: Event) => void): this; + /** + * Emitted when the notification is closed by manual intervention from the user. + * This event is not guarunteed to be emitted in all cases where the notification + * is closed. + */ + on(event: 'close', listener: (event: Event) => void): this; + once(event: 'close', listener: (event: Event) => void): this; + addListener(event: 'close', listener: (event: Event) => void): this; + removeListener(event: 'close', listener: (event: Event) => void): this; + /** + * Emitted when the user clicks the "Reply" button on a notification with hasReply: + * true. + */ + on(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field + */ + reply: string) => void): this; + once(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field + */ + reply: string) => void): this; + addListener(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field + */ + reply: string) => void): this; + removeListener(event: 'reply', listener: (event: Event, + /** + * The string the user entered into the inline reply field + */ + reply: string) => void): this; + /** + * Emitted when the notification is shown to the user, note this could be fired + * multiple times as a notification can be shown multiple times through the show() + * method. + */ + on(event: 'show', listener: (event: Event) => void): this; + once(event: 'show', listener: (event: Event) => void): this; + addListener(event: 'show', listener: (event: Event) => void): this; + removeListener(event: 'show', listener: (event: Event) => void): this; + constructor(options: NotificationConstructorOptions); + static isSupported(): boolean; + /** + * Immediately shows the notification to the user, please note this means unlike + * the HTML5 Notification implementation, simply instantiating a new Notification + * does not immediately show it to the user, you need to call this method before + * the OS will display it. + */ + show(): void; + } + + interface NotificationAction { + + // Docs: http://electron.atom.io/docs/api/structures/notification-action + + /** + * The label for the given action. + */ + text?: string; + /** + * The type of action, can be button. + */ + type: ('button'); + } + + interface Point { + + // Docs: http://electron.atom.io/docs/api/structures/point + + x: number; + y: number; + } + + interface PowerMonitor extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/power-monitor + + /** + * Emitted when the system changes to AC power. + */ + on(event: 'on-ac', listener: Function): this; + once(event: 'on-ac', listener: Function): this; + addListener(event: 'on-ac', listener: Function): this; + removeListener(event: 'on-ac', listener: Function): this; + /** + * Emitted when system changes to battery power. + */ + on(event: 'on-battery', listener: Function): this; + once(event: 'on-battery', listener: Function): this; + addListener(event: 'on-battery', listener: Function): this; + removeListener(event: 'on-battery', listener: Function): this; + /** + * Emitted when system is resuming. + */ + on(event: 'resume', listener: Function): this; + once(event: 'resume', listener: Function): this; + addListener(event: 'resume', listener: Function): this; + removeListener(event: 'resume', listener: Function): this; + /** + * Emitted when the system is suspending. + */ + on(event: 'suspend', listener: Function): this; + once(event: 'suspend', listener: Function): this; + addListener(event: 'suspend', listener: Function): this; + removeListener(event: 'suspend', listener: Function): this; + } + + interface PowerSaveBlocker extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/power-save-blocker + + isStarted(id: number): boolean; + /** + * Starts preventing the system from entering lower-power mode. Returns an integer + * identifying the power save blocker. Note: prevent-display-sleep has higher + * precedence over prevent-app-suspension. Only the highest precedence type takes + * effect. In other words, prevent-display-sleep always takes precedence over + * prevent-app-suspension. For example, an API calling A requests for + * prevent-app-suspension, and another calling B requests for + * prevent-display-sleep. prevent-display-sleep will be used until B stops its + * request. After that, prevent-app-suspension is used. + */ + start(type: 'prevent-app-suspension' | 'prevent-display-sleep'): number; + /** + * Stops the specified power save blocker. + */ + stop(id: number): void; + } + + interface PrinterInfo { + + // Docs: http://electron.atom.io/docs/api/structures/printer-info + + description: string; + isDefault: boolean; + name: string; + status: number; + } + + interface ProcessMetric { + + // Docs: http://electron.atom.io/docs/api/structures/process-metric + + /** + * CPU usage of the process. + */ + cpu: CPUUsage; + /** + * Memory information for the process. + */ + memory: MemoryInfo; + /** + * Process id of the process. + */ + pid: number; + /** + * Process type (Browser or Tab or GPU etc). + */ + type: string; + } + + interface Protocol extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/protocol + + /** + * Intercepts scheme protocol and uses handler as the protocol's new handler which + * sends a Buffer as a response. + */ + interceptBufferProtocol(scheme: string, handler: (request: InterceptBufferProtocolRequest, callback: (buffer?: Buffer) => void) => void, completion?: (error: Error) => void): void; + /** + * Intercepts scheme protocol and uses handler as the protocol's new handler which + * sends a file as a response. + */ + interceptFileProtocol(scheme: string, handler: (request: InterceptFileProtocolRequest, callback: (filePath: string) => void) => void, completion?: (error: Error) => void): void; + /** + * Intercepts scheme protocol and uses handler as the protocol's new handler which + * sends a new HTTP request as a response. + */ + interceptHttpProtocol(scheme: string, handler: (request: InterceptHttpProtocolRequest, callback: (redirectRequest: RedirectRequest) => void) => void, completion?: (error: Error) => void): void; + /** + * Intercepts scheme protocol and uses handler as the protocol's new handler which + * sends a String as a response. + */ + interceptStringProtocol(scheme: string, handler: (request: InterceptStringProtocolRequest, callback: (data?: string) => void) => void, completion?: (error: Error) => void): void; + /** + * The callback will be called with a boolean that indicates whether there is + * already a handler for scheme. + */ + isProtocolHandled(scheme: string, callback: (error: Error) => void): void; + /** + * Registers a protocol of scheme that will send a Buffer as a response. The usage + * is the same with registerFileProtocol, except that the callback should be called + * with either a Buffer object or an object that has the data, mimeType, and + * charset properties. Example: + */ + registerBufferProtocol(scheme: string, handler: (request: RegisterBufferProtocolRequest, callback: (buffer?: Buffer | MimeTypedBuffer) => void) => void, completion?: (error: Error) => void): void; + /** + * Registers a protocol of scheme that will send the file as a response. The + * handler will be called with handler(request, callback) when a request is going + * to be created with scheme. completion will be called with completion(null) when + * scheme is successfully registered or completion(error) when failed. To handle + * the request, the callback should be called with either the file's path or an + * object that has a path property, e.g. callback(filePath) or callback({path: + * filePath}). When callback is called with nothing, a number, or an object that + * has an error property, the request will fail with the error number you + * specified. For the available error numbers you can use, please see the net error + * list. By default the scheme is treated like http:, which is parsed differently + * than protocols that follow the "generic URI syntax" like file:, so you probably + * want to call protocol.registerStandardSchemes to have your scheme treated as a + * standard scheme. + */ + registerFileProtocol(scheme: string, handler: (request: RegisterFileProtocolRequest, callback: (filePath?: string) => void) => void, completion?: (error: Error) => void): void; + /** + * Registers a protocol of scheme that will send an HTTP request as a response. The + * usage is the same with registerFileProtocol, except that the callback should be + * called with a redirectRequest object that has the url, method, referrer, + * uploadData and session properties. By default the HTTP request will reuse the + * current session. If you want the request to have a different session you should + * set session to null. For POST requests the uploadData object must be provided. + */ + registerHttpProtocol(scheme: string, handler: (request: RegisterHttpProtocolRequest, callback: (redirectRequest: RedirectRequest) => void) => void, completion?: (error: Error) => void): void; + registerServiceWorkerSchemes(schemes: string[]): void; + /** + * A standard scheme adheres to what RFC 3986 calls generic URI syntax. For example + * http and https are standard schemes, while file is not. Registering a scheme as + * standard, will allow relative and absolute resources to be resolved correctly + * when served. Otherwise the scheme will behave like the file protocol, but + * without the ability to resolve relative URLs. For example when you load + * following page with custom protocol without registering it as standard scheme, + * the image will not be loaded because non-standard schemes can not recognize + * relative URLs: Registering a scheme as standard will allow access to files + * through the FileSystem API. Otherwise the renderer will throw a security error + * for the scheme. By default web storage apis (localStorage, sessionStorage, + * webSQL, indexedDB, cookies) are disabled for non standard schemes. So in general + * if you want to register a custom protocol to replace the http protocol, you have + * to register it as a standard scheme: Note: This method can only be used before + * the ready event of the app module gets emitted. + */ + registerStandardSchemes(schemes: string[], options?: RegisterStandardSchemesOptions): void; + /** + * Registers a protocol of scheme that will send a String as a response. The usage + * is the same with registerFileProtocol, except that the callback should be called + * with either a String or an object that has the data, mimeType, and charset + * properties. + */ + registerStringProtocol(scheme: string, handler: (request: RegisterStringProtocolRequest, callback: (data?: string) => void) => void, completion?: (error: Error) => void): void; + /** + * Remove the interceptor installed for scheme and restore its original handler. + */ + uninterceptProtocol(scheme: string, completion?: (error: Error) => void): void; + /** + * Unregisters the custom protocol of scheme. + */ + unregisterProtocol(scheme: string, completion?: (error: Error) => void): void; + } + + interface Rectangle { + + // Docs: http://electron.atom.io/docs/api/structures/rectangle + + /** + * The height of the rectangle (must be an integer) + */ + height: number; + /** + * The width of the rectangle (must be an integer) + */ + width: number; + /** + * The x coordinate of the origin of the rectangle (must be an integer) + */ + x: number; + /** + * The y coordinate of the origin of the rectangle (must be an integer) + */ + y: number; + } + + interface Remote extends MainInterface { + + // Docs: http://electron.atom.io/docs/api/remote + + getCurrentWebContents(): WebContents; + getCurrentWindow(): BrowserWindow; + getGlobal(name: string): any; + /** + * e.g. + */ + require(module: string): any; + /** + * The process object in the main process. This is the same as + * remote.getGlobal('process') but is cached. + */ + process?: any; + } + + interface RemoveClientCertificate { + + // Docs: http://electron.atom.io/docs/api/structures/remove-client-certificate + + /** + * Origin of the server whose associated client certificate must be removed from + * the cache. + */ + origin: string; + /** + * clientCertificate. + */ + type: string; + } + + interface RemovePassword { + + // Docs: http://electron.atom.io/docs/api/structures/remove-password + + /** + * When provided, the authentication info related to the origin will only be + * removed otherwise the entire cache will be cleared. + */ + origin?: string; + /** + * Credentials of the authentication. Must be provided if removing by origin. + */ + password?: string; + /** + * Realm of the authentication. Must be provided if removing by origin. + */ + realm?: string; + /** + * Scheme of the authentication. Can be basic, digest, ntlm, negotiate. Must be + * provided if removing by origin. + */ + scheme?: ('basic' | 'digest' | 'ntlm' | 'negotiate'); + /** + * password. + */ + type: string; + /** + * Credentials of the authentication. Must be provided if removing by origin. + */ + username?: string; + } + + interface Screen extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/screen + + /** + * Emitted when newDisplay has been added. + */ + on(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + once(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + addListener(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + removeListener(event: 'display-added', listener: (event: Event, + newDisplay: Display) => void): this; + /** + * Emitted when one or more metrics change in a display. The changedMetrics is an + * array of strings that describe the changes. Possible changes are bounds, + * workArea, scaleFactor and rotation. + */ + on(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + once(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + addListener(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + removeListener(event: 'display-metrics-changed', listener: (event: Event, + display: Display, + changedMetrics: string[]) => void): this; + /** + * Emitted when oldDisplay has been removed. + */ + on(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + once(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + addListener(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + removeListener(event: 'display-removed', listener: (event: Event, + oldDisplay: Display) => void): this; + getAllDisplays(): Display[]; + /** + * The current absolute position of the mouse pointer. + */ + getCursorScreenPoint(): Point; + getDisplayMatching(rect: Rectangle): Display; + getDisplayNearestPoint(point: Point): Display; + getMenuBarHeight(): number; + getPrimaryDisplay(): Display; + } + + interface ScrubberItem { + + // Docs: http://electron.atom.io/docs/api/structures/scrubber-item + + /** + * The image to appear in this item + */ + icon?: NativeImage; + /** + * The text to appear in this item + */ + label?: string; + } + + interface SegmentedControlSegment { + + // Docs: http://electron.atom.io/docs/api/structures/segmented-control-segment + + /** + * Whether this segment is selectable. Default: true + */ + enabled?: boolean; + /** + * The image to appear in this segment + */ + icon?: NativeImage; + /** + * The text to appear in this segment + */ + label?: string; + } + + class Session extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/session + + /** + * If partition starts with persist:, the page will use a persistent session + * available to all pages in the app with the same partition. if there is no + * persist: prefix, the page will use an in-memory session. If the partition is + * empty then default session of the app will be returned. To create a Session with + * options, you have to ensure the Session with the partition has never been used + * before. There is no way to change the options of an existing Session object. + */ + static fromPartition(partition: string, options: FromPartitionOptions): Session; + /** + * A Session object, the default session object of the app. + */ + static defaultSession?: Session; + /** + * Emitted when Electron is about to download item in webContents. Calling + * event.preventDefault() will cancel the download and item will not be available + * from next tick of the process. + */ + on(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + once(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + addListener(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + removeListener(event: 'will-download', listener: (event: Event, + item: DownloadItem, + webContents: WebContents) => void): this; + /** + * Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate + * authentication. + */ + allowNTLMCredentialsForDomains(domains: string): void; + /** + * Clears the session’s HTTP authentication cache. + */ + clearAuthCache(options: RemovePassword | RemoveClientCertificate, callback?: Function): void; + /** + * Clears the session’s HTTP cache. + */ + clearCache(callback: Function): void; + /** + * Clears the host resolver cache. + */ + clearHostResolverCache(callback?: Function): void; + /** + * Clears the data of web storages. + */ + clearStorageData(options?: ClearStorageDataOptions, callback?: Function): void; + /** + * Allows resuming cancelled or interrupted downloads from previous Session. The + * API will generate a DownloadItem that can be accessed with the will-download + * event. The DownloadItem will not have any WebContents associated with it and the + * initial state will be interrupted. The download will start only when the resume + * API is called on the DownloadItem. + */ + createInterruptedDownload(options: CreateInterruptedDownloadOptions): void; + /** + * Disables any network emulation already active for the session. Resets to the + * original network configuration. + */ + disableNetworkEmulation(): void; + /** + * Emulates network with the given configuration for the session. + */ + enableNetworkEmulation(options: EnableNetworkEmulationOptions): void; + /** + * Writes any unwritten DOMStorage data to disk. + */ + flushStorageData(): void; + getBlobData(identifier: string, callback: (result: Buffer) => void): Blob; + /** + * Callback is invoked with the session's current cache size. + */ + getCacheSize(callback: (size: number) => void): void; + getUserAgent(): string; + /** + * Resolves the proxy information for url. The callback will be called with + * callback(proxy) when the request is performed. + */ + resolveProxy(url: string, callback: (proxy: string) => void): void; + /** + * Sets the certificate verify proc for session, the proc will be called with + * proc(request, callback) whenever a server certificate verification is requested. + * Calling callback(0) accepts the certificate, calling callback(-2) rejects it. + * Calling setCertificateVerifyProc(null) will revert back to default certificate + * verify proc. + */ + setCertificateVerifyProc(proc: (request: CertificateVerifyProcRequest, callback: (verificationResult: number) => void) => void): void; + /** + * Sets download saving directory. By default, the download directory will be the + * Downloads under the respective app folder. + */ + setDownloadPath(path: string): void; + /** + * Sets the handler which can be used to respond to permission requests for the + * session. Calling callback(true) will allow the permission and callback(false) + * will reject it. + */ + setPermissionRequestHandler(handler: (webContents: WebContents, permission: string, callback: (permissionGranted: boolean) => void) => void): void; + /** + * Sets the proxy settings. When pacScript and proxyRules are provided together, + * the proxyRules option is ignored and pacScript configuration is applied. The + * proxyRules has to follow the rules below: For example: The proxyBypassRules is a + * comma separated list of rules described below: + */ + setProxy(config: Config, callback: Function): void; + /** + * Overrides the userAgent and acceptLanguages for this session. The + * acceptLanguages must a comma separated ordered list of language codes, for + * example "en-US,fr,de,ko,zh-CN,ja". This doesn't affect existing WebContents, and + * each WebContents can use webContents.setUserAgent to override the session-wide + * user agent. + */ + setUserAgent(userAgent: string, acceptLanguages?: string): void; + cookies: Cookies; + protocol: Protocol; + webRequest: WebRequest; + } + + interface Shell { + + // Docs: http://electron.atom.io/docs/api/shell + + /** + * Play the beep sound. + */ + beep(): void; + /** + * Move the given file to trash and returns a boolean status for the operation. + */ + moveItemToTrash(fullPath: string): boolean; + /** + * Open the given external protocol URL in the desktop's default manner. (For + * example, mailto: URLs in the user's default mail agent). + */ + openExternal(url: string, options?: OpenExternalOptions, callback?: (error: Error) => void): boolean; + /** + * Open the given file in the desktop's default manner. + */ + openItem(fullPath: string): boolean; + /** + * Resolves the shortcut link at shortcutPath. An exception will be thrown when any + * error happens. + */ + readShortcutLink(shortcutPath: string): ShortcutDetails; + /** + * Show the given file in a file manager. If possible, select the file. + */ + showItemInFolder(fullPath: string): boolean; + /** + * Creates or updates a shortcut link at shortcutPath. + */ + writeShortcutLink(shortcutPath: string, operation: 'create' | 'update' | 'replace', options: ShortcutDetails): boolean; + /** + * Creates or updates a shortcut link at shortcutPath. + */ + writeShortcutLink(shortcutPath: string, options: ShortcutDetails): boolean; + } + + interface ShortcutDetails { + + // Docs: http://electron.atom.io/docs/api/structures/shortcut-details + + /** + * The Application User Model ID. Default is empty. + */ + appUserModelId?: string; + /** + * The arguments to be applied to target when launching from this shortcut. Default + * is empty. + */ + args?: string; + /** + * The working directory. Default is empty. + */ + cwd?: string; + /** + * The description of the shortcut. Default is empty. */ description?: string; /** - * The absolute path to an icon to be displayed in a Jump List, which can be an arbitrary - * resource file that contains an icon (e.g. .ico, .exe, .dll). - * You can usually specify process.execPath to show the program icon. + * The path to the icon, can be a DLL or EXE. icon and iconIndex have to be set + * together. Default is empty, which uses the target's icon. */ - iconPath?: string; + icon?: string; /** - * The index of the icon in the resource file. If a resource file contains multiple icons - * this value can be used to specify the zero-based index of the icon that should be displayed - * for this task. If a resource file contains only one icon, this property should be set to zero. + * The resource ID of icon when icon is a DLL or EXE. Default is 0. */ iconIndex?: number; + /** + * The target to launch from this shortcut. + */ + target: string; } - interface LoginItemSettings { - /** - * True if the app is set to open at login. - */ - openAtLogin: boolean; - /** - * True if the app is set to open as hidden at login. This setting is only supported on macOS. - */ - openAsHidden: boolean; - /** - * True if the app was opened at login automatically. This setting is only supported on macOS. - */ - wasOpenedAtLogin?: boolean; - /** - * True if the app was opened as a hidden login item. This indicates that the app should not - * open any windows at startup. This setting is only supported on macOS. - */ - wasOpenedAsHidden?: boolean; - /** - * True if the app was opened as a login item that should restore the state from the previous session. - * This indicates that the app should restore the windows that were open the last time the app was closed. - * This setting is only supported on macOS. - */ - restoreState?: boolean; + interface Size { + + // Docs: http://electron.atom.io/docs/api/structures/size + + height: number; + width: number; } - interface AboutPanelOptions { + interface SystemPreferences extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/system-preferences + + on(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + once(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + addListener(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + removeListener(event: 'accent-color-changed', listener: (event: Event, + /** + * The new RGBA color the user assigned to be their system accent color. + */ + newColor: string) => void): this; + on(event: 'color-changed', listener: (event: Event) => void): this; + once(event: 'color-changed', listener: (event: Event) => void): this; + addListener(event: 'color-changed', listener: (event: Event) => void): this; + removeListener(event: 'color-changed', listener: (event: Event) => void): this; + on(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + once(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + addListener(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + removeListener(event: 'inverted-color-scheme-changed', listener: (event: Event, + /** + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. + */ + invertedColorScheme: boolean) => void): this; + getAccentColor(): string; + getColor(color: '3d-dark-shadow' | '3d-face' | '3d-highlight' | '3d-light' | '3d-shadow' | 'active-border' | 'active-caption' | 'active-caption-gradient' | 'app-workspace' | 'button-text' | 'caption-text' | 'desktop' | 'disabled-text' | 'highlight' | 'highlight-text' | 'hotlight' | 'inactive-border' | 'inactive-caption' | 'inactive-caption-gradient' | 'inactive-caption-text' | 'info-background' | 'info-text' | 'menu' | 'menu-highlight' | 'menubar' | 'menu-text' | 'scrollbar' | 'window' | 'window-frame' | 'window-text'): string; + /** + * This API uses NSUserDefaults on macOS. Some popular key and types are: + */ + getUserDefault(key: string, type: 'string' | 'boolean' | 'integer' | 'float' | 'double' | 'url' | 'array' | 'dictionary'): any; + /** + * An example of using it to determine if you should create a transparent window or + * not (transparent windows won't work correctly when DWM composition is disabled): + */ + isAeroGlassEnabled(): boolean; + isDarkMode(): boolean; + isInvertedColorScheme(): boolean; + isSwipeTrackingFromScrollEventsEnabled(): boolean; + /** + * Posts event as native notifications of macOS. The userInfo is an Object that + * contains the user information dictionary sent along with the notification. + */ + postLocalNotification(event: string, userInfo: any): void; + /** + * Posts event as native notifications of macOS. The userInfo is an Object that + * contains the user information dictionary sent along with the notification. + */ + postNotification(event: string, userInfo: any): void; + /** + * Set the value of key in system preferences. Note that type should match actual + * type of value. An exception is thrown if they don't. This API uses + * NSUserDefaults on macOS. Some popular key and types are: + */ + setUserDefault(key: string, type: string, value: string): void; + /** + * Same as subscribeNotification, but uses NSNotificationCenter for local defaults. + * This is necessary for events such as NSUserDefaultsDidChangeNotification + */ + subscribeLocalNotification(event: string, callback: (event: string, userInfo: any) => void): void; + /** + * Subscribes to native notifications of macOS, callback will be called with + * callback(event, userInfo) when the corresponding event happens. The userInfo is + * an Object that contains the user information dictionary sent along with the + * notification. The id of the subscriber is returned, which can be used to + * unsubscribe the event. Under the hood this API subscribes to + * NSDistributedNotificationCenter, example values of event are: + */ + subscribeNotification(event: string, callback: (event: string, userInfo: any) => void): void; + /** + * Same as unsubscribeNotification, but removes the subscriber from + * NSNotificationCenter. + */ + unsubscribeLocalNotification(id: number): void; + /** + * Removes the subscriber with id. + */ + unsubscribeNotification(id: number): void; + } + + interface Task { + + // Docs: http://electron.atom.io/docs/api/structures/task + + /** + * The command line arguments when program is executed. + */ + arguments: string; + /** + * Description of this task. + */ + description: string; + /** + * The icon index in the icon file. If an icon file consists of two or more icons, + * set this value to identify the icon. If an icon file consists of one icon, this + * value is 0. + */ + iconIndex: number; + /** + * The absolute path to an icon to be displayed in a JumpList, which can be an + * arbitrary resource file that contains an icon. You can usually specify + * process.execPath to show the icon of the program. + */ + iconPath: string; + /** + * Path of the program to execute, usually you should specify process.execPath + * which opens the current program. + */ + program: string; + /** + * The string to be displayed in a JumpList. + */ + title: string; + } + + interface ThumbarButton { + + // Docs: http://electron.atom.io/docs/api/structures/thumbar-button + + click: Function; + /** + * Control specific states and behaviors of the button. By default, it is + * ['enabled']. + */ + flags?: string[]; + /** + * The icon showing in thumbnail toolbar. + */ + icon: NativeImage; + /** + * The text of the button's tooltip. + */ + tooltip?: string; + } + + class TouchBarButton extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-button + + constructor(options: TouchBarButtonConstructorOptions); + backgroundColor: string; + icon: NativeImage; + label: string; + } + + class TouchBarColorPicker extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-color-picker + + constructor(options: TouchBarColorPickerConstructorOptions); + availableColors: string[]; + selectedColor: string; + } + + class TouchBarGroup extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-group + + constructor(options: TouchBarGroupConstructorOptions); + } + + class TouchBarLabel extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-label + + constructor(options: TouchBarLabelConstructorOptions); + label: string; + textColor: string; + } + + class TouchBarPopover extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-popover + + constructor(options: TouchBarPopoverConstructorOptions); + icon: NativeImage; + label: string; + } + + class TouchBarScrubber extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-scrubber + + constructor(options: TouchBarScrubberConstructorOptions); + continuous: boolean; + items: ScrubberItem[]; + mode: string; + overlayStyle: string; + selectedStyle: string; + showArrowButtons: boolean; + } + + class TouchBarSegmentedControl extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-segmented-control + + constructor(options: TouchBarSegmentedControlConstructorOptions); + segments: SegmentedControlSegment[]; + segmentStyle: string; + selectedIndex: number; + } + + class TouchBarSlider extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-slider + + constructor(options: TouchBarSliderConstructorOptions); + label: string; + maxValue: number; + minValue: number; + value: number; + } + + class TouchBarSpacer extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar-spacer + + constructor(options: TouchBarSpacerConstructorOptions); + } + + class TouchBar extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/touch-bar + + constructor(options: TouchBarConstructorOptions); + escapeItem: any; + static TouchBarButton: typeof TouchBarButton; + static TouchBarColorPicker: typeof TouchBarColorPicker; + static TouchBarGroup: typeof TouchBarGroup; + static TouchBarLabel: typeof TouchBarLabel; + static TouchBarPopover: typeof TouchBarPopover; + static TouchBarScrubber: typeof TouchBarScrubber; + static TouchBarSegmentedControl: typeof TouchBarSegmentedControl; + static TouchBarSlider: typeof TouchBarSlider; + static TouchBarSpacer: typeof TouchBarSpacer; + } + + class Tray extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/tray + + /** + * Emitted when the tray balloon is clicked. + */ + on(event: 'balloon-click', listener: Function): this; + once(event: 'balloon-click', listener: Function): this; + addListener(event: 'balloon-click', listener: Function): this; + removeListener(event: 'balloon-click', listener: Function): this; + /** + * Emitted when the tray balloon is closed because of timeout or user manually + * closes it. + */ + on(event: 'balloon-closed', listener: Function): this; + once(event: 'balloon-closed', listener: Function): this; + addListener(event: 'balloon-closed', listener: Function): this; + removeListener(event: 'balloon-closed', listener: Function): this; + /** + * Emitted when the tray balloon shows. + */ + on(event: 'balloon-show', listener: Function): this; + once(event: 'balloon-show', listener: Function): this; + addListener(event: 'balloon-show', listener: Function): this; + removeListener(event: 'balloon-show', listener: Function): this; + /** + * Emitted when the tray icon is clicked. + */ + on(event: 'click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + once(event: 'click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + addListener(event: 'click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + removeListener(event: 'click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + /** + * Emitted when the tray icon is double clicked. + */ + on(event: 'double-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + once(event: 'double-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + addListener(event: 'double-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + removeListener(event: 'double-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + /** + * Emitted when a drag operation ends on the tray or ends at another location. + */ + on(event: 'drag-end', listener: Function): this; + once(event: 'drag-end', listener: Function): this; + addListener(event: 'drag-end', listener: Function): this; + removeListener(event: 'drag-end', listener: Function): this; + /** + * Emitted when a drag operation enters the tray icon. + */ + on(event: 'drag-enter', listener: Function): this; + once(event: 'drag-enter', listener: Function): this; + addListener(event: 'drag-enter', listener: Function): this; + removeListener(event: 'drag-enter', listener: Function): this; + /** + * Emitted when a drag operation exits the tray icon. + */ + on(event: 'drag-leave', listener: Function): this; + once(event: 'drag-leave', listener: Function): this; + addListener(event: 'drag-leave', listener: Function): this; + removeListener(event: 'drag-leave', listener: Function): this; + /** + * Emitted when any dragged items are dropped on the tray icon. + */ + on(event: 'drop', listener: Function): this; + once(event: 'drop', listener: Function): this; + addListener(event: 'drop', listener: Function): this; + removeListener(event: 'drop', listener: Function): this; + /** + * Emitted when dragged files are dropped in the tray icon. + */ + on(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + once(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + addListener(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + removeListener(event: 'drop-files', listener: (event: Event, + /** + * The paths of the dropped files. + */ + files: string[]) => void): this; + /** + * Emitted when dragged text is dropped in the tray icon. + */ + on(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string + */ + text: string) => void): this; + once(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string + */ + text: string) => void): this; + addListener(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string + */ + text: string) => void): this; + removeListener(event: 'drop-text', listener: (event: Event, + /** + * the dropped text string + */ + text: string) => void): this; + /** + * Emitted when the mouse enters the tray icon. + */ + on(event: 'mouse-enter', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + once(event: 'mouse-enter', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + addListener(event: 'mouse-enter', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + removeListener(event: 'mouse-enter', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + /** + * Emitted when the mouse exits the tray icon. + */ + on(event: 'mouse-leave', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + once(event: 'mouse-leave', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + addListener(event: 'mouse-leave', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + removeListener(event: 'mouse-leave', listener: (event: Event, + /** + * The position of the event + */ + position: Point) => void): this; + /** + * Emitted when the tray icon is right clicked. + */ + on(event: 'right-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + once(event: 'right-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + addListener(event: 'right-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + removeListener(event: 'right-click', listener: (event: Event, + /** + * The bounds of tray icon + */ + bounds: Rectangle) => void): this; + constructor(image: NativeImage | string); + /** + * Destroys the tray icon immediately. + */ + destroy(): void; + /** + * Displays a tray balloon. + */ + displayBalloon(options: DisplayBalloonOptions): void; + /** + * The bounds of this tray icon as Object. + */ + getBounds(): Rectangle; + isDestroyed(): boolean; + /** + * Pops up the context menu of the tray icon. When menu is passed, the menu will be + * shown instead of the tray icon's context menu. The position is only available on + * Windows, and it is (0, 0) by default. + */ + popUpContextMenu(menu?: Menu, position?: Point): void; + /** + * Sets the context menu for this icon. + */ + setContextMenu(menu: Menu): void; + /** + * Sets when the tray's icon background becomes highlighted (in blue). Note: You + * can use highlightMode with a BrowserWindow by toggling between 'never' and + * 'always' modes when the window visibility changes. + */ + setHighlightMode(mode: 'selection' | 'always' | 'never'): void; + /** + * Sets the image associated with this tray icon. + */ + setImage(image: NativeImage | string): void; + /** + * Sets the image associated with this tray icon when pressed on macOS. + */ + setPressedImage(image: NativeImage): void; + /** + * Sets the title displayed aside of the tray icon in the status bar. + */ + setTitle(title: string): void; + /** + * Sets the hover text for this tray icon. + */ + setToolTip(toolTip: string): void; + } + + interface UploadBlob { + + // Docs: http://electron.atom.io/docs/api/structures/upload-blob + + /** + * UUID of blob data to upload. + */ + blobUUID: string; + /** + * blob. + */ + type: string; + } + + interface UploadData { + + // Docs: http://electron.atom.io/docs/api/structures/upload-data + + /** + * UUID of blob data. Use method to retrieve the data. + */ + blobUUID: string; + /** + * Content being sent. + */ + bytes: Buffer; + /** + * Path of file being uploaded. + */ + file: string; + } + + interface UploadFile { + + // Docs: http://electron.atom.io/docs/api/structures/upload-file + + /** + * Path of file to be uploaded. + */ + filePath: string; + /** + * Number of bytes to read from offset. Defaults to 0. + */ + length: number; + /** + * Last Modification time in number of seconds sine the UNIX epoch. + */ + modificationTime: number; + /** + * Defaults to 0. + */ + offset: number; + /** + * file. + */ + type: string; + } + + interface UploadFileSystem { + + // Docs: http://electron.atom.io/docs/api/structures/upload-file-system + + /** + * FileSystem url to read data for upload. + */ + filsSystemURL: string; + /** + * Number of bytes to read from offset. Defaults to 0. + */ + length: number; + /** + * Last Modification time in number of seconds sine the UNIX epoch. + */ + modificationTime: number; + /** + * Defaults to 0. + */ + offset: number; + /** + * fileSystem. + */ + type: string; + } + + interface UploadRawData { + + // Docs: http://electron.atom.io/docs/api/structures/upload-raw-data + + /** + * Data to be uploaded. + */ + bytes: Buffer; + /** + * rawData. + */ + type: string; + } + + class WebContents extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/web-contents + + static fromId(id: number): WebContents; + static getAllWebContents(): WebContents[]; + static getFocusedWebContents(): WebContents; + /** + * Emitted before dispatching the keydown and keyup events in the page. Calling + * event.preventDefault will prevent the page keydown/keyup events and the menu + * shortcuts. To only prevent the menu shortcuts, use setIgnoreMenuShortcuts: + */ + on(event: 'before-input-event', listener: (event: Event, + /** + * Input properties + */ + input: Input) => void): this; + once(event: 'before-input-event', listener: (event: Event, + /** + * Input properties + */ + input: Input) => void): this; + addListener(event: 'before-input-event', listener: (event: Event, + /** + * Input properties + */ + input: Input) => void): this; + removeListener(event: 'before-input-event', listener: (event: Event, + /** + * Input properties + */ + input: Input) => void): this; + /** + * Emitted when failed to verify the certificate for url. The usage is the same + * with the certificate-error event of app. + */ + on(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void) => void): this; + once(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void) => void): this; + addListener(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void) => void): this; + removeListener(event: 'certificate-error', listener: (event: Event, + url: string, + /** + * The error code + */ + error: string, + certificate: Certificate, + callback: (isTrusted: boolean) => void) => void): this; + /** + * Emitted when there is a new context menu that needs to be handled. + */ + on(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + once(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + addListener(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + removeListener(event: 'context-menu', listener: (event: Event, + params: ContextMenuParams) => void): this; + /** + * Emitted when the renderer process crashes or is killed. + */ + on(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + once(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + addListener(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + removeListener(event: 'crashed', listener: (event: Event, + killed: boolean) => void): this; + /** + * Emitted when the cursor's type changes. The type parameter can be default, + * crosshair, pointer, text, wait, help, e-resize, n-resize, ne-resize, nw-resize, + * s-resize, se-resize, sw-resize, w-resize, ns-resize, ew-resize, nesw-resize, + * nwse-resize, col-resize, row-resize, m-panning, e-panning, n-panning, + * ne-panning, nw-panning, s-panning, se-panning, sw-panning, w-panning, move, + * vertical-text, cell, context-menu, alias, progress, nodrop, copy, none, + * not-allowed, zoom-in, zoom-out, grab, grabbing, custom. If the type parameter is + * custom, the image parameter will hold the custom cursor image in a NativeImage, + * and scale, size and hotspot will hold additional information about the custom + * cursor. + */ + on(event: 'cursor-changed', listener: (event: Event, + type: string, + image?: NativeImage, + /** + * scaling factor for the custom cursor + */ + scale?: number, + /** + * the size of the `image` + */ + size?: Size, + /** + * coordinates of the custom cursor's hotspot + */ + hotspot?: Point) => void): this; + once(event: 'cursor-changed', listener: (event: Event, + type: string, + image?: NativeImage, + /** + * scaling factor for the custom cursor + */ + scale?: number, + /** + * the size of the `image` + */ + size?: Size, + /** + * coordinates of the custom cursor's hotspot + */ + hotspot?: Point) => void): this; + addListener(event: 'cursor-changed', listener: (event: Event, + type: string, + image?: NativeImage, + /** + * scaling factor for the custom cursor + */ + scale?: number, + /** + * the size of the `image` + */ + size?: Size, + /** + * coordinates of the custom cursor's hotspot + */ + hotspot?: Point) => void): this; + removeListener(event: 'cursor-changed', listener: (event: Event, + type: string, + image?: NativeImage, + /** + * scaling factor for the custom cursor + */ + scale?: number, + /** + * the size of the `image` + */ + size?: Size, + /** + * coordinates of the custom cursor's hotspot + */ + hotspot?: Point) => void): this; + /** + * Emitted when webContents is destroyed. + */ + on(event: 'destroyed', listener: Function): this; + once(event: 'destroyed', listener: Function): this; + addListener(event: 'destroyed', listener: Function): this; + removeListener(event: 'destroyed', listener: Function): this; + /** + * Emitted when DevTools is closed. + */ + on(event: 'devtools-closed', listener: Function): this; + once(event: 'devtools-closed', listener: Function): this; + addListener(event: 'devtools-closed', listener: Function): this; + removeListener(event: 'devtools-closed', listener: Function): this; + /** + * Emitted when DevTools is focused / opened. + */ + on(event: 'devtools-focused', listener: Function): this; + once(event: 'devtools-focused', listener: Function): this; + addListener(event: 'devtools-focused', listener: Function): this; + removeListener(event: 'devtools-focused', listener: Function): this; + /** + * Emitted when DevTools is opened. + */ + on(event: 'devtools-opened', listener: Function): this; + once(event: 'devtools-opened', listener: Function): this; + addListener(event: 'devtools-opened', listener: Function): this; + removeListener(event: 'devtools-opened', listener: Function): this; + /** + * Emitted when the devtools window instructs the webContents to reload + */ + on(event: 'devtools-reload-page', listener: Function): this; + once(event: 'devtools-reload-page', listener: Function): this; + addListener(event: 'devtools-reload-page', listener: Function): this; + removeListener(event: 'devtools-reload-page', listener: Function): this; + /** + * Emitted when a page's theme color changes. This is usually due to encountering a + * meta tag: + */ + on(event: 'did-change-theme-color', listener: Function): this; + once(event: 'did-change-theme-color', listener: Function): this; + addListener(event: 'did-change-theme-color', listener: Function): this; + removeListener(event: 'did-change-theme-color', listener: Function): this; + /** + * This event is like did-finish-load but emitted when the load failed or was + * cancelled, e.g. window.stop() is invoked. The full list of error codes and their + * meaning is available here. + */ + on(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean) => void): this; + once(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean) => void): this; + addListener(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean) => void): this; + removeListener(event: 'did-fail-load', listener: (event: Event, + errorCode: number, + errorDescription: string, + validatedURL: string, + isMainFrame: boolean) => void): this; + /** + * Emitted when the navigation is done, i.e. the spinner of the tab has stopped + * spinning, and the onload event was dispatched. + */ + on(event: 'did-finish-load', listener: Function): this; + once(event: 'did-finish-load', listener: Function): this; + addListener(event: 'did-finish-load', listener: Function): this; + removeListener(event: 'did-finish-load', listener: Function): this; + /** + * Emitted when a frame has done navigation. + */ + on(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean) => void): this; + once(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean) => void): this; + addListener(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean) => void): this; + removeListener(event: 'did-frame-finish-load', listener: (event: Event, + isMainFrame: boolean) => void): this; + /** + * Emitted when a redirect is received while requesting a resource. + */ + on(event: 'did-get-redirect-request', listener: (event: Event, + oldURL: string, + newURL: string, + isMainFrame: boolean, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any) => void): this; + once(event: 'did-get-redirect-request', listener: (event: Event, + oldURL: string, + newURL: string, + isMainFrame: boolean, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any) => void): this; + addListener(event: 'did-get-redirect-request', listener: (event: Event, + oldURL: string, + newURL: string, + isMainFrame: boolean, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any) => void): this; + removeListener(event: 'did-get-redirect-request', listener: (event: Event, + oldURL: string, + newURL: string, + isMainFrame: boolean, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any) => void): this; + /** + * Emitted when details regarding a requested resource are available. status + * indicates the socket connection to download the resource. + */ + on(event: 'did-get-response-details', listener: (event: Event, + status: boolean, + newURL: string, + originalURL: string, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any, + resourceType: string) => void): this; + once(event: 'did-get-response-details', listener: (event: Event, + status: boolean, + newURL: string, + originalURL: string, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any, + resourceType: string) => void): this; + addListener(event: 'did-get-response-details', listener: (event: Event, + status: boolean, + newURL: string, + originalURL: string, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any, + resourceType: string) => void): this; + removeListener(event: 'did-get-response-details', listener: (event: Event, + status: boolean, + newURL: string, + originalURL: string, + httpResponseCode: number, + requestMethod: string, + referrer: string, + headers: any, + resourceType: string) => void): this; + /** + * Emitted when a navigation is done. This event is not emitted for in-page + * navigations, such as clicking anchor links or updating the window.location.hash. + * Use did-navigate-in-page event for this purpose. + */ + on(event: 'did-navigate', listener: (event: Event, + url: string) => void): this; + once(event: 'did-navigate', listener: (event: Event, + url: string) => void): this; + addListener(event: 'did-navigate', listener: (event: Event, + url: string) => void): this; + removeListener(event: 'did-navigate', listener: (event: Event, + url: string) => void): this; + /** + * Emitted when an in-page navigation happened. When in-page navigation happens, + * the page URL changes but does not cause navigation outside of the page. Examples + * of this occurring are when anchor links are clicked or when the DOM hashchange + * event is triggered. + */ + on(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean) => void): this; + once(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean) => void): this; + addListener(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean) => void): this; + removeListener(event: 'did-navigate-in-page', listener: (event: Event, + url: string, + isMainFrame: boolean) => void): this; + /** + * Corresponds to the points in time when the spinner of the tab started spinning. + */ + on(event: 'did-start-loading', listener: Function): this; + once(event: 'did-start-loading', listener: Function): this; + addListener(event: 'did-start-loading', listener: Function): this; + removeListener(event: 'did-start-loading', listener: Function): this; + /** + * Corresponds to the points in time when the spinner of the tab stopped spinning. + */ + on(event: 'did-stop-loading', listener: Function): this; + once(event: 'did-stop-loading', listener: Function): this; + addListener(event: 'did-stop-loading', listener: Function): this; + removeListener(event: 'did-stop-loading', listener: Function): this; + /** + * Emitted when the document in the given frame is loaded. + */ + on(event: 'dom-ready', listener: (event: Event) => void): this; + once(event: 'dom-ready', listener: (event: Event) => void): this; + addListener(event: 'dom-ready', listener: (event: Event) => void): this; + removeListener(event: 'dom-ready', listener: (event: Event) => void): this; + /** + * Emitted when a result is available for [webContents.findInPage] request. + */ + on(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + once(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + addListener(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + removeListener(event: 'found-in-page', listener: (event: Event, + result: Result) => void): this; + /** + * Emitted when webContents wants to do basic auth. The usage is the same with the + * login event of app. + */ + on(event: 'login', listener: (event: Event, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + once(event: 'login', listener: (event: Event, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + addListener(event: 'login', listener: (event: Event, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + removeListener(event: 'login', listener: (event: Event, + request: Request, + authInfo: AuthInfo, + callback: (username: string, password: string) => void) => void): this; + /** + * Emitted when media is paused or done playing. + */ + on(event: 'media-paused', listener: Function): this; + once(event: 'media-paused', listener: Function): this; + addListener(event: 'media-paused', listener: Function): this; + removeListener(event: 'media-paused', listener: Function): this; + /** + * Emitted when media starts playing. + */ + on(event: 'media-started-playing', listener: Function): this; + once(event: 'media-started-playing', listener: Function): this; + addListener(event: 'media-started-playing', listener: Function): this; + removeListener(event: 'media-started-playing', listener: Function): this; + /** + * Emitted when the page requests to open a new window for a url. It could be + * requested by window.open or an external link like . By + * default a new BrowserWindow will be created for the url. Calling + * event.preventDefault() will prevent Electron from automatically creating a new + * BrowserWindow. If you call event.preventDefault() and manually create a new + * BrowserWindow then you must set event.newGuest to reference the new + * BrowserWindow instance, failing to do so may result in unexpected behavior. For + * example: + */ + on(event: 'new-window', listener: (event: Event, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: any, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. + */ + additionalFeatures: string[]) => void): this; + once(event: 'new-window', listener: (event: Event, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: any, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. + */ + additionalFeatures: string[]) => void): this; + addListener(event: 'new-window', listener: (event: Event, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: any, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. + */ + additionalFeatures: string[]) => void): this; + removeListener(event: 'new-window', listener: (event: Event, + url: string, + frameName: string, + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), + /** + * The options which will be used for creating the new `BrowserWindow`. + */ + options: any, + /** + * The non-standard features (features not handled by Chromium or Electron) given + * to `window.open()`. + */ + additionalFeatures: string[]) => void): this; + /** + * Emitted when page receives favicon urls. + */ + on(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs + */ + favicons: string[]) => void): this; + once(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs + */ + favicons: string[]) => void): this; + addListener(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs + */ + favicons: string[]) => void): this; + removeListener(event: 'page-favicon-updated', listener: (event: Event, + /** + * Array of URLs + */ + favicons: string[]) => void): this; + /** + * Emitted when a new frame is generated. Only the dirty area is passed in the + * buffer. + */ + on(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + once(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + addListener(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + removeListener(event: 'paint', listener: (event: Event, + dirtyRect: Rectangle, + /** + * The image data of the whole frame. + */ + image: NativeImage) => void): this; + /** + * Emitted when a plugin process has crashed. + */ + on(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + once(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + addListener(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + removeListener(event: 'plugin-crashed', listener: (event: Event, + name: string, + version: string) => void): this; + /** + * Emitted when bluetooth device needs to be selected on call to + * navigator.bluetooth.requestDevice. To use navigator.bluetooth api webBluetooth + * should be enabled. If event.preventDefault is not called, first available + * device will be selected. callback should be called with deviceId to be selected, + * passing empty string to callback will cancel the request. + */ + on(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + once(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + addListener(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + removeListener(event: 'select-bluetooth-device', listener: (event: Event, + devices: BluetoothDevice[], + callback: (deviceId: string) => void) => void): this; + /** + * Emitted when a client certificate is requested. The usage is the same with the + * select-client-certificate event of app. + */ + on(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + once(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + addListener(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + removeListener(event: 'select-client-certificate', listener: (event: Event, + url: string, + certificateList: Certificate[], + callback: (certificate: Certificate) => void) => void): this; + /** + * Emitted when mouse moves over a link or the keyboard moves the focus to a link. + */ + on(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + once(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + addListener(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + removeListener(event: 'update-target-url', listener: (event: Event, + url: string) => void): this; + /** + * Emitted when a 's web contents is being attached to this web contents. + * Calling event.preventDefault() will destroy the guest page. This event can be + * used to configure webPreferences for the webContents of a before it's + * loaded, and provides the ability to set settings that can't be set via + * attributes. Note: The specified preload script option will be appear as + * preloadURL (not preload) in the webPreferences object emitted with this event. + */ + on(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: any, + /** + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: any) => void): this; + once(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: any, + /** + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: any) => void): this; + addListener(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: any, + /** + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: any) => void): this; + removeListener(event: 'will-attach-webview', listener: (event: Event, + /** + * The web preferences that will be used by the guest page. This object can be + * modified to adjust the preferences for the guest page. + */ + webPreferences: any, + /** + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. + */ + params: any) => void): this; + /** + * Emitted when a user or the page wants to start navigation. It can happen when + * the window.location object is changed or a user clicks a link in the page. This + * event will not emit when the navigation is started programmatically with APIs + * like webContents.loadURL and webContents.back. It is also not emitted for + * in-page navigations, such as clicking anchor links or updating the + * window.location.hash. Use did-navigate-in-page event for this purpose. Calling + * event.preventDefault() will prevent the navigation. + */ + on(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + once(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + addListener(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + removeListener(event: 'will-navigate', listener: (event: Event, + url: string) => void): this; + /** + * Emitted when a beforeunload event handler is attempting to cancel a page unload. + * Calling event.preventDefault() will ignore the beforeunload event handler and + * allow the page to be unloaded. + */ + on(event: 'will-prevent-unload', listener: (event: Event) => void): this; + once(event: 'will-prevent-unload', listener: (event: Event) => void): this; + addListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; + removeListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; + /** + * Adds the specified path to DevTools workspace. Must be used after DevTools + * creation: + */ + addWorkSpace(path: string): void; + /** + * Begin subscribing for presentation events and captured frames, the callback will + * be called with callback(frameBuffer, dirtyRect) when there is a presentation + * event. The frameBuffer is a Buffer that contains raw pixel data. On most + * machines, the pixel data is effectively stored in 32bit BGRA format, but the + * actual representation depends on the endianness of the processor (most modern + * processors are little-endian, on machines with big-endian processors the data is + * in 32bit ARGB format). The dirtyRect is an object with x, y, width, height + * properties that describes which part of the page was repainted. If onlyDirty is + * set to true, frameBuffer will only contain the repainted area. onlyDirty + * defaults to false. + */ + beginFrameSubscription(callback: (frameBuffer: Buffer, dirtyRect: Rectangle) => void): void; + /** + * Begin subscribing for presentation events and captured frames, the callback will + * be called with callback(frameBuffer, dirtyRect) when there is a presentation + * event. The frameBuffer is a Buffer that contains raw pixel data. On most + * machines, the pixel data is effectively stored in 32bit BGRA format, but the + * actual representation depends on the endianness of the processor (most modern + * processors are little-endian, on machines with big-endian processors the data is + * in 32bit ARGB format). The dirtyRect is an object with x, y, width, height + * properties that describes which part of the page was repainted. If onlyDirty is + * set to true, frameBuffer will only contain the repainted area. onlyDirty + * defaults to false. + */ + beginFrameSubscription(onlyDirty: boolean, callback: (frameBuffer: Buffer, dirtyRect: Rectangle) => void): void; + canGoBack(): boolean; + canGoForward(): boolean; + canGoToOffset(offset: number): boolean; + /** + * Captures a snapshot of the page within rect. Upon completion callback will be + * called with callback(image). The image is an instance of NativeImage that stores + * data of the snapshot. Omitting rect will capture the whole visible page. + */ + capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; + /** + * Captures a snapshot of the page within rect. Upon completion callback will be + * called with callback(image). The image is an instance of NativeImage that stores + * data of the snapshot. Omitting rect will capture the whole visible page. + */ + capturePage(callback: (image: NativeImage) => void): void; + /** + * Clears the navigation history. + */ + clearHistory(): void; + /** + * Closes the devtools. + */ + closeDevTools(): void; + /** + * Executes the editing command copy in web page. + */ + copy(): void; + /** + * Copy the image at the given position to the clipboard. + */ + copyImageAt(x: number, y: number): void; + /** + * Executes the editing command cut in web page. + */ + cut(): void; + /** + * Executes the editing command delete in web page. + */ + delete(): void; + /** + * Disable device emulation enabled by webContents.enableDeviceEmulation. + */ + disableDeviceEmulation(): void; + /** + * Initiates a download of the resource at url without navigating. The + * will-download event of session will be triggered. + */ + downloadURL(url: string): void; + /** + * Enable device emulation with the given parameters. + */ + enableDeviceEmulation(parameters: Parameters): void; + /** + * End subscribing for frame presentation events. + */ + endFrameSubscription(): void; + /** + * Evaluates code in page. In the browser window some HTML APIs like + * requestFullScreen can only be invoked by a gesture from the user. Setting + * userGesture to true will remove this limitation. If the result of the executed + * code is a promise the callback result will be the resolved value of the promise. + * We recommend that you use the returned Promise to handle code that results in a + * Promise. + */ + executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; + /** + * Starts a request to find all matches for the text in the web page and returns an + * Integer representing the request id used for the request. The result of the + * request can be obtained by subscribing to found-in-page event. + */ + findInPage(text: string, options?: FindInPageOptions): void; + /** + * Focuses the web page. + */ + focus(): void; + getFrameRate(): number; + getOSProcessId(): number; + /** + * Get the system printer list. + */ + getPrinters(): PrinterInfo[]; + getTitle(): string; + getURL(): string; + getUserAgent(): string; + getWebRTCIPHandlingPolicy(): string; + /** + * Sends a request to get current zoom factor, the callback will be called with + * callback(zoomFactor). + */ + getZoomFactor(callback: (zoomFactor: number) => void): void; + /** + * Sends a request to get current zoom level, the callback will be called with + * callback(zoomLevel). + */ + getZoomLevel(callback: (zoomLevel: number) => void): void; + /** + * Makes the browser go back a web page. + */ + goBack(): void; + /** + * Makes the browser go forward a web page. + */ + goForward(): void; + /** + * Navigates browser to the specified absolute web page index. + */ + goToIndex(index: number): void; + /** + * Navigates to the specified offset from the "current entry". + */ + goToOffset(offset: number): void; + /** + * Checks if any ServiceWorker is registered and returns a boolean as response to + * callback. + */ + hasServiceWorker(callback: (hasWorker: boolean) => void): void; + /** + * Injects CSS into the current web page. + */ + insertCSS(css: string): void; + /** + * Inserts text to the focused element. + */ + insertText(text: string): void; + /** + * Starts inspecting element at position (x, y). + */ + inspectElement(x: number, y: number): void; + /** + * Opens the developer tools for the service worker context. + */ + inspectServiceWorker(): void; + /** + * Schedules a full repaint of the window this web contents is in. If offscreen + * rendering is enabled invalidates the frame and generates a new one through the + * 'paint' event. + */ + invalidate(): void; + isAudioMuted(): boolean; + isCrashed(): boolean; + isDestroyed(): boolean; + isDevToolsFocused(): boolean; + isDevToolsOpened(): boolean; + isFocused(): boolean; + isLoading(): boolean; + isLoadingMainFrame(): boolean; + isOffscreen(): boolean; + isPainting(): boolean; + isWaitingForResponse(): boolean; + /** + * Loads the url in the window. The url must contain the protocol prefix, e.g. the + * http:// or file://. If the load should bypass http cache then use the pragma + * header to achieve it. + */ + loadURL(url: string, options?: LoadURLOptions): void; + /** + * Opens the devtools. + */ + openDevTools(options?: OpenDevToolsOptions): void; + /** + * Executes the editing command paste in web page. + */ + paste(): void; + /** + * Executes the editing command pasteAndMatchStyle in web page. + */ + pasteAndMatchStyle(): void; + /** + * Prints window's web page. When silent is set to true, Electron will pick the + * system's default printer if deviceName is empty and the default settings for + * printing. Calling window.print() in web page is equivalent to calling + * webContents.print({silent: false, printBackground: false, deviceName: ''}). Use + * page-break-before: always; CSS style to force to print to a new page. + */ + print(options?: PrintOptions): void; + /** + * Prints window's web page as PDF with Chromium's preview printing custom + * settings. The callback will be called with callback(error, data) on completion. + * The data is a Buffer that contains the generated PDF data. The landscape will be + * ignored if @page CSS at-rule is used in the web page. By default, an empty + * options will be regarded as: Use page-break-before: always; CSS style to force + * to print to a new page. An example of webContents.printToPDF: + */ + printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; + /** + * Executes the editing command redo in web page. + */ + redo(): void; + /** + * Reloads the current web page. + */ + reload(): void; + /** + * Reloads current page and ignores cache. + */ + reloadIgnoringCache(): void; + /** + * Removes the specified path from DevTools workspace. + */ + removeWorkSpace(path: string): void; + /** + * Executes the editing command replace in web page. + */ + replace(text: string): void; + /** + * Executes the editing command replaceMisspelling in web page. + */ + replaceMisspelling(text: string): void; + savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML', callback: (error: Error) => void): boolean; + /** + * Executes the editing command selectAll in web page. + */ + selectAll(): void; + /** + * Send an asynchronous message to renderer process via channel, you can also send + * arbitrary arguments. Arguments will be serialized in JSON internally and hence + * no functions or prototype chain will be included. The renderer process can + * handle the message by listening to channel with the ipcRenderer module. An + * example of sending messages from the main process to the renderer process: + */ + send(channel: string, ...args: any[]): void; + /** + * Sends an input event to the page. Note: The BrowserWindow containing the + * contents needs to be focused for sendInputEvent() to work. For keyboard events, + * the event object also have following properties: For mouse events, the event + * object also have following properties: For the mouseWheel event, the event + * object also have following properties: + */ + sendInputEvent(event: Event): void; + /** + * Mute the audio on the current web page. + */ + setAudioMuted(muted: boolean): void; + /** + * If offscreen rendering is enabled sets the frame rate to the specified number. + * Only values between 1 and 60 are accepted. + */ + setFrameRate(fps: number): void; + /** + * Ignore application menu shortcuts while this web contents is focused. + */ + setIgnoreMenuShortcuts(ignore: boolean): void; + /** + * Sets the maximum and minimum layout-based (i.e. non-visual) zoom level. + */ + setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + /** + * Set the size of the page. This is only supported for guest contents. + */ + setSize(options: SizeOptions): void; + /** + * Overrides the user agent for this web page. + */ + setUserAgent(userAgent: string): void; + /** + * Sets the maximum and minimum pinch-to-zoom level. + */ + setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + /** + * Setting the WebRTC IP handling policy allows you to control which IPs are + * exposed via WebRTC. See BrowserLeaks for more details. + */ + setWebRTCIPHandlingPolicy(policy: 'default' | 'default_public_interface_only' | 'default_public_and_private_interfaces' | 'disable_non_proxied_udp'): void; + /** + * Changes the zoom factor to the specified factor. Zoom factor is zoom percent + * divided by 100, so 300% = 3.0. + */ + setZoomFactor(factor: number): void; + /** + * Changes the zoom level to the specified level. The original size is 0 and each + * increment above or below represents zooming 20% larger or smaller to default + * limits of 300% and 50% of original size, respectively. + */ + setZoomLevel(level: number): void; + /** + * Deprecated: Call setVisualZoomLevelLimits instead to set the visual zoom level + * limits. This method will be removed in Electron 2.0. + */ + setZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + /** + * Shows pop-up dictionary that searches the selected word on the page. + */ + showDefinitionForSelection(): void; + /** + * Sets the item as dragging item for current drag-drop operation, file is the + * absolute path of the file to be dragged, and icon is the image showing under the + * cursor when dragging. + */ + startDrag(item: Item): void; + /** + * If offscreen rendering is enabled and not painting, start painting. + */ + startPainting(): void; + /** + * Stops any pending navigation. + */ + stop(): void; + /** + * Stops any findInPage request for the webContents with the provided action. + */ + stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; + /** + * If offscreen rendering is enabled and painting, stop painting. + */ + stopPainting(): void; + /** + * Toggles the developer tools. + */ + toggleDevTools(): void; + /** + * Executes the editing command undo in web page. + */ + undo(): void; + /** + * Unregisters any ServiceWorker if present and returns a boolean as response to + * callback when the JS promise is fulfilled or false when the JS promise is + * rejected. + */ + unregisterServiceWorker(callback: (success: boolean) => void): void; + /** + * Executes the editing command unselect in web page. + */ + unselect(): void; + debugger: Debugger; + devToolsWebContents: WebContents; + hostWebContents: WebContents; + id: number; + session: Session; + } + + interface WebFrame extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/web-frame + + /** + * Attempts to free memory that is no longer being used (like images from a + * previous navigation). Note that blindly calling this method probably makes + * Electron slower since it will have to refill these emptied caches, you should + * only call it if an event in your app has occurred that makes you think your page + * is actually using less memory (i.e. you have navigated from a super heavy page + * to a mostly empty one, and intend to stay there). + */ + clearCache(): void; + /** + * Evaluates code in page. In the browser window some HTML APIs like + * requestFullScreen can only be invoked by a gesture from the user. Setting + * userGesture to true will remove this limitation. + */ + executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; + /** + * Returns an object describing usage information of Blink's internal memory + * caches. This will generate: + */ + getResourceUsage(): ResourceUsage; + getZoomFactor(): number; + getZoomLevel(): number; + /** + * Inserts text to the focused element. + */ + insertText(text: string): void; + /** + * Resources will be loaded from this scheme regardless of the current page's + * Content Security Policy. + */ + registerURLSchemeAsBypassingCSP(scheme: string): void; + /** + * Registers the scheme as secure, bypasses content security policy for resources, + * allows registering ServiceWorker and supports fetch API. Specify an option with + * the value of false to omit it from the registration. An example of registering a + * privileged scheme, without bypassing Content Security Policy: + */ + registerURLSchemeAsPrivileged(scheme: string, options?: RegisterURLSchemeAsPrivilegedOptions): void; + /** + * Registers the scheme as secure scheme. Secure schemes do not trigger mixed + * content warnings. For example, https and data are secure schemes because they + * cannot be corrupted by active network attackers. + */ + registerURLSchemeAsSecure(scheme: string): void; + /** + * Sets the maximum and minimum layout-based (i.e. non-visual) zoom level. + */ + setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + /** + * Sets a provider for spell checking in input fields and text areas. The provider + * must be an object that has a spellCheck method that returns whether the word + * passed is correctly spelled. An example of using node-spellchecker as provider: + */ + setSpellCheckProvider(language: string, autoCorrectWord: boolean, provider: Provider): void; + /** + * Sets the maximum and minimum pinch-to-zoom level. + */ + setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + /** + * Changes the zoom factor to the specified factor. Zoom factor is zoom percent + * divided by 100, so 300% = 3.0. + */ + setZoomFactor(factor: number): void; + /** + * Changes the zoom level to the specified level. The original size is 0 and each + * increment above or below represents zooming 20% larger or smaller to default + * limits of 300% and 50% of original size, respectively. + */ + setZoomLevel(level: number): void; + /** + * Deprecated: Call setVisualZoomLevelLimits instead to set the visual zoom level + * limits. This method will be removed in Electron 2.0. + */ + setZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + } + + class WebRequest extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/web-request + + /** + * The listener will be called with listener(details) when a server initiated + * redirect is about to occur. + */ + onBeforeRedirect(filter: OnBeforeRedirectFilter, listener: (details: OnBeforeRedirectDetails) => void): void; + /** + * The listener will be called with listener(details, callback) when a request is + * about to occur. The uploadData is an array of UploadData objects. The callback + * has to be called with an response object. + */ + onBeforeRequest(filter: OnBeforeRequestFilter, listener: (details: OnBeforeRequestDetails, callback: (response: Response) => void) => void): void; + /** + * The listener will be called with listener(details, callback) before sending an + * HTTP request, once the request headers are available. This may occur after a TCP + * connection is made to the server, but before any http data is sent. The callback + * has to be called with an response object. + */ + onBeforeSendHeaders(filter: OnBeforeSendHeadersFilter, listener: Function): void; + /** + * The listener will be called with listener(details) when a request is completed. + */ + onCompleted(filter: OnCompletedFilter, listener: (details: OnCompletedDetails) => void): void; + /** + * The listener will be called with listener(details) when an error occurs. + */ + onErrorOccurred(filter: OnErrorOccurredFilter, listener: (details: OnErrorOccurredDetails) => void): void; + /** + * The listener will be called with listener(details, callback) when HTTP response + * headers of a request have been received. The callback has to be called with an + * response object. + */ + onHeadersReceived(filter: OnHeadersReceivedFilter, listener: Function): void; + /** + * The listener will be called with listener(details) when first byte of the + * response body is received. For HTTP requests, this means that the status line + * and response headers are available. + */ + onResponseStarted(filter: OnResponseStartedFilter, listener: (details: OnResponseStartedDetails) => void): void; + /** + * The listener will be called with listener(details) just before a request is + * going to be sent to the server, modifications of previous onBeforeSendHeaders + * response are visible by the time this listener is fired. + */ + onSendHeaders(filter: OnSendHeadersFilter, listener: (details: OnSendHeadersDetails) => void): void; + } + + interface WebviewTag extends HTMLElement { + + // Docs: http://electron.atom.io/docs/api/webview-tag + + /** + * Fired when a load has committed. This includes navigation within the current + * document as well as subframe document-level loads, but does not include + * asynchronous resource loads. + */ + addEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void): this; + /** + * Fired when the navigation is done, i.e. the spinner of the tab will stop + * spinning, and the onload event is dispatched. + */ + addEventListener(event: 'did-finish-load', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-finish-load', listener: (event: Event) => void): this; + /** + * This event is like did-finish-load, but fired when the load failed or was + * cancelled, e.g. window.stop() is invoked. + */ + addEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void): this; + /** + * Fired when a frame has done navigation. + */ + addEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void): this; + /** + * Corresponds to the points in time when the spinner of the tab starts spinning. + */ + addEventListener(event: 'did-start-loading', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-start-loading', listener: (event: Event) => void): this; + /** + * Corresponds to the points in time when the spinner of the tab stops spinning. + */ + addEventListener(event: 'did-stop-loading', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-stop-loading', listener: (event: Event) => void): this; + /** + * Fired when details regarding a requested resource is available. status indicates + * socket connection to download the resource. + */ + addEventListener(event: 'did-get-response-details', listener: (event: DidGetResponseDetailsEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-get-response-details', listener: (event: DidGetResponseDetailsEvent) => void): this; + /** + * Fired when a redirect was received while requesting a resource. + */ + addEventListener(event: 'did-get-redirect-request', listener: (event: DidGetRedirectRequestEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-get-redirect-request', listener: (event: DidGetRedirectRequestEvent) => void): this; + /** + * Fired when document in the given frame is loaded. + */ + addEventListener(event: 'dom-ready', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'dom-ready', listener: (event: Event) => void): this; + /** + * Fired when page title is set during navigation. explicitSet is false when title + * is synthesized from file url. + */ + addEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void): this; + /** + * Fired when page receives favicon urls. + */ + addEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void): this; + /** + * Fired when page enters fullscreen triggered by HTML API. + */ + addEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void): this; + /** + * Fired when page leaves fullscreen triggered by HTML API. + */ + addEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void): this; + /** + * Fired when the guest window logs a console message. The following example code + * forwards all log messages to the embedder's console without regard for log level + * or other properties. + */ + addEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void): this; + /** + * Fired when a result is available for webview.findInPage request. + */ + addEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void): this; + /** + * Fired when the guest page attempts to open a new browser window. The following + * example code opens the new url in system's default browser. + */ + addEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void): this; + /** + * Emitted when a user or the page wants to start navigation. It can happen when + * the window.location object is changed or a user clicks a link in the page. This + * event will not emit when the navigation is started programmatically with APIs + * like .loadURL and .back. It is also not emitted during in-page + * navigation, such as clicking anchor links or updating the window.location.hash. + * Use did-navigate-in-page event for this purpose. Calling event.preventDefault() + * does NOT have any effect. + */ + addEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void): this; + /** + * Emitted when a navigation is done. This event is not emitted for in-page + * navigations, such as clicking anchor links or updating the window.location.hash. + * Use did-navigate-in-page event for this purpose. + */ + addEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void): this; + /** + * Emitted when an in-page navigation happened. When in-page navigation happens, + * the page URL changes but does not cause navigation outside of the page. Examples + * of this occurring are when anchor links are clicked or when the DOM hashchange + * event is triggered. + */ + addEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void): this; + /** + * Fired when the guest page attempts to close itself. The following example code + * navigates the webview to about:blank when the guest attempts to close itself. + */ + addEventListener(event: 'close', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'close', listener: (event: Event) => void): this; + /** + * Fired when the guest page has sent an asynchronous message to embedder page. + * With sendToHost method and ipc-message event you can easily communicate between + * guest page and embedder page: + */ + addEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void): this; + /** + * Fired when the renderer process is crashed. + */ + addEventListener(event: 'crashed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'crashed', listener: (event: Event) => void): this; + /** + * Fired when the gpu process is crashed. + */ + addEventListener(event: 'gpu-crashed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'gpu-crashed', listener: (event: Event) => void): this; + /** + * Fired when a plugin process is crashed. + */ + addEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void): this; + /** + * Fired when the WebContents is destroyed. + */ + addEventListener(event: 'destroyed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'destroyed', listener: (event: Event) => void): this; + /** + * Emitted when media starts playing. + */ + addEventListener(event: 'media-started-playing', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'media-started-playing', listener: (event: Event) => void): this; + /** + * Emitted when media is paused or done playing. + */ + addEventListener(event: 'media-paused', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'media-paused', listener: (event: Event) => void): this; + /** + * Emitted when a page's theme color changes. This is usually due to encountering a + * meta tag: + */ + addEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void): this; + /** + * Emitted when mouse moves over a link or the keyboard moves the focus to a link. + */ + addEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void, useCapture?: boolean): this; + removeEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void): this; + /** + * Emitted when DevTools is opened. + */ + addEventListener(event: 'devtools-opened', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'devtools-opened', listener: (event: Event) => void): this; + /** + * Emitted when DevTools is closed. + */ + addEventListener(event: 'devtools-closed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'devtools-closed', listener: (event: Event) => void): this; + /** + * Emitted when DevTools is focused / opened. + */ + addEventListener(event: 'devtools-focused', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'devtools-focused', listener: (event: Event) => void): this; + canGoBack(): boolean; + canGoForward(): boolean; + canGoToOffset(offset: number): boolean; + /** + * Captures a snapshot of the webview's page. Same as + * webContents.capturePage([rect, ]callback). + */ + capturePage(callback: (image: NativeImage) => void): void; + /** + * Captures a snapshot of the webview's page. Same as + * webContents.capturePage([rect, ]callback). + */ + capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; + /** + * Clears the navigation history. + */ + clearHistory(): void; + /** + * Closes the DevTools window of guest page. + */ + closeDevTools(): void; + /** + * Executes editing command copy in page. + */ + copy(): void; + /** + * Executes editing command cut in page. + */ + cut(): void; + /** + * Executes editing command delete in page. + */ + delete(): void; + /** + * Evaluates code in page. If userGesture is set, it will create the user gesture + * context in the page. HTML APIs like requestFullScreen, which require user + * action, can take advantage of this option for automation. + */ + executeJavaScript(code: string, userGesture: boolean, callback?: (result: any) => void): void; + /** + * Starts a request to find all matches for the text in the web page and returns an + * Integer representing the request id used for the request. The result of the + * request can be obtained by subscribing to found-in-page event. + */ + findInPage(text: string, options?: FindInPageOptions): void; + getTitle(): string; + getURL(): string; + getUserAgent(): string; + getWebContents(): WebContents; + /** + * Makes the guest page go back. + */ + goBack(): void; + /** + * Makes the guest page go forward. + */ + goForward(): void; + /** + * Navigates to the specified absolute index. + */ + goToIndex(index: number): void; + /** + * Navigates to the specified offset from the "current entry". + */ + goToOffset(offset: number): void; + /** + * Injects CSS into the guest page. + */ + insertCSS(css: string): void; + /** + * Inserts text to the focused element. + */ + insertText(text: string): void; + /** + * Starts inspecting element at position (x, y) of guest page. + */ + inspectElement(x: number, y: number): void; + /** + * Opens the DevTools for the service worker context present in the guest page. + */ + inspectServiceWorker(): void; + isAudioMuted(): boolean; + isCrashed(): boolean; + isDevToolsFocused(): boolean; + isDevToolsOpened(): boolean; + isLoading(): boolean; + isWaitingForResponse(): boolean; + /** + * Loads the url in the webview, the url must contain the protocol prefix, e.g. the + * http:// or file://. + */ + loadURL(url: string, options?: LoadURLOptions): void; + /** + * Opens a DevTools window for guest page. + */ + openDevTools(): void; + /** + * Executes editing command paste in page. + */ + paste(): void; + /** + * Executes editing command pasteAndMatchStyle in page. + */ + pasteAndMatchStyle(): void; + /** + * Prints webview's web page. Same as webContents.print([options]). + */ + print(options?: PrintOptions): void; + /** + * Prints webview's web page as PDF, Same as webContents.printToPDF(options, + * callback). + */ + printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; + /** + * Executes editing command redo in page. + */ + redo(): void; + /** + * Reloads the guest page. + */ + reload(): void; + /** + * Reloads the guest page and ignores cache. + */ + reloadIgnoringCache(): void; + /** + * Executes editing command replace in page. + */ + replace(text: string): void; + /** + * Executes editing command replaceMisspelling in page. + */ + replaceMisspelling(text: string): void; + /** + * Executes editing command selectAll in page. + */ + selectAll(): void; + /** + * Send an asynchronous message to renderer process via channel, you can also send + * arbitrary arguments. The renderer process can handle the message by listening to + * the channel event with the ipcRenderer module. See webContents.send for + * examples. + */ + send(channel: string, ...args: any[]): void; + /** + * Sends an input event to the page. See webContents.sendInputEvent for detailed + * description of event object. + */ + sendInputEvent(event: any): void; + /** + * Set guest page muted. + */ + setAudioMuted(muted: boolean): void; + /** + * Overrides the user agent for the guest page. + */ + setUserAgent(userAgent: string): void; + /** + * Changes the zoom factor to the specified factor. Zoom factor is zoom percent + * divided by 100, so 300% = 3.0. + */ + setZoomFactor(factor: number): void; + /** + * Changes the zoom level to the specified level. The original size is 0 and each + * increment above or below represents zooming 20% larger or smaller to default + * limits of 300% and 50% of original size, respectively. + */ + setZoomLevel(level: number): void; + /** + * Shows pop-up dictionary that searches the selected word on the page. + */ + showDefinitionForSelection(): void; + /** + * Stops any pending navigation. + */ + stop(): void; + /** + * Stops any findInPage request for the webview with the provided action. + */ + stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; + /** + * Executes editing command undo in page. + */ + undo(): void; + /** + * Executes editing command unselect in page. + */ + unselect(): void; + /** + * When this attribute is present the guest page will be allowed to open new + * windows. Popups are disabled by default. + */ + allowpopups?: string; + /** + * When this attribute is present the webview container will automatically resize + * within the bounds specified by the attributes minwidth, minheight, maxwidth, and + * maxheight. These constraints do not impact the webview unless autosize is + * enabled. When autosize is enabled, the webview container size cannot be less + * than the minimum values or greater than the maximum. + */ + autosize?: string; + /** + * A list of strings which specifies the blink features to be enabled separated by + * ,. The full list of supported feature strings can be found in the + * RuntimeEnabledFeatures.json5 file. + */ + blinkfeatures?: string; + /** + * A list of strings which specifies the blink features to be disabled separated by + * ,. The full list of supported feature strings can be found in the + * RuntimeEnabledFeatures.json5 file. + */ + disableblinkfeatures?: string; + /** + * When this attribute is present the webview contents will be prevented from + * resizing when the webview element itself is resized. This can be used in + * combination with webContents.setSize to manually resize the webview contents in + * reaction to a window size change. This can make resizing faster compared to + * relying on the webview element bounds to automatically resize the contents. + */ + disableguestresize?: string; + /** + * When this attribute is present the guest page will have web security disabled. + * Web security is enabled by default. + */ + disablewebsecurity?: string; + /** + * A value that links the webview to a specific webContents. When a webview first + * loads a new webContents is created and this attribute is set to its instance + * identifier. Setting this attribute on a new or existing webview connects it to + * the existing webContents that currently renders in a different webview. The + * existing webview will see the destroy event and will then create a new + * webContents when a new url is loaded. + */ + guestinstance?: string; + /** + * Sets the referrer URL for the guest page. + */ + httpreferrer?: string; + /** + * When this attribute is present the guest page in webview will have node + * integration and can use node APIs like require and process to access low level + * system resources. Node integration is disabled by default in the guest page. + */ + nodeintegration?: string; + /** + * Sets the session used by the page. If partition starts with persist:, the page + * will use a persistent session available to all pages in the app with the same + * partition. if there is no persist: prefix, the page will use an in-memory + * session. By assigning the same partition, multiple pages can share the same + * session. If the partition is unset then default session of the app will be used. + * This value can only be modified before the first navigation, since the session + * of an active renderer process cannot change. Subsequent attempts to modify the + * value will fail with a DOM exception. + */ + partition?: string; + /** + * When this attribute is present the guest page in webview will be able to use + * browser plugins. Plugins are disabled by default. + */ + plugins?: string; + /** + * Specifies a script that will be loaded before other scripts run in the guest + * page. The protocol of script's URL must be either file: or asar:, because it + * will be loaded by require in guest page under the hood. When the guest page + * doesn't have node integration this script will still have access to all Node + * APIs, but global objects injected by Node will be deleted after this script has + * finished executing. Note: This option will be appear as preloadURL (not preload) + * in the webPreferences specified to the will-attach-webview event. + */ + preload?: string; + /** + * Returns the visible URL. Writing to this attribute initiates top-level + * navigation. Assigning src its own value will reload the current page. The src + * attribute can also accept data URLs, such as data:text/plain,Hello, world!. + */ + src?: string; + /** + * Sets the user agent for the guest page before the page is navigated to. Once the + * page is loaded, use the setUserAgent method to change the user agent. + */ + useragent?: string; + /** + * A list of strings which specifies the web preferences to be set on the webview, + * separated by ,. The full list of supported preference strings can be found in + * BrowserWindow. The string follows the same format as the features string in + * window.open. A name by itself is given a true boolean value. A preference can be + * set to another value by including an =, followed by the value. Special values + * yes and 1 are interpreted as true, while no and 0 are interpreted as false. + */ + webpreferences?: string; + } + + interface AboutPanelOptionsOptions { /** * The app's name. */ @@ -714,2665 +5891,312 @@ declare namespace Electron { version?: string; } - // https://github.com/electron/electron/blob/master/docs/api/auto-updater.md - - /** - * This module provides an interface for the Squirrel auto-updater framework. - */ - interface AutoUpdater extends NodeJS.EventEmitter { + interface AddRepresentationOptions { /** - * Emitted when there is an error while updating. + * The scale factor to add the image representation for. */ - on(event: 'error', listener: (error: Error) => void): this; + scaleFactor: number; /** - * Emitted when checking if an update has started. - */ - on(event: 'checking-for-update', listener: Function): this; - /** - * Emitted when there is an available update. The update is downloaded automatically. - */ - on(event: 'update-available', listener: Function): this; - /** - * Emitted when there is no available update. - */ - on(event: 'update-not-available', listener: Function): this; - /** - * Emitted when an update has been downloaded. - * Note: On Windows only releaseName is available. - */ - on(event: 'update-downloaded', listener: (event: Event, releaseNotes: string, releaseName: string, releaseDate: Date, updateURL: string) => void): this; - on(event: string, listener: Function): this; - /** - * Set the url and initialize the auto updater. - */ - setFeedURL(url: string, requestHeaders?: Headers): void; - /** - * @returns The current update feed URL. - */ - getFeedURL(): string; - /** - * Ask the server whether there is an update, you have to call setFeedURL - * before using this API - */ - checkForUpdates(): void; - /** - * Restarts the app and installs the update after it has been downloaded. - * It should only be called after update-downloaded has been emitted. - */ - quitAndInstall(): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/browser-window.md - - /** - * The BrowserWindow class gives you ability to create a browser window. - * You can also create a window without chrome by using Frameless Window API. - */ - class BrowserWindow extends NodeJS.EventEmitter implements Destroyable { - /** - * Emitted when the document changed its title, - * calling event.preventDefault() would prevent the native window’s title to change. - */ - on(event: 'page-title-updated', listener: (event: Event, title: string) => void): this; - /** - * Emitted when the window is going to be closed. It’s emitted before the beforeunload - * and unload event of the DOM. Calling event.preventDefault() will cancel the close. - */ - on(event: 'close', listener: (event: Event) => void): this; - /** - * Emitted when the window is closed. After you have received this event - * you should remove the reference to the window and avoid using it anymore. - */ - on(event: 'closed', listener: Function): this; - /** - * Emitted when the web page becomes unresponsive. - */ - on(event: 'unresponsive', listener: Function): this; - /** - * Emitted when the unresponsive web page becomes responsive again. - */ - on(event: 'responsive', listener: Function): this; - /** - * Emitted when the window loses focus. - */ - on(event: 'blur', listener: Function): this; - /** - * Emitted when the window gains focus. - */ - on(event: 'focus', listener: Function): this; - /** - * Emitted when the window is shown. - */ - on(event: 'show', listener: Function): this; - /** - * Emitted when the window is hidden. - */ - on(event: 'hide', listener: Function): this; - /** - * Emitted when the web page has been rendered and window can be displayed without visual flash. - */ - on(event: 'ready-to-show', listener: Function): this; - /** - * Emitted when window is maximized. - */ - on(event: 'maximize', listener: Function): this; - /** - * Emitted when the window exits from maximized state. - */ - on(event: 'unmaximize', listener: Function): this; - /** - * Emitted when the window is minimized. - */ - on(event: 'minimize', listener: Function): this; - /** - * Emitted when the window is restored from minimized state. - */ - on(event: 'restore', listener: Function): this; - /** - * Emitted when the window is getting resized. - */ - on(event: 'resize', listener: Function): this; - /** - * Emitted when the window is getting moved to a new position. - */ - on(event: 'move', listener: Function): this; - /** - * Emitted when the window enters full screen state. - */ - on(event: 'enter-full-screen', listener: Function): this; - /** - * Emitted when the window leaves full screen state. - */ - on(event: 'leave-full-screen', listener: Function): this; - /** - * Emitted when the window enters full screen state triggered by HTML API. - */ - on(event: 'enter-html-full-screen', listener: Function): this; - /** - * Emitted when the window leaves full screen state triggered by HTML API. - */ - on(event: 'leave-html-full-screen', listener: Function): this; - /** - * Emitted when an App Command is invoked. These are typically related - * to keyboard media keys or browser commands, as well as the "Back" / - * "Forward" buttons built into some mice on Windows. - * Note: This is only implemented on Windows. - */ - on(event: 'app-command', listener: (event: Event, command: string) => void): this; - /** - * Emitted when scroll wheel event phase has begun. - * Note: This is only implemented on macOS. - */ - on(event: 'scroll-touch-begin', listener: Function): this; - /** - * Emitted when scroll wheel event phase has ended. - * Note: This is only implemented on macOS. - */ - on(event: 'scroll-touch-end', listener: Function): this; - /** - * Emitted when scroll wheel event phase filed upon reaching the edge of element. - * Note: This is only implemented on macOS. - */ - on(event: 'scroll-touch-edge', listener: Function): this; - /** - * Emitted on 3-finger swipe. - * Note: This is only implemented on macOS. - */ - on(event: 'swipe', listener: (event: Event, direction: SwipeDirection) => void): this; - on(event: string, listener: Function): this; - /** - * Creates a new BrowserWindow with native properties as set by the options. - */ - constructor(options?: BrowserWindowOptions); - /** - * @returns All opened browser windows. - */ - static getAllWindows(): BrowserWindow[]; - /** - * @returns The window that is focused in this application. - */ - static getFocusedWindow(): BrowserWindow; - /** - * Find a window according to the webContents it owns. - */ - static fromWebContents(webContents: WebContents): BrowserWindow; - /** - * Find a window according to its ID. - */ - static fromId(id: number): BrowserWindow; - /** - * Adds devtools extension located at path. The extension will be remembered - * so you only need to call this API once, this API is not for programming use. - * @returns The extension's name. - * - * Note: This API cannot be called before the ready event of the app module is emitted. - */ - static addDevToolsExtension(path: string): string; - /** - * Remove a devtools extension. - * @param name The name of the devtools extension to remove. - * - * Note: This API cannot be called before the ready event of the app module is emitted. - */ - static removeDevToolsExtension(name: string): void; - /** - * @returns devtools extensions. - * - * Note: This API cannot be called before the ready event of the app module is emitted. - */ - static getDevToolsExtensions(): DevToolsExtensions; - /** - * The WebContents object this window owns, all web page related events and - * operations would be done via it. - * Note: Users should never store this object because it may become null when - * the renderer process (web page) has crashed. - */ - webContents: WebContents; - /** - * Get the unique ID of this window. - */ - id: number; - /** - * Force closing the window, the unload and beforeunload event won't be emitted - * for the web page, and close event would also not be emitted for this window, - * but it would guarantee the closed event to be emitted. - * You should only use this method when the renderer process (web page) has crashed. - */ - destroy(): void; - /** - * Try to close the window, this has the same effect with user manually clicking - * the close button of the window. The web page may cancel the close though, - * see the close event. - */ - close(): void; - /** - * Focus on the window. - */ - focus(): void; - /** - * Remove focus on the window. - */ - blur(): void; - /** - * @returns Whether the window is focused. - */ - isFocused(): boolean; - /** - * @returns Whether the window is destroyed. - */ - isDestroyed(): boolean; - /** - * Shows and gives focus to the window. - */ - show(): void; - /** - * Shows the window but doesn't focus on it. - */ - showInactive(): void; - /** - * Hides the window. - */ - hide(): void; - /** - * @returns Whether the window is visible to the user. - */ - isVisible(): boolean; - /** - * @returns Whether the window is a modal window. - */ - isModal(): boolean; - /** - * Maximizes the window. - */ - maximize(): void; - /** - * Unmaximizes the window. - */ - unmaximize(): void; - /** - * @returns Whether the window is maximized. - */ - isMaximized(): boolean; - /** - * Minimizes the window. On some platforms the minimized window will be - * shown in the Dock. - */ - minimize(): void; - /** - * Restores the window from minimized state to its previous state. - */ - restore(): void; - /** - * @returns Whether the window is minimized. - */ - isMinimized(): boolean; - /** - * Sets whether the window should be in fullscreen mode. - */ - setFullScreen(flag: boolean): void; - /** - * @returns Whether the window is in fullscreen mode. - */ - isFullScreen(): boolean; - /** - * This will have a window maintain an aspect ratio. - * The extra size allows a developer to have space, specified in pixels, - * not included within the aspect ratio calculations. - * This API already takes into account the difference between a window’s size and its content size. - * - * Note: This API is available only on macOS. - */ - setAspectRatio(aspectRatio: number, extraSize?: Size): void; - /** - * Uses Quick Look to preview a file at a given path. - * - * @param path The absolute path to the file to preview with QuickLook. - * @param displayName The name of the file to display on the Quick Look modal view. - * Note: This API is available only on macOS. - */ - previewFile(path: string, displayName?: string): void; - /** - * Resizes and moves the window to width, height, x, y. - */ - setBounds(options: Rectangle, animate?: boolean): void; - /** - * @returns The window's width, height, x and y values. - */ - getBounds(): Rectangle; - /** - * Resizes and moves the window's client area (e.g. the web page) to width, height, x, y. - */ - setContentBounds(options: Rectangle, animate?: boolean): void; - /** - * @returns The window's client area (e.g. the web page) width, height, x and y values. - */ - getContentBounds(): Rectangle; - /** - * Resizes the window to width and height. - */ - setSize(width: number, height: number, animate?: boolean): void; - /** - * @returns The window's width and height. - */ - getSize(): number[]; - /** - * Resizes the window's client area (e.g. the web page) to width and height. - */ - setContentSize(width: number, height: number, animate?: boolean): void; - /** - * @returns The window's client area's width and height. - */ - getContentSize(): number[]; - /** - * Sets the minimum size of window to width and height. - */ - setMinimumSize(width: number, height: number): void; - /** - * @returns The window's minimum width and height. - */ - getMinimumSize(): number[]; - /** - * Sets the maximum size of window to width and height. - */ - setMaximumSize(width: number, height: number): void; - /** - * @returns The window's maximum width and height. - */ - getMaximumSize(): number[]; - /** - * Sets whether the window can be manually resized by user. - */ - setResizable(resizable: boolean): void; - /** - * @returns Whether the window can be manually resized by user. - */ - isResizable(): boolean; - /** - * Sets whether the window can be moved by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setMovable(movable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be moved by user. On Linux always returns true. - */ - isMovable(): boolean; - /** - * Sets whether the window can be manually minimized by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setMinimizable(minimizable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be manually minimized by user. On Linux always returns true. - */ - isMinimizable(): boolean; - /** - * Sets whether the window can be manually maximized by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setMaximizable(maximizable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be manually maximized by user. On Linux always returns true. - */ - isMaximizable(): boolean; - /** - * Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. - */ - setFullScreenable(fullscreenable: boolean): void; - /** - * @returns Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. - */ - isFullScreenable(): boolean; - /** - * Sets whether the window can be manually closed by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setClosable(closable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be manually closed by user. On Linux always returns true. - */ - isClosable(): boolean; - /** - * Sets whether the window should show always on top of other windows. After - * setting this, the window is still a normal window, not a toolbox window - * which can not be focused on. - */ - setAlwaysOnTop(flag: boolean, level?: WindowLevel): void; - /** - * @returns Whether the window is always on top of other windows. - */ - isAlwaysOnTop(): boolean; - /** - * Moves window to the center of the screen. - */ - center(): void; - /** - * Moves window to x and y. - */ - setPosition(x: number, y: number, animate?: boolean): void; - /** - * @returns The window's current position. - */ - getPosition(): number[]; - /** - * Changes the title of native window to title. - */ - setTitle(title: string): void; - /** - * Note: The title of web page can be different from the title of the native window. - * @returns The title of the native window. - */ - getTitle(): string; - /** - * Changes the attachment point for sheets on macOS. - * Note: This API is available only on macOS. - */ - setSheetOffset(offsetY: number, offsetX?: number): void; - /** - * Starts or stops flashing the window to attract user's attention. - */ - flashFrame(flag: boolean): void; - /** - * Makes the window do not show in Taskbar. - */ - setSkipTaskbar(skip: boolean): void; - /** - * Enters or leaves the kiosk mode. - */ - setKiosk(flag: boolean): void; - /** - * @returns Whether the window is in kiosk mode. - */ - isKiosk(): boolean; - /** - * The native type of the handle is HWND on Windows, NSView* on macOS, - * and Window (unsigned long) on Linux. - * @returns The platform-specific handle of the window as Buffer. - */ - getNativeWindowHandle(): Buffer; - /** - * Hooks a windows message. The callback is called when the message is received in the WndProc. - * Note: This API is available only on Windows. - */ - hookWindowMessage(message: number, callback: Function): void; - /** - * @returns Whether the message is hooked. - */ - isWindowMessageHooked(message: number): boolean; - /** - * Unhook the window message. - */ - unhookWindowMessage(message: number): void; - /** - * Unhooks all of the window messages. - */ - unhookAllWindowMessages(): void; - /** - * Sets the pathname of the file the window represents, and the icon of the - * file will show in window's title bar. - * Note: This API is available only on macOS. - */ - setRepresentedFilename(filename: string): void; - /** - * Note: This API is available only on macOS. - * @returns The pathname of the file the window represents. - */ - getRepresentedFilename(): string; - /** - * Specifies whether the window’s document has been edited, and the icon in - * title bar will become grey when set to true. - * Note: This API is available only on macOS. - */ - setDocumentEdited(edited: boolean): void; - /** - * Note: This API is available only on macOS. - * @returns Whether the window's document has been edited. - */ - isDocumentEdited(): boolean; - focusOnWebView(): void; - blurWebView(): void; - /** - * Captures the snapshot of page within rect, upon completion the callback - * will be called. Omitting the rect would capture the whole visible page. - * Note: Be sure to read documents on remote buffer in remote if you are going - * to use this API in renderer process. - * @param callback Supplies the image that stores data of the snapshot. - */ - capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; - /** - * Captures the snapshot of page within rect, upon completion the callback - * will be called. Omitting the rect would capture the whole visible page. - * Note: Be sure to read documents on remote buffer in remote if you are going - * to use this API in renderer process. - * @param callback Supplies the image that stores data of the snapshot. - */ - capturePage(callback: (image: NativeImage) => void): void; - /** - * Same as webContents.loadURL(url). - */ - loadURL(url: string, options?: LoadURLOptions): void; - /** - * Same as webContents.reload. - */ - reload(): void; - /** - * Sets the menu as the window top menu. - * Note: This API is not available on macOS. - */ - setMenu(menu: Menu): void; - /** - * Sets the progress value in the progress bar. - * On Linux platform, only supports Unity desktop environment, you need to - * specify the *.desktop file name to desktopName field in package.json. - * By default, it will assume app.getName().desktop. - * @param progress Valid range is [0, 1.0]. If < 0, the progress bar is removed. - * If greater than 0, it becomes indeterminate. - */ - setProgressBar(progress: number, options?: { - /** - * Mode for the progress bar. - * Note: This is only implemented on Windows. - */ - mode: 'none' | 'normal' | 'indeterminate' | 'error' | 'paused' - }): void; - /** - * Sets a 16px overlay onto the current Taskbar icon, usually used to convey - * some sort of application status or to passively notify the user. - * Note: This API is only available on Windows 7 or above. - * @param overlay The icon to display on the bottom right corner of the Taskbar - * icon. If this parameter is null, the overlay is cleared - * @param description Provided to Accessibility screen readers. - */ - setOverlayIcon(overlay: NativeImage, description: string): void; - /** - * Sets whether the window should have a shadow. On Windows and Linux does nothing. - * Note: This API is available only on macOS. - */ - setHasShadow(hasShadow: boolean): void; - /** - * Note: This API is available only on macOS. - * @returns whether the window has a shadow. On Windows and Linux always returns true. - */ - hasShadow(): boolean; - /** - * Add a thumbnail toolbar with a specified set of buttons to the thumbnail image - * of a window in a taskbar button layout. - * @returns Whether the thumbnail has been added successfully. - * - * Note: This API is available only on Windows. - */ - setThumbarButtons(buttons: ThumbarButton[]): boolean; - /** - * Sets the region of the window to show as the thumbnail image displayed when hovering - * over the window in the taskbar. You can reset the thumbnail to be the entire window - * by specifying an empty region: {x: 0, y: 0, width: 0, height: 0}. - * - * Note: This API is available only on Windows. - */ - setThumbnailClip(region: Rectangle): boolean; - /** - * Sets the toolTip that is displayed when hovering over the window thumbnail in the taskbar. - * Note: This API is available only on Windows. - */ - setThumbnailToolTip(toolTip: string): boolean; - /** - * Sets the application id, app icon, relaunch command and relaunch display name - * for the given window. appIconIndex should be set to 0 if the app icon - * file only has a single icon. - */ - setAppDetails(options: { - appId?: string; - appIconPath?: string; - appIconIndex?: number; - relaunchCommand?: string; - relaunchDisplayName?: string; - }): void; - /** - * Same as webContents.showDefinitionForSelection(). - * Note: This API is available only on macOS. - */ - showDefinitionForSelection(): void; - /** - * Changes window icon. - * Note: This API is not available on macOS. - */ - setIcon(icon: NativeImage): void; - /** - * Sets whether the window menu bar should hide itself automatically. Once set - * the menu bar will only show when users press the single Alt key. - * If the menu bar is already visible, calling setAutoHideMenuBar(true) won't - * hide it immediately. - */ - setAutoHideMenuBar(hide: boolean): void; - /** - * @returns Whether menu bar automatically hides itself. - */ - isMenuBarAutoHide(): boolean; - /** - * Sets whether the menu bar should be visible. If the menu bar is auto-hide, - * users can still bring up the menu bar by pressing the single Alt key. - */ - setMenuBarVisibility(visibile: boolean): void; - /** - * @returns Whether the menu bar is visible. - */ - isMenuBarVisible(): boolean; - /** - * Sets whether the window should be visible on all workspaces. - * Note: This API does nothing on Windows. - */ - setVisibleOnAllWorkspaces(visible: boolean): void; - /** - * Note: This API always returns false on Windows. - * @returns Whether the window is visible on all workspaces. - */ - isVisibleOnAllWorkspaces(): boolean; - /** - * Makes the window ignore all mouse events. - * - * All mouse events happened in this window will be passed to the window below this window, - * but if this window has focus, it will still receive keyboard events. - */ - setIgnoreMouseEvents(ignore: boolean): void; - /** - * Prevents the window contents from being captured by other apps. - * - * On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. - * On Windows it calls SetWindowDisplayAffinity with WDA_MONITOR. - */ - setContentProtection(enable: boolean): void; - /** - * Changes whether the window can be focused. - * Note: This API is available only on Windows. - */ - setFocusable(focusable: boolean): void; - /** - * Sets parent as current window's parent window, - * passing null will turn current window into a top-level window. - * Note: This API is not available on Windows. - */ - setParentWindow(parent: BrowserWindow): void; - /** - * @returns The parent window. - */ - getParentWindow(): BrowserWindow; - /** - * @returns All child windows. - */ - getChildWindows(): BrowserWindow[]; - } - - type WindowLevel = 'normal' | 'floating' | 'torn-off-menu' | 'modal-panel' | 'main-menu' | 'status' | 'pop-up-menu' | 'screen-saver' | 'dock'; - type SwipeDirection = 'up' | 'right' | 'down' | 'left'; - type ThumbarButtonFlags = 'enabled' | 'disabled' | 'dismissonclick' | 'nobackground' | 'hidden' | 'noninteractive'; - - interface ThumbarButton { - icon: NativeImage | string; - click: Function; - tooltip?: string; - flags?: ThumbarButtonFlags[]; - } - - interface DevToolsExtensions { - [name: string]: { - name: string; - value: string; - } - } - - interface WebPreferences { - /** - * Whether to enable DevTools. - * If it is set to false, can not use BrowserWindow.webContents.openDevTools() to open DevTools. - * Default: true. - */ - devTools?: boolean; - /** - * Whether node integration is enabled. - * Default: true. - */ - nodeIntegration?: boolean; - /** - * Specifies a script that will be loaded before other scripts run in the page. - * This script will always have access to node APIs no matter whether node integration is turned on or off. - * The value should be the absolute file path to the script. - * When node integration is turned off, the preload script can reintroduce - * Node global symbols back to the global scope. - */ - preload?: string; - /** - * Sets the session used by the page. Instead of passing the Session object directly, - * you can also choose to use the partition option instead, which accepts a partition string. - * When both session and partition are provided, session would be preferred. - * Default: the default session. - */ - session?: Session; - /** - * Sets the session used by the page according to the session’s partition string. - * If partition starts with persist:, the page will use a persistent session available - * to all pages in the app with the same partition. if there is no persist: prefix, - * the page will use an in-memory session. By assigning the same partition, - * multiple pages can share the same session. - * Default: the default session. - */ - partition?: string; - /** - * The default zoom factor of the page, 3.0 represents 300%. - * Default: 1.0. - */ - zoomFactor?: number; - /** - * Enables JavaScript support. - * Default: true. - */ - javascript?: boolean; - /** - * When setting false, it will disable the same-origin policy (Usually using testing - * websites by people), and set allowDisplayingInsecureContent and allowRunningInsecureContent - * to true if these two options are not set by user. - * Default: true. - */ - webSecurity?: boolean; - /** - * Allow an https page to display content like images from http URLs. - * Default: false. - */ - allowDisplayingInsecureContent?: boolean; - /** - * Allow a https page to run JavaScript, CSS or plugins from http URLs. - * Default: false. - */ - allowRunningInsecureContent?: boolean; - /** - * Enables image support. - * Default: true. - */ - images?: boolean; - /** - * Make TextArea elements resizable. - * Default: true. - */ - textAreasAreResizable?: boolean; - /** - * Enables WebGL support. - * Default: true. - */ - webgl?: boolean; - /** - * Enables WebAudio support. - * Default: true. - */ - webaudio?: boolean; - /** - * Whether plugins should be enabled. - * Default: false. - */ - plugins?: boolean; - /** - * Enables Chromium’s experimental features. - * Default: false. - */ - experimentalFeatures?: boolean; - /** - * Enables Chromium’s experimental canvas features. - * Default: false. - */ - experimentalCanvasFeatures?: boolean; - /** - * Enables DirectWrite font rendering system on Windows. - * Default: true. - */ - directWrite?: boolean; - /** - * Enables scroll bounce (rubber banding) effect on macOS. - * Default: false. - */ - scrollBounce?: boolean; - /** - * A list of feature strings separated by ",", like CSSVariables,KeyboardEventKey to enable. - */ - blinkFeatures?: string; - /** - * A list of feature strings separated by ",", like CSSVariables,KeyboardEventKey to disable. - */ - disableBlinkFeatures?: string; - /** - * Sets the default font for the font-family. - */ - defaultFontFamily?: { - /** - * Default: Times New Roman. - */ - standard?: string; - /** - * Default: Times New Roman. - */ - serif?: string; - /** - * Default: Arial. - */ - sansSerif?: string; - /** - * Default: Courier New. - */ - monospace?: string; - }; - /** - * Default: 16. - */ - defaultFontSize?: number; - /** - * Default: 13. - */ - defaultMonospaceFontSize?: number; - /** - * Default: 0. - */ - minimumFontSize?: number; - /** - * Default: ISO-8859-1. - */ - defaultEncoding?: string; - /** - * Whether to throttle animations and timers when the page becomes background. - * Default: true. - */ - backgroundThrottling?: boolean; - /** - * Whether to enable offscreen rendering for the browser window. - * Default: false. - */ - offscreen?: boolean; - /** - * Whether to enable Chromium OS-level sandbox. - * Default: false. - */ - sandbox?: boolean; - } - - interface BrowserWindowOptions { - /** - * Window’s width in pixels. - * Default: 800. + * Defaults to 0. Required if a bitmap buffer is specified as buffer. */ width?: number; /** - * Window’s height in pixels. - * Default: 600. + * Defaults to 0. Required if a bitmap buffer is specified as buffer. */ height?: number; /** - * Window’s left offset from screen. - * Default: center the window. + * The buffer containing the raw image data. + */ + buffer?: Buffer; + /** + * The data URL containing either a base 64 encoded PNG or JPEG image. + */ + dataURL?: string; + } + + interface AppDetailsOptions { + /** + * Window's . It has to be set, otherwise the other options will have no effect. + */ + appId?: string; + /** + * Window's . + */ + appIconPath?: string; + /** + * Index of the icon in appIconPath. Ignored when appIconPath is not set. Default + * is 0. + */ + appIconIndex?: number; + /** + * Window's . + */ + relaunchCommand?: string; + /** + * Window's . + */ + relaunchDisplayName?: string; + } + + interface AuthInfo { + isProxy: boolean; + scheme: string; + host: string; + port: number; + realm: string; + } + + interface AutoResizeOptions { + /** + * If true, the view's width will grow and shrink together with the window. false + * by default. + */ + width: boolean; + /** + * If true, the view's height will grow and shrink together with the window. false + * by default. + */ + height: boolean; + } + + interface BitmapOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface BrowserViewConstructorOptions { + /** + * See . + */ + webPreferences?: WebPreferences; + } + + interface BrowserWindowConstructorOptions { + /** + * Window's width in pixels. Default is 800. + */ + width?: number; + /** + * Window's height in pixels. Default is 600. + */ + height?: number; + /** + * ( if y is used) Window's left offset from screen. Default is to center the + * window. */ x?: number; /** - * Window’s top offset from screen. - * Default: center the window. + * ( if x is used) Window's top offset from screen. Default is to center the + * window. */ y?: number; /** - * The width and height would be used as web page’s size, which means - * the actual window’s size will include window frame’s size and be slightly larger. - * Default: false. + * The width and height would be used as web page's size, which means the actual + * window's size will include window frame's size and be slightly larger. Default + * is false. */ useContentSize?: boolean; /** * Show window in the center of the screen. - * Default: true */ center?: boolean; /** - * Window’s minimum width. - * Default: 0. + * Window's minimum width. Default is 0. */ minWidth?: number; /** - * Window’s minimum height. - * Default: 0. + * Window's minimum height. Default is 0. */ minHeight?: number; /** - * Window’s maximum width. - * Default: no limit. + * Window's maximum width. Default is no limit. */ maxWidth?: number; /** - * Window’s maximum height. - * Default: no limit. + * Window's maximum height. Default is no limit. */ maxHeight?: number; /** - * Whether window is resizable. - * Default: true. + * Whether window is resizable. Default is true. */ resizable?: boolean; /** - * Whether window is movable. - * Note: This is not implemented on Linux. - * Default: true. + * Whether window is movable. This is not implemented on Linux. Default is true. */ movable?: boolean; /** - * Whether window is minimizable. - * Note: This is not implemented on Linux. - * Default: true. + * Whether window is minimizable. This is not implemented on Linux. Default is + * true. */ minimizable?: boolean; /** - * Whether window is maximizable. - * Note: This is not implemented on Linux. - * Default: true. + * Whether window is maximizable. This is not implemented on Linux. Default is + * true. */ maximizable?: boolean; /** - * Whether window is closable. - * Note: This is not implemented on Linux. - * Default: true. + * Whether window is closable. This is not implemented on Linux. Default is true. */ closable?: boolean; /** - * Whether the window can be focused. - * On Windows setting focusable: false also implies setting skipTaskbar: true. - * On Linux setting focusable: false makes the window stop interacting with wm, - * so the window will always stay on top in all workspaces. - * Default: true. + * Whether the window can be focused. Default is true. On Windows setting + * focusable: false also implies setting skipTaskbar: true. On Linux setting + * focusable: false makes the window stop interacting with wm, so the window will + * always stay on top in all workspaces. */ focusable?: boolean; /** - * Whether the window should always stay on top of other windows. - * Default: false. + * Whether the window should always stay on top of other windows. Default is false. */ alwaysOnTop?: boolean; /** - * Whether the window should show in fullscreen. - * When explicitly set to false the fullscreen button will be hidden or disabled on macOS. - * Default: false. + * Whether the window should show in fullscreen. When explicitly set to false the + * fullscreen button will be hidden or disabled on macOS. Default is false. */ fullscreen?: boolean; /** - * Whether the window can be put into fullscreen mode. - * On macOS, also whether the maximize/zoom button should toggle full screen mode or maximize window. - * Default: true. + * Whether the window can be put into fullscreen mode. On macOS, also whether the + * maximize/zoom button should toggle full screen mode or maximize window. Default + * is true. */ fullscreenable?: boolean; /** - * Whether to show the window in taskbar. - * Default: false. + * Whether to show the window in taskbar. Default is false. */ skipTaskbar?: boolean; /** - * The kiosk mode. - * Default: false. + * The kiosk mode. Default is false. */ kiosk?: boolean; /** - * Default window title. - * Default: "Electron". + * Default window title. Default is "Electron". */ title?: string; /** - * The window icon, when omitted on Windows the executable’s icon would be used as window icon. + * The window icon. On Windows it is recommended to use ICO icons to get best + * visual effects, you can also leave it undefined so the executable's icon will be + * used. */ icon?: NativeImage | string; /** - * Whether window should be shown when created. - * Default: true. + * Whether window should be shown when created. Default is true. */ show?: boolean; /** - * Specify false to create a Frameless Window. - * Default: true. + * Specify false to create a . Default is true. */ frame?: boolean; /** - * Specify parent window. - * Default: null. + * Specify parent window. Default is null. */ parent?: BrowserWindow; /** - * Whether this is a modal window. This only works when the window is a child window. - * Default: false. + * Whether this is a modal window. This only works when the window is a child + * window. Default is false. */ modal?: boolean; /** - * Whether the web view accepts a single mouse-down event that simultaneously activates the window. - * Default: false. + * Whether the web view accepts a single mouse-down event that simultaneously + * activates the window. Default is false. */ acceptFirstMouse?: boolean; /** - * Whether to hide cursor when typing. - * Default: false. + * Whether to hide cursor when typing. Default is false. */ disableAutoHideCursor?: boolean; /** - * Auto hide the menu bar unless the Alt key is pressed. - * Default: true. + * Auto hide the menu bar unless the Alt key is pressed. Default is false. */ autoHideMenuBar?: boolean; /** - * Enable the window to be resized larger than screen. - * Default: false. + * Enable the window to be resized larger than screen. Default is false. */ enableLargerThanScreen?: boolean; /** - * Window’s background color as Hexadecimal value, like #66CD00 or #FFF or #80FFFFFF (alpha is supported). - * Default: #FFF (white). + * Window's background color as Hexadecimal value, like #66CD00 or #FFF or + * #80FFFFFF (alpha is supported). Default is #FFF (white). */ backgroundColor?: string; /** - * Whether window should have a shadow. - * Note: This is only implemented on macOS. - * Default: true. + * Whether window should have a shadow. This is only implemented on macOS. Default + * is true. */ hasShadow?: boolean; /** - * Forces using dark theme for the window. - * Note: Only works on some GTK+3 desktop environments. - * Default: false. + * Forces using dark theme for the window, only works on some GTK+3 desktop + * environments. Default is false. */ darkTheme?: boolean; /** - * Makes the window transparent. - * Default: false. + * Makes the window . Default is false. */ transparent?: boolean; /** - * The type of window, default is normal window. + * The type of window, default is normal window. See more about this below. */ - type?: BrowserWindowType; + type?: string; /** - * The style of window title bar. + * The style of window title bar. Default is default. Possible values are: */ - titleBarStyle?: 'default' | 'hidden' | 'hidden-inset'; + titleBarStyle?: ('default' | 'hidden' | 'hidden-inset' | 'hiddenInset' | 'customButtonsOnHover'); /** - * Use WS_THICKFRAME style for frameless windows on Windows + * Shows the title in the tile bar in full screen mode on macOS for all + * titleBarStyle options. Default is false. + */ + fullscreenWindowTitle?: boolean; + /** + * Use WS_THICKFRAME style for frameless windows on Windows, which adds standard + * window frame. Setting it to false will remove window shadow and window + * animations. Default is true. */ thickFrame?: boolean; /** - * Settings of web page’s features. + * Add a type of vibrancy effect to the window, only on macOS. Can be + * appearance-based, light, dark, titlebar, selection, menu, popover, sidebar, + * medium-light or ultra-dark. */ - webPreferences?: WebPreferences; + vibrancy?: ('appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark'); + /** + * Controls the behavior on macOS when option-clicking the green stoplight button + * on the toolbar or by clicking the Window > Zoom menu item. If true, the window + * will grow to the preferred width of the web page when zoomed, false will cause + * it to zoom to the width of the screen. This will also affect the behavior when + * calling maximize() directly. Default is false. + */ + zoomToPageWidth?: boolean; /** * Tab group name, allows opening the window as a native tab on macOS 10.12+. - * Windows with the same tabbing identifier will be grouped together. + * Windows with the same tabbing identifier will be grouped together. This also + * adds a native new tab button to your window's tab bar and allows your app and + * window to receive the new-window-for-tab event. */ tabbingIdentifier?: string; + /** + * Settings of web page's features. + */ + webPreferences?: WebPreferences; } - type BrowserWindowType = BrowserWindowTypeLinux | BrowserWindowTypeMac | BrowserWindowTypeWindows; - type BrowserWindowTypeLinux = 'desktop' | 'dock' | 'toolbar' | 'splash' | 'notification'; - type BrowserWindowTypeMac = 'desktop' | 'textured'; - type BrowserWindowTypeWindows = 'toolbar'; - - // https://github.com/electron/electron/blob/master/docs/api/clipboard.md - - /** - * The clipboard module provides methods to perform copy and paste operations. - */ - interface Clipboard { + interface CertificateTrustDialogOptions { /** - * @returns The contents of the clipboard as plain text. + * The certificate to trust/import. */ - readText(type?: ClipboardType): string; + certificate: Certificate; /** - * Writes the text into the clipboard as plain text. + * The message to display to the user. */ - writeText(text: string, type?: ClipboardType): void; - /** - * @returns The contents of the clipboard as markup. - */ - readHTML(type?: ClipboardType): string; - /** - * Writes markup to the clipboard. - */ - writeHTML(markup: string, type?: ClipboardType): void; - /** - * @returns The contents of the clipboard as a NativeImage. - */ - readImage(type?: ClipboardType): NativeImage; - /** - * Writes the image into the clipboard. - */ - writeImage(image: NativeImage, type?: ClipboardType): void; - /** - * @returns The contents of the clipboard as RTF. - */ - readRTF(type?: ClipboardType): string; - /** - * Writes the text into the clipboard in RTF. - */ - writeRTF(text: string, type?: ClipboardType): void; - /** - * Clears everything in clipboard. - */ - clear(type?: ClipboardType): void; - /** - * @returns Array available formats for the clipboard type. - */ - availableFormats(type?: ClipboardType): string[]; - /** - * Returns whether the clipboard supports the format of specified data. - * Note: This API is experimental and could be removed in future. - * @returns Whether the clipboard has data in the specified format. - */ - has(format: string, type?: ClipboardType): boolean; - /** - * Reads the data in the clipboard of the specified format. - * Note: This API is experimental and could be removed in future. - */ - read(format: string, type?: ClipboardType): string | NativeImage; - /** - * Writes data to the clipboard. - */ - write(data: { - text?: string; - rtf?: string; - html?: string; - image?: NativeImage; - }, type?: ClipboardType): void; - /** - * @returns An Object containing title and url keys representing the bookmark in the clipboard. - * - * Note: This API is available on macOS and Windows. - */ - readBookmark(): Bookmark; - /** - * Writes the title and url into the clipboard as a bookmark. - * - * Note: This API is available on macOS and Windows. - */ - writeBookmark(title: string, url: string, type?: ClipboardType): void; - /** - * The text on the find pasteboard. This method uses synchronous IPC when called from the renderer process. - * The cached value is reread from the find pasteboard whenever the application is activated. - * - * Note: This API is available on macOS. - */ - readFindText(): string; - /** - * Writes the text into the find pasteboard as plain text. - * This method uses synchronous IPC when called from the renderer process. - * - * Note: This API is available on macOS. - */ - writeFindText(text: string): void; + message: string; } - type ClipboardType = '' | 'selection'; - - interface Bookmark { - title: string; - url: string; - } - - // https://github.com/electron/electron/blob/master/docs/api/content-tracing.md - - /** - * The content-tracing module is used to collect tracing data generated by the underlying Chromium content module. - * This module does not include a web interface so you need to open chrome://tracing/ - * in a Chrome browser and load the generated file to view the result. - */ - interface ContentTracing { + interface CertificateVerifyProcRequest { + hostname: string; + certificate: Certificate; /** - * Get a set of category groups. The category groups can change as new code paths are reached. - * - * @param callback Called once all child processes have acknowledged the getCategories request. + * Verification result from chromium. */ - getCategories(callback: (categoryGroups: string[]) => void): void; - /** - * Start recording on all processes. Recording begins immediately locally and asynchronously - * on child processes as soon as they receive the EnableRecording request. - * - * @param callback Called once all child processes have acknowledged the startRecording request. - */ - startRecording(options: ContentTracingOptions, callback: Function): void; - /** - * Stop recording on all processes. Child processes typically are caching trace data and - * only rarely flush and send trace data back to the main process. That is because it may - * be an expensive operation to send the trace data over IPC, and we would like to avoid - * much runtime overhead of tracing. So, to end tracing, we must asynchronously ask all - * child processes to flush any pending trace data. - * - * @param resultFilePath Trace data will be written into this file if it is not empty, - * or into a temporary file. - * @param callback Called once all child processes have acknowledged the stopRecording request. - */ - stopRecording(resultFilePath: string, callback: (filePath: string) => void): void; - /** - * Start monitoring on all processes. Monitoring begins immediately locally and asynchronously - * on child processes as soon as they receive the startMonitoring request. - * - * @param callback Called once all child processes have acked to the startMonitoring request. - */ - startMonitoring(options: ContentTracingOptions, callback: Function): void; - /** - * Stop monitoring on all processes. - * - * @param callback Called once all child processes have acknowledged the stopMonitoring request. - */ - stopMonitoring(callback: Function): void; - /** - * Get the current monitoring traced data. Child processes typically are caching trace data - * and only rarely flush and send trace data back to the main process. That is because it may - * be an expensive operation to send the trace data over IPC, and we would like to avoid much - * runtime overhead of tracing. So, to end tracing, we must asynchronously ask all child - * processes to flush any pending trace data. - * - * @param callback Called once all child processes have acknowledged the captureMonitoringSnapshot request. - */ - captureMonitoringSnapshot(resultFilePath: string, callback: (filePath: string) => void): void; - /** - * Get the maximum usage across processes of trace buffer as a percentage of the full state. - * - * @param callback Called when the TraceBufferUsage value is determined. - */ - getTraceBufferUsage(callback: Function): void; - /** - * @param callback Called every time the given event occurs on any process. - */ - setWatchEvent(categoryName: string, eventName: string, callback: Function): void; - /** - * Cancel the watch event. This may lead to a race condition with the watch event callback if tracing is enabled. - */ - cancelWatchEvent(): void; - } - - interface ContentTracingOptions { - /** - * Filter to control what category groups should be traced. - * A filter can have an optional - prefix to exclude category groups - * that contain a matching category. Having both included and excluded - * category patterns in the same list is not supported. - * - * Examples: - * test_MyTest* - * test_MyTest*,test_OtherStuff - * -excluded_category1,-excluded_category2 - */ - categoryFilter: string; - /** - * Controls what kind of tracing is enabled, it is a comma-delimited list. - * - * Possible options are: - * record-until-full - * record-continuously - * trace-to-console - * enable-sampling - * enable-systrace - * - * The first 3 options are trace recoding modes and hence mutually exclusive. - * If more than one trace recording modes appear in the traceOptions string, - * the last one takes precedence. If none of the trace recording modes are specified, - * recording mode is record-until-full. - * - * The trace option will first be reset to the default option (record_mode set - * to record-until-full, enable_sampling and enable_systrace set to false) - * before options parsed from traceOptions are applied on it. - */ - traceOptions: string; - } - - // https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md - - /** - * The crash-reporter module enables sending your app's crash reports. - */ - interface CrashReporter { - /** - * You are required to call this method before using other crashReporter APIs. - * - * Note: On macOS, Electron uses a new crashpad client, which is different from breakpad - * on Windows and Linux. To enable the crash collection feature, you are required to call - * the crashReporter.start API to initialize crashpad in the main process and in each - * renderer process from which you wish to collect crash reports. - */ - start(options: CrashReporterStartOptions): void; - /** - * @returns The crash report. When there was no crash report - * sent or the crash reporter is not started, null will be returned. - */ - getLastCrashReport(): CrashReport; - /** - * @returns All uploaded crash reports. - */ - getUploadedReports(): CrashReport[]; - } - - interface CrashReporterStartOptions { - /** - * Default: app.getName() - */ - productName?: string; - companyName: string; - /** - * URL that crash reports would be sent to as POST. - */ - submitURL: string; - /** - * Send the crash report without user interaction. - * Default: true. - */ - autoSubmit?: boolean; - /** - * Default: false. - */ - ignoreSystemCrashHandler?: boolean; - /** - * An object you can define that will be sent along with the report. - * Only string properties are sent correctly, nested objects are not supported. - */ - extra?: { [prop: string]: string }; - - /** - * Path to a folder where the crashes will be temporarily stored by the electron crash reporter - * Applies only to child processes that need crash reporting. - * Electron figures out the crashesDirectory on its own for Main and Renderer process - */ - crashesDirectory?: string; - } - - interface CrashReport { - id: string; - date: Date; - } - - // https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md - - /** - * The desktopCapturer module can be used to get available sources - * that can be used to be captured with getUserMedia. - */ - interface DesktopCapturer { - /** - * Starts a request to get all desktop sources. - * - * Note: There is no guarantee that the size of source.thumbnail is always - * the same as the thumnbailSize in options. It also depends on the scale of the screen or window. - */ - getSources(options: DesktopCapturerOptions, callback: (error: Error, sources: DesktopCapturerSource[]) => any): void; - } - - interface DesktopCapturerOptions { - /** - * The types of desktop sources to be captured. - */ - types?: ('screen' | 'window')[]; - /** - * The suggested size that thumbnail should be scaled. - * Default: {width: 150, height: 150} - */ - thumbnailSize?: Size; - } - - interface DesktopCapturerSource { - /** - * The id of the captured window or screen used in navigator.webkitGetUserMedia. - * The format looks like window:XX or screen:XX where XX is a random generated number. - */ - id: string; - /** - * The described name of the capturing screen or window. - * If the source is a screen, the name will be Entire Screen or Screen ; - * if it is a window, the name will be the window’s title. - */ - name: string; - /** - * A thumbnail image. - */ - thumbnail: NativeImage; - } - - // https://github.com/electron/electron/blob/master/docs/api/dialog.md - - /** - * The dialog module provides APIs to show native system dialogs, such as opening files or alerting, - * so web applications can deliver the same user experience as native applications. - */ - interface Dialog { - /** - * Note: On Windows and Linux an open dialog can not be both a file selector and a directory selector, - * so if you set properties to ['openFile', 'openDirectory'] on these platforms, a directory selector will be shown. - * - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns an array of file paths chosen by the user, - * otherwise returns undefined. - */ - showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: (fileNames: string[]) => void): string[]; - /** - * Note: On Windows and Linux an open dialog can not be both a file selector and a directory selector, - * so if you set properties to ['openFile', 'openDirectory'] on these platforms, a directory selector will be shown. - * - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns an array of file paths chosen by the user, - * otherwise returns undefined. - */ - showOpenDialog(options: OpenDialogOptions, callback?: (fileNames: string[]) => void): string[]; - /** - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns the path of file chosen by the user, otherwise - * returns undefined. - */ - showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (fileName: string) => void): string; - /** - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns the path of file chosen by the user, otherwise - * returns undefined. - */ - showSaveDialog(options: SaveDialogOptions, callback?: (fileName: string) => void): string; - /** - * Shows a message box. It will block until the message box is closed. - * @param callback If supplied, the API call will be asynchronous. - * @returns The index of the clicked button. - */ - showMessageBox(browserWindow: BrowserWindow, options: ShowMessageBoxOptions, callback?: (response: number) => void): number; - /** - * Shows a message box. It will block until the message box is closed. - * @param callback If supplied, the API call will be asynchronous. - * @returns The index of the clicked button. - */ - showMessageBox(options: ShowMessageBoxOptions, callback?: (response: number) => void): number; - /** - * Displays a modal dialog that shows an error message. - * - * This API can be called safely before the ready event the app module emits, - * it is usually used to report errors in early stage of startup. - * If called before the app readyevent on Linux, the message will be emitted to stderr, - * and no GUI dialog will appear. - */ - showErrorBox(title: string, content: string): void; - } - - interface OpenDialogOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will be used. - */ - buttonLabel?: string; - /** - * File types that can be displayed or selected. - */ - filters?: { - name: string; - /** - * Extensions without wildcards or dots (e.g. 'png' is good but '.png' and '*.png' are bad). - * To show all files, use the '*' wildcard (no other wildcard is supported). - */ - extensions: string[]; - }[]; - /** - * Contains which features the dialog should use. - */ - properties?: ('openFile' | 'openDirectory' | 'multiSelections' | 'createDirectory' | 'showHiddenFiles')[]; - } - - interface SaveDialogOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will be used. - */ - buttonLabel?: string; - /** - * File types that can be displayed, see dialog.showOpenDialog for an example. - */ - filters?: { - name: string; - extensions: string[]; - }[]; - } - - interface ShowMessageBoxOptions { - /** - * On Windows, "question" displays the same icon as "info", unless you set an icon using the "icon" option. - */ - type?: 'none' | 'info' | 'error' | 'question' | 'warning'; - /** - * Texts for buttons. On Windows, an empty array will result in one button labeled "OK". - */ - buttons?: string[]; - /** - * Index of the button in the buttons array which will be selected by default when the message box opens. - */ - defaultId?: number; - /** - * Title of the message box (some platforms will not show it). - */ - title?: string; - /** - * Contents of the message box. - */ - message?: string; - /** - * Extra information of the message. - */ - detail?: string; - icon?: NativeImage; - /** - * The value will be returned when user cancels the dialog instead of clicking the buttons of the dialog. - * By default it is the index of the buttons that have "cancel" or "no" as label, - * or 0 if there is no such buttons. On macOS and Windows the index of "Cancel" button - * will always be used as cancelId, not matter whether it is already specified. - */ - cancelId?: number; - /** - * On Windows Electron will try to figure out which one of the buttons are common buttons - * (like "Cancel" or "Yes"), and show the others as command links in the dialog. - * This can make the dialog appear in the style of modern Windows apps. - * If you don’t like this behavior, you can set noLink to true. - */ - noLink?: boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/download-item.md - - /** - * DownloadItem represents a download item in Electron. - */ - interface DownloadItem extends NodeJS.EventEmitter { - /** - * Emitted when the download has been updated and is not done. - */ - on(event: 'updated', listener: (event: Event, state: 'progressing' | 'interrupted') => void): this; - /** - * Emits when the download is in a terminal state. This includes a completed download, - * a cancelled download (via downloadItem.cancel()), and interrupted download that can’t be resumed. - */ - on(event: 'done', listener: (event: Event, state: 'completed' | 'cancelled' | 'interrupted') => void): this; - on(event: string, listener: Function): this; - /** - * Set the save file path of the download item. - * Note: The API is only available in session’s will-download callback function. - * If user doesn’t set the save path via the API, Electron will use the original - * routine to determine the save path (Usually prompts a save dialog). - */ - setSavePath(path: string): void; - /** - * @returns The save path of the download item. - * This will be either the path set via downloadItem.setSavePath(path) or the path selected from the shown save dialog. - */ - getSavePath(): string; - /** - * Pauses the download. - */ - pause(): void; - /** - * @returns Whether the download is paused. - */ - isPaused(): boolean; - /** - * Resumes the download that has been paused. - */ - resume(): void; - /** - * @returns Whether the download can resume. - */ - canResume(): boolean; - /** - * Cancels the download operation. - */ - cancel(): void; - /** - * @returns The origin url where the item is downloaded from. - */ - getURL(): string; - /** - * @returns The mime type. - */ - getMimeType(): string; - /** - * @returns Whether the download has user gesture. - */ - hasUserGesture(): boolean; - /** - * @returns The file name of the download item. - * Note: The file name is not always the same as the actual one saved in local disk. - * If user changes the file name in a prompted download saving dialog, - * the actual name of saved file will be different. - */ - getFilename(): string; - /** - * @returns The total size in bytes of the download item. If the size is unknown, it returns 0. - */ - getTotalBytes(): number; - /** - * @returns The received bytes of the download item. - */ - getReceivedBytes(): number; - /** - * @returns The Content-Disposition field from the response header. - */ - getContentDisposition(): string; - /** - * @returns The current state. - */ - getState(): 'progressing' | 'completed' | 'cancelled' | 'interrupted'; - } - - // https://github.com/electron/electron/blob/master/docs/api/global-shortcut.md - - /** - * The globalShortcut module can register/unregister a global keyboard shortcut - * with the operating system so that you can customize the operations for various shortcuts. - * Note: The shortcut is global; it will work even if the app does not have the keyboard focus. - * You should not use this module until the ready event of the app module is emitted. - */ - interface GlobalShortcut { - /** - * Registers a global shortcut of accelerator. - * @param accelerator Represents a keyboard shortcut. It can contain modifiers - * and key codes, combined by the "+" character. - * @param callback Called when the registered shortcut is pressed by the user. - */ - register(accelerator: string, callback: Function): void; - /** - * @param accelerator Represents a keyboard shortcut. It can contain modifiers - * and key codes, combined by the "+" character. - * @returns Whether the accelerator is registered. - */ - isRegistered(accelerator: string): boolean; - /** - * Unregisters the global shortcut of keycode. - * @param accelerator Represents a keyboard shortcut. It can contain modifiers - * and key codes, combined by the "+" character. - */ - unregister(accelerator: string): void; - /** - * Unregisters all the global shortcuts. - */ - unregisterAll(): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/ipc-main.md - - /** - * The ipcMain module handles asynchronous and synchronous messages - * sent from a renderer process (web page). - * Messages sent from a renderer will be emitted to this module. - */ - interface IpcMain extends NodeJS.EventEmitter { - addListener(channel: string, listener: IpcMainEventListener): this; - on(channel: string, listener: IpcMainEventListener): this; - once(channel: string, listener: IpcMainEventListener): this; - removeListener(channel: string, listener: IpcMainEventListener): this; - removeAllListeners(channel?: string): this; - } - - type IpcMainEventListener = (event: IpcMainEvent, ...args: any[]) => void; - - interface IpcMainEvent { - /** - * Set this to the value to be returned in a synchronous message. - */ - returnValue?: any; - /** - * Returns the webContents that sent the message, you can call sender.send - * to reply to the asynchronous message. - */ - sender: WebContents; - } - - // https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md - - /** - * The ipcRenderer module provides a few methods so you can send synchronous - * and asynchronous messages from the render process (web page) to the main process. - * You can also receive replies from the main process. - */ - interface IpcRenderer extends NodeJS.EventEmitter { - addListener(channel: string, listener: IpcRendererEventListener): this; - on(channel: string, listener: IpcRendererEventListener): this; - once(channel: string, listener: IpcRendererEventListener): this; - removeListener(channel: string, listener: IpcRendererEventListener): this; - removeAllListeners(channel?: string): this; - /** - * Send ...args to the renderer via channel in asynchronous message, the main - * process can handle it by listening to the channel event of ipc module. - */ - send(channel: string, ...args: any[]): void; - /** - * Send ...args to the renderer via channel in synchronous message, and returns - * the result sent from main process. The main process can handle it by listening - * to the channel event of ipc module, and returns by setting event.returnValue. - * Note: Usually developers should never use this API, since sending synchronous - * message would block the whole renderer process. - * @returns The result sent from the main process. - */ - sendSync(channel: string, ...args: any[]): any; - /** - * Like ipc.send but the message will be sent to the host page instead of the main process. - * This is mainly used by the page in to communicate with host page. - */ - sendToHost(channel: string, ...args: any[]): void; - } - - type IpcRendererEventListener = (event: IpcRendererEvent, ...args: any[]) => void; - - interface IpcRendererEvent { - /** - * You can call sender.send to reply to the asynchronous message. - */ - sender: IpcRenderer; - } - - // https://github.com/electron/electron/blob/master/docs/api/menu-item.md - // https://github.com/electron/electron/blob/master/docs/api/accelerator.md - - /** - * The MenuItem allows you to add items to an application or context menu. - */ - class MenuItem { - /** - * Create a new menu item. - */ - constructor(options: MenuItemOptions); - - click: (menuItem: MenuItem, browserWindow: BrowserWindow, event: Event & Modifiers) => void; - /** - * Read-only property. - */ - type: MenuItemType; - /** - * Read-only property. - */ - role: MenuItemRole | MenuItemRoleMac; - /** - * Read-only property. - */ - accelerator: string; - /** - * Read-only property. - */ - icon: NativeImage | string; - /** - * Read-only property. - */ - submenu: Menu | MenuItemOptions[]; - - label: string; - sublabel: string; - enabled: boolean; - visible: boolean; - checked: boolean; - } - - type MenuItemType = 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'; - type MenuItemRole = 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteandmatchstyle' | 'selectall' | 'delete' | 'minimize' | 'close' | 'quit' | 'togglefullscreen' | 'resetzoom' | 'zoomin' | 'zoomout'; - type MenuItemRoleMac = 'about' | 'hide' | 'hideothers' | 'unhide' | 'startspeaking' | 'stopspeaking' | 'front' | 'zoom' | 'window' | 'help' | 'services'; - - interface MenuItemOptions { - /** - * Callback when the menu item is clicked. - */ - click?: (menuItem: MenuItem, browserWindow: BrowserWindow, event: Event & Modifiers) => void; - /** - * Can be normal, separator, submenu, checkbox or radio. - */ - type?: MenuItemType; - label?: string; - sublabel?: string; - /** - * An accelerator is string that represents a keyboard shortcut, it can contain - * multiple modifiers and key codes, combined by the + character. - * - * Examples: - * CommandOrControl+A - * CommandOrControl+Shift+Z - * - * Platform notice: - * On Linux and Windows, the Command key would not have any effect, - * you can use CommandOrControl which represents Command on macOS and Control on - * Linux and Windows to define some accelerators. - * - * Use Alt instead of Option. The Option key only exists on macOS, whereas - * the Alt key is available on all platforms. - * - * The Super key is mapped to the Windows key on Windows and Linux and Cmd on macOS. - * - * Available modifiers: - * Command (or Cmd for short) - * Control (or Ctrl for short) - * CommandOrControl (or CmdOrCtrl for short) - * Alt - * Option - * AltGr - * Shift - * Super - * - * Available key codes: - * 0 to 9 - * A to Z - * F1 to F24 - * Punctuations like ~, !, @, #, $, etc. - * Plus - * Space - * Tab - * Backspace - * Delete - * Insert - * Return (or Enter as alias) - * Up, Down, Left and Right - * Home and End - * PageUp and PageDown - * Escape (or Esc for short) - * VolumeUp, VolumeDown and VolumeMute - * MediaNextTrack, MediaPreviousTrack, MediaStop and MediaPlayPause - * PrintScreen - */ - accelerator?: string; - /** - * In Electron for the APIs that take images, you can pass either file paths - * or NativeImage instances. When passing null, an empty image will be used. - */ - icon?: NativeImage | string; - /** - * If false, the menu item will be greyed out and unclickable. - */ - enabled?: boolean; - /** - * If false, the menu item will be entirely hidden. - */ - visible?: boolean; - /** - * Should only be specified for 'checkbox' or 'radio' type menu items. - */ - checked?: boolean; - /** - * Should be specified for submenu type menu item, when it's specified the - * type: 'submenu' can be omitted for the menu item - */ - submenu?: Menu | MenuItemOptions[]; - /** - * Unique within a single menu. If defined then it can be used as a reference - * to this item by the position attribute. - */ - id?: string; - /** - * This field allows fine-grained definition of the specific location within - * a given menu. - */ - position?: string; - /** - * Define the action of the menu item, when specified the click property will be ignored - */ - role?: MenuItemRole | MenuItemRoleMac; - } - - // https://github.com/electron/electron/blob/master/docs/api/menu.md - - /** - * The Menu class is used to create native menus that can be used as application - * menus and context menus. This module is a main process module which can be used - * in a render process via the remote module. - * - * Each menu consists of multiple menu items, and each menu item can have a submenu. - */ - class Menu extends NodeJS.EventEmitter { - /** - * Creates a new menu. - */ - constructor(); - /** - * Sets menu as the application menu on macOS. On Windows and Linux, the menu - * will be set as each window's top menu. - */ - static setApplicationMenu(menu: Menu): void; - /** - * @returns The application menu if set, or null if not set. - */ - static getApplicationMenu(): Menu; - /** - * Sends the action to the first responder of application. - * This is used for emulating default Cocoa menu behaviors, - * usually you would just use the role property of MenuItem. - * - * Note: This method is macOS only. - */ - static sendActionToFirstResponder(action: string): void; - /** - * @param template Generally, just an array of options for constructing MenuItem. - * You can also attach other fields to element of the template, and they will - * become properties of the constructed menu items. - */ - static buildFromTemplate(template: MenuItemOptions[]): Menu; - /** - * Pops up this menu as a context menu in the browserWindow. You can optionally - * provide a (x,y) coordinate to place the menu at, otherwise it will be placed - * at the current mouse cursor position. - * @param x Horizontal coordinate where the menu will be placed. - * @param y Vertical coordinate where the menu will be placed. - */ - popup(browserWindow?: BrowserWindow, x?: number, y?: number): void; - /** - * Appends the menuItem to the menu. - */ - append(menuItem: MenuItem): void; - /** - * Inserts the menuItem to the pos position of the menu. - */ - insert(position: number, menuItem: MenuItem): void; - /** - * @returns an array containing the menu’s items. - */ - items: MenuItem[]; - } - - // https://github.com/electron/electron/blob/master/docs/api/native-image.md - - /** - * This class is used to represent an image. - */ - class NativeImage { - /** - * Creates an empty NativeImage instance. - */ - static createEmpty(): NativeImage; - /** - * Creates a new NativeImage instance from file located at path. - * This method returns an empty image if the path does not exist, cannot be read, or is not a valid image. - */ - static createFromPath(path: string): NativeImage; - /** - * Creates a new NativeImage instance from buffer. - * @param scaleFactor 1.0 by default. - */ - static createFromBuffer(buffer: Buffer, scaleFactor?: number): NativeImage; - /** - * Creates a new NativeImage instance from dataURL - */ - static createFromDataURL(dataURL: string): NativeImage; - /** - * @returns Buffer that contains the image's PNG encoded data. - */ - toPNG(): Buffer; - /** - * @returns Buffer that contains the image's JPEG encoded data. - */ - toJPEG(quality: number): Buffer; - /** - * @returns Buffer that contains a copy of the image's raw bitmap pixel data. - */ - toBitmap(): Buffer; - /** - * @returns Buffer that contains the image's raw bitmap pixel data. - * - * The difference between getBitmap() and toBitmap() is, getBitmap() does not copy the bitmap data, - * so you have to use the returned Buffer immediately in current event loop tick, - * otherwise the data might be changed or destroyed. - */ - getBitmap(): Buffer; - /** - * @returns The data URL of the image. - */ - toDataURL(): string; - /** - * The native type of the handle is NSImage* on macOS. - * Note: This is only implemented on macOS. - * @returns The platform-specific handle of the image as Buffer. - */ - getNativeHandle(): Buffer; - /** - * @returns Whether the image is empty. - */ - isEmpty(): boolean; - /** - * @returns The size of the image. - */ - getSize(): Size; - /** - * Marks the image as template image. - */ - setTemplateImage(option: boolean): void; - /** - * Returns a boolean whether the image is a template image. - */ - isTemplateImage(): boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/net.md - - /** - * The net module is a client-side API for issuing HTTP(S) requests. - * It is similar to the HTTP and HTTPS modules of Node.js but uses Chromium’s native - * networking library instead of the Node.js implementation, offering better support - * for web proxies. - * The following is a non-exhaustive list of why you may consider using the net module - * instead of the native Node.js modules: - * - Automatic management of system proxy configuration, support of the wpad protocol - * and proxy pac configuration files. - * - Automatic tunneling of HTTPS requests. - * - Support for authenticating proxies using basic, digest, NTLM, Kerberos or negotiate - * authentication schemes. - * - Support for traffic monitoring proxies: Fiddler-like proxies used for access control - * and monitoring. - * - * The net module API has been specifically designed to mimic, as closely as possible, - * the familiar Node.js API. The API components including classes, methods, - * properties and event names are similar to those commonly used in Node.js. - * - * The net API can be used only after the application emits the ready event. - * Trying to use the module before the ready event will throw an error. - */ - interface Net extends NodeJS.EventEmitter { - /** - * @param options The ClientRequest constructor options. - * @param callback A one time listener for the response event. - * - * @returns a ClientRequest instance using the provided options which are directly - * forwarded to the ClientRequest constructor. - */ - request(options: string | RequestOptions, callback?: (response: IncomingMessage) => void): ClientRequest; - } - - /** - * The RequestOptions interface allows to define various options for an HTTP request. - */ - interface RequestOptions { - /** - * The HTTP request method. Defaults to the GET method. - */ - method?: string; - /** - * The request URL. Must be provided in the absolute form with the protocol - * scheme specified as http or https. - */ - url?: string; - /** - * The Session instance with which the request is associated. - */ - session?: Session; - /** - * The name of the partition with which the request is associated. - * Defaults to the empty string. The session option prevails on partition. - * Thus if a session is explicitly specified, partition is ignored. - */ - partition?: string; - /** - * The protocol scheme in the form ā€˜scheme:’. Currently supported values are ā€˜http:’ or ā€˜https:’. - * Defaults to ā€˜http:’. - */ - Protocol?: 'http:' | 'https:'; - /** - * The server host provided as a concatenation of the hostname and the port number ā€˜hostname:port’. - */ - host?: string; - /** - * The server host name. - */ - hostname?: string; - /** - * The server’s listening port number. - */ - port?: number; - /** - * The path part of the request URL. - */ - path?: string; - /** - * A map specifying extra HTTP header name/value. - */ - headers?: { [key: string]: any }; - } - - /** - * The ClientRequest class represents an HTTP request. - */ - class ClientRequest extends NodeJS.EventEmitter { - /** - * Emitted when an HTTP response is received for the request. - */ - on(event: 'response', listener: (response: IncomingMessage) => void): this; - /** - * Emitted when an authenticating proxy is asking for user credentials. - * The callback function is expected to be called back with user credentials. - * Providing empty credentials will cancel the request and report an authentication - * error on the response object. - */ - on(event: 'login', listener: (authInfo: LoginAuthInfo, callback: (username?: string, password?: string) => void) => void): this; - /** - * Emitted just after the last chunk of the request’s data has been written into - * the request object. - */ - on(event: 'finish', listener: () => void): this; - /** - * Emitted when the request is aborted. The abort event will not be fired if the - * request is already closed. - */ - on(event: 'abort', listener: () => void): this; - /** - * Emitted when the net module fails to issue a network request. - * Typically when the request object emits an error event, a close event will - * subsequently follow and no response object will be provided. - */ - on(event: 'error', listener: (error: Error) => void): this; - /** - * Emitted as the last event in the HTTP request-response transaction. - * The close event indicates that no more events will be emitted on either the - * request or response objects. - */ - on(event: 'close', listener: () => void): this; - on(event: string, listener: Function): this; - /** - * A Boolean specifying whether the request will use HTTP chunked transfer encoding or not. - * Defaults to false. The property is readable and writable, however it can be set only before - * the first write operation as the HTTP headers are not yet put on the wire. - * Trying to set the chunkedEncoding property after the first write will throw an error. - * - * Using chunked encoding is strongly recommended if you need to send a large request - * body as data will be streamed in small chunks instead of being internally buffered - * inside Electron process memory. - */ - chunkedEncoding: boolean; - /** - * @param options If options is a String, it is interpreted as the request URL. - * If it is an object, it is expected to be a RequestOptions. - * @param callback A one time listener for the response event. - */ - constructor(options: string | RequestOptions, callback?: (response: IncomingMessage) => void); - /** - * Adds an extra HTTP header. The header name will issued as it is without lowercasing. - * It can be called only before first write. Calling this method after the first write - * will throw an error. - * @param name An extra HTTP header name. - * @param value An extra HTTP header value. - */ - setHeader(name: string, value: string): void; - /** - * @param name Specify an extra header name. - * @returns The value of a previously set extra header name. - */ - getHeader(name: string): string; - /** - * Removes a previously set extra header name. This method can be called only before first write. - * Trying to call it after the first write will throw an error. - * @param name Specify an extra header name. - */ - removeHeader(name: string): void; - /** - * Adds a chunk of data to the request body. The first write operation may cause the - * request headers to be issued on the wire. - * After the first write operation, it is not allowed to add or remove a custom header. - * @param chunk A chunk of the request body’s data. If it is a string, it is converted - * into a Buffer using the specified encoding. - * @param encoding Used to convert string chunks into Buffer objects. Defaults to ā€˜utf-8’. - * @param callback Called after the write operation ends. - */ - write(chunk: string | Buffer, encoding?: string, callback?: Function): boolean; - /** - * Sends the last chunk of the request data. Subsequent write or end operations will not be allowed. - * The finish event is emitted just after the end operation. - * @param chunk A chunk of the request body’s data. If it is a string, it is converted into - * a Buffer using the specified encoding. - * @param encoding Used to convert string chunks into Buffer objects. Defaults to ā€˜utf-8’. - * @param callback Called after the write operation ends. - * - */ - end(chunk?: string | Buffer, encoding?: string, callback?: Function): boolean; - /** - * Cancels an ongoing HTTP transaction. If the request has already emitted the close event, - * the abort operation will have no effect. - * Otherwise an ongoing event will emit abort and close events. - * Additionally, if there is an ongoing response object,it will emit the aborted event. - */ - abort(): void - } - - /** - * An IncomingMessage represents an HTTP response. - */ - interface IncomingMessage extends NodeJS.ReadableStream { - /** - * The data event is the usual method of transferring response data into applicative code. - */ - on(event: 'data', listener: (chunk: Buffer) => void): this; - /** - * Indicates that response body has ended. - */ - on(event: 'end', listener: () => void): this; - /** - * Emitted when a request has been canceled during an ongoing HTTP transaction. - */ - on(event: 'aborted', listener: () => void): this; - /** - * Emitted when an error was encountered while streaming response data events. - * For instance, if the server closes the underlying while the response is still - * streaming, an error event will be emitted on the response object and a close - * event will subsequently follow on the request object. - */ - on(event: 'error', listener: (error: Error) => void): this; - on(event: string, listener: Function): this; - /** - * An Integer indicating the HTTP response status code. - */ - statusCode: number; - /** - * A String representing the HTTP status message. - */ - statusMessage: string; - /** - * An object representing the response HTTP headers. The headers object is formatted as follows: - * - All header names are lowercased. - * - Each header name produces an array-valued property on the headers object. - * - Each header value is pushed into the array associated with its header name. - */ - headers: Headers; - /** - * A string indicating the HTTP protocol version number. Typical values are ā€˜1.0’ or ā€˜1.1’. - */ - httpVersion: string; - /** - * An integer-valued read-only property that returns the HTTP major version number. - */ - httpVersionMajor: number; - /** - * An integer-valued read-only property that returns the HTTP minor version number. - */ - httpVersionMinor: number; - } - - // https://github.com/electron/electron/blob/master/docs/api/power-monitor.md - - /** - * The power-monitor module is used to monitor power state changes. - * You should not use this module until the ready event of the app module is emitted. - */ - interface PowerMonitor extends NodeJS.EventEmitter { - /** - * Emitted when the system is suspending. - */ - on(event: 'suspend', listener: Function): this; - /** - * Emitted when system is resuming. - */ - on(event: 'resume', listener: Function): this; - /** - * Emitted when the system changes to AC power. - */ - on(event: 'on-ac', listener: Function): this; - /** - * Emitted when system changes to battery power. - */ - on(event: 'on-battery', listener: Function): this; - on(event: string, listener: Function): this; - } - - // https://github.com/electron/electron/blob/master/docs/api/power-save-blocker.md - - /** - * The powerSaveBlocker module is used to block the system from entering - * low-power (sleep) mode and thus allowing the app to keep the system and screen active. - */ - interface PowerSaveBlocker { - /** - * Starts preventing the system from entering lower-power mode. - * @returns The blocker ID that is assigned to this power blocker. - * Note: prevent-display-sleep has higher has precedence over prevent-app-suspension. - */ - start(type: 'prevent-app-suspension' | 'prevent-display-sleep'): number; - /** - * @param id The power save blocker id returned by powerSaveBlocker.start. - * Stops the specified power save blocker. - */ - stop(id: number): void; - /** - * @param id The power save blocker id returned by powerSaveBlocker.start. - * @returns Whether the corresponding powerSaveBlocker has started. - */ - isStarted(id: number): boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/protocol.md - - /** - * The protocol module can register a custom protocol or intercept an existing protocol. - */ - interface Protocol { - /** - * Registers custom schemes as standard schemes. - */ - registerStandardSchemes(schemes: string[]): void; - /** - * Registers custom schemes to handle service workers. - */ - registerServiceWorkerSchemes(schemes: string[]): void; - /** - * Registers a protocol of scheme that will send the file as a response. - */ - registerFileProtocol(scheme: string, handler: FileProtocolHandler, completion?: (error: Error) => void): void; - /** - * Registers a protocol of scheme that will send a Buffer as a response. - */ - registerBufferProtocol(scheme: string, handler: BufferProtocolHandler, completion?: (error: Error) => void): void; - /** - * Registers a protocol of scheme that will send a String as a response. - */ - registerStringProtocol(scheme: string, handler: StringProtocolHandler, completion?: (error: Error) => void): void; - /** - * Registers a protocol of scheme that will send an HTTP request as a response. - */ - registerHttpProtocol(scheme: string, handler: HttpProtocolHandler, completion?: (error: Error) => void): void; - /** - * Unregisters the custom protocol of scheme. - */ - unregisterProtocol(scheme: string, completion?: (error: Error) => void): void; - /** - * The callback will be called with a boolean that indicates whether there is already a handler for scheme. - */ - isProtocolHandled(scheme: string, callback: (handled: boolean) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a file as a response. - */ - interceptFileProtocol(scheme: string, handler: FileProtocolHandler, completion?: (error: Error) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a Buffer as a response. - */ - interceptBufferProtocol(scheme: string, handler: BufferProtocolHandler, completion?: (error: Error) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a String as a response. - */ - interceptStringProtocol(scheme: string, handler: StringProtocolHandler, completion?: (error: Error) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a new HTTP request as a response. - */ - interceptHttpProtocol(scheme: string, handler: HttpProtocolHandler, completion?: (error: Error) => void): void; - /** - * Remove the interceptor installed for scheme and restore its original handler. - */ - uninterceptProtocol(scheme: string, completion?: (error: Error) => void): void; - } - - type FileProtocolHandler = (request: ProtocolRequest, callback: FileProtocolCallback) => void; - type BufferProtocolHandler = (request: ProtocolRequest, callback: BufferProtocolCallback) => void; - type StringProtocolHandler = (request: ProtocolRequest, callback: StringProtocolCallback) => void; - type HttpProtocolHandler = (request: ProtocolRequest, callback: HttpProtocolCallback) => void; - - interface ProtocolRequest { - url: string; - referrer: string; - method: string; - uploadData?: { - /** - * Content being sent. - */ - bytes: Buffer, - /** - * Path of file being uploaded. - */ - file: string, - /** - * UUID of blob data. Use session.getBlobData method to retrieve the data. - */ - blobUUID: string; - }[]; - } - - interface ProtocolCallback { - (error: number): void; - (obj: { - error: number - }): void; - (): void; - } - - interface FileProtocolCallback extends ProtocolCallback { - (filePath: string): void; - (obj: { - path: string - }): void; - } - - interface BufferProtocolCallback extends ProtocolCallback { - (buffer: Buffer): void; - (obj: { - data: Buffer, - mimeType: string, - charset?: string - }): void; - } - - interface StringProtocolCallback extends ProtocolCallback { - (str: string): void; - (obj: { - data: string, - mimeType: string, - charset?: string - }): void; - } - - interface HttpProtocolCallback extends ProtocolCallback { - (redirectRequest: { - url: string; - method: string; - session?: Object; - uploadData?: { - contentType: string; - data: string; - }; - }): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/remote.md - - /** - * The remote module provides a simple way to do inter-process communication (IPC) - * between the renderer process (web page) and the main process. - */ - interface Remote extends CommonElectron { - /** - * @returns The object returned by require(module) in the main process. - */ - require(module: string): any; - /** - * @returns The BrowserWindow object which this web page belongs to. - */ - getCurrentWindow(): BrowserWindow; - /** - * @returns The WebContents object of this web page. - */ - getCurrentWebContents(): WebContents; - /** - * @returns The global variable of name (e.g. global[name]) in the main process. - */ - getGlobal(name: string): any; - /** - * Returns the process object in the main process. This is the same as - * remote.getGlobal('process'), but gets cached. - */ - process: NodeJS.Process; - } - - // https://github.com/electron/electron/blob/master/docs/api/screen.md - - /** - * The Display object represents a physical display connected to the system. - * A fake Display may exist on a headless system, or a Display may correspond to a remote, virtual display. - */ - interface Display { - /** - * Unique identifier associated with the display. - */ - id: number; - bounds: Rectangle; - workArea: Rectangle; - size: Size; - workAreaSize: Size; - /** - * Output device’s pixel scale factor. - */ - scaleFactor: number; - /** - * Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. - */ - rotation: number; - touchSupport: 'available' | 'unavailable' | 'unknown'; - } - - type DisplayMetrics = 'bounds' | 'workArea' | 'scaleFactor' | 'rotation'; - - /** - * The screen module retrieves information about screen size, displays, cursor position, etc. - * You can not use this module until the ready event of the app module is emitted. - */ - interface Screen extends NodeJS.EventEmitter { - /** - * Emitted when newDisplay has been added. - */ - on(event: 'display-added', listener: (event: Event, newDisplay: Display) => void): this; - /** - * Emitted when oldDisplay has been removed. - */ - on(event: 'display-removed', listener: (event: Event, oldDisplay: Display) => void): this; - /** - * Emitted when one or more metrics change in a display. - */ - on(event: 'display-metrics-changed', listener: (event: Event, display: Display, changedMetrics: DisplayMetrics[]) => void): this; - on(event: string, listener: Function): this; - /** - * @returns The current absolute position of the mouse pointer. - */ - getCursorScreenPoint(): Point; - /** - * @returns The primary display. - */ - getPrimaryDisplay(): Display; - /** - * @returns An array of displays that are currently available. - */ - getAllDisplays(): Display[]; - /** - * @returns The display nearest the specified point. - */ - getDisplayNearestPoint(point: Point): Display; - /** - * @returns The display that most closely intersects the provided bounds. - */ - getDisplayMatching(rect: Rectangle): Display; - } - - // https://github.com/electron/electron/blob/master/docs/api/session.md - - /** - * The session module can be used to create new Session objects. - * You can also access the session of existing pages by using - * the session property of webContents which is a property of BrowserWindow. - */ - class Session extends NodeJS.EventEmitter { - /** - * @returns a new Session instance from partition string. - */ - static fromPartition(partition: string, options?: FromPartitionOptions): Session; - /** - * @returns the default session object of the app. - */ - static defaultSession: Session; - /** - * Emitted when Electron is about to download item in webContents. - * Calling event.preventDefault() will cancel the download - * and item will not be available from next tick of the process. - */ - on(event: 'will-download', listener: (event: Event, item: DownloadItem, webContents: WebContents) => void): this; - on(event: string, listener: Function): this; - /** - * The cookies gives you ability to query and modify cookies. - */ - cookies: SessionCookies; - /** - * @returns the session’s current cache size. - */ - getCacheSize(callback: (size: number) => void): void; - /** - * Clears the session’s HTTP cache. - */ - clearCache(callback: Function): void; - /** - * Clears the data of web storages. - */ - clearStorageData(callback: Function): void; - /** - * Clears the data of web storages. - */ - clearStorageData(options: ClearStorageDataOptions, callback: Function): void; - /** - * Writes any unwritten DOMStorage data to disk. - */ - flushStorageData(): void; - /** - * Sets the proxy settings. - */ - setProxy(config: ProxyConfig, callback: Function): void; - /** - * Resolves the proxy information for url. - */ - resolveProxy(url: URL, callback: (proxy: string) => void): void; - /** - * Sets download saving directory. - * By default, the download directory will be the Downloads under the respective app folder. - */ - setDownloadPath(path: string): void; - /** - * Emulates network with the given configuration for the session. - */ - enableNetworkEmulation(options: NetworkEmulationOptions): void; - /** - * Disables any network emulation already active for the session. - * Resets to the original network configuration. - */ - disableNetworkEmulation(): void; - /** - * Sets the certificate verify proc for session, the proc will be called - * whenever a server certificate verification is requested. - * - * Calling setCertificateVerifyProc(null) will revert back to default certificate verify proc. - */ - setCertificateVerifyProc(proc: (hostname: string, cert: Certificate, callback: (accepted: boolean) => void) => void): void; - /** - * Sets the handler which can be used to respond to permission requests for the session. - */ - setPermissionRequestHandler(handler: (webContents: WebContents, permission: Permission, callback: (allow: boolean) => void) => void): void; - /** - * Clears the host resolver cache. - */ - clearHostResolverCache(callback: Function): void; - /** - * Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate authentication. - * @param domains Comma-seperated list of servers for which integrated authentication is enabled. - */ - allowNTLMCredentialsForDomains(domains: string): void; - /** - * Overrides the userAgent and acceptLanguages for this session. - * The acceptLanguages must a comma separated ordered list of language codes, for example "en-US,fr,de,ko,zh-CN,ja". - * This doesn't affect existing WebContents, and each WebContents can use webContents.setUserAgent to override the session-wide user agent. - */ - setUserAgent(userAgent: string, acceptLanguages?: string): void; - /** - * @returns The user agent for this session. - */ - getUserAgent(): string; - /** - * Returns the blob data associated with the identifier. - */ - getBlobData(identifier: string, callback: (result: Buffer) => void): void; - /** - * The webRequest API set allows to intercept and modify contents of a request at various stages of its lifetime. - */ - webRequest: WebRequest; - /** - * @returns An instance of protocol module for this session. - */ - protocol: Protocol; - } - - type Permission = 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal'; - - interface FromPartitionOptions { - /** - * Whether to enable cache. - */ - cache?: boolean; + error: string; } interface ClearStorageDataOptions { @@ -3381,1346 +6205,50 @@ declare namespace Electron { */ origin?: string; /** - * The types of storages to clear. + * The types of storages to clear, can contain: appcache, cookies, filesystem, + * indexdb, localstorage, shadercache, websql, serviceworkers */ - storages?: ('appcache' | 'cookies' | 'filesystem' | 'indexdb' | 'localstorage' | 'shadercache' | 'websql' | 'serviceworkers')[]; + storages?: string[]; /** - * The types of quotas to clear. + * The types of quotas to clear, can contain: temporary, persistent, syncable. */ - quotas?: ('temporary' | 'persistent' | 'syncable')[]; + quotas?: string[]; } - interface ProxyConfig { + interface CommandLine { + /** + * Append a switch (with optional value) to Chromium's command line. Note: This + * will not affect process.argv, and is mainly used by developers to control some + * low-level Chromium behaviors. + */ + appendSwitch: (the_switch: string, value?: string) => void; + /** + * Append an argument to Chromium's command line. The argument will be quoted + * correctly. Note: This will not affect process.argv. + */ + appendArgument: (value: string) => void; + } + + interface Config { /** * The URL associated with the PAC file. */ - pacScript?: string; + pacScript: string; /** * Rules indicating which proxies to use. */ - proxyRules?: string; + proxyRules: string; /** * Rules indicating which URLs should bypass the proxy settings. */ - proxyBypassRules?: string; + proxyBypassRules: string; } - interface NetworkEmulationOptions { - /** - * Whether to emulate network outage. - * Default: false. - */ - offline?: boolean; - /** - * RTT in ms. - * Default: 0, which will disable latency throttling. - */ - latency?: number; - /** - * Download rate in Bps. - * Default: 0, which will disable download throttling. - */ - downloadThroughput?: number; - /** - * Upload rate in Bps. - * Default: 0, which will disable upload throttling. - */ - uploadThroughput?: number; - } - - interface CookieFilter { - /** - * Retrieves cookies which are associated with url. Empty implies retrieving cookies of all urls. - */ - url?: string; - /** - * Filters cookies by name. - */ - name?: string; - /** - * Retrieves cookies whose domains match or are subdomains of domains. - */ - domain?: string; - /** - * Retrieves cookies whose path matches path. - */ - path?: string; - /** - * Filters cookies by their Secure property. - */ - secure?: boolean; - /** - * Filters out session or persistent cookies. - */ - session?: boolean; - } - - interface Cookie { - /** - * Emitted when a cookie is changed because it was added, edited, removed, or expired. - */ - on(event: 'changed', listener: (event: Event, cookie: Cookie, cause: CookieChangedCause) => void): this; - on(event: string, listener: Function): this; - /** - * The name of the cookie. - */ - name: string; - /** - * The value of the cookie. - */ - value: string; - /** - * The domain of the cookie. - */ - domain: string; - /** - * Whether the cookie is a host-only cookie. - */ - hostOnly: string; - /** - * The path of the cookie. - */ - path: string; - /** - * Whether the cookie is marked as secure. - */ - secure: boolean; - /** - * Whether the cookie is marked as HTTP only. - */ - httpOnly: boolean; - /** - * Whether the cookie is a session cookie or a persistent cookie with an expiration date. - */ - session: boolean; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * Not provided for session cookies. - */ - expirationDate?: number; - } - - type CookieChangedCause = 'explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'; - - interface CookieDetails { - /** - * The URL associated with the cookie. - */ - url: string; - /** - * The name of the cookie. - * Default: empty. - */ - name?: string; - /** - * The value of the cookie. - * Default: empty. - */ - value?: string; - /** - * The domain of the cookie. - * Default: empty. - */ - domain?: string; - /** - * The path of the cookie. - * Default: empty. - */ - path?: string; - /** - * Whether the cookie should be marked as secure. - * Default: false. - */ - secure?: boolean; - /** - * Whether the cookie should be marked as HTTP only. - * Default: false. - */ - httpOnly?: boolean; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * If omitted, the cookie becomes a session cookie. - */ - expirationDate?: number; - } - - interface SessionCookies { - /** - * Sends a request to get all cookies matching filter. - */ - get(filter: CookieFilter, callback: (error: Error, cookies: Cookie[]) => void): void; - /** - * Sets the cookie with details. - */ - set(details: CookieDetails, callback: (error: Error) => void): void; - /** - * Removes the cookies matching url and name. - */ - remove(url: string, name: string, callback: (error: Error) => void): void; - } - - /** - * Each API accepts an optional filter and a listener, the listener will be called when the API's event has happened. - * Passing null as listener will unsubscribe from the event. - * - * The filter will be used to filter out the requests that do not match the URL patterns. - * If the filter is omitted then all requests will be matched. - * - * For certain events the listener is passed with a callback, - * which should be called with an response object when listener has done its work. - */ - interface WebRequest { - /** - * The listener will be called when a request is about to occur. - */ - onBeforeRequest(listener: (details: WebRequest.BeforeRequestDetails, callback: WebRequest.BeforeRequestCallback) => void): void; - /** - * The listener will be called when a request is about to occur. - */ - onBeforeRequest(filter: WebRequest.Filter, listener: (details: WebRequest.BeforeRequestDetails, callback: WebRequest.BeforeRequestCallback) => void): void; - /** - * The listener will be called before sending an HTTP request, once the request headers are available. - * This may occur after a TCP connection is made to the server, but before any http data is sent. - */ - onBeforeSendHeaders(listener: (details: WebRequest.BeforeSendHeadersDetails, callback: WebRequest.BeforeSendHeadersCallback) => void): void; - /** - * The listener will be called before sending an HTTP request, once the request headers are available. - * This may occur after a TCP connection is made to the server, but before any http data is sent. - */ - onBeforeSendHeaders(filter: WebRequest.Filter, listener: (details: WebRequest.BeforeSendHeadersDetails, callback: WebRequest.BeforeSendHeadersCallback) => void): void; - /** - * The listener will be called just before a request is going to be sent to the server, - * modifications of previous onBeforeSendHeaders response are visible by the time this listener is fired. - */ - onSendHeaders(listener: (details: WebRequest.SendHeadersDetails) => void): void; - /** - * The listener will be called just before a request is going to be sent to the server, - * modifications of previous onBeforeSendHeaders response are visible by the time this listener is fired. - */ - onSendHeaders(filter: WebRequest.Filter, listener: (details: WebRequest.SendHeadersDetails) => void): void; - /** - * The listener will be called when HTTP response headers of a request have been received. - */ - onHeadersReceived(listener: (details: WebRequest.HeadersReceivedDetails, callback: WebRequest.HeadersReceivedCallback) => void): void; - /** - * The listener will be called when HTTP response headers of a request have been received. - */ - onHeadersReceived(filter: WebRequest.Filter, listener: (details: WebRequest.HeadersReceivedDetails, callback: WebRequest.HeadersReceivedCallback) => void): void; - /** - * The listener will be called when first byte of the response body is received. - * For HTTP requests, this means that the status line and response headers are available. - */ - onResponseStarted(listener: (details: WebRequest.ResponseStartedDetails) => void): void; - /** - * The listener will be called when first byte of the response body is received. - * For HTTP requests, this means that the status line and response headers are available. - */ - onResponseStarted(filter: WebRequest.Filter, listener: (details: WebRequest.ResponseStartedDetails) => void): void; - /** - * The listener will be called when a server initiated redirect is about to occur. - */ - onBeforeRedirect(listener: (details: WebRequest.BeforeRedirectDetails) => void): void; - /** - * The listener will be called when a server initiated redirect is about to occur. - */ - onBeforeRedirect(filter: WebRequest.Filter, listener: (details: WebRequest.BeforeRedirectDetails) => void): void; - /** - * The listener will be called when a request is completed. - */ - onCompleted(listener: (details: WebRequest.CompletedDetails) => void): void; - /** - * The listener will be called when a request is completed. - */ - onCompleted(filter: WebRequest.Filter, listener: (details: WebRequest.CompletedDetails) => void): void; - /** - * The listener will be called when an error occurs. - */ - onErrorOccurred(listener: (details: WebRequest.ErrorOccurredDetails) => void): void; - /** - * The listener will be called when an error occurs. - */ - onErrorOccurred(filter: WebRequest.Filter, listener: (details: WebRequest.ErrorOccurredDetails) => void): void; - } - - namespace WebRequest { - interface Filter { - urls: string[]; - } - - interface Details { - id: number; - url: string; - method: string; - resourceType: string; - timestamp: number; - } - - interface UploadData { - /** - * Content being sent. - */ - bytes: Buffer; - /** - * Path of file being uploaded. - */ - file: string; - /** - * UUID of blob data. Use session.getBlobData method to retrieve the data. - */ - blobUUID: string; - } - - interface BeforeRequestDetails extends Details { - uploadData?: UploadData[]; - } - - type BeforeRequestCallback = (response: { - cancel?: boolean; - /** - * The original request is prevented from being sent or completed, and is instead redirected to the given URL. - */ - redirectURL?: string; - }) => void; - - interface BeforeSendHeadersDetails extends Details { - requestHeaders: Headers; - } - - type BeforeSendHeadersCallback = (response: { - cancel?: boolean; - /** - * When provided, request will be made with these headers. - */ - requestHeaders?: Headers; - }) => void; - - interface SendHeadersDetails extends Details { - requestHeaders: Headers; - } - - interface HeadersReceivedDetails extends Details { - statusLine: string; - statusCode: number; - responseHeaders: Headers; - } - - type HeadersReceivedCallback = (response: { - cancel?: boolean; - /** - * When provided, the server is assumed to have responded with these headers. - */ - responseHeaders?: Headers; - /** - * Should be provided when overriding responseHeaders to change header status - * otherwise original response header's status will be used. - */ - statusLine?: string; - }) => void; - - interface ResponseStartedDetails extends Details { - responseHeaders: Headers; - fromCache: boolean; - statusCode: number; - statusLine: string; - } - - interface BeforeRedirectDetails extends Details { - redirectURL: string; - statusCode: number; - ip?: string; - fromCache: boolean; - responseHeaders: Headers; - } - - interface CompletedDetails extends Details { - responseHeaders: Headers; - fromCache: boolean; - statusCode: number; - statusLine: string; - } - - interface ErrorOccurredDetails extends Details { - fromCache: boolean; - error: string; - } - } - - // https://github.com/electron/electron/blob/master/docs/api/shell.md - - /** - * The shell module provides functions related to desktop integration. - */ - interface Shell { - /** - * Show the given file in a file manager. If possible, select the file. - * @returns Whether the item was successfully shown. - */ - showItemInFolder(fullPath: string): boolean; - /** - * Open the given file in the desktop's default manner. - * @returns Whether the item was successfully shown. - */ - openItem(fullPath: string): boolean; - /** - * Open the given external protocol URL in the desktop's default manner - * (e.g., mailto: URLs in the default mail user agent). - * @returns Whether an application was available to open the URL. - */ - openExternal(url: string, options?: { - /** - * Bring the opened application to the foreground. - * Default: true. - */ - activate: boolean; - }): boolean; - /** - * Move the given file to trash. - * @returns Whether the item was successfully moved to the trash. - */ - moveItemToTrash(fullPath: string): boolean; - /** - * Play the beep sound. - */ - beep(): void; - /** - * Creates or updates a shortcut link at shortcutPath. - * - * Note: This API is available only on Windows. - */ - writeShortcutLink(shortcutPath: string, options: ShortcutLinkOptions): boolean; - /** - * Creates or updates a shortcut link at shortcutPath. - * - * Note: This API is available only on Windows. - */ - writeShortcutLink(shortcutPath: string, operation: 'create' | 'update' | 'replace', options: ShortcutLinkOptions): boolean; - /** - * Resolves the shortcut link at shortcutPath. - * An exception will be thrown when any error happens. - * - * Note: This API is available only on Windows. - */ - readShortcutLink(shortcutPath: string): ShortcutLinkOptions; - } - - interface ShortcutLinkOptions { - /** - * The target to launch from this shortcut. - */ - target: string; - /** - * The working directory. - * Default: empty. - */ - cwd?: string; - /** - * The arguments to be applied to target when launching from this shortcut. - * Default: empty. - */ - args?: string; - /** - * The description of the shortcut. - * Default: empty. - */ - description?: string; - /** - * The path to the icon, can be a DLL or EXE. icon and iconIndex have to be set together. - * Default: empty, which uses the target's icon. - */ - icon?: string; - /** - * The resource ID of icon when icon is a DLL or EXE. - * Default: 0. - */ - iconIndex?: number; - /** - * The Application User Model ID. - * Default: empty. - */ - appUserModelId?: string; - } - - // https://github.com/electron/electron/blob/master/docs/api/system-preferences.md - - type SystemColor = - '3d-dark-shadow' | // Dark shadow for three-dimensional display elements. - '3d-face' | // Face color for three-dimensional display elements and for dialog box backgrounds. - '3d-highlight' | // Highlight color for three-dimensional display elements. - '3d-light' | // Light color for three-dimensional display elements. - '3d-shadow' | // Shadow color for three-dimensional display elements. - 'active-border' | // Active window border. - 'active-caption' | // Active window title bar. Specifies the left side color in the color gradient of an active window's title bar if the gradient effect is enabled. - 'active-caption-gradient' | // Right side color in the color gradient of an active window's title bar. - 'app-workspace' | // Background color of multiple document interface (MDI) applications. - 'button-text' | // Text on push buttons. - 'caption-text' | // Text in caption, size box, and scroll bar arrow box. - 'desktop' | // Desktop background color. - 'disabled-text' | // Grayed (disabled) text. - 'highlight' | // Item(s) selected in a control. - 'highlight-text' | // Text of item(s) selected in a control. - 'hotlight' | // Color for a hyperlink or hot-tracked item. - 'inactive-border' | // Inactive window border. - 'inactive-caption' | // Inactive window caption. Specifies the left side color in the color gradient of an inactive window's title bar if the gradient effect is enabled. - 'inactive-caption-gradient' | // Right side color in the color gradient of an inactive window's title bar. - 'inactive-caption-text' | // Color of text in an inactive caption. - 'info-background' | // Background color for tooltip controls. - 'info-text' | // Text color for tooltip controls. - 'menu' | // Menu background. - 'menu-highlight' | // The color used to highlight menu items when the menu appears as a flat menu. - 'menubar' | // The background color for the menu bar when menus appear as flat menus. - 'menu-text' | // Text in menus. - 'scrollbar' | // Scroll bar gray area. - 'window' | // Window background. - 'window-frame' | // Window frame. - 'window-text'; // Text in windows. - - /** - * Get system preferences. - */ - interface SystemPreferences { - /** - * Note: This is only implemented on Windows. - */ - on(event: 'accent-color-changed', listener: (event: Event, newColor: string) => void): this; - /** - * Note: This is only implemented on Windows. - */ - on(event: 'color-changed', listener: (event: Event) => void): this; - /** - * Note: This is only implemented on Windows. - */ - on(event: 'inverted-color-scheme-changed', listener: ( - event: Event, - /** - * @param invertedColorScheme true if an inverted color scheme, such as a high contrast theme, is being used, false otherwise. - */ - invertedColorScheme: boolean - ) => void): this; - on(event: string, listener: Function): this; - /** - * @returns Whether the system is in Dark Mode. - * - * Note: This is only implemented on macOS. - */ - isDarkMode(): boolean; - /** - * @returns Whether the Swipe between pages setting is on. - * - * Note: This is only implemented on macOS. - */ - isSwipeTrackingFromScrollEventsEnabled(): boolean; - /** - * Posts event as native notifications of macOS. - * The userInfo contains the user information dictionary sent along with the notification. - * - * Note: This is only implemented on macOS. - */ - postNotification(event: string, userInfo: Object): void; - /** - * Posts event as native notifications of macOS. - * The userInfo contains the user information dictionary sent along with the notification. - * - * Note: This is only implemented on macOS. - */ - postLocalNotification(event: string, userInfo: Object): void; - /** - * Subscribes to native notifications of macOS, callback will be called when the corresponding event happens. - * The id of the subscriber is returned, which can be used to unsubscribe the event. - * - * Note: This is only implemented on macOS. - */ - subscribeNotification(event: string, callback: (event: Event, userInfo: Object) => void): number; - /** - * Removes the subscriber with id. - * - * Note: This is only implemented on macOS. - */ - unsubscribeNotification(id: number): void; - /** - * Same as subscribeNotification, but uses NSNotificationCenter for local defaults. - */ - subscribeLocalNotification(event: string, callback: (event: Event, userInfo: Object) => void): number; - /** - * Same as unsubscribeNotification, but removes the subscriber from NSNotificationCenter. - */ - unsubscribeLocalNotification(id: number): void; - /** - * Get the value of key in system preferences. - * - * Note: This is only implemented on macOS. - */ - getUserDefault(key: string, type: 'string' | 'boolean' | 'integer' | 'float' | 'double' | 'url' | 'array' | 'dictionary'): any; - /** - * @returns Whether DWM composition (Aero Glass) is enabled. - * - * Note: This is only implemented on Windows. - */ - isAeroGlassEnabled(): boolean; - /** - * @returns The users current system wide color preference in the form of an RGBA hexadecimal string. - * - * Note: This is only implemented on Windows. - */ - getAccentColor(): string; - /** - * @returns true if an inverted color scheme, such as a high contrast theme, is active, false otherwise. - * - * Note: This is only implemented on Windows. - */ - isInvertedColorScheme(): boolean; - /** - * @returns The system color setting in RGB hexadecimal form (#ABCDEF). See the Windows docs for more details. - * - * Note: This is only implemented on Windows. - */ - getColor(color: SystemColor): string; - } - - // https://github.com/electron/electron/blob/master/docs/api/tray.md - - /** - * A Tray represents an icon in an operating system's notification area. - */ - class Tray extends NodeJS.EventEmitter implements Destroyable { - /** - * Emitted when the tray icon is clicked. - * Note: The bounds payload is only implemented on macOS and Windows. - */ - on(event: 'click', listener: (modifiers: Modifiers, bounds: Rectangle) => void): this; - /** - * Emitted when the tray icon is right clicked. - * Note: This is only implemented on macOS and Windows. - */ - on(event: 'right-click', listener: (modifiers: Modifiers, bounds: Rectangle) => void): this; - /** - * Emitted when the tray icon is double clicked. - * Note: This is only implemented on macOS and Windows. - */ - on(event: 'double-click', listener: (modifiers: Modifiers, bounds: Rectangle) => void): this; - /** - * Emitted when the tray balloon shows. - * Note: This is only implemented on Windows. - */ - on(event: 'balloon-show', listener: Function): this; - /** - * Emitted when the tray balloon is clicked. - * Note: This is only implemented on Windows. - */ - on(event: 'balloon-click', listener: Function): this; - /** - * Emitted when the tray balloon is closed because of timeout or user manually closes it. - * Note: This is only implemented on Windows. - */ - on(event: 'balloon-closed', listener: Function): this; - /** - * Emitted when any dragged items are dropped on the tray icon. - * Note: This is only implemented on macOS. - */ - on(event: 'drop', listener: Function): this; - /** - * Emitted when dragged files are dropped in the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drop-files', listener: (event: Event, files: string[]) => void): this; - /** - * Emitted when dragged text is dropped in the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drop-text', listener: (event: Event, text: string) => void): this; - /** - * Emitted when a drag operation enters the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drag-enter', listener: Function): this; - /** - * Emitted when a drag operation exits the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drag-leave', listener: Function): this; - /** - * Emitted when a drag operation ends on the tray or ends at another location. - * Note: This is only implemented on macOS - */ - on(event: 'drag-end', listener: Function): this; - on(event: string, listener: Function): this; - /** - * Creates a new tray icon associated with the image. - */ - constructor(image: NativeImage | string); - /** - * Destroys the tray icon immediately. - */ - destroy(): void; - /** - * Sets the image associated with this tray icon. - */ - setImage(image: NativeImage | string): void; - /** - * Sets the image associated with this tray icon when pressed. - */ - setPressedImage(image: NativeImage): void; - /** - * Sets the hover text for this tray icon. - */ - setToolTip(toolTip: string): void; - /** - * Sets the title displayed aside of the tray icon in the status bar. - * Note: This is only implemented on macOS. - */ - setTitle(title: string): void; - /** - * Sets when the tray's icon background becomes highlighted. - * Note: This is only implemented on macOS. - */ - setHighlightMode(mode: 'selection' | 'always' | 'never'): void; - /** - * Displays a tray balloon. - * Note: This is only implemented on Windows. - */ - displayBalloon(options?: { - icon?: NativeImage; - title?: string; - content?: string; - }): void; - /** - * Pops up the context menu of tray icon. When menu is passed, - * the menu will showed instead of the tray's context menu. - * The position is only available on Windows, and it is (0, 0) by default. - * Note: This is only implemented on macOS and Windows. - */ - popUpContextMenu(menu?: Menu, position?: Point): void; - /** - * Sets the context menu for this icon. - */ - setContextMenu(menu: Menu): void; - /** - * @returns The bounds of this tray icon. - */ - getBounds(): Rectangle; - /** - * @returns Whether the tray icon is destroyed. - */ - isDestroyed(): boolean; - } - - interface Modifiers { - altKey: boolean; - shiftKey: boolean; - ctrlKey: boolean; - metaKey: boolean; - } - - interface DragItem { - /** - * The absolute path of the file to be dragged - */ - file: string; - /** - * The image showing under the cursor when dragging. - */ - icon: NativeImage; - } - - // https://github.com/electron/electron/blob/master/docs/api/web-contents.md - - interface WebContentsStatic { - /** - * @returns An array of all WebContents instances. This will contain web contents for all windows, - * webviews, opened devtools, and devtools extension background pages. - */ - getAllWebContents(): WebContents[]; - /** - * @returns The web contents that is focused in this application, otherwise returns null. - */ - getFocusedWebContents(): WebContents; - /** - * Find a WebContents instance according to its ID. - */ - fromId(id: number): WebContents; - } - - /** - * A WebContents is responsible for rendering and controlling a web page. - */ - interface WebContents extends NodeJS.EventEmitter { - /** - * Emitted when the navigation is done, i.e. the spinner of the tab has stopped spinning, - * and the onload event was dispatched. - */ - on(event: 'did-finish-load', listener: Function): this; - /** - * This event is like did-finish-load but emitted when the load failed or was cancelled, - * e.g. window.stop() is invoked. - */ - on(event: 'did-fail-load', listener: (event: Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => void): this; - /** - * Emitted when a frame has done navigation. - */ - on(event: 'did-frame-finish-load', listener: (event: Event, isMainFrame: boolean) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab started spinning. - */ - on(event: 'did-start-loading', listener: Function): this; - /** - * Corresponds to the points in time when the spinner of the tab stopped spinning. - */ - on(event: 'did-stop-loading', listener: Function): this; - /** - * Emitted when details regarding a requested resource are available. - * status indicates the socket connection to download the resource. - */ - on(event: 'did-get-response-details', listener: (event: Event, - status: boolean, - newURL: string, - originalURL: string, - httpResponseCode: number, - requestMethod: string, - referrer: string, - headers: Headers, - resourceType: string - ) => void): this; - /** - * Emitted when a redirect is received while requesting a resource. - */ - on(event: 'did-get-redirect-request', listener: (event: Event, - oldURL: string, - newURL: string, - isMainFrame: boolean, - httpResponseCode: number, - requestMethod: string, - referrer: string, - headers: Headers - ) => void): this; - /** - * Emitted when the document in the given frame is loaded. - */ - on(event: 'dom-ready', listener: (event: Event) => void): this; - /** - * Emitted when page receives favicon URLs. - */ - on(event: 'page-favicon-updated', listener: (event: Event, favicons: string[]) => void): this; - /** - * Emitted when the page requests to open a new window for a url. - * It could be requested by window.open or an external link like . - * - * By default a new BrowserWindow will be created for the url. - * - * Calling event.preventDefault() will prevent creating new windows. - */ - on(event: 'new-window', listener: (event: Event, - url: string, - frameName: string, - disposition: NewWindowDisposition, - options: BrowserWindowOptions - ) => void): this; - /** - * Emitted when a user or the page wants to start navigation. - * It can happen when the window.location object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with APIs like - * webContents.loadURL and webContents.back. - * - * It is also not emitted for in-page navigations, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - * - * Calling event.preventDefault() will prevent the navigation. - */ - on(event: 'will-navigate', listener: (event: Event, url: string) => void): this; - /** - * Emitted when a navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - */ - on(event: 'did-navigate', listener: (event: Event, url: string) => void): this; - /** - * Emitted when an in-page navigation happened. - * - * When in-page navigation happens, the page URL changes but does not cause - * navigation outside of the page. Examples of this occurring are when anchor links - * are clicked or when the DOM hashchange event is triggered. - */ - on(event: 'did-navigate-in-page', listener: (event: Event, url: string, isMainFrame: boolean) => void): this; - /** - * Emitted when the renderer process has crashed. - */ - on(event: 'crashed', listener: (event: Event, killed: boolean) => void): this; - /** - * Emitted when a plugin process has crashed. - */ - on(event: 'plugin-crashed', listener: (event: Event, name: string, version: string) => void): this; - /** - * Emitted when webContents is destroyed. - */ - on(event: 'destroyed', listener: Function): this; - /** - * Emitted when DevTools is opened. - */ - on(event: 'devtools-opened', listener: Function): this; - /** - * Emitted when DevTools is closed. - */ - on(event: 'devtools-closed', listener: Function): this; - /** - * Emitted when DevTools is focused / opened. - */ - on(event: 'devtools-focused', listener: Function): this; - /** - * Emitted when failed to verify the certificate for url. - * The usage is the same with the "certificate-error" event of app. - */ - on(event: 'certificate-error', listener: (event: Event, - url: string, - error: string, - certificate: Certificate, - callback: (trust: boolean) => void - ) => void): this; - /** - * Emitted when a client certificate is requested. - * The usage is the same with the "select-client-certificate" event of app. - */ - on(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void - ) => void): this; - /** - * Emitted when webContents wants to do basic auth. - * The usage is the same with the "login" event of app. - */ - on(event: 'login', listener: (event: Event, - request: LoginRequest, - authInfo: LoginAuthInfo, - callback: (username: string, password: string) => void - ) => void): this; - /** - * Emitted when a result is available for webContents.findInPage request. - */ - on(event: 'found-in-page', listener: (event: Event, result: FoundInPageResult) => void): this; - /** - * Emitted when media starts playing. - */ - on(event: 'media-started-playing', listener: Function): this; - /** - * Emitted when media is paused or done playing. - */ - on(event: 'media-paused', listener: Function): this; - /** - * Emitted when a page’s theme color changes. This is usually due to encountering a meta tag: - * - */ - on(event: 'did-change-theme-color', listener: Function): this; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - on(event: 'update-target-url', listener: (event: Event, url: string) => void): this; - /** - * Emitted when the cursor’s type changes. - * If the type parameter is custom, the image parameter will hold the custom cursor image - * in a NativeImage, and scale, size and hotspot will hold additional information about the custom cursor. - */ - on(event: 'cursor-changed', listener: (event: Event, type: CursorType, image?: NativeImage, scale?: number, size?: Size, hotspot?: Point) => void): this; - /** - * Emitted when there is a new context menu that needs to be handled. - */ - on(event: 'context-menu', listener: (event: Event, params: ContextMenuParams) => void): this; - /** - * Emitted when bluetooth device needs to be selected on call to navigator.bluetooth.requestDevice. - * To use navigator.bluetooth api webBluetooth should be enabled. - * If event.preventDefault is not called, first available device will be selected. - * callback should be called with deviceId to be selected, - * passing empty string to callback will cancel the request. - */ - on(event: 'select-bluetooth-device', listener: (event: Event, deviceList: BluetoothDevice[], callback: (deviceId: string) => void) => void): this; - /** - * Emitted when a new frame is generated. Only the dirty area is passed in the buffer. - */ - on(event: 'paint', listener: (event: Event, dirtyRect: Rectangle, image: NativeImage) => void): this; - on(event: string, listener: Function): this; - /** - * Loads the url in the window. - * @param url Must contain the protocol prefix (e.g., the http:// or file://). - */ - loadURL(url: string, options?: LoadURLOptions): void; - /** - * Initiates a download of the resource at url without navigating. - * The will-download event of session will be triggered. - */ - downloadURL(url: string): void; - /** - * @returns The URL of current web page. - */ - getURL(): string; - /** - * @returns The title of web page. - */ - getTitle(): string; - /** - * @returns Whether the web page is destroyed. - */ - isDestroyed(): boolean; - /** - * @returns Whether the web page is focused. - */ - isFocused(): boolean; - /** - * @returns Whether web page is still loading resources. - */ - isLoading(): boolean; - /** - * @returns Whether the main frame (and not just iframes or frames within it) is still loading. - */ - isLoadingMainFrame(): boolean; - /** - * @returns Whether web page is waiting for a first-response for the main - * resource of the page. - */ - isWaitingForResponse(): boolean; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Reloads current page. - */ - reload(): void; - /** - * Reloads current page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * @returns Whether the web page can go back. - */ - canGoBack(): boolean; - /** - * @returns Whether the web page can go forward. - */ - canGoForward(): boolean; - /** - * @returns Whether the web page can go to offset. - */ - canGoToOffset(offset: number): boolean; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Makes the web page go back. - */ - goBack(): void; - /** - * Makes the web page go forward. - */ - goForward(): void; - /** - * Navigates to the specified absolute index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * @returns Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Overrides the user agent for this page. - */ - setUserAgent(userAgent: string): void; - /** - * @returns The user agent for this web page. - */ - getUserAgent(): string; - /** - * Injects CSS into this page. - */ - insertCSS(css: string): void; - /** - * Evaluates code in page. - * @param code Code to evaluate. - * - * @returns Promise - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * Mute the audio on the current web page. - */ - setAudioMuted(muted: boolean): void; - /** - * @returns Whether this page has been muted. - */ - isAudioMuted(): boolean; - /** - * Changes the zoom factor to the specified factor. - * Zoom factor is zoom percent divided by 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * Sends a request to get current zoom factor. - */ - getZoomFactor(callback: (zoomFactor: number) => void): void; - /** - * Changes the zoom level to the specified level. - * The original size is 0 and each increment above or below represents - * zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. - */ - setZoomLevel(level: number): void; - /** - * Sends a request to get current zoom level. - */ - getZoomLevel(callback: (zoomLevel: number) => void): void; - /** - * Sets the maximum and minimum zoom level. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Executes the editing command undo in web page. - */ - undo(): void; - /** - * Executes the editing command redo in web page. - */ - redo(): void; - /** - * Executes the editing command cut in web page. - */ - cut(): void; - /** - * Executes the editing command copy in web page. - */ - copy(): void; - /** - * Copy the image at the given position to the clipboard. - */ - copyImageAt(x: number, y: number): void; - /** - * Executes the editing command paste in web page. - */ - paste(): void; - /** - * Executes the editing command pasteAndMatchStyle in web page. - */ - pasteAndMatchStyle(): void; - /** - * Executes the editing command delete in web page. - */ - delete(): void; - /** - * Executes the editing command selectAll in web page. - */ - selectAll(): void; - /** - * Executes the editing command unselect in web page. - */ - unselect(): void; - /** - * Executes the editing command replace in web page. - */ - replace(text: string): void; - /** - * Executes the editing command replaceMisspelling in web page. - */ - replaceMisspelling(text: string): void; - /** - * Inserts text to the focused element. - */ - insertText(text: string): void; - /** - * Starts a request to find all matches for the text in the web page. - * The result of the request can be obtained by subscribing to found-in-page event. - * @returns The request id used for the request. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * Stops any findInPage request for the webContents with the provided action. - */ - stopFindInPage(action: StopFindInPageAtion): void; - /** - * Checks if any serviceworker is registered. - */ - hasServiceWorker(callback: (hasServiceWorker: boolean) => void): void; - /** - * Unregisters any serviceworker if present. - */ - unregisterServiceWorker(callback: (isFulfilled: boolean) => void): void; - /** - * Prints window's web page. When silent is set to false, Electron will pick up system's default printer and default settings for printing. - * Calling window.print() in web page is equivalent to call WebContents.print({silent: false, printBackground: false}). - * Note: On Windows, the print API relies on pdf.dll. If your application doesn't need print feature, you can safely remove pdf.dll in saving binary size. - */ - print(options?: PrintOptions): void; - /** - * Prints windows' web page as PDF with Chromium's preview printing custom settings. - */ - printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; - /** - * Adds the specified path to DevTools workspace. - */ - addWorkSpace(path: string): void; - /** - * Removes the specified path from DevTools workspace. - */ - removeWorkSpace(path: string): void; - /** - * Opens the developer tools. - */ - openDevTools(options?: { - /** - * Opens the devtools with specified dock state. Defaults to last used dock state. - */ - mode?: 'right' | 'bottom' | 'undocked' | 'detach' - }): void; - /** - * Closes the developer tools. - */ - closeDevTools(): void; - /** - * Returns whether the developer tools are opened. - */ - isDevToolsOpened(): boolean; - /** - * Returns whether the developer tools are focused. - */ - isDevToolsFocused(): boolean; - /** - * Toggle the developer tools. - */ - toggleDevTools(): void; - /** - * Starts inspecting element at position (x, y). - */ - inspectElement(x: number, y: number): void; - /** - * Opens the developer tools for the service worker context. - */ - inspectServiceWorker(): void; - /** - * Send args.. to the web page via channel in asynchronous message, the web page - * can handle it by listening to the channel event of ipc module. - * Note: - * 1. The IPC message handler in web pages do not have a event parameter, - * which is different from the handlers on the main process. - * 2. There is no way to send synchronous messages from the main process - * to a renderer process, because it would be very easy to cause dead locks. - */ - send(channel: string, ...args: any[]): void; - /** - * Enable device emulation with the given parameters. - */ - enableDeviceEmulation(parameters: DeviceEmulationParameters): void; - /** - * Disable device emulation. - */ - disableDeviceEmulation(): void; - /** - * Sends an input event to the page. - */ - sendInputEvent(event: SendInputEvent): void; - /** - * Begin subscribing for presentation events and captured frames, - * The callback will be called when there is a presentation event. - */ - beginFrameSubscription(onlyDirty: boolean, callback: BeginFrameSubscriptionCallback): void; - /** - * Begin subscribing for presentation events and captured frames, - * The callback will be called when there is a presentation event. - */ - beginFrameSubscription(callback: BeginFrameSubscriptionCallback): void; - /** - * End subscribing for frame presentation events. - */ - endFrameSubscription(): void; - /** - * @returns If the process of saving page has been initiated successfully. - */ - savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML', callback?: (eror: Error) => void): boolean; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * Note: This API is available only on macOS. - */ - showDefinitionForSelection(): void; - /** - * @returns Whether offscreen rendering is enabled. - */ - isOffscreen(): boolean; - /** - * If offscreen rendering is enabled and not painting, start painting. - */ - startPainting(): void; - /** - * If offscreen rendering is enabled and painting, stop painting. - */ - stopPainting(): void; - /** - * If offscreen rendering is enabled returns whether it is currently painting. - */ - isPainting(): boolean; - /** - * If offscreen rendering is enabled sets the frame rate to the specified number. - * Only values between 1 and 60 are accepted. - */ - setFrameRate(fps: number): void; - /** - * If offscreen rendering is enabled returns the current frame rate. - */ - getFrameRate(): number; - /** - * If offscreen rendering is enabled invalidates the frame and generates a new one through the 'paint' event. - */ - invalidate(): void; - /** - * Sets the item as dragging item for current drag-drop operation. - */ - startDrag(item: DragItem): void; - /** - * Captures a snapshot of the page within rect. - */ - capturePage(callback: (image: NativeImage) => void): void; - /** - * Captures a snapshot of the page within rect. - */ - capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; - /** - * @returns The unique ID of this WebContents. - */ - id: number; - /** - * @returns The session object used by this webContents. - */ - session: Session; - /** - * @returns The WebContents that might own this WebContents. - */ - hostWebContents: WebContents; - /** - * @returns The WebContents of DevTools for this WebContents. - * Note: Users should never store this object because it may become null - * when the DevTools has been closed. - */ - devToolsWebContents: WebContents; - /** - * @returns Debugger API - */ - debugger: Debugger; - } - - interface BeginFrameSubscriptionCallback { - ( - /** - * The frameBuffer is a Buffer that contains raw pixel data. - * On most machines, the pixel data is effectively stored in 32bit BGRA format, - * but the actual representation depends on the endianness of the processor - * (most modern processors are little-endian, on machines with big-endian - * processors the data is in 32bit ARGB format). - */ - frameBuffer: Buffer, - /** - * The dirtyRect is an object with x, y, width, height properties that describes which part of the page was repainted. - * If onlyDirty is set to true, frameBuffer will only contain the repainted area. onlyDirty defaults to false. - */ - dirtyRect?: Rectangle - ): void + interface ConsoleMessageEvent extends Event { + level: number; + message: string; + line: number; + sourceId: string; } interface ContextMenuParams { @@ -4737,7 +6265,8 @@ declare namespace Electron { */ linkURL: string; /** - * Text associated with the link. May be an empty string if the contents of the link are an image. + * Text associated with the link. May be an empty string if the contents of the + * link are an image. */ linkText: string; /** @@ -4749,51 +6278,15 @@ declare namespace Electron { */ frameURL: string; /** - * Source URL for the element that the context menu was invoked on. - * Elements with source URLs are images, audio and video. + * Source URL for the element that the context menu was invoked on. Elements with + * source URLs are images, audio and video. */ srcURL: string; /** - * Type of the node the context menu was invoked on. + * Type of the node the context menu was invoked on. Can be none, image, audio, + * video, canvas, file or plugin. */ - mediaType: 'none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'; - /** - * Parameters for the media element the context menu was invoked on. - */ - mediaFlags: { - /** - * Whether the media element has crashed. - */ - inError: boolean; - /** - * Whether the media element is paused. - */ - isPaused: boolean; - /** - * Whether the media element is muted. - */ - isMuted: boolean; - /** - * Whether the media element has audio. - */ - hasAudio: boolean; - /** - * Whether the media element is looping. - */ - isLooping: boolean; - /** - * Whether the media element's controls are visible. - */ - isControlsVisible: boolean; - /** - * Whether the media element's controls are toggleable. - */ - canToggleControls: boolean; - /** - * Whether the media element can be rotated. - */ - canRotate: boolean; - } + mediaType: ('none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'); /** * Whether the context menu was invoked on an image which has non-empty contents. */ @@ -4802,39 +6295,6 @@ declare namespace Electron { * Whether the context is editable. */ isEditable: boolean; - /** - * These flags indicate whether the renderer believes it is able to perform the corresponding action. - */ - editFlags: { - /** - * Whether the renderer believes it can undo. - */ - canUndo: boolean; - /** - * Whether the renderer believes it can redo. - */ - canRedo: boolean; - /** - * Whether the renderer believes it can cut. - */ - canCut: boolean; - /** - * Whether the renderer believes it can copy - */ - canCopy: boolean; - /** - * Whether the renderer believes it can paste. - */ - canPaste: boolean; - /** - * Whether the renderer believes it can delete. - */ - canDelete: boolean; - /** - * Whether the renderer believes it can select all. - */ - canSelectAll: boolean; - } /** * Text of the selection that the context menu was invoked on. */ @@ -4853,142 +6313,297 @@ declare namespace Electron { frameCharset: string; /** * If the context menu was invoked on an input field, the type of that field. + * Possible values are none, plainText, password, other. */ - inputFieldType: 'none' | 'plainText' | 'password' | 'other'; + inputFieldType: string; /** - * Input source that invoked the context menu. + * Input source that invoked the context menu. Can be none, mouse, keyboard, touch, + * touchMenu. */ - menuSourceType: 'none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu'; + menuSourceType: ('none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu'); + /** + * The flags for the media element the context menu was invoked on. + */ + mediaFlags: MediaFlags; + /** + * These flags indicate whether the renderer believes it is able to perform the + * corresponding action. + */ + editFlags: EditFlags; } - interface BluetoothDevice { - deviceName: string; - deviceId: string; + interface CrashReporterStartOptions { + companyName?: string; + /** + * URL that crash reports will be sent to as POST. + */ + submitURL: string; + /** + * Defaults to app.getName(). + */ + productName?: string; + /** + * Whether crash reports should be sent to the server Default is true. + */ + uploadToServer?: boolean; + /** + * Default is false. + */ + ignoreSystemCrashHandler?: boolean; + /** + * An object you can define that will be sent along with the report. Only string + * properties are sent correctly. Nested objects are not supported and the property + * names and values must be less than 64 characters long. + */ + extra?: any; + /** + * Only used when the crash reporter is used in a forked process (macOS only). + */ + crashesDirectory?: string; } - interface Headers { - [key: string]: string; + interface CreateFromBufferOptions { + /** + * Required for bitmap buffers. + */ + width?: number; + /** + * Required for bitmap buffers. + */ + height?: number; + /** + * Defaults to 1.0. + */ + scaleFactor?: number; } - type NewWindowDisposition = 'default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'; - - /** - * Specifies the action to take place when ending webContents.findInPage request. - * 'clearSelection' - Clear the selection. - * 'keepSelection' - Translate the selection into a normal selection. - * 'activateSelection' - Focus and click the selection node. - */ - type StopFindInPageAtion = 'clearSelection' | 'keepSelection' | 'activateSelection'; - - type CursorType = 'default' | 'crosshair' | 'pointer' | 'text' | 'wait' | 'help' | 'e-resize' | 'n-resize' | 'ne-resize' | 'nw-resize' | 's-resize' | 'se-resize' | 'sw-resize' | 'w-resize' | 'ns-resize' | 'ew-resize' | 'nesw-resize' | 'nwse-resize' | 'col-resize' | 'row-resize' | 'm-panning' | 'e-panning' | 'n-panning' | 'ne-panning' | 'nw-panning' | 's-panning' | 'se-panning' | 'sw-panning' | 'w-panning' | 'move' | 'vertical-text' | 'cell' | 'context-menu' | 'alias' | 'progress' | 'nodrop' | 'copy' | 'none' | 'not-allowed' | 'zoom-in' | 'zoom-out' | 'grab' | 'grabbing' | 'custom'; - - interface LoadURLOptions { + interface CreateInterruptedDownloadOptions { /** - * HTTP Referrer URL. + * Absolute path of the download. */ - httpReferrer?: string; + path: string; /** - * User agent originating the request. + * Complete URL chain for the download. */ - userAgent?: string; + urlChain: string[]; + mimeType?: string; /** - * Extra headers separated by "\n" + * Start range for the download. */ - extraHeaders?: string; + offset: number; + /** + * Total length of the download. + */ + length: number; + /** + * Last-Modified header value. + */ + lastModified: string; + /** + * ETag header value. + */ + eTag: string; + /** + * Time when download was started in number of seconds since UNIX epoch. + */ + startTime?: number; } - interface PrintOptions { + interface Data { + text?: string; + html?: string; + image?: NativeImage; + rtf?: string; /** - * Don't ask user for print settings. - * Defaults: false. + * The title of the url at text. */ - silent?: boolean; - /** - * Also prints the background color and image of the web page. - * Defaults: false. - */ - printBackground?: boolean; + bookmark?: string; } - interface PrintToPDFOptions { + interface Details { /** - * Specify the type of margins to use. - * 0 - default - * 1 - none - * 2 - minimum - * Default: 0 + * The url to associate the cookie with. */ - marginsType?: number; - /** - * Specify page size of the generated PDF. - * Default: A4. - */ - pageSize?: 'A3' | 'A4' | 'A5' | 'Legal' | 'Letter' | 'Tabloid' | Size; - /** - * Whether to print CSS backgrounds. - * Default: false. - */ - printBackground?: boolean; - /** - * Whether to print selection only. - * Default: false. - */ - printSelectionOnly?: boolean; - /** - * true for landscape, false for portrait. - * Default: false. - */ - landscape?: boolean; - } - - interface Certificate { - /** - * PEM encoded data. - */ - data: string; - /** - * Issuer's Common Name. - */ - issuerName: string; - /** - * Subject's Common Name. - */ - subjectName: string; - /** - * Hex value represented string. - */ - serialNumber: string; - /** - * Start date of the certificate being valid in seconds. - */ - validStart: number; - /** - * End date of the certificate being valid in seconds. - */ - validExpiry: number; - /** - * Fingerprint of the certificate. - */ - fingerprint: string; - } - - interface LoginRequest { - method: string; url: string; - referrer: string; + /** + * The name of the cookie. Empty by default if omitted. + */ + name?: string; + /** + * The value of the cookie. Empty by default if omitted. + */ + value?: string; + /** + * The domain of the cookie. Empty by default if omitted. + */ + domain?: string; + /** + * The path of the cookie. Empty by default if omitted. + */ + path?: string; + /** + * Whether the cookie should be marked as Secure. Defaults to false. + */ + secure?: boolean; + /** + * Whether the cookie should be marked as HTTP only. Defaults to false. + */ + httpOnly?: boolean; + /** + * The expiration date of the cookie as the number of seconds since the UNIX epoch. + * If omitted then the cookie becomes a session cookie and will not be retained + * between sessions. + */ + expirationDate?: number; } - interface LoginAuthInfo { - isProxy: boolean; - scheme: string; - host: string; - port: number; - realm: string; + interface DevToolsExtensions { + } + + interface DidChangeThemeColorEvent extends Event { + themeColor: string; + } + + interface DidFailLoadEvent extends Event { + errorCode: number; + errorDescription: string; + validatedURL: string; + isMainFrame: boolean; + } + + interface DidFrameFinishLoadEvent extends Event { + isMainFrame: boolean; + } + + interface DidGetRedirectRequestEvent extends Event { + oldURL: string; + newURL: string; + isMainFrame: boolean; + } + + interface DidGetResponseDetailsEvent extends Event { + status: boolean; + newURL: string; + originalURL: string; + httpResponseCode: number; + requestMethod: string; + referrer: string; + headers: Headers; + resourceType: string; + } + + interface DidNavigateEvent extends Event { + url: string; + } + + interface DidNavigateInPageEvent extends Event { + isMainFrame: boolean; + url: string; + } + + interface DisplayBalloonOptions { + icon?: NativeImage | string; + title?: string; + content?: string; + } + + interface Dock { + /** + * When critical is passed, the dock icon will bounce until either the application + * becomes active or the request is canceled. When informational is passed, the + * dock icon will bounce for one second. However, the request remains active until + * either the application becomes active or the request is canceled. + */ + bounce: (type?: 'critical' | 'informational') => number; + /** + * Cancel the bounce of id. + */ + cancelBounce: (id: number) => void; + /** + * Bounces the Downloads stack if the filePath is inside the Downloads folder. + */ + downloadFinished: (filePath: string) => void; + /** + * Sets the string to be displayed in the dock’s badging area. + */ + setBadge: (text: string) => void; + getBadge: () => string; + /** + * Hides the dock icon. + */ + hide: () => void; + /** + * Shows the dock icon. + */ + show: () => void; + isVisible: () => boolean; + /** + * Sets the application's dock menu. + */ + setMenu: (menu: Menu) => void; + /** + * Sets the image associated with this dock icon. + */ + setIcon: (image: NativeImage | string) => void; + } + + interface EnableNetworkEmulationOptions { + /** + * Whether to emulate network outage. Defaults to false. + */ + offline?: boolean; + /** + * RTT in ms. Defaults to 0 which will disable latency throttling. + */ + latency?: number; + /** + * Download rate in Bps. Defaults to 0 which will disable download throttling. + */ + downloadThroughput?: number; + /** + * Upload rate in Bps. Defaults to 0 which will disable upload throttling. + */ + uploadThroughput?: number; + } + + interface Extensions { + } + + interface FileIconOptions { + size: ('small' | 'normal' | 'large'); + } + + interface Filter { + /** + * Retrieves cookies which are associated with url. Empty implies retrieving + * cookies of all urls. + */ + url?: string; + /** + * Filters cookies by name. + */ + name?: string; + /** + * Retrieves cookies whose domains match or are subdomains of domains + */ + domain?: string; + /** + * Retrieves cookies whose path matches path. + */ + path?: string; + /** + * Filters cookies by their Secure property. + */ + secure?: boolean; + /** + * Filters out session or persistent cookies. + */ + session?: boolean; } interface FindInPageOptions { /** - * Whether to search forward or backward, defaults to true + * Whether to search forward or backward, defaults to true. */ forward?: boolean; /** @@ -5004,989 +6619,664 @@ declare namespace Electron { */ wordStart?: boolean; /** - * When combined with wordStart, accepts a match in the middle of a word - * if the match begins with an uppercase letter followed by a lowercase - * or non-letter. Accepts several other intra-word matches, defaults to false. + * When combined with wordStart, accepts a match in the middle of a word if the + * match begins with an uppercase letter followed by a lowercase or non-letter. + * Accepts several other intra-word matches, defaults to false. */ medialCapitalAsWordStart?: boolean; } - interface FoundInPageResult { - requestId: number; - /** - * Indicates if more responses are to follow. - */ - finalUpdate: boolean; - /** - * Position of the active match. - */ - activeMatchOrdinal?: number; - /** - * Number of Matches. - */ - matches?: number; - /** - * Coordinates of first match region. - */ - selectionArea?: Rectangle; + interface FoundInPageEvent extends Event { + result: FoundInPageResult; } - interface DeviceEmulationParameters { + interface FromPartitionOptions { /** - * Specify the screen type to emulated - * Default: desktop + * Whether to enable cache. */ - screenPosition?: 'desktop' | 'mobile'; + cache: boolean; + } + + interface Header { + /** + * Specify an extra header name. + */ + name: string; + } + + interface ImportCertificateOptions { + /** + * Path for the pkcs12 file. + */ + certificate: string; + /** + * Passphrase for the certificate. + */ + password: string; + } + + interface Input { + /** + * Either keyUp or keyDown + */ + type: string; + /** + * Equivalent to + */ + key: string; + /** + * Equivalent to + */ + code: string; + /** + * Equivalent to + */ + isAutoRepeat: boolean; + /** + * Equivalent to + */ + shift: boolean; + /** + * Equivalent to + */ + control: boolean; + /** + * Equivalent to + */ + alt: boolean; + /** + * Equivalent to + */ + meta: boolean; + } + + interface InterceptBufferProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface InterceptFileProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface InterceptHttpProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface InterceptStringProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface IpcMessageEvent extends Event { + channel: string; + args: any[]; + } + + interface Item { + /** + * or files Array The path(s) to the file(s) being dragged. + */ + file: string; + /** + * The image must be non-empty on macOS. + */ + icon: NativeImage; + } + + interface JumpListSettings { + /** + * The minimum number of items that will be shown in the Jump List (for a more + * detailed description of this value see the ). + */ + minItems: number; + /** + * Array of JumpListItem objects that correspond to items that the user has + * explicitly removed from custom categories in the Jump List. These items must not + * be re-added to the Jump List in the call to app.setJumpList(), Windows will not + * display any custom category that contains any of the removed items. + */ + removedItems: JumpListItem[]; + } + + interface LoadCommitEvent extends Event { + url: string; + isMainFrame: boolean; + } + + interface LoadURLOptions { + /** + * A HTTP Referrer url. + */ + httpReferrer?: string; + /** + * A user agent originating the request. + */ + userAgent?: string; + /** + * Extra headers separated by "\n" + */ + extraHeaders?: string; + postData?: UploadRawData[] | UploadFile[] | UploadFileSystem[] | UploadBlob[]; + /** + * Base url (with trailing path separator) for files to be loaded by the data url. + * This is needed only if the specified url is a data url and needs to load other + * files. + */ + baseURLForDataURL?: string; + } + + interface LoginItemSettings { + options?: Options; + /** + * true if the app is set to open at login. + */ + openAtLogin: boolean; + /** + * true if the app is set to open as hidden at login. This setting is only + * supported on macOS. + */ + openAsHidden: boolean; + /** + * true if the app was opened at login automatically. This setting is only + * supported on macOS. + */ + wasOpenedAtLogin: boolean; + /** + * true if the app was opened as a hidden login item. This indicates that the app + * should not open any windows at startup. This setting is only supported on macOS. + */ + wasOpenedAsHidden: boolean; + /** + * true if the app was opened as a login item that should restore the state from + * the previous session. This indicates that the app should restore the windows + * that were open the last time the app was closed. This setting is only supported + * on macOS. + */ + restoreState: boolean; + } + + interface LoginItemSettingsOptions { + /** + * The executable path to compare against. Defaults to process.execPath. + */ + path?: string; + /** + * The command-line arguments to compare against. Defaults to an empty array. + */ + args?: string[]; + } + + interface MenuItemConstructorOptions { + /** + * Will be called with click(menuItem, browserWindow, event) when the menu item is + * clicked. + */ + click?: (menuItem: MenuItem, browserWindow: BrowserWindow, event: Event) => void; + /** + * Define the action of the menu item, when specified the click property will be + * ignored. See . + */ + role?: MenuItemRole; + /** + * Can be normal, separator, submenu, checkbox or radio. + */ + type?: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'); + label?: string; + sublabel?: string; + accelerator?: Accelerator; + icon?: NativeImage | string; + /** + * If false, the menu item will be greyed out and unclickable. + */ + enabled?: boolean; + /** + * If false, the menu item will be entirely hidden. + */ + visible?: boolean; + /** + * Should only be specified for checkbox or radio type menu items. + */ + checked?: boolean; + /** + * Should be specified for submenu type menu items. If submenu is specified, the + * type: 'submenu' can be omitted. If the value is not a Menu then it will be + * automatically converted to one using Menu.buildFromTemplate. + */ + submenu?: MenuItemConstructorOptions[] | Menu; + /** + * Unique within a single menu. If defined then it can be used as a reference to + * this item by the position attribute. + */ + id?: string; + /** + * This field allows fine-grained definition of the specific location within a + * given menu. + */ + position?: string; + } + + interface MessageBoxOptions { + /** + * Can be "none", "info", "error", "question" or "warning". On Windows, "question" + * displays the same icon as "info", unless you set an icon using the "icon" + * option. On macOS, both "warning" and "error" display the same warning icon. + */ + type?: string; + /** + * Array of texts for buttons. On Windows, an empty array will result in one button + * labeled "OK". + */ + buttons?: string[]; + /** + * Index of the button in the buttons array which will be selected by default when + * the message box opens. + */ + defaultId?: number; + /** + * Title of the message box, some platforms will not show it. + */ + title?: string; + /** + * Content of the message box. + */ + message: string; + /** + * Extra information of the message. + */ + detail?: string; + /** + * If provided, the message box will include a checkbox with the given label. The + * checkbox state can be inspected only when using callback. + */ + checkboxLabel?: string; + /** + * Initial checked state of the checkbox. false by default. + */ + checkboxChecked?: boolean; + icon?: NativeImage; + /** + * The index of the button to be used to cancel the dialog, via the Esc key. By + * default this is assigned to the first button with "cancel" or "no" as the label. + * If no such labeled buttons exist and this option is not set, 0 will be used as + * the return value or callback response. This option is ignored on Windows. + */ + cancelId?: number; + /** + * On Windows Electron will try to figure out which one of the buttons are common + * buttons (like "Cancel" or "Yes"), and show the others as command links in the + * dialog. This can make the dialog appear in the style of modern Windows apps. If + * you don't like this behavior, you can set noLink to true. + */ + noLink?: boolean; + /** + * Normalize the keyboard access keys across platforms. Default is false. Enabling + * this assumes & is used in the button labels for the placement of the keyboard + * shortcut access key and labels will be converted so they work correctly on each + * platform, & characters are removed on macOS, converted to _ on Linux, and left + * untouched on Windows. For example, a button label of Vie&w will be converted to + * Vie_w on Linux and View on macOS and can be selected via Alt-W on Windows and + * Linux. + */ + normalizeAccessKeys?: boolean; + } + + interface NewWindowEvent extends Event { + url: string; + frameName: string; + /** + * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, + * `save-to-disk` and `other`. + */ + disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); + /** + * The options which should be used for creating the new `BrowserWindow`. + */ + options: Options; + } + + interface NotificationConstructorOptions { + /** + * A title for the notification, which will be shown at the top of the notification + * window when it is shown + */ + title: string; + /** + * A subtitle for the notification, which will be displayed below the title. + */ + subtitle?: string; + /** + * The body text of the notification, which will be displayed below the title or + * subtitle + */ + body: string; + /** + * Whether or not to emit an OS notification noise when showing the notification + */ + silent?: boolean; + /** + * An icon to use in the notification + */ + icon?: NativeImage; + /** + * Whether or not to add an inline reply option to the notification. + */ + hasReply?: boolean; + /** + * The placeholder to write in the inline reply input field. + */ + replyPlaceholder?: string; + /** + * The name of the sound file to play when the notification is shown. + */ + sound?: string; + /** + * Actions to add to the notification. Please read the available actions and + * limitations in the NotificationAction documentation + */ + actions?: NotificationAction[]; + } + + interface OnBeforeRedirectDetails { + id: string; + url: string; + method: string; + resourceType: string; + timestamp: number; + redirectURL: string; + statusCode: number; + /** + * The server IP address that the request was actually sent to. + */ + ip?: string; + fromCache: boolean; + responseHeaders: ResponseHeaders; + } + + interface OnBeforeRedirectFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OnBeforeRequestDetails { + id: number; + url: string; + method: string; + resourceType: string; + timestamp: number; + uploadData: UploadData[]; + } + + interface OnBeforeRequestFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OnBeforeSendHeadersFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OnCompletedDetails { + id: number; + url: string; + method: string; + resourceType: string; + timestamp: number; + responseHeaders: ResponseHeaders; + fromCache: boolean; + statusCode: number; + statusLine: string; + } + + interface OnCompletedFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OnErrorOccurredDetails { + id: number; + url: string; + method: string; + resourceType: string; + timestamp: number; + fromCache: boolean; + /** + * The error description. + */ + error: string; + } + + interface OnErrorOccurredFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OnHeadersReceivedFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OnResponseStartedDetails { + id: number; + url: string; + method: string; + resourceType: string; + timestamp: number; + responseHeaders: ResponseHeaders; + /** + * Indicates whether the response was fetched from disk cache. + */ + fromCache: boolean; + statusCode: number; + statusLine: string; + } + + interface OnResponseStartedFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OnSendHeadersDetails { + id: number; + url: string; + method: string; + resourceType: string; + timestamp: number; + requestHeaders: RequestHeaders; + } + + interface OnSendHeadersFilter { + /** + * Array of URL patterns that will be used to filter out the requests that do not + * match the URL patterns. + */ + urls: string[]; + } + + interface OpenDevToolsOptions { + /** + * Opens the devtools with specified dock state, can be right, bottom, undocked, + * detach. Defaults to last used dock state. In undocked mode it's possible to dock + * back. In detach mode it's not. + */ + mode: ('right' | 'bottom' | 'undocked' | 'detach'); + } + + interface OpenDialogOptions { + title?: string; + defaultPath?: string; + /** + * Custom label for the confirmation button, when left empty the default label will + * be used. + */ + buttonLabel?: string; + filters?: FileFilter[]; + /** + * Contains which features the dialog should use. The following values are + * supported: + */ + properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'>; + /** + * Message to display above input boxes. + */ + message?: string; + } + + interface OpenExternalOptions { + /** + * true to bring the opened application to the foreground. The default is true. + */ + activate: boolean; + } + + interface PageFaviconUpdatedEvent extends Event { + /** + * Array of URLs. + */ + favicons: string[]; + } + + interface PageTitleUpdatedEvent extends Event { + title: string; + explicitSet: boolean; + } + + interface Parameters { + /** + * Specify the screen type to emulate (default: desktop) + */ + screenPosition: ('desktop' | 'mobile'); /** * Set the emulated screen size (screenPosition == mobile) */ - screenSize?: Size; + screenSize: Size; /** - * Position the view on the screen (screenPosition == mobile) - * Default: {x: 0, y: 0} + * Position the view on the screen (screenPosition == mobile) (default: {x: 0, y: + * 0}) */ - viewPosition?: Point; + viewPosition: Point; /** * Set the device scale factor (if zero defaults to original device scale factor) - * Default: 0 + * (default: 0) */ deviceScaleFactor: number; /** - * Set the emulated view size (empty means no override). + * Set the emulated view size (empty means no override) */ - viewSize?: Size; + viewSize: Size; /** - * Whether emulated view should be scaled down if necessary to fit into available space - * Default: false + * Whether emulated view should be scaled down if necessary to fit into available + * space (default: false) */ - fitToView?: boolean; + fitToView: boolean; /** * Offset of the emulated view inside available space (not in fit to view mode) - * Default: {x: 0, y: 0} + * (default: {x: 0, y: 0}) */ - offset?: Point; + offset: Point; /** * Scale of emulated view inside available space (not in fit to view mode) - * Default: 1 + * (default: 1) */ scale: number; } - interface SendInputEvent { - type: 'mouseDown' | 'mouseUp' | 'mouseEnter' | 'mouseLeave' | 'contextMenu' | 'mouseWheel' | 'mouseMove' | 'keyDown' | 'keyUp' | 'char'; - modifiers: ('shift' | 'control' | 'alt' | 'meta' | 'isKeypad' | 'isAutoRepeat' | 'leftButtonDown' | 'middleButtonDown' | 'rightButtonDown' | 'capsLock' | 'numLock' | 'left' | 'right')[]; + interface PluginCrashedEvent extends Event { + name: string; + version: string; } - interface SendInputKeyboardEvent extends SendInputEvent { - keyCode: string; + interface PopupOptions { + /** + * Default is the current mouse cursor position. Must be declared if y is declared. + */ + x?: number; + /** + * Default is the current mouse cursor position. Must be declared if x is declared. + */ + y?: number; + /** + * Set to true to have this method return immediately called, false to return after + * the menu has been selected or closed. Defaults to false. + */ + async?: boolean; + /** + * The index of the menu item to be positioned under the mouse cursor at the + * specified coordinates. Default is -1. + */ + positioningItem?: number; } - interface SendInputMouseEvent extends SendInputEvent { - x: number; - y: number; - button?: 'left' | 'middle' | 'right'; - globalX?: number; - globalY?: number; - movementX?: number; - movementY?: number; - clickCount?: number; + interface PrintOptions { + /** + * Don't ask user for print settings. Default is false. + */ + silent?: boolean; + /** + * Also prints the background color and image of the web page. Default is false. + */ + printBackground?: boolean; + /** + * Set the printer device name to use. Default is ''. + */ + deviceName?: string; } - interface SendInputMouseWheelEvent extends SendInputEvent { - deltaX?: number; - deltaY?: number; - wheelTicksX?: number; - wheelTicksY?: number; - accelerationRatioX?: number; - accelerationRatioY?: number; - hasPreciseScrollingDeltas?: boolean; - canScroll?: boolean; - } - - /** - * Debugger API serves as an alternate transport for remote debugging protocol. - */ - interface Debugger extends NodeJS.EventEmitter { + interface PrintToPDFOptions { /** - * Attaches the debugger to the webContents. - * @param protocolVersion Requested debugging protocol version. + * Specifies the type of margins to use. Uses 0 for default margin, 1 for no + * margin, and 2 for minimum margin. */ - attach(protocolVersion?: string): void; + marginsType?: number; /** - * @returns Whether a debugger is attached to the webContents. + * Specify page size of the generated PDF. Can be A3, A4, A5, Legal, Letter, + * Tabloid or an Object containing height and width in microns. */ - isAttached(): boolean; + pageSize?: string; /** - * Detaches the debugger from the webContents. + * Whether to print CSS backgrounds. */ - detach(): void; + printBackground?: boolean; /** - * Send given command to the debugging target. - * @param method Method name, should be one of the methods defined by the remote debugging protocol. - * @param commandParams JSON object with request parameters. - * @param callback Response defined by the ā€˜returns’ attribute of the command description in the remote debugging protocol. + * Whether to print selection only. */ - sendCommand(method: string, commandParams?: any, callback?: (error: Error, result: any) => void): void; + printSelectionOnly?: boolean; /** - * Emitted when debugging session is terminated. This happens either when - * webContents is closed or devtools is invoked for the attached webContents. + * true for landscape, false for portrait. */ - on(event: 'detach', listener: (event: Event, reason: string) => void): this; - /** - * Emitted whenever debugging target issues instrumentation event. - * Event parameters defined by the ā€˜parameters’ attribute in the remote debugging protocol. - */ - on(event: 'message', listener: (event: Event, method: string, params: any) => void): this; - on(event: string, listener: Function): this; - } - - // https://github.com/electron/electron/blob/master/docs/api/web-frame.md - - /** - * The web-frame module allows you to customize the rendering of the current web page. - */ - interface WebFrame { - /** - * Changes the zoom factor to the specified factor, zoom factor is - * zoom percent / 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * @returns The current zoom factor. - */ - getZoomFactor(): number; - /** - * Changes the zoom level to the specified level, 0 is "original size", and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. - */ - setZoomLevel(level: number): void; - /** - * @returns The current zoom level. - */ - getZoomLevel(): number; - /** - * Sets the maximum and minimum zoom level. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Sets a provider for spell checking in input fields and text areas. - */ - setSpellCheckProvider(language: string, autoCorrectWord: boolean, provider: { - /** - * @returns Whether the word passed is correctly spelled. - */ - spellCheck: (text: string) => boolean; - }): void; - /** - * Sets the scheme as secure scheme. Secure schemes do not trigger mixed content - * warnings. For example, https and data are secure schemes because they cannot be - * corrupted by active network attackers. - */ - registerURLSchemeAsSecure(scheme: string): void; - /** - * Resources will be loaded from this scheme regardless of the current page’s Content Security Policy. - */ - registerURLSchemeAsBypassingCSP(scheme: string): void; - /** - * Registers the scheme as secure, bypasses content security policy for resources, - * allows registering ServiceWorker and supports fetch API. - */ - registerURLSchemeAsPrivileged(scheme: string, options?: RegisterURLSchemeOptions): void; - /** - * Inserts text to the focused element. - */ - insertText(text: string): void; - /** - * Evaluates `code` in page. - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - * - * @returns Promise - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * @returns Object describing usage information of Blink’s internal memory caches. - */ - getResourceUsage(): ResourceUsages; - /** - * Attempts to free memory that is no longer being used (like images from a previous navigation). - */ - clearCache(): void; - } - - interface ResourceUsages { - fonts: ResourceUsage; - images: ResourceUsage; - cssStyleSheets: ResourceUsage; - xslStyleSheets: ResourceUsage; - scripts: ResourceUsage; - other: ResourceUsage; - } - - interface ResourceUsage { - count: number; - decodedSize: number; - liveSize: number; - purgeableSize: number; - purgedSize: number; - size: number; - } - - interface RegisterURLSchemeOptions { - secure?: boolean; - bypassCSP?: boolean; - allowServiceWorkers?: boolean; - supportFetchAPI?: boolean; - corsEnabled?: boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/web-view-tag.md - - /** - * Use the webview tag to embed 'guest' content (such as web pages) in your Electron app. - * The guest content is contained within the webview container. - * An embedded page within your app controls how the guest content is laid out and rendered. - * - * Unlike an iframe, the webview runs in a separate process than your app. - * It doesn't have the same permissions as your web page and all interactions between your app - * and embedded content will be asynchronous. This keeps your app safe from the embedded content. - */ - interface WebViewElement extends HTMLElement { - /** - * Returns the visible URL. Writing to this attribute initiates top-level navigation. - * Assigning src its own value will reload the current page. - * The src attribute can also accept data URLs, such as data:text/plain,Hello, world!. - */ - src: string; - /** - * If "on", the webview container will automatically resize within the bounds specified - * by the attributes minwidth, minheight, maxwidth, and maxheight. - * These constraints do not impact the webview unless autosize is enabled. - * When autosize is enabled, the webview container size cannot be less than - * the minimum values or greater than the maximum. - */ - autosize: string; - /** - * If "on", the guest page in webview will have node integration and can use node APIs - * like require and process to access low level system resources. - */ - nodeintegration: string; - /** - * If "on", the guest page in webview will be able to use browser plugins. - */ - plugins: string; - /** - * Specifies a script that will be loaded before other scripts run in the guest page. - * The protocol of script's URL must be either file: or asar:, - * because it will be loaded by require in guest page under the hood. - * - * When the guest page doesn't have node integration this script will still have access to all Node APIs, - * but global objects injected by Node will be deleted after this script has finished executing. - */ - preload: string; - /** - * Sets the referrer URL for the guest page. - */ - httpreferrer: string; - /** - * Sets the user agent for the guest page before the page is navigated to. - * Once the page is loaded, use the setUserAgent method to change the user agent. - */ - useragent: string; - /** - * If "on", the guest page will have web security disabled. - */ - disablewebsecurity: string; - /** - * Sets the session used by the page. If partition starts with persist:, - * the page will use a persistent session available to all pages in the app with the same partition. - * If there is no persist: prefix, the page will use an in-memory session. - * By assigning the same partition, multiple pages can share the same session. - * If the partition is unset then default session of the app will be used. - * - * This value can only be modified before the first navigation, - * since the session of an active renderer process cannot change. - * Subsequent attempts to modify the value will fail with a DOM exception. - */ - partition: string; - /** - * If "on", the guest page will be allowed to open new windows. - */ - allowpopups: string; - /** - * A list of strings which specifies the web preferences to be set on the webview, separated by ,. - */ - webpreferences: string; - /** - * A list of strings which specifies the blink features to be enabled separated by ,. - */ - blinkfeatures: string; - /** - * A list of strings which specifies the blink features to be disabled separated by ,. - */ - disableblinkfeatures: string; - /** - * A value that links the webview to a specific webContents. - * When a webview first loads a new webContents is created and this attribute is set - * to its instance identifier. Setting this attribute on a new or existing webview connects - * it to the existing webContents that currently renders in a different webview. - * - * The existing webview will see the destroy event and will then create a new webContents when a new url is loaded. - */ - guestinstance: string; - /** - * Loads the url in the webview, the url must contain the protocol prefix, e.g. the http:// or file://. - */ - loadURL(url: string, options?: LoadURLOptions): void; - /** - * @returns URL of guest page. - */ - getURL(): string; - /** - * @returns The title of guest page. - */ - getTitle(): string; - /** - * @returns Whether the web page is destroyed. - */ - isDestroyed(): boolean; - /** - * @returns Whether the web page is focused. - */ - isFocused(): boolean; - /** - * @returns Whether guest page is still loading resources. - */ - isLoading(): boolean; - /** - * Returns a boolean whether the guest page is waiting for a first-response for the main resource of the page. - */ - isWaitingForResponse(): boolean; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Reloads the guest page. - */ - reload(): void; - /** - * Reloads the guest page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * @returns Whether the guest page can go back. - */ - canGoBack(): boolean; - /** - * @returns Whether the guest page can go forward. - */ - canGoForward(): boolean; - /** - * @returns Whether the guest page can go to offset. - */ - canGoToOffset(offset: number): boolean; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Makes the guest page go back. - */ - goBack(): void; - /** - * Makes the guest page go forward. - */ - goForward(): void; - /** - * Navigates to the specified absolute index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * @returns Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Overrides the user agent for the guest page. - */ - setUserAgent(userAgent: string): void; - /** - * @returns The user agent for guest page. - */ - getUserAgent(): string; - /** - * Injects CSS into the guest page. - */ - insertCSS(css: string): void; - /** - * Evaluates code in page. If userGesture is set, it will create the user gesture context in the page. - * HTML APIs like requestFullScreen, which require user action, can take advantage of this option for automation. - * - * @returns Promise - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * Opens a DevTools window for guest page. - */ - openDevTools(): void; - /** - * Closes the DevTools window of guest page. - */ - closeDevTools(): void; - /** - * @returns Whether guest page has a DevTools window attached. - - isDevToolsOpened(): boolean; - /** - * @returns Whether DevTools window of guest page is focused. - */ - isDevToolsFocused(): boolean; - /** - * Starts inspecting element at position (x, y) of guest page. - */ - inspectElement(x: number, y: number): void; - /** - * Opens the DevTools for the service worker context present in the guest page. - */ - inspectServiceWorker(): void; - /** - * Set guest page muted. - */ - setAudioMuted(muted: boolean): void; - /** - * @returns Whether guest page has been muted. - */ - isAudioMuted(): boolean; - /** - * Executes editing command undo in page. - */ - undo(): void; - /** - * Executes editing command redo in page. - */ - redo(): void; - /** - * Executes editing command cut in page. - */ - cut(): void; - /** - * Executes editing command copy in page. - */ - copy(): void; - /** - * Executes editing command paste in page. - */ - paste(): void; - /** - * Executes editing command pasteAndMatchStyle in page. - */ - pasteAndMatchStyle(): void; - /** - * Executes editing command delete in page. - */ - delete(): void; - /** - * Executes editing command selectAll in page. - */ - selectAll(): void; - /** - * Executes editing command unselect in page. - */ - unselect(): void; - /** - * Executes editing command replace in page. - */ - replace(text: string): void; - /** - * Executes editing command replaceMisspelling in page. - */ - replaceMisspelling(text: string): void; - /** - * Inserts text to the focused element. - */ - insertText(text: string): void; - /** - * Starts a request to find all matches for the text in the web page. - * The result of the request can be obtained by subscribing to found-in-page event. - * @returns The request id used for the request. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * Stops any findInPage request for the webview with the provided action. - */ - stopFindInPage(action: StopFindInPageAtion): void; - /** - * Prints webview's web page. Same with webContents.print([options]). - */ - print(options?: PrintOptions): void; - /** - * Prints webview's web page as PDF, Same with webContents.printToPDF(options, callback) - */ - printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; - /** - * Send an asynchronous message to renderer process via channel, you can also send arbitrary arguments. - * The renderer process can handle the message by listening to the channel event with the ipcRenderer module. - * See webContents.send for examples. - */ - send(channel: string, ...args: any[]): void; - /** - * Sends an input event to the page. - * See webContents.sendInputEvent for detailed description of event object. - */ - sendInputEvent(event: SendInputEvent): void - /** - * Changes the zoom factor to the specified factor. - * Zoom factor is zoom percent divided by 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. - * The original size is 0 and each increment above or below represents - * zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. - */ - setZoomLevel(level: number): void; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * Note: This API is available only on macOS. - */ - showDefinitionForSelection(): void; - /** - * @returns The WebContents associated with this webview. - */ - getWebContents(): WebContents; - /** - * Captures a snapshot of the webview's page. Same as webContents.capturePage([rect, ]callback). - */ - capturePage(callback: (image: NativeImage) => void): void; - /** - * Captures a snapshot of the webview's page. Same as webContents.capturePage([rect, ]callback). - */ - capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; - /** - * Fired when a load has committed. This includes navigation within the current document - * as well as subframe document-level loads, but does not include asynchronous resource loads. - */ - addEventListener(type: 'load-commit', listener: (event: WebViewElement.LoadCommitEvent) => void, useCapture?: boolean): void; - /** - * Fired when the navigation is done, i.e. the spinner of the tab will stop spinning, and the onload event is dispatched. - */ - addEventListener(type: 'did-finish-load', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * This event is like did-finish-load, but fired when the load failed or was cancelled, e.g. window.stop() is invoked. - */ - addEventListener(type: 'did-fail-load', listener: (event: WebViewElement.DidFailLoadEvent) => void, useCapture?: boolean): void; - /** - * Fired when a frame has done navigation. - */ - addEventListener(type: 'did-frame-finish-load', listener: (event: WebViewElement.DidFrameFinishLoadEvent) => void, useCapture?: boolean): void; - /** - * Corresponds to the points in time when the spinner of the tab starts spinning. - */ - addEventListener(type: 'did-start-loading', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Corresponds to the points in time when the spinner of the tab stops spinning. - */ - addEventListener(type: 'did-stop-loading', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when details regarding a requested resource is available. - * status indicates socket connection to download the resource. - */ - addEventListener(type: 'did-get-response-details', listener: (event: WebViewElement.DidGetResponseDetails) => void, useCapture?: boolean): void; - /** - * Fired when a redirect was received while requesting a resource. - */ - addEventListener(type: 'did-get-redirect-request', listener: (event: WebViewElement.DidGetRedirectRequestEvent) => void, useCapture?: boolean): void; - /** - * Fired when document in the given frame is loaded. - */ - addEventListener(type: 'dom-ready', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when page title is set during navigation. explicitSet is false when title is synthesized from file URL. - */ - addEventListener(type: 'page-title-updated', listener: (event: WebViewElement.PageTitleUpdatedEvent) => void, useCapture?: boolean): void; - /** - * Fired when page receives favicon URLs. - */ - addEventListener(type: 'page-favicon-updated', listener: (event: WebViewElement.PageFaviconUpdatedEvent) => void, useCapture?: boolean): void; - /** - * Fired when page enters fullscreen triggered by HTML API. - */ - addEventListener(type: 'enter-html-full-screen', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when page leaves fullscreen triggered by HTML API. - */ - addEventListener(type: 'leave-html-full-screen', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when the guest window logs a console message. - */ - addEventListener(type: 'console-message', listener: (event: WebViewElement.ConsoleMessageEvent) => void, useCapture?: boolean): void; - /** - * Fired when a result is available for webview.findInPage request. - */ - addEventListener(type: 'found-in-page', listener: (event: WebViewElement.FoundInPageEvent) => void, useCapture?: boolean): void; - /** - * Fired when the guest page attempts to open a new browser window. - */ - addEventListener(type: 'new-window', listener: (event: WebViewElement.NewWindowEvent) => void, useCapture?: boolean): void; - /** - * Emitted when a user or the page wants to start navigation. - * It can happen when the window.location object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with APIs - * like .loadURL and .back. - * - * It is also not emitted during in-page navigation, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - * - * Calling event.preventDefault() does NOT have any effect. - */ - addEventListener(type: 'will-navigate', listener: (event: WebViewElement.WillNavigateEvent) => void, useCapture?: boolean): void; - /** - * Emitted when a navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - */ - addEventListener(type: 'did-navigate', listener: (event: WebViewElement.DidNavigateEvent) => void, useCapture?: boolean): void; - /** - * Emitted when an in-page navigation happened. - * - * When in-page navigation happens, the page URL changes but does not cause - * navigation outside of the page. Examples of this occurring are when anchor links - * are clicked or when the DOM hashchange event is triggered. - */ - addEventListener(type: 'did-navigate-in-page', listener: (event: WebViewElement.DidNavigateInPageEvent) => void, useCapture?: boolean): void; - /** - * Fired when the guest page attempts to close itself. - */ - addEventListener(type: 'close', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when the guest page has sent an asynchronous message to embedder page. - */ - addEventListener(type: 'ipc-message', listener: (event: WebViewElement.IpcMessageEvent) => void, useCapture?: boolean): void; - /** - * Fired when the renderer process is crashed. - */ - addEventListener(type: 'crashed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when the gpu process is crashed. - */ - addEventListener(type: 'gpu-crashed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when a plugin process is crashed. - */ - addEventListener(type: 'plugin-crashed', listener: (event: WebViewElement.PluginCrashedEvent) => void, useCapture?: boolean): void; - /** - * Fired when the WebContents is destroyed. - */ - addEventListener(type: 'destroyed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when media starts playing. - */ - addEventListener(type: 'media-started-playing', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when media is paused or done playing. - */ - addEventListener(type: 'media-paused', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when a page's theme color changes. This is usually due to encountering a meta tag: - * - */ - addEventListener(type: 'did-change-theme-color', listener: (event: WebViewElement.DidChangeThemeColorEvent) => void, useCapture?: boolean): void; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - addEventListener(type: 'update-target-url', listener: (event: WebViewElement.UpdateTargetUrlEvent) => void, useCapture?: boolean): void; - /** - * Emitted when DevTools is opened. - */ - addEventListener(type: 'devtools-opened', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when DevTools is closed. - */ - addEventListener(type: 'devtools-closed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when DevTools is focused / opened. - */ - addEventListener(type: 'devtools-focused', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - addEventListener(type: string, listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - } - - namespace WebViewElement { - type Event = ElectronPrivate.GlobalEvent; - - interface LoadCommitEvent extends Event { - url: string; - isMainFrame: boolean; - } - - interface DidFailLoadEvent extends Event { - errorCode: number; - errorDescription: string; - validatedURL: string; - isMainFrame: boolean; - } - - interface DidFrameFinishLoadEvent extends Event { - isMainFrame: boolean; - } - - interface DidGetResponseDetails extends Event { - status: boolean; - newURL: string; - originalURL: string; - httpResponseCode: number; - requestMethod: string; - referrer: string; - headers: Headers; - resourceType: string; - } - - interface DidGetRedirectRequestEvent extends Event { - oldURL: string; - newURL: string; - isMainFrame: boolean; - httpResponseCode: number; - requestMethod: string; - referrer: string; - headers: Headers; - } - - interface PageTitleUpdatedEvent extends Event { - title: string; - explicitSet: string; - } - - interface PageFaviconUpdatedEvent extends Event { - favicons: string[]; - } - - interface ConsoleMessageEvent extends Event { - level: number; - message: string; - line: number; - sourceId: string; - } - - interface FoundInPageEvent extends Event { - result: FoundInPageResult; - } - - interface NewWindowEvent extends Event { - url: string; - frameName: string; - disposition: NewWindowDisposition; - options: BrowserWindowOptions; - } - - interface WillNavigateEvent extends Event { - url: string; - } - - interface DidNavigateEvent extends Event { - url: string; - } - - interface DidNavigateInPageEvent extends Event { - url: string; - isMainFrame: boolean; - } - - interface IpcMessageEvent extends Event { - channel: string; - args: any[]; - } - - interface PluginCrashedEvent extends Event { - name: string; - version: string; - } - - interface DidChangeThemeColorEvent extends Event { - themeColor: string; - } - - interface UpdateTargetUrlEvent extends Event { - url: string; - } - } - - /** - * The BrowserWindowProxy object is returned from window.open and provides limited functionality with the child window. - */ - interface BrowserWindowProxy { - /** - * Removes focus from the child window. - */ - blur(): void; - /** - * Forcefully closes the child window without calling its unload event. - */ - close(): void; - /** - * Set to true after the child window gets closed. - */ - closed: boolean; - /** - * Evaluates the code in the child window. - */ - eval(code: string): void; - /** - * Focuses the child window (brings the window to front). - */ - focus(): void; - /** - * Sends a message to the child window with the specified origin or * for no origin preference. - * In addition to these methods, the child window implements window.opener object with no - * properties and a single method. - */ - postMessage(message: string, targetOrigin: string): void; - /** - * Invokes the print dialog on the child window. - */ - print(): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/synopsis.md - - interface CommonElectron { - clipboard: Electron.Clipboard; - crashReporter: Electron.CrashReporter; - nativeImage: typeof Electron.NativeImage; - shell: Electron.Shell; - - app: Electron.App; - autoUpdater: Electron.AutoUpdater; - BrowserWindow: typeof Electron.BrowserWindow; - contentTracing: Electron.ContentTracing; - dialog: Electron.Dialog; - ipcMain: Electron.IpcMain; - globalShortcut: Electron.GlobalShortcut; - Menu: typeof Electron.Menu; - MenuItem: typeof Electron.MenuItem; - net: Electron.Net; - powerMonitor: Electron.PowerMonitor; - powerSaveBlocker: Electron.PowerSaveBlocker; - protocol: Electron.Protocol; - screen: Electron.Screen; - session: typeof Electron.Session; - systemPreferences: Electron.SystemPreferences; - Tray: typeof Electron.Tray; - webContents: Electron.WebContentsStatic; - } - - interface ElectronMainAndRenderer extends CommonElectron { - desktopCapturer: Electron.DesktopCapturer; - ipcRenderer: Electron.IpcRenderer; - remote: Electron.Remote; - webFrame: Electron.WebFrame; - } -} - -declare namespace ElectronPrivate { - type GlobalEvent = Event; -} - -interface Document { - createElement(tagName: 'webview'): Electron.WebViewElement; -} - -// https://github.com/electron/electron/blob/master/docs/api/window-open.md - -interface Window { - /** - * Creates a new window. - */ - open(url: string, frameName?: string, features?: string): Electron.BrowserWindowProxy; -} - -// https://github.com/electron/electron/blob/master/docs/api/file-object.md - -interface File { - /** - * Exposes the real path of the filesystem. - */ - path: string; -} - -// https://github.com/electron/electron/blob/master/docs/api/process.md - -declare namespace NodeJS { - - interface ProcessVersions { - /** - * Electron's version string. - */ - electron: string; - /** - * Chrome's version string. - */ - chrome: string; - } - - interface Process { - /** - * Setting this to true can disable the support for asar archives in Node's built-in modules. - */ - noAsar?: boolean; - /** - * Process's type - */ - type: 'browser' | 'renderer'; - /** - * Path to JavaScript source code. - */ - resourcesPath: string; - /** - * For Mac App Store build, this value is true, for other builds it is undefined. - */ - mas?: boolean; - /** - * If the app is running as a Windows Store app (appx), this value is true, for other builds it is undefined. - */ - windowsStore?: boolean; - /** - * When app is started by being passed as parameter to the default app, - * this value is true in the main process, otherwise it is undefined. - */ - defaultApp?: boolean; - /** - * Emitted when Electron has loaded its internal initialization script - * and is beginning to load the web page or the main script. - */ - on(event: 'loaded', listener: Function): this; - on(event: string, listener: Function): this; - /** - * Causes the main thread of the current process crash; - */ - crash(): void; - /** - * Causes the main thread of the current process hang. - */ - hang(): void; - /** - * Sets the file descriptor soft limit to maxDescriptors or the OS hard limit, - * whichever is lower for the current process. - * - * Note: This API is only available on macOS and Linux. - */ - setFdLimit(maxDescriptors: number): void; - /** - * @returns Object giving memory usage statistics about the current process. - * Note: All statistics are reported in Kilobytes. - */ - getProcessMemoryInfo(): ProcessMemoryInfo; - /** - * @returns Object giving memory usage statistics about the entire system. - * Note: All statistics are reported in Kilobytes. - */ - getSystemMemoryInfo(): SystemMemoryInfo; + landscape?: boolean; } interface ProcessMemoryInfo { @@ -5999,18 +7289,249 @@ declare namespace NodeJS { */ peakWorkingSetSize: number; /** - * The amount of memory not shared by other processes, such as JS heap or HTML content. + * The amount of memory not shared by other processes, such as JS heap or HTML + * content. */ privateBytes: number; /** - * The amount of memory shared between processes, typically memory consumed by the Electron code itself. + * The amount of memory shared between processes, typically memory consumed by the + * Electron code itself */ sharedBytes: number; } + interface ProgressBarOptions { + /** + * Mode for the progress bar. Can be none, normal, indeterminate, error, or paused. + */ + mode: ('none' | 'normal' | 'indeterminate' | 'error'); + } + + interface Provider { + /** + * Returns Boolean + */ + spellCheck: (text: string) => void; + } + + interface ReadBookmark { + title: string; + url: string; + } + + interface RedirectRequest { + url: string; + method: string; + session?: Session; + uploadData?: UploadData; + } + + interface RegisterBufferProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface RegisterFileProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface RegisterHttpProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface RegisterStandardSchemesOptions { + /** + * true to register the scheme as secure. Default false. + */ + secure?: boolean; + } + + interface RegisterStringProtocolRequest { + url: string; + referrer: string; + method: string; + uploadData: UploadData[]; + } + + interface RegisterURLSchemeAsPrivilegedOptions { + /** + * Default true. + */ + secure?: boolean; + /** + * Default true. + */ + bypassCSP?: boolean; + /** + * Default true. + */ + allowServiceWorkers?: boolean; + /** + * Default true. + */ + supportFetchAPI?: boolean; + /** + * Default true. + */ + corsEnabled?: boolean; + } + + interface RelaunchOptions { + args?: string[]; + execPath?: string; + } + + interface Request { + method: string; + url: string; + referrer: string; + } + + interface ResizeOptions { + /** + * Defaults to the image's width. + */ + width?: number; + /** + * Defaults to the image's height + */ + height?: number; + /** + * The desired quality of the resize image. Possible values are good, better or + * best. The default is best. These values express a desired quality/speed + * tradeoff. They are translated into an algorithm-specific method that depends on + * the capabilities (CPU, GPU) of the underlying platform. It is possible for all + * three methods to be mapped to the same algorithm on a given platform. + */ + quality?: string; + } + + interface ResourceUsage { + images: MemoryUsageDetails; + cssStyleSheets: MemoryUsageDetails; + xslStyleSheets: MemoryUsageDetails; + fonts: MemoryUsageDetails; + other: MemoryUsageDetails; + } + + interface Response { + cancel?: boolean; + /** + * The original request is prevented from being sent or completed and is instead + * redirected to the given URL. + */ + redirectURL?: string; + } + + interface Result { + requestId: number; + /** + * Position of the active match. + */ + activeMatchOrdinal: number; + /** + * Number of Matches. + */ + matches: number; + /** + * Coordinates of first match region. + */ + selectionArea: SelectionArea; + finalUpdate: boolean; + } + + interface SaveDialogOptions { + title?: string; + /** + * Absolute directory path, absolute file path, or file name to use by default. + */ + defaultPath?: string; + /** + * Custom label for the confirmation button, when left empty the default label will + * be used. + */ + buttonLabel?: string; + filters?: FileFilter[]; + /** + * Message to display above text fields. + */ + message?: string; + /** + * Custom label for the text displayed in front of the filename text field. + */ + nameFieldLabel?: string; + /** + * Show the tags input box, defaults to true. + */ + showsTagField?: boolean; + } + + interface Settings { + /** + * true to open the app at login, false to remove the app as a login item. Defaults + * to false. + */ + openAtLogin?: boolean; + /** + * true to open the app as hidden. Defaults to false. The user can edit this + * setting from the System Preferences so + * app.getLoginItemStatus().wasOpenedAsHidden should be checked when the app is + * opened to know the current value. This setting is only supported on macOS. + */ + openAsHidden?: boolean; + /** + * The executable to launch at login. Defaults to process.execPath. + */ + path?: string; + /** + * The command-line arguments to pass to the executable. Defaults to an empty + * array. Take care to wrap paths in quotes. + */ + args?: string[]; + } + + interface SizeOptions { + /** + * Normal size of the page. This can be used in combination with the attribute to + * manually resize the webview guest contents. + */ + normal?: Normal; + } + + interface SourcesOptions { + /** + * An array of Strings that lists the types of desktop sources to be captured, + * available types are screen and window. + */ + types: string[]; + /** + * The size that the media source thumbnail should be scaled to. Default is 150 x + * 150. + */ + thumbnailSize?: Size; + } + + interface StartMonitoringOptions { + categoryFilter: string; + traceOptions: string; + } + + interface StartRecordingOptions { + categoryFilter: string; + traceOptions: string; + } + interface SystemMemoryInfo { /** - * The total amount of physical memory available to the system. + * The total amount of physical memory in Kilobytes available to the system. */ total: number; /** @@ -6018,21 +7539,668 @@ declare namespace NodeJS { */ free: number; /** - * The total amount of swap memory available to the system. + * The total amount of swap memory in Kilobytes available to the system. */ swapTotal: number; /** - * The free amount of swap memory available to the system. + * The free amount of swap memory in Kilobytes available to the system. */ swapFree: number; } + + interface ToBitmapOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface ToDataURLOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface ToPNGOptions { + /** + * Defaults to 1.0. + */ + scaleFactor?: number; + } + + interface TouchBarButtonConstructorOptions { + /** + * Button text. + */ + label?: string; + /** + * Button background color in hex format, i.e #ABCDEF. + */ + backgroundColor?: string; + /** + * Button icon. + */ + icon?: NativeImage; + /** + * Can be left, right or overlay. + */ + iconPosition: ('left' | 'right' | 'overlay'); + /** + * Function to call when the button is clicked. + */ + click?: () => void; + } + + interface TouchBarColorPickerConstructorOptions { + /** + * Array of hex color strings to appear as possible colors to select. + */ + availableColors?: string[]; + /** + * The selected hex color in the picker, i.e #ABCDEF. + */ + selectedColor?: string; + /** + * Function to call when a color is selected. + */ + change?: (color: string) => void; + } + + interface TouchBarConstructorOptions { + items: (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer)[]; + escapeItem?: TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer; + } + + interface TouchBarGroupConstructorOptions { + /** + * Items to display as a group. + */ + items: TouchBar; + } + + interface TouchBarLabelConstructorOptions { + /** + * Text to display. + */ + label?: string; + /** + * Hex color of text, i.e #ABCDEF. + */ + textColor?: string; + } + + interface TouchBarPopoverConstructorOptions { + /** + * Popover button text. + */ + label?: string; + /** + * Popover button icon. + */ + icon?: NativeImage; + /** + * Items to display in the popover. + */ + items?: TouchBar; + /** + * true to display a close button on the left of the popover, false to not show it. + * Default is true. + */ + showCloseButton?: boolean; + } + + interface TouchBarScrubberConstructorOptions { + /** + * An array of items to place in this scrubber + */ + items: ScrubberItem[]; + /** + * Called when the user taps an item that was not the last tapped item + */ + select: (selectedIndex: number) => void; + /** + * Called when the user taps any item + */ + highlight: (highlightedIndex: number) => void; + /** + * Selected item style. Defaults to null. + */ + selectedStyle: string; + /** + * Selected overlay item style. Defaults to null. + */ + overlayStyle: string; + /** + * Defaults to false. + */ + showArrowButtons: boolean; + /** + * Defaults to free. + */ + mode: string; + /** + * Defaults to true. + */ + continuous: boolean; + } + + interface TouchBarSegmentedControlConstructorOptions { + /** + * Style of the segments: + */ + segmentStyle?: ('automatic' | 'rounded' | 'textured-rounded' | 'round-rect' | 'textured-square' | 'capsule' | 'small-square' | 'separated'); + /** + * The selection mode of the control: + */ + mode?: ('single' | 'multiple' | 'buttons'); + /** + * An array of segments to place in this control. + */ + segments: SegmentedControlSegment[]; + /** + * The index of the currently selected segment, will update automatically with user + * interaction. When the mode is multiple it will be the last selected item. + */ + selectedIndex?: number; + /** + * Called when the user selects a new segment + */ + change: (selectedIndex: number, isSelected: boolean) => void; + } + + interface TouchBarSliderConstructorOptions { + /** + * Label text. + */ + label?: string; + /** + * Selected value. + */ + value?: number; + /** + * Minimum value. + */ + minValue?: number; + /** + * Maximum value. + */ + maxValue?: number; + /** + * Function to call when the slider is changed. + */ + change?: (newValue: number) => void; + } + + interface TouchBarSpacerConstructorOptions { + /** + * Size of spacer, possible values are: + */ + size?: ('small' | 'large' | 'flexible'); + } + + interface UpdateTargetUrlEvent extends Event { + url: string; + } + + interface Versions { + /** + * A String representing Chrome's version string. + */ + chrome?: string; + /** + * A String representing Electron's version string. + */ + electron?: string; + } + + interface WillNavigateEvent extends Event { + url: string; + } + + interface EditFlags { + /** + * Whether the renderer believes it can undo. + */ + canUndo: boolean; + /** + * Whether the renderer believes it can redo. + */ + canRedo: boolean; + /** + * Whether the renderer believes it can cut. + */ + canCut: boolean; + /** + * Whether the renderer believes it can copy + */ + canCopy: boolean; + /** + * Whether the renderer believes it can paste. + */ + canPaste: boolean; + /** + * Whether the renderer believes it can delete. + */ + canDelete: boolean; + /** + * Whether the renderer believes it can select all. + */ + canSelectAll: boolean; + } + + interface Extra { + } + + interface FoundInPageResult { + requestId: number; + /** + * Position of the active match. + */ + activeMatchOrdinal: number; + /** + * Number of Matches. + */ + matches: number; + /** + * Coordinates of first match region. + */ + selectionArea: SelectionArea; + finalUpdate: boolean; + } + + interface Headers { + } + + interface MediaFlags { + /** + * Whether the media element has crashed. + */ + inError: boolean; + /** + * Whether the media element is paused. + */ + isPaused: boolean; + /** + * Whether the media element is muted. + */ + isMuted: boolean; + /** + * Whether the media element has audio. + */ + hasAudio: boolean; + /** + * Whether the media element is looping. + */ + isLooping: boolean; + /** + * Whether the media element's controls are visible. + */ + isControlsVisible: boolean; + /** + * Whether the media element's controls are toggleable. + */ + canToggleControls: boolean; + /** + * Whether the media element can be rotated. + */ + canRotate: boolean; + } + + interface Normal { + width: number; + height: number; + } + + interface Options { + } + + interface RequestHeaders { + } + + interface ResponseHeaders { + } + + interface SelectionArea { + } + + interface WebPreferences { + /** + * Whether to enable DevTools. If it is set to false, can not use + * BrowserWindow.webContents.openDevTools() to open DevTools. Default is true. + */ + devTools?: boolean; + /** + * Whether node integration is enabled. Default is true. + */ + nodeIntegration?: boolean; + /** + * Whether node integration is enabled in web workers. Default is false. More about + * this can be found in . + */ + nodeIntegrationInWorker?: boolean; + /** + * Specifies a script that will be loaded before other scripts run in the page. + * This script will always have access to node APIs no matter whether node + * integration is turned on or off. The value should be the absolute file path to + * the script. When node integration is turned off, the preload script can + * reintroduce Node global symbols back to the global scope. See example . + */ + preload?: string; + /** + * If set, this will sandbox the renderer associated with the window, making it + * compatible with the Chromium OS-level sandbox and disabling the Node.js engine. + * This is not the same as the nodeIntegration option and the APIs available to the + * preload script are more limited. Read more about the option . This option is + * currently experimental and may change or be removed in future Electron releases. + */ + sandbox?: boolean; + /** + * Sets the session used by the page. Instead of passing the Session object + * directly, you can also choose to use the partition option instead, which accepts + * a partition string. When both session and partition are provided, session will + * be preferred. Default is the default session. + */ + session?: Session; + /** + * Sets the session used by the page according to the session's partition string. + * If partition starts with persist:, the page will use a persistent session + * available to all pages in the app with the same partition. If there is no + * persist: prefix, the page will use an in-memory session. By assigning the same + * partition, multiple pages can share the same session. Default is the default + * session. + */ + partition?: string; + /** + * The default zoom factor of the page, 3.0 represents 300%. Default is 1.0. + */ + zoomFactor?: number; + /** + * Enables JavaScript support. Default is true. + */ + javascript?: boolean; + /** + * When false, it will disable the same-origin policy (usually using testing + * websites by people), and set allowRunningInsecureContent to true if this options + * has not been set by user. Default is true. + */ + webSecurity?: boolean; + /** + * Allow an https page to run JavaScript, CSS or plugins from http URLs. Default is + * false. + */ + allowRunningInsecureContent?: boolean; + /** + * Enables image support. Default is true. + */ + images?: boolean; + /** + * Make TextArea elements resizable. Default is true. + */ + textAreasAreResizable?: boolean; + /** + * Enables WebGL support. Default is true. + */ + webgl?: boolean; + /** + * Enables WebAudio support. Default is true. + */ + webaudio?: boolean; + /** + * Whether plugins should be enabled. Default is false. + */ + plugins?: boolean; + /** + * Enables Chromium's experimental features. Default is false. + */ + experimentalFeatures?: boolean; + /** + * Enables Chromium's experimental canvas features. Default is false. + */ + experimentalCanvasFeatures?: boolean; + /** + * Enables scroll bounce (rubber banding) effect on macOS. Default is false. + */ + scrollBounce?: boolean; + /** + * A list of feature strings separated by ,, like CSSVariables,KeyboardEventKey to + * enable. The full list of supported feature strings can be found in the file. + */ + blinkFeatures?: string; + /** + * A list of feature strings separated by ,, like CSSVariables,KeyboardEventKey to + * disable. The full list of supported feature strings can be found in the file. + */ + disableBlinkFeatures?: string; + /** + * Sets the default font for the font-family. + */ + defaultFontFamily?: DefaultFontFamily; + /** + * Defaults to 16. + */ + defaultFontSize?: number; + /** + * Defaults to 13. + */ + defaultMonospaceFontSize?: number; + /** + * Defaults to 0. + */ + minimumFontSize?: number; + /** + * Defaults to ISO-8859-1. + */ + defaultEncoding?: string; + /** + * Whether to throttle animations and timers when the page becomes background. This + * also affects the [Page Visibility API][#page-visibility]. Defaults to true. + */ + backgroundThrottling?: boolean; + /** + * Whether to enable offscreen rendering for the browser window. Defaults to false. + * See the for more details. + */ + offscreen?: boolean; + /** + * Whether to run Electron APIs and the specified preload script in a separate + * JavaScript context. Defaults to false. The context that the preload script runs + * in will still have full access to the document and window globals but it will + * use its own set of JavaScript builtins (Array, Object, JSON, etc.) and will be + * isolated from any changes made to the global environment by the loaded page. The + * Electron API will only be available in the preload script and not the loaded + * page. This option should be used when loading potentially untrusted remote + * content to ensure the loaded content cannot tamper with the preload script and + * any Electron APIs being used. This option uses the same technique used by . You + * can access this context in the dev tools by selecting the 'Electron Isolated + * Context' entry in the combo box at the top of the Console tab. This option is + * currently experimental and may change or be removed in future Electron releases. + */ + contextIsolation?: boolean; + /** + * Whether to use native window.open(). Defaults to false. This option is currently + * experimental. + */ + nativeWindowOpen?: boolean; + /** + * Whether to enable the . Defaults to the value of the nodeIntegration option. The + * preload script configured for the will have node integration enabled + * when it is executed so you should ensure remote/untrusted content is not able to + * create a tag with a possibly malicious preload script. You can use the + * will-attach-webview event on to strip away the preload script and to validate or + * alter the 's initial settings. + */ + webviewTag?: boolean; + } + + interface DefaultFontFamily { + /** + * Defaults to Times New Roman. + */ + standard?: string; + /** + * Defaults to Times New Roman. + */ + serif?: string; + /** + * Defaults to Arial. + */ + sansSerif?: string; + /** + * Defaults to Courier New. + */ + monospace?: string; + /** + * Defaults to Script. + */ + cursive?: string; + /** + * Defaults to Impact. + */ + fantasy?: string; + } + + // ### BEGIN VSCODE ADDITION ### + type MenuItemRole = 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteandmatchstyle' | 'selectall' | 'delete' | 'minimize' | 'close' | 'quit' | 'togglefullscreen' | 'resetzoom' | 'zoomin' | 'zoomout' | 'about' | 'hide' | 'hideothers' | 'unhide' | 'startspeaking' | 'stopspeaking' | 'front' | 'zoom' | 'window' | 'help' | 'services'; + + interface LoginRequest { + method: string; + url: string; + referrer: string; + } + + interface LoginAuthInfo { + isProxy: boolean; + scheme: string; + host: string; + port: number; + realm: string; + } + // ### END VSCODE ADDITION ### } declare module 'electron' { - var electron: Electron.ElectronMainAndRenderer; - export = electron; + export = Electron; } -// interface NodeRequireFunction { -// (moduleName: 'electron'): Electron.ElectronMainAndRenderer; -// } \ No newline at end of file +interface NodeRequireFunction { + (moduleName: 'electron'): typeof Electron; +} + +interface File { + /** + * The real path to the file on the users filesystem + */ + path: string; +} + +declare module 'original-fs' { + import * as fs from 'fs'; + export = fs; +} + +interface Document { + createElement(tagName: 'webview'): Electron.WebviewTag; +} + +declare namespace NodeJS { + interface Process extends EventEmitter { + + // Docs: http://electron.atom.io/docs/api/process + + // /** + // * Emitted when Electron has loaded its internal initialization script and is + // * beginning to load the web page or the main script. It can be used by the preload + // * script to add removed Node global symbols back to the global scope when node + // * integration is turned off: + // */ + // on(event: 'loaded', listener: Function): this; + // once(event: 'loaded', listener: Function): this; + // addListener(event: 'loaded', listener: Function): this; + // removeListener(event: 'loaded', listener: Function): this; + /** + * Causes the main thread of the current process crash. + */ + crash(): void; + getCPUUsage(): Electron.CPUUsage; + getIOCounters(): Electron.IOCounters; + /** + * Returns an object giving memory usage statistics about the current process. Note + * that all statistics are reported in Kilobytes. + */ + getProcessMemoryInfo(): Electron.ProcessMemoryInfo; + /** + * Returns an object giving memory usage statistics about the entire system. Note + * that all statistics are reported in Kilobytes. + */ + getSystemMemoryInfo(): Electron.SystemMemoryInfo; + /** + * Causes the main thread of the current process hang. + */ + hang(): void; + /** + * Sets the file descriptor soft limit to maxDescriptors or the OS hard limit, + * whichever is lower for the current process. + */ + setFdLimit(maxDescriptors: number): void; + /** + * A Boolean. When app is started by being passed as parameter to the default app, + * this property is true in the main process, otherwise it is undefined. + */ + defaultApp?: boolean; + /** + * A Boolean. For Mac App Store build, this property is true, for other builds it + * is undefined. + */ + mas?: boolean; + /** + * A Boolean that controls ASAR support inside your application. Setting this to + * true will disable the support for asar archives in Node's built-in modules. + */ + noAsar?: boolean; + /** + * A Boolean that controls whether or not deprecation warnings are printed to + * stderr. Setting this to true will silence deprecation warnings. This property + * is used instead of the --no-deprecation command line flag. + */ + noDeprecation?: boolean; + /** + * A String representing the path to the resources directory. + */ + resourcesPath?: string; + /** + * A Boolean that controls whether or not deprecation warnings will be thrown as + * exceptions. Setting this to true will throw errors for deprecations. This + * property is used instead of the --throw-deprecation command line flag. + */ + throwDeprecation?: boolean; + /** + * A Boolean that controls whether or not deprecations printed to stderr include + * their stack trace. Setting this to true will print stack traces for + * deprecations. This property is instead of the --trace-deprecation command line + * flag. + */ + traceDeprecation?: boolean; + /** + * A Boolean that controls whether or not process warnings printed to stderr + * include their stack trace. Setting this to true will print stack traces for + * process warnings (including deprecations). This property is instead of the + * --trace-warnings command line flag. + */ + traceProcessWarnings?: boolean; + /** + * A String representing the current process's type, can be "browser" (i.e. main + * process) or "renderer". + */ + type?: string; + /** + * A Boolean. If the app is running as a Windows Store app (appx), this property is + * true, for otherwise it is undefined. + */ + windowsStore?: boolean; + } + interface ProcessVersions { + electron: string; + chrome: string; + } +} \ No newline at end of file diff --git a/src/typings/native-keymap.d.ts b/src/typings/native-keymap.d.ts index 092191dd759..716a74e38b8 100644 --- a/src/typings/native-keymap.d.ts +++ b/src/typings/native-keymap.d.ts @@ -42,12 +42,28 @@ declare module 'native-keymap' { export function getKeyMap(): IKeyboardMapping; + /* __GDPR__FRAGMENT__ + "IKeyboardLayoutInfo" : { + "name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "text": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ export interface IWindowsKeyboardLayoutInfo { name: string; id: string; text: string; } + /* __GDPR__FRAGMENT__ + "IKeyboardLayoutInfo" : { + "model" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "layout": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "variant": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "options": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "rules": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ export interface ILinuxKeyboardLayoutInfo { model: string; layout: string; @@ -56,6 +72,12 @@ declare module 'native-keymap' { rules: string; } + /* __GDPR__FRAGMENT__ + "IKeyboardLayoutInfo" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "lang": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ export interface IMacKeyboardLayoutInfo { id: string; lang: string; diff --git a/src/typings/node.d.ts b/src/typings/node.d.ts index 8c33c5a8412..05c02cd26b9 100644 --- a/src/typings/node.d.ts +++ b/src/typings/node.d.ts @@ -1,19 +1,25 @@ -// Type definitions for Node.js v6.x +// Type definitions for Node.js v7.x // Project: http://nodejs.org/ -// Definitions by: Microsoft TypeScript , DefinitelyTyped +// Definitions by: Microsoft TypeScript +// DefinitelyTyped +// Parambir Singh +// Roberto Desideri +// Christian Vaagland Tellnes +// Wilco Bakker +// Daniel Imms // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /************************************************ * * -* Node.js v6.x API * +* Node.js v7.x API * * * ************************************************/ // This needs to be global to avoid TS2403 in case lib.dom.d.ts is present in the same build interface Console { - Console: typeof NodeJS.Console; + Console: NodeJS.ConsoleConstructor; assert(value: any, message?: string, ...optionalParams: any[]): void; - dir(obj: any, options?: { showHidden?: boolean, depth?: number, colors?: boolean }): void; + dir(obj: any, options?: NodeJS.InspectOptions): void; error(message?: any, ...optionalParams: any[]): void; info(message?: any, ...optionalParams: any[]): void; log(message?: any, ...optionalParams: any[]): void; @@ -40,6 +46,17 @@ interface WeakMapConstructor { } interface SetConstructor { } interface WeakSetConstructor { } +// Forward-declare needed types from lib.es2015.d.ts (in case users are using `--lib es5`) +interface Iterable { } +interface Iterator { + next(value?: any): IteratorResult; +} +interface IteratorResult { } +interface SymbolConstructor { + readonly iterator: symbol; +} +declare var Symbol: SymbolConstructor; + /************************************************ * * * GLOBAL * @@ -83,7 +100,7 @@ interface NodeModule { children: NodeModule[]; } -// declare var module: NodeModule; +declare var module: NodeModule; // Same as module.exports declare var exports: any; @@ -100,7 +117,7 @@ declare var SlowBuffer: { // Buffer class -type BufferEncoding = "ascii" | "utf8" | "utf16le" | "ucs2" | "binary" | "hex"; +type BufferEncoding = "ascii" | "utf8" | "utf16le" | "ucs2" | "base64" | "latin1" | "binary" | "hex"; interface Buffer extends NodeBuffer { } /** @@ -248,7 +265,17 @@ declare var Buffer: { * * ************************************************/ declare namespace NodeJS { - export var Console: { + export interface InspectOptions { + showHidden?: boolean; + depth?: number | null; + colors?: boolean; + customInspect?: boolean; + showProxy?: boolean; + maxArrayLength?: number | null; + breakLength?: number; + } + + export interface ConsoleConstructor { prototype: Console; new(stdout: WritableStream, stderr?: WritableStream): Console; } @@ -280,14 +307,13 @@ declare namespace NodeJS { export interface ReadableStream extends EventEmitter { readable: boolean; - isTTY?: boolean; read(size?: number): string | Buffer; - setEncoding(encoding: string | null): void; - pause(): ReadableStream; - resume(): ReadableStream; + setEncoding(encoding: string | null): this; + pause(): this; + resume(): this; isPaused(): boolean; pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; + unpipe(destination?: T): this; unshift(chunk: string): void; unshift(chunk: Buffer): void; wrap(oldStream: ReadableStream): ReadableStream; @@ -295,7 +321,6 @@ declare namespace NodeJS { export interface WritableStream extends EventEmitter { writable: boolean; - isTTY?: boolean; write(buffer: Buffer | string, cb?: Function): boolean; write(str: string, encoding?: string, cb?: Function): boolean; end(): void; @@ -304,10 +329,7 @@ declare namespace NodeJS { end(str: string, encoding?: string, cb?: Function): void; } - export interface ReadWriteStream extends ReadableStream, WritableStream { - pause(): ReadWriteStream; - resume(): ReadWriteStream; - } + export interface ReadWriteStream extends ReadableStream, WritableStream { } export interface Events extends EventEmitter { } @@ -357,10 +379,24 @@ declare namespace NodeJS { | 'sunos' | 'win32'; + export interface Socket extends ReadWriteStream { + isTTY?: true; + } + + export interface WriteStream extends Socket { + columns?: number; + rows?: number; + } + export interface ReadStream extends Socket { + isRaw?: boolean; + setRawMode?(mode: boolean): void; + } + export interface Process extends EventEmitter { - stdout: WritableStream; - stderr: WritableStream; - stdin: ReadableStream; + stdout: WriteStream; + stderr: WriteStream; + stdin: ReadStream; + openStdin(): Socket; argv: string[]; argv0: string; execArgv: string[]; @@ -368,6 +404,7 @@ declare namespace NodeJS { abort(): void; chdir(directory: string): void; cwd(): string; + emitWarning(warning: string | Error, name?: string, ctor?: Function): void; env: any; exit(code?: number): void; exitCode: number; @@ -632,6 +669,7 @@ declare module "http" { headers?: { [key: string]: any }; auth?: string; agent?: Agent | boolean; + timeout?: number; } export interface Server extends net.Server { @@ -818,7 +856,7 @@ declare module "cluster" { id: string; process: child.ChildProcess; suicide: boolean; - send(message: any, sendHandle?: any): boolean; + send(message: any, sendHandle?: any, callback?: (error: Error) => void): boolean; kill(signal?: string): void; destroy(signal?: string): void; disconnect(): void; @@ -837,15 +875,15 @@ declare module "cluster" { */ addListener(event: string, listener: Function): this; addListener(event: "disconnect", listener: () => void): this; - addListener(event: "error", listener: (code: number, signal: string) => void): this; + addListener(event: "error", listener: (error: Error) => void): this; addListener(event: "exit", listener: (code: number, signal: string) => void): this; addListener(event: "listening", listener: (address: Address) => void): this; addListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. addListener(event: "online", listener: () => void): this; - emit(event: string, listener: Function): boolean + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "disconnect", listener: () => void): boolean - emit(event: "error", listener: (code: number, signal: string) => void): boolean + emit(event: "error", listener: (error: Error) => void): boolean emit(event: "exit", listener: (code: number, signal: string) => void): boolean emit(event: "listening", listener: (address: Address) => void): boolean emit(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): boolean @@ -853,7 +891,7 @@ declare module "cluster" { on(event: string, listener: Function): this; on(event: "disconnect", listener: () => void): this; - on(event: "error", listener: (code: number, signal: string) => void): this; + on(event: "error", listener: (error: Error) => void): this; on(event: "exit", listener: (code: number, signal: string) => void): this; on(event: "listening", listener: (address: Address) => void): this; on(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. @@ -861,7 +899,7 @@ declare module "cluster" { once(event: string, listener: Function): this; once(event: "disconnect", listener: () => void): this; - once(event: "error", listener: (code: number, signal: string) => void): this; + once(event: "error", listener: (error: Error) => void): this; once(event: "exit", listener: (code: number, signal: string) => void): this; once(event: "listening", listener: (address: Address) => void): this; once(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. @@ -869,7 +907,7 @@ declare module "cluster" { prependListener(event: string, listener: Function): this; prependListener(event: "disconnect", listener: () => void): this; - prependListener(event: "error", listener: (code: number, signal: string) => void): this; + prependListener(event: "error", listener: (error: Error) => void): this; prependListener(event: "exit", listener: (code: number, signal: string) => void): this; prependListener(event: "listening", listener: (address: Address) => void): this; prependListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. @@ -877,7 +915,7 @@ declare module "cluster" { prependOnceListener(event: string, listener: Function): this; prependOnceListener(event: "disconnect", listener: () => void): this; - prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this; + prependOnceListener(event: "error", listener: (error: Error) => void): this; prependOnceListener(event: "exit", listener: (code: number, signal: string) => void): this; prependOnceListener(event: "listening", listener: (address: Address) => void): this; prependOnceListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. @@ -917,7 +955,7 @@ declare module "cluster" { addListener(event: "online", listener: (worker: Worker) => void): this; addListener(event: "setup", listener: (settings: any) => void): this; - emit(event: string, listener: Function): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "disconnect", listener: (worker: Worker) => void): boolean; emit(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): boolean; emit(event: "fork", listener: (worker: Worker) => void): boolean; @@ -995,7 +1033,7 @@ declare module "cluster" { export function addListener(event: "online", listener: (worker: Worker) => void): Cluster; export function addListener(event: "setup", listener: (settings: any) => void): Cluster; - export function emit(event: string, listener: Function): boolean; + export function emit(event: string | symbol, ...args: any[]): boolean; export function emit(event: "disconnect", listener: (worker: Worker) => void): boolean; export function emit(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): boolean; export function emit(event: "fork", listener: (worker: Worker) => void): boolean; @@ -1052,7 +1090,17 @@ declare module "cluster" { declare module "zlib" { import * as stream from "stream"; - export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; finishFlush?: number } + + export interface ZlibOptions { + flush?: number; // default: zlib.constants.Z_NO_FLUSH + finishFlush?: number; // default: zlib.constants.Z_FINISH + chunkSize?: number; // default: 16*1024 + windowBits?: number; + level?: number; // compression only + memLevel?: number; // compression only + strategy?: number; // compression only + dictionary?: any; // deflate/inflate only, empty dictionary by default + } export interface Gzip extends stream.Transform { } export interface Gunzip extends stream.Transform { } @@ -1071,19 +1119,65 @@ declare module "zlib" { export function createUnzip(options?: ZlibOptions): Unzip; export function deflate(buf: Buffer | string, callback: (error: Error, result: Buffer) => void): void; + export function deflate(buf: Buffer | string, options: ZlibOptions, callback: (error: Error, result: Buffer) => void): void; export function deflateSync(buf: Buffer | string, options?: ZlibOptions): Buffer; export function deflateRaw(buf: Buffer | string, callback: (error: Error, result: Buffer) => void): void; + export function deflateRaw(buf: Buffer | string, options: ZlibOptions, callback: (error: Error, result: Buffer) => void): void; export function deflateRawSync(buf: Buffer | string, options?: ZlibOptions): Buffer; - export function gzip(buf: Buffer, callback: (error: Error, result: Buffer) => void): void; - export function gzipSync(buf: Buffer, options?: ZlibOptions): Buffer; - export function gunzip(buf: Buffer, callback: (error: Error, result: Buffer) => void): void; - export function gunzipSync(buf: Buffer, options?: ZlibOptions): Buffer; - export function inflate(buf: Buffer, callback: (error: Error, result: Buffer) => void): void; - export function inflateSync(buf: Buffer, options?: ZlibOptions): Buffer; - export function inflateRaw(buf: Buffer, callback: (error: Error, result: Buffer) => void): void; - export function inflateRawSync(buf: Buffer, options?: ZlibOptions): Buffer; - export function unzip(buf: Buffer, callback: (error: Error, result: Buffer) => void): void; - export function unzipSync(buf: Buffer, options?: ZlibOptions): Buffer; + export function gzip(buf: Buffer | string, callback: (error: Error, result: Buffer) => void): void; + export function gzip(buf: Buffer | string, options: ZlibOptions, callback: (error: Error, result: Buffer) => void): void; + export function gzipSync(buf: Buffer | string, options?: ZlibOptions): Buffer; + export function gunzip(buf: Buffer | string, callback: (error: Error, result: Buffer) => void): void; + export function gunzip(buf: Buffer | string, options: ZlibOptions, callback: (error: Error, result: Buffer) => void): void; + export function gunzipSync(buf: Buffer | string, options?: ZlibOptions): Buffer; + export function inflate(buf: Buffer | string, callback: (error: Error, result: Buffer) => void): void; + export function inflate(buf: Buffer | string, options: ZlibOptions, callback: (error: Error, result: Buffer) => void): void; + export function inflateSync(buf: Buffer | string, options?: ZlibOptions): Buffer; + export function inflateRaw(buf: Buffer | string, callback: (error: Error, result: Buffer) => void): void; + export function inflateRaw(buf: Buffer | string, options: ZlibOptions, callback: (error: Error, result: Buffer) => void): void; + export function inflateRawSync(buf: Buffer | string, options?: ZlibOptions): Buffer; + export function unzip(buf: Buffer | string, callback: (error: Error, result: Buffer) => void): void; + export function unzip(buf: Buffer | string, options: ZlibOptions, callback: (error: Error, result: Buffer) => void): void; + export function unzipSync(buf: Buffer | string, options?: ZlibOptions): Buffer; + + export namespace constants { + // Allowed flush values. + + export const Z_NO_FLUSH: number; + export const Z_PARTIAL_FLUSH: number; + export const Z_SYNC_FLUSH: number; + export const Z_FULL_FLUSH: number; + export const Z_FINISH: number; + export const Z_BLOCK: number; + export const Z_TREES: number; + + // Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal events. + + export const Z_OK: number; + export const Z_STREAM_END: number; + export const Z_NEED_DICT: number; + export const Z_ERRNO: number; + export const Z_STREAM_ERROR: number; + export const Z_DATA_ERROR: number; + export const Z_MEM_ERROR: number; + export const Z_BUF_ERROR: number; + export const Z_VERSION_ERROR: number; + + // Compression levels. + + export const Z_NO_COMPRESSION: number; + export const Z_BEST_SPEED: number; + export const Z_BEST_COMPRESSION: number; + export const Z_DEFAULT_COMPRESSION: number; + + // Compression strategy. + + export const Z_FILTERED: number; + export const Z_HUFFMAN_ONLY: number; + export const Z_RLE: number; + export const Z_FIXED: number; + export const Z_DEFAULT_STRATEGY: number; + } // Constants export var Z_NO_FLUSH: number; @@ -1116,7 +1210,6 @@ declare module "zlib" { export var Z_ASCII: number; export var Z_UNKNOWN: number; export var Z_DEFLATED: number; - export var Z_NULL: number; } declare module "os" { @@ -1153,7 +1246,7 @@ declare module "os" { export function userInfo(options?: { encoding: string }): { username: string, uid: number, gid: number, shell: any, homedir: string } export var constants: { UV_UDP_REUSEADDR: number, - errno: { + signals: { SIGHUP: number; SIGINT: number; SIGQUIT: number; @@ -1189,7 +1282,7 @@ declare module "os" { SIGSYS: number; SIGUNUSED: number; }, - signals: { + errno: { E2BIG: number; EACCES: number; EADDRINUSE: number; @@ -1366,11 +1459,10 @@ declare module "repl" { } export interface REPLServer extends readline.ReadLine { + context: any; defineCommand(keyword: string, cmd: Function | { help: string, action: Function }): void; displayPrompt(preserveCursor?: boolean): void; - context: any; - /** * events.EventEmitter * 1. exit @@ -1381,7 +1473,7 @@ declare module "repl" { addListener(event: "exit", listener: () => void): this; addListener(event: "reset", listener: Function): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "exit"): boolean; emit(event: "reset", context: any): boolean; @@ -1402,7 +1494,7 @@ declare module "repl" { prependOnceListener(event: "reset", listener: Function): this; } - export function start(options: ReplOptions): REPLServer; + export function start(options?: string | ReplOptions): REPLServer; } declare module "readline" { @@ -1446,7 +1538,7 @@ declare module "readline" { addListener(event: "SIGINT", listener: () => void): this; addListener(event: "SIGTSTP", listener: () => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "close"): boolean; emit(event: "line", input: any): boolean; emit(event: "pause"): boolean; @@ -1492,25 +1584,26 @@ declare module "readline" { prependOnceListener(event: "SIGTSTP", listener: () => void): this; } - export interface Completer { - (line: string): CompleterResult; - (line: string, callback: (err: any, result: CompleterResult) => void): any; - } + type Completer = (line: string) => CompleterResult; + type AsyncCompleter = (line: string, callback: (err: any, result: CompleterResult) => void) => any; export type CompleterResult = [string[], string]; export interface ReadLineOptions { input: NodeJS.ReadableStream; output?: NodeJS.WritableStream; - completer?: Completer; + completer?: Completer | AsyncCompleter; terminal?: boolean; historySize?: number; + prompt?: string; + crlfDelay?: number; + removeHistoryDuplicates?: boolean; } - export function createInterface(input: NodeJS.ReadableStream, output?: NodeJS.WritableStream, completer?: Completer, terminal?: boolean): ReadLine; + export function createInterface(input: NodeJS.ReadableStream, output?: NodeJS.WritableStream, completer?: Completer | AsyncCompleter, terminal?: boolean): ReadLine; export function createInterface(options: ReadLineOptions): ReadLine; - export function cursorTo(stream: NodeJS.WritableStream, x: number, y?: number): void; + export function cursorTo(stream: NodeJS.WritableStream, x: number, y: number): void; export function moveCursor(stream: NodeJS.WritableStream, dx: number | string, dy: number | string): void; export function clearLine(stream: NodeJS.WritableStream, dir: number): void; export function clearScreenDown(stream: NodeJS.WritableStream): void; @@ -1558,6 +1651,7 @@ declare module "child_process" { stdout: stream.Readable; stderr: stream.Readable; stdio: [stream.Writable, stream.Readable, stream.Readable]; + killed: boolean; pid: number; kill(signal?: string): void; send(message: any, sendHandle?: any): boolean; @@ -1582,7 +1676,7 @@ declare module "child_process" { addListener(event: "exit", listener: (code: number, signal: string) => void): this; addListener(event: "message", listener: (message: any, sendHandle: net.Socket | net.Server) => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "close", code: number, signal: string): boolean; emit(event: "disconnect"): boolean; emit(event: "error", err: Error): boolean; @@ -1683,6 +1777,7 @@ declare module "child_process" { execPath?: string; execArgv?: string[]; silent?: boolean; + stdio?: any[]; uid?: number; gid?: number; } @@ -1791,29 +1886,172 @@ declare module "url" { path?: string; } + export interface UrlObject { + protocol?: string; + slashes?: boolean; + auth?: string; + host?: string; + hostname?: string; + port?: string | number; + pathname?: string; + search?: string; + query?: { [key: string]: any; }; + hash?: string; + } + export function parse(urlStr: string, parseQueryString?: boolean, slashesDenoteHost?: boolean): Url; - export function format(url: Url): string; + export function format(URL: URL, options?: URLFormatOptions): string; + export function format(urlObject: UrlObject): string; export function resolve(from: string, to: string): string; + + export interface URLFormatOptions { + auth?: boolean; + fragment?: boolean; + search?: boolean; + unicode?: boolean; + } + + export class URLSearchParams implements Iterable { + constructor(init?: URLSearchParams | string | { [key: string]: string | string[] } | Iterable); + append(name: string, value: string): void; + delete(name: string): void; + entries(): Iterator; + forEach(callback: (value: string, name: string) => void): void; + get(name: string): string | null; + getAll(name: string): string[]; + has(name: string): boolean; + keys(): Iterator; + set(name: string, value: string): void; + sort(): void; + toString(): string; + values(): Iterator; + [Symbol.iterator](): Iterator; + } + + export class URL { + constructor(input: string, base?: string | URL); + hash: string; + host: string; + hostname: string; + href: string; + readonly origin: string; + password: string; + pathname: string; + port: string; + protocol: string; + search: string; + readonly searchParams: URLSearchParams; + username: string; + toString(): string; + toJSON(): string; + } } declare module "dns" { - export interface MxRecord { - exchange: string, - priority: number + // Supported getaddrinfo flags. + export const ADDRCONFIG: number; + export const V4MAPPED: number; + + export interface LookupOptions { + family?: number; + hints?: number; + all?: boolean; } - export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) => void): string; - export function lookup(domain: string, callback: (err: Error, address: string, family: number) => void): string; - export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve4(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve6(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveMx(domain: string, callback: (err: Error, addresses: MxRecord[]) => void): string[]; - export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function reverse(ip: string, callback: (err: Error, domains: string[]) => void): string[]; + export interface LookupOneOptions extends LookupOptions { + all?: false; + } + + export interface LookupAllOptions extends LookupOptions { + all: true; + } + + export interface LookupAddress { + address: string; + family: number; + } + + export function lookup(hostname: string, family: number, callback: (err: NodeJS.ErrnoException, address: string, family: number) => void): void; + export function lookup(hostname: string, options: LookupOneOptions, callback: (err: NodeJS.ErrnoException, address: string, family: number) => void): void; + export function lookup(hostname: string, options: LookupAllOptions, callback: (err: NodeJS.ErrnoException, addresses: LookupAddress[]) => void): void; + export function lookup(hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException, address: string | LookupAddress[], family: number) => void): void; + export function lookup(hostname: string, callback: (err: NodeJS.ErrnoException, address: string, family: number) => void): void; + + export interface ResolveOptions { + ttl: boolean; + } + + export interface ResolveWithTtlOptions extends ResolveOptions { + ttl: true; + } + + export interface RecordWithTtl { + address: string; + ttl: number; + } + + export interface MxRecord { + priority: number; + exchange: string; + } + + export interface NaptrRecord { + flags: string; + service: string; + regexp: string; + replacement: string; + order: number; + preference: number; + } + + export interface SoaRecord { + nsname: string; + hostmaster: string; + serial: number; + refresh: number; + retry: number; + expire: number; + minttl: number; + } + + export interface SrvRecord { + priority: number; + weight: number; + port: number; + name: string; + } + + export function resolve(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve(hostname: string, rrtype: "A", callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve(hostname: string, rrtype: "AAAA", callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve(hostname: string, rrtype: "CNAME", callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve(hostname: string, rrtype: "MX", callback: (err: NodeJS.ErrnoException, addresses: MxRecord[]) => void): void; + export function resolve(hostname: string, rrtype: "NAPTR", callback: (err: NodeJS.ErrnoException, addresses: NaptrRecord[]) => void): void; + export function resolve(hostname: string, rrtype: "NS", callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve(hostname: string, rrtype: "PTR", callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve(hostname: string, rrtype: "SOA", callback: (err: NodeJS.ErrnoException, addresses: SoaRecord) => void): void; + export function resolve(hostname: string, rrtype: "SRV", callback: (err: NodeJS.ErrnoException, addresses: SrvRecord[]) => void): void; + export function resolve(hostname: string, rrtype: "TXT", callback: (err: NodeJS.ErrnoException, addresses: string[][]) => void): void; + export function resolve(hostname: string, rrtype: string, callback: (err: NodeJS.ErrnoException, addresses: string[] | MxRecord[] | NaptrRecord[] | SoaRecord | SrvRecord[] | string[][]) => void): void; + + export function resolve4(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve4(hostname: string, options: ResolveWithTtlOptions, callback: (err: NodeJS.ErrnoException, addresses: RecordWithTtl[]) => void): void; + export function resolve4(hostname: string, options: ResolveOptions, callback: (err: NodeJS.ErrnoException, addresses: string[] | RecordWithTtl[]) => void): void; + + export function resolve6(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolve6(hostname: string, options: ResolveWithTtlOptions, callback: (err: NodeJS.ErrnoException, addresses: RecordWithTtl[]) => void): void; + export function resolve6(hostname: string, options: ResolveOptions, callback: (err: NodeJS.ErrnoException, addresses: string[] | RecordWithTtl[]) => void): void; + + export function resolveCname(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolveMx(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: MxRecord[]) => void): void; + export function resolveNaptr(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: NaptrRecord[]) => void): void; + export function resolveNs(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolvePtr(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: string[]) => void): void; + export function resolveSoa(hostname: string, callback: (err: NodeJS.ErrnoException, address: SoaRecord) => void): void; + export function resolveSrv(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: SrvRecord[]) => void): void; + export function resolveTxt(hostname: string, callback: (err: NodeJS.ErrnoException, addresses: string[][]) => void): void; + + export function reverse(ip: string, callback: (err: NodeJS.ErrnoException, hostnames: string[]) => void): void; export function setServers(servers: string[]): void; //Error codes @@ -1858,11 +2096,11 @@ declare module "net" { connect(port: number, host?: string, connectionListener?: Function): void; connect(path: string, connectionListener?: Function): void; bufferSize: number; - setEncoding(encoding?: string): void; + setEncoding(encoding?: string): this; write(data: any, encoding?: string, callback?: Function): void; - destroy(): void; - pause(): Socket; - resume(): Socket; + destroy(err?: any): void; + pause(): this; + resume(): this; setTimeout(timeout: number, callback?: Function): void; setNoDelay(noDelay?: boolean): void; setKeepAlive(enable?: boolean, initialDelay?: number): void; @@ -1877,6 +2115,7 @@ declare module "net" { localPort: number; bytesRead: number; bytesWritten: number; + connecting: boolean; destroyed: boolean; // Extended base methods @@ -1907,7 +2146,7 @@ declare module "net" { addListener(event: "lookup", listener: (err: Error, address: string, family: string | number, host: string) => void): this; addListener(event: "timeout", listener: () => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "close", had_error: boolean): boolean; emit(event: "connect"): boolean; emit(event: "data", data: Buffer): boolean; @@ -1959,7 +2198,7 @@ declare module "net" { } export var Socket: { - new(options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): Socket; + new(options?: { fd?: number; allowHalfOpen?: boolean; readable?: boolean; writable?: boolean; }): Socket; }; export interface ListenOptions { @@ -1987,6 +2226,7 @@ declare module "net" { unref(): Server; maxConnections: number; connections: number; + listening: boolean; /** * events.EventEmitter @@ -2001,7 +2241,7 @@ declare module "net" { addListener(event: "error", listener: (err: Error) => void): this; addListener(event: "listening", listener: () => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "close"): boolean; emit(event: "connection", socket: Socket): boolean; emit(event: "error", err: Error): boolean; @@ -2032,7 +2272,7 @@ declare module "net" { prependOnceListener(event: "listening", listener: () => void): this; } export function createServer(connectionListener?: (socket: Socket) => void): Server; - export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) => void): Server; + export function createServer(options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean }, connectionListener?: (socket: Socket) => void): Server; export function connect(options: { port: number, host?: string, localAddress?: string, localPort?: string, family?: number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; export function connect(port: number, host?: string, connectionListener?: Function): Socket; export function connect(path: string, connectionListener?: Function): Socket; @@ -2065,12 +2305,14 @@ declare module "dgram" { exclusive?: boolean; } + type SocketType = "udp4" | "udp6"; + interface SocketOptions { - type: "udp4" | "udp6"; + type: SocketType; reuseAddr?: boolean; } - export function createSocket(type: string, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; + export function createSocket(type: SocketType, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; export function createSocket(options: SocketOptions, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; export interface Socket extends events.EventEmitter { @@ -2078,7 +2320,7 @@ declare module "dgram" { send(msg: Buffer | String | any[], offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void; bind(port?: number, address?: string, callback?: () => void): void; bind(options: BindOptions, callback?: Function): void; - close(callback?: any): void; + close(callback?: () => void): void; address(): AddressInfo; setBroadcast(flag: boolean): void; setTTL(ttl: number): void; @@ -2102,7 +2344,7 @@ declare module "dgram" { addListener(event: "listening", listener: () => void): this; addListener(event: "message", listener: (msg: Buffer, rinfo: AddressInfo) => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "close"): boolean; emit(event: "error", err: Error): boolean; emit(event: "listening"): boolean; @@ -2172,23 +2414,23 @@ declare module "fs" { */ addListener(event: string, listener: Function): this; addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - addListener(event: "error", listener: (code: number, signal: string) => void): this; + addListener(event: "error", listener: (error: Error) => void): this; on(event: string, listener: Function): this; on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - on(event: "error", listener: (code: number, signal: string) => void): this; + on(event: "error", listener: (error: Error) => void): this; once(event: string, listener: Function): this; once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - once(event: "error", listener: (code: number, signal: string) => void): this; + once(event: "error", listener: (error: Error) => void): this; prependListener(event: string, listener: Function): this; prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - prependListener(event: "error", listener: (code: number, signal: string) => void): this; + prependListener(event: "error", listener: (error: Error) => void): this; prependOnceListener(event: string, listener: Function): this; prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this; + prependOnceListener(event: "error", listener: (error: Error) => void): this; } export interface ReadStream extends stream.Readable { @@ -2306,40 +2548,40 @@ declare module "fs" { export function realpath(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void; export function realpath(path: string | Buffer, cache: { [path: string]: string }, callback: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void; export function realpathSync(path: string | Buffer, cache?: { [path: string]: string }): string; - /* + /** * Asynchronous unlink - deletes the file specified in {path} * * @param path * @param callback No arguments other than a possible exception are given to the completion callback. */ export function unlink(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* + /** * Synchronous unlink - deletes the file specified in {path} * * @param path */ export function unlinkSync(path: string | Buffer): void; - /* + /** * Asynchronous rmdir - removes the directory specified in {path} * * @param path * @param callback No arguments other than a possible exception are given to the completion callback. */ export function rmdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* + /** * Synchronous rmdir - removes the directory specified in {path} * * @param path */ export function rmdirSync(path: string | Buffer): void; - /* + /** * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. * * @param path * @param callback No arguments other than a possible exception are given to the completion callback. */ export function mkdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* + /** * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. * * @param path @@ -2347,7 +2589,7 @@ declare module "fs" { * @param callback No arguments other than a possible exception are given to the completion callback. */ export function mkdir(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* + /** * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. * * @param path @@ -2355,7 +2597,7 @@ declare module "fs" { * @param callback No arguments other than a possible exception are given to the completion callback. */ export function mkdir(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* + /** * Synchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. * * @param path @@ -2363,7 +2605,7 @@ declare module "fs" { * @param callback No arguments other than a possible exception are given to the completion callback. */ export function mkdirSync(path: string | Buffer, mode?: number): void; - /* + /** * Synchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. * * @param path @@ -2371,22 +2613,23 @@ declare module "fs" { * @param callback No arguments other than a possible exception are given to the completion callback. */ export function mkdirSync(path: string | Buffer, mode?: string): void; - /* + /** * Asynchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory. * * @param prefix * @param callback The created folder path is passed as a string to the callback's second parameter. */ export function mkdtemp(prefix: string, callback?: (err: NodeJS.ErrnoException, folder: string) => void): void; - /* + /** * Synchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory. * * @param prefix * @returns Returns the created folder path. */ export function mkdtempSync(prefix: string): string; - export function readdir(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void; - export function readdirSync(path: string | Buffer): string[]; + export function readdir(path: string | Buffer, callback: (err: NodeJS.ErrnoException, files: string[]) => void): void; + export function readdir(path: string | Buffer, options: string | {}, callback: (err: NodeJS.ErrnoException, files: string[]) => void): void; + export function readdirSync(path: string | Buffer, options?: string | {}): string[]; export function close(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; export function closeSync(fd: number): void; export function open(path: string | Buffer, flags: string | number, callback: (err: NodeJS.ErrnoException, fd: number) => void): void; @@ -2402,32 +2645,36 @@ declare module "fs" { export function futimesSync(fd: number, atime: Date, mtime: Date): void; export function fsync(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; export function fsyncSync(fd: number): void; - export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; + export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number | null, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; export function write(fd: number, buffer: Buffer, offset: number, length: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; export function write(fd: number, data: any, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; export function write(fd: number, data: any, offset: number, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; export function write(fd: number, data: any, offset: number, encoding: string, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; - export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number; - export function writeSync(fd: number, data: any, position?: number, enconding?: string): number; - export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void; - export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; - /* + export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number | null): number; + export function writeSync(fd: number, data: any, position?: number | null, enconding?: string): number; + export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number | null, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void; + export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number | null): number; + /** * Asynchronous readFile - Asynchronously reads the entire contents of a file. * * @param fileName * @param encoding * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. */ + export function readFile(filename: string, encoding: null, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; export function readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void; - /* + export function readFile(filename: string, encoding: string | null, callback: (err: NodeJS.ErrnoException, data: string | Buffer) => void): void; + /** * Asynchronous readFile - Asynchronously reads the entire contents of a file. * * @param fileName * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer. * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. */ + export function readFile(filename: string, options: { encoding: null; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; export function readFile(filename: string, options: { encoding: string; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string) => void): void; - /* + export function readFile(filename: string, options: { encoding: string | null; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string | Buffer) => void): void; + /** * Asynchronous readFile - Asynchronously reads the entire contents of a file. * * @param fileName @@ -2435,28 +2682,32 @@ declare module "fs" { * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. */ export function readFile(filename: string, options: { flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; - /* + /** * Asynchronous readFile - Asynchronously reads the entire contents of a file. * * @param fileName * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. */ export function readFile(filename: string, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; - /* + /** * Synchronous readFile - Synchronously reads the entire contents of a file. * * @param fileName * @param encoding */ + export function readFileSync(filename: string, encoding: null): Buffer; export function readFileSync(filename: string, encoding: string): string; - /* + export function readFileSync(filename: string, encoding: string | null): string | Buffer; + /** * Synchronous readFile - Synchronously reads the entire contents of a file. * * @param fileName * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer. */ + export function readFileSync(filename: string, options: { encoding: null; flag?: string; }): Buffer; export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string; - /* + export function readFileSync(filename: string, options: { encoding: string | null; flag?: string; }): string | Buffer; + /** * Synchronous readFile - Synchronously reads the entire contents of a file. * * @param fileName @@ -2464,14 +2715,17 @@ declare module "fs" { */ export function readFileSync(filename: string, options?: { flag?: string; }): Buffer; export function writeFile(filename: string | number, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; - export function writeFile(filename: string | number, data: any, options: string, callback?: (err: NodeJS.ErrnoException) => void): void; + export function writeFile(filename: string | number, data: any, encoding: string, callback: (err: NodeJS.ErrnoException) => void): void; export function writeFile(filename: string | number, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; export function writeFile(filename: string | number, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; + export function writeFileSync(filename: string, data: any, encoding: string): void; export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; + export function appendFile(filename: string, data: any, encoding: string, callback: (err: NodeJS.ErrnoException) => void): void; export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; export function appendFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; + export function appendFileSync(filename: string, data: any, encoding: string): void; export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void; @@ -2820,6 +3074,25 @@ declare module "tls" { CN: string; } + export interface PeerCertificate { + subject: Certificate; + issuer: Certificate; + subjectaltname: string; + infoAccess: { [index: string]: string[] }; + modulus: string; + exponent: string; + valid_from: string; + valid_to: string; + fingerprint: string; + ext_key_usage: string[]; + serialNumber: string; + raw: Buffer; + } + + export interface DetailedPeerCertificate extends PeerCertificate { + issuerCertificate: DetailedPeerCertificate; + } + export interface CipherNameAndProtocol { /** * The cipher name. @@ -2831,7 +3104,7 @@ declare module "tls" { version: string; } - export class TLSSocket extends stream.Duplex { + export class TLSSocket extends net.Socket { /** * Construct a new tls.TLSSocket object from an existing TCP socket. */ @@ -2928,18 +3201,11 @@ declare module "tls" { * if false only the top certificate without issuer property. * If the peer does not provide a certificate, it returns null or an empty object. * @param {boolean} detailed - If true; the full chain with issuer property will be returned. - * @returns {any} - An object representing the peer's certificate. + * @returns {PeerCertificate | DetailedPeerCertificate} - An object representing the peer's certificate. */ - getPeerCertificate(detailed?: boolean): { - subject: Certificate; - issuerInfo: Certificate; - issuer: Certificate; - raw: any; - valid_from: string; - valid_to: string; - fingerprint: string; - serialNumber: string; - }; + getPeerCertificate(detailed: true): DetailedPeerCertificate; + getPeerCertificate(detailed?: false): PeerCertificate; + getPeerCertificate(detailed?: boolean): PeerCertificate | DetailedPeerCertificate; /** * Could be used to speed up handshake establishment when reconnecting to the server. * @returns {any} - ASN.1 encoded TLS session or undefined if none was negotiated. @@ -2958,7 +3224,7 @@ declare module "tls" { /** * The numeric representation of the local port. */ - localPort: string; + localPort: number; /** * The string representation of the remote IP address. * For example, '74.125.127.100' or '2001:4860:a005::68'. @@ -3004,7 +3270,7 @@ declare module "tls" { addListener(event: "OCSPResponse", listener: (response: Buffer) => void): this; addListener(event: "secureConnect", listener: () => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "OCSPResponse", response: Buffer): boolean; emit(event: "secureConnect"): boolean; @@ -3097,7 +3363,7 @@ declare module "tls" { addListener(event: "resumeSession", listener: (sessionId: any, callback: (err: Error, sessionData: any) => void) => void): this; addListener(event: "secureConnection", listener: (tlsSocket: TLSSocket) => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "tlsClientError", err: Error, tlsSocket: TLSSocket): boolean; emit(event: "newSession", sessionId: any, sessionData: any, callback: (err: Error, resp: Buffer) => void): boolean; emit(event: "OCSPRequest", certificate: Buffer, issuer: Buffer, callback: Function): boolean; @@ -3170,10 +3436,10 @@ declare module "tls" { context: any; } - export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) => void): Server; - export function connect(options: ConnectionOptions, secureConnectionListener?: () => void): ClearTextStream; - export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () => void): ClearTextStream; - export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () => void): ClearTextStream; + export function createServer(options: TlsOptions, secureConnectionListener?: (socket: TLSSocket) => void): Server; + export function connect(options: ConnectionOptions, secureConnectionListener?: () => void): TLSSocket; + export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () => void): TLSSocket; + export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () => void): TLSSocket; export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair; export function createSecureContext(details: SecureContextOptions): SecureContext; } @@ -3295,6 +3561,13 @@ declare module "crypto" { export function randomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void; export function pseudoRandomBytes(size: number): Buffer; export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void; + export function randomFillSync(buffer: Buffer | Uint8Array, offset?: number, size?: number): Buffer; + export function randomFill(buffer: Buffer, callback: (err: Error, buf: Buffer) => void): void; + export function randomFill(buffer: Uint8Array, callback: (err: Error, buf: Uint8Array) => void): void; + export function randomFill(buffer: Buffer, offset: number, callback: (err: Error, buf: Buffer) => void): void; + export function randomFill(buffer: Uint8Array, offset: number, callback: (err: Error, buf: Uint8Array) => void): void; + export function randomFill(buffer: Buffer, offset: number, size: number, callback: (err: Error, buf: Buffer) => void): void; + export function randomFill(buffer: Uint8Array, offset: number, size: number, callback: (err: Error, buf: Uint8Array) => void): void; export interface RsaPublicKey { key: string; padding?: number; @@ -3337,6 +3610,7 @@ declare module "stream" { class internal extends events.EventEmitter { pipe(destination: T, options?: { end?: boolean; }): T; } + namespace internal { export class Stream extends internal { } @@ -3345,22 +3619,22 @@ declare module "stream" { highWaterMark?: number; encoding?: string; objectMode?: boolean; - read?: (size?: number) => any; + read?: (this: Readable, size?: number) => any; } - export class Readable extends events.EventEmitter implements NodeJS.ReadableStream { + export class Readable extends Stream implements NodeJS.ReadableStream { readable: boolean; constructor(opts?: ReadableOptions); - protected _read(size: number): void; + _read(size: number): void; read(size?: number): any; - setEncoding(encoding: string): void; - pause(): Readable; - resume(): Readable; + setEncoding(encoding: string): this; + pause(): this; + resume(): this; isPaused(): boolean; pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; + unpipe(destination?: T): this; unshift(chunk: any): void; - wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; + wrap(oldStream: NodeJS.ReadableStream): Readable; push(chunk: any, encoding?: string): boolean; /** @@ -3380,7 +3654,7 @@ declare module "stream" { addListener(event: "readable", listener: () => void): this; addListener(event: "error", listener: (err: Error) => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "close"): boolean; emit(event: "data", chunk: Buffer | string): boolean; emit(event: "end"): boolean; @@ -3431,12 +3705,13 @@ declare module "stream" { writev?: (chunks: { chunk: string | Buffer, encoding: string }[], callback: Function) => any; } - export class Writable extends events.EventEmitter implements NodeJS.WritableStream { + export class Writable extends Stream implements NodeJS.WritableStream { writable: boolean; constructor(opts?: WritableOptions); - protected _write(chunk: any, encoding: string, callback: Function): void; + _write(chunk: any, encoding: string, callback: Function): void; write(chunk: any, cb?: Function): boolean; write(chunk: any, encoding?: string, cb?: Function): boolean; + setDefaultEncoding(encoding: string): this; end(): void; end(chunk: any, cb?: Function): void; end(chunk: any, encoding?: string, cb?: Function): void; @@ -3459,7 +3734,7 @@ declare module "stream" { addListener(event: "pipe", listener: (src: Readable) => void): this; addListener(event: "unpipe", listener: (src: Readable) => void): this; - emit(event: string, ...args: any[]): boolean; + emit(event: string | symbol, ...args: any[]): boolean; emit(event: "close"): boolean; emit(event: "drain", chunk: Buffer | string): boolean; emit(event: "error", err: Error): boolean; @@ -3515,16 +3790,13 @@ declare module "stream" { } // Note: Duplex extends both Readable and Writable. - export class Duplex extends Readable implements NodeJS.ReadWriteStream { - // Readable - pause(): Duplex; - resume(): Duplex; - // Writeable + export class Duplex extends Readable implements Writable { writable: boolean; constructor(opts?: DuplexOptions); - protected _write(chunk: any, encoding: string, callback: Function): void; + _write(chunk: any, encoding: string, callback: Function): void; write(chunk: any, cb?: Function): boolean; write(chunk: any, encoding?: string, cb?: Function): boolean; + setDefaultEncoding(encoding: string): this; end(): void; end(chunk: any, cb?: Function): void; end(chunk: any, encoding?: string, cb?: Function): void; @@ -3535,28 +3807,9 @@ declare module "stream" { flush?: (callback: Function) => any; } - // Note: Transform lacks the _read and _write methods of Readable/Writable. - export class Transform extends events.EventEmitter implements NodeJS.ReadWriteStream { - readable: boolean; - writable: boolean; + export class Transform extends Duplex { constructor(opts?: TransformOptions); - protected _transform(chunk: any, encoding: string, callback: Function): void; - protected _flush(callback: Function): void; - read(size?: number): any; - setEncoding(encoding: string): void; - pause(): Transform; - resume(): Transform; - isPaused(): boolean; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: any): void; - wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; - push(chunk: any, encoding?: string): boolean; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; + _transform(chunk: any, encoding: string, callback: Function): void; } export class PassThrough extends Transform { } @@ -3566,39 +3819,33 @@ declare module "stream" { } declare module "util" { - export interface InspectOptions { - showHidden?: boolean; - depth?: number; - colors?: boolean; - customInspect?: boolean; - } - + export interface InspectOptions extends NodeJS.InspectOptions { } export function format(format: any, ...param: any[]): string; export function debug(string: string): void; export function error(...param: any[]): void; export function puts(...param: any[]): void; export function print(...param: any[]): void; export function log(string: string): void; - export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string; + export function inspect(object: any, showHidden?: boolean, depth?: number | null, color?: boolean): string; export function inspect(object: any, options: InspectOptions): string; - export function isArray(object: any): boolean; - export function isRegExp(object: any): boolean; - export function isDate(object: any): boolean; - export function isError(object: any): boolean; + export function isArray(object: any): object is any[]; + export function isRegExp(object: any): object is RegExp; + export function isDate(object: any): object is Date; + export function isError(object: any): object is Error; export function inherits(constructor: any, superConstructor: any): void; export function debuglog(key: string): (msg: string, ...param: any[]) => void; - export function isBoolean(object: any): boolean; - export function isBuffer(object: any): boolean; + export function isBoolean(object: any): object is boolean; + export function isBuffer(object: any): object is Buffer; export function isFunction(object: any): boolean; - export function isNull(object: any): boolean; - export function isNullOrUndefined(object: any): boolean; - export function isNumber(object: any): boolean; + export function isNull(object: any): object is null; + export function isNullOrUndefined(object: any): object is null | undefined; + export function isNumber(object: any): object is number; export function isObject(object: any): boolean; export function isPrimitive(object: any): boolean; - export function isString(object: any): boolean; - export function isSymbol(object: any): boolean; - export function isUndefined(object: any): boolean; - export function deprecate(fn: Function, message: string): Function; + export function isString(object: any): object is string; + export function isSymbol(object: any): object is symbol; + export function isUndefined(object: any): object is undefined; + export function deprecate(fn: T, message: string): T; } declare module "assert" { @@ -3628,19 +3875,16 @@ declare module "assert" { export function notStrictEqual(actual: any, expected: any, message?: string): void; export function deepStrictEqual(actual: any, expected: any, message?: string): void; export function notDeepStrictEqual(actual: any, expected: any, message?: string): void; - export var throws: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; - export var doesNotThrow: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; + export function throws(block: Function, message?: string): void; + export function throws(block: Function, error: Function, message?: string): void; + export function throws(block: Function, error: RegExp, message?: string): void; + export function throws(block: Function, error: (err: any) => boolean, message?: string): void; + + export function doesNotThrow(block: Function, message?: string): void; + export function doesNotThrow(block: Function, error: Function, message?: string): void; + export function doesNotThrow(block: Function, error: RegExp, message?: string): void; + export function doesNotThrow(block: Function, error: (err: any) => boolean, message?: string): void; export function ifError(value: any): void; } @@ -3971,10 +4215,8 @@ declare module "v8" { physical_space_size: number; } - const enum DoesZapCodeSpaceFlag { - Disabled = 0, - Enabled = 1 - } + //** Signifies if the --zap_code_space option is enabled or not. 1 == enabled, 0 == disabled. */ + type DoesZapCodeSpaceFlag = 0 | 1; interface HeapInfo { total_heap_size: number; diff --git a/src/typings/winreg.d.ts b/src/typings/winreg.d.ts deleted file mode 100644 index 70047d8b50f..00000000000 --- a/src/typings/winreg.d.ts +++ /dev/null @@ -1,338 +0,0 @@ -// Type definitions for Winreg v1.2.0 -// Project: http://fresc81.github.io/node-winreg/ -// Definitions by: RX14 , BobBuehler -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - -declare var Winreg: WinregStatic; - -interface WinregStatic { - /** - * Creates a registry object, which provides access to a single registry key. - * Note: This class is returned by a call to ```require('winreg')```. - * - * @public - * @class - * - * @param {@link Options} options - the options - * - * @example - * var Registry = require('winreg') - * , autoStartCurrentUser = new Registry({ - * hive: Registry.HKCU, - * key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' - * }); - */ - new (options: Winreg.Options): Winreg.Registry; - - /** - * Registry hive key HKEY_LOCAL_MACHINE. - * Note: For writing to this hive your program has to run with admin privileges. - */ - HKLM: string; - - /** - * Registry hive key HKEY_CURRENT_USER. - */ - HKCU: string; - - /** - * Registry hive key HKEY_CLASSES_ROOT. - * Note: For writing to this hive your program has to run with admin privileges. - */ - HKCR: string; - - /** - * Registry hive key HKEY_USERS. - * Note: For writing to this hive your program has to run with admin privileges. - */ - HKU: string; - - /** - * Registry hive key HKEY_CURRENT_CONFIG. - * Note: For writing to this hive your program has to run with admin privileges. - */ - HKCC: string; - - /** - * Collection of available registry hive keys. - */ - HIVES: Array; - - /** - * Registry value type STRING. - * - * Values of this type contain a string. - */ - REG_SZ: string; - - /** - * Registry value type MULTILINE_STRING. - * - * Values of this type contain a multiline string. - */ - REG_MULTI_SZ: string; - - /** - * Registry value type EXPANDABLE_STRING. - * - * Values of this type contain an expandable string. - */ - REG_EXPAND_SZ: string; - - /** - * Registry value type DOUBLE_WORD. - * - * Values of this type contain a double word (32 bit integer). - */ - REG_DWORD: string; - - /** - * Registry value type QUAD_WORD. - * - * Values of this type contain a quad word (64 bit integer). - */ - REG_QWORD: string; - - /** - * Registry value type BINARY. - * - * Values of this type contain a binary value. - */ - REG_BINARY: string; - - /** - * Registry value type UNKNOWN. - * - * Values of this type contain a value of an unknown type. - */ - REG_NONE: string; - - /** - * Collection of available registry value types. - */ - REG_TYPES: Array; - - /** - * The name of the default value. May be used instead of the empty string literal for better readability. - */ - DEFAULT_VALUE: string; -} - -declare namespace Winreg { - export interface Options { - /** - * Optional hostname, must start with '\\' sequence. - */ - host?: string; - - /** - * Optional hive ID, default is HKLM. - */ - hive?: string; - - /** - * Optional key, default is the root key. - */ - key?: string; - - /** - * Optional registry hive architecture ('x86' or 'x64'; only valid on Windows 64 Bit Operating Systems). - */ - arch?: string; - } - - /** - * A registry object, which provides access to a single registry key. - */ - export interface Registry { - /** - * The hostname. - * @readonly - */ - host: string; - - /** - * The hive id. - * @readonly - */ - hive: string; - - /** - * The registry key name. - * @readonly - */ - key: string; - - /** - * The full path to the registry key. - * @readonly - */ - path: string; - - /** - * The registry hive architecture ('x86' or 'x64'). - * @readonly - */ - arch: string; - - /** - * Creates a new {@link Registry} instance that points to the parent registry key. - * @readonly - */ - parent: Registry; - - /** - * Retrieve all values from this registry key. - * @param {valuesCallback} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @param {array=} cb.items - an array of {@link RegistryItem} objects - * @returns {Registry} this registry key object - */ - values(cb: (err: Error, result: Array) => void): Registry; - - /** - * Retrieve all subkeys from this registry key. - * @param {function (err, items)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @param {array=} cb.items - an array of {@link Registry} objects - * @returns {Registry} this registry key object - */ - keys(cb: (err: Error, result: Array) => void): Registry; - - /** - * Gets a named value from this registry key. - * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value - * @param {function (err, item)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @param {RegistryItem=} cb.item - the retrieved registry item - * @returns {Registry} this registry key object - */ - get(name: string, cb: (err: Error, result: Winreg.RegistryItem) => void): Registry; - - /** - * Sets a named value in this registry key, overwriting an already existing value. - * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value - * @param {string} type - the value type - * @param {string} value - the value - * @param {function (err)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @returns {Registry} this registry key object - */ - set(name: string, type: string, value: string, cb: (err: Error) => void): Registry; - - /** - * Remove a named value from this registry key. If name is empty, sets the default value of this key. - * Note: This key must be already existing. - * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value - * @param {function (err)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @returns {Registry} this registry key object - */ - remove(name: string, cb: (err: Error) => void): Registry; - - /** - * Remove all subkeys and values (including the default value) from this registry key. - * @param {function (err)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @returns {Registry} this registry key object - */ - clear(cb: (err: Error) => void): Registry; - - /** - * Alias for the clear method to keep it backward compatible. - * @method - * @deprecated Use {@link Registry#clear} or {@link Registry#destroy} in favour of this method. - * @param {function (err)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @returns {Registry} this registry key object - */ - erase(cb: (err: Error) => void): Registry; - - /** - * Delete this key and all subkeys from the registry. - * @param {function (err)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @returns {Registry} this registry key object - */ - destroy(cb: (err: Error) => void): Registry; - - /** - * Create this registry key. Note that this is a no-op if the key already exists. - * @param {function (err)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @returns {Registry} this registry key object - */ - create(cb: (err: Error) => void): Registry; - - /** - * Checks if this key already exists. - * @param {function (err, exists)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @param {boolean=} cb.exists - true if a registry key with this name already exists - * @returns {Registry} this registry key object - */ - keyExists(cb: (err: Error, exists: boolean) => void): Registry; - - /** - * Checks if a value with the given name already exists within this key. - * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value - * @param {function (err, exists)} cb - callback function - * @param {error=} cb.err - error object or null if successful - * @param {boolean=} cb.exists - true if a value with the given name was found in this key - * @returns {Registry} this registry key object - */ - valueExists(name: string, cb: (err: Error, exists: boolean) => void): Registry; - } - - /** - * A single registry value record. - * Objects of this type are created internally and returned by methods of {@link Registry} objects. - */ - export interface RegistryItem { - /** - * The hostname. - * @readonly - */ - host: string; - - /** - * The hive id. - * @readonly - */ - hive: string; - - /** - * The registry key. - * @readonly - */ - key: string; - - /** - * The value name. - * @readonly - */ - name: string; - - /** - * The value type. - * @readonly - */ - type: string; - - /** - * The value. - * @readonly - */ - value: string; - - /** - * The hive architecture. - * @readonly - */ - arch: string; - } -} - -declare module "winreg" { - export = Winreg; -} \ No newline at end of file diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index ef40720682f..0f26b76a5aa 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -7,451 +7,541 @@ * to be stable and consumed by external programs. */ -/** - * An object containing start up options for the terminal. - */ -interface ITerminalOptions { +declare module 'xterm' { /** - * A data uri of the sound to use for the bell (needs bellStyle = 'sound'). + * An object containing start up options for the terminal. */ - bellSound?: string; + interface ITerminalOptions { + /** + * A data uri of the sound to use for the bell (needs bellStyle = 'sound'). + */ + bellSound?: string; + + /** + * The type of the bell notification the terminal will use. + */ + bellStyle?: 'none' | 'visual' | 'sound' | 'both'; + + /** + * The number of columns in the terminal. + */ + cols?: number; + + /** + * Whether the cursor blinks. + */ + cursorBlink?: boolean; + + /** + * The style of the cursor. + */ + cursorStyle?: 'block' | 'underline' | 'bar'; + + /** + * Whether input should be disabled. + */ + disableStdin?: boolean; + + /** + * Whether to enable the rendering of bold text. + */ + enableBold?: boolean; + + /** + * The font size used to render text. + */ + fontSize?: number; + + /** + * The font family used to render text. + */ + fontFamily?: string; + + /** + * The line height used to render text. + */ + lineHeight?: number; + + /** + * The number of rows in the terminal. + */ + rows?: number; + + /** + * The amount of scrollback in the terminal. Scrollback is the amount of rows + * that are retained when lines are scrolled beyond the initial viewport. + */ + scrollback?: number; + + /** + * The size of tab stops in the terminal. + */ + tabStopWidth?: number; + + /** + * The color theme of the terminal. + */ + theme?: ITheme; + } /** - * The type of the bell notification the terminal will use. + * Contains colors to theme the terminal with. */ - bellStyle?: 'none' | 'visual' | 'sound' | 'both'; + interface ITheme { + /** The default foreground color */ + foreground?: string, + /** The default background color */ + background?: string, + /** The cursor color */ + cursor?: string, + /** The selection color (can be transparent) */ + selection?: string, + /** The accent color of the cursor (used as the foreground color for a block cursor) */ + cursorAccent?: string, + /** ANSI black (eg. `\x1b[30m`) */ + black?: string, + /** ANSI red (eg. `\x1b[31m`) */ + red?: string, + /** ANSI green (eg. `\x1b[32m`) */ + green?: string, + /** ANSI yellow (eg. `\x1b[33m`) */ + yellow?: string, + /** ANSI blue (eg. `\x1b[34m`) */ + blue?: string, + /** ANSI magenta (eg. `\x1b[35m`) */ + magenta?: string, + /** ANSI cyan (eg. `\x1b[36m`) */ + cyan?: string, + /** ANSI white (eg. `\x1b[37m`) */ + white?: string, + /** ANSI bright black (eg. `\x1b[1;30m`) */ + brightBlack?: string, + /** ANSI bright red (eg. `\x1b[1;31m`) */ + brightRed?: string, + /** ANSI bright green (eg. `\x1b[1;32m`) */ + brightGreen?: string, + /** ANSI bright yellow (eg. `\x1b[1;33m`) */ + brightYellow?: string, + /** ANSI bright blue (eg. `\x1b[1;34m`) */ + brightBlue?: string, + /** ANSI bright magenta (eg. `\x1b[1;35m`) */ + brightMagenta?: string, + /** ANSI bright cyan (eg. `\x1b[1;36m`) */ + brightCyan?: string, + /** ANSI bright white (eg. `\x1b[1;37m`) */ + brightWhite?: string + } /** - * The number of columns in the terminal. + * An object containing options for a link matcher. */ - cols?: number; + interface ILinkMatcherOptions { + /** + * The index of the link from the regex.match(text) call. This defaults to 0 + * (for regular expressions without capture groups). + */ + matchIndex?: number; - /** - * Whether the cursor blinks. - */ - cursorBlink?: boolean; + /** + * A callback that validates an individual link, returning true if valid and + * false if invalid. + */ + validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; - /** - * The style of the cursor. - */ - cursorStyle?: 'block' | 'underline' | 'bar'; + /** + * A callback that fires when the mouse hovers over a link for a moment. + */ + tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; - /** - * Whether input should be disabled. - */ - disableStdin?: boolean; + /** + * A callback that fires when the mouse leaves a link. Note that this can + * happen even when tooltipCallback hasn't fired for the link yet. + */ + leaveCallback?: (event: MouseEvent, uri: string) => boolean | void; - /** - * The number of rows in the terminal. - */ - rows?: number; + /** + * The priority of the link matcher, this defines the order in which the link + * matcher is evaluated relative to others, from highest to lowest. The + * default value is 0. + */ + priority?: number; + } - /** - * The amount of scrollback in the terminal. Scrollback is the amount of rows - * that are retained when lines are scrolled beyond the initial viewport. - */ - scrollback?: number; - - /** - * The size of tab stops in the terminal. - */ - tabStopWidth?: number; - } - - /** - * An object containing options for a link matcher. - */ - interface ILinkMatcherOptions { - /** - * The index of the link from the regex.match(text) call. This defaults to 0 - * (for regular expressions without capture groups). - */ - matchIndex?: number; - - /** - * A callback that validates an individual link, returning true if valid and - * false if invalid. - */ - validationCallback?: (uri: string, element: HTMLElement, callback: (isValid: boolean) => void) => void; - - /** - * The priority of the link matcher, this defines the order in which the link - * matcher is evaluated relative to others, from highest to lowest. The - * default value is 0. - */ - priority?: number; - } - - declare module 'xterm' { /** * The class that represents an xterm.js terminal. */ export class Terminal { - /** - * The element containing the terminal. - */ - element: HTMLElement; - - /** - * The textarea that accepts input for the terminal. - */ - textarea: HTMLTextAreaElement; - - /** - * The number of rows in the terminal's viewport. - */ - rows: number; - - /** - * The number of columns in the terminal's viewport. - */ - cols: number; - - /** - * Creates a new `Terminal` object. - * - * @param options An object containing a set of options. - */ - constructor(options?: ITerminalOptions); - - /** - * Unfocus the terminal. - */ - blur(): void; - - /** - * Focus the terminal. - */ - focus(): void; - - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'blur' | 'focus' | 'lineFeed', listener: () => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'data', listener: (data?: string) => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'key', listener: (key?: string, event?: KeyboardEvent) => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'keypress' | 'keydown', listener: (event?: KeyboardEvent) => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'refresh', listener: (data?: {start: number, end: number}) => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'resize', listener: (data?: {cols: number, rows: number}) => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'scroll', listener: (ydisp?: number) => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'title', listener: (title?: string) => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: string, listener: (...args: any[]) => void): void; - - /** - * Deregisters an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - off(type: 'blur' | 'focus' | 'lineFeed' | 'data' | 'key' | 'keypress' | 'keydown' | 'refresh' | 'resize' | 'scroll' | 'title' | string, listener: (...args: any[]) => void): void; - - /** - * Resizes the terminal. - * @param x The number of columns to resize to. - * @param y The number of rows to resize to. - */ - resize(columns: number, rows: number): void; - - /** - * Writes text to the terminal, followed by a break line character (\n). - * @param data The text to write to the terminal. - */ - writeln(data: string): void; - - /** - * Opens the terminal within an element. - * @param parent The element to create the terminal within. - */ - open(parent: HTMLElement): void; - - /** - * Attaches a custom key event handler which is run before keys are - * processed, giving consumers of xterm.js ultimate control as to what keys - * should be processed by the terminal and what keys should not. - * @param customKeyEventHandler The custom KeyboardEvent handler to attach. - * This is a function that takes a KeyboardEvent, allowing consumers to stop - * propogation and/or prevent the default action. The function returns - * whether the event should be processed by xterm.js. - */ - attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; - - /** - * (EXPERIMENTAL) Registers a link matcher, allowing custom link patterns to - * be matched and handled. - * @param regex The regular expression to search for, specifically this - * searches the textContent of the rows. You will want to use \s to match a - * space ' ' character for example. - * @param handler The callback when the link is called. - * @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; - - /** - * (EXPERIMENTAL) Deregisters a link matcher if it has been registered. - * @param matcherId The link matcher's ID (returned after register) - */ - deregisterLinkMatcher(matcherId: number): void; - - /** - * Gets whether the terminal has an active selection. - */ - hasSelection(): boolean; - - /** - * Gets the terminal's current selection, this is useful for implementing - * copy behavior outside of xterm.js. - */ - getSelection(): string; - - /** - * Clears the current terminal selection. - */ - clearSelection(): void; - - /** - * Selects all text within the terminal. - */ - 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; - - /** - * Destroys the terminal and detaches it from the DOM. - */ - destroy(): void; - - /** - * Scroll the display of the terminal - * @param amount The number of lines to scroll down (negative scroll up). - */ - scrollDisp(amount: number): void; - - /** - * Scroll the display of the terminal by a number of pages. - * @param pageCount The number of pages to scroll (negative scrolls up). - */ - scrollPages(pageCount: number): void; - - /** - * Scrolls the display of the terminal to the top. - */ - scrollToTop(): void; - - /** - * Scrolls the display of the terminal to the bottom. - */ - scrollToBottom(): void; - - /** - * Clear the entire buffer, making the prompt line the new first line. - */ - clear(): void; - - /** - * Writes text to the terminal. - * @param data The text to write to the terminal. - */ - write(data: string): void; - - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'termName'): string; - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: 'colors'): string[]; - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: 'cols' | 'rows' | 'tabStopWidth' | 'scrollback'): number; - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: 'geometry'): [number, number]; - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: 'handler'): (data: string) => void; - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: string): any; - - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'termName' | 'bellSound', value: string): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'bellStyle', value: null | 'none' | 'visual' | 'sound' | 'both'): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'cursorStyle', value: null | 'block' | 'underline' | 'bar'): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'colors', value: string[]): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'cols' | 'rows' | 'tabStopWidth' | 'scrollback', value: number): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'geometry', value: [number, number]): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: 'handler', value: (data: string) => void): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: string, value: any): void; - - /** - * Tells the renderer to refresh terminal content between two rows - * (inclusive) at the next opportunity. - * @param start The row to start from (between 0 and this.rows - 1). - * @param end The row to end at (between start and this.rows - 1). - */ - refresh(start: number, end: number): void; - - /** - * Perform a full reset (RIS, aka '\x1bc'). - */ - reset(): void - - /** - * Loads an addon, attaching it to the Terminal prototype and making it - * available to all newly created Terminals. - * @param addon The addon to load. - */ - static loadAddon(addon: 'attach' | 'fit' | 'fullscreen' | 'search' | 'terminado'): void; - - - - - - // Moficiations to official .d.ts below - - buffer: { /** - * The viewport position. + * The element containing the terminal. */ - ydisp: number; - }; + element: HTMLElement; - /** - * Emit an event on the terminal. - */ - emit(type: string, data: any): void; + /** + * The textarea that accepts input for the terminal. + */ + textarea: HTMLTextAreaElement; - /** - * 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; + /** + * The number of rows in the terminal's viewport. + */ + rows: number; - /** - * 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; + /** + * The number of columns in the terminal's viewport. + */ + cols: number; + + /** + * Creates a new `Terminal` object. + * + * @param options An object containing a set of options. + */ + constructor(options?: ITerminalOptions); + + /** + * Unfocus the terminal. + */ + blur(): void; + + /** + * Focus the terminal. + */ + focus(): void; + + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'blur' | 'focus' | 'lineFeed', listener: () => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'data', listener: (data?: string) => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'key', listener: (key?: string, event?: KeyboardEvent) => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'keypress' | 'keydown', listener: (event?: KeyboardEvent) => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'refresh', listener: (data?: { start: number, end: number }) => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'resize', listener: (data?: { cols: number, rows: number }) => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'scroll', listener: (ydisp?: number) => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: 'title', listener: (title?: string) => void): void; + /** + * Registers an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + on(type: string, listener: (...args: any[]) => void): void; + + /** + * Deregisters an event listener. + * @param type The type of the event. + * @param listener The listener. + */ + off(type: 'blur' | 'focus' | 'lineFeed' | 'data' | 'key' | 'keypress' | 'keydown' | 'refresh' | 'resize' | 'scroll' | 'title' | string, listener: (...args: any[]) => void): void; + + /** + * Resizes the terminal. + * @param x The number of columns to resize to. + * @param y The number of rows to resize to. + */ + resize(columns: number, rows: number): void; + + /** + * Writes text to the terminal, followed by a break line character (\n). + * @param data The text to write to the terminal. + */ + writeln(data: string): void; + + /** + * Opens the terminal within an element. + * @param parent The element to create the terminal within. + */ + open(parent: HTMLElement): void; + + /** + * Attaches a custom key event handler which is run before keys are + * processed, giving consumers of xterm.js ultimate control as to what keys + * should be processed by the terminal and what keys should not. + * @param customKeyEventHandler The custom KeyboardEvent handler to attach. + * This is a function that takes a KeyboardEvent, allowing consumers to stop + * propogation and/or prevent the default action. The function returns + * whether the event should be processed by xterm.js. + */ + attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; + + /** + * (EXPERIMENTAL) Registers a link matcher, allowing custom link patterns to + * be matched and handled. + * @param regex The regular expression to search for, specifically this + * searches the textContent of the rows. You will want to use \s to match a + * space ' ' character for example. + * @param handler The callback when the link is called. + * @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; + + /** + * (EXPERIMENTAL) Deregisters a link matcher if it has been registered. + * @param matcherId The link matcher's ID (returned after register) + */ + deregisterLinkMatcher(matcherId: number): void; + + /** + * Gets whether the terminal has an active selection. + */ + hasSelection(): boolean; + + /** + * Gets the terminal's current selection, this is useful for implementing + * copy behavior outside of xterm.js. + */ + getSelection(): string; + + /** + * Clears the current terminal selection. + */ + clearSelection(): void; + + /** + * Selects all text within the terminal. + */ + 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; + + /** + * Destroys the terminal and detaches it from the DOM. + */ + destroy(): void; + + /** + * Scroll the display of the terminal + * @param amount The number of lines to scroll down (negative scroll up). + */ + scrollLines(amount: number): void; + + /** + * Scroll the display of the terminal by a number of pages. + * @param pageCount The number of pages to scroll (negative scrolls up). + */ + scrollPages(pageCount: number): void; + + /** + * Scrolls the display of the terminal to the top. + */ + scrollToTop(): void; + + /** + * Scrolls the display of the terminal to the bottom. + */ + scrollToBottom(): void; + + /** + * Clear the entire buffer, making the prompt line the new first line. + */ + clear(): void; + + /** + * Writes text to the terminal. + * @param data The text to write to the terminal. + */ + write(data: string): void; + + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'termName'): string; + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'colors'): string[]; + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'cols' | 'fontSize' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number; + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'geometry'): [number, number]; + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'handler'): (data: string) => void; + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: string): any; + + /** + * Sets an option on the terminal. + * @param key The option key. + * @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: 'bellStyle', value: null | 'none' | 'visual' | 'sound' | 'both'): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'cursorStyle', value: null | 'block' | 'underline' | 'bar'): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'colors', value: string[]): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'cols' | 'fontSize' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback', value: number): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'geometry', value: [number, number]): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'handler', value: (data: string) => void): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @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: string, value: any): void; + + /** + * Tells the renderer to refresh terminal content between two rows + * (inclusive) at the next opportunity. + * @param start The row to start from (between 0 and this.rows - 1). + * @param end The row to end at (between start and this.rows - 1). + */ + refresh(start: number, end: number): void; + + /** + * Perform a full reset (RIS, aka '\x1bc'). + */ + reset(): void + + /** + * Loads an addon, attaching it to the Terminal prototype and making it + * available to all newly created Terminals. + * @param addon The addon to load. + */ + static loadAddon(addon: 'attach' | 'fit' | 'fullscreen' | 'search' | 'terminado' | 'winptyCompat'): void; + + + + // Modifications to official .d.ts below + + buffer: { + /** + * The viewport position. + */ + ydisp: number; + }; + + /** + * Emit an event on the terminal. + */ + emit(type: string, data: any): 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; + + winptyCompatInit(): void; } - } +} \ No newline at end of file diff --git a/src/vs/base/browser/builder.ts b/src/vs/base/browser/builder.ts index 4ab3711618e..d7e54d6b39b 100644 --- a/src/vs/base/browser/builder.ts +++ b/src/vs/base/browser/builder.ts @@ -559,9 +559,9 @@ export class Builder implements IDisposable { /** * Registers listener on event types on the current element. */ - public on(type: string, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; - public on(typeArray: string[], fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; - public on(arg1: any, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder { + public on(type: string, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; + public on(typeArray: string[], fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; + public on(arg1: any, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder { // Event Type Array if (types.isArray(arg1)) { @@ -575,7 +575,7 @@ export class Builder implements IDisposable { let type = arg1; // Add Listener - let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e: Event) => { + let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e) => { fn(e, this, unbind); // Pass in Builder as Second Argument }, useCapture || false); @@ -641,9 +641,9 @@ export class Builder implements IDisposable { * Registers listener on event types on the current element and removes * them after first invocation. */ - public once(type: string, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; - public once(typesArray: string[], fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; - public once(arg1: any, fn: (e: Event, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder { + public once(type: string, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; + public once(typesArray: string[], fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder; + public once(arg1: any, fn: (e: E, builder: Builder, unbind: IDisposable) => void, listenerToUnbindContainer?: IDisposable[], useCapture?: boolean): Builder { // Event Type Array if (types.isArray(arg1)) { @@ -657,7 +657,7 @@ export class Builder implements IDisposable { let type = arg1; // Add Listener - let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e: Event) => { + let unbind: IDisposable = DOM.addDisposableListener(this.currentElement, type, (e) => { fn(e, this, unbind); // Pass in Builder as Second Argument unbind.dispose(); }, useCapture || false); diff --git a/src/vs/base/browser/dnd.ts b/src/vs/base/browser/dnd.ts index 15ccf8bea8f..7ca472fe69e 100644 --- a/src/vs/base/browser/dnd.ts +++ b/src/vs/base/browser/dnd.ts @@ -6,7 +6,6 @@ 'use strict'; import { $ } from 'vs/base/browser/builder'; -import URI from 'vs/base/common/uri'; /** * A helper that will execute a provided function when the provided HTMLElement receives @@ -40,42 +39,4 @@ export class DelayedDragHandler { public dispose(): void { this.clearDragTimeout(); } -} - -export interface IDraggedResource { - resource: URI; - isExternal: boolean; -} - -export function extractResources(e: DragEvent, externalOnly?: boolean): IDraggedResource[] { - const resources: IDraggedResource[] = []; - if (e.dataTransfer.types.length > 0) { - - // Check for in-app DND - if (!externalOnly) { - const rawData = e.dataTransfer.getData('URL'); - if (rawData) { - try { - resources.push({ resource: URI.parse(rawData), isExternal: false }); - } catch (error) { - // Invalid URI - } - } - } - - // Check for native file transfer - if (e.dataTransfer && e.dataTransfer.files) { - for (let i = 0; i < e.dataTransfer.files.length; i++) { - if (e.dataTransfer.files[i] && e.dataTransfer.files[i].path) { - try { - resources.push({ resource: URI.file(e.dataTransfer.files[i].path), isExternal: true }); - } catch (error) { - // Invalid URI - } - } - } - } - } - - return resources; } \ No newline at end of file diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index d0dfb1d885c..8087c77656e 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import * as platform from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; import { TimeoutTimer } from 'vs/base/common/async'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -412,18 +413,18 @@ class AnimationFrameQueueItem implements IDisposable { /** * Add a throttled listener. `handler` is fired at most every 16ms or with the next animation frame (if browser supports it). */ -export interface IEventMerger { - (lastEvent: R, currentEvent: Event): R; +export interface IEventMerger { + (lastEvent: R, currentEvent: E): R; } const MINIMUM_TIME_MS = 16; -const DEFAULT_EVENT_MERGER: IEventMerger = function (lastEvent: Event, currentEvent: Event) { +const DEFAULT_EVENT_MERGER: IEventMerger = function (lastEvent: Event, currentEvent: Event) { return currentEvent; }; -class TimeoutThrottledDomListener extends Disposable { +class TimeoutThrottledDomListener extends Disposable { - constructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger = DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) { + constructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger = DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) { super(); let lastEvent: R = null; @@ -451,8 +452,8 @@ class TimeoutThrottledDomListener extends Disposable { } } -export function addDisposableThrottledListener(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger, minimumTimeMs?: number): IDisposable { - return new TimeoutThrottledDomListener(node, type, handler, eventMerger, minimumTimeMs); +export function addDisposableThrottledListener(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger, minimumTimeMs?: number): IDisposable { + return new TimeoutThrottledDomListener(node, type, handler, eventMerger, minimumTimeMs); } export function getComputedStyle(el: HTMLElement): CSSStyleDeclaration { @@ -1054,3 +1055,23 @@ export function computeScreenAwareSize(cssPx: number): number { const screenPx = window.devicePixelRatio * cssPx; return Math.max(1, Math.floor(screenPx)) / window.devicePixelRatio; } + +/** + * See https://github.com/Microsoft/monaco-editor/issues/601 + * To protect against malicious code in the linked site, particularly phishing attempts, + * the window.opener should be set to null to prevent the linked site from having access + * to change the location of the current page. + * See https://mathiasbynens.github.io/rel-noopener/ + */ +export function windowOpenNoOpener(url: string): void { + if (platform.isNative) { + // In VSCode, window.open() always returns null... + window.open(url); + } else { + let newTab = window.open(); + if (newTab) { + newTab.opener = null; + newTab.location.href = url; + } + } +} diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index 3e2e2fc289e..09b2f37842e 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -96,7 +96,7 @@ export class GlobalMouseMoveMonitor extends Disposable { for (let i = 0; i < windowChain.length; i++) { this.hooks.push(dom.addDisposableThrottledListener(windowChain[i].window.document, 'mousemove', (data: R) => this.mouseMoveCallback(data), - (lastEvent: R, currentEvent: MouseEvent) => this.mouseMoveEventMerger(lastEvent, currentEvent) + (lastEvent: R, currentEvent) => this.mouseMoveEventMerger(lastEvent, currentEvent as MouseEvent) )); this.hooks.push(dom.addDisposableListener(windowChain[i].window.document, 'mouseup', (e: MouseEvent) => this.stopMonitoring(true))); } diff --git a/src/vs/base/browser/htmlContentRenderer.ts b/src/vs/base/browser/htmlContentRenderer.ts index a49e4411274..1a0097aadf8 100644 --- a/src/vs/base/browser/htmlContentRenderer.ts +++ b/src/vs/base/browser/htmlContentRenderer.ts @@ -29,13 +29,13 @@ function createElement(options: RenderOptions): HTMLElement { return element; } -export function renderText(text: string, options: RenderOptions = {}): Node { +export function renderText(text: string, options: RenderOptions = {}): HTMLElement { const element = createElement(options); element.textContent = text; return element; } -export function renderFormattedText(formattedText: string, options: RenderOptions = {}): Node { +export function renderFormattedText(formattedText: string, options: RenderOptions = {}): HTMLElement { const element = createElement(options); _renderFormattedText(element, parseFormattedText(formattedText), options.actionCallback); return element; @@ -47,11 +47,9 @@ export function renderFormattedText(formattedText: string, options: RenderOption * @param content a html element description * @param actionCallback a callback function for any action links in the string. Argument is the zero-based index of the clicked action. */ -export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions = {}): Node { +export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions = {}): HTMLElement { const element = createElement(options); - const { codeBlockRenderer, actionCallback } = options; - // signal to code-block render that the // element has been created let signalInnerHTML: Function; diff --git a/src/vs/base/browser/keyboardEvent.ts b/src/vs/base/browser/keyboardEvent.ts index 6f90f1b1b07..22b92dbb28f 100644 --- a/src/vs/base/browser/keyboardEvent.ts +++ b/src/vs/base/browser/keyboardEvent.ts @@ -163,7 +163,7 @@ function extractKeyCode(e: KeyboardEvent): KeyCode { return KeyCodeUtils.fromString(char); } return KEY_CODE_MAP[e.keyCode] || KeyCode.Unknown; -}; +} export interface IKeyboardEvent { readonly browserEvent: KeyboardEvent; diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 930ab74fd19..06e582d642e 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -21,6 +21,10 @@ display: inline-block; } +.monaco-action-bar.reverse .actions-container { + flex-direction: row-reverse; +} + .monaco-action-bar .action-item { cursor: pointer; display: inline-block; diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 688cb903a45..62c84c331c5 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -118,17 +118,18 @@ export class BaseActionItem extends EventEmitter implements IActionItem { this.builder.on(EventType.Tap, e => this.onClick(e)); - this.builder.on(DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { + this.builder.on(DOM.EventType.MOUSE_DOWN, (e) => { if (!enableDragging) { - DOM.EventHelper.stop(e); // do not run when dragging is on because that would disable it + DOM.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it } - if (this._action.enabled && e.button === 0) { + const mouseEvent = e as MouseEvent; + if (this._action.enabled && mouseEvent.button === 0) { this.builder.addClass('active'); } }); - this.builder.on(DOM.EventType.CLICK, (e: MouseEvent) => { + this.builder.on(DOM.EventType.CLICK, (e) => { DOM.EventHelper.stop(e, true); // See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard // > Writing to the clipboard @@ -145,7 +146,7 @@ export class BaseActionItem extends EventEmitter implements IActionItem { } }); - this.builder.on([DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT], (e: MouseEvent) => { + this.builder.on([DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT], (e) => { DOM.EventHelper.stop(e); this.builder.removeClass('active'); }); @@ -350,8 +351,10 @@ export class ActionItem extends BaseActionItem { } export enum ActionsOrientation { - HORIZONTAL = 1, - VERTICAL = 2 + HORIZONTAL, + HORIZONTAL_REVERSE, + VERTICAL, + VERTICAL_REVERSE, } export interface IActionItemProvider { @@ -420,18 +423,38 @@ export class ActionBar extends EventEmitter implements IActionRunner { DOM.addClass(this.domNode, 'animated'); } - let isVertical = this.options.orientation === ActionsOrientation.VERTICAL; - if (isVertical) { - this.domNode.className += ' vertical'; + let previousKey: KeyCode; + let nextKey: KeyCode; + + switch (this.options.orientation) { + case ActionsOrientation.HORIZONTAL: + previousKey = KeyCode.LeftArrow; + nextKey = KeyCode.RightArrow; + break; + case ActionsOrientation.HORIZONTAL_REVERSE: + previousKey = KeyCode.RightArrow; + nextKey = KeyCode.LeftArrow; + this.domNode.className += ' reverse'; + break; + case ActionsOrientation.VERTICAL: + previousKey = KeyCode.UpArrow; + nextKey = KeyCode.DownArrow; + this.domNode.className += ' vertical'; + break; + case ActionsOrientation.VERTICAL_REVERSE: + previousKey = KeyCode.DownArrow; + nextKey = KeyCode.UpArrow; + this.domNode.className += ' vertical reverse'; + break; } - $(this.domNode).on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - let event = new StandardKeyboardEvent(e); + $(this.domNode).on(DOM.EventType.KEY_DOWN, (e) => { + let event = new StandardKeyboardEvent(e as KeyboardEvent); let eventHandled = true; - if (event.equals(isVertical ? KeyCode.UpArrow : KeyCode.LeftArrow)) { + if (event.equals(previousKey)) { this.focusPrevious(); - } else if (event.equals(isVertical ? KeyCode.DownArrow : KeyCode.RightArrow)) { + } else if (event.equals(nextKey)) { this.focusNext(); } else if (event.equals(KeyCode.Escape)) { this.cancel(); @@ -447,8 +470,8 @@ export class ActionBar extends EventEmitter implements IActionRunner { } }); - $(this.domNode).on(DOM.EventType.KEY_UP, (e: KeyboardEvent) => { - let event = new StandardKeyboardEvent(e); + $(this.domNode).on(DOM.EventType.KEY_UP, (e) => { + let event = new StandardKeyboardEvent(e as KeyboardEvent); // Run action on Enter/Space if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { @@ -573,6 +596,22 @@ export class ActionBar extends EventEmitter implements IActionRunner { }); } + public getWidth(index: number): number { + if (index >= 0 && index < this.actionsList.children.length) { + return this.actionsList.children.item(index).clientWidth; + } + + return 0; + } + + public getHeight(index: number): number { + if (index >= 0 && index < this.actionsList.children.length) { + return this.actionsList.children.item(index).clientHeight; + } + + return 0; + } + public pull(index: number): void { if (index >= 0 && index < this.items.length) { this.items.splice(index, 1); diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index 356692bf766..044a2cebdb0 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -67,8 +67,8 @@ export class Button extends EventEmitter { this.emit(DOM.EventType.CLICK, e); }); - this.$el.on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - let event = new StandardKeyboardEvent(e); + this.$el.on(DOM.EventType.KEY_DOWN, (e) => { + let event = new StandardKeyboardEvent(e as KeyboardEvent); let eventHandled = false; if (this.enabled && event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { this.emit(DOM.EventType.CLICK, e); @@ -83,7 +83,7 @@ export class Button extends EventEmitter { } }); - this.$el.on(DOM.EventType.MOUSE_OVER, (e: MouseEvent) => { + this.$el.on(DOM.EventType.MOUSE_OVER, (e) => { if (!this.$el.hasClass('disabled')) { const hoverBackground = this.buttonHoverBackground ? this.buttonHoverBackground.toString() : null; if (hoverBackground) { @@ -92,7 +92,7 @@ export class Button extends EventEmitter { } }); - this.$el.on(DOM.EventType.MOUSE_OUT, (e: MouseEvent) => { + this.$el.on(DOM.EventType.MOUSE_OUT, (e) => { this.applyStyles(); // restore standard styles }); diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 10144ee2c71..86b39b2e234 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -73,6 +73,10 @@ export class Checkbox extends Widget { }); } + public get enabled(): boolean { + return this.domNode.getAttribute('aria-disabled') !== 'true'; + } + public focus(): void { this.domNode.focus(); } diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index 958297431e2..fe0788dbf3a 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -268,8 +268,7 @@ export class FindInput extends Widget { placeholder: this.placeholder || '', ariaLabel: this.label || '', validationOptions: { - validation: this.validation || null, - showMessage: true + validation: this.validation || null }, inputBackground: this.inputBackground, inputForeground: this.inputForeground, diff --git a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts index 9f622f16fdb..95cf18196c1 100644 --- a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts +++ b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts @@ -4,11 +4,10 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { escape } from 'vs/base/common/strings'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as dom from 'vs/base/browser/dom'; import * as objects from 'vs/base/common/objects'; -import { expand as expandOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; +import { render as renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; export interface IHighlight { start: number; @@ -64,19 +63,19 @@ export class HighlightedLabel implements IDisposable { } if (pos < highlight.start) { htmlContent.push(''); - htmlContent.push(expandOcticons(escape(this.text.substring(pos, highlight.start)))); + htmlContent.push(renderOcticons(this.text.substring(pos, highlight.start))); htmlContent.push(''); pos = highlight.end; } htmlContent.push(''); - htmlContent.push(expandOcticons(escape(this.text.substring(highlight.start, highlight.end)))); + htmlContent.push(renderOcticons(this.text.substring(highlight.start, highlight.end))); htmlContent.push(''); pos = highlight.end; } if (pos < this.text.length) { htmlContent.push(''); - htmlContent.push(expandOcticons(escape(this.text.substring(pos)))); + htmlContent.push(renderOcticons(this.text.substring(pos))); htmlContent.push(''); } diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index 2e75d866672..60dec0ac2a3 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -11,12 +11,18 @@ import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlighte import { IMatch } from 'vs/base/common/filters'; import uri from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); -import { IRootProvider, getPathLabel, IUserHomeProvider } from 'vs/base/common/labels'; +import { IWorkspaceFolderProvider, getPathLabel, IUserHomeProvider } from 'vs/base/common/labels'; +import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; export interface IIconLabelCreationOptions { supportHighlights?: boolean; } +export interface ILabelBadgeOptions { + title: string; + className: string; +} + export interface IIconLabelOptions { title?: string; extraClasses?: string[]; @@ -24,56 +30,101 @@ export interface IIconLabelOptions { matches?: IMatch[]; } -export class IconLabel { - private domNode: HTMLElement; - private labelNode: HTMLElement | HighlightedLabel; - private descriptionNode: HTMLElement; +class FastLabelNode { + private disposed: boolean; + private _textContent: string; + private _className: string; + private _title: string; + private _empty: boolean; - constructor(container: HTMLElement, options?: IIconLabelCreationOptions) { - this.domNode = dom.append(container, dom.$('.monaco-icon-label')); - if (options && options.supportHighlights) { - this.labelNode = new HighlightedLabel(dom.append(this.domNode, dom.$('a.label-name'))); - } else { - this.labelNode = dom.append(this.domNode, dom.$('a.label-name')); - } - this.descriptionNode = dom.append(this.domNode, dom.$('span.label-description')); + constructor(private _element: HTMLElement) { } public get element(): HTMLElement { - return this.domNode; + return this._element; } - public get labelElement(): HTMLElement { + public set textContent(content: string) { + if (this.disposed || content === this._textContent) { + return; + } + + this._textContent = content; + this._element.textContent = content; + } + + public set className(className: string) { + if (this.disposed || className === this._className) { + return; + } + + this._className = className; + this._element.className = className; + } + + public set title(title: string) { + if (this.disposed || title === this._title) { + return; + } + + this._title = title; + this._element.title = title; + } + + public set empty(empty: boolean) { + if (this.disposed || empty === this._empty) { + return; + } + + this._empty = empty; + this._element.style.marginLeft = empty ? '0' : null; + } + + public dispose(): void { + this.disposed = true; + } +} + +export class IconLabel { + private domNode: FastLabelNode; + private labelNode: FastLabelNode | HighlightedLabel; + private descriptionNode: FastLabelNode; + + constructor(container: HTMLElement, options?: IIconLabelCreationOptions) { + this.domNode = new FastLabelNode(dom.append(container, dom.$('.monaco-icon-label'))); + + const labelDescriptionContainer = new FastLabelNode(dom.append(this.domNode.element, dom.$('.monaco-icon-label-description-container'))); + + if (options && options.supportHighlights) { + this.labelNode = new HighlightedLabel(dom.append(labelDescriptionContainer.element, dom.$('a.label-name'))); + } else { + this.labelNode = new FastLabelNode(dom.append(labelDescriptionContainer.element, dom.$('a.label-name'))); + } + + this.descriptionNode = new FastLabelNode(dom.append(labelDescriptionContainer.element, dom.$('span.label-description'))); + } + + public get element(): HTMLElement { + return this.domNode.element; + } + + public onClick(callback: (event: MouseEvent) => void): IDisposable { + return combinedDisposable([ + dom.addDisposableListener(this.labelElement, dom.EventType.CLICK, (e: MouseEvent) => callback(e)), + dom.addDisposableListener(this.descriptionNode.element, dom.EventType.CLICK, (e: MouseEvent) => callback(e)) + ]); + } + + private get labelElement(): HTMLElement { const labelNode = this.labelNode; if (labelNode instanceof HighlightedLabel) { return labelNode.element; - } else { - return labelNode; } - } - public get descriptionElement(): HTMLElement { - return this.descriptionNode; + return labelNode.element; } public setValue(label?: string, description?: string, options?: IIconLabelOptions): void { - const labelNode = this.labelNode; - if (labelNode instanceof HighlightedLabel) { - labelNode.set(label || '', options ? options.matches : void 0); - } else { - labelNode.textContent = label || ''; - } - - this.descriptionNode.textContent = description || ''; - - if (!description) { - dom.addClass(this.descriptionNode, 'empty'); - } else { - dom.removeClass(this.descriptionNode, 'empty'); - } - - this.domNode.title = options && options.title ? options.title : ''; - const classes = ['monaco-icon-label']; if (options) { if (options.extraClasses) { @@ -86,27 +137,37 @@ export class IconLabel { } this.domNode.className = classes.join(' '); + this.domNode.title = options && options.title ? options.title : ''; + + const labelNode = this.labelNode; + if (labelNode instanceof HighlightedLabel) { + labelNode.set(label || '', options ? options.matches : void 0); + } else { + labelNode.textContent = label || ''; + } + + this.descriptionNode.textContent = description || ''; + this.descriptionNode.empty = !description; } public dispose(): void { - const labelNode = this.labelNode; - if (labelNode instanceof HighlightedLabel) { - labelNode.dispose(); - } + this.domNode.dispose(); + this.labelNode.dispose(); + this.descriptionNode.dispose(); } } export class FileLabel extends IconLabel { - constructor(container: HTMLElement, file: uri, provider: IRootProvider, userHome?: IUserHomeProvider) { + constructor(container: HTMLElement, file: uri, provider: IWorkspaceFolderProvider, userHome?: IUserHomeProvider) { super(container); this.setFile(file, provider, userHome); } - public setFile(file: uri, provider: IRootProvider, userHome: IUserHomeProvider): void { + public setFile(file: uri, provider: IWorkspaceFolderProvider, userHome: IUserHomeProvider): void { const parent = paths.dirname(file.fsPath); this.setValue(paths.basename(file.fsPath), parent && parent !== '.' ? getPathLabel(parent, provider, userHome) : '', { title: file.fsPath }); } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 993b4a30822..6e6a73fb542 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -6,7 +6,7 @@ /* ---------- Icon label ---------- */ .monaco-icon-label { - display: inline-block; /* required for icons support :before rule */ + display: flex; /* required for icons support :before rule */ overflow: hidden; text-overflow: ellipsis; } @@ -25,25 +25,46 @@ /* fonts icons */ -webkit-font-smoothing: antialiased; vertical-align: top; + + flex-shrink: 0; /* fix for https://github.com/Microsoft/vscode/issues/13787 */ } -.monaco-icon-label > .label-name { +.monaco-icon-label > .monaco-icon-label-description-container { + overflow: hidden; /* this causes the label/description to shrink first if decorations are enabled */ + text-overflow: ellipsis; +} + +.monaco-icon-label > .monaco-icon-label-description-container > .label-name { color: inherit; white-space: pre; /* enable to show labels that include multiple whitespaces */ } -.monaco-icon-label > .label-description { +.monaco-icon-label > .monaco-icon-label-description-container > .label-description { opacity: 0.7; margin-left: 0.5em; font-size: 0.9em; white-space: pre; /* enable to show labels that include multiple whitespaces */ } -.monaco-icon-label > .label-description.empty { - margin-left: 0; +.monaco-icon-label.italic > .monaco-icon-label-description-container > .label-name, +.monaco-icon-label.italic > .monaco-icon-label-description-container > .label-description { + font-style: italic; } -.monaco-icon-label.italic > .label-name, -.monaco-icon-label.italic > .label-description { - font-style: italic; -} \ No newline at end of file +.monaco-icon-label::after { + opacity: 0.75; + font-size: 90%; + font-weight: 600; + padding: 0 12px 0 5px; + margin-left: auto; + text-align: center; +} + +/* make sure selection color wins when a label is being selected */ +.monaco-tree.focused .selected .monaco-icon-label, /* tree */ +.monaco-tree.focused .selected .monaco-icon-label::after, +.monaco-list:focus .focused.selected .monaco-icon-label, /* list */ +.monaco-list:focus .focused.selected .monaco-icon-label::after +{ + color: inherit !important; +} diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 18b09e697e8..8dfb882931c 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -54,7 +54,6 @@ export interface IMessage { export interface IInputValidationOptions { validation: IInputValidator; - showMessage?: boolean; } export enum MessageType { @@ -90,7 +89,6 @@ export class InputBox extends Widget { private placeholder: string; private ariaLabel: string; private validation: IInputValidator; - private showValidationMessage: boolean; private state = 'idle'; private cachedHeight: number; @@ -135,7 +133,6 @@ export class InputBox extends Widget { if (this.options.validationOptions) { this.validation = this.options.validationOptions.validation; - this.showValidationMessage = this.options.validationOptions.showMessage || false; } this.element = dom.append(container, $('.monaco-inputbox.idle')); @@ -179,7 +176,13 @@ export class InputBox extends Widget { }); } - setTimeout(() => this.updateMirror(), 0); + setTimeout(() => { + if (!this.input) { + return; + } + + this.updateMirror(); + }, 0); // Support actions if (this.options.actions) { @@ -385,9 +388,9 @@ export class InputBox extends Widget { className: 'monaco-inputbox-message' }; - let spanElement: HTMLElement = (this.message.formatContent + const spanElement = (this.message.formatContent ? renderFormattedText(this.message.content, renderOptions) - : renderText(this.message.content, renderOptions)) as any; + : renderText(this.message.content, renderOptions)); dom.addClass(spanElement, this.classForType(this.message.type)); const styles = this.stylesForType(this.message.type); @@ -491,7 +494,6 @@ export class InputBox extends Widget { this.placeholder = null; this.ariaLabel = null; this.validation = null; - this.showValidationMessage = null; this.state = null; this.actionbar = null; diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 3a4e10f7b26..16f8e590c29 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -14,7 +14,7 @@ import * as platform from 'vs/base/common/platform'; import { EventType as TouchEventType } from 'vs/base/browser/touch'; import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import Event, { Emitter, EventBufferer, chain, mapEvent, fromCallback, any } from 'vs/base/common/event'; +import Event, { Emitter, EventBufferer, chain, mapEvent, fromCallback, anyEvent } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IDelegate, IRenderer, IListEvent, IListMouseEvent, IListContextMenuEvent } from './list'; import { ListView, IListViewOptions } from './listView'; @@ -52,7 +52,7 @@ interface IRenderedElement { index: number; } -class TraitRenderer implements IRenderer +class TraitRenderer implements IRenderer { private rendered: IRenderedElement[] = []; @@ -107,8 +107,8 @@ class Trait implements ISpliceable, IDisposable { get trait(): string { return this._trait; } @memoize - get renderer(): TraitRenderer { - return new TraitRenderer(this); + get renderer(): TraitRenderer { + return new TraitRenderer(this); } constructor(private _trait: string) { @@ -247,6 +247,8 @@ class KeyboardController implements IDisposable { onKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this, this.disposables); onKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUpArrow, this, this.disposables); onKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDownArrow, this, this.disposables); + onKeyDown.filter(e => (platform.isMacintosh ? e.metaKey : e.ctrlKey) && e.keyCode === KeyCode.KEY_A).on(this.onCtrlA, this, this.disposables); + onKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(this.onEscape, this, this.disposables); } private onEnter(e: StandardKeyboardEvent): void { @@ -288,6 +290,20 @@ class KeyboardController implements IDisposable { this.view.domNode.focus(); } + private onCtrlA(e: StandardKeyboardEvent): void { + e.preventDefault(); + e.stopPropagation(); + this.list.setSelection(range(this.list.length)); + this.view.domNode.focus(); + } + + private onEscape(e: StandardKeyboardEvent): void { + e.preventDefault(); + e.stopPropagation(); + this.list.setSelection([]); + this.view.domNode.focus(); + } + dispose() { this.disposables = dispose(this.disposables); } @@ -307,6 +323,7 @@ function isSelectionChangeEvent(event: IListMouseEvent): boolean { export interface IMouseControllerOptions { selectOnMouseDown?: boolean; + focusOnMouseDown?: boolean; } class MouseController implements IDisposable { @@ -331,7 +348,7 @@ class MouseController implements IDisposable { .map(({ element, index, clientX, clientY }) => ({ element, index, anchor: { x: clientX + 1, y: clientY } })) .event; - return any>(fromKeyboard, fromMouse); + return anyEvent>(fromKeyboard, fromMouse); } constructor( @@ -348,9 +365,12 @@ class MouseController implements IDisposable { } private onMouseDown(e: IListMouseEvent): void { - e.preventDefault(); - e.stopPropagation(); - this.view.domNode.focus(); + if (this.options.focusOnMouseDown === false) { + e.preventDefault(); + e.stopPropagation(); + } else { + this.view.domNode.focus(); + } let reference = this.list.getFocus()[0]; reference = reference === undefined ? this.list.getSelection()[0] : reference; @@ -373,9 +393,6 @@ class MouseController implements IDisposable { } private onPointer(e: IListMouseEvent): void { - e.preventDefault(); - e.stopPropagation(); - if (isSelectionChangeEvent(e)) { return; } @@ -388,9 +405,6 @@ class MouseController implements IDisposable { } private onDoubleClick(e: IListMouseEvent): void { - e.preventDefault(); - e.stopPropagation(); - if (isSelectionChangeEvent(e)) { return; } @@ -406,7 +420,7 @@ class MouseController implements IDisposable { if (isSelectionRangeChangeEvent(e) && reference !== undefined) { const min = Math.min(reference, focus); const max = Math.max(reference, focus); - const rangeSelection = range(max + 1, min); + const rangeSelection = range(min, max + 1); const selection = this.list.getSelection(); const contiguousRange = getContiguousRangeContaining(disjunction(selection, [reference]), reference); @@ -698,6 +712,10 @@ export class List implements ISpliceable, IDisposable { this.view.setScrollTop(scrollTop); } + domFocus(): void { + this.view.domNode.focus(); + } + layout(height?: number): void { this.view.layout(height); } diff --git a/src/vs/base/browser/ui/octiconLabel/octiconLabel.mock.ts b/src/vs/base/browser/ui/octiconLabel/octiconLabel.mock.ts index 1f628552999..46bf06ccb39 100644 --- a/src/vs/base/browser/ui/octiconLabel/octiconLabel.mock.ts +++ b/src/vs/base/browser/ui/octiconLabel/octiconLabel.mock.ts @@ -5,8 +5,8 @@ import octiconLabel = require('vs/base/browser/ui/octiconLabel/octiconLabel'); import { escape } from 'vs/base/common/strings'; -function expand(text: string): string { - return text; +function render(text: string): string { + return escape(text); } class MockOcticonLabel { @@ -18,16 +18,13 @@ class MockOcticonLabel { } set text(text: string) { - let innerHTML = text || ''; - innerHTML = escape(innerHTML); - innerHTML = expand(innerHTML); - this._container.innerHTML = innerHTML; + this._container.innerHTML = render(text || ''); } } var mock: typeof octiconLabel = { - expand: expand, + render: render, OcticonLabel: MockOcticonLabel }; export = mock; \ No newline at end of file diff --git a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts b/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts index 50f4f0dbc76..e7339c58bbd 100644 --- a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts +++ b/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts @@ -8,12 +8,16 @@ import 'vs/css!./octicons/octicons'; import 'vs/css!./octicons/octicons-animations'; import { escape } from 'vs/base/common/strings'; -export function expand(text: string): string { +function expand(text: string): string { return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (match, g1, name, g3, animation) => { return ``; }); } +export function render(label: string): string { + return expand(escape(label)); +} + export class OcticonLabel { private _container: HTMLElement; @@ -23,13 +27,10 @@ export class OcticonLabel { } set text(text: string) { - let innerHTML = text || ''; - innerHTML = escape(innerHTML); - innerHTML = expand(innerHTML); - this._container.innerHTML = innerHTML; + this._container.innerHTML = render(text || ''); } set title(title: string) { this._container.title = title; } -} +} \ No newline at end of file diff --git a/src/vs/base/browser/ui/progressbar/progressbar.ts b/src/vs/base/browser/ui/progressbar/progressbar.ts index ea34e06e1cb..19e5657414c 100644 --- a/src/vs/base/browser/ui/progressbar/progressbar.ts +++ b/src/vs/base/browser/ui/progressbar/progressbar.ts @@ -40,7 +40,6 @@ export class ProgressBar { private toUnbind: IDisposable[]; private workedVal: number; private element: Builder; - private animationRunning: boolean; private bit: HTMLElement; private totalWork: number; private animationStopToken: ValueCallback; @@ -64,11 +63,6 @@ export class ProgressBar { builder.div({ 'class': css_progress_bit }).on([DOM.EventType.ANIMATION_START, DOM.EventType.ANIMATION_END, DOM.EventType.ANIMATION_ITERATION], (e: Event) => { switch (e.type) { - case DOM.EventType.ANIMATION_START: - case DOM.EventType.ANIMATION_END: - this.animationRunning = e.type === DOM.EventType.ANIMATION_START; - break; - case DOM.EventType.ANIMATION_ITERATION: if (this.animationStopToken) { this.animationStopToken(null); diff --git a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts b/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts index 762852ab390..cc2c5bff1f8 100644 --- a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts +++ b/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts @@ -33,6 +33,7 @@ const mapExtToMediaMimes: MapExtToMediaMimes = { '.ico': 'image/x-icon', '.tga': 'image/x-tga', '.psd': 'image/vnd.adobe.photoshop', + '.webp': 'image/webp', '.mid': 'audio/midi', '.midi': 'audio/midi', '.mp4a': 'audio/mp4', diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 338d07b4681..2569e53d3ab 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -12,7 +12,7 @@ import { isIPad } from 'vs/base/browser/browser'; import { isMacintosh } from 'vs/base/common/platform'; import types = require('vs/base/common/types'); import DOM = require('vs/base/browser/dom'); -import { Gesture, EventType, GestureEvent } from 'vs/base/browser/touch'; +import { EventType, GestureEvent } from 'vs/base/browser/touch'; import { EventEmitter } from 'vs/base/common/eventEmitter'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import Event, { Emitter } from 'vs/base/common/event'; @@ -51,7 +51,6 @@ export enum Orientation { export class Sash extends EventEmitter { private $e: Builder; - private gesture: Gesture; private layoutProvider: ISashLayoutProvider; private isDisabled: boolean; private hidden: boolean; @@ -67,11 +66,9 @@ export class Sash extends EventEmitter { this.$e.addClass('mac'); } - this.gesture = new Gesture(this.$e.getHTMLElement()); - - this.$e.on(DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { this.onMouseDown(e); }); - this.$e.on(DOM.EventType.DBLCLICK, (e: MouseEvent) => { this.emit('reset', e); }); - this.$e.on(EventType.Start, (e: GestureEvent) => { this.onTouchStart(e); }); + this.$e.on(DOM.EventType.MOUSE_DOWN, (e) => { this.onMouseDown(e as MouseEvent); }); + this.$e.on(DOM.EventType.DBLCLICK, (e) => { this.emit('reset', e as MouseEvent); }); + this.$e.on(EventType.Start, (e) => { this.onTouchStart(e as GestureEvent); }); this.size = options.baseSize || 5; @@ -141,12 +138,9 @@ export class Sash extends EventEmitter { let $window = $(window); let containerCSSClass = `${this.getOrientation()}-cursor-container${isMacintosh ? '-mac' : ''}`; - let lastCurrentX = startX; - let lastCurrentY = startY; - - $window.on('mousemove', (e: MouseEvent) => { + $window.on('mousemove', (e) => { DOM.EventHelper.stop(e, false); - let mouseMoveEvent = new StandardMouseEvent(e); + let mouseMoveEvent = new StandardMouseEvent(e as MouseEvent); let event: ISashEvent = { startX: startX, @@ -155,11 +149,8 @@ export class Sash extends EventEmitter { currentY: mouseMoveEvent.posy }; - lastCurrentX = mouseMoveEvent.posx; - lastCurrentY = mouseMoveEvent.posy; - this.emit('change', event); - }).once('mouseup', (e: MouseEvent) => { + }).once('mouseup', (e) => { DOM.EventHelper.stop(e, false); this.$e.removeClass('active'); this.emit('end'); @@ -191,9 +182,6 @@ export class Sash extends EventEmitter { currentY: startY }); - let lastCurrentX = startX; - let lastCurrentY = startY; - listeners.push(DOM.addDisposableListener(this.$e.getHTMLElement(), EventType.Change, (event: GestureEvent) => { if (types.isNumber(event.pageX) && types.isNumber(event.pageY)) { this.emit('change', { @@ -202,9 +190,6 @@ export class Sash extends EventEmitter { startY: startY, currentY: event.pageY }); - - lastCurrentX = event.pageX; - lastCurrentY = event.pageY; } })); @@ -268,6 +253,10 @@ export class Sash extends EventEmitter { this.isDisabled = true; } + get enabled(): boolean { + return !this.isDisabled; + } + public dispose(): void { if (this.$e) { this.$e.destroy(); diff --git a/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts index 04a0d41fdb0..76e76cd5be3 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.ts +++ b/src/vs/base/browser/ui/selectBox/selectBox.ts @@ -36,7 +36,6 @@ export class SelectBox extends Widget { private selectElement: HTMLSelectElement; private options: string[]; private selected: number; - private container: HTMLElement; private _onDidSelect: Emitter; private toDispose: IDisposable[]; private selectBackground: Color; @@ -113,7 +112,6 @@ export class SelectBox extends Widget { } public render(container: HTMLElement): void { - this.container = container; dom.addClass(container, 'select-container'); container.appendChild(this.selectElement); this.setOptions(this.options, this.selected); diff --git a/src/vs/base/browser/ui/splitview/panelview.css b/src/vs/base/browser/ui/splitview/panelview.css new file mode 100644 index 00000000000..50a7d87499a --- /dev/null +++ b/src/vs/base/browser/ui/splitview/panelview.css @@ -0,0 +1,109 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-panel-view { + width: 100%; + height: 100%; +} + +.monaco-panel-view .panel { + overflow: hidden; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; +} + +.monaco-panel-view .panel > .panel-header { + font-size: 11px; + font-weight: bold; + text-transform: uppercase; + padding-left: 20px; + overflow: hidden; + display: flex; + cursor: pointer; +} + +.monaco-panel-view .panel > .panel-header { + background-image: url('arrow-collapse.svg'); + background-position: 2px center; + background-repeat: no-repeat; +} + +.monaco-panel-view .panel > .panel-header.expanded { + background-image: url('arrow-expand.svg'); + background-position: 2px center; + background-repeat: no-repeat; +} + +.vs-dark .monaco-panel-view .panel > .panel-header { + background-image: url('arrow-collapse-dark.svg'); +} + +.vs-dark .monaco-panel-view .panel > .panel-header.expanded { + background-image: url('arrow-expand-dark.svg'); +} + +/* TODO: actions should be part of the panel, but they aren't yet */ +.monaco-panel-view .panel > .panel-header > .actions { + display: none; + flex: 1; +} + +/* TODO: actions should be part of the panel, but they aren't yet */ +.monaco-panel-view .panel:hover > .panel-header.expanded > .actions, +.monaco-panel-view .panel > .panel-header.focused.expanded > .actions { + display: initial; +} + +/* TODO: actions should be part of the panel, but they aren't yet */ +.monaco-panel-view .panel > .panel-header > .actions .action-label { + width: 28px; + height: 22px; + background-size: 16px; + background-position: center center; + background-repeat: no-repeat; + margin-right: 0; +} + +/* Bold font style does not go well with CJK fonts */ +.monaco-panel-view:lang(zh-Hans) .panel > .panel-header, +.monaco-panel-view:lang(zh-Hant) .panel > .panel-header, +.monaco-panel-view:lang(ja) .panel > .panel-header, +.monaco-panel-view:lang(ko) .panel > .panel-header { + font-weight: normal; +} + +.monaco-panel-view .panel > .panel-header.hidden { + display: none; +} + +.monaco-panel-view .panel > .panel-body { + overflow: hidden; + flex: 1; +} + +/* Animation */ + +.monaco-panel-view.animated .split-view-view { + transition-duration: 0.15s; + -webkit-transition-duration: 0.15s; + -moz-transition-duration: 0.15s; + transition-timing-function: ease-out; + -webkit-transition-timing-function: ease-out; + -moz-transition-timing-function: ease-out; +} + +.monaco-panel-view.animated.vertical .split-view-view { + transition-property: height; + -webkit-transition-property: height; + -moz-transition-property: height; +} + +.monaco-panel-view.animated.horizontal .split-view-view { + transition-property: width; + -webkit-transition-property: width; + -moz-transition-property: width; +} diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts new file mode 100644 index 00000000000..00e111e5668 --- /dev/null +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -0,0 +1,430 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import 'vs/css!./panelview'; +import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; +import Event, { Emitter, chain } from 'vs/base/common/event'; +import { domEvent } from 'vs/base/browser/event'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { $, append, addClass, removeClass, toggleClass, trackFocus } from 'vs/base/browser/dom'; +import { firstIndex } from 'vs/base/common/arrays'; +import { Color, RGBA } from 'vs/base/common/color'; +import { SplitView, IView } from './splitview'; + +export interface IPanelOptions { + ariaHeaderLabel?: string; + minimumBodySize?: number; + maximumBodySize?: number; + expanded?: boolean; +} + +export interface IPanelStyles { + dropBackground?: Color; + headerForeground?: Color; + headerBackground?: Color; + headerHighContrastBorder?: Color; +} + +export abstract class Panel implements IView { + + private static HEADER_SIZE = 22; + + protected _expanded: boolean; + private expandedSize: number | undefined = undefined; + private _headerVisible = true; + private _minimumBodySize: number; + private _maximumBodySize: number; + private ariaHeaderLabel: string; + private styles: IPanelStyles | undefined = undefined; + + private el: HTMLElement; + private header: HTMLElement; + protected disposables: IDisposable[] = []; + + private _onDidChange = new Emitter(); + readonly onDidChange: Event = this._onDidChange.event; + + get draggableElement(): HTMLElement { + return this.header; + } + + get dropTargetElement(): HTMLElement { + return this.el; + } + + private _dropBackground: Color | undefined; + get dropBackground(): Color | undefined { + return this._dropBackground; + } + + get minimumBodySize(): number { + return this._minimumBodySize; + } + + set minimumBodySize(size: number) { + this._minimumBodySize = size; + this._onDidChange.fire(); + } + + get maximumBodySize(): number { + return this._maximumBodySize; + } + + set maximumBodySize(size: number) { + this._maximumBodySize = size; + this._onDidChange.fire(); + } + + private get headerSize(): number { + return this.headerVisible ? Panel.HEADER_SIZE : 0; + } + + get minimumSize(): number { + const headerSize = this.headerSize; + const expanded = !this.headerVisible || this.isExpanded(); + const minimumBodySize = expanded ? this._minimumBodySize : 0; + + return headerSize + minimumBodySize; + } + + get maximumSize(): number { + const headerSize = this.headerSize; + const expanded = !this.headerVisible || this.isExpanded(); + const maximumBodySize = expanded ? this._maximumBodySize : 0; + + return headerSize + maximumBodySize; + } + + constructor(options: IPanelOptions = {}) { + this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded; + this.ariaHeaderLabel = options.ariaHeaderLabel || ''; + this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120; + this._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY; + } + + isExpanded(): boolean { + return this._expanded; + } + + setExpanded(expanded: boolean): void { + if (this._expanded === !!expanded) { + return; + } + + this._expanded = !!expanded; + this.updateHeader(); + this._onDidChange.fire(expanded ? this.expandedSize : undefined); + } + + get headerVisible(): boolean { + return this._headerVisible; + } + + set headerVisible(visible: boolean) { + if (this._headerVisible === !!visible) { + return; + } + + this._headerVisible = !!visible; + this.updateHeader(); + this._onDidChange.fire(); + } + + render(container: HTMLElement): void { + this.el = append(container, $('.panel')); + + this.header = $('.panel-header'); + append(this.el, this.header); + this.header.setAttribute('tabindex', '0'); + this.header.setAttribute('role', 'toolbar'); + this.header.setAttribute('aria-label', this.ariaHeaderLabel); + this.renderHeader(this.header); + + const focusTracker = trackFocus(this.header); + focusTracker.addFocusListener(() => addClass(this.header, 'focused')); + focusTracker.addBlurListener(() => removeClass(this.header, 'focused')); + + this.updateHeader(); + + const onHeaderKeyDown = chain(domEvent(this.header, 'keydown')) + .map(e => new StandardKeyboardEvent(e)); + + onHeaderKeyDown.filter(e => e.keyCode === KeyCode.Enter || e.keyCode === KeyCode.Space) + .event(() => this.setExpanded(!this.isExpanded()), null, this.disposables); + + onHeaderKeyDown.filter(e => e.keyCode === KeyCode.LeftArrow) + .event(() => this.setExpanded(false), null, this.disposables); + + onHeaderKeyDown.filter(e => e.keyCode === KeyCode.RightArrow) + .event(() => this.setExpanded(true), null, this.disposables); + + domEvent(this.header, 'click') + (() => this.setExpanded(!this.isExpanded()), null, this.disposables); + + // TODO@Joao move this down to panelview + // onHeaderKeyDown.filter(e => e.keyCode === KeyCode.UpArrow) + // .event(focusPrevious, this, this.disposables); + + // onHeaderKeyDown.filter(e => e.keyCode === KeyCode.DownArrow) + // .event(focusNext, this, this.disposables); + + const body = append(this.el, $('.panel-body')); + this.renderBody(body); + } + + layout(size: number): void { + const headerSize = this.headerVisible ? Panel.HEADER_SIZE : 0; + this.layoutBody(size - headerSize); + + if (this.isExpanded()) { + this.expandedSize = size; + } + } + + style(styles: IPanelStyles): void { + this.styles = styles; + + if (!this.header) { + return; + } + + this.updateHeader(); + } + + protected updateHeader(): void { + const expanded = !this.headerVisible || this.isExpanded(); + + this.header.style.height = `${this.headerSize}px`; + this.header.style.lineHeight = `${this.headerSize}px`; + toggleClass(this.header, 'hidden', !this.headerVisible); + toggleClass(this.header, 'expanded', expanded); + this.header.setAttribute('aria-expanded', String(expanded)); + + this.header.style.color = this.styles.headerForeground ? this.styles.headerForeground.toString() : null; + this.header.style.backgroundColor = this.styles.headerBackground ? this.styles.headerBackground.toString() : null; + this.header.style.borderTop = this.styles.headerHighContrastBorder ? `1px solid ${this.styles.headerHighContrastBorder}` : null; + this._dropBackground = this.styles.dropBackground; + } + + protected abstract renderHeader(container: HTMLElement): void; + protected abstract renderBody(container: HTMLElement): void; + protected abstract layoutBody(size: number): void; + + dispose(): void { + this.disposables = dispose(this.disposables); + } +} + +interface IDndContext { + draggable: PanelDraggable | null; +} + +class PanelDraggable implements IDisposable { + + private static DefaultDragOverBackgroundColor = new Color(new RGBA(128, 128, 128, 0.5)); + + // see https://github.com/Microsoft/vscode/issues/14470 + private dragOverCounter = 0; + private disposables: IDisposable[] = []; + + private _onDidDrop = new Emitter<{ from: Panel, to: Panel }>(); + readonly onDidDrop = this._onDidDrop.event; + + constructor(private panel: Panel, private context: IDndContext) { + panel.draggableElement.draggable = true; + domEvent(panel.draggableElement, 'dragstart')(this.onDragStart, this, this.disposables); + domEvent(panel.dropTargetElement, 'dragenter')(this.onDragEnter, this, this.disposables); + domEvent(panel.dropTargetElement, 'dragleave')(this.onDragLeave, this, this.disposables); + domEvent(panel.dropTargetElement, 'dragend')(this.onDragEnd, this, this.disposables); + domEvent(panel.dropTargetElement, 'drop')(this.onDrop, this, this.disposables); + } + + private onDragStart(e: DragEvent): void { + e.dataTransfer.effectAllowed = 'move'; + + const dragImage = append(document.body, $('.monaco-panel-drag-image', {}, this.panel.draggableElement.textContent)); + e.dataTransfer.setDragImage(dragImage, -10, -10); + setTimeout(() => document.body.removeChild(dragImage), 0); + + this.context.draggable = this; + } + + private onDragEnter(e: DragEvent): void { + if (!this.context.draggable || this.context.draggable === this) { + return; + } + + this.dragOverCounter++; + this.render(); + } + + private onDragLeave(e: DragEvent): void { + if (!this.context.draggable || this.context.draggable === this) { + return; + } + + this.dragOverCounter--; + + if (this.dragOverCounter === 0) { + this.render(); + } + } + + private onDragEnd(e: DragEvent): void { + if (!this.context.draggable) { + return; + } + + this.dragOverCounter = 0; + this.render(); + this.context.draggable = null; + } + + private onDrop(e: DragEvent): void { + if (!this.context.draggable) { + return; + } + + this.dragOverCounter = 0; + this.render(); + + if (this.context.draggable !== this) { + this._onDidDrop.fire({ from: this.context.draggable.panel, to: this.panel }); + } + + this.context.draggable = null; + } + + private render(): void { + let backgroundColor: string = null; + + if (this.dragOverCounter > 0) { + backgroundColor = (this.panel.dropBackground || PanelDraggable.DefaultDragOverBackgroundColor).toString(); + } + + this.panel.dropTargetElement.style.backgroundColor = backgroundColor; + } + + dispose(): void { + this.disposables = dispose(this.disposables); + } +} + +export class IPanelViewOptions { + dnd?: boolean; +} + +interface IPanelItem { + panel: Panel; + disposable: IDisposable; +} + +export class PanelView implements IDisposable { + + private dnd: boolean; + private dndContext: IDndContext = { draggable: null }; + private el: HTMLElement; + private panelItems: IPanelItem[] = []; + private splitview: SplitView; + private animationTimer: number | null = null; + + private _onDidDrop = new Emitter<{ from: Panel, to: Panel }>(); + readonly onDidDrop: Event<{ from: Panel, to: Panel }> = this._onDidDrop.event; + + readonly onDidSashChange: Event; + + constructor(container: HTMLElement, options: IPanelViewOptions = {}) { + this.dnd = !!options.dnd; + this.el = append(container, $('.monaco-panel-view')); + this.splitview = new SplitView(this.el); + this.onDidSashChange = this.splitview.onDidSashChange; + } + + addPanel(panel: Panel, size: number, index = this.splitview.length): void { + const disposables: IDisposable[] = []; + panel.onDidChange(this.setupAnimation, this, disposables); + + const panelItem = { panel, disposable: combinedDisposable(disposables) }; + this.panelItems.splice(index, 0, panelItem); + this.splitview.addView(panel, size, index); + + if (this.dnd) { + const draggable = new PanelDraggable(panel, this.dndContext); + disposables.push(draggable); + draggable.onDidDrop(this._onDidDrop.fire, this._onDidDrop, disposables); + } + } + + removePanel(panel: Panel): void { + const index = firstIndex(this.panelItems, item => item.panel === panel); + + if (index === -1) { + return; + } + + this.splitview.removeView(index); + const panelItem = this.panelItems.splice(index, 1)[0]; + panelItem.disposable.dispose(); + } + + movePanel(from: Panel, to: Panel): void { + const fromIndex = firstIndex(this.panelItems, item => item.panel === from); + const toIndex = firstIndex(this.panelItems, item => item.panel === to); + + if (fromIndex === -1 || toIndex === -1) { + return; + } + + const [panelItem] = this.panelItems.splice(fromIndex, 1); + this.panelItems.splice(toIndex, 0, panelItem); + + this.splitview.moveView(fromIndex, toIndex); + } + + resizePanel(panel: Panel, size: number): void { + const index = firstIndex(this.panelItems, item => item.panel === panel); + + if (index === -1) { + return; + } + + this.splitview.resizeView(index, size); + } + + getPanelSize(panel: Panel): number { + const index = firstIndex(this.panelItems, item => item.panel === panel); + + if (index === -1) { + return -1; + } + + return this.splitview.getViewSize(index); + } + + layout(size: number): void { + this.splitview.layout(size); + } + + private setupAnimation(): void { + if (typeof this.animationTimer === 'number') { + window.clearTimeout(this.animationTimer); + } + + addClass(this.el, 'animated'); + + this.animationTimer = window.setTimeout(() => { + this.animationTimer = null; + removeClass(this.el, 'animated'); + }, 200); + } + + dispose(): void { + this.panelItems.forEach(i => i.disposable.dispose()); + this.splitview.dispose(); + } +} diff --git a/src/vs/base/browser/ui/splitview/splitview.css b/src/vs/base/browser/ui/splitview/splitview.css index 4a6de69c521..41d3de5c826 100644 --- a/src/vs/base/browser/ui/splitview/splitview.css +++ b/src/vs/base/browser/ui/splitview/splitview.css @@ -3,96 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-split-view { +.monaco-split-view2 { position: relative; -} - -.monaco-split-view > .split-view-view { overflow: hidden; -} - -.monaco-split-view.vertical > .split-view-view { width: 100%; -} - -.monaco-split-view.horizontal > .split-view-view { height: 100%; } -.monaco-split-view > .split-view-view > .header { - position: relative; - line-height: 22px; - font-size: 11px; - font-weight: bold; - text-transform: uppercase; - padding-left: 20px; +.monaco-split-view2 > .split-view-view { overflow: hidden; - display: flex; } -.monaco-split-view > .split-view-view > .header.hide { - display: none; +.monaco-split-view2.vertical > .split-view-view { + width: 100%; } -/* Bold font style does not go well with CJK fonts */ -.monaco-split-view:lang(zh-Hans) > .split-view-view > .header, -.monaco-split-view:lang(zh-Hant) > .split-view-view > .header, -.monaco-split-view:lang(ja) > .split-view-view > .header, -.monaco-split-view:lang(ko) > .split-view-view > .header { font-weight: normal; } - -.monaco-split-view > .split-view-view > .header.collapsible { - cursor: pointer; +.monaco-split-view2.horizontal > .split-view-view { + height: 100%; } - -.monaco-split-view > .split-view-view > .header.collapsible { - background-image: url('arrow-collapse.svg'); - background-position: 2px center; - background-repeat: no-repeat; -} - -.monaco-split-view > .split-view-view > .header.collapsible:not(.collapsed) { - background-image: url('arrow-expand.svg'); - background-position: 2px center; - background-repeat: no-repeat; -} - -.vs-dark .monaco-split-view > .split-view-view > .header.collapsible { - background-image: url('arrow-collapse-dark.svg'); -} - -.vs-dark .monaco-split-view > .split-view-view > .header.collapsible:not(.collapsed) { - background-image: url('arrow-expand-dark.svg'); - background-position: 2px center; - background-repeat: no-repeat; -} - -/* Animation */ - -.monaco-split-view.animated > .split-view-view { - transition-duration: 0.15s; - -webkit-transition-duration: 0.15s; - -moz-transition-duration: 0.15s; - transition-timing-function: ease-out; - -webkit-transition-timing-function: ease-out; - -moz-transition-timing-function: ease-out; -} - -.monaco-split-view.vertical.animated > .split-view-view { - transition-property: height; - -webkit-transition-property: height; - -moz-transition-property: height; -} - -.monaco-split-view.horizontal.animated > .split-view-view { - transition-property: width; - -webkit-transition-property: width; - -moz-transition-property: width; -} - -.hc-black .split-view-view .action-label { - background: none; -} - -.hc-black .split-view-view > .header .action-label:before { - top: 4px !important; -} \ No newline at end of file diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 6faeda7eb20..64c18622cb4 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -6,1038 +6,393 @@ 'use strict'; import 'vs/css!./splitview'; -import lifecycle = require('vs/base/common/lifecycle'); -import ee = require('vs/base/common/eventEmitter'); +import { IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import Event, { fromEventEmitter, mapEvent, Emitter } from 'vs/base/common/event'; import types = require('vs/base/common/types'); import dom = require('vs/base/browser/dom'); -import numbers = require('vs/base/common/numbers'); -import sash = require('vs/base/browser/ui/sash/sash'); -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import Event, { Emitter } from 'vs/base/common/event'; -import { Color } from 'vs/base/common/color'; +import { clamp } from 'vs/base/common/numbers'; +import { range, firstIndex } from 'vs/base/common/arrays'; +import { Sash, Orientation, ISashEvent as IBaseSashEvent } from 'vs/base/browser/ui/sash/sash'; +export { Orientation } from 'vs/base/browser/ui/sash/sash'; -export enum Orientation { - VERTICAL, - HORIZONTAL -} - -export enum ViewSizing { - Flexible, - Fixed -} - -export interface IOptions { +export interface ISplitViewOptions { orientation?: Orientation; // default Orientation.VERTICAL - canChangeOrderByDragAndDrop?: boolean; } -export interface ISashEvent { +export interface IView { + readonly minimumSize: number; + readonly maximumSize: number; + readonly onDidChange: Event; + render(container: HTMLElement, orientation: Orientation): void; + layout(size: number, orientation: Orientation): void; +} + +interface ISashEvent { + sash: Sash; start: number; current: number; } -export interface IViewOptions { - sizing?: ViewSizing; - fixedSize?: number; - minimumSize?: number; -} - -export interface IView extends ee.IEventEmitter { - preferredSize: number; +interface IViewItem { + view: IView; size: number; - sizing: ViewSizing; - fixedSize: number; - minimumSize: number; - maximumSize: number; - draggableElement?: HTMLElement; - draggableLabel?: string; - render(container: HTMLElement, orientation: Orientation): void; - layout(size: number, orientation: Orientation): void; - focus(): void; + container: HTMLElement; + disposable: IDisposable; + layout(): void; } -interface IState { - start?: number; - sizes?: number[]; - up?: number[]; - down?: number[]; - maxUp?: number; - maxDown?: number; - collapses: number[]; - expands: number[]; +interface ISashItem { + sash: Sash; + disposable: IDisposable; } -export abstract class View extends ee.EventEmitter implements IView { - - size: number; - protected _sizing: ViewSizing; - protected _fixedSize: number; - protected _minimumSize: number; - - constructor(public preferredSize: number, opts: IViewOptions) { - super(); - - this.size = 0; - this._sizing = types.isUndefined(opts.sizing) ? ViewSizing.Flexible : opts.sizing; - this._fixedSize = types.isUndefined(opts.fixedSize) ? 22 : opts.fixedSize; - this._minimumSize = types.isUndefined(opts.minimumSize) ? 22 : opts.minimumSize; - } - - get sizing(): ViewSizing { return this._sizing; } - get fixedSize(): number { return this._fixedSize; } - get minimumSize(): number { return this.sizing === ViewSizing.Fixed ? this.fixedSize : this._minimumSize; } - get maximumSize(): number { return this.sizing === ViewSizing.Fixed ? this.fixedSize : Number.POSITIVE_INFINITY; } - - protected setFlexible(size?: number): void { - this._sizing = ViewSizing.Flexible; - this.emit('change', types.isUndefined(size) ? this._minimumSize : size); - } - - protected setFixed(size?: number): void { - this._sizing = ViewSizing.Fixed; - this._fixedSize = types.isUndefined(size) ? this._fixedSize : size; - this.emit('change', this._fixedSize); - } - - abstract render(container: HTMLElement, orientation: Orientation): void; - abstract focus(): void; - abstract layout(size: number, orientation: Orientation): void; +interface ISashDragState { + index: number; + start: number; + sizes: number[]; + minDelta: number; + maxDelta: number; } -export interface IHeaderViewOptions extends IHeaderViewStyles, IViewOptions { - headerSize?: number; +enum State { + Idle, + Busy } -export interface IHeaderViewStyles { - headerForeground?: Color; - headerBackground?: Color; - headerHighContrastBorder?: Color; -} +export class SplitView implements IDisposable { -const headerDefaultOpts = { - headerBackground: Color.fromHex('#808080').transparent(0.2) -}; - -export abstract class HeaderView extends View { - - private _headerSize: number; - private _showHeader: boolean; - - protected header: HTMLElement; - protected body: HTMLElement; - - private headerForeground: Color; - private headerBackground: Color; - private headerHighContrastBorder: Color; - - constructor(initialSize: number, opts: IHeaderViewOptions) { - super(initialSize, opts); - - this._headerSize = types.isUndefined(opts.headerSize) ? 22 : opts.headerSize; - this._showHeader = this._headerSize > 0; - - this.headerForeground = opts.headerForeground; - this.headerBackground = opts.headerBackground || headerDefaultOpts.headerBackground; - this.headerHighContrastBorder = opts.headerHighContrastBorder; - } - - style(styles: IHeaderViewStyles): void { - this.headerForeground = styles.headerForeground; - this.headerBackground = styles.headerBackground; - this.headerHighContrastBorder = styles.headerHighContrastBorder; - - this.applyStyles(); - } - - protected get headerSize(): number { - return this._showHeader ? this._headerSize : 0; - } - - protected applyStyles(): void { - if (this.header) { - const headerForegroundColor = this.headerForeground ? this.headerForeground.toString() : null; - const headerBackgroundColor = this.headerBackground ? this.headerBackground.toString() : null; - const headerHighContrastBorderColor = this.headerHighContrastBorder ? this.headerHighContrastBorder.toString() : null; - - this.header.style.color = headerForegroundColor; - this.header.style.backgroundColor = headerBackgroundColor; - this.header.style.borderTop = headerHighContrastBorderColor ? `1px solid ${headerHighContrastBorderColor}` : null; - } - } - - get draggableElement(): HTMLElement { return this.header; } - - render(container: HTMLElement, orientation: Orientation): void { - this.header = document.createElement('div'); - this.header.className = 'header'; - - let headerSize = this.headerSize + 'px'; - - if (orientation === Orientation.HORIZONTAL) { - this.header.style.width = headerSize; - } else { - this.header.style.height = headerSize; - } - - if (this._showHeader) { - this.renderHeader(this.header); - container.appendChild(this.header); - } - - this.body = document.createElement('div'); - this.body.className = 'body'; - - this.layoutBodyContainer(orientation); - this.renderBody(this.body); - container.appendChild(this.body); - - this.applyStyles(); - } - - showHeader(): boolean { - if (!this._showHeader) { - if (!this.body.parentElement.contains(this.header)) { - this.renderHeader(this.header); - this.body.parentElement.insertBefore(this.header, this.body); - } - dom.removeClass(this.header, 'hide'); - this._showHeader = true; - return true; - } - return false; - } - - hideHeader(): boolean { - if (this._showHeader) { - dom.addClass(this.header, 'hide'); - this._showHeader = false; - return true; - } - return false; - } - - layout(size: number, orientation: Orientation): void { - this.layoutBodyContainer(orientation); - this.layoutBody(size - this.headerSize); - } - - private layoutBodyContainer(orientation: Orientation): void { - let size = `calc(100% - ${this.headerSize}px)`; - - if (orientation === Orientation.HORIZONTAL) { - this.body.style.width = size; - } else { - this.body.style.height = size; - } - } - - dispose(): void { - this.header = null; - this.body = null; - - super.dispose(); - } - - protected abstract renderHeader(container: HTMLElement): void; - protected abstract renderBody(container: HTMLElement): void; - protected abstract layoutBody(size: number): void; -} - -export interface ICollapsibleViewOptions { - sizing: ViewSizing; - ariaHeaderLabel: string; - bodySize?: number; - initialState?: CollapsibleState; -} - -export enum CollapsibleState { - EXPANDED, - COLLAPSED -} - -export abstract class AbstractCollapsibleView extends HeaderView { - - protected state: CollapsibleState; - - private ariaHeaderLabel: string; - private headerClickListener: lifecycle.IDisposable; - private headerKeyListener: lifecycle.IDisposable; - private focusTracker: dom.IFocusTracker; - private _bodySize: number; - private _previousSize: number = null; - private readonly viewSizing: ViewSizing; - - constructor(initialSize: number | undefined, opts: ICollapsibleViewOptions) { - super(initialSize, opts); - this.viewSizing = opts.sizing; - this.ariaHeaderLabel = opts.ariaHeaderLabel; - - this.setBodySize(types.isUndefined(opts.bodySize) ? 22 : opts.bodySize); - - if (typeof this.preferredSize === 'undefined') { - this.preferredSize = this._bodySize + this.headerSize; - } - - this.changeState(types.isUndefined(opts.initialState) ? CollapsibleState.EXPANDED : opts.initialState); - } - - get previousSize(): number { - return this._previousSize; - } - - setBodySize(bodySize: number) { - this._bodySize = bodySize; - this.updateSize(); - } - - private updateSize() { - if (this.viewSizing === ViewSizing.Fixed) { - this.setFixed(this.state === CollapsibleState.EXPANDED ? this._bodySize + this.headerSize : this.headerSize); - } else { - this._minimumSize = this._bodySize + this.headerSize; - this._previousSize = !this.previousSize || this._previousSize < this._minimumSize ? this._minimumSize : this._previousSize; - if (this.state === CollapsibleState.EXPANDED) { - this.setFlexible(this._previousSize || this._minimumSize); - } else { - this._previousSize = this.size || this._minimumSize; - this.setFixed(this.headerSize); - } - } - } - - render(container: HTMLElement, orientation: Orientation): void { - super.render(container, orientation); - - dom.addClass(this.header, 'collapsible'); - dom.addClass(this.body, 'collapsible'); - - // Keyboard access - this.header.setAttribute('tabindex', '0'); - this.header.setAttribute('role', 'toolbar'); - if (this.ariaHeaderLabel) { - this.header.setAttribute('aria-label', this.ariaHeaderLabel); - } - this.header.setAttribute('aria-expanded', String(this.state === CollapsibleState.EXPANDED)); - this.headerKeyListener = dom.addDisposableListener(this.header, dom.EventType.KEY_DOWN, (e) => { - let event = new StandardKeyboardEvent(e); - let eventHandled = false; - if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space) || (event.equals(KeyCode.LeftArrow) && this.state === CollapsibleState.EXPANDED) || (event.equals(KeyCode.RightArrow) && this.state === CollapsibleState.COLLAPSED)) { - this.toggleExpansion(); - eventHandled = true; - } else if (event.equals(KeyCode.Escape)) { - this.header.blur(); - eventHandled = true; - } else if (event.equals(KeyCode.UpArrow)) { - this.emit('focusPrevious'); - eventHandled = true; - } else if (event.equals(KeyCode.DownArrow)) { - this.emit('focusNext'); - eventHandled = true; - } - - if (eventHandled) { - dom.EventHelper.stop(event, true); - } - }); - - // Mouse access - this.headerClickListener = dom.addDisposableListener(this.header, dom.EventType.CLICK, () => this.toggleExpansion()); - - // Track state of focus in header so that other components can adjust styles based on that - // (for example show or hide actions based on the state of being focused or not) - this.focusTracker = dom.trackFocus(this.header); - this.focusTracker.addFocusListener(() => { - dom.addClass(this.header, 'focused'); - }); - - this.focusTracker.addBlurListener(() => { - dom.removeClass(this.header, 'focused'); - }); - } - - focus(): void { - if (this.header) { - this.header.focus(); - } - } - - layout(size: number, orientation: Orientation): void { - this.layoutHeader(); - super.layout(size, orientation); - } - - isExpanded(): boolean { - return this.state === CollapsibleState.EXPANDED; - } - - expand(): void { - if (this.isExpanded()) { - return; - } - - this.changeState(CollapsibleState.EXPANDED); - } - - collapse(): void { - if (!this.isExpanded()) { - return; - } - - this.changeState(CollapsibleState.COLLAPSED); - } - - toggleExpansion(): void { - if (this.isExpanded()) { - this.collapse(); - } else { - this.expand(); - } - } - - private layoutHeader(): void { - if (!this.header) { - return; - } - - if (this.state === CollapsibleState.COLLAPSED) { - dom.addClass(this.header, 'collapsed'); - } else { - dom.removeClass(this.header, 'collapsed'); - } - } - - protected changeState(state: CollapsibleState): void { - this.state = state; - - if (this.header) { - this.header.setAttribute('aria-expanded', String(this.state === CollapsibleState.EXPANDED)); - } - - this.layoutHeader(); - this.updateSize(); - } - - showHeader(): boolean { - const result = super.showHeader(); - if (result) { - this.updateSize(); - } - return result; - } - - hideHeader(): boolean { - const result = super.hideHeader(); - if (result) { - this.updateSize(); - } - return result; - } - - dispose(): void { - if (this.headerClickListener) { - this.headerClickListener.dispose(); - this.headerClickListener = null; - } - - if (this.headerKeyListener) { - this.headerKeyListener.dispose(); - this.headerKeyListener = null; - } - - if (this.focusTracker) { - this.focusTracker.dispose(); - this.focusTracker = null; - } - - super.dispose(); - } -} - -class PlainView extends View { - render() { } - focus() { } - layout() { } -} - -class DeadView extends PlainView { - - constructor(view: IView) { - super(view.size, { sizing: ViewSizing.Fixed, fixedSize: 0 }); - } -} - -class VoidView extends PlainView { - - constructor() { - super(0, { sizing: ViewSizing.Fixed, minimumSize: 0, fixedSize: 0 }); - } - - setFlexible(size?: number): void { - super.setFlexible(size); - } - - setFixed(size?: number): void { - super.setFixed(size); - } -} - -function sum(arr: number[]): number { - return arr.reduce((a, b) => a + b); -} - -export interface SplitViewStyles { - dropBackground?: Color; -} - -export class SplitView extends lifecycle.Disposable implements - sash.IHorizontalSashLayoutProvider, - sash.IVerticalSashLayoutProvider { private orientation: Orientation; - private canDragAndDrop: boolean; private el: HTMLElement; - private size: number; - private viewElements: HTMLElement[]; - private views: IView[]; - private viewChangeListeners: lifecycle.IDisposable[]; - private viewFocusPreviousListeners: lifecycle.IDisposable[]; - private viewFocusNextListeners: lifecycle.IDisposable[]; - private viewFocusListeners: lifecycle.IDisposable[]; - private viewDnDListeners: lifecycle.IDisposable[][]; - private sashOrientation: sash.Orientation; - private sashes: sash.Sash[]; - private sashesListeners: lifecycle.IDisposable[]; - private measureContainerSize: () => number; - private layoutViewElement: (viewElement: HTMLElement, size: number) => void; - private eventWrapper: (event: sash.ISashEvent) => ISashEvent; - private animationTimeout: number; - private state: IState; - private draggedView: IView; - private dropBackground: Color; + private size = 0; + private contentSize = 0; + private viewItems: IViewItem[] = []; + private sashItems: ISashItem[] = []; + private sashDragState: ISashDragState; + private state: State = State.Idle; - private _onFocus: Emitter = this._register(new Emitter()); - readonly onFocus: Event = this._onFocus.event; - - private _onDidOrderChange: Emitter = this._register(new Emitter()); - readonly onDidOrderChange: Event = this._onDidOrderChange.event; - - constructor(container: HTMLElement, options?: IOptions) { - super(); - options = options || {}; + private _onDidSashChange = new Emitter(); + readonly onDidSashChange = this._onDidSashChange.event; + get length(): number { + return this.viewItems.length; + } + constructor(container: HTMLElement, options: ISplitViewOptions = {}) { this.orientation = types.isUndefined(options.orientation) ? Orientation.VERTICAL : options.orientation; - this.canDragAndDrop = !!options.canChangeOrderByDragAndDrop; this.el = document.createElement('div'); - dom.addClass(this.el, 'monaco-split-view'); + dom.addClass(this.el, 'monaco-split-view2'); dom.addClass(this.el, this.orientation === Orientation.VERTICAL ? 'vertical' : 'horizontal'); container.appendChild(this.el); - - this.size = null; - this.viewElements = []; - this.views = []; - this.viewChangeListeners = []; - this.viewFocusPreviousListeners = []; - this.viewFocusNextListeners = []; - this.viewFocusListeners = []; - this.viewDnDListeners = []; - this.sashes = []; - this.sashesListeners = []; - this.animationTimeout = null; - - this.sashOrientation = this.orientation === Orientation.VERTICAL - ? sash.Orientation.HORIZONTAL - : sash.Orientation.VERTICAL; - - if (this.orientation === Orientation.VERTICAL) { - this.measureContainerSize = () => dom.getContentHeight(container); - this.layoutViewElement = (viewElement, size) => viewElement.style.height = size + 'px'; - this.eventWrapper = e => { return { start: e.startY, current: e.currentY }; }; - } else { - this.measureContainerSize = () => dom.getContentWidth(container); - this.layoutViewElement = (viewElement, size) => viewElement.style.width = size + 'px'; - this.eventWrapper = e => { return { start: e.startX, current: e.currentX }; }; - } - - // The void space exists to handle the case where all other views are fixed size - this.addView(new VoidView(), 1, 0); } - getViews(): T[] { - return this.views.slice(0, this.views.length - 1); - } - - addView(view: IView, initialWeight: number = 1, index = this.views.length - 1): void { - if (initialWeight <= 0) { - throw new Error('Initial weight must be a positive number.'); + addView(view: IView, size: number, index = this.viewItems.length): void { + if (this.state !== State.Idle) { + throw new Error('Cant modify splitview'); } - /** - * Reset size to null. This will layout newly added views to initial weights. - */ - this.size = null; + this.state = State.Busy; - let viewCount = this.views.length; + // Add view + const container = dom.$('.split-view-view'); - // Create view container - let viewElement = document.createElement('div'); - dom.addClass(viewElement, 'split-view-view'); - this.viewElements.splice(index, 0, viewElement); - - // Create view - view.render(viewElement, this.orientation); - this.views.splice(index, 0, view); - - // Render view - if (index === viewCount) { - this.el.appendChild(viewElement); + if (index === this.viewItems.length) { + this.el.appendChild(container); } else { - this.el.insertBefore(viewElement, this.el.children.item(index)); + this.el.insertBefore(container, this.el.children.item(index)); } - // Listen to Drag and Drop - this.viewDnDListeners[index] = this.createDnDListeners(view, viewElement); + const onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size)); + const containerDisposable = toDisposable(() => this.el.removeChild(container)); + const disposable = combinedDisposable([onChangeDisposable, containerDisposable]); + + const layoutContainer = this.orientation === Orientation.VERTICAL + ? size => item.container.style.height = `${item.size}px` + : size => item.container.style.width = `${item.size}px`; + + const layout = () => { + layoutContainer(item.size); + item.view.layout(item.size, this.orientation); + }; + + size = Math.round(size); + const item: IViewItem = { view, container, size, layout, disposable }; + this.viewItems.splice(index, 0, item); // Add sash - if (this.views.length > 2) { - let s = new sash.Sash(this.el, this, { orientation: this.sashOrientation }); - this.sashes.splice(index - 1, 0, s); - this.sashesListeners.push(s.addListener('start', e => this.onSashStart(s, this.eventWrapper(e)))); - this.sashesListeners.push(s.addListener('change', e => this.onSashChange(s, this.eventWrapper(e)))); + if (this.viewItems.length > 1) { + const orientation = this.orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL; + const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: sash => this.getSashPosition(sash) } : { getVerticalSashLeft: sash => this.getSashPosition(sash) }; + const sash = new Sash(this.el, layoutProvider, { orientation }); + const sashEventMapper = this.orientation === Orientation.VERTICAL + ? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY }) + : (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX }); + + const onStart = mapEvent(fromEventEmitter(sash, 'start'), sashEventMapper); + const onStartDisposable = onStart(this.onSashStart, this); + const onChange = mapEvent(fromEventEmitter(sash, 'change'), sashEventMapper); + const onSashChangeDisposable = onChange(this.onSashChange, this); + const onEnd = mapEvent(fromEventEmitter(sash, 'end'), () => null); + const onEndDisposable = onEnd(() => this._onDidSashChange.fire()); + + const disposable = combinedDisposable([onStartDisposable, onSashChangeDisposable, onEndDisposable, sash]); + const sashItem: ISashItem = { sash, disposable }; + + this.sashItems.splice(index - 1, 0, sashItem); } - this.viewChangeListeners.splice(index, 0, view.addListener('change', size => this.onViewChange(view, size))); - this.onViewChange(view, view.minimumSize); - - let viewFocusTracker = dom.trackFocus(viewElement); - this.viewFocusListeners.splice(index, 0, viewFocusTracker); - viewFocusTracker.addFocusListener(() => this._onFocus.fire(view)); - - this.viewFocusPreviousListeners.splice(index, 0, view.addListener('focusPrevious', () => index > 0 && this.views[index - 1].focus())); - this.viewFocusNextListeners.splice(index, 0, view.addListener('focusNext', () => index < this.views.length && this.views[index + 1].focus())); + view.render(container, this.orientation); + this.relayout(); + this.state = State.Idle; } - removeView(view: IView): void { - let index = this.views.indexOf(view); + removeView(index: number): void { + if (this.state !== State.Idle) { + throw new Error('Cant modify splitview'); + } - if (index < 0) { + this.state = State.Busy; + + if (index < 0 || index >= this.viewItems.length) { return; } - this.size = null; - let deadView = new DeadView(view); - this.views[index] = deadView; - this.onViewChange(deadView, 0); + // Remove view + const viewItem = this.viewItems.splice(index, 1)[0]; + viewItem.disposable.dispose(); - let sashIndex = Math.max(index - 1, 0); - if (sashIndex < this.sashes.length) { - this.sashes[sashIndex].dispose(); - this.sashes.splice(sashIndex, 1); + // Remove sash + if (this.viewItems.length >= 1) { + const sashIndex = Math.max(index - 1, 0); + const sashItem = this.sashItems.splice(sashIndex, 1)[0]; + sashItem.disposable.dispose(); } - this.viewChangeListeners[index].dispose(); - this.viewChangeListeners.splice(index, 1); - - this.viewFocusPreviousListeners[index].dispose(); - this.viewFocusPreviousListeners.splice(index, 1); - - this.viewFocusListeners[index].dispose(); - this.viewFocusListeners.splice(index, 1); - - this.viewFocusNextListeners[index].dispose(); - this.viewFocusNextListeners.splice(index, 1); - - lifecycle.dispose(this.viewDnDListeners[index]); - this.viewDnDListeners.splice(index, 1); - - this.views.splice(index, 1); - this.el.removeChild(this.viewElements[index]); - this.viewElements.splice(index, 1); - - deadView.dispose(); - view.dispose(); + this.relayout(); + this.state = State.Idle; } - layout(size?: number): void { - size = size || this.measureContainerSize(); + moveView(from: number, to: number): void { + if (this.state !== State.Idle) { + throw new Error('Cant modify splitview'); + } - if (this.size === null) { - this.size = size; - this.initialLayout(); + this.state = State.Busy; + + if (from < 0 || from >= this.viewItems.length) { return; } - size = Math.max(size, this.views.reduce((t, v) => t + v.minimumSize, 0)); - - let diff = Math.abs(this.size - size); - let up = numbers.countToArray(this.views.length - 1, -1); - - let collapses = this.views.map(v => v.size - v.minimumSize); - let expands = this.views.map(v => v.maximumSize - v.size); - - if (size < this.size) { - this.expandCollapse(Math.min(diff, sum(collapses)), collapses, expands, up, []); - } else if (size > this.size) { - this.expandCollapse(Math.min(diff, sum(expands)), collapses, expands, [], up); - } - - this.size = size; - this.layoutViews(); - } - - style(styles: SplitViewStyles): void { - this.dropBackground = styles.dropBackground; - } - - private createDnDListeners(view: IView, viewElement: HTMLElement): lifecycle.IDisposable[] { - if (!this.canDragAndDrop || view instanceof VoidView) { - return []; - } - - const disposables: lifecycle.IDisposable[] = []; - - // Allow to drag - if (view.draggableElement) { - view.draggableElement.draggable = true; - disposables.push(dom.addDisposableListener(view.draggableElement, dom.EventType.DRAG_START, (e: DragEvent) => { - e.dataTransfer.effectAllowed = 'move'; - - const dragImage = document.createElement('div'); - dragImage.className = 'monaco-tree-drag-image'; - dragImage.textContent = view.draggableLabel ? view.draggableLabel : view.draggableElement.textContent; - document.body.appendChild(dragImage); - e.dataTransfer.setDragImage(dragImage, -10, -10); - setTimeout(() => document.body.removeChild(dragImage), 0); - - this.draggedView = view; - })); - } - - // Drag enter - let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470 - disposables.push(dom.addDisposableListener(viewElement, dom.EventType.DRAG_ENTER, (e: DragEvent) => { - if (this.draggedView && this.draggedView !== view) { - counter++; - this.updateFromDragging(view, viewElement, true); - } - })); - - // Drag leave - disposables.push(dom.addDisposableListener(viewElement, dom.EventType.DRAG_LEAVE, (e: DragEvent) => { - if (this.draggedView && this.draggedView !== view) { - counter--; - if (counter === 0) { - this.updateFromDragging(view, viewElement, false); - } - } - })); - - // Drag end - disposables.push(dom.addDisposableListener(viewElement, dom.EventType.DRAG_END, (e: DragEvent) => { - if (this.draggedView) { - counter = 0; - this.updateFromDragging(view, viewElement, false); - this.draggedView = null; - } - })); - - // Drop - disposables.push(dom.addDisposableListener(viewElement, dom.EventType.DROP, (e: DragEvent) => { - dom.EventHelper.stop(e, true); - counter = 0; - this.updateFromDragging(view, viewElement, false); - if (this.draggedView && this.draggedView !== view) { - this.move(this.views.indexOf(this.draggedView), this.views.indexOf(view)); - } - this.draggedView = null; - })); - - return disposables; - } - - private updateFromDragging(view: IView, viewElement: HTMLElement, isDragging: boolean): void { - viewElement.style.backgroundColor = isDragging && this.dropBackground ? this.dropBackground.toString() : null; - } - - private move(fromIndex: number, toIndex: number): void { - if (fromIndex < 0 || toIndex > this.views.length - 2) { + if (to < 0 || to >= this.viewItems.length) { return; } - const [viewChangeListener] = this.viewChangeListeners.splice(fromIndex, 1); - this.viewChangeListeners.splice(toIndex, 0, viewChangeListener); - - const [viewFocusPreviousListener] = this.viewFocusPreviousListeners.splice(fromIndex, 1); - this.viewFocusPreviousListeners.splice(toIndex, 0, viewFocusPreviousListener); - - const [viewFocusListener] = this.viewFocusListeners.splice(fromIndex, 1); - this.viewFocusListeners.splice(toIndex, 0, viewFocusListener); - - const [viewFocusNextListener] = this.viewFocusNextListeners.splice(fromIndex, 1); - this.viewFocusNextListeners.splice(toIndex, 0, viewFocusNextListener); - - const [viewDnDListeners] = this.viewDnDListeners.splice(fromIndex, 1); - this.viewDnDListeners.splice(toIndex, 0, viewDnDListeners); - - const [view] = this.views.splice(fromIndex, 1); - this.views.splice(toIndex, 0, view); - - this.el.removeChild(this.viewElements[fromIndex]); - this.el.insertBefore(this.viewElements[fromIndex], this.viewElements[toIndex < fromIndex ? toIndex : toIndex + 1]); - const [viewElement] = this.viewElements.splice(fromIndex, 1); - this.viewElements.splice(toIndex, 0, viewElement); - - this.layout(); - - this._onDidOrderChange.fire(); - } - - private onSashStart(sash: sash.Sash, event: ISashEvent): void { - let i = this.sashes.indexOf(sash); - let collapses = this.views.map(v => v.size - v.minimumSize); - let expands = this.views.map(v => v.maximumSize - v.size); - - let up = numbers.countToArray(i, -1); - let down = numbers.countToArray(i + 1, this.views.length); - - let collapsesUp = up.map(i => collapses[i]); - let collapsesDown = down.map(i => collapses[i]); - let expandsUp = up.map(i => expands[i]); - let expandsDown = down.map(i => expands[i]); - - this.state = { - start: event.start, - sizes: this.views.map(v => v.size), - up: up, - down: down, - maxUp: Math.min(sum(collapsesUp), sum(expandsDown)), - maxDown: Math.min(sum(expandsUp), sum(collapsesDown)), - collapses: collapses, - expands: expands - }; - } - - private onSashChange(sash: sash.Sash, event: ISashEvent): void { - let diff = event.current - this.state.start; - - for (let i = 0; i < this.views.length; i++) { - this.views[i].size = this.views[i].preferredSize = this.state.sizes[i]; + if (from === to) { + return; } - if (diff < 0) { - this.expandCollapse(Math.min(-diff, this.state.maxUp), this.state.collapses, this.state.expands, this.state.up, this.state.down); + const viewItem = this.viewItems.splice(from, 1)[0]; + this.viewItems.splice(to, 0, viewItem); + + if (to + 1 < this.viewItems.length) { + this.el.insertBefore(viewItem.container, this.viewItems[to + 1].container); } else { - this.expandCollapse(Math.min(diff, this.state.maxDown), this.state.collapses, this.state.expands, this.state.down, this.state.up); + this.el.appendChild(viewItem.container); } this.layoutViews(); + this.state = State.Idle; } - // Main algorithm - private expandCollapse(collapse: number, collapses: number[], expands: number[], collapseIndexes: number[], expandIndexes: number[]): void { - let totalCollapse = collapse; - let totalExpand = totalCollapse; - - collapseIndexes.forEach(i => { - let collapse = Math.min(collapses[i], totalCollapse); - totalCollapse -= collapse; - this.views[i].size -= collapse; - }); - - expandIndexes.forEach(i => { - let expand = Math.min(expands[i], totalExpand); - totalExpand -= expand; - this.views[i].size += expand; - }); + private relayout(): void { + const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); + this.resize(this.viewItems.length - 1, this.contentSize - contentSize); } - private initialLayout(): void { - let totalWeight = 0; - let fixedSize = 0; + layout(size: number): void { + const previousSize = Math.max(this.size, this.contentSize); + this.size = size; + this.resize(this.viewItems.length - 1, size - previousSize); + } - this.views.forEach((v, i) => { - if (v.sizing === ViewSizing.Flexible) { - totalWeight += v.preferredSize; - } else { - fixedSize += v.fixedSize; - } - }); + private onSashStart({ sash, start }: ISashEvent): void { + const index = firstIndex(this.sashItems, item => item.sash === sash); + const sizes = this.viewItems.map(i => i.size); - let flexibleSize = this.size - fixedSize; + const upIndexes = range(index, -1); + const collapseUp = upIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0); + const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0); - this.views.forEach((v, i) => { - if (v.sizing === ViewSizing.Flexible) { - if (totalWeight === 0) { - v.size = flexibleSize; - } else { - v.size = v.preferredSize * flexibleSize / totalWeight; - } - } else { - v.size = v.fixedSize; - } - }); + const downIndexes = range(index + 1, this.viewItems.length); + const collapseDown = downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0); + const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0); - // Leftover - let index = this.getLastFlexibleViewIndex(); - if (index >= 0) { - this.views[index].size += this.size - this.views.reduce((t, v) => t + v.size, 0); + const minDelta = -Math.min(collapseUp, expandDown); + const maxDelta = Math.min(collapseDown, expandUp); + + this.sashDragState = { start, index, sizes, minDelta, maxDelta }; + } + + private onSashChange({ sash, current }: ISashEvent): void { + const { index, start, sizes, minDelta, maxDelta } = this.sashDragState; + const delta = clamp(current - start, minDelta, maxDelta); + + this.resize(index, delta, sizes); + } + + private onViewChange(item: IViewItem, size: number | undefined): void { + const index = this.viewItems.indexOf(item); + + if (index < 0 || index >= this.viewItems.length) { + return; } - // Layout + size = typeof size === 'number' ? size : item.size; + size = clamp(size, item.view.minimumSize, item.view.maximumSize); + item.size = size; + this.relayout(); + } + + resizeView(index: number, size: number): void { + if (this.state !== State.Idle) { + throw new Error('Cant modify splitview'); + } + + this.state = State.Busy; + + if (index < 0 || index >= this.viewItems.length) { + return; + } + + const item = this.viewItems[index]; + size = Math.round(size); + size = clamp(size, item.view.minimumSize, item.view.maximumSize); + let delta = size - item.size; + + if (delta !== 0 && index < this.viewItems.length - 1) { + const downIndexes = range(index + 1, this.viewItems.length); + const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0); + const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0); + const deltaDown = clamp(delta, -expandDown, collapseDown); + + this.resize(index, deltaDown); + delta -= deltaDown; + } + + if (delta !== 0 && index > 0) { + const upIndexes = range(index - 1, -1); + const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0); + const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0); + const deltaUp = clamp(-delta, -collapseUp, expandUp); + + this.resize(index - 1, deltaUp); + } + + this.state = State.Idle; + } + + getViewSize(index: number): number { + if (index < 0 || index >= this.viewItems.length) { + return -1; + } + + return this.viewItems[index].size; + } + + private resize(index: number, delta: number, sizes = this.viewItems.map(i => i.size)): void { + if (index < 0 || index >= this.viewItems.length) { + return; + } + + if (delta !== 0) { + const upIndexes = range(index, -1); + const up = upIndexes.map(i => this.viewItems[i]); + const upSizes = upIndexes.map(i => sizes[i]); + const downIndexes = range(index + 1, this.viewItems.length); + const down = downIndexes.map(i => this.viewItems[i]); + const downSizes = downIndexes.map(i => sizes[i]); + + for (let i = 0, deltaUp = delta; deltaUp !== 0 && i < up.length; i++) { + const item = up[i]; + const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize); + const viewDelta = size - upSizes[i]; + + deltaUp -= viewDelta; + item.size = size; + } + + for (let i = 0, deltaDown = delta; deltaDown !== 0 && i < down.length; i++) { + const item = down[i]; + const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize); + const viewDelta = size - downSizes[i]; + + deltaDown += viewDelta; + item.size = size; + } + } + + let contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); + let emptyDelta = this.size - contentSize; + + for (let i = this.viewItems.length - 1; emptyDelta > 0 && i >= 0; i--) { + const item = this.viewItems[i]; + const size = clamp(item.size + emptyDelta, item.view.minimumSize, item.view.maximumSize); + const viewDelta = size - item.size; + + emptyDelta -= viewDelta; + item.size = size; + } + + this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); + this.layoutViews(); } - private getLastFlexibleViewIndex(exceptIndex: number = null): number { - for (let i = this.views.length - 1; i >= 0; i--) { - if (exceptIndex === i) { - continue; - } - if (this.views[i].sizing === ViewSizing.Flexible) { - return i; - } - } - - return -1; - } - private layoutViews(): void { - for (let i = 0; i < this.views.length; i++) { - // Layout the view elements - this.layoutViewElement(this.viewElements[i], this.views[i].size); - - // Layout the views themselves - this.views[i].layout(this.views[i].size, this.orientation); - } - - // Layout the sashes - this.sashes.forEach(s => s.layout()); + this.viewItems.forEach(item => item.layout()); + this.sashItems.forEach(item => item.sash.layout()); // Update sashes enablement let previous = false; - let collapsesDown = this.views.map(v => previous = (v.size - v.minimumSize > 0) || previous); + const collapsesDown = this.viewItems.map(i => previous = (i.size - i.view.minimumSize > 0) || previous); previous = false; - let expandsDown = this.views.map(v => previous = (v.maximumSize - v.size > 0) || previous); + const expandsDown = this.viewItems.map(i => previous = (i.view.maximumSize - i.size > 0) || previous); - let reverseViews = this.views.slice().reverse(); + const reverseViews = [...this.viewItems].reverse(); previous = false; - let collapsesUp = reverseViews.map(v => previous = (v.size - v.minimumSize > 0) || previous).reverse(); + const collapsesUp = reverseViews.map(i => previous = (i.size - i.view.minimumSize > 0) || previous).reverse(); previous = false; - let expandsUp = reverseViews.map(v => previous = (v.maximumSize - v.size > 0) || previous).reverse(); + const expandsUp = reverseViews.map(i => previous = (i.view.maximumSize - i.size > 0) || previous).reverse(); - this.sashes.forEach((s, i) => { + this.sashItems.forEach((s, i) => { if ((collapsesDown[i] && expandsUp[i + 1]) || (expandsDown[i] && collapsesUp[i + 1])) { - s.enable(); + s.sash.enable(); } else { - s.disable(); + s.sash.disable(); } }); } - private onViewChange(view: IView, size: number): void { - if (view !== this.voidView) { - if (this.areAllViewsFixed()) { - this.voidView.setFlexible(); - } else { - this.voidView.setFixed(); + private getSashPosition(sash: Sash): number { + let position = 0; + + for (let i = 0; i < this.sashItems.length; i++) { + position += this.viewItems[i].size; + + if (this.sashItems[i].sash === sash) { + return position; } } - if (this.size === null) { - return; - } - - if (size === view.size) { - return; - } - - this.setupAnimation(); - - let index = this.views.indexOf(view); - let diff = Math.abs(size - view.size); - let up = numbers.countToArray(index - 1, -1); - let down = numbers.countToArray(index + 1, this.views.length); - let downUp = down.concat(up); - - let collapses = this.views.map(v => Math.max(v.size - v.minimumSize, 0)); - let expands = this.views.map(v => Math.max(v.maximumSize - v.size, 0)); - - let collapse: number, collapseIndexes: number[], expandIndexes: number[]; - - if (size < view.size) { - collapse = Math.min(downUp.reduce((t, i) => t + expands[i], 0), diff); - collapseIndexes = [index]; - expandIndexes = downUp; - - } else { - collapse = Math.min(downUp.reduce((t, i) => t + collapses[i], 0), diff); - collapseIndexes = downUp; - expandIndexes = [index]; - } - - this.expandCollapse(collapse, collapses, expands, collapseIndexes, expandIndexes); - this.layoutViews(); - } - - private setupAnimation(): void { - if (types.isNumber(this.animationTimeout)) { - window.clearTimeout(this.animationTimeout); - } - - dom.addClass(this.el, 'animated'); - this.animationTimeout = window.setTimeout(() => this.clearAnimation(), 200); - } - - private clearAnimation(): void { - this.animationTimeout = null; - dom.removeClass(this.el, 'animated'); - } - - private get voidView(): VoidView { - return this.views[this.views.length - 1] as VoidView; - } - - private areAllViewsFixed(): boolean { - return this.views.every((v, i) => v.sizing === ViewSizing.Fixed || i === this.views.length - 1); - } - - getVerticalSashLeft(sash: sash.Sash): number { - return this.getSashPosition(sash); - } - - getHorizontalSashTop(sash: sash.Sash): number { - return this.getSashPosition(sash); - } - - private getSashPosition(sash: sash.Sash): number { - let index = this.sashes.indexOf(sash); - let position = 0; - - for (let i = 0; i <= index; i++) { - position += this.views[i].size; - } - - return position; + return 0; } dispose(): void { - if (types.isNumber(this.animationTimeout)) { - window.clearTimeout(this.animationTimeout); - } - this.orientation = null; - this.size = null; - this.viewElements.forEach(e => this.el.removeChild(e)); - this.el = null; - this.viewElements = []; - this.views = lifecycle.dispose(this.views); - this.sashes = lifecycle.dispose(this.sashes); - this.sashesListeners = lifecycle.dispose(this.sashesListeners); - this.measureContainerSize = null; - this.layoutViewElement = null; - this.eventWrapper = null; - this.state = null; + this.viewItems.forEach(i => i.disposable.dispose()); + this.viewItems = []; - super.dispose(); + this.sashItems.forEach(i => i.disposable.dispose()); + this.sashItems = []; } } diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 2565b518f14..7f0ef21e7d2 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -23,6 +23,7 @@ export interface IToolBarOptions { actionItemProvider?: IActionItemProvider; ariaLabel?: string; getKeyBinding?: (action: IAction) => ResolvedKeybinding; + actionRunner?: IActionRunner; } /** @@ -49,6 +50,7 @@ export class ToolBar { this.actionBar = new ActionBar($(element), { orientation: options.orientation, ariaLabel: options.ariaLabel, + actionRunner: options.actionRunner, actionItemProvider: (action: Action) => { // Return special action item for the toggle menu action diff --git a/src/vs/base/common/OSSREADME.json b/src/vs/base/common/OSSREADME.json deleted file mode 100644 index aafe65aace5..00000000000 --- a/src/vs/base/common/OSSREADME.json +++ /dev/null @@ -1,30 +0,0 @@ -// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: -[{ - "name": "string_scorer", - "version": "0.1.20", - "license": "MIT", - "repositoryURL": "https://github.com/joshaven/string_score", - "description": "The file scorer.ts was inspired by the string_score algorithm from Joshaven Potter.", - "licenseDetail": [ - "This software is released under the MIT license:", - "", - "Copyright (c) Joshaven Potter", - "", - "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." - ] -}] diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index 273ffb30cab..b54372196a6 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import { TPromise } from 'vs/base/common/winjs.base'; + /** * Returns the last element of an array. * @param array The array. @@ -111,7 +113,7 @@ function _divideAndMerge(data: T[], compare: (a: T, b: T) => number): void { export function groupBy(data: T[], compare: (a: T, b: T) => number): T[][] { const result: T[][] = []; let currentGroup: T[]; - for (const element of data.slice(0).sort(compare)) { + for (const element of mergeSort(data.slice(0), compare)) { if (!currentGroup || compare(currentGroup[0], element) !== 0) { currentGroup = [element]; result.push(currentGroup); @@ -122,28 +124,43 @@ export function groupBy(data: T[], compare: (a: T, b: T) => number): T[][] { return result; } -/** - * Takes two *sorted* arrays and computes their delta (removed, added elements). - * Finishes in `Math.min(before.length, after.length)` steps. - * @param before - * @param after - * @param compare - */ -export function delta(before: T[], after: T[], compare: (a: T, b: T) => number) { +export interface Splice { + start: number; + deleteCount: number; + inserted: T[]; +} - const removed: T[] = []; - const added: T[] = []; +/** + * Diffs two *sorted* arrays and computes the splices which apply the diff. + */ +export function sortedDiff(before: T[], after: T[], compare: (a: T, b: T) => number): Splice[] { + const result: Splice[] = []; + + function pushSplice(start: number, deleteCount: number, inserted: T[]): void { + if (deleteCount === 0 && inserted.length === 0) { + return; + } + + const latest = result[result.length - 1]; + + if (latest && latest.start + latest.deleteCount === start) { + latest.deleteCount += deleteCount; + latest.inserted.push(...inserted); + } else { + result.push({ start, deleteCount, inserted }); + } + } let beforeIdx = 0; let afterIdx = 0; while (true) { if (beforeIdx === before.length) { - added.push(...after.slice(afterIdx)); + pushSplice(beforeIdx, 0, after.slice(afterIdx)); break; } if (afterIdx === after.length) { - removed.push(...before.slice(beforeIdx)); + pushSplice(beforeIdx, before.length - beforeIdx, []); break; } @@ -156,15 +173,35 @@ export function delta(before: T[], after: T[], compare: (a: T, b: T) => numbe afterIdx += 1; } else if (n < 0) { // beforeElement is smaller -> before element removed - removed.push(beforeElement); + pushSplice(beforeIdx, 1, []); beforeIdx += 1; } else if (n > 0) { // beforeElement is greater -> after element added - added.push(afterElement); + pushSplice(beforeIdx, 0, [afterElement]); afterIdx += 1; } } + return result; +} + +/** + * Takes two *sorted* arrays and computes their delta (removed, added elements). + * Finishes in `Math.min(before.length, after.length)` steps. + * @param before + * @param after + * @param compare + */ +export function delta(before: T[], after: T[], compare: (a: T, b: T) => number): { removed: T[], added: T[] } { + const splices = sortedDiff(before, after, compare); + const removed: T[] = []; + const added: T[] = []; + + for (const splice of splices) { + removed.push(...before.slice(splice.start, splice.start + splice.deleteCount)); + added.push(...splice.inserted); + } + return { removed, added }; } @@ -183,7 +220,51 @@ export function top(array: T[], compare: (a: T, b: T) => number, n: number): return []; } const result = array.slice(0, n).sort(compare); - for (let i = n, m = array.length; i < m; i++) { + topStep(array, compare, result, n, array.length); + return result; +} + +/** + * Asynchronous variant of `top()` allowing for splitting up work in batches between which the event loop can run. + * + * Returns the top N elements from the array. + * + * Faster than sorting the entire array when the array is a lot larger than N. + * + * @param array The unsorted array. + * @param compare A sort function for the elements. + * @param n The number of elements to return. + * @param batch The number of elements to examine before yielding to the event loop. + * @return The first n elemnts from array when sorted with compare. + */ +export function topAsync(array: T[], compare: (a: T, b: T) => number, n: number, batch: number): TPromise { + if (n === 0) { + return TPromise.as([]); + } + let canceled = false; + return new TPromise((resolve, reject) => { + (async () => { + const o = array.length; + const result = array.slice(0, n).sort(compare); + for (let i = n, m = Math.min(n + batch, o); i < o; i = m, m = Math.min(m + batch, o)) { + if (i > n) { + await new Promise(resolve => setTimeout(resolve)); // nextTick() would starve I/O. + } + if (canceled) { + throw new Error('canceled'); + } + topStep(array, compare, result, i, m); + } + return result; + })() + .then(resolve, reject); + }, () => { + canceled = true; + }); +} + +function topStep(array: T[], compare: (a: T, b: T) => number, result: T[], i: number, m: number): void { + for (const n = result.length; i < m; i++) { const element = array[i]; if (compare(element, result[n - 1]) < 0) { result.pop(); @@ -191,7 +272,6 @@ export function top(array: T[], compare: (a: T, b: T) => number, n: number): result.splice(j, 0, element); } } - return result; } /** @@ -287,14 +367,46 @@ export function commonPrefixLength(one: T[], other: T[], equals: (a: T, b: T) } export function flatten(arr: T[][]): T[] { - return arr.reduce((r, v) => r.concat(v), []); + return [].concat(...arr); } -export function range(to: number, from = 0): number[] { +export function range(to: number): number[]; +export function range(from: number, to: number): number[]; +export function range(arg: number, to?: number): number[] { + let from = typeof to === 'number' ? arg : 0; + + if (typeof to === 'number') { + from = arg; + } else { + from = 0; + to = arg; + } + const result: number[] = []; - for (let i = from; i < to; i++) { - result.push(i); + if (from <= to) { + for (let i = from; i < to; i++) { + result.push(i); + } + } else { + for (let i = from; i > to; i--) { + result.push(i); + } + } + + return result; +} + +export function weave(a: T[], b: T[]): T[] { + const result: T[] = []; + let ai = 0, bi = 0; + + for (let i = 0, length = a.length + b.length; i < length; i++) { + if ((i % 2 === 0 && ai < a.length) || bi >= b.length) { + result.push(a[ai++]); + } else { + result.push(b[bi++]); + } } return result; diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 983ca30b520..c19feda0c94 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -13,7 +13,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; -function isThenable(obj: any): obj is Thenable { +export function isThenable(obj: any): obj is Thenable { return obj && typeof (>obj).then === 'function'; } @@ -510,7 +510,7 @@ export class Queue extends Limiter { * A helper to organize queues per resource. The ResourceQueue makes sure to manage queues per resource * by disposing them once the queue is empty. */ -export class ResourceQueue { +export class ResourceQueue { private queues: { [path: string]: Queue }; constructor() { @@ -672,11 +672,53 @@ export class RunOnceScheduler { export function nfcall(fn: Function, ...args: any[]): Promise; export function nfcall(fn: Function, ...args: any[]): TPromise; export function nfcall(fn: Function, ...args: any[]): any { - return new TPromise((c, e) => fn(...args, (err, result) => err ? e(err) : c(result)), () => null); + return new TPromise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)), () => null); } export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Promise; export function ninvoke(thisArg: any, fn: Function, ...args: any[]): TPromise; export function ninvoke(thisArg: any, fn: Function, ...args: any[]): any { - return new TPromise((c, e) => fn.call(thisArg, ...args, (err, result) => err ? e(err) : c(result)), () => null); + return new TPromise((c, e) => fn.call(thisArg, ...args, (err: any, result: any) => err ? e(err) : c(result)), () => null); } + +/** + * An emitter that will ignore any events that occur during a specific code + * execution triggered via throttle() until the promise has finished (either + * successfully or with an error). Only after the promise has finished, the + * last event that was fired during the operation will get emitted. + * + */ +export class ThrottledEmitter extends Emitter { + private suspended: boolean; + + private lastEvent: T; + private hasLastEvent: boolean; + + public throttle(promise: TPromise): TPromise { + this.suspended = true; + + return always(promise, () => this.resume()); + } + + public fire(event?: T): any { + if (this.suspended) { + this.lastEvent = event; + this.hasLastEvent = true; + + return; + } + + return super.fire(event); + } + + private resume(): void { + this.suspended = false; + + if (this.hasLastEvent) { + this.fire(this.lastEvent); + } + + this.hasLastEvent = false; + this.lastEvent = void 0; + } +} \ No newline at end of file diff --git a/src/vs/base/common/callbackList.ts b/src/vs/base/common/callbackList.ts index 9a27d3b844b..9538c3f7df6 100644 --- a/src/vs/base/common/callbackList.ts +++ b/src/vs/base/common/callbackList.ts @@ -6,47 +6,21 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { LinkedList } from 'vs/base/common/linkedList'; export default class CallbackList { - private _callbacks: Function[]; - private _contexts: any[]; + private _callbacks: LinkedList<[Function, any]>; - public add(callback: Function, context: any = null, bucket?: IDisposable[]): void { + public add(callback: Function, context: any = null, bucket?: IDisposable[]): () => void { if (!this._callbacks) { - this._callbacks = []; - this._contexts = []; + this._callbacks = new LinkedList<[Function, any]>(); } - this._callbacks.push(callback); - this._contexts.push(context); - + const remove = this._callbacks.push([callback, context]); if (Array.isArray(bucket)) { - bucket.push({ dispose: () => this.remove(callback, context) }); - } - } - - public remove(callback: Function, context: any = null): void { - if (!this._callbacks) { - return; - } - - let foundCallbackWithDifferentContext = false; - for (let i = 0, len = this._callbacks.length; i < len; i++) { - if (this._callbacks[i] === callback) { - if (this._contexts[i] === context) { - // callback & context match => remove it - this._callbacks.splice(i, 1); - this._contexts.splice(i, 1); - return; - } else { - foundCallbackWithDifferentContext = true; - } - } - } - - if (foundCallbackWithDifferentContext) { - throw new Error('When adding a listener with a context, you should remove it with the same context'); + bucket.push({ dispose: remove }); } + return remove; } public invoke(...args: any[]): any[] { @@ -54,13 +28,12 @@ export default class CallbackList { return undefined; } - const ret: any[] = [], - callbacks = this._callbacks.slice(0), - contexts = this._contexts.slice(0); + const ret: any[] = []; + const elements = this._callbacks.toArray(); - for (let i = 0, len = callbacks.length; i < len; i++) { + for (const [callback, context] of elements) { try { - ret.push(callbacks[i].apply(contexts[i], args)); + ret.push(callback.apply(context, args)); } catch (e) { onUnexpectedError(e); } @@ -68,19 +41,20 @@ export default class CallbackList { return ret; } - public isEmpty(): boolean { - return !this._callbacks || this._callbacks.length === 0; - } - public entries(): [Function, any][] { if (!this._callbacks) { return []; } - return this._callbacks.map((fn, index) => <[Function, any]>[fn, this._contexts[index]]); + return this._callbacks + ? this._callbacks.toArray() + : []; + } + + public isEmpty(): boolean { + return !this._callbacks || this._callbacks.isEmpty(); } public dispose(): void { this._callbacks = undefined; - this._contexts = undefined; } } diff --git a/src/vs/base/common/collections.ts b/src/vs/base/common/collections.ts index 20e27735d7d..70b2e7310f8 100644 --- a/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -31,7 +31,7 @@ export function values(from: IStringDictionary | INumberDictionary): T[ const result: T[] = []; for (let key in from) { if (hasOwnProperty.call(from, key)) { - result.push(from[key]); + result.push((from as any)[key]); } } return result; @@ -54,8 +54,8 @@ export function size(from: IStringDictionary | INumberDictionary): numb export function forEach(from: IStringDictionary | INumberDictionary, callback: (entry: { key: any; value: T; }, remove: Function) => any): void { for (let key in from) { if (hasOwnProperty.call(from, key)) { - const result = callback({ key: key, value: from[key] }, function () { - delete from[key]; + const result = callback({ key: key, value: (from as any)[key] }, function () { + delete (from as any)[key]; }); if (result === false) { return; @@ -72,7 +72,7 @@ export function remove(from: IStringDictionary | INumberDictionary, key if (!hasOwnProperty.call(from, key)) { return false; } - delete from[key]; + delete (from as any)[key]; return true; } diff --git a/src/vs/base/common/comparers.ts b/src/vs/base/common/comparers.ts index 67a95a10c86..70b404ca558 100644 --- a/src/vs/base/common/comparers.ts +++ b/src/vs/base/common/comparers.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import scorer = require('vs/base/common/scorer'); -import strings = require('vs/base/common/strings'); +import * as strings from 'vs/base/common/strings'; import * as paths from 'vs/base/common/paths'; let intlFileNameCollator: Intl.Collator; @@ -37,14 +36,8 @@ export function compareFileNames(one: string, other: string): number { const FileNameMatch = /^(.*?)(\.([^.]*))?$/; export function noIntlCompareFileNames(one: string, other: string): number { - let oneMatch = FileNameMatch.exec(one.toLowerCase()); - let otherMatch = FileNameMatch.exec(other.toLowerCase()); - - let oneName = oneMatch[1] || ''; - let oneExtension = oneMatch[3] || ''; - - let otherName = otherMatch[1] || ''; - let otherExtension = otherMatch[3] || ''; + const [oneName, oneExtension] = extractNameAndExtension(one, true); + const [otherName, otherExtension] = extractNameAndExtension(other, true); if (oneName !== otherName) { return oneName < otherName ? -1 : 1; @@ -59,14 +52,8 @@ export function noIntlCompareFileNames(one: string, other: string): number { export function compareFileExtensions(one: string, other: string): number { if (intlFileNameCollator) { - const oneMatch = one ? FileNameMatch.exec(one) : [] as RegExpExecArray; - const otherMatch = other ? FileNameMatch.exec(other) : [] as RegExpExecArray; - - const oneName = oneMatch[1] || ''; - const oneExtension = oneMatch[3] || ''; - - const otherName = otherMatch[1] || ''; - const otherExtension = otherMatch[3] || ''; + const [oneName, oneExtension] = extractNameAndExtension(one); + const [otherName, otherExtension] = extractNameAndExtension(other); let result = intlFileNameCollator.compare(oneExtension, otherExtension); @@ -92,14 +79,8 @@ export function compareFileExtensions(one: string, other: string): number { } function noIntlCompareFileExtensions(one: string, other: string): number { - const oneMatch = one ? FileNameMatch.exec(one.toLowerCase()) : [] as RegExpExecArray; - const otherMatch = other ? FileNameMatch.exec(other.toLowerCase()) : [] as RegExpExecArray; - - const oneName = oneMatch[1] || ''; - const oneExtension = oneMatch[3] || ''; - - const otherName = otherMatch[1] || ''; - const otherExtension = otherMatch[3] || ''; + const [oneName, oneExtension] = extractNameAndExtension(one, true); + const [otherName, otherExtension] = extractNameAndExtension(other, true); if (oneExtension !== otherExtension) { return oneExtension < otherExtension ? -1 : 1; @@ -112,6 +93,12 @@ function noIntlCompareFileExtensions(one: string, other: string): number { return oneName < otherName ? -1 : 1; } +function extractNameAndExtension(str?: string, lowercase?: boolean): [string, string] { + const match = str ? FileNameMatch.exec(lowercase ? str.toLowerCase() : str) : [] as RegExpExecArray; + + return [(match && match[1]) || '', (match && match[3]) || '']; +} + export function comparePaths(one: string, other: string): number { const oneParts = one.split(paths.nativeSep); const otherParts = other.split(paths.nativeSep); @@ -186,56 +173,4 @@ export function compareByPrefix(one: string, other: string, lookFor: string): nu } return 0; -} - -export interface IScorableResourceAccessor { - getLabel(t: T): string; - getResourcePath(t: T): string; -} - -export function compareByScore(elementA: T, elementB: T, accessor: IScorableResourceAccessor, lookFor: string, lookForNormalizedLower: string, scorerCache?: { [key: string]: number }): number { - const labelA = accessor.getLabel(elementA); - const labelB = accessor.getLabel(elementB); - - // treat prefix matches highest in any case - const prefixCompare = compareByPrefix(labelA, labelB, lookFor); - if (prefixCompare) { - return prefixCompare; - } - - // Give higher importance to label score - const labelAScore = scorer.score(labelA, lookFor, scorerCache); - const labelBScore = scorer.score(labelB, lookFor, scorerCache); - - if (labelAScore !== labelBScore) { - return labelAScore > labelBScore ? -1 : 1; - } - - // Score on full resource path comes next (if available) - let resourcePathA = accessor.getResourcePath(elementA); - let resourcePathB = accessor.getResourcePath(elementB); - if (resourcePathA && resourcePathB) { - const resourceAScore = scorer.score(resourcePathA, lookFor, scorerCache); - const resourceBScore = scorer.score(resourcePathB, lookFor, scorerCache); - - if (resourceAScore !== resourceBScore) { - return resourceAScore > resourceBScore ? -1 : 1; - } - } - - // At this place, the scores are identical so we check for string lengths and favor shorter ones - if (labelA.length !== labelB.length) { - return labelA.length < labelB.length ? -1 : 1; - } - - if (resourcePathA && resourcePathB && resourcePathA.length !== resourcePathB.length) { - return resourcePathA.length < resourcePathB.length ? -1 : 1; - } - - // Finally compare by label or resource path - if (labelA === labelB && resourcePathA && resourcePathB) { - return compareAnything(resourcePathA, resourcePathB, lookForNormalizedLower); - } - - return compareAnything(labelA, labelB, lookForNormalizedLower); -} +} \ No newline at end of file diff --git a/src/vs/base/common/decorators.ts b/src/vs/base/common/decorators.ts index 8b83c71bafa..8f7578c29fc 100644 --- a/src/vs/base/common/decorators.ts +++ b/src/vs/base/common/decorators.ts @@ -5,7 +5,7 @@ 'use strict'; -export function createDecorator(mapFn: (fn: Function) => Function): Function { +export function createDecorator(mapFn: (fn: Function, key: string) => Function): Function { return (target: any, key: string, descriptor: any) => { let fnKey: string = null; let fn: Function = null; @@ -22,7 +22,7 @@ export function createDecorator(mapFn: (fn: Function) => Function): Function { throw new Error('not supported'); } - descriptor[fnKey] = mapFn(fn); + descriptor[fnKey] = mapFn(fn, key); }; } @@ -56,4 +56,15 @@ export function memoize(target: any, key: string, descriptor: any) { return this[memoizeKey]; }; +} + +export function debounce(delay: number): Function { + return createDecorator((fn, key) => { + const timerKey = `$debounce$${key}`; + + return function (this: any, ...args: any[]) { + clearTimeout(this[timerKey]); + this[timerKey] = setTimeout(() => fn.apply(this, args), delay); + }; + }); } \ No newline at end of file diff --git a/src/vs/base/common/diff/diff2.ts b/src/vs/base/common/diff/diff2.ts index d0b99788b9f..3bb52c68b94 100644 --- a/src/vs/base/common/diff/diff2.ts +++ b/src/vs/base/common/diff/diff2.ts @@ -57,8 +57,6 @@ export class LcsDiff2 { private ids_for_x: number[]; private ids_for_y: number[]; - private hashFunc: IHashFunction; - private resultX: boolean[]; private resultY: boolean[]; private forwardPrev: number[]; @@ -72,14 +70,6 @@ export class LcsDiff2 { this.ids_for_x = []; this.ids_for_y = []; - if (hashFunc) { - this.hashFunc = hashFunc; - } else { - this.hashFunc = function (sequence, index) { - return sequence[index]; - }; - } - this.resultX = []; this.resultY = []; this.forwardPrev = []; diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index cd322eb4b29..87fd773a532 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, combinedDisposable, empty as EmptyDisposable } from 'vs/base/common/lifecycle'; import CallbackList from 'vs/base/common/callbackList'; import { EventEmitter } from 'vs/base/common/eventEmitter'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -82,7 +82,7 @@ export class Emitter { this._options.onFirstListenerAdd(this); } - this._callbacks.add(listener, thisArgs); + const remove = this._callbacks.add(listener, thisArgs); if (firstListener && this._options && this._options.onFirstListenerDidAdd) { this._options.onFirstListenerDidAdd(this); @@ -97,7 +97,7 @@ export class Emitter { dispose: () => { result.dispose = Emitter._noop; if (!this._disposed) { - this._callbacks.remove(listener, thisArgs); + remove(); if (this._options && this._options.onLastListenerRemove && this._callbacks.isEmpty()) { this._options.onLastListenerRemove(this); } @@ -304,7 +304,7 @@ export function once(event: Event): Event { }; } -export function any(...events: Event[]): Event { +export function anyEvent(...events: Event[]): Event { return (listener, thisArgs = null, disposables?) => combinedDisposable(events.map(event => event(e => listener.call(thisArgs, e), null, disposables))); } @@ -313,17 +313,17 @@ export function debounceEvent(event: Event, merger: (last: O, event: I) export function debounceEvent(event: Event, merger: (last: O, event: I) => O, delay: number = 100, leading = false): Event { let subscription: IDisposable; - let output: O; - let handle: number; + let output: O = undefined; + let handle: number = undefined; let numDebouncedCalls = 0; const emitter = new Emitter({ onFirstListenerAdd() { subscription = event(cur => { numDebouncedCalls++; - output = merger(output, cur); - if (!handle && leading) { + + if (leading && !handle) { emitter.fire(output); } @@ -331,11 +331,11 @@ export function debounceEvent(event: Event, merger: (last: O, event: I) handle = setTimeout(() => { let _output = output; output = undefined; + handle = undefined; if (!leading || numDebouncedCalls > 1) { emitter.fire(_output); } - handle = null; numDebouncedCalls = 0; }, delay); }); @@ -528,3 +528,35 @@ export function echo(event: Event, nextTick = false, buffer: T[] = []): Ev return emitter.event; } + +export class Relay implements IDisposable { + + private emitter = new Emitter(); + readonly output: Event = this.emitter.event; + + private disposable: IDisposable = EmptyDisposable; + + set input(event: Event) { + this.disposable.dispose(); + this.disposable = event(this.emitter.fire, this.emitter); + } + + dispose() { + this.disposable.dispose(); + this.emitter.dispose(); + } +} + +export interface NodeEventEmitter { + on(event: string | symbol, listener: Function): this; + removeListener(event: string | symbol, listener: Function): this; +} + +export function fromNodeEventEmitter(emitter: NodeEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event { + const fn = (...args: any[]) => result.fire(map(...args)); + const onFirstListenerAdd = () => emitter.on(eventName, fn); + const onLastListenerRemove = () => emitter.removeListener(eventName, fn); + const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove }); + + return result.event; +} diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 27609764bdb..64abb96b9ad 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -109,6 +109,7 @@ function _matchesSubString(word: string, wordToMatchAgainst: string, i: number, if (result = _matchesSubString(word, wordToMatchAgainst, i + 1, j + 1)) { return join({ start: j, end: j + 1 }, result); } + return null; } return _matchesSubString(word, wordToMatchAgainst, i, j + 1); @@ -121,7 +122,7 @@ function isLower(code: number): boolean { return CharCode.a <= code && code <= CharCode.z; } -function isUpper(code: number): boolean { +export function isUpper(code: number): boolean { return CharCode.A <= code && code <= CharCode.Z; } @@ -242,7 +243,13 @@ function isCamelCasePattern(word: string): boolean { } export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] { - if (!camelCaseWord || camelCaseWord.length === 0) { + if (!camelCaseWord) { + return null; + } + + camelCaseWord = camelCaseWord.trim(); + + if (camelCaseWord.length === 0) { return null; } diff --git a/src/vs/base/common/functional.ts b/src/vs/base/common/functional.ts index f4f84befbd1..a352dc9d7df 100644 --- a/src/vs/base/common/functional.ts +++ b/src/vs/base/common/functional.ts @@ -10,7 +10,7 @@ export function not(fn: Function): Function { return (...args) => !fn(...args); } -export function once(fn: T): T { +export function once(this: any, fn: T): T { const _this = this; let didCall = false; let result: any; diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index cc14eea9d51..4837cc12f55 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -16,6 +16,11 @@ export interface IExpression { [pattern: string]: boolean | SiblingClause | any; } +export interface IRelativePattern { + base: string; + pattern: string; +} + export function getEmptyExpression(): IExpression { return Object.create(null); } @@ -28,6 +33,8 @@ export interface SiblingClause { when: string; } +const GLOBSTAR = '**'; +const GLOB_SPLIT = '/'; const PATH_REGEX = '[/\\\\]'; // any slash or backslash const NO_PATH_REGEX = '[^/\\\\]'; // any non-slash and non-backslash const ALL_FORWARD_SLASHES = /\//g; @@ -103,10 +110,10 @@ function parseRegExp(pattern: string): string { let regEx = ''; // Split up into segments for each slash found - let segments = splitGlobAware(pattern, '/'); + let segments = splitGlobAware(pattern, GLOB_SPLIT); // Special case where we only have globstars - if (segments.every(s => s === '**')) { + if (segments.every(s => s === GLOBSTAR)) { regEx = '.*'; } @@ -116,7 +123,7 @@ function parseRegExp(pattern: string): string { segments.forEach((segment, index) => { // Globstar is special - if (segment === '**') { + if (segment === GLOBSTAR) { // if we have more than one globstar after another, just ignore it if (!previousSegmentWasGlobStar) { @@ -145,17 +152,28 @@ function parseRegExp(pattern: string): string { } // Support brackets - if (char !== ']' && inBrackets) { + if (inBrackets && (char !== ']' || !bracketVal) /* ] is literally only allowed as first character in brackets to match it */) { let res: string; - switch (char) { - case '-': // allow the range operator - res = char; - break; - case '^': // allow the negate operator - res = char; - break; - default: - res = strings.escapeRegExpCharacters(char); + + // range operator + if (char === '-') { + res = char; + } + + // negation operator (only valid on first index in bracket) + else if ((char === '^' || char === '!') && !bracketVal) { + res = '^'; + } + + // glob split matching is not allowed within character ranges + // see http://man7.org/linux/man-pages/man7/glob.7.html + else if (char === GLOB_SPLIT) { + res = ''; + } + + // anything else gets escaped + else { + res = strings.escapeRegExpCharacters(char); } bracketVal += res; @@ -207,7 +225,7 @@ function parseRegExp(pattern: string): string { } // Tail: Add the slash we had split on if there is more to come and the next one is not a globstar - if (index < segments.length - 1 && segments[index + 1] !== '**') { + if (index < segments.length - 1 && segments[index + 1] !== GLOBSTAR) { regEx += PATH_REGEX; } @@ -264,11 +282,19 @@ const NULL = function (): string { return null; }; -function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPattern { - if (!pattern) { +function parsePattern(arg1: string | IRelativePattern, options: IGlobOptions): ParsedStringPattern { + if (!arg1) { return NULL; } + // Handle IRelativePattern + let pattern: string; + if (typeof arg1 !== 'string') { + pattern = arg1.pattern; + } else { + pattern = arg1; + } + // Whitespace trimming pattern = pattern.trim(); @@ -276,7 +302,7 @@ function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPatte const patternKey = `${pattern}_${!!options.trimForExclusions}`; let parsedPattern = CACHE.get(patternKey); if (parsedPattern) { - return parsedPattern; + return wrapRelativePattern(parsedPattern, arg1); } // Check for Trivias @@ -304,7 +330,21 @@ function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPatte // Cache CACHE.set(patternKey, parsedPattern); - return parsedPattern; + return wrapRelativePattern(parsedPattern, arg1); +} + +function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | IRelativePattern): ParsedStringPattern { + if (typeof arg2 === 'string') { + return parsedPattern; + } + + return function (path, basename) { + if (!paths.isEqualOrParent(path, arg2.base)) { + return null; + } + + return parsedPattern(paths.relative(arg2.base, path), basename); + }; } function trimForExclusions(pattern: string, options: IGlobOptions): string { @@ -395,9 +435,9 @@ function toRegExp(pattern: string): ParsedStringPattern { * - simple brace expansion ({js,ts} => js or ts) * - character ranges (using [...]) */ -export function match(pattern: string, path: string): boolean; +export function match(pattern: string | IRelativePattern, path: string): boolean; export function match(expression: IExpression, path: string, siblingsFn?: () => string[]): string /* the matching pattern */; -export function match(arg1: string | IExpression, path: string, siblingsFn?: () => string[]): any { +export function match(arg1: string | IExpression | IRelativePattern, path: string, siblingsFn?: () => string[]): any { if (!arg1 || !path) { return false; } @@ -413,16 +453,16 @@ export function match(arg1: string | IExpression, path: string, siblingsFn?: () * - simple brace expansion ({js,ts} => js or ts) * - character ranges (using [...]) */ -export function parse(pattern: string, options?: IGlobOptions): ParsedPattern; +export function parse(pattern: string | IRelativePattern, options?: IGlobOptions): ParsedPattern; export function parse(expression: IExpression, options?: IGlobOptions): ParsedExpression; -export function parse(arg1: string | IExpression, options: IGlobOptions = {}): any { +export function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): any { if (!arg1) { return FALSE; } // Glob with String - if (typeof arg1 === 'string') { - const parsedPattern = parsePattern(arg1, options); + if (typeof arg1 === 'string' || isRelativePattern(arg1)) { + const parsedPattern = parsePattern(arg1 as string | IRelativePattern, options); if (parsedPattern === NULL) { return FALSE; } @@ -442,12 +482,18 @@ export function parse(arg1: string | IExpression, options: IGlobOptions = {}): a return parsedExpression(arg1, options); } +function isRelativePattern(obj: any): obj is IRelativePattern { + const rp = obj as IRelativePattern; + + return typeof rp.base === 'string' && typeof rp.pattern === 'string'; +} + /** * Same as `parse`, but the ParsedExpression is guaranteed to return a Promise */ export function parseToAsync(expression: IExpression, options?: IGlobOptions): ParsedExpression { const parsedExpression = parse(expression, options); - return (path: string, basename?: string, siblingsFn?: () => TPromise): TPromise => { + return (path: string, basename?: string, siblingsFn?: () => string[] | TPromise): string | TPromise => { const result = parsedExpression(path, basename, siblingsFn); return result instanceof TPromise ? result : TPromise.as(result); }; diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index ab7ae6065f1..b06fe9aaf58 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -6,7 +6,6 @@ 'use strict'; import { equals } from 'vs/base/common/arrays'; -import { marked } from 'vs/base/common/marked/marked'; export interface IMarkdownString { value: string; @@ -56,7 +55,7 @@ export function isEmptyMarkdownString(oneOrMany: IMarkdownString | IMarkdownStri export function isMarkdownString(thing: any): thing is IMarkdownString { if (thing instanceof MarkdownString) { return true; - } else if (typeof thing === 'object') { + } else if (thing && typeof thing === 'object') { return typeof (thing).value === 'string' && (typeof (thing).isTrusted === 'boolean' || (thing).isTrusted === void 0); } @@ -93,16 +92,3 @@ export function removeMarkdownEscapes(text: string): string { } return text.replace(/\\([\\`*_{}[\]()#+\-.!])/g, '$1'); } - -export function containsCommandLink(value: string): boolean { - let uses = false; - const renderer = new marked.Renderer(); - renderer.link = (href, title, text): string => { - if (href.match(/^command:/i)) { - uses = true; - } - return 'link'; - }; - marked(value, { renderer }); - return uses; -} diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index 0b19d5e56ae..f930237759c 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -5,11 +5,15 @@ 'use strict'; -export interface IIterator { +export interface IIterator { + next(): { done: boolean, value: E }; +} + +export interface INextIterator { next(): T; } -export class ArrayIterator implements IIterator { +export class ArrayIterator implements INextIterator { private items: T[]; protected start: number; @@ -73,16 +77,16 @@ export class ArrayNavigator extends ArrayIterator implements INavigator } -export class MappedIterator implements IIterator { +export class MappedIterator implements INextIterator { - constructor(protected iterator: IIterator, protected fn: (item: T) => R) { + constructor(protected iterator: INextIterator, protected fn: (item: T) => R) { // noop } next() { return this.fn(this.iterator.next()); } } -export interface INavigator extends IIterator { +export interface INavigator extends INextIterator { current(): T; previous(): T; parent(): T; diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index ee28dec9890..1727e9e752e 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -786,7 +786,7 @@ export function getLocation(text: string, position: number): Location { path: segments, previousNode, isAtPropertyKey, - matches: (pattern: string[]) => { + matches: (pattern: JSONPath) => { let k = 0; for (let i = 0; k < pattern.length && i < segments.length; i++) { if (pattern[k] === segments[i] || pattern[k] === '*') { diff --git a/src/vs/base/common/jsonSchema.ts b/src/vs/base/common/jsonSchema.ts index 1405eee19a5..538858e0c0d 100644 --- a/src/vs/base/common/jsonSchema.ts +++ b/src/vs/base/common/jsonSchema.ts @@ -6,6 +6,7 @@ export interface IJSONSchema { id?: string; + $id?: string; $schema?: string; type?: string | string[]; title?: string; @@ -17,19 +18,19 @@ export interface IJSONSchema { additionalProperties?: boolean | IJSONSchema; minProperties?: number; maxProperties?: number; - dependencies?: IJSONSchemaMap | string[]; + dependencies?: IJSONSchemaMap | { [prop: string]: string[] }; items?: IJSONSchema | IJSONSchema[]; minItems?: number; maxItems?: number; uniqueItems?: boolean; - additionalItems?: boolean; + additionalItems?: boolean | IJSONSchema; pattern?: string; minLength?: number; maxLength?: number; minimum?: number; maximum?: number; - exclusiveMinimum?: boolean; - exclusiveMaximum?: boolean; + exclusiveMinimum?: boolean | number; + exclusiveMaximum?: boolean | number; multipleOf?: number; required?: string[]; $ref?: string; @@ -40,11 +41,20 @@ export interface IJSONSchema { enum?: any[]; format?: string; + // schema draft 06 + const?: any; + contains?: IJSONSchema; + propertyNames?: IJSONSchema; + + // VSCode extensions defaultSnippets?: IJSONSchemaSnippet[]; // VSCode extension errorMessage?: string; // VSCode extension patternErrorMessage?: string; // VSCode extension deprecationMessage?: string; // VSCode extension enumDescriptions?: string[]; // VSCode extension + markdownEnumDescriptions?: string[]; // VSCode extension + markdownDescription?: string; // VSCode extension + doNotSuggest?: boolean; // VSCode extension } export interface IJSONSchemaMap { diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index 63b1c9697ab..a0316776036 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -17,10 +17,10 @@ export interface ILabelProvider { getLabel(element: any): string; } -export interface IRootProvider { - getRoot(resource: URI): URI; +export interface IWorkspaceFolderProvider { + getWorkspaceFolder(resource: URI): { uri: URI }; getWorkspace(): { - roots: URI[]; + folders: { uri: URI }[]; }; } @@ -28,7 +28,7 @@ export interface IUserHomeProvider { userHome: string; } -export function getPathLabel(resource: URI | string, rootProvider?: IRootProvider, userHomeProvider?: IUserHomeProvider): string { +export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFolderProvider, userHomeProvider?: IUserHomeProvider): string { if (!resource) { return null; } @@ -37,20 +37,24 @@ export function getPathLabel(resource: URI | string, rootProvider?: IRootProvide resource = URI.file(resource); } + if (resource.scheme !== 'file' && resource.scheme !== 'untitled') { + return resource.authority + resource.path; + } + // return early if we can resolve a relative path label from the root - const baseResource = rootProvider ? rootProvider.getRoot(resource) : null; + const baseResource = rootProvider ? rootProvider.getWorkspaceFolder(resource) : null; if (baseResource) { - const hasMultipleRoots = rootProvider.getWorkspace().roots.length > 1; + const hasMultipleRoots = rootProvider.getWorkspace().folders.length > 1; let pathLabel: string; - if (isEqual(baseResource.fsPath, resource.fsPath, !platform.isLinux /* ignorecase */)) { + if (isEqual(baseResource.uri.fsPath, resource.fsPath, !platform.isLinux /* ignorecase */)) { pathLabel = ''; // no label if pathes are identical } else { - pathLabel = normalize(ltrim(resource.fsPath.substr(baseResource.fsPath.length), nativeSep), true); + pathLabel = normalize(ltrim(resource.fsPath.substr(baseResource.uri.fsPath.length), nativeSep), true); } if (hasMultipleRoots) { - const rootName = basename(baseResource.fsPath); + const rootName = basename(baseResource.uri.fsPath); pathLabel = pathLabel ? join(rootName, pathLabel) : rootName; // always show root basename if there are multiple } @@ -58,8 +62,8 @@ export function getPathLabel(resource: URI | string, rootProvider?: IRootProvide } // convert c:\something => C:\something - if (platform.isWindows && resource.fsPath && resource.fsPath[1] === ':') { - return normalize(resource.fsPath.charAt(0).toUpperCase() + resource.fsPath.slice(1), true); + if (hasDriveLetter(resource.fsPath)) { + return normalize(normalizeDriveLetter(resource.fsPath), true); } // normalize and tildify (macOS, Linux only) @@ -71,6 +75,18 @@ export function getPathLabel(resource: URI | string, rootProvider?: IRootProvide return res; } +function hasDriveLetter(path: string): boolean { + return platform.isWindows && path && path[1] === ':'; +} + +export function normalizeDriveLetter(path: string): string { + if (hasDriveLetter(path)) { + return path.charAt(0).toUpperCase() + path.slice(1); + } + + return path; +} + 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)}`; diff --git a/src/vs/base/common/linkedList.ts b/src/vs/base/common/linkedList.ts new file mode 100644 index 00000000000..a6be2dc2ee1 --- /dev/null +++ b/src/vs/base/common/linkedList.ts @@ -0,0 +1,122 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IIterator } from 'vs/base/common/iterator'; + +class Node { + element: E; + next: Node; + prev: Node; + + constructor(element: E) { + this.element = element; + } +} + +export class LinkedList { + + private _first: Node; + private _last: Node; + + isEmpty(): boolean { + return !this._first; + } + + unshift(element: E) { + return this.insert(element, false); + } + + push(element: E) { + return this.insert(element, true); + } + + private insert(element: E, atTheEnd: boolean) { + const newNode = new Node(element); + if (!this._first) { + this._first = newNode; + this._last = newNode; + + } else if (atTheEnd) { + // push + const oldLast = this._last; + this._last = newNode; + newNode.prev = oldLast; + oldLast.next = newNode; + + } else { + // unshift + const oldFirst = this._first; + this._first = newNode; + newNode.next = oldFirst; + oldFirst.prev = newNode; + } + + return () => { + + for (let candidate = this._first; candidate instanceof Node; candidate = candidate.next) { + if (candidate !== newNode) { + continue; + } + if (candidate.prev && candidate.next) { + // middle + let anchor = candidate.prev; + anchor.next = candidate.next; + candidate.next.prev = anchor; + + } else if (!candidate.prev && !candidate.next) { + // only node + this._first = undefined; + this._last = undefined; + + } else if (!candidate.next) { + // last + this._last = this._last.prev; + this._last.next = undefined; + + } else if (!candidate.prev) { + // first + this._first = this._first.next; + this._first.prev = undefined; + } + + // done + break; + } + }; + } + + iterator(): IIterator { + let _done: boolean; + let _value: E; + let element = { + get done() { return _done; }, + get value() { return _value; } + }; + let node = this._first; + return { + next(): { done: boolean; value: E } { + if (!node) { + _done = true; + _value = undefined; + } else { + _done = false; + _value = node.element; + node = node.next; + } + return element; + } + }; + } + + toArray(): E[] { + let result: E[] = []; + for (let node = this._first; node instanceof Node; node = node.next) { + result.push(node.element); + } + return result; + } +} diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 003e893e7f8..1809b01cdf2 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -220,110 +220,335 @@ export class BoundedMap { } } -// --- trie'ish datastructure +export interface IKeyIterator { + reset(key: string): this; + next(): this; + join(parts: string[]): string; -class Node { - element?: E; - readonly children = new Map>(); + hasNext(): boolean; + cmp(a: string): number; + value(): string; } -/** - * A trie map that allows for fast look up when keys are substrings - * to the actual search keys (dir/subdir-problem). - */ -export class TrieMap { +export class StringIterator implements IKeyIterator { - static PathSplitter = (s: string) => s.split(/[\\/]/).filter(s => !!s); + private _value: string = ''; + private _pos: number = 0; - private readonly _splitter: (s: string) => string[]; - private _root = new Node(); - - constructor(splitter: (s: string) => string[] = TrieMap.PathSplitter) { - this._splitter = s => splitter(s).filter(s => Boolean(s)); + reset(key: string): this { + this._value = key; + this._pos = 0; + return this; } - insert(path: string, element: E): void { - const parts = this._splitter(path); - let i = 0; + next(): this { + this._pos += 1; + return this; + } - // find insertion node - let node = this._root; - for (; i < parts.length; i++) { - let child = node.children.get(parts[i]); - if (child) { - node = child; - continue; + join(parts: string[]): string { + return parts.join(''); + } + + hasNext(): boolean { + return this._pos < this._value.length - 1; + } + + cmp(a: string): number { + let aCode = a.charCodeAt(0); + let thisCode = this._value.charCodeAt(this._pos); + return aCode - thisCode; + } + + value(): string { + return this._value[this._pos]; + } +} + +export class PathIterator implements IKeyIterator { + + private static _fwd = '/'.charCodeAt(0); + private static _bwd = '\\'.charCodeAt(0); + + private _value: string; + private _from: number; + private _to: number; + + reset(key: string): this { + this._value = key.replace(/\\$|\/$/, ''); + this._from = 0; + this._to = 0; + return this.next(); + } + + hasNext(): boolean { + return this._to < this._value.length; + } + + join(parts: string[]): string { + return parts.join('/'); + } + + next(): this { + // this._data = key.split(/[\\/]/).filter(s => !!s); + this._from = this._to; + let justSeps = true; + for (; this._to < this._value.length; this._to++) { + const ch = this._value.charCodeAt(this._to); + if (ch === PathIterator._fwd || ch === PathIterator._bwd) { + if (justSeps) { + this._from++; + } else { + break; + } + } else { + justSeps = false; } - break; + } + return this; + } + + cmp(a: string): number { + + let aPos = 0; + let aLen = a.length; + let thisPos = this._from; + + while (aPos < aLen && thisPos < this._to) { + let cmp = a.charCodeAt(aPos) - this._value.charCodeAt(thisPos); + if (cmp !== 0) { + return cmp; + } + aPos += 1; + thisPos += 1; } - // create new nodes - let newNode: Node; - for (; i < parts.length; i++) { - newNode = new Node(); - node.children.set(parts[i], newNode); - node = newNode; + if (aLen === this._to - this._from) { + return 0; + } else if (aPos < aLen) { + return -1; + } else { + return 1; + } + } + + value(): string { + return this._value.substring(this._from, this._to); + } +} + +class TernarySearchTreeNode { + str: string; + element: E; + left: TernarySearchTreeNode; + mid: TernarySearchTreeNode; + right: TernarySearchTreeNode; + + isEmpty(): boolean { + return !this.left && !this.mid && !this.right && !this.element; + } +} + +export class TernarySearchTree { + + static forPaths(): TernarySearchTree { + return new TernarySearchTree(new PathIterator()); + } + + static forStrings(): TernarySearchTree { + return new TernarySearchTree(new StringIterator()); + } + + private _iter: IKeyIterator; + private _root: TernarySearchTreeNode; + + constructor(segments: IKeyIterator) { + this._iter = segments; + } + + clear(): void { + this._root = undefined; + } + + set(key: string, element: E): void { + let iter = this._iter.reset(key); + let node: TernarySearchTreeNode; + + if (!this._root) { + this._root = new TernarySearchTreeNode(); + this._root.str = iter.value(); } + node = this._root; + while (true) { + let val = iter.cmp(node.str); + if (val > 0) { + // left + if (!node.left) { + node.left = new TernarySearchTreeNode(); + node.left.str = iter.value(); + } + node = node.left; + + } else if (val < 0) { + // right + if (!node.right) { + node.right = new TernarySearchTreeNode(); + node.right.str = iter.value(); + } + node = node.right; + + } else if (iter.hasNext()) { + // mid + iter.next(); + if (!node.mid) { + node.mid = new TernarySearchTreeNode(); + node.mid.str = iter.value(); + } + node = node.mid; + } else { + break; + } + } node.element = element; } - lookUp(path: string): E { - const parts = this._splitter(path); - - let { children } = this._root; - let node: Node; - for (const part of parts) { - node = children.get(part); - if (!node) { - return undefined; - } - children = node.children; - } - - return node.element; - } - - findSubstr(path: string): E { - const parts = this._splitter(path); - - let lastNode: Node; - let { children } = this._root; - for (const part of parts) { - const node = children.get(part); - if (!node) { + get(key: string): E { + let iter = this._iter.reset(key); + let node = this._root; + while (node) { + let val = iter.cmp(node.str); + if (val > 0) { + // left + node = node.left; + } else if (val < 0) { + // right + node = node.right; + } else if (iter.hasNext()) { + // mid + iter.next(); + node = node.mid; + } else { break; } - if (node.element) { - lastNode = node; - } - children = node.children; } + return node ? node.element : undefined; + } - // return the last matching node - // that had an element - if (lastNode) { - return lastNode.element; + delete(key: string): void { + + let iter = this._iter.reset(key); + let stack: [-1 | 0 | 1, TernarySearchTreeNode][] = []; + let node = this._root; + + // find and unset node + while (node) { + let val = iter.cmp(node.str); + if (val > 0) { + // left + stack.push([1, node]); + node = node.left; + } else if (val < 0) { + // right + stack.push([-1, node]); + node = node.right; + } else if (iter.hasNext()) { + // mid + iter.next(); + stack.push([0, node]); + node = node.mid; + } else { + // remove element + node.element = undefined; + + // clean up empty nodes + while (stack.length > 0 && node.isEmpty()) { + let [dir, parent] = stack.pop(); + switch (dir) { + case 1: parent.left = undefined; break; + case 0: parent.mid = undefined; break; + case -1: parent.right = undefined; break; + } + node = parent; + } + break; + } + } + } + + findSubstr(key: string): E { + let iter = this._iter.reset(key); + let node = this._root; + let candidate: E; + while (node) { + let val = iter.cmp(node.str); + if (val > 0) { + // left + node = node.left; + } else if (val < 0) { + // right + node = node.right; + } else if (iter.hasNext()) { + // mid + iter.next(); + candidate = node.element || candidate; + node = node.mid; + } else { + break; + } + } + return node && node.element || candidate; + } + + findSuperstr(key: string): TernarySearchTree { + let iter = this._iter.reset(key); + let node = this._root; + while (node) { + let val = iter.cmp(node.str); + if (val > 0) { + // left + node = node.left; + } else if (val < 0) { + // right + node = node.right; + } else if (iter.hasNext()) { + // mid + iter.next(); + node = node.mid; + } else { + // collect + if (!node.mid) { + return undefined; + } + let ret = new TernarySearchTree(this._iter); + ret._root = node.mid; + return ret; + } } return undefined; } - findSuperstr(path: string): TrieMap { - const parts = this._splitter(path); + forEach(callback: (value: E, index: string) => any) { + this._forEach(this._root, [], callback); + } - let { children } = this._root; - let node: Node; - for (const part of parts) { - node = children.get(part); - if (!node) { - return undefined; + private _forEach(node: TernarySearchTreeNode, parts: string[], callback: (value: E, index: string) => any) { + if (node) { + // left + this._forEach(node.left, parts, callback); + + // node + parts.push(node.str); + if (node.element) { + callback(node.element, this._iter.join(parts)); } - children = node.children; - } + // mid + this._forEach(node.mid, parts, callback); + parts.pop(); - const result = new TrieMap(this._splitter); - result._root = node; - return result; + // right + this._forEach(node.right, parts, callback); + } } } diff --git a/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts index 6868a298966..ff9872c075d 100644 --- a/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -37,7 +37,7 @@ let userRegisteredAssociations: ITextMimeAssociationItem[] = []; /** * Associate a text mime to the registry. */ -export function registerTextMime(association: ITextMimeAssociation): void { +export function registerTextMime(association: ITextMimeAssociation, warnOnOverwrite = false): void { // Register const associationItem = toTextMimeAssociationItem(association); @@ -49,7 +49,7 @@ export function registerTextMime(association: ITextMimeAssociation): void { } // Check for conflicts unless this is a user configured association - if (!associationItem.userConfigured) { + if (warnOnOverwrite && !associationItem.userConfigured) { registeredAssociations.forEach(a => { if (a.mime === associationItem.mime || a.userConfigured) { return; // same mime or userConfigured is ok diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 93de044478a..c88cdaf8bec 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -38,5 +38,7 @@ export namespace Schemas { export const file: string = 'file'; + export const mailto: string = 'mailto'; + export const untitled: string = 'untitled'; } diff --git a/src/vs/base/common/numbers.ts b/src/vs/base/common/numbers.ts index 65bcbbd7922..f23b941b7fe 100644 --- a/src/vs/base/common/numbers.ts +++ b/src/vs/base/common/numbers.ts @@ -46,3 +46,12 @@ export function countToArray(fromOrTo: number, to?: number): number[] { return result; } + + +export function clamp(value: number, min: number, max: number): number { + return Math.min(Math.max(value, min), max); +} + +export function rot(index: number, modulo: number): number { + return (modulo + (index % modulo)) % modulo; +} \ No newline at end of file diff --git a/src/vs/base/common/objects.ts b/src/vs/base/common/objects.ts index e2be7bda662..308c65519a6 100644 --- a/src/vs/base/common/objects.ts +++ b/src/vs/base/common/objects.ts @@ -15,8 +15,8 @@ export function clone(obj: T): T { // See https://github.com/Microsoft/TypeScript/issues/10990 return obj as any; } - const result = (Array.isArray(obj)) ? [] : {}; - Object.keys(obj).forEach(key => { + const result: any = Array.isArray(obj) ? [] : {}; + Object.keys(obj).forEach((key: keyof T) => { if (obj[key] && typeof obj[key] === 'object') { result[key] = clone(obj[key]); } else { @@ -30,8 +30,8 @@ export function deepClone(obj: T): T { if (!obj || typeof obj !== 'object') { return obj; } - const result = (Array.isArray(obj)) ? [] : {}; - Object.getOwnPropertyNames(obj).forEach(key => { + const result: any = Array.isArray(obj) ? [] : {}; + Object.getOwnPropertyNames(obj).forEach((key: keyof T) => { if (obj[key] && typeof obj[key] === 'object') { result[key] = deepClone(obj[key]); } else { @@ -73,7 +73,7 @@ function _cloneAndChange(obj: any, changer: (orig: any) => any, encounteredObjec const r2 = {}; for (let i2 in obj) { if (hasOwnProperty.call(obj, i2)) { - r2[i2] = _cloneAndChange(obj[i2], changer, encounteredObjects); + (r2 as any)[i2] = _cloneAndChange(obj[i2], changer, encounteredObjects); } } encounteredObjects.pop(); @@ -231,7 +231,7 @@ export function derive(baseClass: any, derivedClass: any): void { } // Cast to any due to Bug 16188:PropertyDescriptor set and get function should be optional. - Object.defineProperty(derivedClass.prototype, 'constructor', { value: derivedClass, writable: true, configurable: true, enumerable: true }); + Object.defineProperty(derivedClass.prototype, 'constructor', { value: derivedClass, writable: true, configurable: true, enumerable: true }); } /** diff --git a/src/vs/base/common/paging.ts b/src/vs/base/common/paging.ts index de3319b5038..286fa69d08f 100644 --- a/src/vs/base/common/paging.ts +++ b/src/vs/base/common/paging.ts @@ -51,7 +51,7 @@ export class PagedModel implements IPagedModel { get length(): number { return this.pager.total; } - constructor(private arg: IPager | T[], private pageTimeout: number = 500) { + constructor(arg: IPager | T[], private pageTimeout: number = 500) { this.pager = isArray(arg) ? singlePagePager(arg) : arg; this.pages = [{ isResolved: true, promise: null, promiseIndexes: new Set(), elements: this.pager.firstPage.slice() }]; diff --git a/src/vs/base/common/parsers.ts b/src/vs/base/common/parsers.ts index 0aa919598e2..48938d10a4e 100644 --- a/src/vs/base/common/parsers.ts +++ b/src/vs/base/common/parsers.ts @@ -50,10 +50,10 @@ export interface IProblemReporter { } export class NullProblemReporter implements IProblemReporter { - info(message: string): void { }; - warn(message: string): void { }; - error(message: string): void { }; - fatal(message: string): void { }; + info(message: string): void { } + warn(message: string): void { } + error(message: string): void { } + fatal(message: string): void { } status: ValidationStatus = new ValidationStatus(); } @@ -112,7 +112,7 @@ export abstract class Parser { } protected static merge(destination: T, source: T, overwrite: boolean): void { - Object.keys(source).forEach((key) => { + Object.keys(source).forEach((key: keyof T) => { let destValue = destination[key]; let sourceValue = source[key]; if (Types.isUndefined(sourceValue)) { @@ -163,7 +163,7 @@ export abstract class AbstractSystemVariables implements ISystemVariables { } resolveAny(value: T): T; - resolveAny(value: any): any { + resolveAny(value: any): any { if (Types.isString(value)) { return this.resolveString(value); } else if (Types.isArray(value)) { @@ -197,7 +197,7 @@ export abstract class AbstractSystemVariables implements ISystemVariables { } private __resolveAnyLiteral(values: T): T; - private __resolveAnyLiteral(values: any): any { + private __resolveAnyLiteral(values: any): any { let result: IStringDictionary | string[]> = Object.create(null); Object.keys(values).forEach(key => { let value = values[key]; diff --git a/src/vs/base/common/performance.d.ts b/src/vs/base/common/performance.d.ts new file mode 100644 index 00000000000..efa32f3dd10 --- /dev/null +++ b/src/vs/base/common/performance.d.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export interface PerformanceEntry { + readonly type: 'mark' | 'measure'; + readonly name: string; + readonly startTime: number; + readonly duration: number; +} + +export function mark(name: string): void; +export function measure(name: string, from?: string, to?: string): void; + +/** + * Time something, shorthant for `mark` and `measure` + */ +export function time(name: string): { stop(): void }; + +/** + * All entries filtered by type and sorted by `startTime`. + */ +export function getEntries(type?: 'mark' | 'measure'): PerformanceEntry[]; + +/** + * Import entries + */ +export function importEntries(entries: PerformanceEntry[]): void; diff --git a/src/vs/base/common/performance.js b/src/vs/base/common/performance.js new file mode 100644 index 00000000000..578f8a79dee --- /dev/null +++ b/src/vs/base/common/performance.js @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +/*global define*/ + +// This module can be loaded in an amd and commonjs-context. +// Because we want both instances to use the same perf-data +// we store them globally +global._performanceEntries = global._performanceEntries || []; + +if (typeof define !== "function" && typeof module === "object" && typeof module.exports === "object") { + // this is commonjs, fake amd + global.define = function (dep, callback) { + module.exports = callback(); + global.define = undefined; + }; +} + +define([], function () { + + // const _now = global.performance && performance.now ? performance.now : Date.now + const _now = Date.now; + + class PerformanceEntry { + constructor(type, name, startTime, duration) { + this.type = type; + this.name = name; + this.startTime = startTime; + this.duration = duration; + } + } + + function _getEntry(type, name) { + for (let i = global._performanceEntries.length - 1; i >= 0; i--) { + if ( + (type === undefined || global._performanceEntries[i].type === type) && + (name === undefined || global._performanceEntries[i].name === name) + ) { + return global._performanceEntries[i]; + } + } + } + + function importEntries(entries) { + global._performanceEntries.splice(0, 0, ...entries); + } + + function getEntries(type, name) { + return global._performanceEntries.filter(entry => { + return (type === undefined || entry.type === type) && + (name === undefined || entry.name === name); + }).sort((a, b) => { + return a.startTime - b.startTime; + }); + } + + function mark(name) { + const entry = new PerformanceEntry('mark', name, _now(), 0); + global._performanceEntries.push(entry); + if (typeof console.timeStamp === 'function') { + console.timeStamp(name); + } + } + + function time(name) { + let from = `${name}/start`; + mark(from); + return { stop() { measure(name, from); } }; + } + + function measure(name, from, to) { + + let startTime; + let duration; + let now = _now(); + + if (!from) { + startTime = now; + } else { + startTime = _getEntry(undefined, from).startTime; + } + + if (!to) { + duration = now - startTime; + } else { + duration = _getEntry(undefined, to).startTime - startTime; + } + + const entry = new PerformanceEntry('measure', name, startTime, duration); + global._performanceEntries.push(entry); + } + + var exports = { + mark: mark, + measure: measure, + time: time, + getEntries: getEntries, + importEntries: importEntries + }; + + return exports; +}); diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts new file mode 100644 index 00000000000..4b883338383 --- /dev/null +++ b/src/vs/base/common/resources.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as paths from 'vs/base/common/paths'; +import uri from 'vs/base/common/uri'; +import { equalsIgnoreCase } from 'vs/base/common/strings'; + +export function basenameOrAuthority(resource: uri): string { + return paths.basename(resource.fsPath) || resource.authority; +} + +export function isEqualOrParent(first: uri, second: uri, ignoreCase?: boolean): boolean { + if (first.scheme === second.scheme && first.authority === second.authority) { + return paths.isEqualOrParent(first.fsPath, second.fsPath, ignoreCase); + } + + return false; +} + +export function isEqual(first: uri, second: uri, ignoreCase?: boolean): boolean { + const identityEquals = (first === second); + if (identityEquals) { + return true; + } + + if (!first || !second) { + return false; + } + + if (ignoreCase) { + return equalsIgnoreCase(first.toString(), second.toString()); + } + + return first.toString() === second.toString(); +} + +export function dirname(resource: uri): uri { + return resource.with({ + path: paths.dirname(resource.path) + }); +} diff --git a/src/vs/base/common/scorer.ts b/src/vs/base/common/scorer.ts deleted file mode 100644 index 79e879b8d25..00000000000 --- a/src/vs/base/common/scorer.ts +++ /dev/null @@ -1,134 +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'; - -// Based on material from: -/*! -BEGIN THIRD PARTY -*/ -/*! -* string_score.js: String Scoring Algorithm 0.1.22 -* -* http://joshaven.com/string_score -* https://github.com/joshaven/string_score -* -* Copyright (C) 2009-2014 Joshaven Potter -* Special thanks to all of the contributors listed here https://github.com/joshaven/string_score -* MIT License: http://opensource.org/licenses/MIT -* -* Date: Tue Mar 1 2011 -* Updated: Tue Mar 10 2015 -*/ - -/** - * Compute a score for the given string and the given query. - * - * Rules: - * Character score: 1 - * Same case bonus: 1 - * Upper case bonus: 1 - * Consecutive match bonus: 5 - * Start of word/path bonus: 7 - * Start of string bonus: 8 - */ -const wordPathBoundary = ['-', '_', ' ', '/', '\\', '.']; -export function score(target: string, query: string, cache?: { [id: string]: number }): number { - if (!target || !query) { - return 0; // return early if target or query are undefined - } - - const hash = target + query; - const cached = cache && cache[hash]; - if (typeof cached === 'number') { - return cached; - } - - const queryLen = query.length; - const targetLower = target.toLowerCase(); - const queryLower = query.toLowerCase(); - - let index = 0; - let startAt = 0; - let score = 0; - while (index < queryLen) { - let indexOf = targetLower.indexOf(queryLower[index], startAt); - if (indexOf < 0) { - score = 0; // This makes sure that the query is contained in the target - break; - } - - // Character match bonus - score += 1; - - // Consecutive match bonus - if (startAt === indexOf) { - score += 5; - } - - // Same case bonus - if (target[indexOf] === query[indexOf]) { - score += 1; - } - - // Start of word bonus - if (indexOf === 0) { - score += 8; - } - - // After separator bonus - else if (wordPathBoundary.some(w => w === target[indexOf - 1])) { - score += 7; - } - - // Inside word upper case bonus - else if (isUpper(target.charCodeAt(indexOf))) { - score += 1; - } - - startAt = indexOf + 1; - index++; - } - - if (cache) { - cache[hash] = score; - } - - return score; -} - -function isUpper(code: number): boolean { - return 65 <= code && code <= 90; -} - -/** - * A fast method to check if a given string would produce a score > 0 for the given query. - */ -export function matches(target: string, queryLower: string): boolean { - if (!target || !queryLower) { - return false; // return early if target or query are undefined - } - - const queryLen = queryLower.length; - const targetLower = target.toLowerCase(); - - let index = 0; - let lastIndexOf = -1; - while (index < queryLen) { - let indexOf = targetLower.indexOf(queryLower[index], lastIndexOf + 1); - if (indexOf < 0) { - return false; - } - - lastIndexOf = indexOf; - - index++; - } - - return true; -} -/*! -END THIRD PARTY -*/ \ No newline at end of file diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 7af18aadcb6..babe28e9273 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -221,7 +221,7 @@ export function createRegExp(searchString: string, isRegex: boolean, options: Re export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean { // Exit early if it's one of these special cases which are meant to match // against an empty string - if (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$') { + if (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$' || regexp.source === '^\\s*$') { return false; } @@ -231,6 +231,10 @@ export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean { return (match && regexp.lastIndex === 0); } +export function regExpContainsBackreference(regexpValue: string): boolean { + return !!regexpValue.match(/([^\\]|^)(\\\\)*\\\d+/); +} + /** * The normalize() method returns the Unicode Normalization Form of a given string. The form will be * the Normalization Form Canonical Composition. @@ -238,9 +242,19 @@ export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean { * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize} */ export const canNormalize = typeof (('').normalize) === 'function'; -const nonAsciiCharactersPattern = /[^\u0000-\u0080]/; -const normalizedCache = new BoundedMap(10000); // bounded to 10000 elements + +const nfcCache = new BoundedMap(10000); // bounded to 10000 elements export function normalizeNFC(str: string): string { + return normalize(str, 'NFC', nfcCache); +} + +const nfdCache = new BoundedMap(10000); // bounded to 10000 elements +export function normalizeNFD(str: string): string { + return normalize(str, 'NFD', nfdCache); +} + +const nonAsciiCharactersPattern = /[^\u0000-\u0080]/; +function normalize(str: string, form: string, normalizedCache: BoundedMap): string { if (!canNormalize || !str) { return str; } @@ -252,7 +266,7 @@ export function normalizeNFC(str: string): string { let res: string; if (nonAsciiCharactersPattern.test(str)) { - res = (str).normalize('NFC'); + res = (str).normalize(form); } else { res = str; } @@ -705,6 +719,10 @@ export function startsWithUTF8BOM(str: string): boolean { return (str && str.length > 0 && str.charCodeAt(0) === CharCode.UTF8_BOM); } +export function stripUTF8BOM(str: string): string { + return startsWithUTF8BOM(str) ? str.substr(1) : str; +} + /** * Appends two strings. If the appended result is longer than maxLength, * trims the start of the result and replaces it with '...'. @@ -735,3 +753,35 @@ export function repeat(s: string, count: number): string { } return result; } + +/** + * Checks if the characters of the provided query string are included in the + * target string. The characters do not have to be contiguous within the string. + */ +export function fuzzyContains(target: string, query: string): boolean { + if (!target || !query) { + return false; // return early if target or query are undefined + } + + if (target.length < query.length) { + return false; // impossible for query to be contained in target + } + + const queryLen = query.length; + const targetLower = target.toLowerCase(); + + let index = 0; + let lastIndexOf = -1; + while (index < queryLen) { + let indexOf = targetLower.indexOf(query[index], lastIndexOf + 1); + if (indexOf < 0) { + return false; + } + + lastIndexOf = indexOf; + + index++; + } + + return true; +} \ No newline at end of file diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 043e9be8be9..d99a0e403db 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -21,6 +21,42 @@ function encodeNoop(str: string): string { } +const _schemePattern = /^\w[\w\d+.-]*$/; +const _singleSlashStart = /^\//; +const _doubleSlashStart = /^\/\//; + +function _validateUri(ret: URI): void { + // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 + // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + if (ret.scheme && !_schemePattern.test(ret.scheme)) { + throw new Error('[UriError]: Scheme contains illegal characters.'); + } + + // path, http://tools.ietf.org/html/rfc3986#section-3.3 + // If a URI contains an authority component, then the path component + // must either be empty or begin with a slash ("/") character. If a URI + // does not contain an authority component, then the path cannot begin + // with two slash characters ("//"). + if (ret.path) { + if (ret.authority) { + if (!_singleSlashStart.test(ret.path)) { + throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); + } + } else { + if (_doubleSlashStart.test(ret.path)) { + throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); + } + } + } +} + +const _empty = ''; +const _slash = '/'; +const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; +const _driveLetterPath = /^\/[a-zA-Z]:/; +const _upperCaseDrive = /^(\/)?([A-Z]:)/; +const _driveLetter = /^[a-zA-Z]:/; + /** * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. * This class is a simple parser which creates the basic component paths @@ -37,7 +73,7 @@ function encodeNoop(str: string): string { * * */ -export default class URI { +export default class URI implements UriComponents { static isUri(thing: any): thing is URI { if (thing instanceof URI) { @@ -53,12 +89,6 @@ export default class URI { && typeof (thing).scheme === 'string'; } - private static _empty = ''; - private static _slash = '/'; - private static _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; - private static _driveLetterPath = /^\/[a-zA-Z]:/; - private static _upperCaseDrive = /^(\/)?([A-Z]:)/; - /** * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'. * The part before the first colon. @@ -86,21 +116,38 @@ export default class URI { */ readonly fragment: string; - private _formatted: string = null; - private _fsPath: string = null; + /** + * @internal + */ + protected constructor(scheme: string, authority: string, path: string, query: string, fragment: string); /** * @internal */ - private constructor(scheme: string, authority: string, path: string, query: string, fragment: string) { + protected constructor(components: UriComponents); - this.scheme = scheme || URI._empty; - this.authority = authority || URI._empty; - this.path = path || URI._empty; - this.query = query || URI._empty; - this.fragment = fragment || URI._empty; + /** + * @internal + */ + protected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string) { - this._validate(this); + if (typeof schemeOrData === 'object') { + this.scheme = schemeOrData.scheme || _empty; + this.authority = schemeOrData.authority || _empty; + this.path = schemeOrData.path || _empty; + this.query = schemeOrData.query || _empty; + this.fragment = schemeOrData.fragment || _empty; + // no validation because it's this URI + // that creates uri components. + // _validateUri(this); + } else { + this.scheme = schemeOrData || _empty; + this.authority = authority || _empty; + this.path = path || _empty; + this.query = query || _empty; + this.fragment = fragment || _empty; + _validateUri(this); + } } // ---- filesystem path ----------------------- @@ -112,24 +159,7 @@ export default class URI { * invalid characters and semantics. Will *not* look at the scheme of this URI. */ get fsPath(): string { - if (!this._fsPath) { - let value: string; - if (this.authority && this.path && this.scheme === 'file') { - // unc path: file://shares/c$/far/boo - value = `//${this.authority}${this.path}`; - } else if (URI._driveLetterPath.test(this.path)) { - // windows drive letter: file:///c:/far/boo - value = this.path[1].toLowerCase() + this.path.substr(2); - } else { - // other path - value = this.path; - } - if (platform.isWindows) { - value = value.replace(/\//g, '\\'); - } - this._fsPath = value; - } - return this._fsPath; + return _makeFsPath(this); } // ---- modify to new ------------------------- @@ -176,60 +206,66 @@ export default class URI { return this; } - return new URI(scheme, authority, path, query, fragment); + return new _URI(scheme, authority, path, query, fragment); } // ---- parse & validate ------------------------ public static parse(value: string): URI { - const match = URI._regexp.exec(value); + const match = _regexp.exec(value); if (!match) { - return new URI(URI._empty, URI._empty, URI._empty, URI._empty, URI._empty); + return new _URI(_empty, _empty, _empty, _empty, _empty); } - return new URI( - match[2] || URI._empty, - decodeURIComponent(match[4] || URI._empty), - decodeURIComponent(match[5] || URI._empty), - decodeURIComponent(match[7] || URI._empty), - decodeURIComponent(match[9] || URI._empty), + return new _URI( + match[2] || _empty, + decodeURIComponent(match[4] || _empty), + decodeURIComponent(match[5] || _empty), + decodeURIComponent(match[7] || _empty), + decodeURIComponent(match[9] || _empty), ); } public static file(path: string): URI { - let authority = URI._empty; + let authority = _empty; // normalize to fwd-slashes on windows, // on other systems bwd-slashes are valid // filename character, eg /f\oo/ba\r.txt if (platform.isWindows) { - path = path.replace(/\\/g, URI._slash); + path = path.replace(/\\/g, _slash); } // check for authority as used in UNC shares // or use the path as given - if (path[0] === URI._slash && path[0] === path[1]) { - let idx = path.indexOf(URI._slash, 2); + if (path[0] === _slash && path[1] === _slash) { + let idx = path.indexOf(_slash, 2); if (idx === -1) { authority = path.substring(2); - path = URI._empty; + path = _slash; } else { authority = path.substring(2, idx); - path = path.substring(idx); + path = path.substring(idx) || _slash; } } // Ensure that path starts with a slash // or that it is at least a slash - if (path[0] !== URI._slash) { - path = URI._slash + path; + if (_driveLetter.test(path)) { + path = _slash + path; + + } else if (path[0] !== _slash) { + // tricky -> makes invalid paths + // but otherwise we have to stop + // allowing relative paths... + path = _slash + path; } - return new URI('file', authority, path, URI._empty, URI._empty); + return new _URI('file', authority, path, _empty, _empty); } public static from(components: { scheme?: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { - return new URI( + return new _URI( components.scheme, components.authority, components.path, @@ -238,35 +274,6 @@ export default class URI { ); } - private static _schemePattern = /^\w[\w\d+.-]*$/; - private static _singleSlashStart = /^\//; - private static _doubleSlashStart = /^\/\//; - - private _validate(ret: URI): void { - // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 - // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - if (ret.scheme && !URI._schemePattern.test(ret.scheme)) { - throw new Error('[UriError]: Scheme contains illegal characters.'); - } - - // path, http://tools.ietf.org/html/rfc3986#section-3.3 - // If a URI contains an authority component, then the path component - // must either be empty or begin with a slash ("/") character. If a URI - // does not contain an authority component, then the path cannot begin - // with two slash characters ("//"). - if (ret.path) { - if (ret.authority) { - if (!URI._singleSlashStart.test(ret.path)) { - throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); - } - } else { - if (URI._doubleSlashStart.test(ret.path)) { - throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); - } - } - } - } - // ---- printing/externalize --------------------------- /** @@ -274,82 +281,14 @@ export default class URI { * @param skipEncoding Do not encode the result, default is `false` */ public toString(skipEncoding: boolean = false): string { - if (!skipEncoding) { - if (!this._formatted) { - this._formatted = URI._asFormatted(this, false); - } - return this._formatted; - } else { - // we don't cache that - return URI._asFormatted(this, true); - } + return _asFormatted(this, skipEncoding); } - private static _asFormatted(uri: URI, skipEncoding: boolean): string { - - const encoder = !skipEncoding - ? encodeURIComponent2 - : encodeNoop; - - const parts: string[] = []; - - let { scheme, authority, path, query, fragment } = uri; - if (scheme) { - parts.push(scheme, ':'); - } - if (authority || scheme === 'file') { - parts.push('//'); - } - if (authority) { - authority = authority.toLowerCase(); - let idx = authority.indexOf(':'); - if (idx === -1) { - parts.push(encoder(authority)); - } else { - parts.push(encoder(authority.substr(0, idx)), authority.substr(idx)); - } - } - if (path) { - // lower-case windows drive letters in /C:/fff or C:/fff - const m = URI._upperCaseDrive.exec(path); - if (m) { - if (m[1]) { - path = '/' + m[2].toLowerCase() + path.substr(3); // "/c:".length === 3 - } else { - path = m[2].toLowerCase() + path.substr(2); // // "c:".length === 2 - } - } - - // encode every segement but not slashes - // make sure that # and ? are always encoded - // when occurring in paths - otherwise the result - // cannot be parsed back again - let lastIdx = 0; - while (true) { - let idx = path.indexOf(URI._slash, lastIdx); - if (idx === -1) { - parts.push(encoder(path.substring(lastIdx))); - break; - } - parts.push(encoder(path.substring(lastIdx, idx)), URI._slash); - lastIdx = idx + 1; - }; - } - if (query) { - parts.push('?', encoder(query)); - } - if (fragment) { - parts.push('#', encoder(fragment)); - } - - return parts.join(URI._empty); - } - - public toJSON(): any { + public toJSON(): object { const res = { + $mid: 1, fsPath: this.fsPath, external: this.toString(), - $mid: 1 }; if (this.path) { @@ -375,21 +314,15 @@ export default class URI { return res; } - static revive(data: any): URI { - let result = new URI( - (data).scheme, - (data).authority, - (data).path, - (data).query, - (data).fragment - ); + static revive(data: UriComponents | any): URI { + let result = new _URI(data); result._fsPath = (data).fsPath; result._formatted = (data).external; return result; } } -interface UriComponents { +export interface UriComponents { scheme: string; authority: string; path: string; @@ -402,3 +335,129 @@ interface UriState extends UriComponents { fsPath: string; external: string; } + + +// tslint:disable-next-line:class-name +class _URI extends URI { + + _formatted: string = null; + _fsPath: string = null; + + get fsPath(): string { + if (!this._fsPath) { + this._fsPath = _makeFsPath(this); + } + return this._fsPath; + } + + public toString(skipEncoding: boolean = false): string { + if (!skipEncoding) { + if (!this._formatted) { + this._formatted = _asFormatted(this, false); + } + return this._formatted; + } else { + // we don't cache that + return _asFormatted(this, true); + } + } +} + + +/** + * Compute `fsPath` for the given uri + * @param uri + */ +function _makeFsPath(uri: URI): string { + + let value: string; + if (uri.authority && uri.path && uri.scheme === 'file') { + // unc path: file://shares/c$/far/boo + value = `//${uri.authority}${uri.path}`; + } else if (_driveLetterPath.test(uri.path)) { + // windows drive letter: file:///c:/far/boo + value = uri.path[1].toLowerCase() + uri.path.substr(2); + } else { + // other path + value = uri.path; + } + if (platform.isWindows) { + value = value.replace(/\//g, '\\'); + } + return value; +} + +/** + * Create the external version of a uri + */ +function _asFormatted(uri: URI, skipEncoding: boolean): string { + + const encoder = !skipEncoding + ? encodeURIComponent2 + : encodeNoop; + + const parts: string[] = []; + + let { scheme, authority, path, query, fragment } = uri; + if (scheme) { + parts.push(scheme, ':'); + } + if (authority || scheme === 'file') { + parts.push('//'); + } + if (authority) { + let idx = authority.indexOf('@'); + if (idx !== -1) { + const userinfo = authority.substr(0, idx); + authority = authority.substr(idx + 1); + idx = userinfo.indexOf(':'); + if (idx === -1) { + parts.push(encoder(userinfo)); + } else { + parts.push(encoder(userinfo.substr(0, idx)), ':', encoder(userinfo.substr(idx + 1))); + } + parts.push('@'); + } + authority = authority.toLowerCase(); + idx = authority.indexOf(':'); + if (idx === -1) { + parts.push(encoder(authority)); + } else { + parts.push(encoder(authority.substr(0, idx)), authority.substr(idx)); + } + } + if (path) { + // lower-case windows drive letters in /C:/fff or C:/fff + const m = _upperCaseDrive.exec(path); + if (m) { + if (m[1]) { + path = '/' + m[2].toLowerCase() + path.substr(3); // "/c:".length === 3 + } else { + path = m[2].toLowerCase() + path.substr(2); // // "c:".length === 2 + } + } + + // encode every segement but not slashes + // make sure that # and ? are always encoded + // when occurring in paths - otherwise the result + // cannot be parsed back again + let lastIdx = 0; + while (true) { + let idx = path.indexOf(_slash, lastIdx); + if (idx === -1) { + parts.push(encoder(path.substring(lastIdx))); + break; + } + parts.push(encoder(path.substring(lastIdx, idx)), _slash); + lastIdx = idx + 1; + } + } + if (query) { + parts.push('?', encoder(query)); + } + if (fragment) { + parts.push('#', encoder(fragment)); + } + + return parts.join(_empty); +} diff --git a/src/vs/base/common/winjs.base.d.ts b/src/vs/base/common/winjs.base.d.ts index 54cfd1ada1c..a0ec0a59013 100644 --- a/src/vs/base/common/winjs.base.d.ts +++ b/src/vs/base/common/winjs.base.d.ts @@ -13,7 +13,7 @@ export declare class Promise { resolve: (value: T | PromiseLike) => void, reject: (reason: any) => void, progress: (progress: TProgress) => void) => void, - oncancel?: () => void); + oncancel?: () => void); public then( onfulfilled?: ((value: T) => TResult1 | PromiseLike) | null, @@ -29,7 +29,7 @@ export declare class Promise { public static as(value: null): Promise; public static as(value: undefined): Promise; - public static as>(value: TPromise): TPromise; + public static as>(value: SomePromise): SomePromise; public static as(value: T): Promise; public static is(value: any): value is PromiseLike; diff --git a/src/vs/base/common/winjs.polyfill.promise.ts b/src/vs/base/common/winjs.polyfill.promise.ts new file mode 100644 index 00000000000..65d46c7f076 --- /dev/null +++ b/src/vs/base/common/winjs.polyfill.promise.ts @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Promise as WinJSPromise } from './winjs.base'; + +/** + * A polyfill for the native promises. The implementation is based on + * WinJS promises but tries to gap differences between winjs promises + * and native promises. + */ +export class PolyfillPromise implements Promise { + + static all(thenables: Thenable[]): PolyfillPromise { + return new PolyfillPromise(WinJSPromise.join(thenables).then(null, values => { + // WinJSPromise returns a sparse array whereas + // native promises return the *first* error + for (var key in values) { + if (values.hasOwnProperty(key)) { + return values[key]; + } + } + })); + } + + static race(thenables: Thenable[]): PolyfillPromise { + // WinJSPromise returns `{ key: , value: }` + // from the `any` call and Promise.race just wants the value + return new PolyfillPromise(WinJSPromise.any(thenables).then(entry => entry.value, err => err.value)); + } + + static resolve(value): PolyfillPromise { + return new PolyfillPromise(WinJSPromise.wrap(value)); + } + + static reject(value): PolyfillPromise { + return new PolyfillPromise(WinJSPromise.wrapError(value)); + } + + private _winjsPromise: WinJSPromise; + + constructor(winjsPromise: WinJSPromise); + constructor(callback: (resolve: (value?: T) => void, reject: (err?: any) => void) => any); + constructor(callback: WinJSPromise | ((resolve: (value?: T) => void, reject: (err?: any) => void) => any)) { + + if (WinJSPromise.is(callback)) { + this._winjsPromise = callback; + } else { + this._winjsPromise = new WinJSPromise((resolve, reject) => { + let initializing = true; + callback(function (value) { + if (!initializing) { + resolve(value); + } else { + setImmediate(resolve, value); + } + }, function (err) { + if (!initializing) { + reject(err); + } else { + setImmediate(reject, err); + } + }); + initializing = false; + }); + } + } + + then(onFulfilled?: any, onRejected?: any): PolyfillPromise { + return new PolyfillPromise(this._winjsPromise.then(onFulfilled, onRejected)); + } + + catch(onRejected?: any): PolyfillPromise { + return new PolyfillPromise(this._winjsPromise.then(null, onRejected)); + } +} diff --git a/src/vs/base/node/config.ts b/src/vs/base/node/config.ts index 6d30e650d6e..f83c0e14aa0 100644 --- a/src/vs/base/node/config.ts +++ b/src/vs/base/node/config.ts @@ -6,11 +6,12 @@ 'use strict'; import * as fs from 'fs'; -import * as path from 'path'; +import { dirname, basename } from 'path'; import * as objects from 'vs/base/common/objects'; import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import * as json from 'vs/base/common/json'; +import * as extfs from 'vs/base/node/extfs'; export interface IConfigurationChangeEvent { config: T; @@ -49,9 +50,11 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { private timeoutHandle: NodeJS.Timer; private disposables: IDisposable[]; private _onDidUpdateConfiguration: Emitter>; + private configName: string; constructor(private _path: string, private options: IConfigOptions = { changeBufferDelay: 0, defaultConfig: Object.create(null), onError: error => console.error(error) }) { this.disposables = []; + this.configName = basename(this._path); this._onDidUpdateConfiguration = new Emitter>(); this.disposables.push(this._onDidUpdateConfiguration); @@ -121,8 +124,8 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { private registerWatcher(): void { // Watch the parent of the path so that we detect ADD and DELETES - const parentFolder = path.dirname(this._path); - this.watch(parentFolder); + const parentFolder = dirname(this._path); + this.watch(parentFolder, true); // Check if the path is a symlink and watch its target if so fs.lstat(this._path, (err, stat) => { @@ -137,20 +140,19 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { return; // path is not a valid symlink } - this.watch(realPath); + this.watch(realPath, false); }); } }); } - private watch(path: string): void { + private watch(path: string, isParentFolder: boolean): void { if (this.disposed) { return; // avoid watchers that will never get disposed by checking for being disposed } try { - const watcher = fs.watch(path); - watcher.on('change', () => this.onConfigFileChange()); + const watcher = extfs.watch(path, (type, file) => this.onConfigFileChange(type, file, isParentFolder)); watcher.on('error', (code, signal) => this.options.onError(`Error watching ${path} for configuration changes (${code}, ${signal})`)); this.disposables.push(toDisposable(() => { @@ -166,7 +168,11 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { } } - private onConfigFileChange(): void { + private onConfigFileChange(eventType: string, filename: string, isParentFolder: boolean): void { + if (isParentFolder && filename !== this.configName) { + return; // a change to a sibling file that is not our config file + } + if (this.timeoutHandle) { global.clearTimeout(this.timeoutHandle); this.timeoutHandle = null; diff --git a/src/vs/base/node/console.ts b/src/vs/base/node/console.ts new file mode 100644 index 00000000000..8bbcc17fd4f --- /dev/null +++ b/src/vs/base/node/console.ts @@ -0,0 +1,128 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; + +export interface IRemoteConsoleLog { + type: string; + severity: string; + arguments: string; +} + +interface IStackArgument { + __$stack: string; +} + +export interface IStackFrame { + uri: URI; + line: number; + column: number; +} + +export function isRemoteConsoleLog(obj: any): obj is IRemoteConsoleLog { + const entry = obj as IRemoteConsoleLog; + + return entry && typeof entry.type === 'string' && typeof entry.severity === 'string'; +} + +export function parse(entry: IRemoteConsoleLog): { args: any[], stack?: string } { + const args: any[] = []; + let stack: string; + + // Parse Entry + try { + const parsedArguments: any[] = JSON.parse(entry.arguments); + + // Check for special stack entry as last entry + const stackArgument = parsedArguments[parsedArguments.length - 1] as IStackArgument; + if (stackArgument && stackArgument.__$stack) { + parsedArguments.pop(); // stack is handled specially + stack = stackArgument.__$stack; + } + + args.push(...parsedArguments); + } catch (error) { + args.push('Unable to log remote console arguments', entry.arguments); + } + + return { args, stack }; +} + +export function getFirstFrame(entry: IRemoteConsoleLog): IStackFrame; +export function getFirstFrame(stack: string): IStackFrame; +export function getFirstFrame(arg0: IRemoteConsoleLog | string): IStackFrame { + if (typeof arg0 !== 'string') { + return getFirstFrame(parse(arg0).stack); + } + + // Parse a source information out of the stack if we have one. Format can be: + // at vscode.commands.registerCommand (/Users/someone/Desktop/test-ts/out/src/extension.js:18:17) + // or + // at /Users/someone/Desktop/test-ts/out/src/extension.js:18:17 + // or + // at c:\Users\someone\Desktop\end-js\extension.js:19:17 + // or + // at e.$executeContributedCommand(c:\Users\someone\Desktop\end-js\extension.js:19:17) + const stack = arg0; + if (stack) { + const topFrame = stack.split('\n')[0]; + + // at [^\/]* => line starts with "at" followed by any character except '/' (to not capture unix paths too late) + // (?:(?:[a-zA-Z]+:)|(?:[\/])|(?:\\\\) => windows drive letter OR unix root OR unc root + // (?:.+) => simple pattern for the path, only works because of the line/col pattern after + // :(?:\d+):(?:\d+) => :line:column data + const matches = /at [^\/]*((?:(?:[a-zA-Z]+:)|(?:[\/])|(?:\\\\))(?:.+)):(\d+):(\d+)/.exec(topFrame); + if (matches && matches.length === 4) { + return { + uri: URI.file(matches[1]), + line: Number(matches[2]), + column: Number(matches[3]) + } as IStackFrame; + } + } + + return void 0; +} + +export function log(entry: IRemoteConsoleLog, label: string): void { + const { args, stack } = parse(entry); + + const isOneStringArg = typeof args[0] === 'string' && args.length === 1; + + let topFrame = stack && stack.split('\n')[0]; + if (topFrame) { + topFrame = `(${topFrame.trim()})`; + } + + let consoleArgs = []; + + // First arg is a string + if (typeof args[0] === 'string') { + if (topFrame && isOneStringArg) { + consoleArgs = [`%c[${label}] %c${args[0]} %c${topFrame}`, color('blue'), color('black'), color('grey')]; + } else { + consoleArgs = [`%c[${label}] %c${args[0]}`, color('blue'), color('black'), ...args.slice(1)]; + } + } + + // First arg is something else, just apply all + else { + consoleArgs = [`%c[${label}]%`, color('blue'), ...args]; + } + + // Stack: add to args unless already aded + if (topFrame && !isOneStringArg) { + consoleArgs.push(topFrame); + } + + // Log it + console[entry.severity].apply(console, consoleArgs); +} + +function color(color: string): string { + return `color: ${color}`; +} \ No newline at end of file diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index 8656fbe19cb..e7579c071c4 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -95,17 +95,12 @@ export function detectEncodingByBOM(file: string): TPromise { } const MINIMUM_THRESHOLD = 0.2; - const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32']; -const MAPPED_ENCODINGS: { [name: string]: string } = { - 'ibm866': 'cp866' -}; /** * Guesses the encoding from buffer. */ export async function guessEncodingByBuffer(buffer: NodeBuffer): TPromise { - const jschardet = await import('jschardet'); jschardet.Constants.MINIMUM_THRESHOLD = MINIMUM_THRESHOLD; @@ -126,9 +121,14 @@ export async function guessEncodingByBuffer(buffer: NodeBuffer): TPromise(emitter: EventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event { - const fn = (...args) => result.fire(map(...args)); - const onFirstListenerAdd = () => emitter.on(eventName, fn); - const onLastListenerRemove = () => emitter.removeListener(eventName, fn); - const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove }); - - return result.event; -}; diff --git a/src/vs/base/node/extfs.ts b/src/vs/base/node/extfs.ts index 9d05bf98bfb..b17a41aa17d 100644 --- a/src/vs/base/node/extfs.ts +++ b/src/vs/base/node/extfs.ts @@ -450,3 +450,19 @@ export function realpath(path: string, callback: (error: Error, realpath: string function normalizePath(path: string): string { return strings.rtrim(paths.normalize(path), paths.sep); } + +export function watch(path: string, onChange: (type: string, path: string) => void): fs.FSWatcher { + const watcher = fs.watch(path); + watcher.on('change', (type, raw) => { + let file = raw.toString(); + if (platform.isMacintosh) { + // Mac: uses NFD unicode form on disk, but we want NFC + // See also https://github.com/nodejs/node/issues/2165 + file = strings.normalizeNFC(file); + } + + onChange(type, file); + }); + + return watcher; +} \ No newline at end of file diff --git a/src/vs/base/node/id.ts b/src/vs/base/node/id.ts index f8b65bfcbc9..22a79358a0a 100644 --- a/src/vs/base/node/id.ts +++ b/src/vs/base/node/id.ts @@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as errors from 'vs/base/common/errors'; import * as uuid from 'vs/base/common/uuid'; import { networkInterfaces } from 'os'; -import { TrieMap } from 'vs/base/common/map'; +import { TernarySearchTree } from 'vs/base/common/map'; // http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/ // VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69 @@ -23,21 +23,30 @@ import { TrieMap } from 'vs/base/common/map'; // Sun xVM VirtualBox 08-00-27 export const virtualMachineHint: { value(): number } = new class { - private _virtualMachineOUIs: TrieMap; + private _virtualMachineOUIs: TernarySearchTree; private _value: number; private _isVirtualMachineMacAdress(mac: string): boolean { if (!this._virtualMachineOUIs) { - this._virtualMachineOUIs = new TrieMap(s => s.split(/[-:]/)); - // this._virtualMachineOUIs.insert('00-00-00', true); - this._virtualMachineOUIs.insert('00-50-56', true); - this._virtualMachineOUIs.insert('00-0C-29', true); - this._virtualMachineOUIs.insert('00-05-69', true); - this._virtualMachineOUIs.insert('00-03-FF', true); - this._virtualMachineOUIs.insert('00-1C-42', true); - this._virtualMachineOUIs.insert('00-16-3E', true); - this._virtualMachineOUIs.insert('08-00-27', true); + this._virtualMachineOUIs = TernarySearchTree.forStrings(); + // dash-separated + this._virtualMachineOUIs.set('00-50-56', true); + this._virtualMachineOUIs.set('00-0C-29', true); + this._virtualMachineOUIs.set('00-05-69', true); + this._virtualMachineOUIs.set('00-03-FF', true); + this._virtualMachineOUIs.set('00-1C-42', true); + this._virtualMachineOUIs.set('00-16-3E', true); + this._virtualMachineOUIs.set('08-00-27', true); + + // colon-separated + this._virtualMachineOUIs.set('00:50:56', true); + this._virtualMachineOUIs.set('00:0C:29', true); + this._virtualMachineOUIs.set('00:05:69', true); + this._virtualMachineOUIs.set('00:03:FF', true); + this._virtualMachineOUIs.set('00:1C:42', true); + this._virtualMachineOUIs.set('00:16:3E', true); + this._virtualMachineOUIs.set('08:00:27', true); } return this._virtualMachineOUIs.findSubstr(mac); } diff --git a/src/vs/base/node/mime.ts b/src/vs/base/node/mime.ts index ee5ce368a7a..1e71046cce6 100644 --- a/src/vs/base/node/mime.ts +++ b/src/vs/base/node/mime.ts @@ -56,7 +56,7 @@ const ZERO_BYTE_DETECTION_BUFFER_MAX_LEN = 512; // number of bytes to look at to const NO_GUESS_BUFFER_MAX_LEN = 512; // when not auto guessing the encoding, small number of bytes are enough const AUTO_GUESS_BUFFER_MAX_LEN = 512 * 8; // with auto guessing we want a lot more content to be read for guessing -function maxBufferLen(arg1?: DetectMimesOption | boolean): number { +export function maxBufferLen(arg1?: DetectMimesOption | boolean): number { let autoGuessEncoding: boolean; if (typeof arg1 === 'boolean') { autoGuessEncoding = arg1; diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index 16f8d7509be..e75dd48d1b5 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -189,3 +189,24 @@ const tmpDir = os.tmpdir(); export function del(path: string, tmp = tmpDir): TPromise { return nfcall(extfs.del, path, tmp); } + +export function whenDeleted(path: string): TPromise { + + // Complete when wait marker file is deleted + return new TPromise(c => { + let running = false; + const interval = setInterval(() => { + if (!running) { + running = true; + fs.exists(path, exists => { + running = false; + + if (!exists) { + clearInterval(interval); + c(null); + } + }); + } + }, 1000); + }); +} \ No newline at end of file diff --git a/src/vs/base/node/ports.ts b/src/vs/base/node/ports.ts index c515e902d8b..1ab7de9ab2c 100644 --- a/src/vs/base/node/ports.ts +++ b/src/vs/base/node/ports.ts @@ -46,6 +46,10 @@ function doFindFreePort(startPort: number, giveUpAfter: number, clb: (port: numb return doFindFreePort(startPort + 1, giveUpAfter - 1, clb); }); + client.once('data', () => { + // this listener is required since node.js 8.x + }); + client.once('error', (err: Error & { code?: string }) => { dispose(client); diff --git a/src/vs/base/node/startupTimers.d.ts b/src/vs/base/node/startupTimers.d.ts deleted file mode 100644 index 432cb72088e..00000000000 --- a/src/vs/base/node/startupTimers.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Profile } from './profiler'; - -declare interface TickStart { - name: string; - started: number; -} - -export declare class Tick { - - readonly duration: number; - readonly name: string; - readonly started: number; - readonly stopped: number; - readonly profile: Profile; - - static compareByStart(a: Tick, b: Tick): number; -} - -declare interface TickController { - while>(t: T): T; - stop(stopped?: number): void; -} - -export function startTimer(name: string): TickController; - -export function stopTimer(name: string): void; - -export function ticks(): Tick[]; - -export function tick(name: string): Tick; - -export function setProfileList(names: string[]): void; - -export function disable(): void; diff --git a/src/vs/base/node/startupTimers.js b/src/vs/base/node/startupTimers.js deleted file mode 100644 index 7fc81812efc..00000000000 --- a/src/vs/base/node/startupTimers.js +++ /dev/null @@ -1,128 +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'; - -/*global define*/ - -var requireProfiler; - -if (typeof define !== "function" && typeof module === "object" && typeof module.exports === "object") { - // this is commonjs, fake amd - global.define = function (dep, callback) { - module.exports = callback(); - global.define = undefined; - }; - requireProfiler = function () { - return require('v8-profiler'); - }; -} else { - // this is amd - requireProfiler = function () { - return require.__$__nodeRequire('v8-profiler'); - }; -} - -define([], function () { - - function Tick(name, started, stopped, profile) { - this.name = name; - this.started = started; - this.stopped = stopped; - this.duration = Math.round(((stopped[0] * 1.e9 + stopped[1]) - (started[0] * 1e9 + started[1])) / 1.e6); - this.profile = profile; - } - Tick.compareByStart = function (a, b) { - if (a.started < b.started) { - return -1; - } else if (a.started > b.started) { - return 1; - } else { - return 0; - } - }; - - // This module can be loaded in an amd and commonjs-context. - // Because we want both instances to use the same tick-data - // we store them globally - global._perfStarts = global._perfStarts || new Map(); - global._perfTicks = global._perfTicks || new Map(); - global._perfToBeProfiled = global._perfToBeProfiled || new Set(); - - var _starts = global._perfStarts; - var _ticks = global._perfTicks; - var _toBeProfiled = global._perfToBeProfiled; - - function startTimer(name) { - if (_starts.has(name)) { - throw new Error("${name}" + " already exists"); - } - if (_toBeProfiled.has(name)) { - requireProfiler().startProfiling(name, true); - } - _starts.set(name, { name: name, started: process.hrtime() }); - var stop = stopTimer.bind(undefined, name); - return { - stop: stop, - while: function (thenable) { - thenable.then(function () { stop(); }, function () { stop(); }); - return thenable; - } - }; - } - - function stopTimer(name) { - var profile = _toBeProfiled.has(name) ? requireProfiler().stopProfiling(name) : undefined; - var start = _starts.get(name); - if (start !== undefined) { - var tick = new Tick(start.name, start.started, process.hrtime(), profile); - _ticks.set(name, tick); - _starts.delete(name); - } - } - - function ticks() { - var ret = []; - _ticks.forEach(function (value) { ret.push(value); }); - return ret; - } - - function tick(name) { - var ret = _ticks.get(name); - if (!ret) { - var now = Date.now(); - ret = new Tick(name, now, now); - } - return ret; - } - - function setProfileList(names) { - _toBeProfiled.clear(); - names.forEach(function (name) { _toBeProfiled.add(name); }); - } - - var exports = { - Tick: Tick, - startTimer: startTimer, - stopTimer: stopTimer, - ticks: ticks, - tick: tick, - setProfileList: setProfileList, - disable: disable, - }; - - function disable() { - var emptyController = Object.freeze({ while: function (t) { return t; }, stop: function () { } }); - var emptyTicks = Object.create([]); - exports.startTimer = function () { return emptyController; }; - exports.stopTimer = function () { }; - exports.ticks = function () { return emptyTicks; }; - - delete global._perfStarts; - delete global._perfTicks; - } - - return exports; -}); diff --git a/src/vs/base/parts/ipc/common/ipc.electron.ts b/src/vs/base/parts/ipc/common/ipc.electron.ts index f9f773a330c..1223020a9ff 100644 --- a/src/vs/base/parts/ipc/common/ipc.electron.ts +++ b/src/vs/base/parts/ipc/common/ipc.electron.ts @@ -18,7 +18,7 @@ export class Protocol implements IMessagePassingProtocol { private _onMessage: Event; get onMessage(): Event { return this._onMessage; } - constructor(private sender: Sender, private onMessageEvent: Event) { + constructor(private sender: Sender, onMessageEvent: Event) { const emitter = new Emitter(); onMessageEvent(msg => emitter.fire(msg)); this._onMessage = emitter.event; diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 01bd2037e57..d4712447f32 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -411,8 +411,8 @@ export class IPCServer implements IChannelServer, IRoutingChannelClient, IDispos } dispose(): void { - this.channels = null; - this.channelClients = null; + this.channels = Object.create(null); + this.channelClients = Object.create(null); this.onClientAdded.dispose(); } } diff --git a/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts b/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts index 599cf277211..7e3ce8ddd1e 100644 --- a/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts +++ b/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { fromEventEmitter } from 'vs/base/node/event'; +import { fromNodeEventEmitter } from 'vs/base/common/event'; import { IPCClient } from 'vs/base/parts/ipc/common/ipc'; import { Protocol } from 'vs/base/parts/ipc/common/ipc.electron'; import { ipcRenderer } from 'electron'; @@ -11,7 +11,7 @@ import { ipcRenderer } from 'electron'; export class Client extends IPCClient { private static createProtocol(): Protocol { - const onMessage = fromEventEmitter(ipcRenderer, 'ipc:message', (_, message) => message); + const onMessage = fromNodeEventEmitter(ipcRenderer, 'ipc:message', (_, message) => message); ipcRenderer.send('ipc:hello'); return new Protocol(ipcRenderer, onMessage); } diff --git a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts index d0295a4937b..c6e556c6c0a 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts @@ -3,8 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import Event, { filterEvent, mapEvent } from 'vs/base/common/event'; -import { fromEventEmitter } from 'vs/base/node/event'; +import Event, { filterEvent, mapEvent, fromNodeEventEmitter } from 'vs/base/common/event'; import { IPCServer, ClientConnectionEvent } from 'vs/base/parts/ipc/common/ipc'; import { Protocol } from 'vs/base/parts/ipc/common/ipc.electron'; import { ipcMain } from 'electron'; @@ -19,7 +18,7 @@ interface IIPCEvent { } function createScopedOnMessageEvent(senderId: number): Event { - const onMessage = fromEventEmitter(ipcMain, 'ipc:message', (event, message) => ({ event, message })); + const onMessage = fromNodeEventEmitter(ipcMain, 'ipc:message', (event, message) => ({ event, message })); const onMessageFromSender = filterEvent(onMessage, ({ event }) => event.sender.getId() === senderId); return mapEvent(onMessageFromSender, ({ message }) => message); } @@ -27,12 +26,12 @@ function createScopedOnMessageEvent(senderId: number): Event { export class Server extends IPCServer { private static getOnDidClientConnect(): Event { - const onHello = fromEventEmitter(ipcMain, 'ipc:hello', ({ sender }) => sender); + const onHello = fromNodeEventEmitter(ipcMain, 'ipc:hello', ({ sender }) => sender); return mapEvent(onHello, webContents => { const onMessage = createScopedOnMessageEvent(webContents.getId()); const protocol = new Protocol(webContents, onMessage); - const onDidClientDisconnect = fromEventEmitter(webContents, 'destroyed'); + const onDidClientDisconnect = fromNodeEventEmitter(webContents, 'destroyed'); return { protocol, onDidClientDisconnect }; }); diff --git a/src/vs/base/parts/ipc/node/ipc.cp.ts b/src/vs/base/parts/ipc/node/ipc.cp.ts index 45d401724c4..d7c610160f1 100644 --- a/src/vs/base/parts/ipc/node/ipc.cp.ts +++ b/src/vs/base/parts/ipc/node/ipc.cp.ts @@ -8,16 +8,16 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { Delayer } from 'vs/base/common/async'; import { clone, assign } from 'vs/base/common/objects'; -import { Emitter } from 'vs/base/common/event'; -import { fromEventEmitter } from 'vs/base/node/event'; +import { Emitter, fromNodeEventEmitter } from 'vs/base/common/event'; import { createQueuedSender } from 'vs/base/node/processes'; import { ChannelServer as IPCServer, ChannelClient as IPCClient, IChannelClient, IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { isRemoteConsoleLog, log } from 'vs/base/node/console'; export class Server extends IPCServer { constructor() { super({ send: r => { try { process.send(r); } catch (e) { /* not much to do */ } }, - onMessage: fromEventEmitter(process, 'message', msg => msg) + onMessage: fromNodeEventEmitter(process, 'message', msg => msg) }); process.once('disconnect', () => this.dispose()); @@ -148,27 +148,18 @@ export class Client implements IChannelClient, IDisposable { this.child = fork(this.modulePath, args, forkOpts); const onMessageEmitter = new Emitter(); - const onRawMessage = fromEventEmitter(this.child, 'message', msg => msg); + const onRawMessage = fromNodeEventEmitter(this.child, 'message', msg => msg); onRawMessage(msg => { - // Handle console logs specially - if (msg && msg.type === '__$console') { - let args = ['%c[IPC Library: ' + this.options.serverName + ']', 'color: darkgreen']; - try { - const parsed = JSON.parse(msg.arguments); - args = args.concat(Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(msg.arguments); - } - console[msg.severity].apply(console, args); + // Handle remote console logs specially + if (isRemoteConsoleLog(msg)) { + log(msg, `IPC Library: ${this.options.serverName}`); return null; } // Anything else goes to the outside - else { - onMessageEmitter.fire(msg); - } + onMessageEmitter.fire(msg); }); const sender = this.options.useQueue ? createQueuedSender(this.child) : this.child; diff --git a/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts index e4194ca6693..a080e193cb7 100644 --- a/src/vs/base/parts/ipc/node/ipc.net.ts +++ b/src/vs/base/parts/ipc/node/ipc.net.ts @@ -7,8 +7,7 @@ import { Socket, Server as NetServer, createConnection, createServer } from 'net'; import { TPromise } from 'vs/base/common/winjs.base'; -import Event, { Emitter, once, mapEvent } from 'vs/base/common/event'; -import { fromEventEmitter } from 'vs/base/node/event'; +import Event, { Emitter, once, mapEvent, fromNodeEventEmitter } from 'vs/base/common/event'; import { IMessagePassingProtocol, ClientConnectionEvent, IPCServer, IPCClient } from 'vs/base/parts/ipc/common/ipc'; import { join } from 'path'; import { tmpdir } from 'os'; @@ -156,11 +155,11 @@ export class Protocol implements IMessagePassingProtocol { export class Server extends IPCServer { private static toClientConnectionEvent(server: NetServer): Event { - const onConnection = fromEventEmitter(server, 'connection'); + const onConnection = fromNodeEventEmitter(server, 'connection'); return mapEvent(onConnection, socket => ({ protocol: new Protocol(socket), - onDidClientDisconnect: once(fromEventEmitter(socket, 'close')) + onDidClientDisconnect: once(fromNodeEventEmitter(socket, 'close')) })); } diff --git a/src/vs/base/parts/ipc/test/node/testService.ts b/src/vs/base/parts/ipc/test/node/testService.ts index 36c2120d22f..0a970bfe735 100644 --- a/src/vs/base/parts/ipc/test/node/testService.ts +++ b/src/vs/base/parts/ipc/test/node/testService.ts @@ -61,7 +61,7 @@ export class TestService implements ITestService { } progress(batch); process.nextTick(send); - }; + } process.nextTick(send); }); } @@ -94,7 +94,7 @@ export class TestChannel implements ITestChannel { export class TestServiceClient implements ITestService { private _onMarco: Event; - get onMarco(): Event { return this._onMarco; }; + get onMarco(): Event { return this._onMarco; } constructor(private channel: ITestChannel) { this._onMarco = eventFromCall(channel, 'event:marco'); diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index 24bb80a1fb2..773a4b79b4d 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -10,13 +10,10 @@ import { TPromise } from 'vs/base/common/winjs.base'; import types = require('vs/base/common/types'); import URI from 'vs/base/common/uri'; import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree'; -import filters = require('vs/base/common/filters'); -import strings = require('vs/base/common/strings'); -import paths = require('vs/base/common/paths'); import { IconLabel, IIconLabelOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode } from 'vs/base/parts/quickopen/common/quickOpen'; import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; -import { compareAnything, compareByScore as doCompareByScore } from 'vs/base/common/comparers'; +import { compareAnything } from 'vs/base/common/comparers'; import { ActionBar, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import DOM = require('vs/base/browser/dom'); @@ -24,6 +21,7 @@ import { IQuickOpenStyles } from 'vs/base/parts/quickopen/browser/quickOpenWidge import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; import { OS } from 'vs/base/common/platform'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; +import { IItemAccessor } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export interface IContext { event: any; @@ -37,18 +35,25 @@ export interface IHighlight { let IDS = 0; -class EntryAccessor { +export class QuickOpenItemAccessorClass implements IItemAccessor { - public static getLabel(entry: QuickOpenEntry) { + public getItemLabel(entry: QuickOpenEntry): string { return entry.getLabel(); } - public static getResourcePath(entry: QuickOpenEntry) { + public getItemDescription(entry: QuickOpenEntry): string { + return entry.getDescription(); + } + + public getItemPath(entry: QuickOpenEntry): string { const resource = entry.getResource(); - return resource && resource.fsPath; + + return resource ? resource.fsPath : void 0; } } +export const QuickOpenItemAccessor = new QuickOpenItemAccessorClass(); + export class QuickOpenEntry { private id: string; private labelHighlights: IHighlight[]; @@ -166,116 +171,6 @@ export class QuickOpenEntry { return false; } - /** - * A good default sort implementation for quick open entries respecting highlight information - * as well as associated resources. - */ - public static compare(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string): number { - - // Give matches with label highlights higher priority over - // those with only description highlights - const labelHighlightsA = elementA.getHighlights()[0] || []; - const labelHighlightsB = elementB.getHighlights()[0] || []; - if (labelHighlightsA.length && !labelHighlightsB.length) { - return -1; - } else if (!labelHighlightsA.length && labelHighlightsB.length) { - return 1; - } - - // Fallback to the full path if labels are identical and we have associated resources - let nameA = elementA.getLabel(); - let nameB = elementB.getLabel(); - if (nameA === nameB) { - const resourceA = elementA.getResource(); - const resourceB = elementB.getResource(); - - if (resourceA && resourceB) { - nameA = resourceA.fsPath; - nameB = resourceB.fsPath; - } - } - - return compareAnything(nameA, nameB, lookFor); - } - - public static compareByScore(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string, lookForNormalizedLower: string, scorerCache?: { [key: string]: number }): number { - return doCompareByScore(elementA, elementB, EntryAccessor, lookFor, lookForNormalizedLower, scorerCache); - } - - /** - * A good default highlight implementation for an entry with label and description. - */ - public static highlight(entry: QuickOpenEntry, lookFor: string, fuzzyHighlight = false): { labelHighlights: IHighlight[], descriptionHighlights: IHighlight[] } { - let labelHighlights: IHighlight[] = []; - const descriptionHighlights: IHighlight[] = []; - - const normalizedLookFor = strings.stripWildcards(lookFor); - const label = entry.getLabel(); - const description = entry.getDescription(); - - // Highlight file aware - if (entry.getResource()) { - - // Highlight entire label and description if searching for full absolute path - const fsPath = entry.getResource().fsPath; - if (lookFor.length === fsPath.length && lookFor.toLowerCase() === fsPath.toLowerCase()) { - labelHighlights.push({ start: 0, end: label.length }); - descriptionHighlights.push({ start: 0, end: description.length }); - } - - // Fuzzy/Full-Path: Highlight is special - else if (fuzzyHighlight || lookFor.indexOf(paths.nativeSep) >= 0) { - const candidateLabelHighlights = filters.matchesFuzzy(lookFor, label, fuzzyHighlight); - if (!candidateLabelHighlights) { - const pathPrefix = description ? (description + paths.nativeSep) : ''; - const pathPrefixLength = pathPrefix.length; - - // If there are no highlights in the label, build a path out of description and highlight and match on both, - // then extract the individual label and description highlights back to the original positions - let pathHighlights = filters.matchesFuzzy(lookFor, pathPrefix + label, fuzzyHighlight); - if (!pathHighlights && lookFor !== normalizedLookFor) { - pathHighlights = filters.matchesFuzzy(normalizedLookFor, pathPrefix + label, fuzzyHighlight); - } - - if (pathHighlights) { - pathHighlights.forEach(h => { - - // Match overlaps label and description part, we need to split it up - if (h.start < pathPrefixLength && h.end > pathPrefixLength) { - labelHighlights.push({ start: 0, end: h.end - pathPrefixLength }); - descriptionHighlights.push({ start: h.start, end: pathPrefixLength }); - } - - // Match on label part - else if (h.start >= pathPrefixLength) { - labelHighlights.push({ start: h.start - pathPrefixLength, end: h.end - pathPrefixLength }); - } - - // Match on description part - else { - descriptionHighlights.push(h); - } - }); - } - } else { - labelHighlights = candidateLabelHighlights; - } - } - - // Highlight only inside label - else { - labelHighlights = filters.matchesFuzzy(lookFor, label); - } - } - - // Highlight by label otherwise - else { - labelHighlights = filters.matchesFuzzy(lookFor, label); - } - - return { labelHighlights, descriptionHighlights }; - } - public isFile(): boolean { return false; // TODO@Ben debt with editor history merging } @@ -686,3 +581,37 @@ export class QuickOpenModel implements return entry.run(mode, context); } } + +/** + * A good default sort implementation for quick open entries respecting highlight information + * as well as associated resources. + */ +export function compareEntries(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string): number { + + // Give matches with label highlights higher priority over + // those with only description highlights + const labelHighlightsA = elementA.getHighlights()[0] || []; + const labelHighlightsB = elementB.getHighlights()[0] || []; + if (labelHighlightsA.length && !labelHighlightsB.length) { + return -1; + } + + if (!labelHighlightsA.length && labelHighlightsB.length) { + return 1; + } + + // Fallback to the full path if labels are identical and we have associated resources + let nameA = elementA.getLabel(); + let nameB = elementB.getLabel(); + if (nameA === nameB) { + const resourceA = elementA.getResource(); + const resourceB = elementB.getResource(); + + if (resourceA && resourceB) { + nameA = resourceA.fsPath; + nameB = resourceB.fsPath; + } + } + + return compareAnything(nameA, nameB, lookFor); +} \ No newline at end of file diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 63d07bf6c35..5018c59b31b 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -151,8 +151,8 @@ export class QuickOpenWidget implements IModelProvider { this.builder = $().div((div: Builder) => { // Eventing - div.on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); + div.on(DOM.EventType.KEY_DOWN, (e) => { + const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e as KeyboardEvent); if (keyboardEvent.keyCode === KeyCode.Escape) { DOM.EventHelper.stop(e, true); @@ -261,8 +261,8 @@ export class QuickOpenWidget implements IModelProvider { } })); }). - on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); + on(DOM.EventType.KEY_DOWN, (e) => { + const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e as KeyboardEvent); // Only handle when in quick navigation mode if (!this.quickNavigateConfiguration) { @@ -276,8 +276,8 @@ export class QuickOpenWidget implements IModelProvider { this.navigateInTree(keyboardEvent.keyCode); } }). - on(DOM.EventType.KEY_UP, (e: KeyboardEvent) => { - const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); + on(DOM.EventType.KEY_UP, (e) => { + const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e as KeyboardEvent); const keyCode = keyboardEvent.keyCode; // Only handle when in quick navigation mode @@ -532,6 +532,13 @@ export class QuickOpenWidget implements IModelProvider { if (this.usageLogger) { const indexOfAcceptedElement = this.model.entries.indexOf(value); const entriesCount = this.model.entries.length; + /* __GDPR__ + "quickOpenWidgetItemAccepted" : { + "index" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "count": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "isQuickNavigate": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.usageLogger.publicLog('quickOpenWidgetItemAccepted', { index: indexOfAcceptedElement, count: entriesCount, isQuickNavigate: this.quickNavigateConfiguration ? true : false }); } @@ -773,6 +780,12 @@ export class QuickOpenWidget implements IModelProvider { if (this.model) { const entriesCount = this.model.entries.filter(e => this.isElementVisible(this.model, e)).length; if (this.usageLogger) { + /* __GDPR__ + "quickOpenWidgetCancelled" : { + "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "isQuickNavigate": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.usageLogger.publicLog('quickOpenWidgetCancelled', { count: entriesCount, isQuickNavigate: this.quickNavigateConfiguration ? true : false }); } } diff --git a/src/vs/base/parts/quickopen/common/quickOpen.ts b/src/vs/base/parts/quickopen/common/quickOpen.ts index 2d16a043060..1efef91896c 100644 --- a/src/vs/base/parts/quickopen/common/quickOpen.ts +++ b/src/vs/base/parts/quickopen/common/quickOpen.ts @@ -6,6 +6,11 @@ import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; +/* __GDPR__FRAGMENT__ + "IQuickNavigateConfiguration" : { + "keybindings" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ export interface IQuickNavigateConfiguration { keybindings: ResolvedKeybinding[]; } diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts new file mode 100644 index 00000000000..75b33c6ebf6 --- /dev/null +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -0,0 +1,614 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { 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 { CharCode } from 'vs/base/common/charCode'; + +export type Score = [number /* score */, number[] /* match positions */]; +export type ScorerCache = { [key: string]: IItemScore }; + +const NO_MATCH = 0; +const NO_SCORE: Score = [NO_MATCH, []]; + +// const DEBUG = false; +// const DEBUG_MATRIX = false; + +export function score(target: string, query: string, queryLower: string, fuzzy: boolean): Score { + if (!target || !query) { + return NO_SCORE; // return early if target or query are undefined + } + + const targetLength = target.length; + const queryLength = query.length; + + if (targetLength < queryLength) { + return NO_SCORE; // impossible for query to be contained in target + } + + // if (DEBUG) { + // console.group(`Target: ${target}, Query: ${query}`); + // } + + const targetLower = target.toLowerCase(); + + // When not searching fuzzy, we require the query to be contained fully + // in the target string contiguously. + if (!fuzzy) { + const indexOfQueryInTarget = targetLower.indexOf(queryLower); + if (indexOfQueryInTarget === -1) { + // if (DEBUG) { + // console.log(`Characters not matching consecutively ${queryLower} within ${targetLower}`); + // } + + return NO_SCORE; + } + } + + // When searching fuzzy, we require the query to be contained fully + // in the target string as separate substrings + else { + let targetOffset = 0; + for (let queryIndex = 0; queryIndex < queryLength; queryIndex++) { + targetOffset = targetLower.indexOf(queryLower[queryIndex], targetOffset); + if (targetOffset === -1) { + return NO_SCORE; + } + } + } + + const res = doScore(query, queryLower, queryLength, target, targetLower, targetLength); + + // if (DEBUG) { + // console.log(`%cFinal Score: ${res[0]}`, 'font-weight: bold'); + // console.groupEnd(); + // } + + return res; +} + +function doScore(query: string, queryLower: string, queryLength: number, target: string, targetLower: string, targetLength: number): [number, number[]] { + const scores = []; + const matches = []; + + // + // Build Scorer Matrix + // The matrix is composed of query q and target t. For each index we score + // q[i] with t[i] and compare that with the previous score. If the score is + // equal or larger, we keep the match. In addition to the score, we also keep + // the length of the consecutive matches to use as boost for the score. + // + // t a r g e t + // q + // u + // e + // r + // y + // + for (let queryIndex = 0; queryIndex < queryLength; queryIndex++) { + for (let targetIndex = 0; targetIndex < targetLength; targetIndex++) { + const currentIndex = queryIndex * targetLength + targetIndex; + const leftIndex = currentIndex - 1; + const diagIndex = (queryIndex - 1) * targetLength + targetIndex - 1; + + const leftScore = targetIndex > 0 ? scores[leftIndex] : 0; + const diagScore = queryIndex > 0 && targetIndex > 0 ? scores[diagIndex] : 0; + + const matchesSequenceLength = queryIndex > 0 && targetIndex > 0 ? matches[diagIndex] : 0; + + const score = computeCharScore(query, queryLower, queryIndex, target, targetLower, targetIndex, matchesSequenceLength); + + // We have a score and its equal or larger than the left score + // Match: sequence continues growing from previous diag value + // Score: increases by diag score value + if (score && diagScore + score >= leftScore) { + matches[currentIndex] = matchesSequenceLength + 1; + scores[currentIndex] = diagScore + score; + } + + // We either have no score or the score is lower than the left score + // Match: reset to 0 + // Score: pick up from left hand side + else { + matches[currentIndex] = NO_MATCH; + scores[currentIndex] = leftScore; + } + } + } + + // Restore Positions (starting from bottom right of matrix) + const positions = []; + let queryIndex = queryLength - 1; + let targetIndex = targetLength - 1; + while (queryIndex >= 0 && targetIndex >= 0) { + const currentIndex = queryIndex * targetLength + targetIndex; + const match = matches[currentIndex]; + if (match === NO_MATCH) { + targetIndex--; // go left + } else { + positions.push(targetIndex); + + // go up and left + queryIndex--; + targetIndex--; + } + } + + // Print matrix + // if (DEBUG_MATRIX) { + // printMatrix(query, target, matches, scores); + // } + + return [scores[queryLength * targetLength - 1], positions.reverse()]; +} + +function computeCharScore(query: string, queryLower: string, queryIndex: number, target: string, targetLower: string, targetIndex: number, matchesSequenceLength: number): number { + let score = 0; + + if (queryLower[queryIndex] !== targetLower[targetIndex]) { + return score; // no match of characters + } + + // Character match bonus + score += 1; + + // if (DEBUG) { + // console.groupCollapsed(`%cCharacter match bonus: +1 (char: ${queryLower[queryIndex]} at index ${targetIndex}, total score: ${score})`, 'font-weight: normal'); + // } + + // Consecutive match bonus + if (matchesSequenceLength > 0) { + score += (matchesSequenceLength * 5); + + // if (DEBUG) { + // console.log('Consecutive match bonus: ' + (matchesSequenceLength * 5)); + // } + } + + // Same case bonus + if (query[queryIndex] === target[targetIndex]) { + score += 1; + + // if (DEBUG) { + // console.log('Same case bonus: +1'); + // } + } + + // Start of word bonus + if (targetIndex === 0) { + score += 8; + + // if (DEBUG) { + // console.log('Start of word bonus: +8'); + // } + } + + else { + + // After separator bonus + const separatorBonus = scoreSeparatorAtPos(target.charCodeAt(targetIndex - 1)); + if (separatorBonus) { + score += separatorBonus; + + // if (DEBUG) { + // console.log('After separtor bonus: +4'); + // } + } + + // Inside word upper case bonus (camel case) + else if (isUpper(target.charCodeAt(targetIndex))) { + score += 1; + + // if (DEBUG) { + // console.log('Inside word upper case bonus: +1'); + // } + } + } + + // if (DEBUG) { + // console.groupEnd(); + // } + + return score; +} + +function scoreSeparatorAtPos(charCode: number): number { + switch (charCode) { + case CharCode.Slash: + case CharCode.Backslash: + return 5; // prefer path separators... + case CharCode.Underline: + case CharCode.Dash: + case CharCode.Period: + case CharCode.Space: + case CharCode.SingleQuote: + case CharCode.DoubleQuote: + case CharCode.Colon: + return 4; // ...over other separators + default: + return 0; + } +} + +// function printMatrix(query: string, target: string, matches: number[], scores: number[]): void { +// console.log('\t' + target.split('').join('\t')); +// for (let queryIndex = 0; queryIndex < query.length; queryIndex++) { +// let line = query[queryIndex] + '\t'; +// for (let targetIndex = 0; targetIndex < target.length; targetIndex++) { +// const currentIndex = queryIndex * target.length + targetIndex; +// line = line + 'M' + matches[currentIndex] + '/' + 'S' + scores[currentIndex] + '\t'; +// } + +// console.log(line); +// } +// } + +/** + * Scoring on structural items that have a label and optional description. + */ +export interface IItemScore { + + /** + * Overall score. + */ + score: number; + + /** + * Matches within the label. + */ + labelMatch?: IMatch[]; + + /** + * Matches within the description. + */ + descriptionMatch?: IMatch[]; +} + +const NO_ITEM_SCORE: IItemScore = Object.freeze({ score: 0 }); + +export interface IItemAccessor { + + /** + * Just the label of the item to score on. + */ + getItemLabel(item: T): string; + + /** + * The optional description of the item to score on. Can be null. + */ + getItemDescription(item: T): string; + + /** + * If the item is a file, the path of the file to score on. Can be null. + */ + getItemPath(file: T): string; +} + +const PATH_IDENTITY_SCORE = 1 << 18; +const LABEL_PREFIX_SCORE = 1 << 17; +const LABEL_CAMELCASE_SCORE = 1 << 16; +const LABEL_SCORE_THRESHOLD = 1 << 15; + +export interface IPreparedQuery { + value: string; + lowercase: string; + containsPathSeparator: boolean; +} + +/** + * Helper function to prepare a search value for scoring in quick open by removing unwanted characters. + */ +export function prepareQuery(value: string): IPreparedQuery { + let lowercase: string; + let containsPathSeparator: boolean; + + if (value) { + value = stripWildcards(value).replace(/\s/g, ''); // get rid of all wildcards and whitespace + if (isWindows) { + value = value.replace(/\//g, '\\'); // Help Windows users to search for paths when using slash + } + + lowercase = value.toLowerCase(); + containsPathSeparator = value.indexOf(nativeSep) >= 0; + } + + return { value, lowercase, containsPathSeparator }; +} + +export function scoreItem(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache): IItemScore { + if (!item || !query.value) { + return NO_ITEM_SCORE; // we need an item and query to score on at least + } + + const label = accessor.getItemLabel(item); + if (!label) { + return NO_ITEM_SCORE; // we need a label at least + } + + const description = accessor.getItemDescription(item); + + let cacheHash: string; + if (description) { + cacheHash = `${label}${description}${query.value}${fuzzy}`; + } else { + cacheHash = `${label}${query.value}${fuzzy}`; + } + + const cached = cache[cacheHash]; + if (cached) { + return cached; + } + + const itemScore = doScoreItem(label, description, accessor.getItemPath(item), query, fuzzy); + cache[cacheHash] = itemScore; + + return itemScore; +} + +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.value, path, true)) { + return { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : void 0 }; + } + + // We only consider label matches if the query is not including file path separators + const preferLabelMatches = !path || !query.containsPathSeparator; + if (preferLabelMatches) { + + // 2.) treat prefix matches on the label second highest + const prefixLabelMatch = matchesPrefix(query.value, label); + if (prefixLabelMatch) { + return { score: LABEL_PREFIX_SCORE, labelMatch: prefixLabelMatch }; + } + + // 3.) treat camelcase matches on the label third highest + const camelcaseLabelMatch = matchesCamelCase(query.value, label); + if (camelcaseLabelMatch) { + return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch }; + } + + // 4.) prefer scores on the label if any + const [labelScore, labelPositions] = score(label, query.value, query.lowercase, fuzzy); + if (labelScore) { + return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) }; + } + } + + // 5.) finally compute description + label scores if we have a description + if (description) { + let descriptionPrefix = description; + if (!!path) { + descriptionPrefix = `${description}${nativeSep}`; // assume this is a file path + } + + const descriptionPrefixLength = descriptionPrefix.length; + const descriptionAndLabel = `${descriptionPrefix}${label}`; + + const [labelDescriptionScore, labelDescriptionPositions] = score(descriptionAndLabel, query.value, query.lowercase, fuzzy); + if (labelDescriptionScore) { + const labelDescriptionMatches = createMatches(labelDescriptionPositions); + const labelMatch: IMatch[] = []; + const descriptionMatch: IMatch[] = []; + + // We have to split the matches back onto the label and description portions + labelDescriptionMatches.forEach(h => { + + // Match overlaps label and description part, we need to split it up + if (h.start < descriptionPrefixLength && h.end > descriptionPrefixLength) { + labelMatch.push({ start: 0, end: h.end - descriptionPrefixLength }); + descriptionMatch.push({ start: h.start, end: descriptionPrefixLength }); + } + + // Match on label part + else if (h.start >= descriptionPrefixLength) { + labelMatch.push({ start: h.start - descriptionPrefixLength, end: h.end - descriptionPrefixLength }); + } + + // Match on description part + else { + descriptionMatch.push(h); + } + }); + + return { score: labelDescriptionScore, labelMatch, descriptionMatch }; + } + } + + return NO_ITEM_SCORE; +} + +export function compareItemsByScore(itemA: T, itemB: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor, cache: ScorerCache, fallbackComparer = fallbackCompare): number { + const itemScoreA = scoreItem(itemA, query, fuzzy, accessor, cache); + const itemScoreB = scoreItem(itemB, query, fuzzy, accessor, cache); + + const scoreA = itemScoreA.score; + const scoreB = itemScoreB.score; + + // 1.) prefer identity matches + if (scoreA === PATH_IDENTITY_SCORE || scoreB === PATH_IDENTITY_SCORE) { + if (scoreA !== scoreB) { + return scoreA === PATH_IDENTITY_SCORE ? -1 : 1; + } + } + + // 2.) prefer label prefix matches + if (scoreA === LABEL_PREFIX_SCORE || scoreB === LABEL_PREFIX_SCORE) { + if (scoreA !== scoreB) { + return scoreA === LABEL_PREFIX_SCORE ? -1 : 1; + } + + const labelA = accessor.getItemLabel(itemA); + const labelB = accessor.getItemLabel(itemB); + + // prefer shorter names when both match on label prefix + if (labelA.length !== labelB.length) { + return labelA.length - labelB.length; + } + } + + // 3.) prefer camelcase matches + if (scoreA === LABEL_CAMELCASE_SCORE || scoreB === LABEL_CAMELCASE_SCORE) { + if (scoreA !== scoreB) { + return scoreA === LABEL_CAMELCASE_SCORE ? -1 : 1; + } + + const labelA = accessor.getItemLabel(itemA); + const labelB = accessor.getItemLabel(itemB); + + // prefer more compact camel case matches over longer + const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch); + if (comparedByMatchLength !== 0) { + return comparedByMatchLength; + } + + // prefer shorter names when both match on label camelcase + if (labelA.length !== labelB.length) { + return labelA.length - labelB.length; + } + } + + // 4.) prefer label scores + if (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) { + if (scoreB < LABEL_SCORE_THRESHOLD) { + return -1; + } + + if (scoreA < LABEL_SCORE_THRESHOLD) { + return 1; + } + } + + // 5.) compare by score + if (scoreA !== scoreB) { + return scoreA > scoreB ? -1 : 1; + } + + // 6.) scores are identical, prefer more compact matches (label and description) + const itemAMatchDistance = computeLabelAndDescriptionMatchDistance(itemA, itemScoreA, accessor); + const itemBMatchDistance = computeLabelAndDescriptionMatchDistance(itemB, itemScoreB, accessor); + if (itemAMatchDistance && itemBMatchDistance && itemAMatchDistance !== itemBMatchDistance) { + return itemBMatchDistance > itemAMatchDistance ? -1 : 1; + } + + // 7.) at this point, scores are identical and match compactness as well + // for both items so we start to use the fallback compare + return fallbackComparer(itemA, itemB, query, accessor); +} + +function computeLabelAndDescriptionMatchDistance(item: T, score: IItemScore, accessor: IItemAccessor): number { + const hasLabelMatches = (score.labelMatch && score.labelMatch.length); + const hasDescriptionMatches = (score.descriptionMatch && score.descriptionMatch.length); + + let matchStart: number = -1; + let matchEnd: number = -1; + + // If we have description matches, the start is first of description match + if (hasDescriptionMatches) { + matchStart = score.descriptionMatch[0].start; + } + + // Otherwise, the start is the first label match + else if (hasLabelMatches) { + matchStart = score.labelMatch[0].start; + } + + // If we have label match, the end is the last label match + // If we had a description match, we add the length of the description + // as offset to the end to indicate this. + if (hasLabelMatches) { + matchEnd = score.labelMatch[score.labelMatch.length - 1].end; + if (hasDescriptionMatches) { + const itemDescription = accessor.getItemDescription(item); + if (itemDescription) { + matchEnd += itemDescription.length; + } + } + } + + // If we have just a description match, the end is the last description match + else if (hasDescriptionMatches) { + matchEnd = score.descriptionMatch[score.descriptionMatch.length - 1].end; + } + + return matchEnd - matchStart; +} + +function compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number { + if ((!matchesA && !matchesB) || (!matchesA.length && !matchesB.length)) { + return 0; // make sure to not cause bad comparing when matches are not provided + } + + if (!matchesB || !matchesB.length) { + return -1; + } + + if (!matchesA || !matchesA.length) { + return 1; + } + + // Compute match length of A (first to last match) + const matchStartA = matchesA[0].start; + const matchEndA = matchesA[matchesA.length - 1].end; + const matchLengthA = matchEndA - matchStartA; + + // Compute match length of B (first to last match) + const matchStartB = matchesB[0].start; + const matchEndB = matchesB[matchesB.length - 1].end; + const matchLengthB = matchEndB - matchStartB; + + // Prefer shorter match length + return matchLengthA === matchLengthB ? 0 : matchLengthB < matchLengthA ? 1 : -1; +} + +export function fallbackCompare(itemA: T, itemB: T, query: IPreparedQuery, accessor: IItemAccessor): number { + + // check for label + description length and prefer shorter + const labelA = accessor.getItemLabel(itemA); + const labelB = accessor.getItemLabel(itemB); + + const descriptionA = accessor.getItemDescription(itemA); + const descriptionB = accessor.getItemDescription(itemB); + + const labelDescriptionALength = labelA.length + (descriptionA ? descriptionA.length : 0); + const labelDescriptionBLength = labelB.length + (descriptionB ? descriptionB.length : 0); + + if (labelDescriptionALength !== labelDescriptionBLength) { + return labelDescriptionALength - labelDescriptionBLength; + } + + // check for path length and prefer shorter + const pathA = accessor.getItemPath(itemA); + const pathB = accessor.getItemPath(itemB); + + if (pathA && pathB && pathA.length !== pathB.length) { + return pathA.length - pathB.length; + } + + // 7.) finally we have equal scores and equal length, we fallback to comparer + + // compare by label + if (labelA !== labelB) { + return compareAnything(labelA, labelB, query.value); + } + + // compare by description + if (descriptionA && descriptionB && descriptionA !== descriptionB) { + return compareAnything(descriptionA, descriptionB, query.value); + } + + // compare by path + if (pathA && pathB && pathA !== pathB) { + return compareAnything(pathA, pathB, query.value); + } + + // equal + return 0; +} \ No newline at end of file diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts new file mode 100644 index 00000000000..464967ff845 --- /dev/null +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -0,0 +1,778 @@ +/*--------------------------------------------------------------------------------------------- + * 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 scorer from 'vs/base/parts/quickopen/common/quickOpenScorer'; +import URI from 'vs/base/common/uri'; +import { basename, dirname, nativeSep } from 'vs/base/common/paths'; +import { isWindows } from 'vs/base/common/platform'; + +class ResourceAccessorClass implements scorer.IItemAccessor { + + getItemLabel(resource: URI): string { + return basename(resource.fsPath); + } + + getItemDescription(resource: URI): string { + return dirname(resource.fsPath); + } + + getItemPath(resource: URI): string { + return resource.fsPath; + } +} + +const ResourceAccessor = new ResourceAccessorClass(); + +class NullAccessorClass implements scorer.IItemAccessor { + + getItemLabel(resource: URI): string { + return void 0; + } + + getItemDescription(resource: URI): string { + return void 0; + } + + getItemPath(resource: URI): string { + return void 0; + } +} + +function _doScore(target: string, query: string, fuzzy: boolean): scorer.Score { + return scorer.score(target, query, query.toLowerCase(), fuzzy); +} + +function scoreItem(item: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor, cache: scorer.ScorerCache): scorer.IItemScore { + return scorer.scoreItem(item, scorer.prepareQuery(query), fuzzy, accessor, cache); +} + +function compareItemsByScore(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor, cache: scorer.ScorerCache, fallbackComparer = scorer.fallbackCompare): number { + return scorer.compareItemsByScore(itemA, itemB, scorer.prepareQuery(query), fuzzy, accessor, cache, fallbackComparer); +} + +const NullAccessor = new NullAccessorClass(); +let cache: scorer.ScorerCache = Object.create(null); + +suite('Quick Open Scorer', () => { + + setup(() => { + cache = Object.create(null); + }); + + test('score (fuzzy)', function () { + const target = 'HeLlo-World'; + + const scores: scorer.Score[] = []; + scores.push(_doScore(target, 'HelLo-World', true)); // direct case match + scores.push(_doScore(target, 'hello-world', true)); // direct mix-case match + scores.push(_doScore(target, 'HW', true)); // direct case prefix (multiple) + scores.push(_doScore(target, 'hw', true)); // direct mix-case prefix (multiple) + scores.push(_doScore(target, 'H', true)); // direct case prefix + scores.push(_doScore(target, 'h', true)); // direct mix-case prefix + scores.push(_doScore(target, 'ld', true)); // in-string mix-case match (consecutive, avoids scattered hit) + scores.push(_doScore(target, 'W', true)); // direct case word prefix + scores.push(_doScore(target, 'w', true)); // direct mix-case word prefix + scores.push(_doScore(target, 'Ld', true)); // in-string case match (multiple) + scores.push(_doScore(target, 'L', true)); // in-string case match + scores.push(_doScore(target, 'l', true)); // in-string mix-case match + scores.push(_doScore(target, '4', true)); // no match + + // Assert scoring order + let sortedScores = scores.concat().sort((a, b) => b[0] - a[0]); + assert.deepEqual(scores, sortedScores); + + // Assert scoring positions + let positions = scores[0][1]; + assert.equal(positions.length, 'HelLo-World'.length); + + positions = scores[2][1]; + assert.equal(positions.length, 'HW'.length); + assert.equal(positions[0], 0); + assert.equal(positions[1], 6); + }); + + test('score (non fuzzy)', function () { + const target = 'HeLlo-World'; + + assert.ok(_doScore(target, 'HelLo-World', false)[0] > 0); + assert.equal(_doScore(target, 'HelLo-World', false)[1].length, 'HelLo-World'.length); + + assert.ok(_doScore(target, 'hello-world', false)[0] > 0); + assert.equal(_doScore(target, 'HW', false)[0], 0); + assert.ok(_doScore(target, 'h', false)[0] > 0); + assert.ok(_doScore(target, 'ello', false)[0] > 0); + assert.ok(_doScore(target, 'ld', false)[0] > 0); + assert.equal(_doScore(target, 'eo', false)[0], 0); + }); + + test('scoreItem - matches are proper', function () { + let res = scoreItem(null, 'something', true, ResourceAccessor, cache); + assert.ok(!res.score); + + const resource = URI.file('/xyz/some/path/someFile123.txt'); + + res = scoreItem(resource, 'something', true, NullAccessor, cache); + assert.ok(!res.score); + + // Path Identity + const identityRes = scoreItem(resource, ResourceAccessor.getItemPath(resource), true, ResourceAccessor, cache); + assert.ok(identityRes.score); + assert.equal(identityRes.descriptionMatch.length, 1); + assert.equal(identityRes.labelMatch.length, 1); + assert.equal(identityRes.descriptionMatch[0].start, 0); + assert.equal(identityRes.descriptionMatch[0].end, ResourceAccessor.getItemDescription(resource).length); + assert.equal(identityRes.labelMatch[0].start, 0); + assert.equal(identityRes.labelMatch[0].end, ResourceAccessor.getItemLabel(resource).length); + + // Basename Prefix + const basenamePrefixRes = scoreItem(resource, 'som', true, ResourceAccessor, cache); + assert.ok(basenamePrefixRes.score); + assert.ok(!basenamePrefixRes.descriptionMatch); + assert.equal(basenamePrefixRes.labelMatch.length, 1); + assert.equal(basenamePrefixRes.labelMatch[0].start, 0); + assert.equal(basenamePrefixRes.labelMatch[0].end, 'som'.length); + + // Basename Camelcase + const basenameCamelcaseRes = scoreItem(resource, 'sF', true, ResourceAccessor, cache); + assert.ok(basenameCamelcaseRes.score); + assert.ok(!basenameCamelcaseRes.descriptionMatch); + assert.equal(basenameCamelcaseRes.labelMatch.length, 2); + assert.equal(basenameCamelcaseRes.labelMatch[0].start, 0); + assert.equal(basenameCamelcaseRes.labelMatch[0].end, 1); + assert.equal(basenameCamelcaseRes.labelMatch[1].start, 4); + assert.equal(basenameCamelcaseRes.labelMatch[1].end, 5); + + // Basename Match + const basenameRes = scoreItem(resource, 'of', true, ResourceAccessor, cache); + assert.ok(basenameRes.score); + assert.ok(!basenameRes.descriptionMatch); + assert.equal(basenameRes.labelMatch.length, 2); + assert.equal(basenameRes.labelMatch[0].start, 1); + assert.equal(basenameRes.labelMatch[0].end, 2); + assert.equal(basenameRes.labelMatch[1].start, 4); + assert.equal(basenameRes.labelMatch[1].end, 5); + + // Path Match + const pathRes = scoreItem(resource, 'xyz123', true, ResourceAccessor, cache); + assert.ok(pathRes.score); + assert.ok(pathRes.descriptionMatch); + assert.ok(pathRes.labelMatch); + assert.equal(pathRes.labelMatch.length, 1); + assert.equal(pathRes.labelMatch[0].start, 8); + assert.equal(pathRes.labelMatch[0].end, 11); + assert.equal(pathRes.descriptionMatch.length, 1); + assert.equal(pathRes.descriptionMatch[0].start, 1); + assert.equal(pathRes.descriptionMatch[0].end, 4); + + // No Match + const noRes = scoreItem(resource, '987', true, ResourceAccessor, cache); + assert.ok(!noRes.score); + assert.ok(!noRes.labelMatch); + assert.ok(!noRes.descriptionMatch); + + // Verify Scores + assert.ok(identityRes.score > basenamePrefixRes.score); + assert.ok(basenamePrefixRes.score > basenameRes.score); + assert.ok(basenameRes.score > pathRes.score); + assert.ok(pathRes.score > noRes.score); + }); + + test('scoreItem - invalid input', function () { + + let res = scoreItem(null, null, true, ResourceAccessor, cache); + assert.equal(res.score, 0); + + res = scoreItem(null, 'null', true, ResourceAccessor, cache); + assert.equal(res.score, 0); + }); + + test('scoreItem - optimize for file paths', function () { + const resource = URI.file('/xyz/others/spath/some/xsp/file123.txt'); + + // xsp is more relevant to the end of the file path even though it matches + // fuzzy also in the beginning. we verify the more relevant match at the + // end gets returned. + const pathRes = scoreItem(resource, 'xspfile123', true, ResourceAccessor, cache); + assert.ok(pathRes.score); + assert.ok(pathRes.descriptionMatch); + assert.ok(pathRes.labelMatch); + assert.equal(pathRes.labelMatch.length, 1); + assert.equal(pathRes.labelMatch[0].start, 0); + assert.equal(pathRes.labelMatch[0].end, 7); + assert.equal(pathRes.descriptionMatch.length, 1); + assert.equal(pathRes.descriptionMatch[0].start, 23); + assert.equal(pathRes.descriptionMatch[0].end, 26); + }); + + test('scoreItem - avoid match scattering (bug #36119)', function () { + const resource = URI.file('projects/ui/cula/ats/target.mk'); + + const pathRes = scoreItem(resource, 'tcltarget.mk', true, ResourceAccessor, cache); + assert.ok(pathRes.score); + assert.ok(pathRes.descriptionMatch); + assert.ok(pathRes.labelMatch); + assert.equal(pathRes.labelMatch.length, 1); + assert.equal(pathRes.labelMatch[0].start, 0); + assert.equal(pathRes.labelMatch[0].end, 9); + }); + + test('scoreItem - prefers more compact matches', function () { + const resource = URI.file('/1a111d1/11a1d1/something.txt'); + + // expect "ad" to be matched towards the end of the file because the + // match is more compact + const res = scoreItem(resource, 'ad', true, ResourceAccessor, cache); + assert.ok(res.score); + assert.ok(res.descriptionMatch); + assert.ok(!res.labelMatch.length); + assert.equal(res.descriptionMatch.length, 2); + assert.equal(res.descriptionMatch[0].start, 11); + assert.equal(res.descriptionMatch[0].end, 12); + assert.equal(res.descriptionMatch[1].start, 13); + assert.equal(res.descriptionMatch[1].end, 14); + }); + + test('compareItemsByScore - identity', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileB.txt'); + const resourceC = URI.file('/unrelated/some/path/other/fileC.txt'); + + // Full resource A path + let query = ResourceAccessor.getItemPath(resourceA); + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + // Full resource B path + query = ResourceAccessor.getItemPath(resourceB); + + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - basename prefix', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileB.txt'); + const resourceC = URI.file('/unrelated/some/path/other/fileC.txt'); + + // Full resource A basename + let query = ResourceAccessor.getItemLabel(resourceA); + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + // Full resource B basename + query = ResourceAccessor.getItemLabel(resourceB); + + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - basename camelcase', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileB.txt'); + const resourceC = URI.file('/unrelated/some/path/other/fileC.txt'); + + // resource A camelcase + let query = 'fA'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + // resource B camelcase + query = 'fB'; + + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - basename scores', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileB.txt'); + const resourceC = URI.file('/unrelated/some/path/other/fileC.txt'); + + // Resource A part of basename + let query = 'fileA'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + // Resource B part of basename + query = 'fileB'; + + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - path scores', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileB.txt'); + const resourceC = URI.file('/unrelated/some/path/other/fileC.txt'); + + // Resource A part of path + let query = 'pathfileA'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + // Resource B part of path + query = 'pathfileB'; + + res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - prefer shorter basenames', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileBLonger.txt'); + const resourceC = URI.file('/unrelated/the/path/other/fileC.txt'); + + // Resource A part of path + let query = 'somepath'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - prefer shorter basenames (match on basename)', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileBLonger.txt'); + const resourceC = URI.file('/unrelated/the/path/other/fileC.txt'); + + // Resource A part of path + let query = 'file'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceC); + assert.equal(res[2], resourceB); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceC); + assert.equal(res[2], resourceB); + }); + + test('compareFilesByScore - prefer shorter paths', function () { + const resourceA = URI.file('/some/path/fileA.txt'); + const resourceB = URI.file('/some/path/other/fileB.txt'); + const resourceC = URI.file('/unrelated/some/path/other/fileC.txt'); + + // Resource A part of path + let query = 'somepath'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - prefer shorter paths (bug #17443)', function () { + const resourceA = URI.file('config/test/t1.js'); + const resourceB = URI.file('config/test.js'); + const resourceC = URI.file('config/test/t2.js'); + + let query = 'co/te'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + assert.equal(res[2], resourceC); + }); + + test('compareFilesByScore - allow to provide fallback sorter (bug #31591)', function () { + const resourceA = URI.file('virtual/vscode.d.ts'); + const resourceB = URI.file('vscode/src/vs/vscode.d.ts'); + + let query = 'vscode'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - prefer more compact camel case matches', function () { + const resourceA = URI.file('config/test/openthisAnythingHandler.js'); + const resourceB = URI.file('config/test/openthisisnotsorelevantforthequeryAnyHand.js'); + + let query = 'AH'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - prefer more compact matches (label)', function () { + const resourceA = URI.file('config/test/examasdaple.js'); + const resourceB = URI.file('config/test/exampleasdaasd.ts'); + + let query = 'xp'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - prefer more compact matches (path)', function () { + const resourceA = URI.file('config/test/examasdaple/file.js'); + const resourceB = URI.file('config/test/exampleasdaasd/file.ts'); + + let query = 'xp'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - prefer more compact matches (label and path)', function () { + const resourceA = URI.file('config/example/thisfile.ts'); + const resourceB = URI.file('config/24234243244/example/file.js'); + + let query = 'exfile'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + assert.equal(res[1], resourceA); + }); + + test('compareFilesByScore - avoid match scattering (bug #34210)', function () { + const resourceA = URI.file('node_modules1/bundle/lib/model/modules/ot1/index.js'); + const resourceB = URI.file('node_modules1/bundle/lib/model/modules/un1/index.js'); + const resourceC = URI.file('node_modules1/bundle/lib/model/modules/modu1/index.js'); + const resourceD = URI.file('node_modules1/bundle/lib/model/modules/oddl1/index.js'); + + let query = isWindows ? 'modu1\\index.js' : 'modu1/index.js'; + + let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + + res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + + query = isWindows ? 'un1\\index.js' : 'un1/index.js'; + + res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #21019 1.)', function () { + const resourceA = URI.file('app/containers/Services/NetworkData/ServiceDetails/ServiceLoad/index.js'); + const resourceB = URI.file('app/containers/Services/NetworkData/ServiceDetails/ServiceDistribution/index.js'); + const resourceC = URI.file('app/containers/Services/NetworkData/ServiceDetailTabs/ServiceTabs/StatVideo/index.js'); + + let query = 'StatVideoindex'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + }); + + test('compareFilesByScore - avoid match scattering (bug #21019 2.)', function () { + const resourceA = URI.file('src/build-helper/store/redux.ts'); + const resourceB = URI.file('src/repository/store/redux.ts'); + + let query = 'reproreduxts'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #26649)', function () { + const resourceA = URI.file('photobook/src/components/AddPagesButton/index.js'); + const resourceB = URI.file('photobook/src/components/ApprovalPageHeader/index.js'); + const resourceC = URI.file('photobook/src/canvasComponents/BookPage/index.js'); + + let query = 'bookpageIndex'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceC); + }); + + test('compareFilesByScore - avoid match scattering (bug #33247)', function () { + const resourceA = URI.file('ui/src/utils/constants.js'); + const resourceB = URI.file('ui/src/ui/Icons/index.js'); + + let query = isWindows ? 'ui\\icons' : 'ui/icons'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #33247 comment)', function () { + const resourceA = URI.file('ui/src/components/IDInput/index.js'); + const resourceB = URI.file('ui/src/ui/Input/index.js'); + + let query = isWindows ? 'ui\\input\\index' : 'ui/input/index'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #36166)', function () { + const resourceA = URI.file('django/contrib/sites/locale/ga/LC_MESSAGES/django.mo'); + const resourceB = URI.file('django/core/signals.py'); + + let query = 'djancosig'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #32918)', function () { + const resourceA = URI.file('adsys/protected/config.php'); + const resourceB = URI.file('adsys/protected/framework/smarty/sysplugins/smarty_internal_config.php'); + const resourceC = URI.file('duowanVideo/wap/protected/config.php'); + + let query = 'protectedconfig.php'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceC); + assert.equal(res[2], resourceB); + + res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceA); + assert.equal(res[1], resourceC); + assert.equal(res[2], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #14879)', function () { + const resourceA = URI.file('pkg/search/gradient/testdata/constraint_attrMatchString.yml'); + const resourceB = URI.file('cmd/gradient/main.go'); + + let query = 'gradientmain'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #14727 1)', function () { + const resourceA = URI.file('alpha-beta-cappa.txt'); + const resourceB = URI.file('abc.txt'); + + let query = 'abc'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #14727 2)', function () { + const resourceA = URI.file('xerxes-yak-zubba/index.js'); + const resourceB = URI.file('xyz/index.js'); + + let query = 'xyz'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #18381)', function () { + const resourceA = URI.file('AssymblyInfo.cs'); + const resourceB = URI.file('IAsynchronousTask.java'); + + let query = 'async'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #35572)', function () { + const resourceA = URI.file('static/app/source/angluar/-admin/-organization/-settings/layout/layout.js'); + const resourceB = URI.file('static/app/source/angular/-admin/-project/-settings/_settings/settings.js'); + + let query = 'partisettings'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #36810)', function () { + const resourceA = URI.file('Trilby.TrilbyTV.Web.Portal/Views/Systems/Index.cshtml'); + const resourceB = URI.file('Trilby.TrilbyTV.Web.Portal/Areas/Admins/Views/Tips/Index.cshtml'); + + let query = 'tipsindex.cshtml'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - prefer shorter hit (bug #20546)', function () { + const resourceA = URI.file('editor/core/components/tests/list-view-spec.js'); + const resourceB = URI.file('editor/core/components/list-view.js'); + + let query = 'listview'; + + let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('compareFilesByScore - avoid match scattering (bug #12095)', function () { + const resourceA = URI.file('src/vs/workbench/parts/files/common/explorerViewModel.ts'); + const resourceB = URI.file('src/vs/workbench/parts/files/browser/views/explorerView.ts'); + const resourceC = URI.file('src/vs/workbench/parts/files/browser/views/explorerViewer.ts'); + + let query = 'filesexplorerview.ts'; + + let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + + res = [resourceA, resourceC, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache)); + assert.equal(res[0], resourceB); + }); + + test('prepareSearchForScoring', function () { + assert.equal(scorer.prepareQuery(' f*a ').value, 'fa'); + assert.equal(scorer.prepareQuery('model Tester.ts').value, 'modelTester.ts'); + assert.equal(scorer.prepareQuery('Model Tester.ts').lowercase, 'modeltester.ts'); + assert.equal(scorer.prepareQuery('ModelTester.ts').containsPathSeparator, false); + assert.equal(scorer.prepareQuery('Model' + nativeSep + 'Tester.ts').containsPathSeparator, true); + }); +}); \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/tree.ts b/src/vs/base/parts/tree/browser/tree.ts index e8bae236d8d..5deb416f417 100644 --- a/src/vs/base/parts/tree/browser/tree.ts +++ b/src/vs/base/parts/tree/browser/tree.ts @@ -101,6 +101,13 @@ export interface ITree extends Events.IEventEmitter { */ collapseAll(elements?: any[], recursive?: boolean): WinJS.Promise; + /** + * Collapses several elements. + * Collapses all elements at the greatest tree depth that has expanded elements. + * The returned promise returns a boolean for whether the elements were collapsed or not. + */ + collapseDeepestExpandedLevel(): WinJS.Promise; + /** * Toggles an element's expansion state. */ diff --git a/src/vs/base/parts/tree/browser/treeImpl.ts b/src/vs/base/parts/tree/browser/treeImpl.ts index 2c18c5700fb..0397e0171f4 100644 --- a/src/vs/base/parts/tree/browser/treeImpl.ts +++ b/src/vs/base/parts/tree/browser/treeImpl.ts @@ -64,8 +64,6 @@ const defaultStyles: _.ITreeStyles = { export class Tree extends Events.EventEmitter implements _.ITree { private container: HTMLElement; - private configuration: _.ITreeConfiguration; - private options: _.ITreeOptions; private context: _.ITreeContext; private model: Model.TreeModel; @@ -87,16 +85,14 @@ export class Tree extends Events.EventEmitter implements _.ITree { this.toDispose.push(this._onDispose, this._onHighlightChange); this.container = container; - this.configuration = configuration; - this.options = options; - mixin(this.options, defaultStyles, false); + mixin(options, defaultStyles, false); - this.options.twistiePixels = typeof this.options.twistiePixels === 'number' ? this.options.twistiePixels : 32; - this.options.showTwistie = this.options.showTwistie === false ? false : true; - this.options.indentPixels = typeof this.options.indentPixels === 'number' ? this.options.indentPixels : 12; - this.options.alwaysFocused = this.options.alwaysFocused === true ? true : false; - this.options.useShadows = this.options.useShadows === false ? false : true; - this.options.paddingOnRow = this.options.paddingOnRow === false ? false : true; + options.twistiePixels = typeof options.twistiePixels === 'number' ? options.twistiePixels : 32; + options.showTwistie = options.showTwistie === false ? false : true; + options.indentPixels = typeof options.indentPixels === 'number' ? options.indentPixels : 12; + options.alwaysFocused = options.alwaysFocused === true ? true : false; + options.useShadows = options.useShadows === false ? false : true; + options.paddingOnRow = options.paddingOnRow === false ? false : true; this.context = new TreeContext(this, configuration, options); this.model = new Model.TreeModel(this.context); @@ -186,6 +182,10 @@ export class Tree extends Events.EventEmitter implements _.ITree { return this.model.collapseAll(elements, recursive); } + public collapseDeepestExpandedLevel(): WinJS.Promise { + return this.model.collapseDeepestExpandedLevel(); + } + public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise { return this.model.toggleExpansion(element, recursive); } diff --git a/src/vs/base/parts/tree/browser/treeModel.ts b/src/vs/base/parts/tree/browser/treeModel.ts index 1c5623fab9e..cfeafa0b078 100644 --- a/src/vs/base/parts/tree/browser/treeModel.ts +++ b/src/vs/base/parts/tree/browser/treeModel.ts @@ -206,8 +206,6 @@ export class Item extends Events.EventEmitter { public firstChild: Item; public lastChild: Item; - private userContent: HTMLElement; - private height: number; private depth: number; @@ -238,7 +236,6 @@ export class Item extends Events.EventEmitter { this.firstChild = null; this.lastChild = null; - this.userContent = null; this.traits = {}; this.depth = 0; this.expanded = this.context.dataSource.shouldAutoexpand && this.context.dataSource.shouldAutoexpand(this.context.tree, element); @@ -486,6 +483,17 @@ export class Item extends Events.EventEmitter { return result; } + public getChildren(): Item[] { + var child = this.firstChild; + var results = []; + while (child) { + results.push(child); + child = child.next; + } + + return results; + } + private isAncestorOf(item: Item): boolean { while (item) { if (item.id === this.id) { @@ -894,6 +902,27 @@ export class TreeModel extends Events.EventEmitter { return WinJS.Promise.join(promises); } + public collapseDeepestExpandedLevel(): WinJS.Promise { + var levelToCollapse = this.findDeepestExpandedLevel(this.input, 0); + + var items = [this.input]; + for (var i = 0; i < levelToCollapse; i++) { + items = arrays.flatten(items.map(node => node.getChildren())); + } + + var promises = items.map(child => this.collapse(child, false)); + return WinJS.Promise.join(promises); + } + + private findDeepestExpandedLevel(item: Item, currentLevel: number): number { + var expandedChildren = item.getChildren().filter(child => child.isExpanded()); + if (!expandedChildren.length) { + return currentLevel; + } + + return Math.max(...expandedChildren.map(child => this.findDeepestExpandedLevel(child, currentLevel + 1))); + } + public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise { return this.isExpanded(element) ? this.collapse(element, recursive) : this.expand(element); } diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index ac5ba32ad5c..2aea91d703f 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -392,8 +392,6 @@ export class TreeView extends HeightMap { private isRefreshing = false; private refreshingPreviousChildrenIds: { [id: string]: string[] } = {}; - - private dragAndDropListeners: { (): void; }[]; private currentDragAndDropData: _.IDragAndDropData; private currentDropElement: any; private currentDropElementReaction: _.IDragOverReaction; @@ -437,7 +435,6 @@ export class TreeView extends HeightMap { this.modelListeners = []; this.viewListeners = []; - this.dragAndDropListeners = []; this.model = null; this.items = {}; diff --git a/src/vs/base/parts/tree/browser/treeViewModel.ts b/src/vs/base/parts/tree/browser/treeViewModel.ts index f0434f5488a..fb4e6530932 100644 --- a/src/vs/base/parts/tree/browser/treeViewModel.ts +++ b/src/vs/base/parts/tree/browser/treeViewModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { IIterator, ArrayIterator } from 'vs/base/common/iterator'; +import { INextIterator, ArrayIterator } from 'vs/base/common/iterator'; import { Item } from './treeModel'; export interface IViewItem { @@ -30,7 +30,7 @@ export class HeightMap extends EventEmitter { return !last ? 0 : last.top + last.height; } - public onInsertItems(iterator: IIterator, afterItemId: string = null): number { + public onInsertItems(iterator: INextIterator, afterItemId: string = null): number { var item: Item; var viewItem: IViewItem; var i: number, j: number; @@ -90,7 +90,7 @@ export class HeightMap extends EventEmitter { } // Contiguous items - public onRemoveItems(iterator: IIterator): void { + public onRemoveItems(iterator: INextIterator): void { var itemId: string; var viewItem: IViewItem; var startIndex: number = null; @@ -139,7 +139,7 @@ export class HeightMap extends EventEmitter { } // Ordered, but not necessarily contiguous items - public onRefreshItems(iterator: IIterator): void { + public onRefreshItems(iterator: INextIterator): void { var item: Item; var viewItem: IViewItem; var newHeight: number; @@ -240,4 +240,4 @@ export class HeightMap extends EventEmitter { this.heightMap = null; this.indexes = null; } -} \ No newline at end of file +} diff --git a/src/vs/base/parts/tree/test/browser/treeModel.test.ts b/src/vs/base/parts/tree/test/browser/treeModel.test.ts index 29ad69af4e8..e6bdfae1691 100644 --- a/src/vs/base/parts/tree/test/browser/treeModel.test.ts +++ b/src/vs/base/parts/tree/test/browser/treeModel.test.ts @@ -7,7 +7,6 @@ import assert = require('assert'); import lifecycle = require('vs/base/common/lifecycle'); -import ee = require('vs/base/common/eventEmitter'); import _ = require('vs/base/parts/tree/browser/tree'); import WinJS = require('vs/base/common/winjs.base'); import Events = require('vs/base/common/eventEmitter'); @@ -75,7 +74,7 @@ class EventCounter { this._count = 0; } - public listen(emitter: ee.IEventEmitter, event: string, fn: (e) => void = null): () => void { + public listen(emitter: Events.IEventEmitter, event: string, fn: (e) => void = null): () => void { let r = emitter.addListener(event, (e) => { this._count++; if (fn) { @@ -636,6 +635,24 @@ suite('TreeModel - Expansion', () => { }); }); + test('collapseDeepestExpandedLevel', (done) => { + model.setInput(SAMPLE.DEEP2).done(() => { + model.expand(SAMPLE.DEEP2.children[0]).done(() => { + model.expand(SAMPLE.DEEP2.children[0].children[0]).done(() => { + + assert(model.isExpanded(SAMPLE.DEEP2.children[0])); + assert(model.isExpanded(SAMPLE.DEEP2.children[0].children[0])); + + model.collapseDeepestExpandedLevel().done(() => { + assert(model.isExpanded(SAMPLE.DEEP2.children[0])); + assert(!model.isExpanded(SAMPLE.DEEP2.children[0].children[0])); + done(); + }); + }); + }); + }); + }); + test('auto expand single child folders', (done) => { model.setInput(SAMPLE.DEEP).done(() => { model.expand(SAMPLE.DEEP.children[0]).done(() => { @@ -1423,12 +1440,10 @@ suite('TreeModel - Dynamic data model', () => { var gotTimes = 0; var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; }); - var p1, p2; - var p1Completes = []; dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p1Completes.push(c); }); }; - p1 = model.refresh('grandfather'); + model.refresh('grandfather'); // just a single get assert.equal(refreshTimes, 1); // (+1) grandfather @@ -1445,7 +1460,7 @@ suite('TreeModel - Dynamic data model', () => { var p2Complete; dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p2Complete = c; }); }; - p2 = model.refresh('father'); + var p2 = model.refresh('father'); // same situation still assert.equal(refreshTimes, 3); // (+1) second father refresh @@ -1500,13 +1515,12 @@ suite('TreeModel - Dynamic data model', () => { var gotTimes = 0; var getListener = dataModel.addListener('getChildren', (element) => { getTimes++; }); var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; }); - - var p1, p2; + var p2; var p1Complete; dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p1Complete = c; }); }; - p1 = model.refresh('father'); + model.refresh('father'); assert.equal(getTimes, 1); assert.equal(gotTimes, 0); @@ -1724,7 +1738,7 @@ suite('TreeModel - bugs', () => { }).done(() => { // teardown - while (listeners.length > 0) { listeners.pop()(); }; + while (listeners.length > 0) { listeners.pop()(); } listeners = null; model.dispose(); model = null; diff --git a/src/vs/base/test/browser/builder.test.ts b/src/vs/base/test/browser/builder.test.ts index 99c3f4ec4ee..b6e496b7277 100644 --- a/src/vs/base/test/browser/builder.test.ts +++ b/src/vs/base/test/browser/builder.test.ts @@ -22,7 +22,7 @@ let withElementsBySelector = function (selector: string, offdom: boolean = false return new MultiBuilder(builders); }; -let withBuilder = function (builder, offdom) { +let withBuilder = function (builder: Builder, offdom: boolean) { if (builder instanceof MultiBuilder) { return new MultiBuilder(builder); } @@ -107,7 +107,7 @@ suite('Builder', () => { assert(allDivs instanceof MultiBuilder); for (let key in b) { - if (b.hasOwnProperty(key) && Types.isFunction(b[key])) { + if (b.hasOwnProperty(key) && Types.isFunction((b as any)[key])) { assert(allDivs.hasOwnProperty(key)); } } @@ -121,7 +121,7 @@ suite('Builder', () => { assert(noElement instanceof MultiBuilder); for (let key in b) { - if (b.hasOwnProperty(key) && Types.isFunction(b[key])) { + if (b.hasOwnProperty(key) && Types.isFunction((b as any)[key])) { assert(noElement.hasOwnProperty(key)); } } @@ -381,15 +381,15 @@ suite('Builder', () => { test('Builder Multibuilder fn call that returns Multibuilder', function () { let b = Build.withElementById(fixtureId); - b.div(function (div) { + b.div(function (div: Builder) { div.span(); }); - b.div(function (div) { + b.div(function (div: Builder) { div.span(); }); - b.div(function (div) { + b.div(function (div: Builder) { div.span(); }); @@ -402,13 +402,13 @@ suite('Builder', () => { test('Builder.p() and other elements', function () { let b = Build.withElementById(fixtureId); b.empty(); - b.div(function (div) { + b.div(function (div: Builder) { assert(div !== b); assert.strictEqual('div', div.getHTMLElement().nodeName.toLowerCase()); - div.p(function (p) { - p.ul(function (ul) { - ul.li(function (li) { + div.p(function (p: Builder) { + p.ul(function (ul: Builder) { + ul.li(function (li: Builder) { li.span({ id: 'builderspan', innerHtml: 'Foo Bar' @@ -485,10 +485,10 @@ suite('Builder', () => { test('Builder.p() and other elements', function () { let b = Build.withElementById(fixtureId); - b.element('div', function (div) { - div.element('p', function (p) { - p.element('ul', function (ul) { - ul.element('li', function (li) { + b.element('div', function (div: Builder) { + div.element('p', function (p: Builder) { + p.element('ul', function (ul: Builder) { + ul.element('li', function (li: Builder) { li.element('span', { id: 'builderspan', innerHtml: 'Foo Bar' @@ -908,7 +908,7 @@ suite('Builder', () => { assert(b.children().length === 0); let divB; - b.div(function (div) { + b.div(function (div: Builder) { divB = div.clone(); div.span(); }); @@ -1018,7 +1018,7 @@ suite('Builder', () => { type: 'button' }); - let listeners = []; + let listeners: Builder[] = []; let counter = 0; b.on(DomUtils.EventType.CLICK, function (e) { counter++; @@ -1042,7 +1042,7 @@ suite('Builder', () => { type: 'button' }); - let listeners = []; + let listeners: Builder[] = []; let counter = 0; b.on(DomUtils.EventType.CLICK, function (e) { counter++; @@ -1064,8 +1064,8 @@ suite('Builder', () => { }); test('Builder.empty()', function () { - let inputs = []; - let bindings = []; + let inputs: Builder[] = []; + let bindings: Builder[] = []; let b = Build.withElementById(fixtureId); let counter1 = 0; @@ -1076,33 +1076,33 @@ suite('Builder', () => { let counter6 = 0; let counter7 = 0; - b.div(function (div) { + b.div(function (div: Builder) { div.bind('Foo Bar'); div.setProperty('Foo', 'Bar'); bindings.push(div.clone()); div.element('input', { type: 'button' - }).on(DomUtils.EventType.CLICK, function (e) { + }).on(DomUtils.EventType.CLICK, function () { counter1++; assert(counter1 <= 1); }); inputs.push(div.clone()); - div.p(function (p) { + div.p(function (p: Builder) { p.bind('Foo Bar'); p.setProperty('Foo', 'Bar'); bindings.push(p.clone()); p.element('input', { type: 'button' - }).on(DomUtils.EventType.CLICK, function (e) { + }).on(DomUtils.EventType.CLICK, function () { counter2++; assert(counter2 <= 1); }); inputs.push(p.clone()); - p.ul(function (ul) { + p.ul(function (ul: Builder) { ul.bind('Foo Bar'); ul.setProperty('Foo', 'Bar'); bindings.push(ul.clone()); @@ -1115,7 +1115,7 @@ suite('Builder', () => { }); inputs.push(ul.clone()); - ul.li(function (li) { + ul.li(function (li: Builder) { li.bind('Foo Bar'); li.setProperty('Foo', 'Bar'); bindings.push(li.clone()); @@ -1220,7 +1220,7 @@ suite('Builder', () => { let old = DomUtils.addDisposableListener; try { - (DomUtils as any).addDisposableListener = function (node, type, handler) { + (DomUtils as any).addDisposableListener = function (node: any, type: any, handler: any) { let unbind: IDisposable = old.call(null, node, type, handler); return { @@ -1231,13 +1231,13 @@ suite('Builder', () => { }; }; - b.div(function (div) { - div.p(function (p) { + b.div(function (div: Builder) { + div.p(function (p: Builder) { p.span().on([DomUtils.EventType.CLICK, DomUtils.EventType.KEY_DOWN], function (e) { }); p.img().on([DomUtils.EventType.KEY_PRESS, DomUtils.EventType.MOUSE_OUT], function (e) { }, null, true); // useCapture - p.a(function (a) { + p.a(function (a: Builder) { a.span().on([DomUtils.EventType.CLICK, DomUtils.EventType.KEY_DOWN], function (e) { }); }).on([DomUtils.EventType.SELECT, DomUtils.EventType.BLUR], function (e) { }); }); @@ -1251,8 +1251,8 @@ suite('Builder', () => { }); test('Builder.destroy()', function () { - let inputs = []; - let bindings = []; + let inputs: Builder[] = []; + let bindings: Builder[] = []; let b = Build.withElementById(fixtureId); let counter1 = 0; @@ -1263,7 +1263,7 @@ suite('Builder', () => { let counter6 = 0; let counter7 = 0; - b.div(function (div) { + b.div(function (div: Builder) { div.bind('Foo Bar'); div.setProperty('Foo', 'Bar'); bindings.push(div.clone()); @@ -1276,7 +1276,7 @@ suite('Builder', () => { }, null, true); // useCapture inputs.push(div.clone()); - div.p(function (p) { + div.p(function (p: Builder) { p.bind('Foo Bar'); p.setProperty('Foo', 'Bar'); bindings.push(p.clone()); @@ -1289,7 +1289,7 @@ suite('Builder', () => { }); inputs.push(p.clone()); - p.ul(function (ul) { + p.ul(function (ul: Builder) { ul.bind('Foo Bar'); ul.setProperty('Foo', 'Bar'); bindings.push(ul.clone()); @@ -1302,14 +1302,14 @@ suite('Builder', () => { }); inputs.push(ul.clone()); - ul.li(function (li) { + ul.li(function (li: Builder) { li.bind('Foo Bar'); li.setProperty('Foo', 'Bar'); bindings.push(li.clone()); li.element('input', { type: 'button' - }).on(DomUtils.EventType.CLICK, function (e) { + }).on(DomUtils.EventType.CLICK, function () { counter4++; assert(counter4 <= 1); }); @@ -1407,7 +1407,7 @@ suite('Builder', () => { let old = DomUtils.addDisposableListener; try { - (DomUtils as any).addDisposableListener = function (node, type, handler) { + (DomUtils as any).addDisposableListener = function (node: any, type: any, handler: any) { let unbind: IDisposable = old.call(null, node, type, handler); return { @@ -1418,13 +1418,13 @@ suite('Builder', () => { }; }; - b.div(function (div) { - div.p(function (p) { + b.div(function (div: Builder) { + div.p(function (p: Builder) { p.span().on([DomUtils.EventType.CLICK, DomUtils.EventType.KEY_DOWN], function (e) { }); p.img().on([DomUtils.EventType.KEY_PRESS, DomUtils.EventType.MOUSE_OUT], function (e) { }); - p.a(function (a) { + p.a(function (a: Builder) { a.span().on([DomUtils.EventType.CLICK, DomUtils.EventType.KEY_DOWN], function (e) { }); }).on([DomUtils.EventType.SELECT, DomUtils.EventType.BLUR], function (e) { }); }); @@ -1441,13 +1441,13 @@ suite('Builder', () => { test('Builder.empty() MultiBuilder', function () { let b = Build.withElementById(fixtureId); - let inputs = []; + let inputs: Builder[] = []; let firstCounter = 0; - b.div(function (div) { + b.div(function (div: Builder) { div.element('input', { type: 'button' - }).on(DomUtils.EventType.CLICK, function (e) { + }).on(DomUtils.EventType.CLICK, function () { firstCounter++; }); @@ -1455,10 +1455,10 @@ suite('Builder', () => { }); let secondCounter = 0; - b.div(function (div) { + b.div(function (div: Builder) { div.element('input', { type: 'button' - }).on(DomUtils.EventType.CLICK, function (e) { + }).on(DomUtils.EventType.CLICK, function () { secondCounter++; }); @@ -1466,10 +1466,10 @@ suite('Builder', () => { }); let thirdCounter = 0; - b.div(function (div) { + b.div(function (div: Builder) { div.element('input', { type: 'button' - }).on(DomUtils.EventType.CLICK, function (e) { + }).on(DomUtils.EventType.CLICK, function () { thirdCounter++; }); diff --git a/src/vs/base/test/browser/dom.test.ts b/src/vs/base/test/browser/dom.test.ts index 4b8239985f1..012be3b61be 100644 --- a/src/vs/base/test/browser/dom.test.ts +++ b/src/vs/base/test/browser/dom.test.ts @@ -86,11 +86,11 @@ suite('dom', () => { //}); test('safeStringify', function () { - let obj1 = { + let obj1: any = { friend: null }; - let obj2 = { + let obj2: any = { friend: null }; @@ -100,7 +100,7 @@ suite('dom', () => { let arr: any = [1]; arr.push(arr); - let circular = { + let circular: any = { a: 42, b: null, c: [ diff --git a/src/vs/base/test/browser/htmlContent.test.ts b/src/vs/base/test/browser/htmlContent.test.ts index dcd1c4d5afb..b91068ae15e 100644 --- a/src/vs/base/test/browser/htmlContent.test.ts +++ b/src/vs/base/test/browser/htmlContent.test.ts @@ -10,7 +10,7 @@ import { renderMarkdown, renderText, renderFormattedText } from 'vs/base/browser suite('HtmlContent', () => { test('render simple element', () => { - var result: HTMLElement = renderText('testing'); + var result: HTMLElement = renderText('testing'); assert.strictEqual(result.nodeType, document.ELEMENT_NODE); assert.strictEqual(result.textContent, 'testing'); @@ -18,7 +18,7 @@ suite('HtmlContent', () => { }); test('render element with class', () => { - var result: HTMLElement = renderText('testing', { + var result: HTMLElement = renderText('testing', { className: 'testClass' }); assert.strictEqual(result.nodeType, document.ELEMENT_NODE); @@ -26,32 +26,32 @@ suite('HtmlContent', () => { }); test('simple formatting', () => { - var result: HTMLElement = renderFormattedText('**bold**'); + var result: HTMLElement = renderFormattedText('**bold**'); assert.strictEqual(result.children.length, 1); assert.strictEqual(result.firstChild.textContent, 'bold'); assert.strictEqual((result.firstChild).tagName, 'B'); assert.strictEqual(result.innerHTML, 'bold'); - result = renderFormattedText('__italics__'); + result = renderFormattedText('__italics__'); assert.strictEqual(result.innerHTML, 'italics'); - result = renderFormattedText('this string has **bold** and __italics__'); + result = renderFormattedText('this string has **bold** and __italics__'); assert.strictEqual(result.innerHTML, 'this string has bold and italics'); }); test('no formatting', () => { - var result: HTMLElement = renderFormattedText('this is just a string'); + var result: HTMLElement = renderFormattedText('this is just a string'); assert.strictEqual(result.innerHTML, 'this is just a string'); }); test('preserve newlines', () => { - var result: HTMLElement = renderFormattedText('line one\nline two'); + var result: HTMLElement = renderFormattedText('line one\nline two'); assert.strictEqual(result.innerHTML, 'line one
line two'); }); test('action', () => { var callbackCalled = false; - var result: HTMLElement = renderFormattedText('[[action]]', { + var result: HTMLElement = renderFormattedText('[[action]]', { actionCallback(content) { assert.strictEqual(content, '0'); callbackCalled = true; @@ -67,7 +67,7 @@ suite('HtmlContent', () => { test('fancy action', () => { var callbackCalled = false; - var result: HTMLElement = renderFormattedText('__**[[action]]**__', { + var result: HTMLElement = renderFormattedText('__**[[action]]**__', { actionCallback(content) { assert.strictEqual(content, '0'); callbackCalled = true; @@ -82,13 +82,13 @@ suite('HtmlContent', () => { }); test('escaped formatting', () => { - var result: HTMLElement = renderFormattedText('\\*\\*bold\\*\\*'); + var result: HTMLElement = renderFormattedText('\\*\\*bold\\*\\*'); assert.strictEqual(result.children.length, 0); assert.strictEqual(result.innerHTML, '**bold**'); }); test('image rendering conforms to default', () => { const markdown = { value: `![image](someimageurl 'caption')` }; - const result: HTMLElement = renderMarkdown(markdown); + const result: HTMLElement = renderMarkdown(markdown); const renderer = new marked.Renderer(); const imageFromMarked = marked(markdown.value, { sanitize: true, @@ -98,7 +98,7 @@ suite('HtmlContent', () => { }); test('image rendering conforms to default without title', () => { const markdown = { value: `![image](someimageurl)` }; - const result: HTMLElement = renderMarkdown(markdown); + const result: HTMLElement = renderMarkdown(markdown); const renderer = new marked.Renderer(); const imageFromMarked = marked(markdown.value, { sanitize: true, @@ -107,15 +107,15 @@ suite('HtmlContent', () => { assert.strictEqual(result.innerHTML, imageFromMarked); }); test('image width from title params', () => { - var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|width=100 'caption')` }); + var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|width=100 'caption')` }); assert.strictEqual(result.innerHTML, `

image

`); }); test('image height from title params', () => { - var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=100 'caption')` }); + var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=100 'caption')` }); assert.strictEqual(result.innerHTML, `

image

`); }); test('image width and height from title params', () => { - var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=200,width=100 'caption')` }); + var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=200,width=100 'caption')` }); assert.strictEqual(result.innerHTML, `

image

`); }); }); diff --git a/src/vs/base/test/browser/ui/splitview/splitview.test.ts b/src/vs/base/test/browser/ui/splitview/splitview.test.ts new file mode 100644 index 00000000000..044af37c4eb --- /dev/null +++ b/src/vs/base/test/browser/ui/splitview/splitview.test.ts @@ -0,0 +1,343 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { Emitter } from 'vs/base/common/event'; +import { SplitView, IView, Orientation } from 'vs/base/browser/ui/splitview/splitview'; +import { Sash } from 'vs/base/browser/ui/sash/sash'; + +class TestView implements IView { + + private _onDidChange = new Emitter(); + readonly onDidChange = this._onDidChange.event; + + get minimumSize(): number { return this._minimumSize; } + set minimumSize(size: number) { this._minimumSize = size; this._onDidChange.fire(); } + + get maximumSize(): number { return this._maximumSize; } + set maximumSize(size: number) { this._maximumSize = size; this._onDidChange.fire(); } + + private _onDidRender = new Emitter<{ container: HTMLElement; orientation: Orientation }>(); + readonly onDidRender = this._onDidRender.event; + + private _size = 0; + get size(): number { return this._size; } + private _onDidLayout = new Emitter<{ size: number; orientation: Orientation }>(); + readonly onDidLayout = this._onDidLayout.event; + + private _onDidFocus = new Emitter(); + readonly onDidFocus = this._onDidFocus.event; + + constructor( + private _minimumSize: number, + private _maximumSize: number + ) { + assert(_minimumSize <= _maximumSize, 'splitview view minimum size must be <= maximum size'); + } + + render(container: HTMLElement, orientation: Orientation): void { + this._onDidRender.fire({ container, orientation }); + } + + layout(size: number, orientation: Orientation): void { + this._size = size; + this._onDidLayout.fire({ size, orientation }); + } + + focus(): void { + this._onDidFocus.fire(); + } + + dispose(): void { + this._onDidChange.dispose(); + this._onDidRender.dispose(); + this._onDidLayout.dispose(); + this._onDidFocus.dispose(); + } +} + +function getSashes(splitview: SplitView): Sash[] { + return (splitview as any).sashItems.map(i => i.sash) as Sash[]; +} + +suite('Splitview', () => { + let container: HTMLElement; + + setup(() => { + container = document.createElement('div'); + container.style.position = 'absolute'; + container.style.width = `${200}px`; + container.style.height = `${200}px`; + }); + + teardown(() => { + container = null; + }); + + test('empty splitview has empty DOM', () => { + const splitview = new SplitView(container); + assert.equal(container.firstElementChild.childElementCount, 0, 'split view should be empty'); + splitview.dispose(); + }); + + test('has views and sashes as children', () => { + const view1 = new TestView(20, 20); + const view2 = new TestView(20, 20); + const view3 = new TestView(20, 20); + const splitview = new SplitView(container); + + splitview.addView(view1, 20); + splitview.addView(view2, 20); + splitview.addView(view3, 20); + + let viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-view'); + assert.equal(viewQuery.length, 3, 'split view should have 3 views'); + + let sashQuery = container.querySelectorAll('.monaco-split-view2 > .monaco-sash'); + assert.equal(sashQuery.length, 2, 'split view should have 2 sashes'); + + splitview.removeView(2); + + viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-view'); + assert.equal(viewQuery.length, 2, 'split view should have 2 views'); + + sashQuery = container.querySelectorAll('.monaco-split-view2 > .monaco-sash'); + assert.equal(sashQuery.length, 1, 'split view should have 1 sash'); + + splitview.removeView(0); + + viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-view'); + assert.equal(viewQuery.length, 1, 'split view should have 1 view'); + + sashQuery = container.querySelectorAll('.monaco-split-view2 > .monaco-sash'); + assert.equal(sashQuery.length, 0, 'split view should have no sashes'); + + splitview.removeView(0); + + viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-view'); + assert.equal(viewQuery.length, 0, 'split view should have no views'); + + sashQuery = container.querySelectorAll('.monaco-split-view2 > .monaco-sash'); + assert.equal(sashQuery.length, 0, 'split view should have no sashes'); + + splitview.dispose(); + view1.dispose(); + view2.dispose(); + view3.dispose(); + }); + + test('calls view methods on addView and removeView', () => { + const view = new TestView(20, 20); + const splitview = new SplitView(container); + + let didLayout = false; + const layoutDisposable = view.onDidLayout(() => didLayout = true); + + let didRender = false; + const renderDisposable = view.onDidRender(() => didRender = true); + + splitview.addView(view, 20); + + assert.equal(view.size, 20, 'view has right size'); + assert(didLayout, 'layout is called'); + assert(didLayout, 'render is called'); + + splitview.dispose(); + layoutDisposable.dispose(); + renderDisposable.dispose(); + view.dispose(); + }); + + test('stretches view to viewport', () => { + const view = new TestView(20, Number.POSITIVE_INFINITY); + const splitview = new SplitView(container); + splitview.layout(200); + + splitview.addView(view, 20); + assert.equal(view.size, 200, 'view is stretched'); + + splitview.layout(200); + assert.equal(view.size, 200, 'view stayed the same'); + + splitview.layout(100); + assert.equal(view.size, 100, 'view is collapsed'); + + splitview.layout(20); + assert.equal(view.size, 20, 'view is collapsed'); + + splitview.layout(10); + assert.equal(view.size, 20, 'view is clamped'); + + splitview.layout(200); + assert.equal(view.size, 200, 'view is stretched'); + + splitview.dispose(); + view.dispose(); + }); + + test('can resize views', () => { + const view1 = new TestView(20, Number.POSITIVE_INFINITY); + const view2 = new TestView(20, Number.POSITIVE_INFINITY); + const view3 = new TestView(20, Number.POSITIVE_INFINITY); + const splitview = new SplitView(container); + splitview.layout(200); + + splitview.addView(view1, 20); + splitview.addView(view2, 20); + splitview.addView(view3, 20); + + assert.equal(view1.size, 160, 'view1 is stretched'); + assert.equal(view2.size, 20, 'view2 size is 20'); + assert.equal(view3.size, 20, 'view3 size is 20'); + + splitview.resizeView(1, 40); + + assert.equal(view1.size, 140, 'view1 is collapsed'); + assert.equal(view2.size, 40, 'view2 is stretched'); + assert.equal(view3.size, 20, 'view3 stays the same'); + + splitview.resizeView(0, 70); + + assert.equal(view1.size, 70, 'view1 is collapsed'); + assert.equal(view2.size, 110, 'view2 is expanded'); + assert.equal(view3.size, 20, 'view3 stays the same'); + + splitview.resizeView(2, 40); + + assert.equal(view1.size, 70, 'view1 stays the same'); + assert.equal(view2.size, 90, 'view2 is collapsed'); + assert.equal(view3.size, 40, 'view3 is stretched'); + + splitview.dispose(); + view3.dispose(); + view2.dispose(); + view1.dispose(); + }); + + test('reacts to view changes', () => { + const view1 = new TestView(20, Number.POSITIVE_INFINITY); + const view2 = new TestView(20, Number.POSITIVE_INFINITY); + const view3 = new TestView(20, Number.POSITIVE_INFINITY); + const splitview = new SplitView(container); + splitview.layout(200); + + splitview.addView(view1, 20); + splitview.addView(view2, 20); + splitview.addView(view3, 20); + + assert.equal(view1.size, 160, 'view1 is stretched'); + assert.equal(view2.size, 20, 'view2 size is 20'); + assert.equal(view3.size, 20, 'view3 size is 20'); + + view1.maximumSize = 20; + + assert.equal(view1.size, 20, 'view1 is collapsed'); + assert.equal(view2.size, 20, 'view2 stays the same'); + assert.equal(view3.size, 160, 'view3 is stretched'); + + view3.maximumSize = 40; + + assert.equal(view1.size, 20, 'view1 stays the same'); + assert.equal(view2.size, 140, 'view2 is stretched'); + assert.equal(view3.size, 40, 'view3 is collapsed'); + + view2.maximumSize = 200; + + assert.equal(view1.size, 20, 'view1 stays the same'); + assert.equal(view2.size, 140, 'view2 stays the same'); + assert.equal(view3.size, 40, 'view3 stays the same'); + + view3.maximumSize = Number.POSITIVE_INFINITY; + view3.minimumSize = 100; + + assert.equal(view1.size, 20, 'view1 is collapsed'); + assert.equal(view2.size, 80, 'view2 is collapsed'); + assert.equal(view3.size, 100, 'view3 is stretched'); + + splitview.dispose(); + view3.dispose(); + view2.dispose(); + view1.dispose(); + }); + + test('sashes are properly enabled/disabled', () => { + const view1 = new TestView(20, Number.POSITIVE_INFINITY); + const view2 = new TestView(20, Number.POSITIVE_INFINITY); + const view3 = new TestView(20, Number.POSITIVE_INFINITY); + const splitview = new SplitView(container); + splitview.layout(200); + + splitview.addView(view1, 20); + splitview.addView(view2, 20); + splitview.addView(view3, 20); + + let sashes = getSashes(splitview); + assert.equal(sashes.length, 2, 'there are two sashes'); + assert.equal(sashes[0].enabled, true, 'first sash is enabled'); + assert.equal(sashes[1].enabled, true, 'second sash is enabled'); + + splitview.layout(60); + assert.equal(sashes[0].enabled, false, 'first sash is disabled'); + assert.equal(sashes[1].enabled, false, 'second sash is disabled'); + + splitview.layout(20); + assert.equal(sashes[0].enabled, false, 'first sash is disabled'); + assert.equal(sashes[1].enabled, false, 'second sash is disabled'); + + splitview.layout(200); + assert.equal(sashes[0].enabled, true, 'first sash is enabled'); + assert.equal(sashes[1].enabled, true, 'second sash is enabled'); + + view1.maximumSize = 20; + assert.equal(sashes[0].enabled, false, 'first sash is disabled'); + assert.equal(sashes[1].enabled, true, 'second sash is enabled'); + + view2.maximumSize = 20; + assert.equal(sashes[0].enabled, false, 'first sash is disabled'); + assert.equal(sashes[1].enabled, false, 'second sash is disabled'); + + view1.maximumSize = 300; + assert.equal(sashes[0].enabled, true, 'first sash is enabled'); + assert.equal(sashes[1].enabled, true, 'second sash is enabled'); + + view2.maximumSize = 200; + assert.equal(sashes[0].enabled, true, 'first sash is enabled'); + assert.equal(sashes[1].enabled, true, 'second sash is enabled'); + + splitview.dispose(); + view3.dispose(); + view2.dispose(); + view1.dispose(); + }); + + test('issue #35497', () => { + const view1 = new TestView(160, Number.POSITIVE_INFINITY); + const view2 = new TestView(66, 66); + + const splitview = new SplitView(container); + splitview.layout(986); + + splitview.addView(view1, 142, 0); + assert.equal(view1.size, 986, 'first view is stretched'); + + view2.onDidRender(() => { + assert.throws(() => splitview.resizeView(1, 922)); + assert.throws(() => splitview.resizeView(1, 922)); + }); + + splitview.addView(view2, 66, 0); + assert.equal(view2.size, 66, 'second view is fixed'); + assert.equal(view1.size, 986 - 66, 'first view is collapsed'); + + const viewContainers = container.querySelectorAll('.split-view-view'); + assert.equal(viewContainers.length, 2, 'there are two view containers'); + assert.equal((viewContainers.item(0) as HTMLElement).style.height, '66px', 'second view container is 66px'); + assert.equal((viewContainers.item(1) as HTMLElement).style.height, `${986 - 66}px`, 'first view container is 66px'); + + splitview.dispose(); + view2.dispose(); + view1.dispose(); + }); +}); \ No newline at end of file diff --git a/src/vs/base/test/common/arrays.test.ts b/src/vs/base/test/common/arrays.test.ts index 4d1e67c20fc..ca7a9bc7996 100644 --- a/src/vs/base/test/common/arrays.test.ts +++ b/src/vs/base/test/common/arrays.test.ts @@ -5,6 +5,7 @@ 'use strict'; import * as assert from 'assert'; +import { TPromise } from 'vs/base/common/winjs.base'; import arrays = require('vs/base/common/arrays'); suite('Arrays', () => { @@ -94,7 +95,51 @@ suite('Arrays', () => { } }); - test('delta', function () { + test('sortedDiff', function () { + function compare(a: number, b: number): number { + return a - b; + } + + let d = arrays.sortedDiff([1, 2, 4], [], compare); + assert.deepEqual(d, [ + { start: 0, deleteCount: 3, inserted: [] } + ]); + + d = arrays.sortedDiff([], [1, 2, 4], compare); + assert.deepEqual(d, [ + { start: 0, deleteCount: 0, inserted: [1, 2, 4] } + ]); + + d = arrays.sortedDiff([1, 2, 4], [1, 2, 4], compare); + assert.deepEqual(d, []); + + d = arrays.sortedDiff([1, 2, 4], [2, 3, 4, 5], compare); + assert.deepEqual(d, [ + { start: 0, deleteCount: 1, inserted: [] }, + { start: 2, deleteCount: 0, inserted: [3] }, + { start: 3, deleteCount: 0, inserted: [5] }, + ]); + + d = arrays.sortedDiff([2, 3, 4, 5], [1, 2, 4], compare); + assert.deepEqual(d, [ + { start: 0, deleteCount: 0, inserted: [1] }, + { start: 1, deleteCount: 1, inserted: [] }, + { start: 3, deleteCount: 1, inserted: [] }, + ]); + + d = arrays.sortedDiff([1, 3, 5, 7], [5, 9, 11], compare); + assert.deepEqual(d, [ + { start: 0, deleteCount: 2, inserted: [] }, + { start: 3, deleteCount: 1, inserted: [9, 11] } + ]); + + d = arrays.sortedDiff([1, 3, 7], [5, 9, 11], compare); + assert.deepEqual(d, [ + { start: 0, deleteCount: 3, inserted: [5, 9, 11] } + ]); + }); + + test('delta sorted arrays', function () { function compare(a: number, b: number): number { return a - b; } @@ -157,7 +202,7 @@ suite('Arrays', () => { }); test('top', function () { - const cmp = (a, b) => { + const cmp = (a: number, b: number) => { assert.strictEqual(typeof a, 'number', 'typeof a'); assert.strictEqual(typeof b, 'number', 'typeof b'); return a - b; @@ -171,5 +216,58 @@ suite('Arrays', () => { assert.deepEqual(arrays.top([3, 2, 1], cmp, 3), [1, 2, 3]); assert.deepEqual(arrays.top([4, 6, 2, 7, 8, 3, 5, 1], cmp, 3), [1, 2, 3]); }); + + test('topAsync', function (done) { + const cmp = (a: number, b: number) => { + assert.strictEqual(typeof a, 'number', 'typeof a'); + assert.strictEqual(typeof b, 'number', 'typeof b'); + return a - b; + }; + + testTopAsync(cmp, 1) + .then(() => { + return testTopAsync(cmp, 2); + }) + .then(done, done); + }); + + function testTopAsync(cmp: any, m: number) { + return TPromise.as(null).then(() => { + return arrays.topAsync([], cmp, 1, m) + .then(result => { + assert.deepEqual(result, []); + }); + }).then(() => { + return arrays.topAsync([1], cmp, 0, m) + .then(result => { + assert.deepEqual(result, []); + }); + }).then(() => { + return arrays.topAsync([1, 2], cmp, 1, m) + .then(result => { + assert.deepEqual(result, [1]); + }); + }).then(() => { + return arrays.topAsync([2, 1], cmp, 1, m) + .then(result => { + assert.deepEqual(result, [1]); + }); + }).then(() => { + return arrays.topAsync([1, 3, 2], cmp, 2, m) + .then(result => { + assert.deepEqual(result, [1, 2]); + }); + }).then(() => { + return arrays.topAsync([3, 2, 1], cmp, 3, m) + .then(result => { + assert.deepEqual(result, [1, 2, 3]); + }); + }).then(() => { + return arrays.topAsync([4, 6, 2, 7, 8, 3, 5, 1], cmp, 3, m) + .then(result => { + assert.deepEqual(result, [1, 2, 3]); + }); + }); + } }); diff --git a/src/vs/base/test/common/assert.test.ts b/src/vs/base/test/common/assert.test.ts index 8ccd53a455f..a28f77f0fe8 100644 --- a/src/vs/base/test/common/assert.test.ts +++ b/src/vs/base/test/common/assert.test.ts @@ -23,7 +23,7 @@ suite('Assert', () => { assert.throws(function () { ok(null, 'Foo Bar'); - }, function (e) { + }, function (e: Error) { return e.message.indexOf('Foo Bar') >= 0; }); diff --git a/src/vs/base/test/common/async.test.ts b/src/vs/base/test/common/async.test.ts index 08b5eef4fd2..ad09cfc655f 100644 --- a/src/vs/base/test/common/async.test.ts +++ b/src/vs/base/test/common/async.test.ts @@ -472,7 +472,7 @@ suite('Async', () => { test('Queue - order is kept', function (done) { let queue = new Async.Queue(); - let res = []; + let res: number[] = []; let f1 = () => TPromise.as(true).then(() => res.push(1)); let f2 = () => TPromise.timeout(10).then(() => res.push(2)); @@ -498,7 +498,7 @@ suite('Async', () => { test('Queue - errors bubble individually but not cause stop', function (done) { let queue = new Async.Queue(); - let res = []; + let res: number[] = []; let error = false; let f1 = () => TPromise.as(true).then(() => res.push(1)); @@ -525,7 +525,7 @@ suite('Async', () => { test('Queue - order is kept (chained)', function (done) { let queue = new Async.Queue(); - let res = []; + let res: number[] = []; let f1 = () => TPromise.as(true).then(() => res.push(1)); let f2 = () => TPromise.timeout(10).then(() => res.push(2)); @@ -560,7 +560,7 @@ suite('Async', () => { done(); }); - let res = []; + let res: number[] = []; let f1 = () => TPromise.timeout(10).then(() => res.push(2)); let f2 = () => TPromise.timeout(20).then(() => res.push(4)); @@ -595,4 +595,29 @@ suite('Async', () => { const r1Queue2 = queue.queueFor(URI.file('/some/path')); assert.notEqual(r1Queue, r1Queue2); // previous one got disposed after finishing }); + + test('ThrottledEmitter', function () { + const emitter = new Async.ThrottledEmitter(); + + const fnThatEmitsEvent = () => { + emitter.fire(); + }; + + const promiseFn = TPromise.timeout(0).then(() => { + fnThatEmitsEvent(); + fnThatEmitsEvent(); + fnThatEmitsEvent(); + }); + + let count = 0; + emitter.event(() => { + count++; + }); + + emitter.throttle(promiseFn); + + promiseFn.then(() => { + assert.equal(count, 1); + }); + }); }); diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 2e26cb50b0c..fb2386be509 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -179,6 +179,29 @@ suite('Event', function () { } }); + test('reusing event function and context', function () { + let counter = 0; + function listener() { + counter += 1; + } + const context = {}; + + let emitter = new Emitter(); + let reg1 = emitter.event(listener, context); + let reg2 = emitter.event(listener, context); + + emitter.fire(); + assert.equal(counter, 2); + + reg1.dispose(); + emitter.fire(); + assert.equal(counter, 3); + + reg2.dispose(); + emitter.fire(); + assert.equal(counter, 3); + }); + test('Debounce Event', function (done: () => void) { let doc = new Samples.Document3(); @@ -376,7 +399,7 @@ suite('Event utils', () => { suite('buffer', () => { test('should buffer events', () => { - const result = []; + const result: number[] = []; const emitter = new Emitter(); const event = emitter.event; const bufferedEvent = buffer(event); @@ -398,7 +421,7 @@ suite('Event utils', () => { }); test('should buffer events on next tick', () => { - const result = []; + const result: number[] = []; const emitter = new Emitter(); const event = emitter.event; const bufferedEvent = buffer(event, true); @@ -422,7 +445,7 @@ suite('Event utils', () => { }); test('should fire initial buffer events', () => { - const result = []; + const result: number[] = []; const emitter = new Emitter(); const event = emitter.event; const bufferedEvent = buffer(event, false, [-2, -1, 0]); @@ -440,7 +463,7 @@ suite('Event utils', () => { suite('echo', () => { test('should echo events', () => { - const result = []; + const result: number[] = []; const emitter = new Emitter(); const event = emitter.event; const echoEvent = echo(event); @@ -462,8 +485,8 @@ suite('Event utils', () => { }); test('should echo events for every listener', () => { - const result1 = []; - const result2 = []; + const result1: number[] = []; + const result2: number[] = []; const emitter = new Emitter(); const event = emitter.event; const echoEvent = echo(event); @@ -501,7 +524,7 @@ suite('Event utils', () => { suite('EventMultiplexer', () => { test('works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); m.event(r => result.push(r)); @@ -515,7 +538,7 @@ suite('Event utils', () => { }); test('multiplexer dispose works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); m.event(r => result.push(r)); @@ -535,7 +558,7 @@ suite('Event utils', () => { }); test('event dispose works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); m.event(r => result.push(r)); @@ -555,7 +578,7 @@ suite('Event utils', () => { }); test('mutliplexer event dispose works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); m.event(r => result.push(r)); @@ -575,7 +598,7 @@ suite('Event utils', () => { }); test('hot start works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); m.event(r => result.push(r)); @@ -593,7 +616,7 @@ suite('Event utils', () => { }); test('cold start works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); const e1 = new Emitter(); @@ -612,7 +635,7 @@ suite('Event utils', () => { }); test('late add works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); const e1 = new Emitter(); @@ -633,7 +656,7 @@ suite('Event utils', () => { }); test('add dispose works', () => { - const result = []; + const result: number[] = []; const m = new EventMultiplexer(); const e1 = new Emitter(); @@ -660,4 +683,4 @@ suite('Event utils', () => { assert.deepEqual(result, [1, 2, 3, 4, 5]); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/common/filters.perf.test.ts b/src/vs/base/test/common/filters.perf.test.ts index 7f6359042d7..652fbe65506 100644 --- a/src/vs/base/test/common/filters.perf.test.ts +++ b/src/vs/base/test/common/filters.perf.test.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -// import * as assert from 'assert'; import * as filters from 'vs/base/common/filters'; import { data } from './filters.perf.data'; diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index abda7f3352b..45018c5a8e4 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { IFilter, or, matchesPrefix, matchesStrictPrefix, matchesCamelCase, matchesSubString, matchesContiguousSubString, matchesWords, fuzzyScore, nextTypoPermutation, fuzzyScoreGraceful } from 'vs/base/common/filters'; +import { IFilter, or, matchesPrefix, matchesStrictPrefix, matchesCamelCase, matchesSubString, matchesContiguousSubString, matchesWords, fuzzyScore, nextTypoPermutation, fuzzyScoreGraceful, IMatch } from 'vs/base/common/filters'; function filterOk(filter: IFilter, word: string, wordToMatchAgainst: string, highlights?: { start: number; end: number; }[]) { let r = filter(word, wordToMatchAgainst); @@ -15,15 +15,16 @@ function filterOk(filter: IFilter, word: string, wordToMatchAgainst: string, hig } } -function filterNotOk(filter, word, suggestion) { +function filterNotOk(filter: IFilter, word: string, suggestion: string) { assert(!filter(word, suggestion)); } suite('Filters', () => { test('or', function () { - let filter, counters; - let newFilter = function (i, r) { - return function () { counters[i]++; return r; }; + let filter: IFilter; + let counters: number[]; + let newFilter = function (i: number, r: boolean): IFilter { + return function (): IMatch[] { counters[i]++; return r as any; }; }; counters = [0, 0]; @@ -161,6 +162,18 @@ suite('Filters', () => { { start: 9, end: 10 }, { start: 18, end: 19 } ]); + filterOk(matchesSubString, 'abc', 'abcabc', [ + { start: 0, end: 3 }, + ]); + filterOk(matchesSubString, 'abc', 'aaabbbccc', [ + { start: 0, end: 1 }, + { start: 3, end: 4 }, + { start: 6, end: 7 }, + ]); + }); + + test('matchesSubString performance (#35346)', function () { + filterNotOk(matchesSubString, 'aaaaaaaaaaaaaaaaaaaax', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); }); test('WordFilter', function () { diff --git a/src/vs/base/test/common/linkedList.test.ts b/src/vs/base/test/common/linkedList.test.ts new file mode 100644 index 00000000000..726da08601e --- /dev/null +++ b/src/vs/base/test/common/linkedList.test.ts @@ -0,0 +1,121 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { LinkedList } from 'vs/base/common/linkedList'; + +suite('LinkedList', function () { + + function assertElements(list: LinkedList, ...elements: E[]) { + // first: assert toArray + assert.deepEqual(list.toArray(), elements); + + // second: assert iterator + for (let iter = list.iterator(), element = iter.next(); !element.done; element = iter.next()) { + assert.equal(elements.shift(), element.value); + } + assert.equal(elements.length, 0); + } + + test('Push/Iter', function () { + const list = new LinkedList(); + list.push(0); + list.push(1); + list.push(2); + assertElements(list, 0, 1, 2); + }); + + test('Push/Remove', function () { + let list = new LinkedList(); + let disp = list.push(0); + list.push(1); + list.push(2); + disp(); + assertElements(list, 1, 2); + + list = new LinkedList(); + list.push(0); + disp = list.push(1); + list.push(2); + disp(); + assertElements(list, 0, 2); + + list = new LinkedList(); + list.push(0); + list.push(1); + disp = list.push(2); + disp(); + assertElements(list, 0, 1); + }); + + test('Push/toArray', function () { + let list = new LinkedList(); + list.push('foo'); + list.push('bar'); + list.push('far'); + list.push('boo'); + + assert.deepEqual( + list.toArray(), + [ + 'foo', + 'bar', + 'far', + 'boo', + ] + ); + }); + + test('unshift/Iter', function () { + const list = new LinkedList(); + list.unshift(0); + list.unshift(1); + list.unshift(2); + assertElements(list, 2, 1, 0); + }); + + test('unshift/Remove', function () { + let list = new LinkedList(); + let disp = list.unshift(0); + list.unshift(1); + list.unshift(2); + disp(); + assertElements(list, 2, 1); + + list = new LinkedList(); + list.unshift(0); + disp = list.unshift(1); + list.unshift(2); + disp(); + assertElements(list, 2, 0); + + list = new LinkedList(); + list.unshift(0); + list.unshift(1); + disp = list.unshift(2); + disp(); + assertElements(list, 1, 0); + }); + + test('unshift/toArray', function () { + let list = new LinkedList(); + list.unshift('foo'); + list.unshift('bar'); + list.unshift('far'); + list.unshift('boo'); + + assert.deepEqual( + list.toArray(), + [ + 'boo', + 'far', + 'bar', + 'foo', + ] + ); + }); +}); diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index b26a2079943..830f6592004 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -6,7 +6,7 @@ 'use strict'; -import { BoundedMap, TrieMap, ResourceMap } from 'vs/base/common/map'; +import { BoundedMap, ResourceMap, TernarySearchTree, PathIterator, StringIterator } from 'vs/base/common/map'; import * as assert from 'assert'; import URI from 'vs/base/common/uri'; @@ -311,53 +311,213 @@ suite('Map', () => { assert.ok(!map.has('4')); }); + test('PathIterator', function () { + const iter = new PathIterator(); + iter.reset('file:///usr/bin/file.txt'); - test('TrieMap - basics', function () { + assert.equal(iter.value(), 'file:'); + assert.equal(iter.hasNext(), true); + assert.equal(iter.cmp('file:'), 0); + assert.ok(iter.cmp('a') < 0); + assert.ok(iter.cmp('aile:') < 0); + assert.ok(iter.cmp('z') > 0); + assert.ok(iter.cmp('zile:') > 0); - const map = new TrieMap(); + iter.next(); + assert.equal(iter.value(), 'usr'); + assert.equal(iter.hasNext(), true); - map.insert('/user/foo/bar', 1); - map.insert('/user/foo', 2); - map.insert('/user/foo/flip/flop', 3); + iter.next(); + assert.equal(iter.value(), 'bin'); + assert.equal(iter.hasNext(), true); - assert.equal(map.findSubstr('/user/bar'), undefined); - assert.equal(map.findSubstr('/user/foo'), 2); - assert.equal(map.findSubstr('\\user\\foo'), 2); - assert.equal(map.findSubstr('/user/foo/ba'), 2); - assert.equal(map.findSubstr('/user/foo/far/boo'), 2); - assert.equal(map.findSubstr('/user/foo/bar'), 1); - assert.equal(map.findSubstr('/user/foo/bar/far/boo'), 1); + iter.next(); + assert.equal(iter.value(), 'file.txt'); + assert.equal(iter.hasNext(), false); + iter.next(); + assert.equal(iter.value(), ''); + assert.equal(iter.hasNext(), false); + iter.next(); + assert.equal(iter.value(), ''); + assert.equal(iter.hasNext(), false); + + // + iter.reset('/foo/bar/'); + assert.equal(iter.value(), 'foo'); + assert.equal(iter.hasNext(), true); + + iter.next(); + assert.equal(iter.value(), 'bar'); + assert.equal(iter.hasNext(), false); }); - test('TrieMap - lookup', function () { + function assertTernarySearchTree(trie: TernarySearchTree, ...elements: [string, E][]) { + const map = new Map(); + for (const [key, value] of elements) { + map.set(key, value); + } + map.forEach((value, key) => { + assert.equal(trie.get(key), value); + }); + trie.forEach((element, key) => { + assert.equal(element, map.get(key)); + map.delete(key); + }); + assert.equal(map.size, 0); + } - const map = new TrieMap(); - map.insert('/user/foo/bar', 1); - map.insert('/user/foo', 2); - map.insert('/user/foo/flip/flop', 3); + test('TernarySearchTree - set', function () { - assert.equal(map.lookUp('/foo'), undefined); - assert.equal(map.lookUp('/user'), undefined); - assert.equal(map.lookUp('/user/foo'), 2); - assert.equal(map.lookUp('/user/foo/bar'), 1); - assert.equal(map.lookUp('/user/foo/bar/boo'), undefined); + let trie = TernarySearchTree.forStrings(); + trie.set('foobar', 1); + trie.set('foobaz', 2); + + assertTernarySearchTree(trie, ['foobar', 1], ['foobaz', 2]); // longer + + trie = TernarySearchTree.forStrings(); + trie.set('foobar', 1); + trie.set('fooba', 2); + assertTernarySearchTree(trie, ['foobar', 1], ['fooba', 2]); // shorter + + trie = TernarySearchTree.forStrings(); + trie.set('foo', 1); + trie.set('foo', 2); + assertTernarySearchTree(trie, ['foo', 2]); + + trie = TernarySearchTree.forStrings(); + trie.set('foo', 1); + trie.set('foobar', 2); + trie.set('bar', 3); + trie.set('foob', 4); + trie.set('bazz', 5); + + assertTernarySearchTree(trie, + ['foo', 1], + ['foobar', 2], + ['bar', 3], + ['foob', 4], + ['bazz', 5] + ); }); - test('TrieMap - superstr', function () { + test('TernarySearchTree - findLongestMatch', function () { - const map = new TrieMap(); - map.insert('/user/foo/bar', 1); - map.insert('/user/foo', 2); - map.insert('/user/foo/flip/flop', 3); + let trie = TernarySearchTree.forStrings(); + trie.set('foo', 1); + trie.set('foobar', 2); + trie.set('foobaz', 3); - const supMap = map.findSuperstr('/user'); + assert.equal(trie.findSubstr('f'), undefined); + assert.equal(trie.findSubstr('z'), undefined); + assert.equal(trie.findSubstr('foo'), 1); + assert.equal(trie.findSubstr('fooö'), 1); + assert.equal(trie.findSubstr('fooba'), 1); + assert.equal(trie.findSubstr('foobarr'), 2); + assert.equal(trie.findSubstr('foobazrr'), 3); + }); - assert.equal(supMap.lookUp('foo'), 2); - assert.equal(supMap.lookUp('foo/bar'), 1); - assert.equal(supMap.lookUp('foo/flip/flop'), 3); - assert.equal(supMap.lookUp('foo/flip/flop/bar'), undefined); - assert.equal(supMap.lookUp('user'), undefined); + test('TernarySearchTree - basics', function () { + let trie = new TernarySearchTree(new StringIterator()); + + trie.set('foo', 1); + trie.set('bar', 2); + trie.set('foobar', 3); + + assert.equal(trie.get('foo'), 1); + assert.equal(trie.get('bar'), 2); + assert.equal(trie.get('foobar'), 3); + assert.equal(trie.get('foobaz'), undefined); + assert.equal(trie.get('foobarr'), undefined); + + assert.equal(trie.findSubstr('fo'), undefined); + assert.equal(trie.findSubstr('foo'), 1); + assert.equal(trie.findSubstr('foooo'), 1); + + + trie.delete('foobar'); + trie.delete('bar'); + assert.equal(trie.get('foobar'), undefined); + assert.equal(trie.get('bar'), undefined); + + trie.set('foobar', 17); + trie.set('barr', 18); + assert.equal(trie.get('foobar'), 17); + assert.equal(trie.get('barr'), 18); + assert.equal(trie.get('bar'), undefined); + }); + + test('TernarySearchTree - delete & cleanup', function () { + let trie = new TernarySearchTree(new StringIterator()); + trie.set('foo', 1); + trie.set('foobar', 2); + trie.set('bar', 3); + + trie.delete('foo'); + trie.delete('foobar'); + }); + + test('TernarySearchTree (PathSegments) - basics', function () { + let trie = new TernarySearchTree(new PathIterator()); + + trie.set('/user/foo/bar', 1); + trie.set('/user/foo', 2); + trie.set('/user/foo/flip/flop', 3); + + assert.equal(trie.get('/user/foo/bar'), 1); + assert.equal(trie.get('/user/foo'), 2); + assert.equal(trie.get('/user//foo'), 2); + assert.equal(trie.get('/user\\foo'), 2); + assert.equal(trie.get('/user/foo/flip/flop'), 3); + + assert.equal(trie.findSubstr('/user/bar'), undefined); + assert.equal(trie.findSubstr('/user/foo'), 2); + assert.equal(trie.findSubstr('\\user\\foo'), 2); + assert.equal(trie.findSubstr('/user//foo'), 2); + assert.equal(trie.findSubstr('/user/foo/ba'), 2); + assert.equal(trie.findSubstr('/user/foo/far/boo'), 2); + assert.equal(trie.findSubstr('/user/foo/bar'), 1); + assert.equal(trie.findSubstr('/user/foo/bar/far/boo'), 1); + }); + + test('TernarySearchTree (PathSegments) - lookup', function () { + + const map = new TernarySearchTree(new PathIterator()); + map.set('/user/foo/bar', 1); + map.set('/user/foo', 2); + map.set('/user/foo/flip/flop', 3); + + assert.equal(map.get('/foo'), undefined); + assert.equal(map.get('/user'), undefined); + assert.equal(map.get('/user/foo'), 2); + assert.equal(map.get('/user/foo/bar'), 1); + assert.equal(map.get('/user/foo/bar/boo'), undefined); + }); + + test('TernarySearchTree (PathSegments) - superstr', function () { + + const map = new TernarySearchTree(new PathIterator()); + map.set('/user/foo/bar', 1); + map.set('/user/foo', 2); + map.set('/user/foo/flip/flop', 3); + map.set('/usr/foo', 4); + + const elements = map.findSuperstr('/user'); + + assertTernarySearchTree(elements, ['foo/bar', 1], ['foo', 2], ['foo/flip/flop', 3]); + // assert.equal(elements.length, 3); + assert.equal(elements.get('foo/bar'), 1); + assert.equal(elements.get('foo'), 2); + assert.equal(elements.get('foo/flip/flop'), 3); + + assertTernarySearchTree(map.findSuperstr('/usr'), ['foo', 4]); + assert.equal(map.findSuperstr('/usr/foo'), undefined); + assert.equal(map.get('/usr/foo'), 4); + + assert.equal(map.findSuperstr('/not'), undefined); + assert.equal(map.findSuperstr('/us'), undefined); + assert.equal(map.findSuperstr('/usrr'), undefined); + assert.equal(map.findSuperstr('/userr'), undefined); }); test('ResourceMap - basics', function () { diff --git a/src/vs/base/test/common/objects.test.ts b/src/vs/base/test/common/objects.test.ts index 48379430d93..3ee70c7d407 100644 --- a/src/vs/base/test/common/objects.test.ts +++ b/src/vs/base/test/common/objects.test.ts @@ -7,12 +7,12 @@ import * as assert from 'assert'; import objects = require('vs/base/common/objects'); -let check = (one, other, msg) => { +let check = (one: any, other: any, msg: string) => { assert(objects.equals(one, other), msg); assert(objects.equals(other, one), '[reverse] ' + msg); }; -let checkNot = (one, other, msg) => { +let checkNot = (one: any, other: any, msg: string) => { assert(!objects.equals(one, other), msg); assert(!objects.equals(other, one), '[reverse] ' + msg); }; @@ -92,11 +92,11 @@ suite('Objects', () => { }); test('safeStringify', function () { - let obj1 = { + let obj1: any = { friend: null }; - let obj2 = { + let obj2: any = { friend: null }; @@ -106,7 +106,7 @@ suite('Objects', () => { let arr: any = [1]; arr.push(arr); - let circular = { + let circular: any = { a: 42, b: null, c: [ diff --git a/src/vs/base/test/common/scorer.test.ts b/src/vs/base/test/common/scorer.test.ts deleted file mode 100644 index e0cd72662c0..00000000000 --- a/src/vs/base/test/common/scorer.test.ts +++ /dev/null @@ -1,54 +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 scorer = require('vs/base/common/scorer'); - -suite('Scorer', () => { - - test('score', function () { - const target = 'HelLo-World'; - - const scores = []; - scores.push(scorer.score(target, 'HelLo-World')); // direct case match - scores.push(scorer.score(target, 'hello-world')); // direct mix-case match - scores.push(scorer.score(target, 'HW')); // direct case prefix (multiple) - scores.push(scorer.score(target, 'H')); // direct case prefix - scores.push(scorer.score(target, 'hw')); // direct mix-case prefix (multiple) - scores.push(scorer.score(target, 'h')); // direct mix-case prefix - scores.push(scorer.score(target, 'W')); // direct case word prefix - scores.push(scorer.score(target, 'w')); // direct mix-case word prefix - scores.push(scorer.score(target, 'Ld')); // in-string case match (multiple) - scores.push(scorer.score(target, 'L')); // in-string case match - scores.push(scorer.score(target, 'ld')); // in-string mix-case match - scores.push(scorer.score(target, 'l')); // in-string mix-case match - scores.push(scorer.score(target, '4')); // no match - - // Assert scoring order - let sortedScores = scores.sort((a, b) => b - a); - assert.deepEqual(scores, sortedScores); - }); - - test('cache', function () { - const cache = Object.create(null); - - scorer.score('target', 'query', cache); - scorer.score('target', 't', cache); - - assert.equal(Object.getOwnPropertyNames(cache).length, 2); - }); - - test('matches', function () { - assert.ok(scorer.matches('hello world', 'h')); - assert.ok(!scorer.matches('hello world', 'q')); - assert.ok(scorer.matches('hello world', 'hw')); - assert.ok(scorer.matches('hello world', 'horl')); - assert.ok(scorer.matches('hello world', 'd')); - assert.ok(!scorer.matches('hello world', 'wh')); - assert.ok(!scorer.matches('d', 'dd')); - }); -}); \ No newline at end of file diff --git a/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts index af164c308b8..53e4a534c07 100644 --- a/src/vs/base/test/common/strings.test.ts +++ b/src/vs/base/test/common/strings.test.ts @@ -312,6 +312,22 @@ suite('Strings', () => { assert(regExpWithFlags.multiline); }); + test('regExpContainsBackreference', () => { + assert(strings.regExpContainsBackreference('foo \\5 bar')); + assert(strings.regExpContainsBackreference('\\2')); + assert(strings.regExpContainsBackreference('(\\d)(\\n)(\\1)')); + assert(strings.regExpContainsBackreference('(A).*?\\1')); + assert(strings.regExpContainsBackreference('\\\\\\1')); + assert(strings.regExpContainsBackreference('foo \\\\\\1')); + + assert(!strings.regExpContainsBackreference('')); + assert(!strings.regExpContainsBackreference('\\\\1')); + assert(!strings.regExpContainsBackreference('foo \\\\1')); + assert(!strings.regExpContainsBackreference('(A).*?\\\\1')); + assert(!strings.regExpContainsBackreference('foo \\d1 bar')); + assert(!strings.regExpContainsBackreference('123')); + }); + test('getLeadingWhitespace', () => { assert.equal(strings.getLeadingWhitespace(' foo'), ' '); assert.equal(strings.getLeadingWhitespace(' foo', 2), ''); @@ -322,6 +338,33 @@ suite('Strings', () => { assert.equal(strings.getLeadingWhitespace(' ', 0, 1), ' '); assert.equal(strings.getLeadingWhitespace('\t\tfunction foo(){', 0, 1), '\t'); assert.equal(strings.getLeadingWhitespace('\t\tfunction foo(){', 0, 2), '\t\t'); + }); + test('fuzzyContains', function () { + assert.ok(!strings.fuzzyContains(void 0, null)); + assert.ok(strings.fuzzyContains('hello world', 'h')); + assert.ok(!strings.fuzzyContains('hello world', 'q')); + assert.ok(strings.fuzzyContains('hello world', 'hw')); + assert.ok(strings.fuzzyContains('hello world', 'horl')); + assert.ok(strings.fuzzyContains('hello world', 'd')); + assert.ok(!strings.fuzzyContains('hello world', 'wh')); + assert.ok(!strings.fuzzyContains('d', 'dd')); + }); + + test('startsWithUTF8BOM', () => { + assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER)); + assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'a')); + assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'aaaaaaaaaa')); + assert(!strings.startsWithUTF8BOM(' ' + strings.UTF8_BOM_CHARACTER)); + assert(!strings.startsWithUTF8BOM('foo')); + assert(!strings.startsWithUTF8BOM('')); + }); + + test('stripUTF8BOM', () => { + assert.equal(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER), ''); + assert.equal(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER + 'foobar'), 'foobar'); + assert.equal(strings.stripUTF8BOM('foobar' + strings.UTF8_BOM_CHARACTER), 'foobar' + strings.UTF8_BOM_CHARACTER); + assert.equal(strings.stripUTF8BOM('abc'), 'abc'); + assert.equal(strings.stripUTF8BOM(''), ''); }); }); diff --git a/src/vs/base/test/common/types.test.ts b/src/vs/base/test/common/types.test.ts index 81c3be204fd..205c0b088c7 100644 --- a/src/vs/base/test/common/types.test.ts +++ b/src/vs/base/test/common/types.test.ts @@ -184,7 +184,7 @@ suite('Types', () => { function isFoo(f) { } assert.throws(() => types.validateConstraints([new foo()], [isFoo])); - function isFoo2(f) { return true; }; + function isFoo2(f) { return true; } types.validateConstraints([new foo()], [isFoo2]); assert.throws(() => types.validateConstraints([1, true], [types.isNumber, types.isString])); @@ -198,7 +198,7 @@ suite('Types', () => { assert(types.create(zeroConstructor) instanceof zeroConstructor); assert(types.isObject(types.create(zeroConstructor))); - let manyArgConstructor = function (foo, bar) { + let manyArgConstructor = function (this: any, foo, bar) { this.foo = foo; this.bar = bar; }; diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 1e8340f98c7..3341b0bcb6a 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -368,6 +368,23 @@ suite('URI', () => { assert.equal(value.toString(), 'http://l%C3%B6calhost:8080/far'); }); + test('URI#toString, user information in authority', () => { + var value = URI.parse('http://foo:bar@localhost/far'); + assert.equal(value.toString(), 'http://foo:bar@localhost/far'); + + value = URI.parse('http://foo@localhost/far'); + assert.equal(value.toString(), 'http://foo@localhost/far'); + + value = URI.parse('http://foo:bAr@localhost:8080/far'); + assert.equal(value.toString(), 'http://foo:bAr@localhost:8080/far'); + + value = URI.parse('http://foo@localhost:8080/far'); + assert.equal(value.toString(), 'http://foo@localhost:8080/far'); + + value = URI.from({ scheme: 'http', authority: 'föö:bör@löcalhost:8080', path: '/far', query: undefined, fragment: undefined }); + assert.equal(value.toString(), 'http://f%C3%B6%C3%B6:b%C3%B6r@l%C3%B6calhost:8080/far'); + }); + test('correctFileUriToFilePath2', () => { var test = (input: string, expected: string) => { diff --git a/src/vs/base/test/common/utils.ts b/src/vs/base/test/common/utils.ts index f69d864e509..0dc656251c2 100644 --- a/src/vs/base/test/common/utils.ts +++ b/src/vs/base/test/common/utils.ts @@ -85,6 +85,6 @@ export function onError(error: Error, done: () => void): void { done(); } -export function toResource(path) { +export function toResource(this: any, path: string) { return URI.file(paths.join('C:\\', new Buffer(this.test.fullTitle()).toString('base64'), path)); } diff --git a/src/vs/base/test/common/winjs.polyfill.promise.test.ts b/src/vs/base/test/common/winjs.polyfill.promise.test.ts new file mode 100644 index 00000000000..5114888d419 --- /dev/null +++ b/src/vs/base/test/common/winjs.polyfill.promise.test.ts @@ -0,0 +1,152 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { PolyfillPromise } from 'vs/base/common/winjs.polyfill.promise'; +import { Promise as WinJSPromise } from 'vs/base/common/winjs.base'; + +suite('Polyfill Promise', function () { + + test('sync-resolve, NativePromise', function () { + // native promise behaviour + const actual: string[] = []; + const promise = new Promise(resolve => { + actual.push('inCtor'); + resolve(null); + }).then(() => actual.push('inThen')); + actual.push('afterCtor'); + return promise.then(() => { + assert.deepEqual(actual, ['inCtor', 'afterCtor', 'inThen']); + }); + }); + + test('sync-resolve, WinJSPromise', function () { + + // winjs promise behaviour + const actual: string[] = []; + const promise = new WinJSPromise(resolve => { + actual.push('inCtor'); + resolve(null); + }).then(() => actual.push('inThen')); + actual.push('afterCtor'); + return promise.then(() => { + assert.deepEqual(actual, ['inCtor', 'inThen', 'afterCtor']); + }); + }); + + test('sync-resolve, PolyfillPromise', function () { + + // winjs promise behaviour + const actual: string[] = []; + const promise = new PolyfillPromise(resolve => { + actual.push('inCtor'); + resolve(null); + }).then(() => actual.push('inThen')); + actual.push('afterCtor'); + return promise.then(() => { + assert.deepEqual(actual, ['inCtor', 'afterCtor', 'inThen']); + }); + }); + + test('PolyfillPromise, executor has two params', function () { + return new PolyfillPromise(function () { + assert.equal(arguments.length, 2); + assert.equal(typeof arguments[0], 'function'); + assert.equal(typeof arguments[1], 'function'); + + arguments[0](); + }); + }); + + // run the same tests for the native and polyfill promise + ([Promise, PolyfillPromise]).forEach(PromiseCtor => { + + test(PromiseCtor.name + ', resolved value', function () { + return new PromiseCtor((resolve: Function) => resolve(1)).then((value: number) => assert.equal(value, 1)); + }); + + test(PromiseCtor.name + ', rejected value', function () { + return new PromiseCtor((_: Function, reject: Function) => reject(1)).then(null, (value: number) => assert.equal(value, 1)); + }); + + test(PromiseCtor.name + ', catch', function () { + return new PromiseCtor((_: Function, reject: Function) => reject(1)).catch((value: number) => assert.equal(value, 1)); + }); + + test(PromiseCtor.name + ', static-resolve', function () { + return PromiseCtor.resolve(42).then((value: number) => assert.equal(value, 42)); + }); + + test(PromiseCtor.name + ', static-reject', function () { + return PromiseCtor.reject(42).then(null, (value: number) => assert.equal(value, 42)); + }); + + test(PromiseCtor.name + ', static-all, 1', function () { + return PromiseCtor.all([ + PromiseCtor.resolve(1), + PromiseCtor.resolve(2) + ]).then((values: number[]) => { + assert.deepEqual(values, [1, 2]); + }); + }); + + test(PromiseCtor.name + ', static-all, 2', function () { + return PromiseCtor.all([ + PromiseCtor.resolve(1), + 3, + PromiseCtor.resolve(2) + ]).then((values: number[]) => { + assert.deepEqual(values, [1, 3, 2]); + }); + }); + + test(PromiseCtor.name + ', static-all, 3', function () { + return PromiseCtor.all([ + PromiseCtor.resolve(1), + PromiseCtor.reject(13), + PromiseCtor.reject(12), + ]).catch((values: number) => { + assert.deepEqual(values, 13); + }); + }); + + test(PromiseCtor.name + ', static-race, 1', function () { + return PromiseCtor.race([ + PromiseCtor.resolve(1), + PromiseCtor.resolve(2), + ]).then((value: number) => { + assert.deepEqual(value, 1); + }); + }); + + test(PromiseCtor.name + ', static-race, 2', function () { + return PromiseCtor.race([ + PromiseCtor.reject(-1), + PromiseCtor.resolve(2), + ]).catch((value: number) => { + assert.deepEqual(value, -1); + }); + }); + + test(PromiseCtor.name + ', static-race, 3', function () { + return PromiseCtor.race([ + PromiseCtor.resolve(1), + PromiseCtor.reject(2), + ]).then((value: number) => { + assert.deepEqual(value, 1); + }); + }); + + test(PromiseCtor.name + ', throw in ctor', function () { + return new PromiseCtor(() => { + throw new Error('sooo bad'); + }).catch((err: Error) => { + assert.equal(err.message, 'sooo bad'); + }); + }); + + }); +}); diff --git a/src/vs/base/test/node/console.test.ts b/src/vs/base/test/node/console.test.ts new file mode 100644 index 00000000000..27410c922fa --- /dev/null +++ b/src/vs/base/test/node/console.test.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { getFirstFrame } from 'vs/base/node/console'; +import { normalize } from 'path'; + +suite('Console', () => { + + test('getFirstFrame', function () { + let stack = 'at vscode.commands.registerCommand (/Users/someone/Desktop/test-ts/out/src/extension.js:18:17)'; + let frame = getFirstFrame(stack); + + assert.equal(frame.uri.fsPath, normalize('/Users/someone/Desktop/test-ts/out/src/extension.js')); + assert.equal(frame.line, 18); + assert.equal(frame.column, 17); + + stack = 'at /Users/someone/Desktop/test-ts/out/src/extension.js:18:17'; + frame = getFirstFrame(stack); + + assert.equal(frame.uri.fsPath, normalize('/Users/someone/Desktop/test-ts/out/src/extension.js')); + assert.equal(frame.line, 18); + assert.equal(frame.column, 17); + + stack = 'at c:\\Users\\someone\\Desktop\\end-js\\extension.js:18:17'; + frame = getFirstFrame(stack); + + assert.equal(frame.uri.fsPath, 'c:\\Users\\someone\\Desktop\\end-js\\extension.js'); + assert.equal(frame.line, 18); + assert.equal(frame.column, 17); + + stack = 'at e.$executeContributedCommand(c:\\Users\\someone\\Desktop\\end-js\\extension.js:18:17)'; + frame = getFirstFrame(stack); + + assert.equal(frame.uri.fsPath, 'c:\\Users\\someone\\Desktop\\end-js\\extension.js'); + assert.equal(frame.line, 18); + assert.equal(frame.column, 17); + + stack = 'at /Users/someone/Desktop/test-ts/out/src/extension.js:18:17\nat /Users/someone/Desktop/test-ts/out/src/other.js:28:27\nat /Users/someone/Desktop/test-ts/out/src/more.js:38:37'; + frame = getFirstFrame(stack); + + assert.equal(frame.uri.fsPath, normalize('/Users/someone/Desktop/test-ts/out/src/extension.js')); + assert.equal(frame.line, 18); + assert.equal(frame.column, 17); + + }); +}); \ No newline at end of file diff --git a/src/vs/base/test/node/extfs/extfs.test.ts b/src/vs/base/test/node/extfs/extfs.test.ts index ca184afd097..21fbc552dd8 100644 --- a/src/vs/base/test/node/extfs/extfs.test.ts +++ b/src/vs/base/test/node/extfs/extfs.test.ts @@ -16,6 +16,8 @@ import strings = require('vs/base/common/strings'); import extfs = require('vs/base/node/extfs'); import { onError } from 'vs/base/test/common/utils'; +const ignore = () => { }; + suite('Extfs', () => { test('mkdirp', function (done: () => void) { @@ -30,7 +32,7 @@ suite('Extfs', () => { assert.ok(fs.existsSync(newDir)); - extfs.del(parentDir, os.tmpdir(), () => { }, done); + extfs.del(parentDir, os.tmpdir(), done, ignore); }); // 493 = 0755 }); @@ -160,7 +162,7 @@ suite('Extfs', () => { extfs.readdir(path.join(parentDir, 'extfs', id), (error, children) => { assert.equal(children.some(n => n === 'öäü'), true); // Mac always converts to NFD, so - extfs.del(parentDir, os.tmpdir(), () => { }, done); + extfs.del(parentDir, os.tmpdir(), done, ignore); }); }); // 493 = 0755 } else { @@ -197,7 +199,7 @@ suite('Extfs', () => { assert.equal(fs.readFileSync(testFile), largeString); - extfs.del(parentDir, os.tmpdir(), () => { }, done); + extfs.del(parentDir, os.tmpdir(), done, ignore); }); }); }); @@ -228,7 +230,7 @@ suite('Extfs', () => { assert.equal(real, newDir); } - extfs.del(parentDir, os.tmpdir(), () => { }, done); + extfs.del(parentDir, os.tmpdir(), done, ignore); }); }); @@ -243,7 +245,7 @@ suite('Extfs', () => { assert.ok(realpath); assert.ok(!error); - extfs.del(parentDir, os.tmpdir(), () => { }, done); + extfs.del(parentDir, os.tmpdir(), done, ignore); }); }); }); @@ -262,7 +264,7 @@ suite('Extfs', () => { } assert.ok(realpath); - extfs.del(parentDir, os.tmpdir(), () => { }, done); + extfs.del(parentDir, os.tmpdir(), done, ignore); }); }); }); \ No newline at end of file diff --git a/src/vs/base/test/node/flow.test.ts b/src/vs/base/test/node/flow.test.ts index 0988096b322..f1edf9c98de 100644 --- a/src/vs/base/test/node/flow.test.ts +++ b/src/vs/base/test/node/flow.test.ts @@ -13,45 +13,45 @@ const sequence = flow.sequence; const parallel = flow.parallel; suite('Flow', () => { - function assertCounterEquals(counter, expected): void { + function assertCounterEquals(counter: number, expected: number): void { assert.ok(counter === expected, 'Expected ' + expected + ' assertions, but got ' + counter); } - function syncThrowsError(callback): void { + function syncThrowsError(callback: any): void { callback(new Error('foo'), null); } - function syncSequenceGetThrowsError(value, callback) { + function syncSequenceGetThrowsError(value: any, callback: any) { sequence( function onError(error) { callback(error, null); }, - function getFirst() { + function getFirst(this: any) { syncThrowsError(this); }, - function handleFirst(first) { + function handleFirst(first: number) { //Foo } ); } - function syncGet(value, callback): void { + function syncGet(value: any, callback: any): void { callback(null, value); } - function syncGetError(value, callback): void { + function syncGetError(value: any, callback: any): void { callback(new Error(''), null); } - function asyncGet(value, callback): void { + function asyncGet(value: any, callback: any): void { process.nextTick(function () { callback(null, value); }); } - function asyncGetError(value, callback): void { + function asyncGetError(value: any, callback: any): void { process.nextTick(function () { callback(new Error(''), null); }); @@ -72,7 +72,7 @@ suite('Flow', () => { }); test('loopByFunctionSync', function (done: () => void) { - const elements = function (callback) { + const elements = function (callback: Function) { callback(null, ['1', '2', '3']); }; @@ -87,7 +87,7 @@ suite('Flow', () => { }); test('loopByFunctionAsync', function (done: () => void) { - const elements = function (callback) { + const elements = function (callback: Function) { process.nextTick(function () { callback(null, ['1', '2', '3']); }); @@ -176,23 +176,23 @@ suite('Flow', () => { errorCount++; }, - function getFirst() { + function getFirst(this: any) { syncGet('1', this); }, - function handleFirst(first) { + function handleFirst(this: any, first: number) { assert.deepEqual('1', first); assertionCount++; syncGet('2', this); }, - function handleSecond(second) { + function handleSecond(this: any, second: any) { assert.deepEqual('2', second); assertionCount++; syncGet(null, this); }, - function handleThird(third) { + function handleThird(third: any) { assert.ok(!third); assertionCount++; @@ -212,23 +212,23 @@ suite('Flow', () => { errorCount++; }, - function getFirst() { + function getFirst(this: any) { asyncGet('1', this); }, - function handleFirst(first) { + function handleFirst(this: any, first: number) { assert.deepEqual('1', first); assertionCount++; asyncGet('2', this); }, - function handleSecond(second) { + function handleSecond(this: any, second: number) { assert.deepEqual('2', second); assertionCount++; asyncGet(null, this); }, - function handleThird(third) { + function handleThird(third: number) { assert.ok(!third); assertionCount++; @@ -252,17 +252,17 @@ suite('Flow', () => { done(); }, - function getFirst() { + function getFirst(this: any) { syncGet('1', this); }, - function handleFirst(first) { + function handleFirst(this: any, first: number) { assert.deepEqual('1', first); assertionCount++; syncGet('2', this); }, - function handleSecond(second) { + function handleSecond(second: number) { if (true) { throw new Error(''); } @@ -270,7 +270,7 @@ suite('Flow', () => { // syncGet(null, this); }, - function handleThird(third) { + function handleThird(third: number) { throw new Error('We should not be here'); } ); @@ -289,17 +289,17 @@ suite('Flow', () => { done(); }, - function getFirst() { + function getFirst(this: any) { syncGet('1', this); }, - function handleFirst(first) { + function handleFirst(this: any, first: number) { assert.deepEqual('1', first); assertionCount++; syncGetError('2', this); }, - function handleSecond(second) { + function handleSecond(second: number) { throw new Error('We should not be here'); } ); @@ -318,17 +318,17 @@ suite('Flow', () => { done(); }, - function getFirst() { + function getFirst(this: any) { asyncGet('1', this); }, - function handleFirst(first) { + function handleFirst(this: any, first: number) { assert.deepEqual('1', first); assertionCount++; asyncGet('2', this); }, - function handleSecond(second) { + function handleSecond(second: number) { if (true) { throw new Error(''); } @@ -336,7 +336,7 @@ suite('Flow', () => { // asyncGet(null, this); }, - function handleThird(third) { + function handleThird(third: number) { throw new Error('We should not be here'); } ); @@ -355,17 +355,17 @@ suite('Flow', () => { done(); }, - function getFirst() { + function getFirst(this: any) { asyncGet('1', this); }, - function handleFirst(first) { + function handleFirst(this: any, first: number) { assert.deepEqual('1', first); assertionCount++; asyncGetError('2', this); }, - function handleSecond(second) { + function handleSecond(second: number) { throw new Error('We should not be here'); } ); @@ -377,7 +377,7 @@ suite('Flow', () => { done(); }, - function getFirst() { + function getFirst(this: any) { syncSequenceGetThrowsError('1', this); } ); @@ -392,16 +392,16 @@ suite('Flow', () => { errorCount++; }, - function getFirst() { + function getFirst(this: any) { this(true); }, - function getSecond(result) { + function getSecond(this: any, result: boolean) { assert.equal(result, true); this(false); }, - function last(result) { + function last(result: boolean) { assert.equal(result, false); assertionCount++; diff --git a/src/vs/base/test/node/glob.test.ts b/src/vs/base/test/node/glob.test.ts index 1e3183171bd..de91bfb6ab5 100644 --- a/src/vs/base/test/node/glob.test.ts +++ b/src/vs/base/test/node/glob.test.ts @@ -7,6 +7,7 @@ import * as assert from 'assert'; import * as path from 'path'; import glob = require('vs/base/common/glob'); +import { isWindows } from 'vs/base/common/platform'; suite('Glob', () => { @@ -415,7 +416,7 @@ suite('Glob', () => { assert.strictEqual(glob.match(expression, 'test.js', () => siblings), null); - expression = { + expression = { '**/*.js': { } }; @@ -459,6 +460,46 @@ suite('Glob', () => { assert(!glob.match(p, 'foo.8')); assert(!glob.match(p, 'bar.5')); assert(glob.match(p, 'foo.f')); + + p = 'foo.[!0-9]'; + + assert(!glob.match(p, 'foo.5')); + assert(!glob.match(p, 'foo.8')); + assert(!glob.match(p, 'bar.5')); + assert(glob.match(p, 'foo.f')); + + p = 'foo.[0!^*?]'; + + assert(!glob.match(p, 'foo.5')); + assert(!glob.match(p, 'foo.8')); + assert(glob.match(p, 'foo.0')); + assert(glob.match(p, 'foo.!')); + assert(glob.match(p, 'foo.^')); + assert(glob.match(p, 'foo.*')); + assert(glob.match(p, 'foo.?')); + + p = 'foo[/]bar'; + + assert(!glob.match(p, 'foo/bar')); + + p = 'foo.[[]'; + + assert(glob.match(p, 'foo.[')); + + p = 'foo.[]]'; + + assert(glob.match(p, 'foo.]')); + + p = 'foo.[][!]'; + + assert(glob.match(p, 'foo.]')); + assert(glob.match(p, 'foo.[')); + assert(glob.match(p, 'foo.!')); + + p = 'foo.[]-]'; + + assert(glob.match(p, 'foo.]')); + assert(glob.match(p, 'foo.-')); }); test('full path', function () { @@ -884,4 +925,56 @@ suite('Glob', () => { // Later expressions take precedence assert.deepEqual(glob.mergeExpressions({ 'a': true, 'b': false, 'c': true }, { 'a': false, 'b': true }), { 'a': false, 'b': true, 'c': true }); }); + + test('relative pattern - glob star', function () { + if (isWindows) { + let p = { base: 'C:\\DNXConsoleApp\\foo', pattern: '**/*.cs' }; + assert(glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.cs')); + assert(glob.match(p, 'C:\\DNXConsoleApp\\foo\\bar\\Program.cs')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.ts')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\Program.cs')); + assert(!glob.match(p, 'C:\\other\\DNXConsoleApp\\foo\\Program.ts')); + } else { + let p: glob.IRelativePattern = { base: '/DNXConsoleApp/foo', pattern: '**/*.cs' }; + assert(glob.match(p, '/DNXConsoleApp/foo/Program.cs')); + assert(glob.match(p, '/DNXConsoleApp/foo/bar/Program.cs')); + assert(!glob.match(p, '/DNXConsoleApp/foo/Program.ts')); + assert(!glob.match(p, '/DNXConsoleApp/Program.cs')); + assert(!glob.match(p, '/other/DNXConsoleApp/foo/Program.ts')); + } + }); + + test('relative pattern - single star', function () { + if (isWindows) { + let p = { base: 'C:\\DNXConsoleApp\\foo', pattern: '*.cs' }; + assert(glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.cs')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\foo\\bar\\Program.cs')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.ts')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\Program.cs')); + assert(!glob.match(p, 'C:\\other\\DNXConsoleApp\\foo\\Program.ts')); + } else { + let p: glob.IRelativePattern = { base: '/DNXConsoleApp/foo', pattern: '*.cs' }; + assert(glob.match(p, '/DNXConsoleApp/foo/Program.cs')); + assert(!glob.match(p, '/DNXConsoleApp/foo/bar/Program.cs')); + assert(!glob.match(p, '/DNXConsoleApp/foo/Program.ts')); + assert(!glob.match(p, '/DNXConsoleApp/Program.cs')); + assert(!glob.match(p, '/other/DNXConsoleApp/foo/Program.ts')); + } + }); + + test('relative pattern - single star with path', function () { + if (isWindows) { + let p = { base: 'C:\\DNXConsoleApp\\foo', pattern: 'something/*.cs' }; + assert(glob.match(p, 'C:\\DNXConsoleApp\\foo\\something\\Program.cs')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.cs')); + } else { + let p: glob.IRelativePattern = { base: '/DNXConsoleApp/foo', pattern: 'something/*.cs' }; + assert(glob.match(p, '/DNXConsoleApp/foo/something/Program.cs')); + assert(!glob.match(p, '/DNXConsoleApp/foo/Program.cs')); + } + }); + + test('pattern with "base" does not explode - #36081', function () { + assert.ok(glob.match({ 'base': true }, 'base')); + }); }); \ No newline at end of file diff --git a/src/vs/code/electron-browser/contrib/contributions.ts b/src/vs/code/electron-browser/contrib/contributions.ts new file mode 100644 index 00000000000..acb31a18450 --- /dev/null +++ b/src/vs/code/electron-browser/contrib/contributions.ts @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { NodeCachedDataCleaner } from 'vs/code/electron-browser/contrib/nodeCachedDataCleaner'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; + +export function createSharedProcessContributions(service: IInstantiationService): void { + service.createInstance(NodeCachedDataCleaner); +} diff --git a/src/vs/code/electron-browser/contrib/nodeCachedDataCleaner.ts b/src/vs/code/electron-browser/contrib/nodeCachedDataCleaner.ts new file mode 100644 index 00000000000..2f56affc386 --- /dev/null +++ b/src/vs/code/electron-browser/contrib/nodeCachedDataCleaner.ts @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { join, basename, dirname } from 'path'; +import { readdir, rimraf, stat } from 'vs/base/node/pfs'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import product from 'vs/platform/node/product'; + +export class NodeCachedDataCleaner { + + private static _DataMaxAge = product.nameLong.indexOf('Insiders') >= 0 + ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week + : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months + + private _disposables: IDisposable[] = []; + + constructor( + @IEnvironmentService private readonly _environmentService: IEnvironmentService + ) { + this._manageCachedDataSoon(); + } + + dispose(): void { + this._disposables = dispose(this._disposables); + } + + private _manageCachedDataSoon(): void { + // Cached data is stored as user data and we run a cleanup task everytime + // the editor starts. The strategy is to delete all files that are older than + // 3 months (1 week respectively) + if (!this._environmentService.nodeCachedDataDir) { + return; + } + + // The folder which contains folders of cached data. Each of these folder is per + // version + const nodeCachedDataRootDir = dirname(this._environmentService.nodeCachedDataDir); + const nodeCachedDataCurrent = basename(this._environmentService.nodeCachedDataDir); + + let handle = setTimeout(() => { + handle = undefined; + + readdir(nodeCachedDataRootDir).then(entries => { + + const now = Date.now(); + const deletes: TPromise[] = []; + + entries.forEach(entry => { + // name check + // * not the current cached data folder + if (entry !== nodeCachedDataCurrent) { + + const path = join(nodeCachedDataRootDir, entry); + deletes.push(stat(path).then(stats => { + // stat check + // * only directories + // * only when old enough + if (stats.isDirectory()) { + const diff = now - stats.mtime.getTime(); + if (diff > NodeCachedDataCleaner._DataMaxAge) { + return rimraf(path); + } + } + return undefined; + })); + } + }); + + return TPromise.join(deletes); + + }).done(undefined, onUnexpectedError); + + }, 30 * 1000); + + this._disposables.push({ + dispose() { clearTimeout(handle); } + }); + } +} diff --git a/src/vs/code/electron-browser/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcessMain.ts index ef7a31319cf..a379f352d8f 100644 --- a/src/vs/code/electron-browser/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcessMain.ts @@ -35,6 +35,7 @@ import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc'; import { ipcRenderer } from 'electron'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { StorageService, inMemoryLocalStorageInstance } from 'vs/platform/storage/common/storageService'; +import { createSharedProcessContributions } from 'vs/code/electron-browser/contrib/contributions'; interface ISharedProcessInitData { sharedIPCHandle: string; @@ -98,16 +99,18 @@ function main(server: Server, initData: ISharedProcessInitData): void { server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appender)); const services = new ServiceCollection(); - const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, extensionTestsPath } = accessor.get(IEnvironmentService); + const environmentService = accessor.get(IEnvironmentService); + const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, extensionTestsPath, installSource } = environmentService; - if (isBuilt && !extensionDevelopmentPath && product.enableTelemetry) { + if (isBuilt && !extensionDevelopmentPath && !environmentService.args['disable-telemetry'] && product.enableTelemetry) { const disableStorage = !!extensionTestsPath; // never keep any state when running extension tests! const storage = disableStorage ? inMemoryLocalStorageInstance : window.localStorage; const storageService = new StorageService(storage, storage); const config: ITelemetryServiceConfig = { appender, - commonProperties: resolveCommonProperties(product.commit, pkg.version) + commonProperties: resolveCommonProperties(product.commit, pkg.version, installSource) + // __GDPR__COMMON__ "common.machineId" : { "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } .then(result => Object.defineProperty(result, 'common.machineId', { get: () => storageService.get(machineIdStorageKey), enumerable: true @@ -132,6 +135,8 @@ function main(server: Server, initData: ISharedProcessInitData): void { // clean up deprecated extensions (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions(); + + createSharedProcessContributions(instantiationService2); }); }); } diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 51b6db552f4..5683665f46b 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -5,7 +5,7 @@ 'use strict'; -import { app, ipcMain as ipc, BrowserWindow } from 'electron'; +import { app, ipcMain as ipc, BrowserWindow, dialog } from 'electron'; import * as platform from 'vs/base/common/platform'; import { WindowsManager } from 'vs/code/electron-main/windows'; import { IWindowsService, OpenContext } from 'vs/platform/windows/common/windows'; @@ -59,7 +59,7 @@ import { touch } from 'vs/base/node/pfs'; export class CodeApplication { - private static APP_ICON_REFRESH_KEY = 'macOSAppIconRefresh'; + private static APP_ICON_REFRESH_KEY = 'macOSAppIconRefresh3'; private toDispose: IDisposable[]; private windowsMainService: IWindowsMainService; @@ -76,7 +76,7 @@ export class CodeApplication { @ILogService private logService: ILogService, @IEnvironmentService private environmentService: IEnvironmentService, @ILifecycleService private lifecycleService: ILifecycleService, - @IConfigurationService private configurationService: ConfigurationService, + @IConfigurationService configurationService: ConfigurationService, @IStorageService private storageService: IStorageService, @IHistoryMainService private historyService: IHistoryMainService ) { @@ -228,9 +228,9 @@ export class CodeApplication { }); // Keyboard layout changes - KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(isISOKeyboard => { + KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => { if (this.windowsMainService) { - this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', isISOKeyboard); + this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false); } }); } @@ -291,10 +291,11 @@ export class CodeApplication { services.set(ICredentialsService, new SyncDescriptor(CredentialsService)); // Telemtry - if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !!product.enableTelemetry) { + if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { const channel = getDelayedChannel(this.sharedProcessClient.then(c => c.getChannel('telemetryAppender'))); const appender = new TelemetryAppenderClient(channel); - const commonProperties = resolveCommonProperties(product.commit, pkg.version) + const commonProperties = resolveCommonProperties(product.commit, pkg.version, this.environmentService.installSource) + // __GDPR__COMMON__ "common.machineId" : { "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } .then(result => Object.defineProperty(result, 'common.machineId', { get: () => this.storageService.getItem(machineIdStorageKey), enumerable: true @@ -370,15 +371,40 @@ export class CodeApplication { private afterWindowOpen(accessor: ServicesAccessor): void { const appInstantiationService = accessor.get(IInstantiationService); - // Setup Windows mutex let windowsMutex: Mutex = null; if (platform.isWindows) { + + // Setup Windows mutex try { const Mutex = (require.__$__nodeRequire('windows-mutex') as any).Mutex; windowsMutex = new Mutex(product.win32MutexName); this.toDispose.push({ dispose: () => windowsMutex.release() }); } catch (e) { - // noop + if (!this.environmentService.isBuilt) { + dialog.showMessageBox({ + title: product.nameLong, + type: 'warning', + message: 'Failed to load windows-mutex!', + detail: e.toString(), + noLink: true + }); + } + } + + // Ensure Windows foreground love module + try { + // tslint:disable-next-line:no-unused-expression + require.__$__nodeRequire('windows-foreground-love'); + } catch (e) { + if (!this.environmentService.isBuilt) { + dialog.showMessageBox({ + title: product.nameLong, + type: 'warning', + message: 'Failed to load windows-foreground-love!', + detail: e.toString(), + noLink: true + }); + } } } diff --git a/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts index 64492f3e3a4..6434cfd557c 100644 --- a/src/vs/code/electron-main/auth.ts +++ b/src/vs/code/electron-main/auth.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; -import { fromEventEmitter } from 'vs/base/node/event'; +import { fromNodeEventEmitter } from 'vs/base/common/event'; import { BrowserWindow, app } from 'electron'; type LoginEvent = { @@ -34,7 +34,7 @@ export class ProxyAuthHandler { constructor( @IWindowsMainService private windowsService: IWindowsMainService ) { - const onLogin = fromEventEmitter(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb })); + const onLogin = fromNodeEventEmitter(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb })); onLogin(this.onLogin, this, this.disposables); } @@ -79,6 +79,7 @@ export class ProxyAuthHandler { const onWindowClose = () => cb('', ''); win.on('close', onWindowClose); + win.setMenu(null); win.loadURL(url); win.webContents.executeJavaScript(javascript, true).then(({ username, password }: Credentials) => { cb(username, password); diff --git a/src/vs/code/electron-main/keyboard.ts b/src/vs/code/electron-main/keyboard.ts index e44e0cda3eb..d7d10e70d7b 100644 --- a/src/vs/code/electron-main/keyboard.ts +++ b/src/vs/code/electron-main/keyboard.ts @@ -7,7 +7,6 @@ import * as nativeKeymap from 'native-keymap'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { isMacintosh } from 'vs/base/common/platform'; import { IStorageService } from 'vs/platform/storage/node/storage'; import Event, { Emitter, once } from 'vs/base/common/event'; import { ConfigWatcher } from 'vs/base/node/config'; @@ -21,59 +20,24 @@ export class KeyboardLayoutMonitor { public static readonly INSTANCE = new KeyboardLayoutMonitor(); - private _emitter: Emitter; + private _emitter: Emitter; private _registered: boolean; - private _isISOKeyboard: boolean; private constructor() { - this._emitter = new Emitter(); + this._emitter = new Emitter(); this._registered = false; - this._isISOKeyboard = this._readIsISOKeyboard(); } - public onDidChangeKeyboardLayout(callback: (isISOKeyboard: boolean) => void): IDisposable { + public onDidChangeKeyboardLayout(callback: () => void): IDisposable { if (!this._registered) { this._registered = true; nativeKeymap.onDidChangeKeyboardLayout(() => { - this._emitter.fire(this._isISOKeyboard); + this._emitter.fire(); }); - - if (isMacintosh) { - // See https://github.com/Microsoft/vscode/issues/24153 - // On OSX, on ISO keyboards, Chromium swaps the scan codes - // of IntlBackslash and Backquote. - // - // The C++ methods can give the current keyboard type (ISO or not) - // only after a NSEvent was handled. - // - // We therefore poll. - setInterval(() => { - let newValue = this._readIsISOKeyboard(); - if (this._isISOKeyboard === newValue) { - // no change - return; - } - - this._isISOKeyboard = newValue; - this._emitter.fire(this._isISOKeyboard); - - }, 3000); - } } return this._emitter.event(callback); } - - private _readIsISOKeyboard(): boolean { - if (isMacintosh) { - return nativeKeymap.isISOKeyboard(); - } - return false; - } - - public isISOKeyboard(): boolean { - return this._isISOKeyboard; - } } export interface IKeybinding { @@ -174,4 +138,9 @@ export class KeybindingsResolver { return this.keybindings[commandId]; } + + public dispose(): void { + this._onKeybindingsChanged.dispose(); + this.keybindingsWatcher.dispose(); + } } \ No newline at end of file diff --git a/src/vs/code/electron-main/launch.ts b/src/vs/code/electron-main/launch.ts index 7c56c411513..189224ef9c6 100644 --- a/src/vs/code/electron-main/launch.ts +++ b/src/vs/code/electron-main/launch.ts @@ -14,6 +14,7 @@ import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; +import { whenDeleted } from 'vs/base/node/pfs'; export const ID = 'launchService'; export const ILaunchService = createDecorator(ID); @@ -104,8 +105,8 @@ export class LaunchService implements ILaunchService { context, cli: args, userEnv, - forceNewWindow: args.wait || args['new-window'], - preferNewWindow: !args['reuse-window'], + forceNewWindow: args['new-window'], + preferNewWindow: !args['reuse-window'] && !args.wait, forceReuseWindow: args['reuse-window'], diffMode: args.diff, addMode: args.add @@ -113,9 +114,13 @@ export class LaunchService implements ILaunchService { } // If the other instance is waiting to be killed, we hook up a window listener if one window - // is being used and only then resolve the startup promise which will kill this second instance + // is being used and only then resolve the startup promise which will kill this second instance. + // In addition, we poll for the wait marker file to be deleted to return. if (args.wait && usedWindows.length === 1 && usedWindows[0]) { - return this.windowsService.waitForWindowClose(usedWindows[0].id); + return TPromise.any([ + this.windowsService.waitForWindowCloseOrLoad(usedWindows[0].id), + whenDeleted(args.waitMarkerFilePath) + ]).then(() => void 0, () => void 0); } return TPromise.as(null); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index e78ec8c97b8..ea526f1c4c0 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -138,7 +138,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise { // it happens on Linux and OS X that the pipe is left behind // let's delete it, since we can't connect to it - // and the retry the whole thing + // and then retry the whole thing try { fs.unlinkSync(environmentService.mainIPCHandle); } catch (e) { @@ -214,4 +214,4 @@ function main() { }).done(null, err => instantiationService.invokeFunction(quit, err)); } -main(); \ No newline at end of file +main(); diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 782824af672..9d48e22e95d 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -10,9 +10,9 @@ import { isMacintosh, isLinux, isWindows, language } from 'vs/base/common/platfo import * as arrays from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem, BrowserWindow } from 'electron'; -import { OpenContext } from 'vs/platform/windows/common/windows'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { OpenContext, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { AutoSaveConfiguration } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IUpdateService, State as UpdateState } from 'vs/platform/update/common/update'; import product from 'vs/platform/node/product'; @@ -22,31 +22,16 @@ import { mnemonicMenuLabel as baseMnemonicLabel, unmnemonicLabel, getPathLabel } import { KeybindingsResolver } from 'vs/code/electron-main/keyboard'; import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows'; import { IHistoryMainService } from 'vs/platform/history/common/history'; -import { IWorkspaceIdentifier, IWorkspacesMainService, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; interface IExtensionViewlet { id: string; label: string; } -interface IConfiguration extends IFilesConfiguration { - window: { - enableMenuBarMnemonics: boolean; - }; - workbench: { - sideBar: { - location: 'left' | 'right'; - }, - statusBar: { - visible: boolean; - }, - activityBar: { - visible: boolean; - } - }; - editor: { - multiCursorModifier: 'ctrlCmd' | 'alt' - }; +interface IMenuItemClickHandler { + inDevTools: (contents: Electron.WebContents) => void; + inNoWindow: () => void; } const telemetryFrom = 'menu'; @@ -55,12 +40,15 @@ export class CodeMenu { private static MAX_MENU_RECENT_ENTRIES = 10; - private currentAutoSaveSetting: string; - private currentMultiCursorModifierSetting: string; - private currentSidebarLocation: 'left' | 'right'; - private currentStatusbarVisible: boolean; - private currentActivityBarVisible: boolean; - private currentEnableMenuBarMnemonics: boolean; + private keys = [ + 'files.autoSave', + 'editor.multiCursorModifier', + 'workbench.sideBar.location', + 'workbench.statusBar.visible', + 'workbench.activityBar.visible', + 'window.enableMenuBarMnemonics', + 'window.nativeTabs' + ]; private isQuitting: boolean; private appMenuInstalled: boolean; @@ -73,7 +61,8 @@ export class CodeMenu { private closeFolder: Electron.MenuItem; private closeWorkspace: Electron.MenuItem; - private saveWorkspaceAs: Electron.MenuItem; + + private nativeTabMenuItems: Electron.MenuItem[]; constructor( @IUpdateService private updateService: IUpdateService, @@ -82,16 +71,14 @@ export class CodeMenu { @IWindowsMainService private windowsService: IWindowsMainService, @IEnvironmentService private environmentService: IEnvironmentService, @ITelemetryService private telemetryService: ITelemetryService, - @IHistoryMainService private historyService: IHistoryMainService, - @IWorkspacesMainService private workspacesService: IWorkspacesMainService + @IHistoryMainService private historyService: IHistoryMainService ) { this.extensionViewlets = []; + this.nativeTabMenuItems = []; this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0); this.keybindingsResolver = instantiationService.createInstance(KeybindingsResolver); - this.onConfigurationUpdated(this.configurationService.getConfiguration()); - this.install(); this.registerListeners(); @@ -127,7 +114,7 @@ export class CodeMenu { }); // Update when auto save config changes - this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), true /* update menu if changed */)); + this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)); // Listen to update service this.updateService.onStateChange(() => this.updateMenu()); @@ -136,58 +123,56 @@ export class CodeMenu { this.keybindingsResolver.onKeybindingsChanged(() => this.updateMenu()); } - private onConfigurationUpdated(config: IConfiguration, handleMenu?: boolean): void { - let updateMenu = false; - const newAutoSaveSetting = config && config.files && config.files.autoSave; - if (newAutoSaveSetting !== this.currentAutoSaveSetting) { - this.currentAutoSaveSetting = newAutoSaveSetting; - updateMenu = true; - } - - const newMultiCursorModifierSetting = config && config.editor && config.editor.multiCursorModifier; - if (newMultiCursorModifierSetting !== this.currentMultiCursorModifierSetting) { - this.currentMultiCursorModifierSetting = newMultiCursorModifierSetting; - updateMenu = true; - } - - const newSidebarLocation = config && config.workbench && config.workbench.sideBar && config.workbench.sideBar.location || 'left'; - if (newSidebarLocation !== this.currentSidebarLocation) { - this.currentSidebarLocation = newSidebarLocation; - updateMenu = true; - } - - let newStatusbarVisible = config && config.workbench && config.workbench.statusBar && config.workbench.statusBar.visible; - if (typeof newStatusbarVisible !== 'boolean') { - newStatusbarVisible = true; - } - if (newStatusbarVisible !== this.currentStatusbarVisible) { - this.currentStatusbarVisible = newStatusbarVisible; - updateMenu = true; - } - - let newActivityBarVisible = config && config.workbench && config.workbench.activityBar && config.workbench.activityBar.visible; - if (typeof newActivityBarVisible !== 'boolean') { - newActivityBarVisible = true; - } - if (newActivityBarVisible !== this.currentActivityBarVisible) { - this.currentActivityBarVisible = newActivityBarVisible; - updateMenu = true; - } - - let newEnableMenuBarMnemonics = config && config.window && config.window.enableMenuBarMnemonics; - if (typeof newEnableMenuBarMnemonics !== 'boolean') { - newEnableMenuBarMnemonics = true; - } - if (newEnableMenuBarMnemonics !== this.currentEnableMenuBarMnemonics) { - this.currentEnableMenuBarMnemonics = newEnableMenuBarMnemonics; - updateMenu = true; - } - - if (handleMenu && updateMenu) { + private onConfigurationUpdated(event: IConfigurationChangeEvent): void { + if (this.keys.some(key => event.affectsConfiguration(key))) { this.updateMenu(); } } + private get currentAutoSaveSetting(): string { + return this.configurationService.getValue('files.autoSave'); + } + + private get currentMultiCursorModifierSetting(): string { + return this.configurationService.getValue('editor.multiCursorModifier'); + } + + private get currentSidebarLocation(): string { + return this.configurationService.getValue('workbench.sideBar.location') || 'left'; + } + + private get currentStatusbarVisible(): boolean { + let statusbarVisible = this.configurationService.getValue('workbench.statusBar.visible'); + if (typeof statusbarVisible !== 'boolean') { + statusbarVisible = true; + } + return statusbarVisible; + } + + private get currentActivityBarVisible(): boolean { + let activityBarVisible = this.configurationService.getValue('workbench.activityBar.visible'); + if (typeof activityBarVisible !== 'boolean') { + activityBarVisible = true; + } + return activityBarVisible; + } + + private get currentEnableMenuBarMnemonics(): boolean { + let enableMenuBarMnemonics = this.configurationService.getValue('window.enableMenuBarMnemonics'); + if (typeof enableMenuBarMnemonics !== 'boolean') { + enableMenuBarMnemonics = true; + } + return enableMenuBarMnemonics; + } + + private get currentEnableNativeTabs(): boolean { + let enableNativeTabs = this.configurationService.getValue('window.nativeTabs'); + if (typeof enableNativeTabs !== 'boolean') { + enableNativeTabs = false; + } + return enableNativeTabs; + } + private updateMenu(): void { this.menuUpdater.schedule(); // buffer multiple attempts to update the menu } @@ -217,6 +202,15 @@ export class CodeMenu { if ((e.oldCount === 0 && e.newCount > 0) || (e.oldCount > 0 && e.newCount === 0)) { this.updateMenu(); } + + // Update specific items that are dependent on window count + else if (this.currentEnableNativeTabs) { + this.nativeTabMenuItems.forEach(item => { + if (item) { + item.enabled = e.newCount > 1; + } + }); + } } private updateWorkspaceMenuItems(): void { @@ -226,8 +220,7 @@ export class CodeMenu { this.closeWorkspace.visible = isInWorkspaceContext; this.closeFolder.visible = !isInWorkspaceContext; - this.closeFolder.enabled = isInFolderContext; - this.saveWorkspaceAs.enabled = isInFolderContext || isInWorkspaceContext; + this.closeFolder.enabled = isInFolderContext || isLinux /* https://github.com/Microsoft/vscode/issues/36431 */; } private install(): void { @@ -362,9 +355,26 @@ export class CodeMenu { newFile = this.createMenuItem(nls.localize({ key: 'miNewFile', comment: ['&& denotes a mnemonic'] }, "&&New File"), 'workbench.action.files.newUntitledFile'); } - const open = new MenuItem(this.likeAction('workbench.action.files.openFileFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), click: (menuItem, win, event) => this.windowsService.pickFileFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); - const openWorkspace = new MenuItem(this.likeAction('workbench.action.openWorkspace', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open Workspace...")), click: () => this.windowsService.openWorkspace() })); - const openFolder = new MenuItem(this.likeAction('workbench.action.files.openFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), click: (menuItem, win, event) => this.windowsService.pickFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + let open: Electron.MenuItem; + if (hasNoWindows) { + open = new MenuItem(this.likeAction('workbench.action.files.openFileFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...")), click: (menuItem, win, event) => this.windowsService.pickFileFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + } else { + open = this.createMenuItem(nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open..."), ['workbench.action.files.openFileFolder', 'workbench.action.files.openFileFolderInNewWindow']); + } + + let openWorkspace: Electron.MenuItem; + if (hasNoWindows) { + openWorkspace = new MenuItem(this.likeAction('workbench.action.openWorkspace', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open Workspace...")), click: (menuItem, win, event) => this.windowsService.pickWorkspaceAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + } else { + openWorkspace = this.createMenuItem(nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open Workspace..."), ['workbench.action.openWorkspace', 'workbench.action.openWorkspaceInNewWindow']); + } + + let openFolder: Electron.MenuItem; + if (hasNoWindows) { + openFolder = new MenuItem(this.likeAction('workbench.action.files.openFolder', { label: this.mnemonicLabel(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...")), click: (menuItem, win, event) => this.windowsService.pickFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }) })); + } else { + openFolder = this.createMenuItem(nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder..."), ['workbench.action.files.openFolder', 'workbench.action.files.openFolderInNewWindow']); + } let openFile: Electron.MenuItem; if (hasNoWindows) { @@ -377,9 +387,7 @@ export class CodeMenu { this.setOpenRecentMenu(openRecentMenu); const openRecent = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent")), submenu: openRecentMenu, enabled: openRecentMenu.items.length > 0 }); - const isMultiRootEnabled = (product.quality !== 'stable'); // TODO@Ben multi root - - this.saveWorkspaceAs = this.createMenuItem(nls.localize({ key: 'miSaveWorkspaceAs', comment: ['&& denotes a mnemonic'] }, "&&Save Workspace As..."), 'workbench.action.saveWorkspaceAs'); + const saveWorkspaceAs = this.createMenuItem(nls.localize({ key: 'miSaveWorkspaceAs', comment: ['&& denotes a mnemonic'] }, "&&Save Workspace As..."), 'workbench.action.saveWorkspaceAs'); const addFolder = this.createMenuItem(nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Add Folder to Workspace..."), 'workbench.action.addRootFolder'); const saveFile = this.createMenuItem(nls.localize({ key: 'miSave', comment: ['&& denotes a mnemonic'] }, "&&Save"), 'workbench.action.files.save'); @@ -411,11 +419,11 @@ export class CodeMenu { isMacintosh ? open : null, !isMacintosh ? openFile : null, !isMacintosh ? openFolder : null, - isMultiRootEnabled ? openWorkspace : null, + openWorkspace, openRecent, - isMultiRootEnabled ? __separator__() : null, - isMultiRootEnabled ? addFolder : null, - isMultiRootEnabled ? this.saveWorkspaceAs : null, + __separator__(), + addFolder, + saveWorkspaceAs, __separator__(), saveFile, saveFileAs, @@ -517,12 +525,12 @@ export class CodeMenu { }, false)); } - private isOptionClick(event: Electron.Event & Electron.Modifiers): boolean { + private isOptionClick(event: Electron.Event): boolean { return event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey))); } private createRoleMenuItem(label: string, commandId: string, role: Electron.MenuItemRole): Electron.MenuItem { - const options: Electron.MenuItemOptions = { + const options: Electron.MenuItemConstructorOptions = { label: this.mnemonicLabel(label), role, enabled: true @@ -539,8 +547,14 @@ export class CodeMenu { let paste: Electron.MenuItem; if (isMacintosh) { - undo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', devTools => devTools.undo()); - redo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', devTools => devTools.redo()); + undo = this.createContextAwareMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', { + inDevTools: devTools => devTools.undo(), + inNoWindow: () => Menu.sendActionToFirstResponder('undo:') + }); + redo = this.createContextAwareMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', { + inDevTools: devTools => devTools.redo(), + inNoWindow: () => Menu.sendActionToFirstResponder('redo:') + }); cut = this.createRoleMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"), 'editor.action.clipboardCutAction', 'cut'); copy = this.createRoleMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"), 'editor.action.clipboardCopyAction', 'copy'); paste = this.createRoleMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction', 'paste'); @@ -611,7 +625,10 @@ export class CodeMenu { let selectAll: Electron.MenuItem; if (isMacintosh) { - selectAll = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll', (devTools) => devTools.selectAll()); + selectAll = this.createContextAwareMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll', { + inDevTools: devTools => devTools.selectAll(), + inNoWindow: () => Menu.sendActionToFirstResponder('selectAll:') + }); } else { selectAll = this.createMenuItem(nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"), 'editor.action.selectAll'); } @@ -863,10 +880,26 @@ export class CodeMenu { const bringAllToFront = new MenuItem({ label: nls.localize('mBringToFront', "Bring All to Front"), role: 'front', enabled: this.windowsService.getWindowCount() > 0 }); const switchWindow = this.createMenuItem(nls.localize({ key: 'miSwitchWindow', comment: ['&& denotes a mnemonic'] }, "Switch &&Window..."), 'workbench.action.switchWindow'); + this.nativeTabMenuItems = []; + const nativeTabMenuItems: Electron.MenuItem[] = []; + if (this.currentEnableNativeTabs) { + const hasMultipleWindows = this.windowsService.getWindowCount() > 1; + + this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowPreviousTab', "Show Previous Tab"), 'workbench.action.showPreviousWindowTab', hasMultipleWindows)); + this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowNextTab', "Show Next Tab"), 'workbench.action.showNextWindowTab', hasMultipleWindows)); + this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mMoveTabToNewWindow', "Move Tab to New Window"), 'workbench.action.moveWindowTabToNewWindow', hasMultipleWindows)); + this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mMergeAllWindows', "Merge All Windows"), 'workbench.action.mergeAllWindowTabs', hasMultipleWindows)); + + nativeTabMenuItems.push(__separator__(), ...this.nativeTabMenuItems); + } else { + this.nativeTabMenuItems = []; + } + [ minimize, zoom, switchWindow, + ...nativeTabMenuItems, __separator__(), bringAllToFront ].forEach(item => macWindowMenu.append(item)); @@ -912,14 +945,14 @@ export class CodeMenu { const keyboardShortcutsUrl = isLinux ? product.keyboardShortcutsUrlLinux : isMacintosh ? product.keyboardShortcutsUrlMac : product.keyboardShortcutsUrlWin; arrays.coalesce([ - new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.showWelcomePage'), enabled: (this.windowsService.getWindowCount() > 0) }), - new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miInteractivePlayground', comment: ['&& denotes a mnemonic'] }, "&&Interactive Playground")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.showInteractivePlayground'), enabled: (this.windowsService.getWindowCount() > 0) }), - product.documentationUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.openDocumentationUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, - product.releaseNotesUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'update.showCurrentReleaseNotes'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")), click: () => this.runActionInRenderer('workbench.action.showWelcomePage'), enabled: (this.windowsService.getWindowCount() > 0) }), + new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miInteractivePlayground', comment: ['&& denotes a mnemonic'] }, "&&Interactive Playground")), click: () => this.runActionInRenderer('workbench.action.showInteractivePlayground'), enabled: (this.windowsService.getWindowCount() > 0) }), + product.documentationUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.runActionInRenderer('workbench.action.openDocumentationUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + product.releaseNotesUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.runActionInRenderer('update.showCurrentReleaseNotes'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, __separator__(), - keyboardShortcutsUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.keybindingsReference'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, - product.introductoryVideosUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.openIntroductoryVideosUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, - product.tipsAndTricksUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "&&Tips and Tricks")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.openTipsAndTricksUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + keyboardShortcutsUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")), click: () => this.runActionInRenderer('workbench.action.keybindingsReference'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + product.introductoryVideosUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")), click: () => this.runActionInRenderer('workbench.action.openIntroductoryVideosUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + product.tipsAndTricksUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "&&Tips and Tricks")), click: () => this.runActionInRenderer('workbench.action.openTipsAndTricksUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, (product.introductoryVideosUrl || keyboardShortcutsUrl) ? __separator__() : null, product.twitterUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(product.twitterUrl, 'openTwitterUrl') }) : null, product.requestFeatureUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")), click: () => this.openUrl(product.requestFeatureUrl, 'openUserVoiceUrl') }) : null, @@ -970,8 +1003,8 @@ export class CodeMenu { const terminateTask = this.createMenuItem(nls.localize({ key: 'miTerminateTask', comment: ['&& denotes a mnemonic'] }, "&&Terminate Task..."), 'workbench.action.tasks.terminate'); // const testTask = this.createMenuItem(nls.localize({ key: 'miTestTask', comment: ['&& denotes a mnemonic'] }, "Run Test T&&ask..."), 'workbench.action.tasks.test'); // const showTaskLog = this.createMenuItem(nls.localize({ key: 'miShowTaskLog', comment: ['&& denotes a mnemonic'] }, "&&Show Task Log"), 'workbench.action.tasks.showLog'); - const configureTask = this.createMenuItem(nls.localize({ key: 'miConfigureTask', comment: ['&& denotes a mnemonic'] }, "&&Configure Tasks"), 'workbench.action.tasks.configureTaskRunner'); - const configureBuildTask = this.createMenuItem(nls.localize({ key: 'miConfigureBuildTask', comment: ['&& denotes a mnemonic'] }, "Configure De&&fault Build Task"), 'workbench.action.tasks.configureDefaultBuildTask'); + const configureTask = this.createMenuItem(nls.localize({ key: 'miConfigureTask', comment: ['&& denotes a mnemonic'] }, "&&Configure Tasks..."), 'workbench.action.tasks.configureTaskRunner'); + const configureBuildTask = this.createMenuItem(nls.localize({ key: 'miConfigureBuildTask', comment: ['&& denotes a mnemonic'] }, "Configure De&&fault Build Task..."), 'workbench.action.tasks.configureDefaultBuildTask'); // const configureTestTask = this.createMenuItem(nls.localize({ key: 'miConfigureTestTask', comment: ['&& denotes a mnemonic'] }, "Configure Defau&< Test Task"), 'workbench.action.tasks.configureDefaultTestTask'); [ @@ -1054,13 +1087,13 @@ export class CodeMenu { private createMenuItem(label: string, click: () => void, enabled?: boolean, checked?: boolean): Electron.MenuItem; private createMenuItem(arg1: string, arg2: any, arg3?: boolean, arg4?: boolean): Electron.MenuItem { const label = this.mnemonicLabel(arg1); - const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: Electron.MenuItem, win: Electron.BrowserWindow, event: Electron.Event & Electron.Modifiers) => { + const click: () => void = (typeof arg2 === 'function') ? arg2 : (menuItem: Electron.MenuItem, win: Electron.BrowserWindow, event: Electron.Event) => { let commandId = arg2; if (Array.isArray(arg2)) { commandId = this.isOptionClick(event) ? arg2[1] : arg2[0]; // support alternative action if we got multiple action Ids and the option key was pressed while invoking } - this.windowsService.sendToFocused('vscode:runAction', commandId); + this.runActionInRenderer(commandId); }; const enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsService.getWindowCount() > 0; const checked = typeof arg4 === 'boolean' ? arg4 : false; @@ -1070,7 +1103,7 @@ export class CodeMenu { commandId = arg2; } - const options: Electron.MenuItemOptions = { + const options: Electron.MenuItemConstructorOptions = { label, click, enabled @@ -1084,26 +1117,34 @@ export class CodeMenu { return new MenuItem(this.withKeybinding(commandId, options)); } - private createDevToolsAwareMenuItem(label: string, commandId: string, devToolsFocusedFn: (contents: Electron.WebContents) => void): Electron.MenuItem { + private createContextAwareMenuItem(label: string, commandId: string, clickHandler: IMenuItemClickHandler): Electron.MenuItem { return new MenuItem(this.withKeybinding(commandId, { label: this.mnemonicLabel(label), enabled: this.windowsService.getWindowCount() > 0, click: () => { - const windowInFocus = this.windowsService.getFocusedWindow(); - if (!windowInFocus) { - return; + + // No Active Window + const activeWindow = this.windowsService.getFocusedWindow(); + if (!activeWindow) { + return clickHandler.inNoWindow(); } - if (windowInFocus.win.webContents.isDevToolsFocused()) { - devToolsFocusedFn(windowInFocus.win.webContents.devToolsWebContents); - } else { - this.windowsService.sendToFocused('vscode:runAction', commandId); + // DevTools focused + if (activeWindow.win.webContents.isDevToolsFocused()) { + return clickHandler.inDevTools(activeWindow.win.webContents.devToolsWebContents); } + + // Finally execute command in Window + this.runActionInRenderer(commandId); } })); } - private withKeybinding(commandId: string, options: Electron.MenuItemOptions): Electron.MenuItemOptions { + private runActionInRenderer(id: string): void { + this.windowsService.sendToFocused('vscode:runAction', { id, from: 'menu' } as IRunActionInWindowRequest); + } + + private withKeybinding(commandId: string, options: Electron.MenuItemConstructorOptions): Electron.MenuItemConstructorOptions { const binding = this.keybindingsResolver.getKeybinding(commandId); // Apply binding if there is one @@ -1134,7 +1175,7 @@ export class CodeMenu { return options; } - private likeAction(commandId: string, options: Electron.MenuItemOptions, setAccelerator = !options.accelerator): Electron.MenuItemOptions { + private likeAction(commandId: string, options: Electron.MenuItemConstructorOptions, setAccelerator = !options.accelerator): Electron.MenuItemConstructorOptions { if (setAccelerator) { options = this.withKeybinding(commandId, options); } @@ -1180,6 +1221,12 @@ export class CodeMenu { } private reportMenuActionTelemetry(id: string): void { + /* __GDPR__ + "workbencActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id, from: telemetryFrom }); } diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 238f028c015..4a11a3a662f 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -11,7 +11,7 @@ import { stopProfiling } from 'vs/base/node/profiler'; import nls = require('vs/nls'); import URI from 'vs/base/common/uri'; import { IStorageService } from 'vs/platform/storage/node/storage'; -import { shell, screen, BrowserWindow, systemPreferences, app } from 'electron'; +import { shell, screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage } from 'electron'; import { TPromise, TValueCallback } from 'vs/base/common/winjs.base'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; @@ -19,13 +19,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { parseArgs } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; -import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces'; import { IBackupMainService } from 'vs/platform/backup/common/backup'; +import { ICommandAction } from 'vs/platform/actions/common/actions'; +import { mark, getEntries } from 'vs/base/common/performance'; export interface IWindowState { width?: number; @@ -65,6 +66,10 @@ interface IWorkbenchEditorConfiguration { }; } +interface ITouchBarSegment extends Electron.SegmentedControlSegment { + id: string; +} + export class CodeWindow implements ICodeWindow { public static themeStorageKey = 'theme'; @@ -93,6 +98,8 @@ export class CodeWindow implements ICodeWindow { private currentConfig: IWindowConfiguration; private pendingLoadConfig: IWindowConfiguration; + private touchBarGroups: Electron.TouchBarSegmentedControl[]; + constructor( config: IWindowCreationOptions, @ILogService private logService: ILogService, @@ -102,6 +109,7 @@ export class CodeWindow implements ICodeWindow { @IWorkspacesMainService private workspaceService: IWorkspacesMainService, @IBackupMainService private backupService: IBackupMainService ) { + this.touchBarGroups = []; this._lastFocusTime = -1; this._readyState = ReadyState.NONE; this.whenReadyCallbacks = []; @@ -113,6 +121,9 @@ export class CodeWindow implements ICodeWindow { // respect configured menu bar visibility this.onConfigurationUpdated(); + // macOS: touch bar support + this.createTouchBar(); + // Eventing this.registerListeners(); } @@ -130,7 +141,7 @@ export class CodeWindow implements ICodeWindow { backgroundColor = '#171717'; // https://github.com/electron/electron/issues/5150 } - const options: Electron.BrowserWindowOptions = { + const options: Electron.BrowserWindowConstructorOptions = { width: this.windowState.width, height: this.windowState.height, x: this.windowState.x, @@ -179,6 +190,23 @@ export class CodeWindow implements ICodeWindow { this._win = new BrowserWindow(options); this._id = this._win.id; + // TODO@Ben Bug in Electron (https://github.com/electron/electron/issues/10862). On multi-monitor setups, + // it can happen that the position we set to the window is not the correct one on the display. + // To workaround, we ask the window for its position and set it again if not matching. + // This only applies if the window is not fullscreen or maximized and multiple monitors are used. + if (isWindows && !isFullscreenOrMaximized) { + try { + if (screen.getAllDisplays().length > 1) { + const [x, y] = this._win.getPosition(); + if (x !== this.windowState.x || y !== this.windowState.y) { + this._win.setPosition(this.windowState.x, this.windowState.y, false); + } + } + } catch (err) { + this.logService.log(`Unexpected error fixing window position on windows with multiple windows: ${err}\n${err.stack}`); + } + } + if (useCustomTitleStyle) { this._win.setSheetOffset(22); // offset dialogs by the height of the custom title bar if we have any } @@ -279,10 +307,6 @@ export class CodeWindow implements ICodeWindow { return this.currentConfig ? this.currentConfig.folderPath : void 0; } - public get openedFilePath(): string { - return this.currentConfig && this.currentConfig.filesToOpen && this.currentConfig.filesToOpen[0] && this.currentConfig.filesToOpen[0].filePath; - } - public setReady(): void { this._readyState = ReadyState.READY; @@ -320,7 +344,7 @@ export class CodeWindow implements ICodeWindow { }); // Prevent loading of svgs - this._win.webContents.session.webRequest.onBeforeRequest((details, callback) => { + this._win.webContents.session.webRequest.onBeforeRequest(null, (details, callback) => { if (details.url.indexOf('.svg') > 0) { const uri = URI.parse(details.url); if (uri && !uri.scheme.match(/file/i) && (uri.path as any).endsWith('.svg')) { @@ -331,7 +355,7 @@ export class CodeWindow implements ICodeWindow { return callback({}); }); - this._win.webContents.session.webRequest.onHeadersReceived((details, callback) => { + this._win.webContents.session.webRequest.onHeadersReceived(null, (details, callback) => { const contentType: string[] = (details.responseHeaders['content-type'] || details.responseHeaders['Content-Type']) as any; if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) { return callback({ cancel: true }); @@ -388,7 +412,7 @@ export class CodeWindow implements ICodeWindow { }); // Window Failed to load - this._win.webContents.on('did-fail-load', (event: Event, errorCode: string, errorDescription: string) => { + this._win.webContents.on('did-fail-load', (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => { this.logService.warn('[electron event]: fail to load, ', errorDescription); }); @@ -403,7 +427,7 @@ export class CodeWindow implements ICodeWindow { } // Handle configuration changes - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated())); // Handle Workspace events this.toDispose.push(this.workspaceService.onUntitledWorkspaceDeleted(e => this.onUntitledWorkspaceDeleted(e))); @@ -434,18 +458,18 @@ export class CodeWindow implements ICodeWindow { this._win.removeAllListeners('swipe'); } } - }; + } private registerNavigationListenerOn(command: 'swipe' | 'app-command', back: 'left' | 'browser-backward', forward: 'right' | 'browser-forward', acrossEditors: boolean) { - this._win.on(command, (e: Electron.Event, cmd: string) => { + this._win.on(command as 'swipe' /* | 'app-command' */, (e: Electron.Event, cmd: string) => { if (this.readyState !== ReadyState.READY) { return; // window must be ready } if (cmd === back) { - this.send('vscode:runAction', acrossEditors ? 'workbench.action.openPreviousRecentlyUsedEditor' : 'workbench.action.navigateBack'); + this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openPreviousRecentlyUsedEditor' : 'workbench.action.navigateBack', from: 'mouse' } as IRunActionInWindowRequest); } else if (cmd === forward) { - this.send('vscode:runAction', acrossEditors ? 'workbench.action.openNextRecentlyUsedEditor' : 'workbench.action.navigateForward'); + this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openNextRecentlyUsedEditor' : 'workbench.action.navigateForward', from: 'mouse' } as IRunActionInWindowRequest); } }); } @@ -484,6 +508,7 @@ export class CodeWindow implements ICodeWindow { } // Load URL + mark('main:loadWindow'); this._win.loadURL(this.getUrl(config)); // Make window visible if it did not open in N seconds because this indicates an error @@ -516,6 +541,7 @@ export class CodeWindow implements ICodeWindow { delete configuration.filesToOpen; delete configuration.filesToCreate; delete configuration.filesToDiff; + delete configuration.filesToWait; // Some configuration things get inherited if the window is being reloaded and we are // in extension development mode. These options are all development related. @@ -549,14 +575,12 @@ export class CodeWindow implements ICodeWindow { windowConfiguration.highContrast = isWindows && systemPreferences.isInvertedColorScheme() && (!windowConfig || windowConfig.autoDetectHighContrast); windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled(); - // Set Keyboard Config - windowConfiguration.isISOKeyboard = KeyboardLayoutMonitor.INSTANCE.isISOKeyboard(); - // Theme windowConfiguration.baseTheme = this.getBaseTheme(); windowConfiguration.backgroundColor = this.getBackgroundColor(); // Perf Counters + windowConfiguration.perfEntries = getEntries(); windowConfiguration.perfStartTime = global.perfStartTime; windowConfiguration.perfAppReady = global.perfAppReady; windowConfiguration.perfWindowLoadTime = Date.now(); @@ -599,6 +623,9 @@ export class CodeWindow implements ICodeWindow { } public serializeWindowState(): IWindowState { + if (!this._win) { + return defaultWindowState(); + } // fullscreen gets special treatment if (this._win.isFullScreen()) { @@ -730,7 +757,13 @@ export class CodeWindow implements ICodeWindow { // Multi Monitor (non-fullscreen): be less strict because metrics can be crazy const bounds = { x: state.x, y: state.y, width: state.width, height: state.height }; const display = screen.getDisplayMatching(bounds); - if (display && display.bounds.x + display.bounds.width > bounds.x && display.bounds.y + display.bounds.height > bounds.y) { + if ( + display && // we have a display matching the desired bounds + bounds.x < display.bounds.x + display.bounds.width && // prevent window from falling out of the screen to the right + bounds.y < display.bounds.y + display.bounds.height && // prevent window from falling out of the screen to the bottom + bounds.x + bounds.width > display.bounds.x && // prevent window from falling out of the screen to the left + bounds.y + bounds.height > display.bounds.y // prevent window from falling out of the scree nto the top + ) { if (state.mode === WindowMode.Maximized) { const defaults = defaultWindowState(WindowMode.Maximized); // when maximized, make sure we have good values when the user restores the window defaults.x = state.x; // carefull to keep x/y position so that the window ends up on the correct monitor @@ -800,7 +833,7 @@ export class CodeWindow implements ICodeWindow { if (notify) { this.send('vscode:showInfoMessage', nls.localize('hiddenMenuBar', "You can still access the menu bar by pressing the **Alt** key.")); - }; + } break; case ('hidden'): @@ -814,7 +847,7 @@ export class CodeWindow implements ICodeWindow { this._win.setAutoHideMenuBar(false); }); break; - }; + } } public onWindowTitleDoubleClick(): void { @@ -860,6 +893,78 @@ export class CodeWindow implements ICodeWindow { this._win.webContents.send(channel, ...args); } + public updateTouchBar(groups: ICommandAction[][]): void { + if (!isMacintosh) { + return; // only supported on macOS + } + + // Update segments for all groups. Setting the segments property + // of the group directly prevents ugly flickering from happening + this.touchBarGroups.forEach((touchBarGroup, index) => { + const commands = groups[index]; + touchBarGroup.segments = this.createTouchBarGroupSegments(commands); + }); + } + + private createTouchBar(): void { + if (!isMacintosh) { + return; // only supported on macOS + } + + // To avoid flickering, we try to reuse the touch bar group + // as much as possible by creating a large number of groups + // for reusing later. + for (let i = 0; i < 10; i++) { + const groupTouchBar = this.createTouchBarGroup(); + this.touchBarGroups.push(groupTouchBar); + } + + // Ugly workaround for native crash on macOS 10.12.1. We are not + // leveraging the API for changing the ESC touch bar item. + // See https://github.com/electron/electron/issues/10442 + (this._win)._setEscapeTouchBarItem = () => { }; + + this._win.setTouchBar(new TouchBar({ items: this.touchBarGroups })); + } + + private createTouchBarGroup(items: ICommandAction[] = []): Electron.TouchBarSegmentedControl { + + // Group Segments + const segments = this.createTouchBarGroupSegments(items); + + // Group Control + const control = new TouchBar.TouchBarSegmentedControl({ + segments, + mode: 'buttons', + segmentStyle: 'automatic', + change: (selectedIndex) => { + this.sendWhenReady('vscode:runAction', { id: (control.segments[selectedIndex] as ITouchBarSegment).id, from: 'touchbar' }); + } + }); + + return control; + } + + private createTouchBarGroupSegments(items: ICommandAction[] = []): ITouchBarSegment[] { + const segments: ITouchBarSegment[] = items.map(item => { + let icon: Electron.NativeImage; + if (item.iconPath) { + icon = nativeImage.createFromPath(item.iconPath); + if (icon.isEmpty()) { + icon = void 0; + } + } + + return { + id: item.id, + label: !icon ? item.title as string : void 0, + icon + }; + }); + + return segments; + } + public dispose(): void { if (this.showTimeoutHandle) { clearTimeout(this.showTimeoutHandle); @@ -869,4 +974,4 @@ export class CodeWindow implements ICodeWindow { this._win = null; // Important to dereference the window object to allow for GC } -} \ No newline at end of file +} diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 8f319fc2933..f0d030a42ef 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -5,7 +5,7 @@ 'use strict'; -import * as path from 'path'; +import { basename, normalize, join, dirname } from 'path'; import * as fs from 'original-fs'; import { localize } from 'vs/nls'; import * as arrays from 'vs/base/common/arrays'; @@ -19,7 +19,7 @@ import { IPathWithLineAndColumn, parseLineAndColumnAware } from 'vs/code/node/pa import { ILifecycleService, UnloadReason, IWindowUnloadEvent } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; -import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, ReadyState } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, ReadyState, IPathsToWaitFor, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderPath } from 'vs/code/node/windowsFinder'; import CommonEvent, { Emitter } from 'vs/base/common/event'; import product from 'vs/platform/node/product'; @@ -29,9 +29,12 @@ import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent } fr import { IHistoryMainService } from 'vs/platform/history/common/history'; import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { Schemas } from 'vs/base/common/network'; +import { normalizeNFC } from 'vs/base/common/strings'; +import URI from 'vs/base/common/uri'; enum WindowError { UNRESPONSIVE, @@ -77,6 +80,7 @@ interface IOpenBrowserWindowOptions { filesToOpen?: IPath[]; filesToCreate?: IPath[]; filesToDiff?: IPath[]; + filesToWait?: IPathsToWaitFor; forceNewWindow?: boolean; windowToUse?: CodeWindow; @@ -113,6 +117,7 @@ export class WindowsManager implements IWindowsMainService { private lastClosedWindowState: IWindowState; private fileDialog: FileDialog; + private workspacesManager: WorkspacesManager; private _onWindowReady = new Emitter(); onWindowReady: CommonEvent = this._onWindowReady.event; @@ -120,6 +125,9 @@ export class WindowsManager implements IWindowsMainService { private _onWindowClose = new Emitter(); onWindowClose: CommonEvent = this._onWindowClose.event; + private _onWindowLoad = new Emitter(); + onWindowLoad: CommonEvent = this._onWindowLoad.event; + private _onActiveWindowChanged = new Emitter(); onActiveWindowChanged: CommonEvent = this._onActiveWindowChanged.event; @@ -135,14 +143,16 @@ export class WindowsManager implements IWindowsMainService { @IEnvironmentService private environmentService: IEnvironmentService, @ILifecycleService private lifecycleService: ILifecycleService, @IBackupMainService private backupService: IBackupMainService, - @ITelemetryService private telemetryService: ITelemetryService, + @ITelemetryService telemetryService: ITelemetryService, @IConfigurationService private configurationService: IConfigurationService, @IHistoryMainService private historyService: IHistoryMainService, @IWorkspacesMainService private workspacesService: IWorkspacesMainService, @IInstantiationService private instantiationService: IInstantiationService ) { this.windowsState = this.storageService.getItem(WindowsManager.windowsStateStorageKey) || { openedWindows: [] }; + this.fileDialog = new FileDialog(environmentService, telemetryService, storageService, this); + this.workspacesManager = new WorkspacesManager(workspacesService, backupService, environmentService, this); this.migrateLegacyWindowState(); } @@ -172,11 +182,6 @@ export class WindowsManager implements IWindowsMainService { state.folderPath = state.workspacePath; state.workspacePath = void 0; } - - // TODO@Ben migration to new workspace ID - if (state.workspace) { - state.workspace.id = this.workspacesService.getWorkspaceId(state.workspace.configPath); - } }); } @@ -273,7 +278,6 @@ export class WindowsManager implements IWindowsMainService { private onBeforeQuit(): void { const currentWindowsState: ILegacyWindowsState = { openedWindows: [], - openedFolders: [], // TODO@Ben migration so that old clients do not fail over data (prevents NPEs) lastPluginDevelopmentHostWindow: this.windowsState.lastPluginDevelopmentHostWindow, lastActiveWindow: this.lastClosedWindowState }; @@ -359,7 +363,7 @@ export class WindowsManager implements IWindowsMainService { // When run with --add, take the folders that are to be opened as // folders that should be added to the currently active window. let foldersToAdd: IPath[] = []; - if (openConfig.addMode && product.quality !== 'stable') { // TODO@Ben multi root + if (openConfig.addMode) { foldersToAdd = pathsToOpen.filter(path => !!path.folderPath).map(path => ({ filePath: path.folderPath })); pathsToOpen = pathsToOpen.filter(path => !path.folderPath); } @@ -376,6 +380,12 @@ export class WindowsManager implements IWindowsMainService { filesToCreate = []; // diff ignores other files that do not exist } + // When run with --wait, make sure we keep the paths to wait for + let filesToWait: IPathsToWaitFor; + if (openConfig.cli.wait && openConfig.cli.waitMarkerFilePath) { + filesToWait = { paths: [...filesToDiff, ...filesToOpen, ...filesToCreate], waitMarkerFilePath: openConfig.cli.waitMarkerFilePath }; + } + // // These are windows to open to show workspaces // @@ -399,7 +409,7 @@ export class WindowsManager implements IWindowsMainService { workspacesToRestore.push(...this.workspacesService.getUntitledWorkspacesSync()); // collect from previous window session emptyToRestore = this.backupService.getEmptyWindowBackupPaths(); - emptyToRestore.push(...pathsToOpen.filter(w => !w.workspace && !w.folderPath && w.backupPath).map(w => path.basename(w.backupPath))); // add empty windows with backupPath + emptyToRestore.push(...pathsToOpen.filter(w => !w.workspace && !w.folderPath && w.backupPath).map(w => basename(w.backupPath))); // add empty windows with backupPath emptyToRestore = arrays.distinct(emptyToRestore); // prevent duplicates } @@ -409,26 +419,44 @@ export class WindowsManager implements IWindowsMainService { const emptyToOpen = pathsToOpen.filter(win => !win.workspace && !win.folderPath && !win.filePath && !win.backupPath).length; // Open based on config - const usedWindows = this.doOpen(openConfig, workspacesToOpen, workspacesToRestore, foldersToOpen, foldersToRestore, emptyToRestore, emptyToOpen, filesToOpen, filesToCreate, filesToDiff, foldersToAdd); + const usedWindows = this.doOpen(openConfig, workspacesToOpen, workspacesToRestore, foldersToOpen, foldersToRestore, emptyToRestore, emptyToOpen, filesToOpen, filesToCreate, filesToDiff, filesToWait, foldersToAdd); - // Make sure to pass focus to one of the windows if we open multiple + // Make sure to pass focus to the most relevant of the windows if we open multiple if (usedWindows.length > 1) { - let focusLast = true; + let focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && !openConfig.cli._.length && (!openConfig.pathsToOpen || !openConfig.pathsToOpen.length); + let focusLastOpened = true; + let focusLastWindow = true; - // Only focus the last active window if the user did not open a specific path via - // CLI or API. In those cases we do not want windows to get focus from previous - // session but actually one of the windows the user explicitly asked to open. - const focusLastActive = !openConfig.forceEmpty && !openConfig.cli._.length && (!openConfig.pathsToOpen || !openConfig.pathsToOpen.length); - if (focusLastActive && this.windowsState.lastActiveWindow) { + // 1.) focus last active window if we are not instructed to open any paths + if (focusLastActive) { const lastActiveWindw = usedWindows.filter(w => w.backupPath === this.windowsState.lastActiveWindow.backupPath); if (lastActiveWindw.length) { lastActiveWindw[0].focus(); - focusLast = false; + focusLastOpened = false; + focusLastWindow = false; } } - // Otherwise: focus last window we opened - if (focusLast) { + // 2.) if instructed to open paths, focus last window which is not restored + if (focusLastOpened) { + for (let i = usedWindows.length - 1; i >= 0; i--) { + const usedWindow = usedWindows[i]; + if ( + (usedWindow.openedWorkspace && workspacesToRestore.some(workspace => workspace.id === usedWindow.openedWorkspace.id)) || // skip over restored workspace + (usedWindow.openedFolderPath && foldersToRestore.some(folder => folder === usedWindow.openedFolderPath)) || // skip over restored folder + (usedWindow.backupPath && emptyToRestore.some(empty => empty === basename(usedWindow.backupPath))) // skip over restored empty window + ) { + continue; + } + + usedWindow.focus(); + focusLastWindow = false; + break; + } + } + + // 3.) finally, always ensure to have at least last used window focused + if (focusLastWindow) { usedWindows[usedWindows.length - 1].focus(); } } @@ -451,10 +479,10 @@ export class WindowsManager implements IWindowsMainService { } // If we got started with --wait from the CLI, we need to signal to the outside when the window - // used for the edit operation is closed so that the waiting process can continue. We do this by - // deleting the waitMarkerFilePath. + // used for the edit operation is closed or loaded to a different folder so that the waiting + // process can continue. We do this by deleting the waitMarkerFilePath. if (openConfig.context === OpenContext.CLI && openConfig.cli.wait && openConfig.cli.waitMarkerFilePath && usedWindows.length === 1 && usedWindows[0]) { - this.waitForWindowClose(usedWindows[0].id).done(() => fs.unlink(openConfig.cli.waitMarkerFilePath, error => void 0)); + this.waitForWindowCloseOrLoad(usedWindows[0].id).done(() => fs.unlink(openConfig.cli.waitMarkerFilePath, error => void 0)); } return usedWindows; @@ -481,6 +509,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], + filesToWait: IPathsToWaitFor, foldersToAdd: IPath[] ) { const usedWindows: CodeWindow[] = []; @@ -505,7 +534,7 @@ export class WindowsManager implements IWindowsMainService { // Find suitable window or folder path to open files in const fileToCheck = filesToOpen[0] || filesToCreate[0] || filesToDiff[0]; - const bestWindowOrFolder = findBestWindowOrFolderForFile({ + let bestWindowOrFolder = findBestWindowOrFolderForFile({ windows: WindowsManager.WINDOWS, newWindow: openFilesInNewWindow, reuseWindow: openConfig.forceReuseWindow, @@ -515,6 +544,12 @@ export class WindowsManager implements IWindowsMainService { workspaceResolver: workspace => this.workspacesService.resolveWorkspaceSync(workspace.configPath) }); + // Special case: we started with --wait and we got back a folder to open. In this case + // we actually prefer to not open the folder but operate purely on the file. + if (typeof bestWindowOrFolder === 'string' && filesToWait) { + bestWindowOrFolder = !openFilesInNewWindow ? this.getLastActiveWindow() : null; + } + // We found a window to open the files in if (bestWindowOrFolder instanceof CodeWindow) { @@ -532,12 +567,13 @@ export class WindowsManager implements IWindowsMainService { else { // Do open files - usedWindows.push(this.doOpenFilesInExistingWindow(bestWindowOrFolder, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFilesInExistingWindow(bestWindowOrFolder, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; } } @@ -555,6 +591,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen, filesToCreate, filesToDiff, + filesToWait, forceNewWindow: true })); @@ -562,6 +599,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; } } @@ -575,12 +613,13 @@ export class WindowsManager implements IWindowsMainService { const windowOnWorkspace = windowsOnWorkspace[0]; // Do open files - usedWindows.push(this.doOpenFilesInExistingWindow(windowOnWorkspace, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFilesInExistingWindow(windowOnWorkspace, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then } @@ -592,12 +631,13 @@ export class WindowsManager implements IWindowsMainService { } // Do open folder - usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { workspace: workspaceToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { workspace: workspaceToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then }); @@ -613,12 +653,13 @@ export class WindowsManager implements IWindowsMainService { const windowOnFolderPath = windowsOnFolderPath[0]; // Do open files - usedWindows.push(this.doOpenFilesInExistingWindow(windowOnFolderPath, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFilesInExistingWindow(windowOnFolderPath, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then } @@ -630,12 +671,13 @@ export class WindowsManager implements IWindowsMainService { } // Do open folder - usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { folderPath: folderToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { folderPath: folderToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then }); @@ -651,6 +693,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen, filesToCreate, filesToDiff, + filesToWait, forceNewWindow: true, emptyWindowBackupFolder })); @@ -659,6 +702,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then }); @@ -681,11 +725,11 @@ export class WindowsManager implements IWindowsMainService { return arrays.distinct(usedWindows); } - private doOpenFilesInExistingWindow(window: CodeWindow, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[]): CodeWindow { + private doOpenFilesInExistingWindow(window: CodeWindow, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], filesToWait: IPathsToWaitFor): CodeWindow { window.focus(); // make sure window has focus window.ready().then(readyWindow => { - readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff }); + readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff, filesToWait }); }); return window; @@ -701,7 +745,7 @@ export class WindowsManager implements IWindowsMainService { return window; } - private doOpenFolderOrWorkspace(openConfig: IOpenConfiguration, folderOrWorkspace: IPathToOpen, openInNewWindow: boolean, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], windowToUse?: CodeWindow): CodeWindow { + private doOpenFolderOrWorkspace(openConfig: IOpenConfiguration, folderOrWorkspace: IPathToOpen, openInNewWindow: boolean, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], filesToWait: IPathsToWaitFor, windowToUse?: CodeWindow): CodeWindow { const browserWindow = this.openInBrowserWindow({ userEnv: openConfig.userEnv, cli: openConfig.cli, @@ -711,6 +755,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen, filesToCreate, filesToDiff, + filesToWait, forceNewWindow: openInNewWindow, windowToUse }); @@ -748,10 +793,10 @@ export class WindowsManager implements IWindowsMainService { // This will ensure to open these folders in one window instead of multiple // If we are in addMode, we should not do this because in that case all // folders should be added to the existing window. - if (!openConfig.addMode && isCommandLineOrAPICall && product.quality !== 'stable') { // TODO@Ben multi root + if (!openConfig.addMode && isCommandLineOrAPICall) { const foldersToOpen = windowsToOpen.filter(path => !!path.folderPath); if (foldersToOpen.length > 1) { - const workspace = this.workspacesService.createWorkspaceSync(foldersToOpen.map(folder => folder.folderPath)); + const workspace = this.workspacesService.createWorkspaceSync(foldersToOpen.map(folder => ({ uri: URI.file(folder.folderPath) }))); // Add workspace and remove folders thereby windowsToOpen.push({ workspace }); @@ -768,7 +813,7 @@ export class WindowsManager implements IWindowsMainService { // Warn if the requested path to open does not exist if (!path) { - const options: Electron.ShowMessageBoxOptions = { + const options: Electron.MessageBoxOptions = { title: product.nameLong, type: 'info', buttons: [localize('ok', "OK")], @@ -893,7 +938,7 @@ export class WindowsManager implements IWindowsMainService { restoreWindows = ((windowConfig && windowConfig.restoreWindows) || 'one') as RestoreWindowsSetting; if (restoreWindows === 'one' /* default */ && windowConfig && windowConfig.reopenFolders) { - restoreWindows = windowConfig.reopenFolders; // TODO@Ben migration + restoreWindows = windowConfig.reopenFolders; // TODO@Ben migration from deprecated window.reopenFolders setting } if (['all', 'folders', 'one', 'none'].indexOf(restoreWindows) === -1) { @@ -917,7 +962,7 @@ export class WindowsManager implements IWindowsMainService { anyPath = parsedPath.path; } - const candidate = path.normalize(anyPath); + const candidate = normalize(anyPath); try { const candidateStat = fs.statSync(candidate); if (candidateStat) { @@ -1028,6 +1073,7 @@ export class WindowsManager implements IWindowsMainService { configuration.filesToOpen = options.filesToOpen; configuration.filesToCreate = options.filesToCreate; configuration.filesToDiff = options.filesToDiff; + configuration.filesToWait = options.filesToWait; configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir; // if we know the backup folder upfront (for empty windows to restore), we can set it @@ -1035,7 +1081,7 @@ export class WindowsManager implements IWindowsMainService { // For all other cases we first call into registerEmptyWindowBackupSync() to set it before // loading the window. if (options.emptyWindowBackupFolder) { - configuration.backupPath = path.join(this.environmentService.backupHome, options.emptyWindowBackupFolder); + configuration.backupPath = join(this.environmentService.backupHome, options.emptyWindowBackupFolder); } let window: CodeWindow; @@ -1122,6 +1168,9 @@ export class WindowsManager implements IWindowsMainService { // Load it window.load(configuration); + + // Signal event + this._onWindowLoad.fire(window.id); } }); @@ -1272,97 +1321,32 @@ export class WindowsManager implements IWindowsMainService { }); } - public saveAndOpenWorkspace(window: CodeWindow, path: string): TPromise { - if (!window || !window.win || window.readyState !== ReadyState.READY || !window.openedWorkspace || !path) { - return TPromise.as(null); // return early if the window is not ready or disposed or does not have a workspace - } - - return this.doSaveAndOpenWorkspace(window, window.openedWorkspace, path); + public saveAndEnterWorkspace(win: CodeWindow, path: string): TPromise { + return this.workspacesManager.saveAndEnterWorkspace(win, path).then(result => this.doEnterWorkspace(win, result)); } - public createAndOpenWorkspace(window: CodeWindow, folders?: string[], path?: string): TPromise { - if (!window || !window.win || window.readyState !== ReadyState.READY) { - return TPromise.as(null); // return early if the window is not ready or disposed - } - - return this.workspacesService.createWorkspace(folders).then(workspace => { - return this.doSaveAndOpenWorkspace(window, workspace, path); - }); + public createAndEnterWorkspace(win: CodeWindow, folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { + return this.workspacesManager.createAndEnterWorkspace(win, folders, path).then(result => this.doEnterWorkspace(win, result)); } - private doSaveAndOpenWorkspace(window: CodeWindow, workspace: IWorkspaceIdentifier, path?: string): TPromise { - let savePromise: TPromise; - if (path) { - savePromise = this.workspacesService.saveWorkspace(workspace, path); - } else { - savePromise = TPromise.as(workspace); - } + private doEnterWorkspace(win: CodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult { - return savePromise.then(workspace => { - window.focus(); + // Mark as recently opened + this.historyService.addRecentlyOpened([result.workspace], []); - // Only open workspace when the window has not vetoed this - return this.lifecycleService.unload(window, UnloadReason.RELOAD, workspace).done(veto => { - if (!veto) { + // Trigger Eevent to indicate load of workspace into window + this._onWindowReady.fire(win); - // Register window for backups and migrate current backups over - let backupPath: string; - if (window.config && !window.config.extensionDevelopmentPath) { - backupPath = this.backupService.registerWorkspaceBackupSync(workspace, window.config.backupPath); - } - - // Craft a new window configuration to use for the transition - const configuration: IWindowConfiguration = mixin({}, window.config); - configuration.folderPath = void 0; - configuration.workspace = workspace; - configuration.backupPath = backupPath; - - // Reload - window.reload(configuration); - } - }); - }); + return result; } - public openWorkspace(window: CodeWindow = this.getLastActiveWindow()): void { - let defaultPath: string; - if (window && window.openedWorkspace && !this.workspacesService.isUntitledWorkspace(window.openedWorkspace)) { - defaultPath = path.dirname(window.openedWorkspace.configPath); - } else { - defaultPath = this.getWorkspaceDialogDefaultPath(window ? (window.openedWorkspace || window.openedFolderPath) : void 0); - } - - this.pickFileAndOpen({ - windowId: window ? window.id : void 0, - dialogOptions: { - buttonLabel: mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open")), - title: localize('openWorkspaceTitle', "Open Workspace"), - filters: WORKSPACE_FILTER, - properties: ['openFile'], - defaultPath - } - }); - } - - private getWorkspaceDialogDefaultPath(workspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): string { - let defaultPath: string; - if (workspace) { - if (isSingleFolderWorkspaceIdentifier(workspace)) { - defaultPath = path.dirname(workspace); - } else { - const resolvedWorkspace = this.workspacesService.resolveWorkspaceSync(workspace.configPath); - if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { - defaultPath = path.dirname(resolvedWorkspace.folders[0].path); - } - } - } - - return defaultPath; + public pickWorkspaceAndOpen(options: INativeOpenDialogOptions): void { + this.workspacesManager.pickWorkspaceAndOpen(options); } private onBeforeWindowUnload(e: IWindowUnloadEvent): void { - const windowClosing = e.reason === UnloadReason.CLOSE; - const windowLoading = e.reason === UnloadReason.LOAD; + const windowClosing = (e.reason === UnloadReason.CLOSE); + const windowLoading = (e.reason === UnloadReason.LOAD); if (!windowClosing && !windowLoading) { return; // only interested when window is closing or loading } @@ -1380,74 +1364,8 @@ export class WindowsManager implements IWindowsMainService { return; // Windows/Linux: quits when last window is closed, so do not ask then } - this.promptToSaveUntitledWorkspace(e, workspace); - } - - private promptToSaveUntitledWorkspace(e: IWindowUnloadEvent, workspace: IWorkspaceIdentifier): void { - enum ConfirmResult { - SAVE, - DONT_SAVE, - CANCEL - } - - const save = { label: mnemonicButtonLabel(localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), result: ConfirmResult.SAVE }; - const dontSave = { label: mnemonicButtonLabel(localize({ key: 'doNotSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save")), result: ConfirmResult.DONT_SAVE }; - const cancel = { label: localize('cancel', "Cancel"), result: ConfirmResult.CANCEL }; - - const buttons: { label: string; result: ConfirmResult; }[] = []; - if (isWindows) { - buttons.push(save, dontSave, cancel); - } else if (isLinux) { - buttons.push(dontSave, cancel, save); - } else { - buttons.push(save, cancel, dontSave); - } - - const options: Electron.ShowMessageBoxOptions = { - title: this.environmentService.appNameLong, - message: localize('saveWorkspaceMessage', "Do you want to save your workspace configuration as a file?"), - detail: localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."), - noLink: true, - type: 'warning', - buttons: buttons.map(button => button.label), - cancelId: buttons.indexOf(cancel) - }; - - if (isLinux) { - options.defaultId = 2; - } - - const res = dialog.showMessageBox(e.window.win, options); - - switch (buttons[res].result) { - - // Cancel: veto unload - case ConfirmResult.CANCEL: - e.veto(true); - break; - - // Don't Save: delete workspace - case ConfirmResult.DONT_SAVE: - this.workspacesService.deleteUntitledWorkspaceSync(workspace); - e.veto(false); - break; - - // Save: save workspace, but do not veto unload - case ConfirmResult.SAVE: { - const target = dialog.showSaveDialog(e.window.win, { - buttonLabel: mnemonicButtonLabel(localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), - title: localize('saveWorkspace', "Save Workspace"), - filters: WORKSPACE_FILTER, - defaultPath: this.getWorkspaceDialogDefaultPath(workspace) - }); - - if (target) { - e.veto(this.workspacesService.saveWorkspace(workspace, target).then(() => false, () => false)); - } else { - e.veto(true); // keep veto if no target was provided - } - } - } + // Handle untitled workspaces with prompt as needed + this.workspacesManager.promptToSaveUntitledWorkspace(e, workspace); } public focusLastActive(cli: ParsedArgs, context: OpenContext): CodeWindow { @@ -1470,14 +1388,19 @@ export class WindowsManager implements IWindowsMainService { this.open({ context, cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true }); } - public waitForWindowClose(windowId: number): TPromise { + public waitForWindowCloseOrLoad(windowId: number): TPromise { return new TPromise(c => { - const toDispose = this.onWindowClose(id => { + function handler(id: number) { if (id === windowId) { - toDispose.dispose(); + closeListener.dispose(); + loadListener.dispose(); + c(null); } - }); + } + + const closeListener = this.onWindowClose(id => handler(id)); + const loadListener = this.onWindowLoad(id => handler(id)); }); } @@ -1533,7 +1456,7 @@ export class WindowsManager implements IWindowsMainService { dialog.showMessageBox(window.win, { title: product.nameLong, type: 'warning', - buttons: [localize('reopen', "Reopen"), localize('wait', "Keep Waiting"), localize('close', "Close")], + buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], message: localize('appStalled', "The window is no longer responding"), detail: localize('appStalledDetail', "You can reopen or close the window or keep waiting."), noLink: true @@ -1556,7 +1479,7 @@ export class WindowsManager implements IWindowsMainService { dialog.showMessageBox(window.win, { title: product.nameLong, type: 'warning', - buttons: [localize('reopen', "Reopen"), localize('close', "Close")], + buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], message: localize('appCrashed', "The window has crashed"), detail: localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."), noLink: true @@ -1675,6 +1598,7 @@ class FileDialog { // Telemetry if (options.telemetryEventName) { + // __GDPR__TODO__ Dynamic event names and dynamic properties. Can not be registered statically. this.telemetryService.publicLog(options.telemetryEventName, { ...options.telemetryExtraData, outcome: numberOfPaths ? 'success' : 'canceled', @@ -1695,7 +1619,7 @@ class FileDialog { }); } - public getFileOrFolderPaths(options: IInternalNativeOpenDialogOptions, clb: (paths: string[]) => void): void { + private getFileOrFolderPaths(options: IInternalNativeOpenDialogOptions, clb: (paths: string[]) => void): void { // Ensure dialog options if (!options.dialogOptions) { @@ -1720,13 +1644,20 @@ class FileDialog { options.dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory']; } + if (isMacintosh) { + options.dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files + } + // Show Dialog const focusedWindow = this.windowsMainService.getWindowById(options.windowId) || this.windowsMainService.getFocusedWindow(); dialog.showOpenDialog(focusedWindow && focusedWindow.win, options.dialogOptions, paths => { if (paths && paths.length > 0) { + if (isMacintosh) { + paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS + } // Remember path in storage for next time - this.storageService.setItem(FileDialog.workingDirPickerStorageKey, path.dirname(paths[0])); + this.storageService.setItem(FileDialog.workingDirPickerStorageKey, dirname(paths[0])); // Return return clb(paths); @@ -1735,4 +1666,200 @@ class FileDialog { return clb(void (0)); }); } -} \ No newline at end of file +} + +class WorkspacesManager { + + constructor( + private workspacesService: IWorkspacesMainService, + private backupService: IBackupMainService, + private environmentService: IEnvironmentService, + private windowsMainService: IWindowsMainService + ) { + } + + public saveAndEnterWorkspace(window: CodeWindow, path: string): TPromise { + if (!window || !window.win || window.readyState !== ReadyState.READY || !window.openedWorkspace || !path || !this.isValidTargetWorkspacePath(window, path)) { + return TPromise.as(null); // return early if the window is not ready or disposed or does not have a workspace + } + + return this.doSaveAndOpenWorkspace(window, window.openedWorkspace, path); + } + + public createAndEnterWorkspace(window: CodeWindow, folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { + if (!window || !window.win || window.readyState !== ReadyState.READY || !this.isValidTargetWorkspacePath(window, path)) { + return TPromise.as(null); // return early if the window is not ready or disposed + } + + return this.workspacesService.createWorkspace(folders).then(workspace => { + return this.doSaveAndOpenWorkspace(window, workspace, path); + }); + } + + private isValidTargetWorkspacePath(window: CodeWindow, path?: string): boolean { + if (!path) { + return true; + } + + if (window.openedWorkspace && window.openedWorkspace.configPath === path) { + return false; // window is already opened on a workspace with that path + } + + // Prevent overwriting a workspace that is currently opened in another window + if (findWindowOnWorkspace(this.windowsMainService.getWindows(), { id: this.workspacesService.getWorkspaceId(path), configPath: path })) { + const options: Electron.MessageBoxOptions = { + title: product.nameLong, + type: 'info', + buttons: [localize('ok', "OK")], + message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", basename(path)), + detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."), + noLink: true + }; + + const activeWindow = BrowserWindow.getFocusedWindow(); + if (activeWindow) { + dialog.showMessageBox(activeWindow, options); + } else { + dialog.showMessageBox(options); + } + + return false; + } + + return true; // OK + } + + private doSaveAndOpenWorkspace(window: CodeWindow, workspace: IWorkspaceIdentifier, path?: string): TPromise { + let savePromise: TPromise; + if (path) { + savePromise = this.workspacesService.saveWorkspace(workspace, path); + } else { + savePromise = TPromise.as(workspace); + } + + return savePromise.then(workspace => { + window.focus(); + + // Register window for backups and migrate current backups over + let backupPath: string; + if (!window.config.extensionDevelopmentPath) { + backupPath = this.backupService.registerWorkspaceBackupSync(workspace, window.config.backupPath); + } + + // Update window configuration properly based on transition to workspace + window.config.folderPath = void 0; + window.config.workspace = workspace; + window.config.backupPath = backupPath; + + return { workspace, backupPath }; + }); + } + + public pickWorkspaceAndOpen(options: INativeOpenDialogOptions): void { + const window = this.windowsMainService.getWindowById(options.windowId) || this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); + + this.windowsMainService.pickFileAndOpen({ + windowId: window ? window.id : void 0, + dialogOptions: { + buttonLabel: mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open")), + title: localize('openWorkspaceTitle', "Open Workspace"), + filters: WORKSPACE_FILTER, + properties: ['openFile'], + defaultPath: options.dialogOptions && options.dialogOptions.defaultPath + }, + forceNewWindow: options.forceNewWindow, + telemetryEventName: options.telemetryEventName, + telemetryExtraData: options.telemetryExtraData + }); + } + + public promptToSaveUntitledWorkspace(e: IWindowUnloadEvent, workspace: IWorkspaceIdentifier): void { + enum ConfirmResult { + SAVE, + DONT_SAVE, + CANCEL + } + + const save = { label: mnemonicButtonLabel(localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), result: ConfirmResult.SAVE }; + const dontSave = { label: mnemonicButtonLabel(localize({ key: 'doNotSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save")), result: ConfirmResult.DONT_SAVE }; + const cancel = { label: localize('cancel', "Cancel"), result: ConfirmResult.CANCEL }; + + const buttons: { label: string; result: ConfirmResult; }[] = []; + if (isWindows) { + buttons.push(save, dontSave, cancel); + } else if (isLinux) { + buttons.push(dontSave, cancel, save); + } else { + buttons.push(save, cancel, dontSave); + } + + const options: Electron.MessageBoxOptions = { + title: this.environmentService.appNameLong, + message: localize('saveWorkspaceMessage', "Do you want to save your workspace configuration as a file?"), + detail: localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."), + noLink: true, + type: 'warning', + buttons: buttons.map(button => button.label), + cancelId: buttons.indexOf(cancel) + }; + + if (isLinux) { + options.defaultId = 2; + } + + const res = dialog.showMessageBox(e.window.win, options); + + switch (buttons[res].result) { + + // Cancel: veto unload + case ConfirmResult.CANCEL: + e.veto(true); + break; + + // Don't Save: delete workspace + case ConfirmResult.DONT_SAVE: + this.workspacesService.deleteUntitledWorkspaceSync(workspace); + e.veto(false); + break; + + // Save: save workspace, but do not veto unload + case ConfirmResult.SAVE: { + let target = dialog.showSaveDialog(e.window.win, { + buttonLabel: mnemonicButtonLabel(localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), + title: localize('saveWorkspace', "Save Workspace"), + filters: WORKSPACE_FILTER, + defaultPath: this.getUntitledWorkspaceSaveDialogDefaultPath(workspace) + }); + + if (target) { + if (isMacintosh) { + target = normalizeNFC(target); // normalize paths returned from the OS + } + + e.veto(this.workspacesService.saveWorkspace(workspace, target).then(() => false, () => false)); + } else { + e.veto(true); // keep veto if no target was provided + } + } + } + } + + private getUntitledWorkspaceSaveDialogDefaultPath(workspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): string { + if (workspace) { + if (isSingleFolderWorkspaceIdentifier(workspace)) { + return dirname(workspace); + } + + const resolvedWorkspace = this.workspacesService.resolveWorkspaceSync(workspace.configPath); + if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { + for (const folder of resolvedWorkspace.folders) { + if (folder.uri.scheme === Schemas.file) { + return dirname(folder.uri.fsPath); + } + } + } + } + + return void 0; + } +} diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index d0f0416e6ff..f528cfe4ce4 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -14,9 +14,13 @@ import pkg from 'vs/platform/node/package'; import * as fs from 'fs'; import * as paths from 'path'; import * as os from 'os'; +import { whenDeleted } from 'vs/base/node/pfs'; function shouldSpawnCliProcess(argv: ParsedArgs): boolean { - return argv['list-extensions'] || !!argv['install-extension'] || !!argv['uninstall-extension']; + return !!argv['install-source'] + || !!argv['list-extensions'] + || !!argv['install-extension'] + || !!argv['uninstall-extension']; } interface IMainCli { @@ -105,14 +109,7 @@ export function main(argv: string[]): TPromise { child.once('exit', () => c(null)); // Complete when wait marker file is deleted - const interval = setInterval(() => { - fs.exists(waitMarkerFilePath, exists => { - if (!exists) { - clearInterval(interval); - c(null); - } - }); - }, 1000); + whenDeleted(waitMarkerFilePath).done(c, c); }); } } diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 2aab9956ea2..d3fe06e8082 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -7,6 +7,7 @@ import { localize } from 'vs/nls'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; import * as path from 'path'; +import * as fs from 'fs'; import { TPromise } from 'vs/base/common/winjs.base'; import { sequence } from 'vs/base/common/async'; @@ -16,7 +17,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; -import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; +import { EnvironmentService, getInstallSourcePath } from 'vs/platform/environment/node/environmentService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionManifest, IGalleryExtension, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -50,6 +51,7 @@ type Task = { (): TPromise }; class Main { constructor( + @IEnvironmentService private environmentService: IEnvironmentService, @IExtensionManagementService private extensionManagementService: IExtensionManagementService, @IExtensionGalleryService private extensionGalleryService: IExtensionGalleryService ) { } @@ -57,7 +59,9 @@ class Main { run(argv: ParsedArgs): TPromise { // TODO@joao - make this contributable - if (argv['list-extensions']) { + if (argv['install-source']) { + return this.setInstallSource(argv['install-source']); + } else if (argv['list-extensions']) { return this.listExtensions(argv['show-versions']); } else if (argv['install-extension']) { const arg = argv['install-extension']; @@ -71,6 +75,13 @@ class Main { return undefined; } + private setInstallSource(installSource: string): TPromise { + return new TPromise((c, e) => { + const path = getInstallSourcePath(this.environmentService.userDataPath); + fs.writeFile(path, installSource.slice(0, 30), 'utf8', err => err ? e(err) : c(null)); + }); + } + private listExtensions(showVersions: boolean): TPromise { return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => { extensions.forEach(e => console.log(getId(e.manifest, showVersions))); @@ -99,7 +110,7 @@ class Main { return TPromise.as(null); } - return this.extensionGalleryService.query({ names: [id] }) + return this.extensionGalleryService.query({ names: [id], source: 'cli' }) .then>(null, err => { if (err.responseText) { try { @@ -122,7 +133,7 @@ class Main { console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id)); console.log(localize('installing', "Installing...")); - return this.extensionManagementService.installFromGallery(extension, false) + return this.extensionManagementService.installFromGallery(extension) .then(() => console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.version))); }); }); @@ -161,7 +172,7 @@ export function main(argv: ParsedArgs): TPromise { const envService = accessor.get(IEnvironmentService); return TPromise.join([envService.appSettingsHome, envService.extensionsPath].map(p => mkdirp(p))).then(() => { - const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt } = envService; + const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, installSource } = envService; const services = new ServiceCollection(); services.set(IConfigurationService, new SyncDescriptor(ConfigurationService)); @@ -170,7 +181,7 @@ export function main(argv: ParsedArgs): TPromise { services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); services.set(IChoiceService, new SyncDescriptor(ChoiceCliService)); - if (isBuilt && !extensionDevelopmentPath && product.enableTelemetry) { + if (isBuilt && !extensionDevelopmentPath && !envService.args['disable-telemetry'] && product.enableTelemetry) { const appenders: AppInsightsAppender[] = []; if (product.aiConfig && product.aiConfig.asimovKey) { @@ -183,7 +194,7 @@ export function main(argv: ParsedArgs): TPromise { const config: ITelemetryServiceConfig = { appender: combinedAppender(...appenders), - commonProperties: resolveCommonProperties(product.commit, pkg.version), + commonProperties: resolveCommonProperties(product.commit, pkg.version, installSource), piiPaths: [appRoot, extensionsPath] }; diff --git a/src/vs/code/node/shellEnv.ts b/src/vs/code/node/shellEnv.ts index 92c146fefae..e64c64e6400 100644 --- a/src/vs/code/node/shellEnv.ts +++ b/src/vs/code/node/shellEnv.ts @@ -58,6 +58,9 @@ function getUnixShellEnvironment(): TPromise { delete env['ELECTRON_NO_ATTACH_CONSOLE']; } + // https://github.com/Microsoft/vscode/issues/22593#issuecomment-336050758 + delete env['XDG_RUNTIME_DIR']; + c(env); } catch (err) { e(err); diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index d8b0d1e93d4..f45fa1fcb1c 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -11,6 +11,7 @@ import * as platform from 'vs/base/common/platform'; import * as paths from 'vs/base/common/paths'; import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; +import { Schemas } from 'vs/base/common/network'; export interface ISimpleWindow { openedWorkspace?: IWorkspaceIdentifier; @@ -62,7 +63,7 @@ function findWindowOnFilePath(windows: W[], filePath: s for (let i = 0; i < workspaceWindows.length; i++) { const window = workspaceWindows[i]; const resolvedWorkspace = workspaceResolver(window.openedWorkspace); - if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => paths.isEqualOrParent(filePath, folder.path, !platform.isLinux /* ignorecase */))) { + if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => folder.uri.scheme === Schemas.file && paths.isEqualOrParent(filePath, folder.uri.fsPath, !platform.isLinux /* ignorecase */))) { return window; } } @@ -164,4 +165,4 @@ export function findWindowOnWorkspaceOrFolderPath(windo return false; })[0]; -} \ No newline at end of file +} diff --git a/src/vs/code/test/node/windowsFinder.test.ts b/src/vs/code/test/node/windowsFinder.test.ts index 0651a98d6b2..2c0b84336ff 100644 --- a/src/vs/code/test/node/windowsFinder.test.ts +++ b/src/vs/code/test/node/windowsFinder.test.ts @@ -9,6 +9,7 @@ import path = require('path'); import { findBestWindowOrFolderForFile, ISimpleWindow, IBestWindowOrFolderOptions } from 'vs/code/node/windowsFinder'; import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; const fixturesFolder = require.toUrl('./fixtures'); @@ -24,7 +25,7 @@ function options(custom?: Partial>): I reuseWindow: false, context: OpenContext.CLI, codeSettingsFolder: '_vscode', - workspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: [{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }] } : null; }, + workspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }]) } : null; }, ...custom }; } diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 4290a200487..bc8982232d3 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -25,6 +25,13 @@ export interface IViewZoneData { afterLineNumber: number; } +export interface IMarginData { + isAfterLines: boolean; + glyphMarginWidth: number; + lineNumbersWidth: number; + offsetX: number; +} + interface IETextRange { boundingHeight: number; boundingLeft: number; @@ -565,22 +572,28 @@ export class MouseTargetFactory { if (request.isInMarginArea) { let res = ctx.getFullLineRangeAtCoord(request.mouseVerticalOffset); let pos = res.range.getStartPosition(); - let offset = Math.abs(request.pos.x - request.editorPos.x); + const detail: IMarginData = { + isAfterLines: res.isAfterLines, + glyphMarginWidth: ctx.layoutInfo.glyphMarginWidth, + lineNumbersWidth: ctx.layoutInfo.lineNumbersWidth, + offsetX: offset + }; + if (offset <= ctx.layoutInfo.glyphMarginWidth) { // On the glyph margin - return request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, res.isAfterLines); + return request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, detail); } offset -= ctx.layoutInfo.glyphMarginWidth; if (offset <= ctx.layoutInfo.lineNumbersWidth) { // On the line numbers - return request.fulfill(MouseTargetType.GUTTER_LINE_NUMBERS, pos, res.range, res.isAfterLines); + return request.fulfill(MouseTargetType.GUTTER_LINE_NUMBERS, pos, res.range, detail); } offset -= ctx.layoutInfo.lineNumbersWidth; // On the line decorations - return request.fulfill(MouseTargetType.GUTTER_LINE_DECORATIONS, pos, res.range, res.isAfterLines); + return request.fulfill(MouseTargetType.GUTTER_LINE_DECORATIONS, pos, res.range, detail); } return null; } diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index 35b948c6634..2c7548ff84b 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -28,7 +28,7 @@ function gestureChangeEventMerger(lastEvent: IThrottledGestureEvent, currentEven r.translationX += lastEvent.translationX; } return r; -}; +} /** * Basically IE10 and IE11 diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 4b80421d71f..d4428d9ce78 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -7,6 +7,7 @@ import 'vs/css!./textAreaHandler'; import * as platform from 'vs/base/common/platform'; import * as browser from 'vs/base/browser/browser'; +import * as strings from 'vs/base/common/strings'; import { TextAreaInput, ITextAreaInputHost, IPasteData, ICompositionData } from 'vs/editor/browser/controller/textAreaInput'; import { ISimpleModel, ITypeData, TextAreaState, PagedScreenReaderStrategy } from 'vs/editor/browser/controller/textAreaState'; import { Range } from 'vs/editor/common/core/range'; @@ -53,8 +54,6 @@ export class TextAreaHandler extends ViewPart { private readonly _viewController: ViewController; private readonly _viewHelper: ITextAreaHandlerHelper; - - private _pixelRatio: number; private _accessibilitySupport: platform.AccessibilitySupport; private _contentLeft: number; private _contentWidth: number; @@ -85,7 +84,6 @@ export class TextAreaHandler extends ViewPart { const conf = this._context.configuration.editor; - this._pixelRatio = conf.pixelRatio; this._accessibilitySupport = conf.accessibilitySupport; this._contentLeft = conf.layoutInfo.contentLeft; this._contentWidth = conf.layoutInfo.contentWidth; @@ -164,10 +162,24 @@ export class TextAreaHandler extends ViewPart { if (this._accessibilitySupport === platform.AccessibilitySupport.Disabled) { // We know for a fact that a screen reader is not attached + // On OSX, we write the character before the cursor to allow for "long-press" composition + if (platform.isMacintosh) { + const selection = this._selections[0]; + if (selection.isEmpty()) { + const position = selection.getStartPosition(); + if (position.column > 1) { + const lineContent = this._context.model.getLineContent(position.lineNumber); + const charBefore = lineContent.charAt(position.column - 2); + if (!strings.isHighSurrogate(charBefore.charCodeAt(0))) { + return new TextAreaState(charBefore, 1, 1, position, position); + } + } + } + } return TextAreaState.EMPTY; } - return PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0]); + return PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0], this._accessibilitySupport === platform.AccessibilitySupport.Unknown); }, deduceModelPosition: (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position => { @@ -291,9 +303,6 @@ export class TextAreaHandler extends ViewPart { if (e.lineHeight) { this._lineHeight = conf.lineHeight; } - if (e.pixelRatio) { - this._pixelRatio = conf.pixelRatio; - } if (e.accessibilitySupport) { this._accessibilitySupport = conf.accessibilitySupport; this._textAreaInput.writeScreenReaderContent('strategy changed'); diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 7d6b9c566b6..97926f7e12a 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -111,7 +111,7 @@ export class TextAreaInput extends Disposable { this._nextCommand = ReadFromTextArea.Type; this._register(dom.addStandardDisposableListener(textArea.domNode, 'keydown', (e: IKeyboardEvent) => { - if (this._isDoingComposition && e.equals(KeyCode.KEY_IN_COMPOSITION)) { + if (this._isDoingComposition && e.keyCode === KeyCode.KEY_IN_COMPOSITION) { // Stop propagation for keyDown events if the IME is processing key input e.stopPropagation(); } diff --git a/src/vs/editor/browser/controller/textAreaState.ts b/src/vs/editor/browser/controller/textAreaState.ts index 8131a3d7b60..88389a1c924 100644 --- a/src/vs/editor/browser/controller/textAreaState.ts +++ b/src/vs/editor/browser/controller/textAreaState.ts @@ -241,7 +241,7 @@ export class PagedScreenReaderStrategy { return new Range(startLineNumber, 1, endLineNumber + 1, 1); } - public static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range): TextAreaState { + public static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range, trimLongText: boolean): TextAreaState { let selectionStartPage = PagedScreenReaderStrategy._getPageOfLine(selection.startLineNumber); let selectionStartPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionStartPage); @@ -273,15 +273,17 @@ export class PagedScreenReaderStrategy { // Chromium handles very poorly text even of a few thousand chars // Cut text to avoid stalling the entire UI - const LIMIT_CHARS = 500; - if (pretext.length > LIMIT_CHARS) { - pretext = pretext.substring(pretext.length - LIMIT_CHARS, pretext.length); - } - if (posttext.length > LIMIT_CHARS) { - posttext = posttext.substring(0, LIMIT_CHARS); - } - if (text.length > 2 * LIMIT_CHARS) { - text = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length); + if (trimLongText) { + const LIMIT_CHARS = 500; + if (pretext.length > LIMIT_CHARS) { + pretext = pretext.substring(pretext.length - LIMIT_CHARS, pretext.length); + } + if (posttext.length > LIMIT_CHARS) { + posttext = posttext.substring(0, LIMIT_CHARS); + } + if (text.length > 2 * LIMIT_CHARS) { + text = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length); + } } return new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, new Position(selection.startLineNumber, selection.startColumn), new Position(selection.endLineNumber, selection.endColumn)); diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index 504c830dda1..b483b681901 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -135,10 +135,10 @@ export class EditorMouseEventFactory { } public onMouseMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { - let myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { + let myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, this._create(currentEvent)); }; - return dom.addDisposableThrottledListener(target, 'mousemove', callback, myMerger, minimumTimeMs); + return dom.addDisposableThrottledListener(target, 'mousemove', callback, myMerger, minimumTimeMs); } } @@ -168,7 +168,7 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { this._globalMouseMoveMonitor.stopMonitoring(true); }, true); - let myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { + let myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, new EditorMouseEvent(currentEvent, this._editorViewDomNode)); }; diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index b8c5900a2d2..72997183743 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -90,6 +90,7 @@ export class View extends ViewEventHandler { private overflowGuardContainer: FastDomNode; // Actual mutable state + // @ts-ignore unused property private _isDisposed: boolean; private _renderAnimationFrame: IDisposable; @@ -308,7 +309,8 @@ export class View extends ViewEventHandler { } private getEditorClassName() { - return this._context.configuration.editor.editorClassName + ' ' + getThemeTypeSelector(this._context.theme.type); + let focused = this._textAreaHandler.isFocused() ? ' focused' : ''; + return this._context.configuration.editor.editorClassName + ' ' + getThemeTypeSelector(this._context.theme.type) + focused; } // --- begin event handlers @@ -323,7 +325,7 @@ export class View extends ViewEventHandler { return false; } public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { - this.domNode.toggleClassName('focused', e.isFocused); + this.domNode.setClassName(this.getEditorClassName()); if (e.isFocused) { this.outgoingEvents.emitViewFocusGained(); } else { @@ -419,6 +421,11 @@ export class View extends ViewEventHandler { this._context.model ); + if (this.contentWidgets.shouldRender()) { + // Give the content widgets a chance to set their max width before a possible synchronous layout + this.contentWidgets.onBeforeRender(viewportData); + } + if (this.viewLines.shouldRender()) { this.viewLines.renderText(viewportData); this.viewLines.onDidRender(); diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index 15adceca2e1..93934f1131b 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -13,6 +13,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { Position, IPosition } from 'vs/editor/common/core/position'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; class Coordinate { _coordinateBrand: void; @@ -73,6 +74,14 @@ export class ViewContentWidgets extends ViewPart { public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { return true; } + public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean { + let keys = Object.keys(this._widgets); + for (let i = 0, len = keys.length; i < len; i++) { + const widgetId = keys[i]; + this._widgets[widgetId].onLineMappingChanged(e); + } + return true; + } public onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean { return true; } @@ -132,6 +141,14 @@ export class ViewContentWidgets extends ViewPart { return false; } + public onBeforeRender(viewportData: ViewportData): void { + let keys = Object.keys(this._widgets); + for (let i = 0, len = keys.length; i < len; i++) { + const widgetId = keys[i]; + this._widgets[widgetId].onBeforeRender(viewportData); + } + } + public prepareRender(ctx: RenderingContext): void { let keys = Object.keys(this._widgets); for (let i = 0, len = keys.length; i < len; i++) { @@ -173,8 +190,13 @@ class Widget { private _lineHeight: number; private _position: IPosition; + private _viewPosition: Position; private _preference: ContentWidgetPositionPreference[]; + private _cachedDomNodeClientWidth: number; + private _cachedDomNodeClientHeight: number; + private _maxWidth: number; private _isVisible: boolean; + private _renderData: Coordinate; constructor(context: ViewContext, viewDomNode: FastDomNode, actual: IContentWidget) { @@ -192,15 +214,18 @@ class Widget { this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; this._lineHeight = this._context.configuration.editor.lineHeight; - this._position = null; + this._setPosition(null); this._preference = null; + this._cachedDomNodeClientWidth = -1; + this._cachedDomNodeClientHeight = -1; + this._maxWidth = this._getMaxWidth(); this._isVisible = false; this._renderData = null; this.domNode.setPosition((this._fixedOverflowWidgets && this.allowEditorOverflow) ? 'fixed' : 'absolute'); - this._updateMaxWidth(); this.domNode.setVisibility('hidden'); this.domNode.setAttribute('widgetId', this.id); + this.domNode.setMaxWidth(this._maxWidth); } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void { @@ -210,22 +235,40 @@ class Widget { if (e.layoutInfo) { this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - - this._updateMaxWidth(); + this._maxWidth = this._getMaxWidth(); } } - private _updateMaxWidth(): void { - const maxWidth = this.allowEditorOverflow - ? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth - : this._contentWidth; + public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): void { + this._setPosition(this._position); + } - this.domNode.setMaxWidth(maxWidth); + private _setPosition(position: IPosition): void { + this._position = position; + this._viewPosition = null; + + if (this._position) { + // Do not trust that widgets give a valid position + const validModelPosition = this._context.model.validateModelPosition(this._position); + if (this._context.model.coordinatesConverter.modelPositionIsVisible(validModelPosition)) { + this._viewPosition = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition); + } + } + } + + private _getMaxWidth(): number { + return ( + this.allowEditorOverflow + ? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth + : this._contentWidth + ); } public setPosition(position: IPosition, preference: ContentWidgetPositionPreference[]): void { - this._position = position; + this._setPosition(position); this._preference = preference; + this._cachedDomNodeClientWidth = -1; + this._cachedDomNodeClientHeight = -1; } private _layoutBoxInViewport(topLeft: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult { @@ -312,50 +355,44 @@ class Widget { return new Coordinate(topLeft.top, topLeft.left + this._contentLeft); } - private _getTopLeft(ctx: RenderingContext, position: Position): Coordinate { - const visibleRange = ctx.visibleRangeForPosition(position); + /** + * Compute `this._topLeft` + */ + private _getTopLeft(ctx: RenderingContext): Coordinate { + if (!this._viewPosition) { + return null; + } + + const visibleRange = ctx.visibleRangeForPosition(this._viewPosition); if (!visibleRange) { return null; } - const top = ctx.getVerticalOffsetForLineNumber(position.lineNumber) - ctx.scrollTop; + const top = ctx.getVerticalOffsetForLineNumber(this._viewPosition.lineNumber) - ctx.scrollTop; return new Coordinate(top, visibleRange.left); } - private _prepareRenderWidget(ctx: RenderingContext): Coordinate { - if (!this._position || !this._preference) { + private _prepareRenderWidget(topLeft: Coordinate, ctx: RenderingContext): Coordinate { + if (!topLeft) { return null; } - // Do not trust that widgets have a valid position - let validModelPosition = this._context.model.validateModelPosition(this._position); - - if (!this._context.model.coordinatesConverter.modelPositionIsVisible(validModelPosition)) { - // this position is hidden by the view model - return null; - } - - let position = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition); - let placement: IBoxLayoutResult = null; let fetchPlacement = (): void => { if (placement) { return; } - const topLeft = this._getTopLeft(ctx, position); - if (!topLeft) { - return; + if (this._cachedDomNodeClientWidth === -1 || this._cachedDomNodeClientHeight === -1) { + const domNode = this.domNode.domNode; + this._cachedDomNodeClientWidth = domNode.clientWidth; + this._cachedDomNodeClientHeight = domNode.clientHeight; } - const domNode = this.domNode.domNode; - const width = domNode.clientWidth; - const height = domNode.clientHeight; - if (this.allowEditorOverflow) { - placement = this._layoutBoxInPage(topLeft, width, height, ctx); + placement = this._layoutBoxInPage(topLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx); } else { - placement = this._layoutBoxInViewport(topLeft, width, height, ctx); + placement = this._layoutBoxInViewport(topLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx); } }; @@ -382,11 +419,6 @@ class Widget { return new Coordinate(placement.belowTop, placement.left); } } else { - const topLeft = this._getTopLeft(ctx, position); - if (!topLeft) { - // Widget outside of viewport - return null; - } if (this.allowEditorOverflow) { return this._prepareRenderWidgetAtExactPositionOverflowing(topLeft); } else { @@ -398,8 +430,25 @@ class Widget { return null; } + /** + * On this first pass, we ensure that the content widget (if it is in the viewport) has the max width set correctly. + */ + public onBeforeRender(viewportData: ViewportData): void { + if (!this._viewPosition || !this._preference) { + return; + } + + if (this._viewPosition.lineNumber < viewportData.startLineNumber || this._viewPosition.lineNumber > viewportData.endLineNumber) { + // Outside of viewport + return; + } + + this.domNode.setMaxWidth(this._maxWidth); + } + public prepareRender(ctx: RenderingContext): void { - this._renderData = this._prepareRenderWidget(ctx); + const topLeft = this._getTopLeft(ctx); + this._renderData = this._prepareRenderWidget(topLeft, ctx); } public render(ctx: RestrictedRenderingContext): void { diff --git a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts index 58e4ee7b40c..a07ae843924 100644 --- a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts +++ b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts @@ -16,6 +16,7 @@ import { editorLineHighlight, editorLineHighlightBorder } from 'vs/editor/common export class CurrentLineHighlightOverlay extends DynamicViewOverlay { private _context: ViewContext; private _lineHeight: number; + // @ts-ignore unused property private _readOnly: boolean; private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; private _selectionIsEmpty: boolean; @@ -110,8 +111,12 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay { public render(startLineNumber: number, lineNumber: number): string { if (lineNumber === this._primaryCursorLineNumber) { if (this._shouldShowCurrentLine()) { + const paintedInMargin = this._willRenderMarginCurrentLine(); + const className = 'current-line' + (paintedInMargin ? ' current-line-both' : ''); return ( - '
' @@ -148,12 +148,12 @@ export class DecorationsOverlay extends DynamicViewOverlay { for (let i = 0, lenI = decorations.length; i < lenI; i++) { const d = decorations[i]; - if (d.source.options.isWholeLine) { + if (d.options.isWholeLine) { continue; } - const className = d.source.options.className; - const showIfCollapsed = d.source.options.showIfCollapsed; + const className = d.options.className; + const showIfCollapsed = d.options.showIfCollapsed; let range = d.range; if (showIfCollapsed && range.endColumn === 1 && range.endLineNumber !== range.startLineNumber) { diff --git a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts index 33874c27b51..757305ebc08 100644 --- a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts +++ b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts @@ -145,7 +145,7 @@ export class GlyphMarginOverlay extends DedupOverlay { let r: DecorationToRender[] = [], rLen = 0; for (let i = 0, len = decorations.length; i < len; i++) { let d = decorations[i]; - let glyphMarginClassName = d.source.options.glyphMarginClassName; + let glyphMarginClassName = d.options.glyphMarginClassName; if (glyphMarginClassName) { r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName); } diff --git a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts index dfd4f11d014..43fe27b0d1c 100644 --- a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts +++ b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts @@ -77,6 +77,9 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean { return true; } + public onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean { + return true; + } // --- end event handlers @@ -93,10 +96,12 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { const lineHeight = this._lineHeight; const indentGuideWidth = dom.computeScreenAwareSize(1); + const indents = this._context.model.getLinesIndentGuides(visibleStartLineNumber, visibleEndLineNumber); + let output: string[] = []; for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) { - let lineIndex = lineNumber - visibleStartLineNumber; - let indent = this._context.model.getLineIndentGuide(lineNumber); + const lineIndex = lineNumber - visibleStartLineNumber; + const indent = indents[lineIndex]; let result = ''; let leftMostVisiblePosition = ctx.visibleRangeForPosition(new Position(lineNumber, 1)); diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 8c5c4ff20e3..a188e564ffa 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -397,7 +397,7 @@ class RenderedViewLine implements IRenderedViewLine { this._pixelOffsetCache = null; if (!containsRTL || this._characterMapping.length === 0 /* the line is empty */) { - this._pixelOffsetCache = new Int32Array(this._characterMapping.length + 1); + this._pixelOffsetCache = new Int32Array(Math.max(2, this._characterMapping.length + 1)); for (let column = 0, len = this._characterMapping.length; column <= len; column++) { this._pixelOffsetCache[column] = -1; } diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index 14341b3c952..1979f4da935 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -551,17 +551,17 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, } } - // (3) handle scrolling - this._linesContent.setLayerHinting(this._canUseLayerHinting); - const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta; - this._linesContent.setTop(-adjustedScrollTop); - this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft()); - // Update max line width (not so important, it is just so the horizontal scrollbar doesn't get too small) if (!this._updateLineWidthsFast()) { // Computing the width of some lines would be slow => delay it this._asyncUpdateLineWidths.schedule(); } + + // (3) handle scrolling + this._linesContent.setLayerHinting(this._canUseLayerHinting); + const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta; + this._linesContent.setTop(-adjustedScrollTop); + this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft()); } // --- width diff --git a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts index 3a143124040..43767788096 100644 --- a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts +++ b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts @@ -73,7 +73,7 @@ export class LinesDecorationsOverlay extends DedupOverlay { let r: DecorationToRender[] = [], rLen = 0; for (let i = 0, len = decorations.length; i < len; i++) { let d = decorations[i]; - let linesDecorationsClassName = d.source.options.linesDecorationsClassName; + let linesDecorationsClassName = d.options.linesDecorationsClassName; if (linesDecorationsClassName) { r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, linesDecorationsClassName); } diff --git a/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts index b83c9faa123..75ff0a0e3ed 100644 --- a/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts +++ b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts @@ -63,7 +63,7 @@ export class MarginViewLineDecorationsOverlay extends DedupOverlay { let r: DecorationToRender[] = [], rLen = 0; for (let i = 0, len = decorations.length; i < len; i++) { let d = decorations[i]; - let marginClassName = d.source.options.marginClassName; + let marginClassName = d.options.marginClassName; if (marginClassName) { r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, marginClassName); } diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 71c534741ef..ab984ed37ec 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -709,7 +709,7 @@ export class Minimap extends ViewPart { const imageData = this._getBuffer(); // Render untouched lines by using last rendered data. - let needed = Minimap._renderUntouchedLines( + let [_dirtyY1, _dirtyY2, needed] = Minimap._renderUntouchedLines( imageData, startLineNumber, endLineNumber, @@ -744,9 +744,13 @@ export class Minimap extends ViewPart { dy += minimapLineHeight; } + const dirtyY1 = (_dirtyY1 === -1 ? 0 : _dirtyY1); + const dirtyY2 = (_dirtyY2 === -1 ? imageData.height : _dirtyY2); + const dirtyHeight = dirtyY2 - dirtyY1; + // Finally, paint to the canvas const ctx = this._canvas.domNode.getContext('2d'); - ctx.putImageData(imageData, 0, 0); + ctx.putImageData(imageData, 0, 0, 0, dirtyY1, imageData.width, dirtyHeight); // Save rendered data for reuse on next frame if possible return new RenderData( @@ -762,14 +766,14 @@ export class Minimap extends ViewPart { endLineNumber: number, minimapLineHeight: number, lastRenderData: RenderData, - ): boolean[] { + ): [number, number, boolean[]] { let needed: boolean[] = []; if (!lastRenderData) { for (let i = 0, len = endLineNumber - startLineNumber + 1; i < len; i++) { needed[i] = true; } - return needed; + return [-1, -1, needed]; } const _lastData = lastRenderData._get(); @@ -780,6 +784,10 @@ export class Minimap extends ViewPart { const WIDTH = target.width; const targetData = target.data; + const maxDestPixel = (endLineNumber - startLineNumber + 1) * minimapLineHeight * WIDTH * 4; + let dirtyPixel1 = -1; // the pixel offset up to which all the data is equal to the prev frame + let dirtyPixel2 = -1; // the pixel offset after which all the data is equal to the prev frame + let copySourceStart = -1; let copySourceEnd = -1; let copyDestStart = -1; @@ -810,6 +818,12 @@ export class Minimap extends ViewPart { if (copySourceStart !== -1) { // flush existing copy request targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart); + if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) { + dirtyPixel1 = copySourceEnd; + } + if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) { + dirtyPixel2 = copySourceStart; + } } copySourceStart = sourceStart; copySourceEnd = sourceEnd; @@ -824,9 +838,18 @@ export class Minimap extends ViewPart { if (copySourceStart !== -1) { // flush existing copy request targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart); + if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) { + dirtyPixel1 = copySourceEnd; + } + if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) { + dirtyPixel2 = copySourceStart; + } } - return needed; + const dirtyY1 = (dirtyPixel1 === -1 ? -1 : dirtyPixel1 / (WIDTH * 4)); + const dirtyY2 = (dirtyPixel2 === -1 ? -1 : dirtyPixel2 / (WIDTH * 4)); + + return [dirtyY1, dirtyY2, needed]; } private static _renderLine( diff --git a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts index 91ebeaf3945..79e46980347 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts @@ -6,262 +6,416 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ViewPart } from 'vs/editor/browser/view/viewPart'; -import { OverviewRulerImpl } from 'vs/editor/browser/viewParts/overviewRuler/overviewRulerImpl'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { Position } from 'vs/editor/common/core/position'; import { TokenizationRegistry } from 'vs/editor/common/modes'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; -import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; import { editorOverviewRulerBorder, editorCursorForeground } from 'vs/editor/common/view/editorColorRegistry'; import { Color } from 'vs/base/common/color'; -import { ThemeColor } from 'vs/platform/theme/common/themeService'; +import { ITheme } from 'vs/platform/theme/common/themeService'; +import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; + +class Settings { + + public readonly lineHeight: number; + public readonly pixelRatio: number; + public readonly overviewRulerLanes: number; + + public readonly renderBorder: boolean; + public readonly borderColor: string; + + public readonly hideCursor: boolean; + public readonly cursorColor: string; + + public readonly themeType: 'light' | 'dark' | 'hc'; + public readonly backgroundColor: string; + + public readonly top: number; + public readonly right: number; + public readonly domWidth: number; + public readonly domHeight: number; + public readonly canvasWidth: number; + public readonly canvasHeight: number; + + public readonly x: number[]; + public readonly w: number[]; + + constructor(config: editorCommon.IConfiguration, theme: ITheme) { + this.lineHeight = config.editor.lineHeight; + this.pixelRatio = config.editor.pixelRatio; + this.overviewRulerLanes = config.editor.viewInfo.overviewRulerLanes; + + this.renderBorder = config.editor.viewInfo.overviewRulerBorder; + const borderColor = theme.getColor(editorOverviewRulerBorder); + this.borderColor = borderColor ? borderColor.toString() : null; + + this.hideCursor = config.editor.viewInfo.hideCursorInOverviewRuler; + const cursorColor = theme.getColor(editorCursorForeground); + this.cursorColor = cursorColor ? cursorColor.transparent(0.7).toString() : null; + + this.themeType = theme.type; + + const minimapEnabled = config.editor.viewInfo.minimap.enabled; + const backgroundColor = (minimapEnabled ? TokenizationRegistry.getDefaultBackground() : null); + this.backgroundColor = (backgroundColor ? Color.Format.CSS.formatHex(backgroundColor) : null); + + const position = config.editor.layoutInfo.overviewRuler; + this.top = position.top; + this.right = position.right; + this.domWidth = position.width; + this.domHeight = position.height; + this.canvasWidth = (this.domWidth * this.pixelRatio) | 0; + this.canvasHeight = (this.domHeight * this.pixelRatio) | 0; + + const [x, w] = this._initLanes(1, this.canvasWidth, this.overviewRulerLanes); + this.x = x; + this.w = w; + } + + private _initLanes(canvasLeftOffset: number, canvasWidth: number, laneCount: number): [number[], number[]] { + const remainingWidth = canvasWidth - canvasLeftOffset; + + if (laneCount >= 3) { + const leftWidth = Math.floor(remainingWidth / 3); + const rightWidth = Math.floor(remainingWidth / 3); + const centerWidth = remainingWidth - leftWidth - rightWidth; + const leftOffset = canvasLeftOffset; + const centerOffset = leftOffset + leftWidth; + const rightOffset = leftOffset + leftWidth + centerWidth; + + return [ + [ + 0, + leftOffset, // Left + centerOffset, // Center + leftOffset, // Left | Center + rightOffset, // Right + leftOffset, // Left | Right + centerOffset, // Center | Right + leftOffset, // Left | Center | Right + ], [ + 0, + leftWidth, // Left + centerWidth, // Center + leftWidth + centerWidth, // Left | Center + rightWidth, // Right + leftWidth + centerWidth + rightWidth, // Left | Right + centerWidth + rightWidth, // Center | Right + leftWidth + centerWidth + rightWidth, // Left | Center | Right + ] + ]; + } else if (laneCount === 2) { + const leftWidth = Math.floor(remainingWidth / 2); + const rightWidth = remainingWidth - leftWidth; + const leftOffset = canvasLeftOffset; + const rightOffset = leftOffset + leftWidth; + + return [ + [ + 0, + leftOffset, // Left + leftOffset, // Center + leftOffset, // Left | Center + rightOffset, // Right + leftOffset, // Left | Right + leftOffset, // Center | Right + leftOffset, // Left | Center | Right + ], [ + 0, + leftWidth, // Left + leftWidth, // Center + leftWidth, // Left | Center + rightWidth, // Right + leftWidth + rightWidth, // Left | Right + leftWidth + rightWidth, // Center | Right + leftWidth + rightWidth, // Left | Center | Right + ] + ]; + } else { + const offset = canvasLeftOffset; + const width = remainingWidth; + + return [ + [ + 0, + offset, // Left + offset, // Center + offset, // Left | Center + offset, // Right + offset, // Left | Right + offset, // Center | Right + offset, // Left | Center | Right + ], [ + 0, + width, // Left + width, // Center + width, // Left | Center + width, // Right + width, // Left | Right + width, // Center | Right + width, // Left | Center | Right + ] + ]; + } + } + + public equals(other: Settings): boolean { + return ( + this.lineHeight === other.lineHeight + && this.pixelRatio === other.pixelRatio + && this.overviewRulerLanes === other.overviewRulerLanes + && this.renderBorder === other.renderBorder + && this.borderColor === other.borderColor + && this.hideCursor === other.hideCursor + && this.cursorColor === other.cursorColor + && this.themeType === other.themeType + && this.backgroundColor === other.backgroundColor + && this.top === other.top + && this.right === other.right + && this.domWidth === other.domWidth + && this.domHeight === other.domHeight + && this.canvasWidth === other.canvasWidth + && this.canvasHeight === other.canvasHeight + ); + } +} + +const enum Constants { + MIN_DECORATION_HEIGHT = 6 +} + +const enum OverviewRulerLane { + Left = 1, + Center = 2, + Right = 4, + Full = 7 +} export class DecorationsOverviewRuler extends ViewPart { - static MIN_DECORATION_HEIGHT = 6; - static MAX_DECORATION_HEIGHT = 60; - private readonly _tokensColorTrackerListener: IDisposable; - - private _overviewRuler: OverviewRulerImpl; - - private _renderBorder: boolean; - private _borderColor: string; - private _cursorColor: string; - - private _shouldUpdateDecorations: boolean; - private _shouldUpdateCursorPosition: boolean; - - private _hideCursor: boolean; + private readonly _domNode: FastDomNode; + private _settings: Settings; private _cursorPositions: Position[]; - private _zonesFromDecorations: OverviewRulerZone[]; - private _zonesFromCursors: OverviewRulerZone[]; - constructor(context: ViewContext) { super(context); - this._overviewRuler = new OverviewRulerImpl( - 1, - 'decorationsOverviewRuler', - this._context.viewLayout.getScrollHeight(), - this._context.configuration.editor.lineHeight, - this._context.configuration.editor.pixelRatio, - DecorationsOverviewRuler.MIN_DECORATION_HEIGHT, - DecorationsOverviewRuler.MAX_DECORATION_HEIGHT, - (lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber) - ); - this._overviewRuler.setLanesCount(this._context.configuration.editor.viewInfo.overviewRulerLanes, false); - this._overviewRuler.setLayout(this._context.configuration.editor.layoutInfo.overviewRuler, false); - this._renderBorder = this._context.configuration.editor.viewInfo.overviewRulerBorder; + this._domNode = createFastDomNode(document.createElement('canvas')); + this._domNode.setClassName('decorationsOverviewRuler'); + this._domNode.setPosition('absolute'); + this._domNode.setLayerHinting(true); - this._updateColors(); + this._settings = null; + this._updateSettings(false); - this._updateBackground(false); this._tokensColorTrackerListener = TokenizationRegistry.onDidChange((e) => { if (e.changedColorMap) { - this._updateBackground(true); + this._updateSettings(true); } }); - this._shouldUpdateDecorations = true; - this._zonesFromDecorations = []; - - this._shouldUpdateCursorPosition = true; - this._hideCursor = this._context.configuration.editor.viewInfo.hideCursorInOverviewRuler; - - this._zonesFromCursors = []; this._cursorPositions = []; } public dispose(): void { super.dispose(); - this._overviewRuler.dispose(); this._tokensColorTrackerListener.dispose(); } - private _updateBackground(render: boolean): void { - const minimapEnabled = this._context.configuration.editor.viewInfo.minimap.enabled; - this._overviewRuler.setUseBackground((minimapEnabled ? TokenizationRegistry.getDefaultBackground() : null), render); - } - - // ---- begin view event handlers - - public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - let prevLanesCount = this._overviewRuler.getLanesCount(); - let newLanesCount = this._context.configuration.editor.viewInfo.overviewRulerLanes; - - if (prevLanesCount !== newLanesCount) { - this._overviewRuler.setLanesCount(newLanesCount, false); + private _updateSettings(renderNow: boolean): boolean { + const newSettings = new Settings(this._context.configuration, this._context.theme); + if (this._settings !== null && this._settings.equals(newSettings)) { + // nothing to do + return false; } - if (e.lineHeight) { - this._overviewRuler.setLineHeight(this._context.configuration.editor.lineHeight, false); - } + this._settings = newSettings; - if (e.pixelRatio) { - this._overviewRuler.setPixelRatio(this._context.configuration.editor.pixelRatio, false); - } + this._domNode.setTop(this._settings.top); + this._domNode.setRight(this._settings.right); + this._domNode.setWidth(this._settings.domWidth); + this._domNode.setHeight(this._settings.domHeight); + this._domNode.domNode.width = this._settings.canvasWidth; + this._domNode.domNode.height = this._settings.canvasHeight; - if (e.viewInfo) { - this._renderBorder = this._context.configuration.editor.viewInfo.overviewRulerBorder; - this._hideCursor = this._context.configuration.editor.viewInfo.hideCursorInOverviewRuler; - this._shouldUpdateCursorPosition = true; - this._updateBackground(false); - } - - if (e.layoutInfo) { - this._overviewRuler.setLayout(this._context.configuration.editor.layoutInfo.overviewRuler, false); + if (renderNow) { + this._render(); } return true; } + // ---- begin view event handlers + + public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { + return this._updateSettings(false); + } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { - this._shouldUpdateCursorPosition = true; this._cursorPositions = []; for (let i = 0, len = e.selections.length; i < len; i++) { this._cursorPositions[i] = e.selections[i].getPosition(); } return true; } - public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { - this._shouldUpdateDecorations = true; return true; } - public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { - this._shouldUpdateCursorPosition = true; - this._shouldUpdateDecorations = true; return true; } - public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { - this._overviewRuler.setScrollHeight(e.scrollHeight, false); - return super.onScrollChanged(e) || e.scrollHeightChanged; + return e.scrollHeightChanged; } - public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean { return true; } - public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean { - this._updateColors(); - this._shouldUpdateDecorations = true; - this._shouldUpdateCursorPosition = true; - return true; + // invalidate color cache + this._context.model.invalidateOverviewRulerColorCache(); + return this._updateSettings(false); } // ---- end view event handlers public getDomNode(): HTMLElement { - return this._overviewRuler.getDomNode(); - } - - private _updateColors() { - let borderColor = this._context.theme.getColor(editorOverviewRulerBorder); - this._borderColor = borderColor ? borderColor.toString() : null; - - let cursorColor = this._context.theme.getColor(editorCursorForeground); - this._cursorColor = cursorColor ? cursorColor.transparent(0.7).toString() : null; - - this._overviewRuler.setThemeType(this._context.theme.type, false); - } - - private _createZonesFromDecorations(): OverviewRulerZone[] { - let decorations = this._context.model.getAllOverviewRulerDecorations(); - let zones: OverviewRulerZone[] = []; - - for (let i = 0, len = decorations.length; i < len; i++) { - let dec = decorations[i]; - let overviewRuler = dec.source.options.overviewRuler; - zones[i] = new OverviewRulerZone( - dec.range.startLineNumber, - dec.range.endLineNumber, - overviewRuler.position, - 0, - this.resolveRulerColor(overviewRuler.color), - this.resolveRulerColor(overviewRuler.darkColor), - this.resolveRulerColor(overviewRuler.hcColor) - ); - } - - return zones; - } - - private resolveRulerColor(color: string | ThemeColor): string { - if (editorCommon.isThemeColor(color)) { - let c = this._context.theme.getColor(color.id) || Color.transparent; - return c.toString(); - } - return color; - } - - private _createZonesFromCursors(): OverviewRulerZone[] { - let zones: OverviewRulerZone[] = []; - - for (let i = 0, len = this._cursorPositions.length; i < len; i++) { - let cursor = this._cursorPositions[i]; - - zones[i] = new OverviewRulerZone( - cursor.lineNumber, - cursor.lineNumber, - editorCommon.OverviewRulerLane.Full, - 2, - this._cursorColor, - this._cursorColor, - this._cursorColor - ); - } - - return zones; + return this._domNode.domNode; } public prepareRender(ctx: RenderingContext): void { // Nothing to read } - public render(ctx: RestrictedRenderingContext): void { - if (this._shouldUpdateDecorations || this._shouldUpdateCursorPosition) { + public render(editorCtx: RestrictedRenderingContext): void { + this._render(); + } - if (this._shouldUpdateDecorations) { - this._shouldUpdateDecorations = false; - this._zonesFromDecorations = this._createZonesFromDecorations(); - } + private _render(): void { + const canvasWidth = this._settings.canvasWidth; + const canvasHeight = this._settings.canvasHeight; + const lineHeight = this._settings.lineHeight; + const viewLayout = this._context.viewLayout; + const outerHeight = this._context.viewLayout.getScrollHeight(); + const heightRatio = canvasHeight / outerHeight; + const decorations = this._context.model.getAllOverviewRulerDecorations(this._context.theme); - if (this._shouldUpdateCursorPosition) { - this._shouldUpdateCursorPosition = false; - if (this._hideCursor) { - this._zonesFromCursors = []; - } else { - this._zonesFromCursors = this._createZonesFromCursors(); - } - } + const minDecorationHeight = (Constants.MIN_DECORATION_HEIGHT * this._settings.pixelRatio) | 0; + const halfMinDecorationHeight = (minDecorationHeight / 2) | 0; - let allZones: OverviewRulerZone[] = []; - allZones = allZones.concat(this._zonesFromCursors); - allZones = allZones.concat(this._zonesFromDecorations); - - this._overviewRuler.setZones(allZones, false); + const canvasCtx = this._domNode.domNode.getContext('2d'); + if (this._settings.backgroundColor === null) { + canvasCtx.clearRect(0, 0, canvasWidth, canvasHeight); + } else { + canvasCtx.fillStyle = this._settings.backgroundColor; + canvasCtx.fillRect(0, 0, canvasWidth, canvasHeight); } - let hasRendered = this._overviewRuler.render(false); + const x = this._settings.x; + const w = this._settings.w; + // Avoid flickering by always rendering the colors in the same order + // colors that don't use transparency will be sorted last (they start with #) + const colors = Object.keys(decorations); + colors.sort(); + for (let cIndex = 0, cLen = colors.length; cIndex < cLen; cIndex++) { + const color = colors[cIndex]; - if (hasRendered && this._renderBorder && this._borderColor && this._overviewRuler.getLanesCount() > 0 && (this._zonesFromDecorations.length > 0 || this._zonesFromCursors.length > 0)) { - let ctx2 = this._overviewRuler.getDomNode().getContext('2d'); - ctx2.beginPath(); - ctx2.lineWidth = 1; - ctx2.strokeStyle = this._borderColor; - ctx2.moveTo(0, 0); - ctx2.lineTo(0, this._overviewRuler.getPixelHeight()); - ctx2.stroke(); + const colorDecorations = decorations[color]; - ctx2.moveTo(0, 0); - ctx2.lineTo(this._overviewRuler.getPixelWidth(), 0); - ctx2.stroke(); + canvasCtx.fillStyle = color; + + let prevLane = 0; + let prevY1 = 0; + let prevY2 = 0; + for (let i = 0, len = colorDecorations.length; i < len; i++) { + const lane = colorDecorations[3 * i]; + const startLineNumber = colorDecorations[3 * i + 1]; + const endLineNumber = colorDecorations[3 * i + 2]; + + let y1 = (viewLayout.getVerticalOffsetForLineNumber(startLineNumber) * heightRatio) | 0; + let y2 = ((viewLayout.getVerticalOffsetForLineNumber(endLineNumber) + lineHeight) * heightRatio) | 0; + let height = y2 - y1; + if (height < minDecorationHeight) { + let yCenter = ((y1 + y2) / 2) | 0; + if (yCenter < halfMinDecorationHeight) { + yCenter = halfMinDecorationHeight; + } else if (yCenter + halfMinDecorationHeight > canvasHeight) { + yCenter = canvasHeight - halfMinDecorationHeight; + } + y1 = yCenter - halfMinDecorationHeight; + y2 = yCenter + halfMinDecorationHeight; + } + + if (y1 > prevY2 + 1 || lane !== prevLane) { + // flush prev + if (i !== 0) { + canvasCtx.fillRect(x[prevLane], prevY1, w[prevLane], prevY2 - prevY1); + } + prevLane = lane; + prevY1 = y1; + prevY2 = y2; + } else { + // merge into prev + if (y2 > prevY2) { + prevY2 = y2; + } + } + } + canvasCtx.fillRect(x[prevLane], prevY1, w[prevLane], prevY2 - prevY1); + } + + // Draw cursors + if (!this._settings.hideCursor) { + const cursorHeight = (2 * this._settings.pixelRatio) | 0; + const halfCursorHeight = (cursorHeight / 2) | 0; + const cursorX = this._settings.x[OverviewRulerLane.Full]; + const cursorW = this._settings.w[OverviewRulerLane.Full]; + canvasCtx.fillStyle = this._settings.cursorColor; + + let prevY1 = -100; + let prevY2 = -100; + for (let i = 0, len = this._cursorPositions.length; i < len; i++) { + const cursor = this._cursorPositions[i]; + + let yCenter = (viewLayout.getVerticalOffsetForLineNumber(cursor.lineNumber) * heightRatio) | 0; + if (yCenter < halfCursorHeight) { + yCenter = halfCursorHeight; + } else if (yCenter + halfCursorHeight > canvasHeight) { + yCenter = canvasHeight - halfCursorHeight; + } + const y1 = yCenter - halfCursorHeight; + const y2 = y1 + cursorHeight; + + if (y1 > prevY2 + 1) { + // flush prev + if (i !== 0) { + canvasCtx.fillRect(cursorX, prevY1, cursorW, prevY2 - prevY1); + } + prevY1 = y1; + prevY2 = y2; + } else { + // merge into prev + if (y2 > prevY2) { + prevY2 = y2; + } + } + } + canvasCtx.fillRect(cursorX, prevY1, cursorW, prevY2 - prevY1); + } + + if (this._settings.renderBorder && this._settings.borderColor && this._settings.overviewRulerLanes > 0) { + canvasCtx.beginPath(); + canvasCtx.lineWidth = 1; + canvasCtx.strokeStyle = this._settings.borderColor; + canvasCtx.moveTo(0, 0); + canvasCtx.lineTo(0, canvasHeight); + canvasCtx.stroke(); + + canvasCtx.moveTo(0, 0); + canvasCtx.lineTo(canvasWidth, 0); + canvasCtx.stroke(); } } } + diff --git a/src/vs/editor/browser/viewParts/rulers/rulers.ts b/src/vs/editor/browser/viewParts/rulers/rulers.ts index 6a5e95b0b8c..036ff988cb7 100644 --- a/src/vs/editor/browser/viewParts/rulers/rulers.ts +++ b/src/vs/editor/browser/viewParts/rulers/rulers.ts @@ -20,7 +20,6 @@ export class Rulers extends ViewPart { public domNode: FastDomNode; private _renderedRulers: FastDomNode[]; private _rulers: number[]; - private _height: number; private _typicalHalfwidthCharacterWidth: number; constructor(context: ViewContext) { @@ -31,7 +30,6 @@ export class Rulers extends ViewPart { this.domNode.setClassName('view-rulers'); this._renderedRulers = []; this._rulers = this._context.configuration.editor.viewInfo.rulers; - this._height = this._context.configuration.editor.layoutInfo.contentHeight; this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; } @@ -44,7 +42,6 @@ export class Rulers extends ViewPart { public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { if (e.viewInfo || e.layoutInfo || e.fontInfo) { this._rulers = this._context.configuration.editor.viewInfo.rulers; - this._height = this._context.configuration.editor.layoutInfo.contentHeight; this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth; return true; } diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index fe646ba39e4..58c1ca9269a 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -30,7 +30,7 @@ import { IPosition } from 'vs/editor/common/core/position'; import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; import { CoreEditorCommand } from 'vs/editor/common/controller/coreCommands'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder } from 'vs/editor/common/view/editorColorRegistry'; +import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoBorder, editorInfoForeground } from 'vs/editor/common/view/editorColorRegistry'; import { Color } from 'vs/base/common/color'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; @@ -400,6 +400,7 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito this._view.render(false, true); this.hasView = true; + this._view.domNode.domNode.setAttribute('data-uri', model.uri.toString()); } } @@ -517,19 +518,28 @@ function getSquigglySVGData(color: Color) { registerThemingParticipant((theme, collector) => { let errorBorderColor = theme.getColor(editorErrorBorder); if (errorBorderColor) { - collector.addRule(`.monaco-editor .redsquiggly { border-bottom: 4px double ${errorBorderColor}; }`); + collector.addRule(`.monaco-editor .errorsquiggly { border-bottom: 4px double ${errorBorderColor}; }`); } let errorForeground = theme.getColor(editorErrorForeground); if (errorForeground) { - collector.addRule(`.monaco-editor .redsquiggly { background: url("data:image/svg+xml,${getSquigglySVGData(errorForeground)}") repeat-x bottom left; }`); + collector.addRule(`.monaco-editor .errorsquiggly { background: url("data:image/svg+xml,${getSquigglySVGData(errorForeground)}") repeat-x bottom left; }`); } let warningBorderColor = theme.getColor(editorWarningBorder); if (warningBorderColor) { - collector.addRule(`.monaco-editor .greensquiggly { border-bottom: 4px double ${warningBorderColor}; }`); + collector.addRule(`.monaco-editor .warningsquiggly { border-bottom: 4px double ${warningBorderColor}; }`); } let warningForeground = theme.getColor(editorWarningForeground); if (warningForeground) { - collector.addRule(`.monaco-editor .greensquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`); + collector.addRule(`.monaco-editor .warningsquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`); + } + + let infoBorderColor = theme.getColor(editorInfoBorder); + if (warningBorderColor) { + collector.addRule(`.monaco-editor .infosquiggly { border-bottom: 4px double ${infoBorderColor}; }`); + } + let infoForeground = theme.getColor(editorInfoForeground); + if (warningForeground) { + collector.addRule(`.monaco-editor .infosquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(infoForeground)}") repeat-x bottom left; }`); } }); \ No newline at end of file diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index 22b17b5f9fb..7764188fe0b 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -764,6 +764,7 @@ registerThemingParticipant((theme, collector) => { }); @editorAction +// @ts-ignore @editorAction uses the class class DiffReviewNext extends EditorAction { constructor() { super({ @@ -787,6 +788,7 @@ class DiffReviewNext extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class DiffReviewPrev extends EditorAction { constructor() { super({ diff --git a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts index 185f3537c51..050937ddb51 100644 --- a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts +++ b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts @@ -11,8 +11,11 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CodeEditor } from 'vs/editor/browser/codeEditor'; -import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IConfigurationChangedEvent, IEditorOptions, IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; +import { IMessageService } from 'vs/platform/message/common/message'; export class EmbeddedCodeEditorWidget extends CodeEditor { @@ -40,7 +43,7 @@ export class EmbeddedCodeEditorWidget extends CodeEditor { this._register(parentEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => this._onParentConfigurationChanged(e))); } - public getParentEditor(): ICodeEditor { + getParentEditor(): ICodeEditor { return this._parentEditor; } @@ -49,7 +52,49 @@ export class EmbeddedCodeEditorWidget extends CodeEditor { super.updateOptions(this._overwriteOptions); } - public updateOptions(newOptions: IEditorOptions): void { + updateOptions(newOptions: IEditorOptions): void { + objects.mixin(this._overwriteOptions, newOptions, true); + super.updateOptions(this._overwriteOptions); + } +} + +export class EmbeddedDiffEditorWidget extends DiffEditorWidget { + + private _parentEditor: ICodeEditor; + private _overwriteOptions: IDiffEditorOptions; + + constructor( + domElement: HTMLElement, + options: IDiffEditorOptions, + parentEditor: ICodeEditor, + @IEditorWorkerService editorWorkerService: IEditorWorkerService, + @IContextKeyService contextKeyService: IContextKeyService, + @IInstantiationService instantiationService: IInstantiationService, + @ICodeEditorService codeEditorService: ICodeEditorService, + @IThemeService themeService: IThemeService, + @IMessageService messageService: IMessageService + ) { + super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, messageService); + + this._parentEditor = parentEditor; + this._overwriteOptions = options; + + // Overwrite parent's options + super.updateOptions(this._overwriteOptions); + + this._register(parentEditor.onDidChangeConfiguration(e => this._onParentConfigurationChanged(e))); + } + + getParentEditor(): ICodeEditor { + return this._parentEditor; + } + + private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void { + super.updateOptions(this._parentEditor.getRawConfiguration()); + super.updateOptions(this._overwriteOptions); + } + + updateOptions(newOptions: IEditorOptions): void { objects.mixin(this._overwriteOptions, newOptions, true); super.updateOptions(this._overwriteOptions); } diff --git a/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts b/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts index 0b7a9454170..20fbcbea5ac 100644 --- a/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts +++ b/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts @@ -15,13 +15,15 @@ export class TrimTrailingWhitespaceCommand implements editorCommon.ICommand { private selection: Selection; private selectionId: string; + private cursors: Position[]; - constructor(selection: Selection) { + constructor(selection: Selection, cursors: Position[]) { this.selection = selection; + this.cursors = cursors; } public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void { - let ops = trimTrailingWhitespace(model, []); + let ops = trimTrailingWhitespace(model, this.cursors); for (let i = 0, len = ops.length; i < len; i++) { let op = ops[i]; diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 29700d8baf2..f9dc3df6ff3 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -23,13 +23,14 @@ import { hash } from 'vs/base/common/hash'; import { EditorModeContext } from 'vs/editor/common/modes/editorModeContext'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, - IModelLanguageChangedEvent, IModelOptionsChangedEvent, TextModelEventType + IModelLanguageChangedEvent, IModelOptionsChangedEvent, TextModelEventType, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents'; import * as editorOptions from 'vs/editor/common/config/editorOptions'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; let EDITOR_ID = 0; @@ -44,6 +45,9 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo private readonly _onDidChangeModelLanguage: Emitter = this._register(new Emitter()); public readonly onDidChangeModelLanguage: Event = this._onDidChangeModelLanguage.event; + private readonly _onDidChangeModelLanguageConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeModelLanguageConfiguration: Event = this._onDidChangeModelLanguageConfiguration.event; + private readonly _onDidChangeModelOptions: Emitter = this._register(new Emitter()); public readonly onDidChangeModelOptions: Event = this._onDidChangeModelOptions.event; @@ -170,7 +174,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo // editor actions don't need to be disposed this._actions = {}; - + this._removeDecorationTypes(); this._postDetachModelCleanup(this._detachModel()); this._onDidDispose.fire(); @@ -232,10 +236,24 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo newModelUrl: model ? model.uri : null }; + this._removeDecorationTypes(); this._onDidChangeModel.fire(e); this._postDetachModelCleanup(detachedModel); } + private _removeDecorationTypes(): void { + this._decorationTypeKeysToIds = {}; + if (this._decorationTypeSubtypes) { + for (let decorationType in this._decorationTypeSubtypes) { + let subTypes = this._decorationTypeSubtypes[decorationType]; + for (let subType in subTypes) { + this._removeDecorationType(decorationType + '-' + subType); + } + } + this._decorationTypeSubtypes = {}; + } + } + public getCenteredRangeInViewport(): Range { if (!this.hasView) { return null; @@ -450,7 +468,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo public revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void { this._revealRange( range, - false ? VerticalRevealType.Center : VerticalRevealType.Simple, + revealVerticalInCenter ? VerticalRevealType.Center : VerticalRevealType.Simple, revealHorizontal, scrollType ); @@ -839,6 +857,26 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo this._decorationTypeKeysToIds[decorationTypeKey] = this.deltaDecorations(oldDecorationsIds, newModelDecorations); } + public setDecorationsFast(decorationTypeKey: string, ranges: IRange[]): void { + + // remove decoration sub types that are no longer used, deregister decoration type if necessary + let oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {}; + for (let subType in oldDecorationsSubTypes) { + this._removeDecorationType(decorationTypeKey + '-' + subType); + } + this._decorationTypeSubtypes[decorationTypeKey] = {}; + + const opts = ModelDecorationOptions.createDynamic(this._resolveDecorationOptions(decorationTypeKey, false)); + let newModelDecorations: editorCommon.IModelDeltaDecoration[] = new Array(ranges.length); + for (let i = 0, len = ranges.length; i < len; i++) { + newModelDecorations[i] = { range: ranges[i], options: opts }; + } + + // update all decorations + let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey] || []; + this._decorationTypeKeysToIds[decorationTypeKey] = this.deltaDecorations(oldDecorationsIds, newModelDecorations); + } + public removeDecorations(decorationTypeKey: string): void { // remove decorations for type and sub type let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey]; @@ -887,6 +925,10 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo this._onDidChangeModelLanguage.fire(e); break; + case TextModelEventType.ModelLanguageConfigurationChanged: + this._onDidChangeModelLanguageConfiguration.fire(e); + break; + case TextModelEventType.ModelContentChanged: this._onDidChangeModelContent.fire(e); break; @@ -948,16 +990,6 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo protected _postDetachModelCleanup(detachedModel: editorCommon.IModel): void { if (detachedModel) { - this._decorationTypeKeysToIds = {}; - if (this._decorationTypeSubtypes) { - for (let decorationType in this._decorationTypeSubtypes) { - let subTypes = this._decorationTypeSubtypes[decorationType]; - for (let subType in subTypes) { - this._removeDecorationType(decorationType + '-' + subType); - } - } - this._decorationTypeSubtypes = {}; - } detachedModel.removeAllDecorationsWithOwnerId(this.id); } } @@ -993,6 +1025,9 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo protected abstract _removeDecorationType(key: string): void; protected abstract _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions; + /* __GDPR__FRAGMENT__ + "EditorTelemetryData" : {} + */ public getTelemetryData(): { [key: string]: any; } { return null; } @@ -1001,7 +1036,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo class EditorContextKeysManager extends Disposable { private _editor: CommonCodeEditor; - + // @ts-ignore unused property private _editorId: IContextKey; private _editorFocus: IContextKey; private _editorTextFocus: IContextKey; diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 14d3ec12623..76613d9b7c4 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -213,7 +213,7 @@ const editorConfiguration: IConfigurationNode = { 'type': 'number' }, 'default': EDITOR_DEFAULTS.viewInfo.rulers, - 'description': nls.localize('rulers', "Columns at which to show vertical rulers") + 'description': nls.localize('rulers', "Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty") }, 'editor.wordSeparators': { 'type': 'string', @@ -410,7 +410,7 @@ const editorConfiguration: IConfigurationNode = { 'editor.autoIndent': { 'type': 'boolean', 'default': EDITOR_DEFAULTS.autoIndent, - 'description': nls.localize('autoIndent', "Controls if the editor should automatically adjust the indentation when users type, paste or move lines. Indentation rules of the language must be available. ") + 'description': nls.localize('autoIndent', "Controls if the editor should automatically adjust the indentation when users type, paste or move lines. Indentation rules of the language must be available.") }, 'editor.suggestOnTriggerCharacters': { 'type': 'boolean', @@ -598,6 +598,11 @@ const editorConfiguration: IConfigurationNode = { 'default': EDITOR_DEFAULTS.contribInfo.colorDecorators, 'description': nls.localize('colorDecorators', "Controls whether the editor should render the inline color decorators and color picker.") }, + 'editor.lightbulb.enabled': { + 'type': 'boolean', + 'default': EDITOR_DEFAULTS.contribInfo.lightbulbEnabled, + 'description': nls.localize('codeActions', "Enables the code action lightbulb") + }, 'diffEditor.renderSideBySide': { 'type': 'boolean', 'default': true, diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index d5e263848d2..ebb78f046b7 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -114,6 +114,17 @@ export interface IEditorMinimapOptions { maxColumn?: number; } +/** + * Configuration options for editor minimap + */ +export interface IEditorLightbulbOptions { + /** + * Enable the lightbulb code action. + * Defaults to true. + */ + enabled?: boolean; +} + /** * Configuration options for the editor. */ @@ -414,7 +425,7 @@ export interface IEditorOptions { * Accept suggestions on ENTER. * Defaults to 'on'. */ - acceptSuggestionOnEnter?: 'on' | 'smart' | 'off'; + acceptSuggestionOnEnter?: boolean | 'on' | 'smart' | 'off'; /** * Accept suggestions on provider defined characters. * Defaults to true. @@ -462,6 +473,10 @@ export interface IEditorOptions { * @internal */ referenceInfos?: boolean; + /** + * Control the behavior and rendering of the code action lightbulb. + */ + lightbulb?: IEditorLightbulbOptions; /** * Enable code folding * Defaults to true in vscode and to false in monaco-editor. @@ -795,6 +810,7 @@ export interface EditorContribOptions { readonly matchBrackets: boolean; readonly find: InternalEditorFindOptions; readonly colorDecorators: boolean; + readonly lightbulbEnabled: boolean; } /** @@ -1140,6 +1156,7 @@ export class InternalEditorOptions { && a.matchBrackets === b.matchBrackets && this._equalFindOptions(a.find, b.find) && a.colorDecorators === b.colorDecorators + && a.lightbulbEnabled === b.lightbulbEnabled ); } @@ -1655,7 +1672,7 @@ export class EditorOptionsValidator { formatOnType: _boolean(opts.formatOnType, defaults.formatOnType), formatOnPaste: _boolean(opts.formatOnPaste, defaults.formatOnPaste), suggestOnTriggerCharacters: _boolean(opts.suggestOnTriggerCharacters, defaults.suggestOnTriggerCharacters), - acceptSuggestionOnEnter: _stringSet<'on' | 'smart' | 'off'>(opts.acceptSuggestionOnEnter, defaults.acceptSuggestionOnEnter, ['on', 'smart', 'off']), + acceptSuggestionOnEnter: typeof opts.acceptSuggestionOnEnter === 'string' ? _stringSet<'on' | 'smart' | 'off'>(opts.acceptSuggestionOnEnter, defaults.acceptSuggestionOnEnter, ['on', 'smart', 'off']) : opts.acceptSuggestionOnEnter ? 'on' : 'off', acceptSuggestionOnCommitCharacter: _boolean(opts.acceptSuggestionOnCommitCharacter, defaults.acceptSuggestionOnCommitCharacter), snippetSuggestions: _stringSet<'top' | 'bottom' | 'inline' | 'none'>(opts.snippetSuggestions, defaults.snippetSuggestions, ['top', 'bottom', 'inline', 'none']), wordBasedSuggestions: _boolean(opts.wordBasedSuggestions, defaults.wordBasedSuggestions), @@ -1669,6 +1686,7 @@ export class EditorOptionsValidator { matchBrackets: _boolean(opts.matchBrackets, defaults.matchBrackets), find: find, colorDecorators: _boolean(opts.colorDecorators, defaults.colorDecorators), + lightbulbEnabled: _boolean(opts.lightbulb ? opts.lightbulb.enabled : false, defaults.lightbulbEnabled) }; } } @@ -1730,7 +1748,7 @@ export class InternalEditorOptionsFactory { renderControlCharacters: (accessibilityIsOn ? false : opts.viewInfo.renderControlCharacters), // DISABLED WHEN SCREEN READER IS ATTACHED fontLigatures: (accessibilityIsOn ? false : opts.viewInfo.fontLigatures), // DISABLED WHEN SCREEN READER IS ATTACHED renderIndentGuides: (accessibilityIsOn ? false : opts.viewInfo.renderIndentGuides), // DISABLED WHEN SCREEN READER IS ATTACHED - renderLineHighlight: (accessibilityIsOn ? 'none' : opts.viewInfo.renderLineHighlight), // DISABLED WHEN SCREEN READER IS ATTACHED + renderLineHighlight: opts.viewInfo.renderLineHighlight, scrollbar: opts.viewInfo.scrollbar, minimap: { enabled: (accessibilityIsOn ? false : opts.viewInfo.minimap.enabled), // DISABLED WHEN SCREEN READER IS ATTACHED @@ -1766,7 +1784,8 @@ export class InternalEditorOptionsFactory { showFoldingControls: opts.contribInfo.showFoldingControls, matchBrackets: (accessibilityIsOn ? false : opts.contribInfo.matchBrackets), // DISABLED WHEN SCREEN READER IS ATTACHED find: opts.contribInfo.find, - colorDecorators: opts.contribInfo.colorDecorators + colorDecorators: opts.contribInfo.colorDecorators, + lightbulbEnabled: opts.contribInfo.lightbulbEnabled } }; } @@ -2074,7 +2093,7 @@ export class EditorLayoutProvider { const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace'; const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace'; -const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', \'Courier New\', monospace, \'Droid Sans Fallback\''; +const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', \'monospace\', monospace, \'Droid Sans Fallback\''; /** * @internal @@ -2205,6 +2224,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = { seedSearchStringFromSelection: true, autoFindInSelection: false }, - colorDecorators: true + colorDecorators: true, + lightbulbEnabled: true }, }; diff --git a/src/vs/editor/common/controller/coreCommands.ts b/src/vs/editor/common/controller/coreCommands.ts index efda8829169..f3a8e446f63 100644 --- a/src/vs/editor/common/controller/coreCommands.ts +++ b/src/vs/editor/common/controller/coreCommands.ts @@ -8,7 +8,7 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { CursorState, ICursors, RevealTarget, IColumnSelectData, CursorContext } from 'vs/editor/common/controller/cursorCommon'; +import { CursorState, ICursors, RevealTarget, IColumnSelectData, CursorContext, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; import { CursorMoveCommands, CursorMove as CursorMove_ } from 'vs/editor/common/controller/cursorMoveCommands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -114,7 +114,7 @@ export namespace EditorScroll_ { value?: number; revealCursor?: boolean; select?: boolean; - }; + } export function parse(args: RawArguments): ParsedArguments { let direction: Direction; @@ -224,7 +224,7 @@ export namespace RevealLine_ { export interface RawArguments { lineNumber?: number; at?: string; - }; + } /** * Values for reveal line 'at' argument @@ -1273,7 +1273,8 @@ export namespace CoreNavigationCommands { const lastAddedCursorIndex = cursors.getLastAddedCursorIndex(); let newStates = cursors.getAll().slice(0); - newStates[lastAddedCursorIndex] = CursorMoveCommands.word(context, newStates[lastAddedCursorIndex], true, args.position); + let lastAddedState = newStates[lastAddedCursorIndex]; + newStates[lastAddedCursorIndex] = CursorMoveCommands.word(context, lastAddedState, lastAddedState.modelState.hasSelection(), args.position); context.model.pushStackElement(); cursors.setStates( @@ -1613,11 +1614,13 @@ export namespace CoreEditingCommands { } public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { - const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); + const cursors = editor._getCursors(); + const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(cursors.getPrevEditOperationType(), editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); if (shouldPushStackElementBefore) { editor.pushUndoStop(); } editor.executeCommands(this.id, commands); + cursors.setPrevEditOperationType(EditOperationType.DeletingLeft); } }); @@ -1636,16 +1639,18 @@ export namespace CoreEditingCommands { } public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { - const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); + const cursors = editor._getCursors(); + const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(cursors.getPrevEditOperationType(), editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); if (shouldPushStackElementBefore) { editor.pushUndoStop(); } editor.executeCommands(this.id, commands); + cursors.setPrevEditOperationType(EditOperationType.DeletingRight); } }); } - +// @ts-ignore unused namespace namespace Config { function findFocusedEditor(accessor: ServicesAccessor): editorCommon.ICommonCodeEditor { diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index aa2cc79c0fe..9c247c0ac58 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -12,8 +12,7 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection, SelectionDirection, ISelection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors } from 'vs/editor/common/controller/cursorCommon'; -import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; +import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; import { TextModelEventType, ModelRawContentChangedEvent, RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; @@ -21,7 +20,6 @@ import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import Event, { Emitter } from 'vs/base/common/event'; -// import { ScreenReaderMessageGenerator } from "vs/editor/common/controller/accGenerator"; function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean { for (let i = 0, len = events.length; i < len; i++) { @@ -100,6 +98,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; private _columnSelectData: IColumnSelectData; + private _prevEditOperationType: EditOperationType; constructor(configuration: editorCommon.IConfiguration, model: editorCommon.IModel, viewModel: IViewModel) { super(); @@ -112,6 +111,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; this._columnSelectData = null; + this._prevEditOperationType = EditOperationType.Other; this._register(this._model.addBulkListener((events) => { if (this._isHandling) { @@ -151,11 +151,10 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this.context = new CursorContext(this._configuration, this._model, this._viewModel); this._cursors.updateContext(this.context); }; - this._register(this._model.onDidChangeLanguage((e) => { + this._register(model.onDidChangeLanguage((e) => { updateCursorContext(); })); - this._register(LanguageConfigurationRegistry.onDidChange(() => { - // TODO@Alex: react only if certain supports changed? (and if my model's mode changed) + this._register(model.onDidChangeLanguageConfiguration(() => { updateCursorContext(); })); this._register(model.onDidChangeOptions(() => { @@ -281,6 +280,9 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } private _onModelContentChanged(hadFlushEvent: boolean): void { + + this._prevEditOperationType = EditOperationType.Other; + if (hadFlushEvent) { // a model.setValue() was called this._cursors.dispose(); @@ -325,6 +327,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this.setStates(source, CursorChangeReason.NotSet, CursorState.fromModelSelections(selections)); } + public getPrevEditOperationType(): EditOperationType { + return this._prevEditOperationType; + } + + public setPrevEditOperationType(type: EditOperationType): void { + this._prevEditOperationType = type; + } + // ------ auxiliary handling logic private _executeEditOperation(opResult: EditOperationResult): void { @@ -347,6 +357,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (result) { // The commands were applied correctly this._interpretCommandResult(result); + + this._prevEditOperationType = opResult.type; } if (opResult.shouldPushStackElementAfter) { @@ -518,16 +530,16 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } // Here we must interpret each typed character individually, that's why we create a new context - this._executeEditOperation(TypeOperations.typeWithInterceptors(this.context.config, this.context.model, this.getSelections(), chr)); + this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr)); } } else { - this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this.context.config, this.context.model, this.getSelections(), text)); + this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text)); } } private _replacePreviousChar(text: string, replaceCharCnt: number): void { - this._executeEditOperation(TypeOperations.replacePreviousChar(this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt)); + this._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt)); } private _paste(text: string, pasteOnNewLine: boolean): void { @@ -541,14 +553,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _externalExecuteCommand(command: editorCommon.ICommand): void { this._cursors.killSecondaryCursors(); - this._executeEditOperation(new EditOperationResult([command], { + this._executeEditOperation(new EditOperationResult(EditOperationType.Other, [command], { shouldPushStackElementBefore: false, shouldPushStackElementAfter: false })); } private _externalExecuteCommands(commands: editorCommon.ICommand[]): void { - this._executeEditOperation(new EditOperationResult(commands, { + this._executeEditOperation(new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: false, shouldPushStackElementAfter: false })); @@ -558,8 +570,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { interface IExecContext { readonly model: editorCommon.IModel; readonly selectionsBefore: Selection[]; - readonly selectionStartMarkers: string[]; - readonly positionMarkers: string[]; + readonly trackedRanges: string[]; + readonly trackedRangesDirection: SelectionDirection[]; } interface ICommandData { @@ -579,15 +591,14 @@ class CommandExecutor { const ctx: IExecContext = { model: model, selectionsBefore: selectionsBefore, - selectionStartMarkers: [], - positionMarkers: [] + trackedRanges: [], + trackedRangesDirection: [] }; const result = this._innerExecuteCommands(ctx, commands); - for (let i = 0; i < ctx.selectionStartMarkers.length; i++) { - ctx.model._removeMarker(ctx.selectionStartMarkers[i]); - ctx.model._removeMarker(ctx.positionMarkers[i]); + for (let i = 0, len = ctx.trackedRanges.length; i < len; i++) { + ctx.model._setTrackedRange(ctx.trackedRanges[i], null, editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges); } return result; @@ -664,9 +675,11 @@ class CommandExecutor { getTrackedSelection: (id: string) => { const idx = parseInt(id, 10); - const selectionStartMarker = ctx.model._getMarker(ctx.selectionStartMarkers[idx]); - const positionMarker = ctx.model._getMarker(ctx.positionMarkers[idx]); - return new Selection(selectionStartMarker.lineNumber, selectionStartMarker.column, positionMarker.lineNumber, positionMarker.column); + const range = ctx.model._getTrackedRange(ctx.trackedRanges[idx]); + if (ctx.trackedRangesDirection[idx] === SelectionDirection.LTR) { + return new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn); + } + return new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn); } }); } else { @@ -753,37 +766,31 @@ class CommandExecutor { }; const trackSelection = (selection: Selection, trackPreviousOnEmpty?: boolean) => { - let selectionMarkerStickToPreviousCharacter: boolean; - let positionMarkerStickToPreviousCharacter: boolean; - + let stickiness: editorCommon.TrackedRangeStickiness; if (selection.isEmpty()) { - // Try to lock it with surrounding text if (typeof trackPreviousOnEmpty === 'boolean') { - selectionMarkerStickToPreviousCharacter = trackPreviousOnEmpty; - positionMarkerStickToPreviousCharacter = trackPreviousOnEmpty; + if (trackPreviousOnEmpty) { + stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore; + } else { + stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter; + } } else { + // Try to lock it with surrounding text const maxLineColumn = ctx.model.getLineMaxColumn(selection.startLineNumber); if (selection.startColumn === maxLineColumn) { - selectionMarkerStickToPreviousCharacter = true; - positionMarkerStickToPreviousCharacter = true; + stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore; } else { - selectionMarkerStickToPreviousCharacter = false; - positionMarkerStickToPreviousCharacter = false; + stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter; } } } else { - if (selection.getDirection() === SelectionDirection.LTR) { - selectionMarkerStickToPreviousCharacter = false; - positionMarkerStickToPreviousCharacter = true; - } else { - selectionMarkerStickToPreviousCharacter = true; - positionMarkerStickToPreviousCharacter = false; - } + stickiness = editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges; } - const l = ctx.selectionStartMarkers.length; - ctx.selectionStartMarkers[l] = ctx.model._addMarker(0, selection.selectionStartLineNumber, selection.selectionStartColumn, selectionMarkerStickToPreviousCharacter); - ctx.positionMarkers[l] = ctx.model._addMarker(0, selection.positionLineNumber, selection.positionColumn, positionMarkerStickToPreviousCharacter); + const l = ctx.trackedRanges.length; + const id = ctx.model._setTrackedRange(null, selection, stickiness); + ctx.trackedRanges[l] = id; + ctx.trackedRangesDirection[l] = selection.getDirection(); return l.toString(); }; diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index 615643272da..b3b40cca6b3 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -31,6 +31,17 @@ export const enum RevealTarget { BottomMost = 2 } +/** + * This is an operation type that will be recorded for undo/redo purposes. + * The goal is to introduce an undo stop when the controller switches between different operation types. + */ +export const enum EditOperationType { + Other = 0, + Typing = 1, + DeletingLeft = 2, + DeletingRight = 3 +} + export interface ICursors { readonly context: CursorContext; getPrimaryCursor(): CursorState; @@ -45,6 +56,9 @@ export interface ICursors { revealRange(revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void; scrollTo(desiredScrollTop: number): void; + + getPrevEditOperationType(): EditOperationType; + setPrevEditOperationType(type: EditOperationType): void; } export interface CharacterMap { @@ -422,17 +436,20 @@ export class CursorState { export class EditOperationResult { _editOperationResultBrand: void; + readonly type: EditOperationType; readonly commands: ICommand[]; readonly shouldPushStackElementBefore: boolean; readonly shouldPushStackElementAfter: boolean; constructor( + type: EditOperationType, commands: ICommand[], opts: { shouldPushStackElementBefore: boolean; shouldPushStackElementAfter: boolean; } ) { + this.type = type; this.commands = commands; this.shouldPushStackElementBefore = opts.shouldPushStackElementBefore; this.shouldPushStackElementAfter = opts.shouldPushStackElementAfter; diff --git a/src/vs/editor/common/controller/cursorDeleteOperations.ts b/src/vs/editor/common/controller/cursorDeleteOperations.ts index 7951ab91b83..e5b498b40e9 100644 --- a/src/vs/editor/common/controller/cursorDeleteOperations.ts +++ b/src/vs/editor/common/controller/cursorDeleteOperations.ts @@ -5,7 +5,7 @@ 'use strict'; import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; -import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult } from 'vs/editor/common/controller/cursorCommon'; +import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations'; @@ -14,9 +14,9 @@ import { ICommand } from 'vs/editor/common/editorCommon'; export class DeleteOperations { - public static deleteRight(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { + public static deleteRight(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { let commands: ICommand[] = []; - let shouldPushStackElementBefore = false; + let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingRight); for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -94,14 +94,14 @@ export class DeleteOperations { return [true, commands]; } - public static deleteLeft(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { + public static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] { if (this._isAutoClosingPairDelete(config, model, selections)) { return this._runAutoClosingPairDelete(config, model, selections); } let commands: ICommand[] = []; - let shouldPushStackElementBefore = false; + let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft); for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -210,7 +210,7 @@ export class DeleteOperations { commands[i] = new ReplaceCommand(selection, ''); } } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); diff --git a/src/vs/editor/common/controller/cursorMoveCommands.ts b/src/vs/editor/common/controller/cursorMoveCommands.ts index 97925d92dcc..c3320572991 100644 --- a/src/vs/editor/common/controller/cursorMoveCommands.ts +++ b/src/vs/editor/common/controller/cursorMoveCommands.ts @@ -418,7 +418,19 @@ export class CursorMoveCommands { let result: CursorState[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - result[i] = CursorState.fromViewState(MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns)); + + let newViewState = MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns); + + if (noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) { + // moved over to the previous view line + const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position); + if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) { + // stayed on the same model line => pass wrapping point where 2 view positions map to a single model position + newViewState = MoveOperations.moveLeft(context.config, context.viewModel, newViewState, inSelectionMode, 1); + } + } + + result[i] = CursorState.fromViewState(newViewState); } return result; } @@ -438,7 +450,18 @@ export class CursorMoveCommands { let result: CursorState[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - result[i] = CursorState.fromViewState(MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns)); + let newViewState = MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns); + + if (noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) { + // moved over to the next view line + const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position); + if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) { + // stayed on the same model line => pass wrapping point where 2 view positions map to a single model position + newViewState = MoveOperations.moveRight(context.config, context.viewModel, newViewState, inSelectionMode, 1); + } + } + + result[i] = CursorState.fromViewState(newViewState); } return result; } @@ -647,7 +670,7 @@ export namespace CursorMove { select?: boolean; by?: string; value?: number; - }; + } export function parse(args: RawArguments): ParsedArguments { if (!args.to) { @@ -730,7 +753,7 @@ export namespace CursorMove { unit: Unit; select: boolean; value: number; - }; + } export const enum Direction { Left, @@ -749,7 +772,7 @@ export namespace CursorMove { ViewPortBottom, ViewPortIfOutside, - }; + } export const enum Unit { None, @@ -757,6 +780,6 @@ export namespace CursorMove { WrappedLine, Character, HalfLine, - }; + } } diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index 763d7731ff6..0ffb52bd5af 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -6,7 +6,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { ReplaceCommand, ReplaceCommandWithoutChangingPosition, ReplaceCommandWithOffsetCursorState } from 'vs/editor/common/commands/replaceCommand'; -import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult } from 'vs/editor/common/controller/cursorCommon'; +import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult, EditOperationType } from 'vs/editor/common/controller/cursorCommon'; import { Range } from 'vs/editor/common/core/range'; import { ICommand, ITokenizedModel } from 'vs/editor/common/editorCommon'; import * as strings from 'vs/base/common/strings'; @@ -73,7 +73,7 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { commands[i] = new ReplaceCommand(selections[i], text[i]); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); @@ -103,7 +103,7 @@ export class TypeOperations { commands[i] = new ReplaceCommand(selection, text); } } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); @@ -255,7 +255,7 @@ export class TypeOperations { return commands; } - public static replacePreviousChar(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult { + public static replacePreviousChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -271,8 +271,8 @@ export class TypeOperations { let range = new Range(pos.lineNumber, startColumn, pos.lineNumber, pos.column); commands[i] = new ReplaceCommand(range, txt); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: false, + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), shouldPushStackElementAfter: false }); } @@ -324,6 +324,13 @@ export class TypeOperations { } // no enter rules applied, we should check indentation rules then. + if (!config.autoIndent) { + // Nothing special + let lineText = model.getLineContent(range.startLineNumber); + let indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1); + return TypeOperations._typeCommand(range, '\n' + config.normalizeIndentation(indentation), keepPosition); + } + let ir = LanguageConfigurationRegistry.getIndentForEnter(model, range, { unshiftIndent: (indent) => { return TypeOperations.unshiftIndent(config, indent); @@ -468,7 +475,7 @@ export class TypeOperations { return cnt; } - private static _runAutoClosingCloseCharType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + private static _runAutoClosingCloseCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; @@ -476,8 +483,8 @@ export class TypeOperations { const typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1); commands[i] = new ReplaceCommand(typeSelection, ch); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: false, + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), shouldPushStackElementAfter: false }); } @@ -550,14 +557,14 @@ export class TypeOperations { return true; } - private static _runAutoClosingOpenCharType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + private static _runAutoClosingOpenCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.autoClosingPairsOpen[ch]; commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false }); @@ -597,14 +604,14 @@ export class TypeOperations { return true; } - private static _runSurroundSelectionType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + private static _runSurroundSelectionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.surroundingPairs[ch]; commands[i] = new SurroundSelectionCommand(selection, ch, closeCharacter); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Other, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: true }); @@ -617,7 +624,7 @@ export class TypeOperations { return false; } - private static _typeInterceptorElectricChar(config: CursorConfiguration, model: ITokenizedModel, selection: Selection, ch: string): EditOperationResult { + private static _typeInterceptorElectricChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selection: Selection, ch: string): EditOperationResult { if (!config.electricChars.hasOwnProperty(ch) || !selection.isEmpty()) { return null; } @@ -639,7 +646,7 @@ export class TypeOperations { if (electricAction.appendText) { const command = new ReplaceCommandWithOffsetCursorState(selection, ch + electricAction.appendText, 0, -electricAction.appendText.length); - return new EditOperationResult([command], { + return new EditOperationResult(EditOperationType.Typing, [command], { shouldPushStackElementBefore: false, shouldPushStackElementAfter: true }); @@ -670,7 +677,7 @@ export class TypeOperations { let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column); const command = new ReplaceCommand(typeSelection, typeText); - return new EditOperationResult([command], { + return new EditOperationResult(EditOperationType.Typing, [command], { shouldPushStackElementBefore: false, shouldPushStackElementAfter: true }); @@ -680,23 +687,31 @@ export class TypeOperations { return null; } - public static typeWithInterceptors(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { + public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult { if (ch === '\n') { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { commands[i] = TypeOperations._enter(config, model, false, selections[i]); } - return new EditOperationResult(commands, { + return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false, }); } if (this._isAutoIndentType(config, model, selections)) { - let indentCommand = this._runAutoIndentType(config, model, selections[0], ch); - if (indentCommand) { - return new EditOperationResult([indentCommand], { + let commands: ICommand[] = []; + let autoIndentFails = false; + for (let i = 0, len = selections.length; i < len; i++) { + commands[i] = this._runAutoIndentType(config, model, selections[i], ch); + if (!commands[i]) { + autoIndentFails = true; + break; + } + } + if (!autoIndentFails) { + return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false, }); @@ -704,36 +719,48 @@ export class TypeOperations { } if (this._isAutoClosingCloseCharType(config, model, selections, ch)) { - return this._runAutoClosingCloseCharType(config, model, selections, ch); + return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch); } if (this._isAutoClosingOpenCharType(config, model, selections, ch)) { - return this._runAutoClosingOpenCharType(config, model, selections, ch); + return this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch); } if (this._isSurroundSelectionType(config, model, selections, ch)) { - return this._runSurroundSelectionType(config, model, selections, ch); + return this._runSurroundSelectionType(prevEditOperationType, config, model, selections, ch); } // Electric characters make sense only when dealing with a single cursor, // as multiple cursors typing brackets for example would interfer with bracket matching if (this._isTypeInterceptorElectricChar(config, model, selections)) { - const r = this._typeInterceptorElectricChar(config, model, selections[0], ch); + const r = this._typeInterceptorElectricChar(prevEditOperationType, config, model, selections[0], ch); if (r) { return r; } } - return this.typeWithoutInterceptors(config, model, selections, ch); + // A simple character type + let commands: ICommand[] = []; + for (let i = 0, len = selections.length; i < len; i++) { + commands[i] = new ReplaceCommand(selections[i], ch); + } + let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.Typing); + if (ch === ' ') { + shouldPushStackElementBefore = true; + } + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: shouldPushStackElementBefore, + shouldPushStackElementAfter: false + }); } - public static typeWithoutInterceptors(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], str: string): EditOperationResult { + public static typeWithoutInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], str: string): EditOperationResult { let commands: ICommand[] = []; for (let i = 0, len = selections.length; i < len; i++) { commands[i] = new ReplaceCommand(selections[i], str); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: false, + return new EditOperationResult(EditOperationType.Typing, commands, { + shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), shouldPushStackElementAfter: false }); } diff --git a/src/vs/editor/common/controller/cursorWordOperations.ts b/src/vs/editor/common/controller/cursorWordOperations.ts index 3666961a2a2..8f83c1f8621 100644 --- a/src/vs/editor/common/controller/cursorWordOperations.ts +++ b/src/vs/editor/common/controller/cursorWordOperations.ts @@ -378,7 +378,7 @@ export class WordOperations { let nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position); let isInNextWord = (nextWord && nextWord.wordType === WordType.Regular && nextWord.start < position.column - 1 && position.column - 1 <= nextWord.end); - if (!inSelectionMode || !cursor.hasSelection()) { + if (!inSelectionMode) { // Entering word selection for the first time let startColumn: number; @@ -425,7 +425,9 @@ export class WordOperations { let lineNumber = position.lineNumber; let column: number; - if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) { + if (cursor.selectionStart.containsPosition(position)) { + column = cursor.selectionStart.endColumn; + } else if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) { column = startColumn; let possiblePosition = new Position(lineNumber, column); if (cursor.selectionStart.containsPosition(possiblePosition)) { @@ -439,6 +441,6 @@ export class WordOperations { } } - return cursor.move(cursor.hasSelection(), lineNumber, column, 0); + return cursor.move(true, lineNumber, column, 0); } } diff --git a/src/vs/editor/common/controller/oneCursor.ts b/src/vs/editor/common/controller/oneCursor.ts index ae9c990ec4a..fc2690244fb 100644 --- a/src/vs/editor/common/controller/oneCursor.ts +++ b/src/vs/editor/common/controller/oneCursor.ts @@ -8,16 +8,21 @@ import { SingleCursorState, CursorContext, CursorState } from 'vs/editor/common/ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection, SelectionDirection } from 'vs/editor/common/core/selection'; +import { TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; export class OneCursor { public modelState: SingleCursorState; public viewState: SingleCursorState; - private _selStartMarker: string; - private _selEndMarker: string; + private _selTrackedRange: string; constructor(context: CursorContext) { + this.modelState = null; + this.viewState = null; + + this._selTrackedRange = null; + this._setState( context, new SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0), @@ -26,8 +31,7 @@ export class OneCursor { } public dispose(context: CursorContext): void { - context.model._removeMarker(this._selStartMarker); - context.model._removeMarker(this._selEndMarker); + this._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, null, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges); } public asCursorState(): CursorState { @@ -35,14 +39,11 @@ export class OneCursor { } public readSelectionFromMarkers(context: CursorContext): Selection { - const start = context.model._getMarker(this._selStartMarker); - const end = context.model._getMarker(this._selEndMarker); - + const range = context.model._getTrackedRange(this._selTrackedRange); if (this.modelState.selection.getDirection() === SelectionDirection.LTR) { - return new Selection(start.lineNumber, start.column, end.lineNumber, end.column); + return new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn); } - - return new Selection(end.lineNumber, end.column, start.lineNumber, start.column); + return new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn); } public ensureValidState(context: CursorContext): void { @@ -100,17 +101,6 @@ export class OneCursor { this.modelState = modelState; this.viewState = viewState; - this._selStartMarker = this._ensureMarker(context, this._selStartMarker, this.modelState.selection.startLineNumber, this.modelState.selection.startColumn, true); - this._selEndMarker = this._ensureMarker(context, this._selEndMarker, this.modelState.selection.endLineNumber, this.modelState.selection.endColumn, false); - } - - private _ensureMarker(context: CursorContext, markerId: string, lineNumber: number, column: number, stickToPreviousCharacter: boolean): string { - if (!markerId) { - return context.model._addMarker(0, lineNumber, column, stickToPreviousCharacter); - } else { - context.model._changeMarker(markerId, lineNumber, column); - context.model._changeMarkerStickiness(markerId, stickToPreviousCharacter); - return markerId; - } + this._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, this.modelState.selection, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges); } } diff --git a/src/vs/editor/common/core/uint.ts b/src/vs/editor/common/core/uint.ts index b68709f2ce2..924b783a4a5 100644 --- a/src/vs/editor/common/core/uint.ts +++ b/src/vs/editor/common/core/uint.ts @@ -7,6 +7,7 @@ export class Uint8Matrix { private _data: Uint8Array; + // @ts-ignore unused property private _rows: number; private _cols: number; diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index a8faeb62a75..2bc38f26a22 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -15,11 +15,11 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { Range, IRange } from 'vs/editor/common/core/range'; import { Selection, ISelection } from 'vs/editor/common/core/selection'; -import { IndentRange } from 'vs/editor/common/model/indentRanges'; +import { IndentRanges } from 'vs/editor/common/model/indentRanges'; import { ITextSource } from 'vs/editor/common/model/textSource'; import { ModelRawContentChangedEvent, IModelContentChangedEvent, IModelDecorationsChangedEvent, - IModelLanguageChangedEvent, IModelOptionsChangedEvent + IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents'; import * as editorOptions from 'vs/editor/common/config/editorOptions'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -157,10 +157,6 @@ export interface IModelDecoration { * Options associated with this decoration. */ readonly options: IModelDecorationOptions; - /** - * A flag describing if this is a problem decoration (e.g. warning/error). - */ - readonly isForValidation: boolean; } /** @@ -585,20 +581,6 @@ export interface ITextModel { */ getLineContent(lineNumber: number): string; - /** - * @internal - */ - getIndentLevel(lineNumber: number): number; - - /** - * @internal - */ - getIndentRanges(): IndentRange[]; - - /** - * @internal - */ - getLineIndentGuide(lineNumber: number): number; /** * Get the text for all lines. @@ -912,32 +894,16 @@ export interface ITokenizedModel extends ITextModel { * @internal */ matchBracket(position: IPosition): [Range, Range]; -} -/** - * A model that can track markers. - */ -export interface ITextModelWithMarkers extends ITextModel { /** * @internal */ - _addMarker(internalDecorationId: number, lineNumber: number, column: number, stickToPreviousCharacter: boolean): string; + getIndentRanges(): IndentRanges; + /** * @internal */ - _changeMarker(id: string, newLineNumber: number, newColumn: number): void; - /** - * @internal - */ - _changeMarkerStickiness(id: string, newStickToPreviousCharacter: boolean): void; - /** - * @internal - */ - _getMarker(id: string): Position; - /** - * @internal - */ - _removeMarker(id: string): void; + getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[]; } /** @@ -1033,12 +999,29 @@ export interface ITextModelWithDecorations { * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors). */ getAllDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[]; + + /** + * Gets all the decorations that should be rendered in the overview ruler as an array. + * @param ownerId If set, it will ignore decorations belonging to other owners. + * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors). + */ + getOverviewRulerDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[]; + + /** + * @internal + */ + _getTrackedRange(id: string): Range; + + /** + * @internal + */ + _setTrackedRange(id: string, newRange: Range, newStickiness: TrackedRangeStickiness): string; } /** * An editable text model. */ -export interface IEditableTextModel extends ITextModelWithMarkers { +export interface IEditableTextModel extends ITextModel { /** * Normalize a string containing whitespace according to indentation rules (converts to spaces or to tabs). @@ -1121,7 +1104,7 @@ export interface IEditableTextModel extends ITextModelWithMarkers { /** * A model. */ -export interface IModel extends IReadOnlyModel, IEditableTextModel, ITextModelWithMarkers, ITokenizedModel, ITextModelWithDecorations { +export interface IModel extends IReadOnlyModel, IEditableTextModel, ITokenizedModel, ITextModelWithDecorations { /** * @deprecated Please use `onDidChangeContent` instead. * An event emitted when the contents of the model have changed. @@ -1149,6 +1132,11 @@ export interface IModel extends IReadOnlyModel, IEditableTextModel, ITextModelWi * @event */ onDidChangeLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration associated with the model has changed. + * @event + */ + onDidChangeLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted right before disposing the model. * @event @@ -1748,6 +1736,11 @@ export interface ICommonCodeEditor extends IEditor { * @event */ onDidChangeModelLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration of the current model has changed. + * @event + */ + onDidChangeModelLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the options of the current model has changed. * @event @@ -1966,6 +1959,11 @@ export interface ICommonCodeEditor extends IEditor { */ setDecorations(decorationTypeKey: string, ranges: IDecorationOptions[]): void; + /** + * @internal + */ + setDecorationsFast(decorationTypeKey: string, ranges: IRange[]): void; + /** * @internal */ diff --git a/src/vs/editor/common/editorCommonExtensions.ts b/src/vs/editor/common/editorCommonExtensions.ts index 7fc3fda9ce2..aaea4371983 100644 --- a/src/vs/editor/common/editorCommonExtensions.ts +++ b/src/vs/editor/common/editorCommonExtensions.ts @@ -153,6 +153,7 @@ export abstract class EditorCommand extends Command { export interface IEditorCommandMenuOptions { group?: string; order?: number; + when?: ContextKeyExpr; } export interface IActionOptions extends ICommandOptions { label: string; @@ -182,7 +183,7 @@ export abstract class EditorAction extends EditorCommand { id: this.id, title: this.label }, - when: this.precondition, + when: ContextKeyExpr.and(this.precondition, this.menuOpts.when), group: this.menuOpts.group, order: this.menuOpts.order }; @@ -194,6 +195,15 @@ export abstract class EditorAction extends EditorCommand { } protected reportTelemetry(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor) { + /* __GDPR__ + "editorActionInvoked" : { + "name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "${include}": [ + "${EditorTelemetryData}" + ] + } + */ accessor.get(ITelemetryService).publicLog('editorActionInvoked', { name: this.label, id: this.id, ...editor.getTelemetryData() }); } diff --git a/src/vs/editor/common/editorContextKeys.ts b/src/vs/editor/common/editorContextKeys.ts index 8843cf821d4..c17abc56f0f 100644 --- a/src/vs/editor/common/editorContextKeys.ts +++ b/src/vs/editor/common/editorContextKeys.ts @@ -42,4 +42,4 @@ export namespace EditorContextKeys { export const hasDocumentFormattingProvider = new RawContextKey('editorHasDocumentFormattingProvider', undefined); export const hasDocumentSelectionFormattingProvider = new RawContextKey('editorHasDocumentSelectionFormattingProvider', undefined); export const hasSignatureHelpProvider = new RawContextKey('editorHasSignatureHelpProvider', undefined); -}; +} diff --git a/src/vs/editor/common/model/editableTextModel.ts b/src/vs/editor/common/model/editableTextModel.ts index 66566d1092b..99478d2869e 100644 --- a/src/vs/editor/common/model/editableTextModel.ts +++ b/src/vs/editor/common/model/editableTextModel.ts @@ -7,12 +7,11 @@ import { Range, IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { EditStack } from 'vs/editor/common/model/editStack'; -import { ILineEdit, LineMarker, MarkersTracker, IModelLine } from 'vs/editor/common/model/modelLine'; +import { ILineEdit, IModelLine } from 'vs/editor/common/model/modelLine'; import { TextModelWithDecorations, ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import * as strings from 'vs/base/common/strings'; import * as arrays from 'vs/base/common/arrays'; import { Selection } from 'vs/editor/common/core/selection'; -import { Position } from 'vs/editor/common/core/position'; import { IDisposable } from 'vs/base/common/lifecycle'; import { LanguageIdentifier } from 'vs/editor/common/modes'; import { ITextSource, IRawTextSource, RawTextSource } from 'vs/editor/common/model/textSource'; @@ -23,6 +22,7 @@ export interface IValidatedEditOperation { sortIndex: number; identifier: editorCommon.ISingleEditOperationIdentifier; range: Range; + rangeOffset: number; rangeLength: number; lines: string[]; forceMoveMarkers: boolean; @@ -249,6 +249,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito sortIndex: 0, identifier: operations[0].identifier, range: entireEditRange, + rangeOffset: this.getOffsetAt(entireEditRange.getStartPosition()), rangeLength: this.getValueLengthInRange(entireEditRange), lines: result.join('').split('\n'), forceMoveMarkers: forceMoveMarkers, @@ -275,15 +276,15 @@ export class EditableTextModel extends TextModelWithDecorations implements edito public applyEdits(rawOperations: editorCommon.IIdentifiedSingleEditOperation[]): editorCommon.IIdentifiedSingleEditOperation[] { try { this._eventEmitter.beginDeferredEmit(); - let markersTracker = this._acquireMarkersTracker(); - return this._applyEdits(markersTracker, rawOperations); + this._acquireDecorationsTracker(); + return this._applyEdits(rawOperations); } finally { - this._releaseMarkersTracker(); + this._releaseDecorationsTracker(); this._eventEmitter.endDeferredEmit(); } } - private _applyEdits(markersTracker: MarkersTracker, rawOperations: editorCommon.IIdentifiedSingleEditOperation[]): editorCommon.IIdentifiedSingleEditOperation[] { + private _applyEdits(rawOperations: editorCommon.IIdentifiedSingleEditOperation[]): editorCommon.IIdentifiedSingleEditOperation[] { if (rawOperations.length === 0) { return []; } @@ -310,6 +311,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito sortIndex: i, identifier: op.identifier, range: validatedRange, + rangeOffset: this.getOffsetAt(validatedRange.getStartPosition()), rangeLength: this.getValueLengthInRange(validatedRange), lines: op.text ? op.text.split(/\r\n|\r|\n/) : null, forceMoveMarkers: op.forceMoveMarkers, @@ -378,7 +380,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito this._mightContainRTL = mightContainRTL; this._mightContainNonBasicASCII = mightContainNonBasicASCII; - this._doApplyEdits(markersTracker, operations); + this._doApplyEdits(operations); this._trimAutoWhitespaceLines = null; if (this._options.trimAutoWhitespace && newTrimAutoWhitespaceCandidates.length > 0) { @@ -465,9 +467,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito return result; } - private _doApplyEdits(markersTracker: MarkersTracker, operations: IValidatedEditOperation[]): void { - - const tabSize = this._options.tabSize; + private _doApplyEdits(operations: IValidatedEditOperation[]): void { // Sort operations descending operations.sort(EditableTextModel._sortOpsDescending); @@ -503,11 +503,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito } this._invalidateLine(currentLineNumber - 1); - this._lines[currentLineNumber - 1].applyEdits(markersTracker, lineEditsQueue.slice(currentLineNumberStart, i), tabSize); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); - } + this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, i)); + this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text) ); @@ -517,11 +514,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito } this._invalidateLine(currentLineNumber - 1); - this._lines[currentLineNumber - 1].applyEdits(markersTracker, lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length), tabSize); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); - } + this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length)); + this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text) ); @@ -529,10 +523,6 @@ export class EditableTextModel extends TextModelWithDecorations implements edito lineEditsQueue = []; }; - let minTouchedLineNumber = operations[operations.length - 1].range.startLineNumber; - let maxTouchedLineNumber = operations[0].range.endLineNumber + 1; - let totalLinesCountDelta = 0; - for (let i = 0, len = operations.length; i < len; i++) { const op = operations[i]; @@ -556,8 +546,6 @@ export class EditableTextModel extends TextModelWithDecorations implements edito const insertingLinesCnt = (op.lines ? op.lines.length - 1 : 0); const editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt); - totalLinesCountDelta += (insertingLinesCnt - deletingLinesCnt); - // Iterating descending to overlap with previous op // in case there are common lines being edited in both for (let j = editingLinesCnt; j >= 0; j--) { @@ -567,8 +555,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito lineNumber: editLineNumber, startColumn: (editLineNumber === startLineNumber ? startColumn : 1), endColumn: (editLineNumber === endLineNumber ? endColumn : this.getLineMaxColumn(editLineNumber)), - text: (op.lines ? op.lines[j] : ''), - forceMoveMarkers: op.forceMoveMarkers + text: (op.lines ? op.lines[j] : '') }); } @@ -579,43 +566,19 @@ export class EditableTextModel extends TextModelWithDecorations implements edito flushLineEdits(); const spliceStartLineNumber = startLineNumber + editingLinesCnt; - const spliceStartColumn = this.getLineMaxColumn(spliceStartLineNumber); - const endLineRemains = this._lines[endLineNumber - 1].split(markersTracker, endColumn, false, tabSize); + const endLineRemains = this._lines[endLineNumber - 1].split(endColumn); this._invalidateLine(spliceStartLineNumber - 1); const spliceCnt = endLineNumber - spliceStartLineNumber; - // Collect all these markers - let markersOnDeletedLines: LineMarker[] = []; - for (let j = 0; j < spliceCnt; j++) { - const deleteLineIndex = spliceStartLineNumber + j; - const deleteLineMarkers = this._lines[deleteLineIndex].getMarkers(); - if (deleteLineMarkers) { - markersOnDeletedLines = markersOnDeletedLines.concat(deleteLineMarkers); - } - } - this._lines.splice(spliceStartLineNumber, spliceCnt); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.removeValues(spliceStartLineNumber, spliceCnt); - } + this._lineStarts.removeValues(spliceStartLineNumber, spliceCnt); // Reconstruct first line - this._lines[spliceStartLineNumber - 1].append(markersTracker, spliceStartLineNumber, endLineRemains, tabSize); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.changeValue(spliceStartLineNumber - 1, this._lines[spliceStartLineNumber - 1].text.length + this._EOL.length); - } + this._lines[spliceStartLineNumber - 1].append(endLineRemains); + this._lineStarts.changeValue(spliceStartLineNumber - 1, this._lines[spliceStartLineNumber - 1].text.length + this._EOL.length); - // Update deleted markers - const deletedMarkersPosition = new Position(spliceStartLineNumber, spliceStartColumn); - for (let j = 0, lenJ = markersOnDeletedLines.length; j < lenJ; j++) { - markersOnDeletedLines[j].updatePosition(markersTracker, deletedMarkersPosition); - } - - this._lines[spliceStartLineNumber - 1].addMarkers(markersOnDeletedLines); rawContentChanges.push( new textModelEvents.ModelRawLineChanged(spliceStartLineNumber, this._lines[spliceStartLineNumber - 1].text) ); @@ -638,11 +601,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito } // Split last line - let leftoverLine = this._lines[spliceLineNumber - 1].split(markersTracker, spliceColumn, op.forceMoveMarkers, tabSize); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.changeValue(spliceLineNumber - 1, this._lines[spliceLineNumber - 1].text.length + this._EOL.length); - } + let leftoverLine = this._lines[spliceLineNumber - 1].split(spliceColumn); + this._lineStarts.changeValue(spliceLineNumber - 1, this._lines[spliceLineNumber - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLineChanged(spliceLineNumber, this._lines[spliceLineNumber - 1].text) ); @@ -653,50 +613,37 @@ export class EditableTextModel extends TextModelWithDecorations implements edito let newLinesContent: string[] = []; let newLinesLengths = new Uint32Array(insertingLinesCnt - editingLinesCnt); for (let j = editingLinesCnt + 1; j <= insertingLinesCnt; j++) { - newLines.push(this._createModelLine(op.lines[j], tabSize)); + newLines.push(this._createModelLine(op.lines[j])); newLinesContent.push(op.lines[j]); newLinesLengths[j - editingLinesCnt - 1] = op.lines[j].length + this._EOL.length; } this._lines = arrays.arrayInsert(this._lines, startLineNumber + editingLinesCnt, newLines); newLinesContent[newLinesContent.length - 1] += leftoverLine.text; - if (this._lineStarts) { - // update prefix sum - this._lineStarts.insertValues(startLineNumber + editingLinesCnt, newLinesLengths); - } + this._lineStarts.insertValues(startLineNumber + editingLinesCnt, newLinesLengths); // Last line - this._lines[startLineNumber + insertingLinesCnt - 1].append(markersTracker, startLineNumber + insertingLinesCnt, leftoverLine, tabSize); - if (this._lineStarts) { - // update prefix sum - this._lineStarts.changeValue(startLineNumber + insertingLinesCnt - 1, this._lines[startLineNumber + insertingLinesCnt - 1].text.length + this._EOL.length); - } + this._lines[startLineNumber + insertingLinesCnt - 1].append(leftoverLine); + this._lineStarts.changeValue(startLineNumber + insertingLinesCnt - 1, this._lines[startLineNumber + insertingLinesCnt - 1].text.length + this._EOL.length); rawContentChanges.push( new textModelEvents.ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLinesContent.join('\n')) ); } + const text = (op.lines ? op.lines.join(this.getEOL()) : ''); contentChanges.push({ range: new Range(startLineNumber, startColumn, endLineNumber, endColumn), rangeLength: op.rangeLength, - text: op.lines ? op.lines.join(this.getEOL()) : '' + text: text }); + this._adjustDecorationsForEdit(op.rangeOffset, op.rangeLength, text.length, op.forceMoveMarkers); + // console.log('AFTER:'); // console.log('<<<\n' + this._lines.map(l => l.text).join('\n') + '\n>>>'); } flushLineEdits(); - maxTouchedLineNumber = Math.max(1, Math.min(this.getLineCount(), maxTouchedLineNumber + totalLinesCountDelta)); - if (totalLinesCountDelta !== 0) { - // must update line numbers all the way to the bottom - maxTouchedLineNumber = this.getLineCount(); - } - - for (let lineNumber = minTouchedLineNumber; lineNumber <= maxTouchedLineNumber; lineNumber++) { - this._lines[lineNumber - 1].updateLineNumber(markersTracker, lineNumber); - } - if (rawContentChanges.length !== 0 || contentChanges.length !== 0) { this._increaseVersionId(); @@ -718,35 +665,9 @@ export class EditableTextModel extends TextModelWithDecorations implements edito this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelContentChanged, e); } - // this._assertLineNumbersOK(); this._resetIndentRanges(); } - public _assertLineNumbersOK(): void { - let foundMarkersCnt = 0; - for (let i = 0, len = this._lines.length; i < len; i++) { - let line = this._lines[i]; - let lineNumber = i + 1; - - let markers = line.getMarkers(); - if (markers !== null) { - for (let j = 0, lenJ = markers.length; j < lenJ; j++) { - foundMarkersCnt++; - let markerId = markers[j].id; - let marker = this._markerIdToMarker[markerId]; - if (marker.position.lineNumber !== lineNumber) { - throw new Error('Misplaced marker with id ' + markerId); - } - } - } - } - - let totalMarkersCnt = Object.keys(this._markerIdToMarker).length; - if (totalMarkersCnt !== foundMarkersCnt) { - throw new Error('There are misplaced markers!'); - } - } - private _undo(): Selection[] { this._isUndoing = true; let r = this._commandManager.undo(); @@ -764,10 +685,10 @@ export class EditableTextModel extends TextModelWithDecorations implements edito public undo(): Selection[] { try { this._eventEmitter.beginDeferredEmit(); - this._acquireMarkersTracker(); + this._acquireDecorationsTracker(); return this._undo(); } finally { - this._releaseMarkersTracker(); + this._releaseDecorationsTracker(); this._eventEmitter.endDeferredEmit(); } } @@ -789,10 +710,10 @@ export class EditableTextModel extends TextModelWithDecorations implements edito public redo(): Selection[] { try { this._eventEmitter.beginDeferredEmit(); - this._acquireMarkersTracker(); + this._acquireDecorationsTracker(); return this._redo(); } finally { - this._releaseMarkersTracker(); + this._releaseDecorationsTracker(); this._eventEmitter.endDeferredEmit(); } } diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index f220df0cfba..a3fdce186ba 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -6,44 +6,243 @@ 'use strict'; import { ITextModel } from 'vs/editor/common/editorCommon'; +import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration'; +import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; -export class IndentRange { - _indentRangeBrand: void; - startLineNumber: number; - endLineNumber: number; - indent: number; +export const MAX_FOLDING_REGIONS = 0xFFFF; - constructor(startLineNumber: number, endLineNumber: number, indent: number) { - this.startLineNumber = startLineNumber; - this.endLineNumber = endLineNumber; - this.indent = indent; +const MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000; +const MASK_LINE_NUMBER = 0xFFFFFF; +const MASK_INDENT = 0xFF000000; + +export class IndentRanges { + private _startIndexes: Uint32Array; + private _endIndexes: Uint32Array; + private _model: ITextModel; + + constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, model: ITextModel) { + if (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) { + throw new Error('invalid startIndexes or endIndexes size'); + } + this._startIndexes = startIndexes; + this._endIndexes = endIndexes; + this._model = model; + this._computeParentIndices(); } - public static deepCloneArr(indentRanges: IndentRange[]): IndentRange[] { - let result: IndentRange[] = []; - for (let i = 0, len = indentRanges.length; i < len; i++) { - let r = indentRanges[i]; - result[i] = new IndentRange(r.startLineNumber, r.endLineNumber, r.indent); + private _computeParentIndices() { + let parentIndexes = []; + let isInsideLast = (startLineNumber: number, endLineNumber: number) => { + let index = parentIndexes[parentIndexes.length - 1]; + return this.getStartLineNumber(index) <= startLineNumber && this.getEndLineNumber(index) >= endLineNumber; + }; + for (let i = 0, len = this._startIndexes.length; i < len; i++) { + let startLineNumber = this._startIndexes[i]; + let endLineNumber = this._endIndexes[i]; + if (startLineNumber > MASK_LINE_NUMBER || endLineNumber > MASK_LINE_NUMBER) { + throw new Error('startLineNumber or endLineNumber must not exceed ' + MASK_LINE_NUMBER); + } + while (parentIndexes.length > 0 && !isInsideLast(startLineNumber, endLineNumber)) { + parentIndexes.pop(); + } + let parentIndex = parentIndexes.length > 0 ? parentIndexes[parentIndexes.length - 1] : -1; + parentIndexes.push(i); + this._startIndexes[i] = startLineNumber + ((parentIndex & 0xFF) << 24); + this._endIndexes[i] = endLineNumber + ((parentIndex & 0xFF00) << 16); } - return result; + } + + public get length(): number { + return this._startIndexes.length; + } + + public getStartLineNumber(index: number): number { + return this._startIndexes[index] & MASK_LINE_NUMBER; + } + + public getEndLineNumber(index: number): number { + return this._endIndexes[index] & MASK_LINE_NUMBER; + } + + public getParentIndex(index: number) { + let parent = ((this._startIndexes[index] & MASK_INDENT) >>> 24) + ((this._endIndexes[index] & MASK_INDENT) >>> 16); + if (parent === MAX_FOLDING_REGIONS) { + return -1; + } + return parent; + } + + public getIndent(index: number) { + const lineNumber = this.getStartLineNumber(index); + const tabSize = this._model.getOptions().tabSize; + const lineContent = this._model.getLineContent(lineNumber); + return computeIndentLevel(lineContent, tabSize); + } + + public contains(index: number, line: number) { + return this.getStartLineNumber(index) <= line && this.getEndLineNumber(index) >= line; + } + + private findIndex(line: number) { + let low = 0, high = this._startIndexes.length; + if (high === 0) { + return -1; // no children + } + while (low < high) { + let mid = Math.floor((low + high) / 2); + if (line < this.getStartLineNumber(mid)) { + high = mid; + } else { + low = mid + 1; + } + } + return low - 1; + } + + + public findRange(line: number): number { + let index = this.findIndex(line); + if (index >= 0) { + let endLineNumber = this.getEndLineNumber(index); + if (endLineNumber >= line) { + return index; + } + index = this.getParentIndex(index); + while (index !== -1) { + if (this.contains(index, line)) { + return index; + } + index = this.getParentIndex(index); + } + } + return -1; + } +} +// public only for testing +export class RangesCollector { + private _startIndexes: number[]; + private _endIndexes: number[]; + private _indentOccurrences: number[]; + private _length: number; + private _foldingRegionsLimit: number; + + constructor(foldingRegionsLimit: number) { + this._startIndexes = []; + this._endIndexes = []; + this._indentOccurrences = []; + this._length = 0; + this._foldingRegionsLimit = foldingRegionsLimit; + } + + public insertFirst(startLineNumber: number, endLineNumber: number, indent: number) { + if (startLineNumber > MASK_LINE_NUMBER || endLineNumber > MASK_LINE_NUMBER) { + return; + } + let index = this._length; + this._startIndexes[index] = startLineNumber; + this._endIndexes[index] = endLineNumber; + this._length++; + if (indent < 1000) { + this._indentOccurrences[indent] = (this._indentOccurrences[indent] || 0) + 1; + } + } + + public toIndentRanges(model: ITextModel) { + if (this._length <= this._foldingRegionsLimit) { + // reverse and create arrays of the exact length + let startIndexes = new Uint32Array(this._length); + let endIndexes = new Uint32Array(this._length); + for (let i = this._length - 1, k = 0; i >= 0; i-- , k++) { + startIndexes[k] = this._startIndexes[i]; + endIndexes[k] = this._endIndexes[i]; + } + return new IndentRanges(startIndexes, endIndexes, model); + } else { + let entries = 0; + let maxIndent = this._indentOccurrences.length; + for (let i = 0; i < this._indentOccurrences.length; i++) { + let n = this._indentOccurrences[i]; + if (n) { + if (n + entries > this._foldingRegionsLimit) { + maxIndent = i; + break; + } + entries += n; + } + } + const tabSize = model.getOptions().tabSize; + // reverse and create arrays of the exact length + let startIndexes = new Uint32Array(entries); + let endIndexes = new Uint32Array(entries); + for (let i = this._length - 1, k = 0; i >= 0; i--) { + let startIndex = this._startIndexes[i]; + let lineContent = model.getLineContent(startIndex); + let indent = computeIndentLevel(lineContent, tabSize); + if (indent < maxIndent) { + startIndexes[k] = startIndex; + endIndexes[k] = this._endIndexes[i]; + k++; + } + } + return new IndentRanges(startIndexes, endIndexes, model); + } + } } -export function computeRanges(model: ITextModel, minimumRangeSize: number = 1): IndentRange[] { - let result: IndentRange[] = []; +interface PreviousRegion { indent: number; line: number; marker: boolean; } - let previousRegions: { indent: number, line: number }[] = []; - previousRegions.push({ indent: -1, line: model.getLineCount() + 1 }); // sentinel, to make sure there's at least one entry +export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, foldingRegionsLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT): IndentRanges { + const tabSize = model.getOptions().tabSize; + let result = new RangesCollector(foldingRegionsLimit); + + let pattern = void 0; + if (markers) { + pattern = new RegExp(`(${markers.start.source})|(?:${markers.end.source})`); + } + + let previousRegions: PreviousRegion[] = []; + previousRegions.push({ indent: -1, line: model.getLineCount() + 1, marker: false }); // sentinel, to make sure there's at least one entry for (let line = model.getLineCount(); line > 0; line--) { - let indent = model.getIndentLevel(line); + let lineContent = model.getLineContent(line); + let indent = computeIndentLevel(lineContent, tabSize); + let previous = previousRegions[previousRegions.length - 1]; if (indent === -1) { + if (offSide && !previous.marker) { + // for offSide languages, empty lines are associated to the next block + previous.line = line; + } continue; // only whitespace } + let m; + if (pattern && (m = lineContent.match(pattern))) { + // folding pattern match + if (m[1]) { // start pattern match + // discard all regions until the folding pattern + let i = previousRegions.length - 1; + while (i > 0 && !previousRegions[i].marker) { + i--; + } + if (i > 0) { + previousRegions.length = i + 1; + previous = previousRegions[i]; - let previous = previousRegions[previousRegions.length - 1]; - + // new folding range from pattern, includes the end line + result.insertFirst(line, previous.line, indent); + previous.marker = false; + previous.indent = indent; + previous.line = line; + continue; + } else { + // no end marker found, treat line as a regular line + } + } else { // end pattern match + previousRegions.push({ indent: -2, line, marker: true }); + continue; + } + } if (previous.indent > indent) { // discard all regions with larger indent do { @@ -53,17 +252,16 @@ export function computeRanges(model: ITextModel, minimumRangeSize: number = 1): // new folding range let endLineNumber = previous.line - 1; - if (endLineNumber - line >= minimumRangeSize) { - result.push(new IndentRange(line, endLineNumber, indent)); + if (endLineNumber - line >= 1) { // needs at east size 1 + result.insertFirst(line, endLineNumber, indent); } } if (previous.indent === indent) { previous.line = line; } else { // previous.indent < indent // new region with a bigger indent - previousRegions.push({ indent, line }); + previousRegions.push({ indent, line, marker: false }); } } - - return result.reverse(); + return result.toIndentRanges(model); } diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts new file mode 100644 index 00000000000..7fa9b78ce63 --- /dev/null +++ b/src/vs/editor/common/model/intervalTree.ts @@ -0,0 +1,1369 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { Range } from 'vs/editor/common/core/range'; +import { IModelDecoration } from 'vs/editor/common/editorCommon'; + +// +// The red-black tree is based on the "Introduction to Algorithms" by Cormen, Leiserson and Rivest. +// + +export const ClassName = { + EditorInfoDecoration: 'infosquiggly', + EditorWarningDecoration: 'warningsquiggly', + EditorErrorDecoration: 'errorsquiggly' +}; + +/** + * Describes the behavior of decorations when typing/editing near their edges. + * Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior` + */ +export const enum TrackedRangeStickiness { + AlwaysGrowsWhenTypingAtEdges = 0, + NeverGrowsWhenTypingAtEdges = 1, + GrowsOnlyWhenTypingBefore = 2, + GrowsOnlyWhenTypingAfter = 3, +} + +const enum NodeColor { + Black = 0, + Red = 1, +} + +const enum Constants { + ColorMask = 0b00000001, + ColorMaskInverse = 0b11111110, + ColorOffset = 0, + + IsVisitedMask = 0b00000010, + IsVisitedMaskInverse = 0b11111101, + IsVisitedOffset = 1, + + IsForValidationMask = 0b00000100, + IsForValidationMaskInverse = 0b11111011, + IsForValidationOffset = 2, + + IsInOverviewRulerMask = 0b00001000, + IsInOverviewRulerMaskInverse = 0b11110111, + IsInOverviewRulerOffset = 3, + + StickinessMask = 0b00110000, + StickinessMaskInverse = 0b11001111, + StickinessOffset = 4, + + /** + * Due to how deletion works (in order to avoid always walking the right subtree of the deleted node), + * the deltas for nodes can grow and shrink dramatically. It has been observed, in practice, that unless + * the deltas are corrected, integer overflow will occur. + * + * The integer overflow occurs when 53 bits are used in the numbers, but we will try to avoid it as + * a node's delta gets below a negative 30 bits number. + * + * MIN SMI (SMall Integer) as defined in v8. + * one bit is lost for boxing/unboxing flag. + * one bit is lost for sign flag. + * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values + */ + MIN_SAFE_DELTA = -(1 << 30), + /** + * MAX SMI (SMall Integer) as defined in v8. + * one bit is lost for boxing/unboxing flag. + * one bit is lost for sign flag. + * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values + */ + MAX_SAFE_DELTA = 1 << 30, +} + +function getNodeColor(node: IntervalNode): NodeColor { + return ((node.metadata & Constants.ColorMask) >>> Constants.ColorOffset); +} +function setNodeColor(node: IntervalNode, color: NodeColor): void { + node.metadata = ( + (node.metadata & Constants.ColorMaskInverse) | (color << Constants.ColorOffset) + ); +} +function getNodeIsVisited(node: IntervalNode): boolean { + return ((node.metadata & Constants.IsVisitedMask) >>> Constants.IsVisitedOffset) === 1; +} +function setNodeIsVisited(node: IntervalNode, value: boolean): void { + node.metadata = ( + (node.metadata & Constants.IsVisitedMaskInverse) | ((value ? 1 : 0) << Constants.IsVisitedOffset) + ); +} +function getNodeIsForValidation(node: IntervalNode): boolean { + return ((node.metadata & Constants.IsForValidationMask) >>> Constants.IsForValidationOffset) === 1; +} +function setNodeIsForValidation(node: IntervalNode, value: boolean): void { + node.metadata = ( + (node.metadata & Constants.IsForValidationMaskInverse) | ((value ? 1 : 0) << Constants.IsForValidationOffset) + ); +} +export function getNodeIsInOverviewRuler(node: IntervalNode): boolean { + return ((node.metadata & Constants.IsInOverviewRulerMask) >>> Constants.IsInOverviewRulerOffset) === 1; +} +function setNodeIsInOverviewRuler(node: IntervalNode, value: boolean): void { + node.metadata = ( + (node.metadata & Constants.IsInOverviewRulerMaskInverse) | ((value ? 1 : 0) << Constants.IsInOverviewRulerOffset) + ); +} +function getNodeStickiness(node: IntervalNode): TrackedRangeStickiness { + return ((node.metadata & Constants.StickinessMask) >>> Constants.StickinessOffset); +} +function setNodeStickiness(node: IntervalNode, stickiness: TrackedRangeStickiness): void { + node.metadata = ( + (node.metadata & Constants.StickinessMaskInverse) | (stickiness << Constants.StickinessOffset) + ); +} + +export class IntervalNode implements IModelDecoration { + + /** + * contains binary encoded information for color, visited, isForValidation and stickiness. + */ + public metadata: number; + + public parent: IntervalNode; + public left: IntervalNode; + public right: IntervalNode; + + public start: number; + public end: number; + public delta: number; + public maxEnd: number; + + public id: string; + public ownerId: number; + public options: ModelDecorationOptions; + + public cachedVersionId: number; + public cachedAbsoluteStart: number; + public cachedAbsoluteEnd: number; + public range: Range; + + constructor(id: string, start: number, end: number) { + this.metadata = 0; + + this.parent = null; + this.left = null; + this.right = null; + setNodeColor(this, NodeColor.Red); + + this.start = start; + this.end = end; + // FORCE_OVERFLOWING_TEST: this.delta = start; + this.delta = 0; + this.maxEnd = end; + + this.id = id; + this.ownerId = 0; + this.options = null; + setNodeIsForValidation(this, false); + setNodeStickiness(this, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges); + setNodeIsInOverviewRuler(this, false); + + this.cachedVersionId = 0; + this.cachedAbsoluteStart = start; + this.cachedAbsoluteEnd = end; + this.range = null; + + setNodeIsVisited(this, false); + } + + public reset(versionId: number, start: number, end: number, range: Range): void { + this.start = start; + this.end = end; + this.maxEnd = end; + this.cachedVersionId = versionId; + this.cachedAbsoluteStart = start; + this.cachedAbsoluteEnd = end; + this.range = range; + } + + public setOptions(options: ModelDecorationOptions) { + this.options = options; + setNodeIsForValidation(this, ( + this.options.className === ClassName.EditorErrorDecoration + || this.options.className === ClassName.EditorWarningDecoration + )); + setNodeStickiness(this, this.options.stickiness); + setNodeIsInOverviewRuler(this, this.options.overviewRuler.color ? true : false); + } + + public setCachedOffsets(absoluteStart: number, absoluteEnd: number, cachedVersionId: number): void { + if (this.cachedVersionId !== cachedVersionId) { + this.range = null; + } + this.cachedVersionId = cachedVersionId; + this.cachedAbsoluteStart = absoluteStart; + this.cachedAbsoluteEnd = absoluteEnd; + } + + public detach(): void { + this.parent = null; + this.left = null; + this.right = null; + } +} + +const SENTINEL: IntervalNode = new IntervalNode(null, 0, 0); +SENTINEL.parent = SENTINEL; +SENTINEL.left = SENTINEL; +SENTINEL.right = SENTINEL; +setNodeColor(SENTINEL, NodeColor.Black); + +export class IntervalTree { + + public root: IntervalNode; + public requestNormalizeDelta: boolean; + + constructor() { + this.root = SENTINEL; + this.requestNormalizeDelta = false; + } + + public intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] { + if (this.root === SENTINEL) { + return []; + } + return intervalSearch(this, start, end, filterOwnerId, filterOutValidation, cachedVersionId); + } + + public search(filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] { + if (this.root === SENTINEL) { + return []; + } + return search(this, filterOwnerId, filterOutValidation, cachedVersionId); + } + + public count(): number { + if (this.root === SENTINEL) { + return 0; + } + return nodeCount(this); + } + + /** + * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes! + */ + public collectNodesFromOwner(ownerId: number): IntervalNode[] { + return collectNodesFromOwner(this, ownerId); + } + + /** + * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes! + */ + public collectNodesPostOrder(): IntervalNode[] { + return collectNodesPostOrder(this); + } + + public insert(node: IntervalNode): void { + rbTreeInsert(this, node); + this._normalizeDeltaIfNecessary(); + } + + public delete(node: IntervalNode): void { + rbTreeDelete(this, node); + this._normalizeDeltaIfNecessary(); + } + + public resolveNode(node: IntervalNode, cachedVersionId: number): void { + const initialNode = node; + let delta = 0; + while (node !== this.root) { + if (node === node.parent.right) { + delta += node.parent.delta; + } + node = node.parent; + } + + const nodeStart = initialNode.start + delta; + const nodeEnd = initialNode.end + delta; + initialNode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId); + } + + public acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void { + // Our strategy is to remove all directly impacted nodes, and then add them back to the tree. + + // (1) collect all nodes that are intersecting this edit as nodes of interest + const nodesOfInterest = searchForEditing(this, offset, offset + length); + + // (2) remove all nodes that are intersecting this edit + for (let i = 0, len = nodesOfInterest.length; i < len; i++) { + const node = nodesOfInterest[i]; + rbTreeDelete(this, node); + } + this._normalizeDeltaIfNecessary(); + + // (3) edit all tree nodes except the nodes of interest + noOverlapReplace(this, offset, offset + length, textLength); + this._normalizeDeltaIfNecessary(); + + // (4) edit the nodes of interest and insert them back in the tree + for (let i = 0, len = nodesOfInterest.length; i < len; i++) { + const node = nodesOfInterest[i]; + node.start = node.cachedAbsoluteStart; + node.end = node.cachedAbsoluteEnd; + nodeAcceptEdit(node, offset, (offset + length), textLength, forceMoveMarkers); + node.maxEnd = node.end; + rbTreeInsert(this, node); + } + this._normalizeDeltaIfNecessary(); + } + + public assertInvariants(): void { + assert(getNodeColor(SENTINEL) === NodeColor.Black); + assert(SENTINEL.parent === SENTINEL); + assert(SENTINEL.left === SENTINEL); + assert(SENTINEL.right === SENTINEL); + assert(SENTINEL.start === 0); + assert(SENTINEL.end === 0); + assert(SENTINEL.delta === 0); + assert(this.root.parent === SENTINEL); + assertValidTree(this); + } + + public getAllInOrder(): IntervalNode[] { + return search(this, 0, false, 0); + } + + public print(): void { + if (this.root === SENTINEL) { + console.log(`~~ empty`); + return; + } + let out: string[] = []; + this._print(this.root, '', 0, out); + console.log(out.join('')); + } + + private _print(n: IntervalNode, indent: string, delta: number, out: string[]): void { + out.push(`${indent}[${getNodeColor(n) === NodeColor.Red ? 'R' : 'B'},${n.delta}, ${n.start}->${n.end}, ${n.maxEnd}] : {${delta + n.start}->${delta + n.end}}, maxEnd: ${n.maxEnd + delta}\n`); + if (n.left !== SENTINEL) { + this._print(n.left, indent + ' ', delta, out); + } else { + out.push(`${indent} NIL\n`); + } + if (n.right !== SENTINEL) { + this._print(n.right, indent + ' ', delta + n.delta, out); + } else { + out.push(`${indent} NIL\n`); + } + } + + private _normalizeDeltaIfNecessary(): void { + if (!this.requestNormalizeDelta) { + return; + } + this.requestNormalizeDelta = false; + normalizeDelta(this); + } +} + +//#region Delta Normalization +function normalizeDelta(T: IntervalTree): void { + let node = T.root; + let delta = 0; + while (node !== SENTINEL) { + + if (node.left !== SENTINEL && !getNodeIsVisited(node.left)) { + // go left + node = node.left; + continue; + } + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + delta += node.delta; + node = node.right; + continue; + } + + // handle current node + node.start = delta + node.start; + node.end = delta + node.end; + node.delta = 0; + recomputeMaxEnd(node); + + setNodeIsVisited(node, true); + + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + if (node === node.parent.right) { + delta -= node.parent.delta; + } + node = node.parent; + } + + setNodeIsVisited(T.root, false); +} +//#endregion + +//#region Editing + +const enum MarkerMoveSemantics { + MarkerDefined = 0, + ForceMove = 1, + ForceStay = 2 +} + +function adjustMarkerBeforeColumn(markerOffset: number, markerStickToPreviousCharacter: boolean, checkOffset: number, moveSemantics: MarkerMoveSemantics): boolean { + if (markerOffset < checkOffset) { + return true; + } + if (markerOffset > checkOffset) { + return false; + } + if (moveSemantics === MarkerMoveSemantics.ForceMove) { + return false; + } + if (moveSemantics === MarkerMoveSemantics.ForceStay) { + return true; + } + return markerStickToPreviousCharacter; +} + +/** + * This is a lot more complicated than strictly necessary to maintain the same behaviour + * as when decorations were implemented using two markers. + */ +function nodeAcceptEdit(node: IntervalNode, start: number, end: number, textLength: number, forceMoveMarkers: boolean): void { + const nodeStickiness = getNodeStickiness(node); + const startStickToPreviousCharacter = ( + nodeStickiness === TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges + || nodeStickiness === TrackedRangeStickiness.GrowsOnlyWhenTypingBefore + ); + const endStickToPreviousCharacter = ( + nodeStickiness === TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + || nodeStickiness === TrackedRangeStickiness.GrowsOnlyWhenTypingBefore + ); + + const deletingCnt = (end - start); + const insertingCnt = textLength; + const commonLength = Math.min(deletingCnt, insertingCnt); + + const nodeStart = node.start; + let startDone = false; + + const nodeEnd = node.end; + let endDone = false; + + { + const moveSemantics = forceMoveMarkers ? MarkerMoveSemantics.ForceMove : (deletingCnt > 0 ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined); + if (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, start, moveSemantics)) { + startDone = true; + } + if (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, start, moveSemantics)) { + endDone = true; + } + } + + if (commonLength > 0 && !forceMoveMarkers) { + const moveSemantics = (deletingCnt > insertingCnt ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined); + if (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, start + commonLength, moveSemantics)) { + startDone = true; + } + if (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, start + commonLength, moveSemantics)) { + endDone = true; + } + } + + { + const moveSemantics = forceMoveMarkers ? MarkerMoveSemantics.ForceMove : MarkerMoveSemantics.MarkerDefined; + if (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, end, moveSemantics)) { + node.start = start + insertingCnt; + startDone = true; + } + if (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, end, moveSemantics)) { + node.end = start + insertingCnt; + endDone = true; + } + } + + // Finish + const deltaColumn = (insertingCnt - deletingCnt); + if (!startDone) { + node.start = Math.max(0, nodeStart + deltaColumn); + startDone = true; + } + if (!endDone) { + node.end = Math.max(0, nodeEnd + deltaColumn); + endDone = true; + } + + if (node.start > node.end) { + node.end = node.start; + } +} + +function searchForEditing(T: IntervalTree, start: number, end: number): IntervalNode[] { + // https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree + // Now, it is known that two intervals A and B overlap only when both + // A.low <= B.high and A.high >= B.low. When searching the trees for + // nodes overlapping with a given interval, you can immediately skip: + // a) all nodes to the right of nodes whose low value is past the end of the given interval. + // b) all nodes that have their maximum 'high' value below the start of the given interval. + let node = T.root; + let delta = 0; + let nodeMaxEnd = 0; + let nodeStart = 0; + let nodeEnd = 0; + let result: IntervalNode[] = []; + let resultLen = 0; + while (node !== SENTINEL) { + if (getNodeIsVisited(node)) { + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + if (node === node.parent.right) { + delta -= node.parent.delta; + } + node = node.parent; + continue; + } + + if (!getNodeIsVisited(node.left)) { + // first time seeing this node + nodeMaxEnd = delta + node.maxEnd; + if (nodeMaxEnd < start) { + // cover case b) from above + // there is no need to search this node or its children + setNodeIsVisited(node, true); + continue; + } + + if (node.left !== SENTINEL) { + // go left + node = node.left; + continue; + } + } + + // handle current node + nodeStart = delta + node.start; + if (nodeStart > end) { + // cover case a) from above + // there is no need to search this node or its right subtree + setNodeIsVisited(node, true); + continue; + } + + nodeEnd = delta + node.end; + if (nodeEnd >= start) { + node.setCachedOffsets(nodeStart, nodeEnd, 0); + result[resultLen++] = node; + } + setNodeIsVisited(node, true); + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + delta += node.delta; + node = node.right; + continue; + } + } + + setNodeIsVisited(T.root, false); + + return result; +} + +function noOverlapReplace(T: IntervalTree, start: number, end: number, textLength: number): void { + // https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree + // Now, it is known that two intervals A and B overlap only when both + // A.low <= B.high and A.high >= B.low. When searching the trees for + // nodes overlapping with a given interval, you can immediately skip: + // a) all nodes to the right of nodes whose low value is past the end of the given interval. + // b) all nodes that have their maximum 'high' value below the start of the given interval. + let node = T.root; + let delta = 0; + let nodeMaxEnd = 0; + let nodeStart = 0; + const editDelta = (textLength - (end - start)); + while (node !== SENTINEL) { + if (getNodeIsVisited(node)) { + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + if (node === node.parent.right) { + delta -= node.parent.delta; + } + recomputeMaxEnd(node); + node = node.parent; + continue; + } + + if (!getNodeIsVisited(node.left)) { + // first time seeing this node + nodeMaxEnd = delta + node.maxEnd; + if (nodeMaxEnd < start) { + // cover case b) from above + // there is no need to search this node or its children + setNodeIsVisited(node, true); + continue; + } + + if (node.left !== SENTINEL) { + // go left + node = node.left; + continue; + } + } + + // handle current node + nodeStart = delta + node.start; + if (nodeStart > end) { + node.start += editDelta; + node.end += editDelta; + node.delta += editDelta; + if (node.delta < Constants.MIN_SAFE_DELTA || node.delta > Constants.MAX_SAFE_DELTA) { + T.requestNormalizeDelta = true; + } + // cover case a) from above + // there is no need to search this node or its right subtree + setNodeIsVisited(node, true); + continue; + } + + setNodeIsVisited(node, true); + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + delta += node.delta; + node = node.right; + continue; + } + } + + setNodeIsVisited(T.root, false); +} + +//#endregion + +//#region Searching + +function nodeCount(T: IntervalTree): number { + let node = T.root; + let count = 0; + while (node !== SENTINEL) { + if (getNodeIsVisited(node)) { + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + node = node.parent; + continue; + } + + if (node.left !== SENTINEL && !getNodeIsVisited(node.left)) { + // go left + node = node.left; + continue; + } + + // handle current node + count++; + setNodeIsVisited(node, true); + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + node = node.right; + continue; + } + } + + setNodeIsVisited(T.root, false); + + return count; +} + +function collectNodesFromOwner(T: IntervalTree, ownerId: number): IntervalNode[] { + let node = T.root; + let result: IntervalNode[] = []; + let resultLen = 0; + while (node !== SENTINEL) { + if (getNodeIsVisited(node)) { + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + node = node.parent; + continue; + } + + if (node.left !== SENTINEL && !getNodeIsVisited(node.left)) { + // go left + node = node.left; + continue; + } + + // handle current node + if (node.ownerId === ownerId) { + result[resultLen++] = node; + } + + setNodeIsVisited(node, true); + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + node = node.right; + continue; + } + } + + setNodeIsVisited(T.root, false); + + return result; +} + +function collectNodesPostOrder(T: IntervalTree): IntervalNode[] { + let node = T.root; + let result: IntervalNode[] = []; + let resultLen = 0; + while (node !== SENTINEL) { + if (getNodeIsVisited(node)) { + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + node = node.parent; + continue; + } + + if (node.left !== SENTINEL && !getNodeIsVisited(node.left)) { + // go left + node = node.left; + continue; + } + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + node = node.right; + continue; + } + + // handle current node + result[resultLen++] = node; + setNodeIsVisited(node, true); + } + + setNodeIsVisited(T.root, false); + + return result; +} + +function search(T: IntervalTree, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] { + let node = T.root; + let delta = 0; + let nodeStart = 0; + let nodeEnd = 0; + let result: IntervalNode[] = []; + let resultLen = 0; + while (node !== SENTINEL) { + if (getNodeIsVisited(node)) { + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + if (node === node.parent.right) { + delta -= node.parent.delta; + } + node = node.parent; + continue; + } + + if (node.left !== SENTINEL && !getNodeIsVisited(node.left)) { + // go left + node = node.left; + continue; + } + + // handle current node + nodeStart = delta + node.start; + nodeEnd = delta + node.end; + + node.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId); + + let include = true; + if (filterOwnerId && node.ownerId && node.ownerId !== filterOwnerId) { + include = false; + } + if (filterOutValidation && getNodeIsForValidation(node)) { + include = false; + } + if (include) { + result[resultLen++] = node; + } + + setNodeIsVisited(node, true); + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + delta += node.delta; + node = node.right; + continue; + } + } + + setNodeIsVisited(T.root, false); + + return result; +} + +function intervalSearch(T: IntervalTree, intervalStart: number, intervalEnd: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] { + // https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree + // Now, it is known that two intervals A and B overlap only when both + // A.low <= B.high and A.high >= B.low. When searching the trees for + // nodes overlapping with a given interval, you can immediately skip: + // a) all nodes to the right of nodes whose low value is past the end of the given interval. + // b) all nodes that have their maximum 'high' value below the start of the given interval. + + let node = T.root; + let delta = 0; + let nodeMaxEnd = 0; + let nodeStart = 0; + let nodeEnd = 0; + let result: IntervalNode[] = []; + let resultLen = 0; + while (node !== SENTINEL) { + if (getNodeIsVisited(node)) { + // going up from this node + setNodeIsVisited(node.left, false); + setNodeIsVisited(node.right, false); + if (node === node.parent.right) { + delta -= node.parent.delta; + } + node = node.parent; + continue; + } + + if (!getNodeIsVisited(node.left)) { + // first time seeing this node + nodeMaxEnd = delta + node.maxEnd; + if (nodeMaxEnd < intervalStart) { + // cover case b) from above + // there is no need to search this node or its children + setNodeIsVisited(node, true); + continue; + } + + if (node.left !== SENTINEL) { + // go left + node = node.left; + continue; + } + } + + // handle current node + nodeStart = delta + node.start; + if (nodeStart > intervalEnd) { + // cover case a) from above + // there is no need to search this node or its right subtree + setNodeIsVisited(node, true); + continue; + } + + nodeEnd = delta + node.end; + + if (nodeEnd >= intervalStart) { + // There is overlap + node.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId); + + let include = true; + if (filterOwnerId && node.ownerId && node.ownerId !== filterOwnerId) { + include = false; + } + if (filterOutValidation && getNodeIsForValidation(node)) { + include = false; + } + + if (include) { + result[resultLen++] = node; + } + } + + setNodeIsVisited(node, true); + + if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) { + // go right + delta += node.delta; + node = node.right; + continue; + } + } + + setNodeIsVisited(T.root, false); + + return result; +} + +//#endregion + +//#region Insertion +function rbTreeInsert(T: IntervalTree, newNode: IntervalNode): IntervalNode { + if (T.root === SENTINEL) { + newNode.parent = SENTINEL; + newNode.left = SENTINEL; + newNode.right = SENTINEL; + setNodeColor(newNode, NodeColor.Black); + T.root = newNode; + return T.root; + } + + treeInsert(T, newNode); + + recomputeMaxEndWalkToRoot(newNode.parent); + + // repair tree + let x = newNode; + while (x !== T.root && getNodeColor(x.parent) === NodeColor.Red) { + if (x.parent === x.parent.parent.left) { + const y = x.parent.parent.right; + + if (getNodeColor(y) === NodeColor.Red) { + setNodeColor(x.parent, NodeColor.Black); + setNodeColor(y, NodeColor.Black); + setNodeColor(x.parent.parent, NodeColor.Red); + x = x.parent.parent; + } else { + if (x === x.parent.right) { + x = x.parent; + leftRotate(T, x); + } + setNodeColor(x.parent, NodeColor.Black); + setNodeColor(x.parent.parent, NodeColor.Red); + rightRotate(T, x.parent.parent); + } + } else { + const y = x.parent.parent.left; + + if (getNodeColor(y) === NodeColor.Red) { + setNodeColor(x.parent, NodeColor.Black); + setNodeColor(y, NodeColor.Black); + setNodeColor(x.parent.parent, NodeColor.Red); + x = x.parent.parent; + } else { + if (x === x.parent.left) { + x = x.parent; + rightRotate(T, x); + } + setNodeColor(x.parent, NodeColor.Black); + setNodeColor(x.parent.parent, NodeColor.Red); + leftRotate(T, x.parent.parent); + } + } + } + + setNodeColor(T.root, NodeColor.Black); + + return newNode; +} + +function treeInsert(T: IntervalTree, z: IntervalNode): void { + let delta: number = 0; + let x = T.root; + const zAbsoluteStart = z.start; + const zAbsoluteEnd = z.end; + while (true) { + const cmp = intervalCompare(zAbsoluteStart, zAbsoluteEnd, x.start + delta, x.end + delta); + if (cmp < 0) { + // this node should be inserted to the left + // => it is not affected by the node's delta + if (x.left === SENTINEL) { + z.start -= delta; + z.end -= delta; + z.maxEnd -= delta; + x.left = z; + break; + } else { + x = x.left; + } + } else { + // this node should be inserted to the right + // => it is not affected by the node's delta + if (x.right === SENTINEL) { + z.start -= (delta + x.delta); + z.end -= (delta + x.delta); + z.maxEnd -= (delta + x.delta); + x.right = z; + break; + } else { + delta += x.delta; + x = x.right; + } + } + } + + z.parent = x; + z.left = SENTINEL; + z.right = SENTINEL; + setNodeColor(z, NodeColor.Red); +} +//#endregion + +//#region Deletion +function rbTreeDelete(T: IntervalTree, z: IntervalNode): void { + + let x: IntervalNode; + let y: IntervalNode; + + // RB-DELETE except we don't swap z and y in case c) + // i.e. we always delete what's pointed at by z. + + if (z.left === SENTINEL) { + x = z.right; + y = z; + + // x's delta is no longer influenced by z's delta + x.delta += z.delta; + if (x.delta < Constants.MIN_SAFE_DELTA || x.delta > Constants.MAX_SAFE_DELTA) { + T.requestNormalizeDelta = true; + } + x.start += z.delta; + x.end += z.delta; + + } else if (z.right === SENTINEL) { + x = z.left; + y = z; + + } else { + y = leftest(z.right); + x = y.right; + + // y's delta is no longer influenced by z's delta, + // but we don't want to walk the entire right-hand-side subtree of x. + // we therefore maintain z's delta in y, and adjust only x + x.start += y.delta; + x.end += y.delta; + x.delta += y.delta; + if (x.delta < Constants.MIN_SAFE_DELTA || x.delta > Constants.MAX_SAFE_DELTA) { + T.requestNormalizeDelta = true; + } + + y.start += z.delta; + y.end += z.delta; + y.delta = z.delta; + if (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) { + T.requestNormalizeDelta = true; + } + } + + if (y === T.root) { + T.root = x; + setNodeColor(x, NodeColor.Black); + + z.detach(); + resetSentinel(); + recomputeMaxEnd(x); + T.root.parent = SENTINEL; + return; + } + + let yWasRed = (getNodeColor(y) === NodeColor.Red); + + if (y === y.parent.left) { + y.parent.left = x; + } else { + y.parent.right = x; + } + + if (y === z) { + x.parent = y.parent; + } else { + + if (y.parent === z) { + x.parent = y; + } else { + x.parent = y.parent; + } + + y.left = z.left; + y.right = z.right; + y.parent = z.parent; + setNodeColor(y, getNodeColor(z)); + + if (z === T.root) { + T.root = y; + } else { + if (z === z.parent.left) { + z.parent.left = y; + } else { + z.parent.right = y; + } + } + + if (y.left !== SENTINEL) { + y.left.parent = y; + } + if (y.right !== SENTINEL) { + y.right.parent = y; + } + } + + z.detach(); + + if (yWasRed) { + recomputeMaxEndWalkToRoot(x.parent); + if (y !== z) { + recomputeMaxEndWalkToRoot(y); + recomputeMaxEndWalkToRoot(y.parent); + } + resetSentinel(); + return; + } + + recomputeMaxEndWalkToRoot(x); + recomputeMaxEndWalkToRoot(x.parent); + if (y !== z) { + recomputeMaxEndWalkToRoot(y); + recomputeMaxEndWalkToRoot(y.parent); + } + + // RB-DELETE-FIXUP + let w: IntervalNode; + while (x !== T.root && getNodeColor(x) === NodeColor.Black) { + + if (x === x.parent.left) { + w = x.parent.right; + + if (getNodeColor(w) === NodeColor.Red) { + setNodeColor(w, NodeColor.Black); + setNodeColor(x.parent, NodeColor.Red); + leftRotate(T, x.parent); + w = x.parent.right; + } + + if (getNodeColor(w.left) === NodeColor.Black && getNodeColor(w.right) === NodeColor.Black) { + setNodeColor(w, NodeColor.Red); + x = x.parent; + } else { + if (getNodeColor(w.right) === NodeColor.Black) { + setNodeColor(w.left, NodeColor.Black); + setNodeColor(w, NodeColor.Red); + rightRotate(T, w); + w = x.parent.right; + } + + setNodeColor(w, getNodeColor(x.parent)); + setNodeColor(x.parent, NodeColor.Black); + setNodeColor(w.right, NodeColor.Black); + leftRotate(T, x.parent); + x = T.root; + } + + } else { + w = x.parent.left; + + if (getNodeColor(w) === NodeColor.Red) { + setNodeColor(w, NodeColor.Black); + setNodeColor(x.parent, NodeColor.Red); + rightRotate(T, x.parent); + w = x.parent.left; + } + + if (getNodeColor(w.left) === NodeColor.Black && getNodeColor(w.right) === NodeColor.Black) { + setNodeColor(w, NodeColor.Red); + x = x.parent; + + } else { + if (getNodeColor(w.left) === NodeColor.Black) { + setNodeColor(w.right, NodeColor.Black); + setNodeColor(w, NodeColor.Red); + leftRotate(T, w); + w = x.parent.left; + } + + setNodeColor(w, getNodeColor(x.parent)); + setNodeColor(x.parent, NodeColor.Black); + setNodeColor(w.left, NodeColor.Black); + rightRotate(T, x.parent); + x = T.root; + } + } + } + + setNodeColor(x, NodeColor.Black); + resetSentinel(); +} + +function leftest(node: IntervalNode): IntervalNode { + while (node.left !== SENTINEL) { + node = node.left; + } + return node; +} + +function resetSentinel(): void { + SENTINEL.parent = SENTINEL; + SENTINEL.delta = 0; // optional + SENTINEL.start = 0; // optional + SENTINEL.end = 0; // optional +} +//#endregion + +//#region Rotations +function leftRotate(T: IntervalTree, x: IntervalNode): void { + const y = x.right; // set y. + + y.delta += x.delta; // y's delta is no longer influenced by x's delta + if (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) { + T.requestNormalizeDelta = true; + } + y.start += x.delta; + y.end += x.delta; + + x.right = y.left; // turn y's left subtree into x's right subtree. + if (y.left !== SENTINEL) { + y.left.parent = x; + } + y.parent = x.parent; // link x's parent to y. + if (x.parent === SENTINEL) { + T.root = y; + } else if (x === x.parent.left) { + x.parent.left = y; + } else { + x.parent.right = y; + } + + y.left = x; // put x on y's left. + x.parent = y; + + recomputeMaxEnd(x); + recomputeMaxEnd(y); +} + +function rightRotate(T: IntervalTree, y: IntervalNode): void { + const x = y.left; + + y.delta -= x.delta; + if (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) { + T.requestNormalizeDelta = true; + } + y.start -= x.delta; + y.end -= x.delta; + + y.left = x.right; + if (x.right !== SENTINEL) { + x.right.parent = y; + } + x.parent = y.parent; + if (y.parent === SENTINEL) { + T.root = x; + } else if (y === y.parent.right) { + y.parent.right = x; + } else { + y.parent.left = x; + } + + x.right = y; + y.parent = x; + + recomputeMaxEnd(y); + recomputeMaxEnd(x); +} +//#endregion + +//#region max end computation + +function computeMaxEnd(node: IntervalNode): number { + let maxEnd = node.end; + if (node.left !== SENTINEL) { + const leftMaxEnd = node.left.maxEnd; + if (leftMaxEnd > maxEnd) { + maxEnd = leftMaxEnd; + } + } + if (node.right !== SENTINEL) { + const rightMaxEnd = node.right.maxEnd + node.delta; + if (rightMaxEnd > maxEnd) { + maxEnd = rightMaxEnd; + } + } + return maxEnd; +} + +export function recomputeMaxEnd(node: IntervalNode): void { + node.maxEnd = computeMaxEnd(node); +} + +function recomputeMaxEndWalkToRoot(node: IntervalNode): void { + while (node !== SENTINEL) { + + const maxEnd = computeMaxEnd(node); + + if (node.maxEnd === maxEnd) { + // no need to go further + return; + } + + node.maxEnd = maxEnd; + node = node.parent; + } +} + +//#endregion + +//#region utils +function intervalCompare(aStart: number, aEnd: number, bStart: number, bEnd: number): number { + if (aStart === bStart) { + return aEnd - bEnd; + } + return aStart - bStart; +} +//#endregion + +//#region Assertion + +function depth(n: IntervalNode): number { + if (n === SENTINEL) { + // The leafs are black + return 1; + } + assert(depth(n.left) === depth(n.right)); + return (getNodeColor(n) === NodeColor.Black ? 1 : 0) + depth(n.left); +} + +function assertValidNode(n: IntervalNode, delta): void { + if (n === SENTINEL) { + return; + } + + let l = n.left; + let r = n.right; + + if (getNodeColor(n) === NodeColor.Red) { + assert(getNodeColor(l) === NodeColor.Black); + assert(getNodeColor(r) === NodeColor.Black); + } + + let expectedMaxEnd = n.end; + if (l !== SENTINEL) { + assert(intervalCompare(l.start + delta, l.end + delta, n.start + delta, n.end + delta) <= 0); + expectedMaxEnd = Math.max(expectedMaxEnd, l.maxEnd); + } + if (r !== SENTINEL) { + assert(intervalCompare(n.start + delta, n.end + delta, r.start + delta + n.delta, r.end + delta + n.delta) <= 0); + expectedMaxEnd = Math.max(expectedMaxEnd, r.maxEnd + n.delta); + } + assert(n.maxEnd === expectedMaxEnd); + + assertValidNode(l, delta); + assertValidNode(r, delta + n.delta); +} + +function assertValidTree(tree: IntervalTree): void { + if (tree.root === SENTINEL) { + return; + } + assert(getNodeColor(tree.root) === NodeColor.Black); + assert(depth(tree.root.left) === depth(tree.root.right)); + assertValidNode(tree.root, 0); +} + +function assert(condition: boolean): void { + if (!condition) { + throw new Error('Assertion violation'); + } +} + +//#endregion diff --git a/src/vs/editor/common/model/model.ts b/src/vs/editor/common/model/model.ts index aef76d48016..2e1410fc830 100644 --- a/src/vs/editor/common/model/model.ts +++ b/src/vs/editor/common/model/model.ts @@ -16,7 +16,7 @@ import { IRawTextSource, RawTextSource } from 'vs/editor/common/model/textSource import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; // The hierarchy is: -// Model -> EditableTextModel -> TextModelWithDecorations -> TextModelWithTrackedRanges -> TextModelWithMarkers -> TextModelWithTokens -> TextModel +// Model -> EditableTextModel -> TextModelWithDecorations -> TextModelWithTokens -> TextModel var MODEL_ID = 0; @@ -34,7 +34,9 @@ export class Model extends EditableTextModel implements IModel { public onDidChangeLanguage(listener: (e: textModelEvents.IModelLanguageChangedEvent) => void): IDisposable { return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelLanguageChanged, listener); } - + public onDidChangeLanguageConfiguration(listener: (e: textModelEvents.IModelLanguageConfigurationChangedEvent) => void): IDisposable { + return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged, listener); + } public static createFromString(text: string, options: ITextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, languageIdentifier: LanguageIdentifier = null, uri: URI = null): Model { return new Model(RawTextSource.fromString(text), options, languageIdentifier, uri); } diff --git a/src/vs/editor/common/model/modelLine.ts b/src/vs/editor/common/model/modelLine.ts index e71219bd689..956359c82b5 100644 --- a/src/vs/editor/common/model/modelLine.ts +++ b/src/vs/editor/common/model/modelLine.ts @@ -7,94 +7,12 @@ import { IState, FontStyle, StandardTokenType, MetadataConsts, ColorId, LanguageId } from 'vs/editor/common/modes'; import { CharCode } from 'vs/base/common/charCode'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; -import { Position } from 'vs/editor/common/core/position'; import { Constants } from 'vs/editor/common/core/uint'; export interface ILineEdit { startColumn: number; endColumn: number; text: string; - forceMoveMarkers: boolean; -} - -export class LineMarker { - _lineMarkerBrand: void; - - public readonly id: string; - public readonly internalDecorationId: number; - - public stickToPreviousCharacter: boolean; - public position: Position; - - constructor(id: string, internalDecorationId: number, position: Position, stickToPreviousCharacter: boolean) { - this.id = id; - this.internalDecorationId = internalDecorationId; - this.position = position; - this.stickToPreviousCharacter = stickToPreviousCharacter; - } - - public toString(): string { - return '{\'' + this.id + '\';' + this.position.toString() + ',' + this.stickToPreviousCharacter + '}'; - } - - public updateLineNumber(markersTracker: MarkersTracker, lineNumber: number): void { - if (this.position.lineNumber === lineNumber) { - return; - } - markersTracker.addChangedMarker(this); - this.position = new Position(lineNumber, this.position.column); - } - - public updateColumn(markersTracker: MarkersTracker, column: number): void { - if (this.position.column === column) { - return; - } - markersTracker.addChangedMarker(this); - this.position = new Position(this.position.lineNumber, column); - } - - public updatePosition(markersTracker: MarkersTracker, position: Position): void { - if (this.position.lineNumber === position.lineNumber && this.position.column === position.column) { - return; - } - markersTracker.addChangedMarker(this); - this.position = position; - } - - public setPosition(position: Position) { - this.position = position; - } - - - public static compareMarkers(a: LineMarker, b: LineMarker): number { - if (a.position.column === b.position.column) { - return (a.stickToPreviousCharacter ? 0 : 1) - (b.stickToPreviousCharacter ? 0 : 1); - } - return a.position.column - b.position.column; - } -} - -export class MarkersTracker { - _changedDecorationsBrand: void; - - private _changedDecorations: number[]; - private _changedDecorationsLen: number; - - constructor() { - this._changedDecorations = []; - this._changedDecorationsLen = 0; - } - - public addChangedMarker(marker: LineMarker): void { - let internalDecorationId = marker.internalDecorationId; - if (internalDecorationId !== 0) { - this._changedDecorations[this._changedDecorationsLen++] = internalDecorationId; - } - } - - public getDecorationIds(): number[] { - return this._changedDecorations; - } } export interface ITokensAdjuster { @@ -102,34 +20,17 @@ export interface ITokensAdjuster { finish(delta: number, lineTextLength: number): void; } -interface IMarkersAdjuster { - adjustDelta(toColumn: number, delta: number, minimumAllowedColumn: number, moveSemantics: MarkerMoveSemantics): void; - adjustSet(toColumn: number, newColumn: number, moveSemantics: MarkerMoveSemantics): void; - finish(delta: number, lineTextLength: number): void; -} - var NO_OP_TOKENS_ADJUSTER: ITokensAdjuster = { adjust: () => { }, finish: () => { } }; -var NO_OP_MARKERS_ADJUSTER: IMarkersAdjuster = { - adjustDelta: () => { }, - adjustSet: () => { }, - finish: () => { } -}; - -const enum MarkerMoveSemantics { - MarkerDefined = 0, - ForceMove = 1, - ForceStay = 2 -} /** * Returns: - * - 0 => the line consists of whitespace - * - otherwise => the indent level is returned value - 1 + * - -1 => the line consists of whitespace + * - otherwise => the indent level is returned value */ -function computePlusOneIndentLevel(line: string, tabSize: number): number { +export function computeIndentLevel(line: string, tabSize: number): number { let indent = 0; let i = 0; let len = line.length; @@ -147,22 +48,15 @@ function computePlusOneIndentLevel(line: string, tabSize: number): number { } if (i === len) { - return 0; // line only consists of whitespace + return -1; // line only consists of whitespace } - return indent + 1; + return indent; } export interface IModelLine { readonly text: string; - // --- markers - addMarker(marker: LineMarker): void; - addMarkers(markers: LineMarker[]): void; - removeMarker(marker: LineMarker): void; - removeMarkers(deleteMarkers: { [markerId: string]: boolean; }): void; - getMarkers(): LineMarker[]; - // --- tokenization resetTokenizationState(): void; isInvalid(): boolean; @@ -172,151 +66,38 @@ export interface IModelLine { getTokens(topLevelLanguageId: LanguageId): LineTokens; setTokens(topLevelLanguageId: LanguageId, tokens: Uint32Array): void; - // --- indentation - updateTabSize(tabSize: number): void; - getIndentLevel(): number; - // --- editing - updateLineNumber(markersTracker: MarkersTracker, newLineNumber: number): void; - applyEdits(markersTracker: MarkersTracker, edits: ILineEdit[], tabSize: number): number; - append(markersTracker: MarkersTracker, myLineNumber: number, other: IModelLine, tabSize: number): void; - split(markersTracker: MarkersTracker, splitColumn: number, forceMoveMarkers: boolean, tabSize: number): IModelLine; + applyEdits(edits: ILineEdit[]): number; + append(other: IModelLine): void; + split(splitColumn: number): IModelLine; } export abstract class AbstractModelLine { - private _markers: LineMarker[]; - - constructor(initializeMarkers: boolean) { - if (initializeMarkers) { - this._markers = null; - } + constructor() { } /// public abstract get text(): string; - protected abstract _setText(text: string, tabSize: number): void; + protected abstract _setText(text: string): void; protected abstract _createTokensAdjuster(): ITokensAdjuster; - protected abstract _createModelLine(text: string, tabSize: number): IModelLine; + protected abstract _createModelLine(text: string): IModelLine; /// - // private _printMarkers(): string { - // if (!this._markers) { - // return '[]'; - // } - // if (this._markers.length === 0) { - // return '[]'; - // } - - // var markers = this._markers; - - // var printMarker = (m:LineMarker) => { - // if (m.stickToPreviousCharacter) { - // return '|' + m.position.column; - // } - // return m.position.column + '|'; - // }; - // return '[' + markers.map(printMarker).join(', ') + ']'; - // } - - private _createMarkersAdjuster(markersTracker: MarkersTracker): IMarkersAdjuster { - if (!this._markers) { - return NO_OP_MARKERS_ADJUSTER; - } - if (this._markers.length === 0) { - return NO_OP_MARKERS_ADJUSTER; - } - - this._markers.sort(LineMarker.compareMarkers); - - var markers = this._markers; - var markersLength = markers.length; - var markersIndex = 0; - var marker = markers[markersIndex]; - - // console.log('------------- INITIAL MARKERS: ' + this._printMarkers()); - - let adjustMarkerBeforeColumn = (toColumn: number, moveSemantics: MarkerMoveSemantics) => { - if (marker.position.column < toColumn) { - return true; - } - if (marker.position.column > toColumn) { - return false; - } - if (moveSemantics === MarkerMoveSemantics.ForceMove) { - return false; - } - if (moveSemantics === MarkerMoveSemantics.ForceStay) { - return true; - } - return marker.stickToPreviousCharacter; - }; - - let adjustDelta = (toColumn: number, delta: number, minimumAllowedColumn: number, moveSemantics: MarkerMoveSemantics) => { - // console.log('------------------------------'); - // console.log('adjustDelta called: toColumn: ' + toColumn + ', delta: ' + delta + ', minimumAllowedColumn: ' + minimumAllowedColumn + ', moveSemantics: ' + MarkerMoveSemantics[moveSemantics]); - // console.log('BEFORE::: markersIndex: ' + markersIndex + ' : ' + this._printMarkers()); - - while (markersIndex < markersLength && adjustMarkerBeforeColumn(toColumn, moveSemantics)) { - if (delta !== 0) { - let newColumn = Math.max(minimumAllowedColumn, marker.position.column + delta); - marker.updateColumn(markersTracker, newColumn); - } - - markersIndex++; - if (markersIndex < markersLength) { - marker = markers[markersIndex]; - } - } - - // console.log('AFTER::: markersIndex: ' + markersIndex + ' : ' + this._printMarkers()); - }; - - let adjustSet = (toColumn: number, newColumn: number, moveSemantics: MarkerMoveSemantics) => { - // console.log('------------------------------'); - // console.log('adjustSet called: toColumn: ' + toColumn + ', newColumn: ' + newColumn + ', moveSemantics: ' + MarkerMoveSemantics[moveSemantics]); - // console.log('BEFORE::: markersIndex: ' + markersIndex + ' : ' + this._printMarkers()); - - while (markersIndex < markersLength && adjustMarkerBeforeColumn(toColumn, moveSemantics)) { - marker.updateColumn(markersTracker, newColumn); - - markersIndex++; - if (markersIndex < markersLength) { - marker = markers[markersIndex]; - } - } - - // console.log('AFTER::: markersIndex: ' + markersIndex + ' : ' + this._printMarkers()); - }; - - let finish = (delta: number, lineTextLength: number) => { - adjustDelta(Constants.MAX_SAFE_SMALL_INTEGER, delta, 1, MarkerMoveSemantics.MarkerDefined); - - // console.log('------------- FINAL MARKERS: ' + this._printMarkers()); - }; - - return { - adjustDelta: adjustDelta, - adjustSet: adjustSet, - finish: finish - }; - } - - public applyEdits(markersTracker: MarkersTracker, edits: ILineEdit[], tabSize: number): number { + public applyEdits(edits: ILineEdit[]): number { let deltaColumn = 0; let resultText = this.text; let tokensAdjuster = this._createTokensAdjuster(); - let markersAdjuster = this._createMarkersAdjuster(markersTracker); for (let i = 0, len = edits.length; i < len; i++) { let edit = edits[i]; // console.log(); // console.log('============================='); - // console.log('EDIT #' + i + ' [ ' + edit.startColumn + ' -> ' + edit.endColumn + ' ] : <<<' + edit.text + '>>>, forceMoveMarkers: ' + edit.forceMoveMarkers); + // console.log('EDIT #' + i + ' [ ' + edit.startColumn + ' -> ' + edit.endColumn + ' ] : <<<' + edit.text + '>>>'); // console.log('deltaColumn: ' + deltaColumn); let startColumn = deltaColumn + edit.startColumn; @@ -324,193 +105,45 @@ export abstract class AbstractModelLine { let deletingCnt = endColumn - startColumn; let insertingCnt = edit.text.length; - // Adjust tokens & markers before this edit - // console.log('Adjust tokens & markers before this edit'); + // Adjust tokens before this edit + // console.log('Adjust tokens before this edit'); tokensAdjuster.adjust(edit.startColumn - 1, deltaColumn, 1); - markersAdjuster.adjustDelta(edit.startColumn, deltaColumn, 1, edit.forceMoveMarkers ? MarkerMoveSemantics.ForceMove : (deletingCnt > 0 ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined)); - // Adjust tokens & markers for the common part of this edit + // Adjust tokens for the common part of this edit let commonLength = Math.min(deletingCnt, insertingCnt); if (commonLength > 0) { - // console.log('Adjust tokens & markers for the common part of this edit'); + // console.log('Adjust tokens for the common part of this edit'); tokensAdjuster.adjust(edit.startColumn - 1 + commonLength, deltaColumn, startColumn); - - if (!edit.forceMoveMarkers) { - markersAdjuster.adjustDelta(edit.startColumn + commonLength, deltaColumn, startColumn, edit.forceMoveMarkers ? MarkerMoveSemantics.ForceMove : (deletingCnt > insertingCnt ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined)); - } } // Perform the edit & update `deltaColumn` resultText = resultText.substring(0, startColumn - 1) + edit.text + resultText.substring(endColumn - 1); deltaColumn += insertingCnt - deletingCnt; - // Adjust tokens & markers inside this edit - // console.log('Adjust tokens & markers inside this edit'); + // Adjust tokens inside this edit + // console.log('Adjust tokens inside this edit'); tokensAdjuster.adjust(edit.endColumn, deltaColumn, startColumn); - markersAdjuster.adjustSet(edit.endColumn, startColumn + insertingCnt, edit.forceMoveMarkers ? MarkerMoveSemantics.ForceMove : MarkerMoveSemantics.MarkerDefined); } - // Wrap up tokens & markers; adjust remaining if needed + // Wrap up tokens; adjust remaining if needed tokensAdjuster.finish(deltaColumn, resultText.length); - markersAdjuster.finish(deltaColumn, resultText.length); // Save the resulting text - this._setText(resultText, tabSize); + this._setText(resultText); return deltaColumn; } - public split(markersTracker: MarkersTracker, splitColumn: number, forceMoveMarkers: boolean, tabSize: number): IModelLine { - // console.log('--> split @ ' + splitColumn + '::: ' + this._printMarkers()); - var myText = this.text.substring(0, splitColumn - 1); - var otherText = this.text.substring(splitColumn - 1); + public split(splitColumn: number): IModelLine { + const myText = this.text.substring(0, splitColumn - 1); + const otherText = this.text.substring(splitColumn - 1); - var otherMarkers: LineMarker[] = null; - - if (this._markers) { - this._markers.sort(LineMarker.compareMarkers); - for (let i = 0, len = this._markers.length; i < len; i++) { - let marker = this._markers[i]; - - if ( - marker.position.column > splitColumn - || ( - marker.position.column === splitColumn - && ( - forceMoveMarkers - || !marker.stickToPreviousCharacter - ) - ) - ) { - let myMarkers = this._markers.slice(0, i); - otherMarkers = this._markers.slice(i); - this._markers = myMarkers; - break; - } - } - - if (otherMarkers) { - for (let i = 0, len = otherMarkers.length; i < len; i++) { - let marker = otherMarkers[i]; - - marker.updateColumn(markersTracker, marker.position.column - (splitColumn - 1)); - } - } - } - - this._setText(myText, tabSize); - - var otherLine = this._createModelLine(otherText, tabSize); - if (otherMarkers) { - otherLine.addMarkers(otherMarkers); - } - return otherLine; + this._setText(myText); + return this._createModelLine(otherText); } - public append(markersTracker: MarkersTracker, myLineNumber: number, other: IModelLine, tabSize: number): void { - // console.log('--> append: THIS :: ' + this._printMarkers()); - // console.log('--> append: OTHER :: ' + this._printMarkers()); - let thisTextLength = this.text.length; - this._setText(this.text + other.text, tabSize); - - if (other instanceof AbstractModelLine) { - if (other._markers) { - // Other has markers - let otherMarkers = other._markers; - - // Adjust other markers - for (let i = 0, len = otherMarkers.length; i < len; i++) { - let marker = otherMarkers[i]; - - marker.updatePosition(markersTracker, new Position(myLineNumber, marker.position.column + thisTextLength)); - } - - this.addMarkers(otherMarkers); - } - } - } - - public addMarker(marker: LineMarker): void { - if (!this._markers) { - this._markers = [marker]; - } else { - this._markers.push(marker); - } - } - - public addMarkers(markers: LineMarker[]): void { - if (markers.length === 0) { - return; - } - - if (!this._markers) { - this._markers = markers.slice(0); - } else { - this._markers = this._markers.concat(markers); - } - } - - public removeMarker(marker: LineMarker): void { - if (!this._markers) { - return; - } - - let index = this._indexOfMarkerId(marker.id); - if (index < 0) { - return; - } - - if (this._markers.length === 1) { - // was last marker on line - this._markers = null; - } else { - this._markers.splice(index, 1); - } - } - - public removeMarkers(deleteMarkers: { [markerId: string]: boolean; }): void { - if (!this._markers) { - return; - } - for (let i = 0, len = this._markers.length; i < len; i++) { - let marker = this._markers[i]; - - if (deleteMarkers[marker.id]) { - this._markers.splice(i, 1); - len--; - i--; - } - } - if (this._markers.length === 0) { - this._markers = null; - } - } - - public getMarkers(): LineMarker[] { - if (!this._markers) { - return null; - } - return this._markers; - } - - public updateLineNumber(markersTracker: MarkersTracker, newLineNumber: number): void { - if (this._markers) { - let markers = this._markers; - for (let i = 0, len = markers.length; i < len; i++) { - let marker = markers[i]; - marker.updateLineNumber(markersTracker, newLineNumber); - } - } - } - - private _indexOfMarkerId(markerId: string): number { - let markers = this._markers; - for (let i = 0, len = markers.length; i < len; i++) { - if (markers[i].id === markerId) { - return i; - } - } - return undefined; + public append(other: IModelLine): void { + this._setText(this.text + other.text); } } @@ -519,59 +152,33 @@ export class ModelLine extends AbstractModelLine implements IModelLine { private _text: string; public get text(): string { return this._text; } - /** - * bits 31 - 1 => indentLevel - * bit 0 => isInvalid - */ - private _metadata: number; + private _isInvalid: boolean; public isInvalid(): boolean { - return (this._metadata & 0x00000001) ? true : false; + return this._isInvalid; } public setIsInvalid(isInvalid: boolean): void { - this._metadata = (this._metadata & 0xfffffffe) | (isInvalid ? 1 : 0); - } - - /** - * Returns: - * - -1 => the line consists of whitespace - * - otherwise => the indent level is returned value - */ - public getIndentLevel(): number { - return ((this._metadata & 0xfffffffe) >> 1) - 1; - } - - private _setPlusOneIndentLevel(value: number): void { - this._metadata = (this._metadata & 0x00000001) | ((value & 0xefffffff) << 1); - } - - public updateTabSize(tabSize: number): void { - if (tabSize === 0) { - // don't care mark - this._metadata = this._metadata & 0x00000001; - } else { - this._setPlusOneIndentLevel(computePlusOneIndentLevel(this._text, tabSize)); - } + this._isInvalid = isInvalid; } private _state: IState; private _lineTokens: ArrayBuffer; - constructor(text: string, tabSize: number) { - super(true); - this._metadata = 0; - this._setText(text, tabSize); + constructor(text: string) { + super(); + this._isInvalid = false; + this._setText(text); this._state = null; this._lineTokens = null; } - protected _createModelLine(text: string, tabSize: number): IModelLine { - return new ModelLine(text, tabSize); + protected _createModelLine(text: string): IModelLine { + return new ModelLine(text); } - public split(markersTracker: MarkersTracker, splitColumn: number, forceMoveMarkers: boolean, tabSize: number): IModelLine { - let result = super.split(markersTracker, splitColumn, forceMoveMarkers, tabSize); + public split(splitColumn: number): IModelLine { + let result = super.split(splitColumn); // Mark overflowing tokens for deletion & delete marked tokens this._deleteMarkedTokens(this._markOverflowingTokensForDeletion(0, this.text.length)); @@ -579,10 +186,10 @@ export class ModelLine extends AbstractModelLine implements IModelLine { return result; } - public append(markersTracker: MarkersTracker, myLineNumber: number, other: IModelLine, tabSize: number): void { + public append(other: IModelLine): void { let thisTextLength = this.text.length; - super.append(markersTracker, myLineNumber, other, tabSize); + super.append(other); if (other instanceof ModelLine) { let otherRawTokens = other._lineTokens; @@ -787,20 +394,14 @@ export class ModelLine extends AbstractModelLine implements IModelLine { this._lineTokens = newTokens.buffer; } - protected _setText(text: string, tabSize: number): void { + protected _setText(text: string): void { this._text = text; - if (tabSize === 0) { - // don't care mark - this._metadata = this._metadata & 0x00000001; - } else { - this._setPlusOneIndentLevel(computePlusOneIndentLevel(text, tabSize)); - } } } /** - * A model line that cannot store any tokenization state, nor does it compute indentation levels. + * A model line that cannot store any tokenization state. * It has no fields except the text. */ export class MinimalModelLine extends AbstractModelLine implements IModelLine { @@ -815,33 +416,21 @@ export class MinimalModelLine extends AbstractModelLine implements IModelLine { public setIsInvalid(isInvalid: boolean): void { } - /** - * Returns: - * - -1 => the line consists of whitespace - * - otherwise => the indent level is returned value - */ - public getIndentLevel(): number { - return 0; + constructor(text: string) { + super(); + this._setText(text); } - public updateTabSize(tabSize: number): void { + protected _createModelLine(text: string): IModelLine { + return new MinimalModelLine(text); } - constructor(text: string, tabSize: number) { - super(false); - this._setText(text, tabSize); + public split(splitColumn: number): IModelLine { + return super.split(splitColumn); } - protected _createModelLine(text: string, tabSize: number): IModelLine { - return new MinimalModelLine(text, tabSize); - } - - public split(markersTracker: MarkersTracker, splitColumn: number, forceMoveMarkers: boolean, tabSize: number): IModelLine { - return super.split(markersTracker, splitColumn, forceMoveMarkers, tabSize); - } - - public append(markersTracker: MarkersTracker, myLineNumber: number, other: IModelLine, tabSize: number): void { - super.append(markersTracker, myLineNumber, other, tabSize); + public append(other: IModelLine): void { + super.append(other); } // --- BEGIN STATE @@ -877,7 +466,7 @@ export class MinimalModelLine extends AbstractModelLine implements IModelLine { return NO_OP_TOKENS_ADJUSTER; } - protected _setText(text: string, tabSize: number): void { + protected _setText(text: string): void { this._text = text; } } diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index ce088944f8d..e4d74605063 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -8,19 +8,17 @@ import { OrderGuaranteeEventEmitter, BulkListenerCallback } from 'vs/base/common import * as strings from 'vs/base/common/strings'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { Range, IRange } from 'vs/editor/common/core/range'; +import { Selection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ModelLine, IModelLine, MinimalModelLine } from 'vs/editor/common/model/modelLine'; import { guessIndentation } from 'vs/editor/common/model/indentationGuesser'; import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; -import { IndentRange, computeRanges } from 'vs/editor/common/model/indentRanges'; import { TextModelSearch, SearchParams } from 'vs/editor/common/model/textModelSearch'; import { TextSource, ITextSource, IRawTextSource, RawTextSource } from 'vs/editor/common/model/textSource'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; -const USE_MIMINAL_MODEL_LINE = true; - const LIMIT_FIND_COUNT = 999; export const LONG_LINE_BOUNDARY = 10000; @@ -85,7 +83,6 @@ export class TextModel implements editorCommon.ITextModel { protected _isDisposing: boolean; protected _options: editorCommon.TextModelResolvedOptions; protected _lineStarts: PrefixSumComputer; - private _indentRanges: IndentRange[]; private _versionId: number; /** @@ -124,11 +121,11 @@ export class TextModel implements editorCommon.ITextModel { this._isDisposing = false; } - protected _createModelLine(text: string, tabSize: number): IModelLine { - if (USE_MIMINAL_MODEL_LINE && this._isTooLargeForTokenization) { - return new MinimalModelLine(text, tabSize); + protected _createModelLine(text: string): IModelLine { + if (this._isTooLargeForTokenization) { + return new MinimalModelLine(text); } - return new ModelLine(text, tabSize); + return new ModelLine(text); } protected _assertNotDisposed(): void { @@ -170,13 +167,6 @@ export class TextModel implements editorCommon.ITextModel { let e = this._options.createChangeEvent(newOpts); this._options = newOpts; - if (e.tabSize) { - let newTabSize = this._options.tabSize; - for (let i = 0, len = this._lines.length; i < len; i++) { - this._lines[i].updateTabSize(newTabSize); - } - } - this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelOptionsChanged, e); } @@ -263,22 +253,9 @@ export class TextModel implements editorCommon.ITextModel { return this._alternativeVersionId; } - private _ensureLineStarts(): void { - if (!this._lineStarts) { - const eolLength = this._EOL.length; - const linesLength = this._lines.length; - const lineStartValues = new Uint32Array(linesLength); - for (let i = 0; i < linesLength; i++) { - lineStartValues[i] = this._lines[i].text.length + eolLength; - } - this._lineStarts = new PrefixSumComputer(lineStartValues); - } - } - public getOffsetAt(rawPosition: IPosition): number { this._assertNotDisposed(); let position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, false); - this._ensureLineStarts(); return this._lineStarts.getAccumulatedValue(position.lineNumber - 2) + position.column - 1; } @@ -287,7 +264,6 @@ export class TextModel implements editorCommon.ITextModel { offset = Math.floor(offset); offset = Math.max(0, offset); - this._ensureLineStarts(); let out = this._lineStarts.getIndexOf(offset); let lineLength = this._lines[out.index].text.length; @@ -504,74 +480,6 @@ export class TextModel implements editorCommon.ITextModel { return this._lines[lineNumber - 1].text; } - public getIndentLevel(lineNumber: number): number { - this._assertNotDisposed(); - if (lineNumber < 1 || lineNumber > this.getLineCount()) { - throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`'); - } - - return this._lines[lineNumber - 1].getIndentLevel(); - } - - protected _resetIndentRanges(): void { - this._indentRanges = null; - } - - private _getIndentRanges(): IndentRange[] { - if (!this._indentRanges) { - this._indentRanges = computeRanges(this); - } - return this._indentRanges; - } - - public getIndentRanges(): IndentRange[] { - this._assertNotDisposed(); - let indentRanges = this._getIndentRanges(); - return IndentRange.deepCloneArr(indentRanges); - } - - private _toValidLineIndentGuide(lineNumber: number, indentGuide: number): number { - let lineIndentLevel = this._lines[lineNumber - 1].getIndentLevel(); - if (lineIndentLevel === -1) { - return indentGuide; - } - let maxIndentGuide = Math.ceil(lineIndentLevel / this._options.tabSize); - return Math.min(maxIndentGuide, indentGuide); - } - - public getLineIndentGuide(lineNumber: number): number { - this._assertNotDisposed(); - if (lineNumber < 1 || lineNumber > this.getLineCount()) { - throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`'); - } - - let indentRanges = this._getIndentRanges(); - - for (let i = indentRanges.length - 1; i >= 0; i--) { - let rng = indentRanges[i]; - - if (rng.startLineNumber === lineNumber) { - return this._toValidLineIndentGuide(lineNumber, Math.ceil(rng.indent / this._options.tabSize)); - } - if (rng.startLineNumber < lineNumber && lineNumber <= rng.endLineNumber) { - return this._toValidLineIndentGuide(lineNumber, 1 + Math.floor(rng.indent / this._options.tabSize)); - } - if (rng.endLineNumber + 1 === lineNumber) { - let bestIndent = rng.indent; - while (i > 0) { - i--; - rng = indentRanges[i]; - if (rng.endLineNumber + 1 === lineNumber) { - bestIndent = rng.indent; - } - } - return this._toValidLineIndentGuide(lineNumber, Math.ceil(bestIndent / this._options.tabSize)); - } - } - - return 0; - } - public getLinesContent(): string[] { this._assertNotDisposed(); var r: string[] = []; @@ -586,6 +494,12 @@ export class TextModel implements editorCommon.ITextModel { return this._EOL; } + protected _onBeforeEOLChange(): void { + } + + protected _onAfterEOLChange(): void { + } + public setEOL(eol: editorCommon.EndOfLineSequence): void { this._assertNotDisposed(); const newEOL = (eol === editorCommon.EndOfLineSequence.CRLF ? '\r\n' : '\n'); @@ -599,9 +513,11 @@ export class TextModel implements editorCommon.ITextModel { const endLineNumber = this.getLineCount(); const endColumn = this.getLineMaxColumn(endLineNumber); + this._onBeforeEOLChange(); this._EOL = newEOL; - this._lineStarts = null; + this._constructLineStarts(); this._increaseVersionId(); + this._onAfterEOLChange(); this._emitModelRawContentChangedEvent( new textModelEvents.ModelRawContentChangedEvent( @@ -668,6 +584,77 @@ export class TextModel implements editorCommon.ITextModel { return lineNumber; } + /** + * Validates `range` is within buffer bounds, but allows it to sit in between surrogate pairs, etc. + * Will try to not allocate if possible. + */ + protected _validateRangeRelaxedNoAllocations(range: IRange): Range { + const linesCount = this._lines.length; + + const initialStartLineNumber = range.startLineNumber; + const initialStartColumn = range.startColumn; + let startLineNumber: number; + let startColumn: number; + + if (initialStartLineNumber < 1) { + startLineNumber = 1; + startColumn = 1; + } else if (initialStartLineNumber > linesCount) { + startLineNumber = linesCount; + startColumn = this.getLineMaxColumn(startLineNumber); + } else { + startLineNumber = initialStartLineNumber | 0; + if (initialStartColumn <= 1) { + startColumn = 1; + } else { + const maxColumn = this.getLineMaxColumn(startLineNumber); + if (initialStartColumn >= maxColumn) { + startColumn = maxColumn; + } else { + startColumn = initialStartColumn | 0; + } + } + } + + const initialEndLineNumber = range.endLineNumber; + const initialEndColumn = range.endColumn; + let endLineNumber: number; + let endColumn: number; + + if (initialEndLineNumber < 1) { + endLineNumber = 1; + endColumn = 1; + } else if (initialEndLineNumber > linesCount) { + endLineNumber = linesCount; + endColumn = this.getLineMaxColumn(endLineNumber); + } else { + endLineNumber = initialEndLineNumber | 0; + if (initialEndColumn <= 1) { + endColumn = 1; + } else { + const maxColumn = this.getLineMaxColumn(endLineNumber); + if (initialEndColumn >= maxColumn) { + endColumn = maxColumn; + } else { + endColumn = initialEndColumn | 0; + } + } + } + + if ( + initialStartLineNumber === startLineNumber + && initialStartColumn === startColumn + && initialEndLineNumber === endLineNumber + && initialEndColumn === endColumn + && range instanceof Range + && !(range instanceof Selection) + ) { + return range; + } + + return new Range(startLineNumber, startColumn, endLineNumber, endColumn); + } + /** * @param strict Do NOT allow a position inside a high-low surrogate pair */ @@ -772,20 +759,28 @@ export class TextModel implements editorCommon.ITextModel { } private _constructLines(textSource: ITextSource): void { - const tabSize = this._options.tabSize; let rawLines = textSource.lines; let modelLines: IModelLine[] = new Array(rawLines.length); for (let i = 0, len = rawLines.length; i < len; i++) { - modelLines[i] = this._createModelLine(rawLines[i], tabSize); + modelLines[i] = this._createModelLine(rawLines[i]); } this._BOM = textSource.BOM; this._mightContainRTL = textSource.containsRTL; this._mightContainNonBasicASCII = !textSource.isBasicASCII; this._EOL = textSource.EOL; this._lines = modelLines; - this._lineStarts = null; - this._resetIndentRanges(); + this._constructLineStarts(); + } + + private _constructLineStarts(): void { + const eolLength = this._EOL.length; + const linesLength = this._lines.length; + const lineStartValues = new Uint32Array(linesLength); + for (let i = 0; i < linesLength; i++) { + lineStartValues[i] = this._lines[i].text.length + eolLength; + } + this._lineStarts = new PrefixSumComputer(lineStartValues); } private _getEndOfLine(eol: editorCommon.EndOfLinePreference): string { diff --git a/src/vs/editor/common/model/textModelEvents.ts b/src/vs/editor/common/model/textModelEvents.ts index 890dd25df46..aaa66c7beab 100644 --- a/src/vs/editor/common/model/textModelEvents.ts +++ b/src/vs/editor/common/model/textModelEvents.ts @@ -18,6 +18,7 @@ export const TextModelEventType = { ModelContentChanged: 'contentChanged', ModelRawContentChanged2: 'rawContentChanged2', ModelDecorationsChanged: 'decorationsChanged', + ModelLanguageConfigurationChanged: 'modelLanguageConfigurationChanged' }; /** @@ -34,6 +35,12 @@ export interface IModelLanguageChangedEvent { readonly newLanguage: string; } +/** + * An event describing that the language configuration associated with a model has changed. + */ +export interface IModelLanguageConfigurationChangedEvent { +} + export interface IModelContentChange { /** * The range that got replaced. @@ -81,18 +88,6 @@ export interface IModelContentChangedEvent { * An event describing that model decorations have changed. */ export interface IModelDecorationsChangedEvent { - /** - * Lists of ids for added decorations. - */ - readonly addedDecorations: string[]; - /** - * Lists of ids for changed decorations. - */ - readonly changedDecorations: string[]; - /** - * List of ids for removed decorations. - */ - readonly removedDecorations: string[]; } /** diff --git a/src/vs/editor/common/model/textModelWithDecorations.ts b/src/vs/editor/common/model/textModelWithDecorations.ts index c66247c0b6a..ff79fbfccce 100644 --- a/src/vs/editor/common/model/textModelWithDecorations.ts +++ b/src/vs/editor/common/model/textModelWithDecorations.ts @@ -10,106 +10,12 @@ import * as strings from 'vs/base/common/strings'; import { CharCode } from 'vs/base/common/charCode'; import { Range, IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { MarkersTracker, LineMarker } from 'vs/editor/common/model/modelLine'; -import { Position } from 'vs/editor/common/core/position'; -import { INewMarker, TextModelWithMarkers } from 'vs/editor/common/model/textModelWithMarkers'; +import { TextModelWithTokens } from 'vs/editor/common/model/textModelWithTokens'; import { LanguageIdentifier } from 'vs/editor/common/modes'; import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; - -export const ClassName = { - EditorWarningDecoration: 'greensquiggly', - EditorErrorDecoration: 'redsquiggly' -}; - -class DecorationsTracker { - - public addedDecorations: string[]; - public addedDecorationsLen: number; - public changedDecorations: string[]; - public changedDecorationsLen: number; - public removedDecorations: string[]; - public removedDecorationsLen: number; - - constructor() { - this.addedDecorations = []; - this.addedDecorationsLen = 0; - this.changedDecorations = []; - this.changedDecorationsLen = 0; - this.removedDecorations = []; - this.removedDecorationsLen = 0; - } - - // --- Build decoration events - - public addNewDecoration(id: string): void { - this.addedDecorations[this.addedDecorationsLen++] = id; - } - - public addRemovedDecoration(id: string): void { - this.removedDecorations[this.removedDecorationsLen++] = id; - } - - public addMovedDecoration(id: string): void { - this.changedDecorations[this.changedDecorationsLen++] = id; - } - - public addUpdatedDecoration(id: string): void { - this.changedDecorations[this.changedDecorationsLen++] = id; - } -} - -export class InternalDecoration implements editorCommon.IModelDecoration { - _internalDecorationBrand: void; - - public readonly id: string; - public readonly internalId: number; - public readonly ownerId: number; - public readonly startMarker: LineMarker; - public readonly endMarker: LineMarker; - public options: ModelDecorationOptions; - public isForValidation: boolean; - public range: Range; - - constructor(id: string, internalId: number, ownerId: number, range: Range, startMarker: LineMarker, endMarker: LineMarker, options: ModelDecorationOptions) { - this.id = id; - this.internalId = internalId; - this.ownerId = ownerId; - this.range = range; - this.startMarker = startMarker; - this.endMarker = endMarker; - this.setOptions(options); - } - - public setOptions(options: ModelDecorationOptions) { - this.options = options; - this.isForValidation = ( - this.options.className === ClassName.EditorErrorDecoration - || this.options.className === ClassName.EditorWarningDecoration - ); - } - - public setRange(multiLineDecorationsMap: { [key: string]: InternalDecoration; }, range: Range): void { - if (this.range.equalsRange(range)) { - return; - } - - let rangeWasMultiLine = (this.range.startLineNumber !== this.range.endLineNumber); - this.range = range; - let rangeIsMultiline = (this.range.startLineNumber !== this.range.endLineNumber); - - if (rangeWasMultiLine === rangeIsMultiline) { - return; - } - - if (rangeIsMultiline) { - multiLineDecorationsMap[this.id] = this; - } else { - delete multiLineDecorationsMap[this.id]; - } - } -} +import { IntervalNode, IntervalTree, recomputeMaxEnd, getNodeIsInOverviewRuler } from 'vs/editor/common/model/intervalTree'; let _INSTANCE_COUNT = 0; /** @@ -128,7 +34,7 @@ function nextInstanceId(): string { return String.fromCharCode(CharCode.A + result - LETTERS_CNT); } -export class TextModelWithDecorations extends TextModelWithMarkers implements editorCommon.ITextModelWithDecorations { +export class TextModelWithDecorations extends TextModelWithTokens implements editorCommon.ITextModelWithDecorations { /** * Used to workaround broken clients that might attempt using a decoration id generated by a different model. @@ -136,39 +42,26 @@ export class TextModelWithDecorations extends TextModelWithMarkers implements ed */ private readonly _instanceId: string; private _lastDecorationId: number; - - private _currentDecorationsTracker: DecorationsTracker; private _currentDecorationsTrackerCnt: number; - - private _currentMarkersTracker: MarkersTracker; - private _currentMarkersTrackerCnt: number; - - private _decorations: { [decorationId: string]: InternalDecoration; }; - private _internalDecorations: { [internalDecorationId: number]: InternalDecoration; }; - private _multiLineDecorationsMap: { [key: string]: InternalDecoration; }; + private _currentDecorationsTrackerDidChange: boolean; + private _decorations: { [decorationId: string]: IntervalNode; }; + private _decorationsTree: DecorationsTrees; constructor(rawTextSource: IRawTextSource, creationOptions: editorCommon.ITextModelCreationOptions, languageIdentifier: LanguageIdentifier) { super(rawTextSource, creationOptions, languageIdentifier); this._instanceId = nextInstanceId(); this._lastDecorationId = 0; - - // Initialize decorations - this._currentDecorationsTracker = null; this._currentDecorationsTrackerCnt = 0; - - this._currentMarkersTracker = null; - this._currentMarkersTrackerCnt = 0; - + this._currentDecorationsTrackerDidChange = false; this._decorations = Object.create(null); - this._internalDecorations = Object.create(null); - this._multiLineDecorationsMap = Object.create(null); + this._decorationsTree = new DecorationsTrees(); } public dispose(): void { this._decorations = null; - this._internalDecorations = null; - this._multiLineDecorationsMap = null; + this._decorationsTree = null; + super.dispose(); } @@ -177,59 +70,108 @@ export class TextModelWithDecorations extends TextModelWithMarkers implements ed // Destroy all my decorations this._decorations = Object.create(null); - this._internalDecorations = Object.create(null); - this._multiLineDecorationsMap = Object.create(null); - } - - private static _shouldStartMarkerSticksToPreviousCharacter(stickiness: editorCommon.TrackedRangeStickiness): boolean { - if (stickiness === editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges || stickiness === editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore) { - return true; - } - return false; - } - - private static _shouldEndMarkerSticksToPreviousCharacter(stickiness: editorCommon.TrackedRangeStickiness): boolean { - if (stickiness === editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges || stickiness === editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore) { - return true; - } - return false; + this._decorationsTree = new DecorationsTrees(); } _getTrackedRangesCount(): number { - return Object.keys(this._decorations).length; + return this._decorationsTree.count(); } // --- END TrackedRanges + protected _acquireDecorationsTracker(): void { + if (this._currentDecorationsTrackerCnt === 0) { + this._currentDecorationsTrackerDidChange = false; + } + this._currentDecorationsTrackerCnt++; + } + + protected _releaseDecorationsTracker(): void { + this._currentDecorationsTrackerCnt--; + if (this._currentDecorationsTrackerCnt === 0) { + if (this._currentDecorationsTrackerDidChange) { + this._emitModelDecorationsChangedEvent(); + } + } + } + + protected _adjustDecorationsForEdit(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void { + this._currentDecorationsTrackerDidChange = true; + this._decorationsTree.acceptReplace(offset, length, textLength, forceMoveMarkers); + } + + protected _onBeforeEOLChange(): void { + super._onBeforeEOLChange(); + + // Ensure all decorations get their `range` set. + const versionId = this.getVersionId(); + const allDecorations = this._decorationsTree.search(0, false, false, versionId); + this._ensureNodesHaveRanges(allDecorations); + } + + protected _onAfterEOLChange(): void { + super._onAfterEOLChange(); + + // Transform back `range` to offsets + const versionId = this.getVersionId(); + const allDecorations = this._decorationsTree.collectNodesPostOrder(); + for (let i = 0, len = allDecorations.length; i < len; i++) { + const node = allDecorations[i]; + + const delta = node.cachedAbsoluteStart - node.start; + + const startOffset = this._lineStarts.getAccumulatedValue(node.range.startLineNumber - 2) + node.range.startColumn - 1; + const endOffset = this._lineStarts.getAccumulatedValue(node.range.endLineNumber - 2) + node.range.endColumn - 1; + + node.cachedAbsoluteStart = startOffset; + node.cachedAbsoluteEnd = endOffset; + node.cachedVersionId = versionId; + + node.start = startOffset - delta; + node.end = endOffset - delta; + + recomputeMaxEnd(node); + } + } + public changeDecorations(callback: (changeAccessor: editorCommon.IModelDecorationsChangeAccessor) => T, ownerId: number = 0): T { this._assertNotDisposed(); try { this._eventEmitter.beginDeferredEmit(); - let decorationsTracker = this._acquireDecorationsTracker(); - return this._changeDecorations(decorationsTracker, ownerId, callback); + this._acquireDecorationsTracker(); + return this._changeDecorations(ownerId, callback); } finally { this._releaseDecorationsTracker(); this._eventEmitter.endDeferredEmit(); } } - private _changeDecorations(decorationsTracker: DecorationsTracker, ownerId: number, callback: (changeAccessor: editorCommon.IModelDecorationsChangeAccessor) => T): T { + private _changeDecorations(ownerId: number, callback: (changeAccessor: editorCommon.IModelDecorationsChangeAccessor) => T): T { let changeAccessor: editorCommon.IModelDecorationsChangeAccessor = { addDecoration: (range: IRange, options: editorCommon.IModelDecorationOptions): string => { - return this._addDecorationImpl(decorationsTracker, ownerId, this.validateRange(range), _normalizeOptions(options)); + this._currentDecorationsTrackerDidChange = true; + return this._deltaDecorationsImpl(ownerId, [], [{ range: range, options: options }])[0]; }, changeDecoration: (id: string, newRange: IRange): void => { - this._changeDecorationImpl(decorationsTracker, id, this.validateRange(newRange)); + this._currentDecorationsTrackerDidChange = true; + this._changeDecorationImpl(id, newRange); }, changeDecorationOptions: (id: string, options: editorCommon.IModelDecorationOptions) => { - this._changeDecorationOptionsImpl(decorationsTracker, id, _normalizeOptions(options)); + this._currentDecorationsTrackerDidChange = true; + this._changeDecorationOptionsImpl(id, _normalizeOptions(options)); }, removeDecoration: (id: string): void => { - this._removeDecorationImpl(decorationsTracker, id); + this._currentDecorationsTrackerDidChange = true; + this._deltaDecorationsImpl(ownerId, [id], []); }, deltaDecorations: (oldDecorations: string[], newDecorations: editorCommon.IModelDeltaDecoration[]): string[] => { - return this._deltaDecorationsImpl(decorationsTracker, ownerId, oldDecorations, this._normalizeDeltaDecorations(newDecorations)); + if (oldDecorations.length === 0 && newDecorations.length === 0) { + // nothing to do + return []; + } + this._currentDecorationsTrackerDidChange = true; + return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations); } }; let result: T = null; @@ -251,41 +193,90 @@ export class TextModelWithDecorations extends TextModelWithMarkers implements ed if (!oldDecorations) { oldDecorations = []; } - return this.changeDecorations((changeAccessor) => { - return changeAccessor.deltaDecorations(oldDecorations, newDecorations); - }, ownerId); + if (oldDecorations.length === 0 && newDecorations.length === 0) { + // nothing to do + return []; + } + + try { + this._eventEmitter.beginDeferredEmit(); + this._acquireDecorationsTracker(); + this._currentDecorationsTrackerDidChange = true; + return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations); + } finally { + this._releaseDecorationsTracker(); + this._eventEmitter.endDeferredEmit(); + } + } + + _getTrackedRange(id: string): Range { + return this.getDecorationRange(id); + } + + _setTrackedRange(id: string, newRange: Range, newStickiness: editorCommon.TrackedRangeStickiness): string { + const node = (id ? this._decorations[id] : null); + + if (!node) { + if (!newRange) { + // node doesn't exist, the request is to delete => nothing to do + return null; + } + // node doesn't exist, the request is to set => add the tracked range + return this._deltaDecorationsImpl(0, [], [{ range: newRange, options: TRACKED_RANGE_OPTIONS[newStickiness] }])[0]; + } + + if (!newRange) { + // node exists, the request is to delete => delete node + this._decorationsTree.delete(node); + delete this._decorations[node.id]; + return null; + } + + // node exists, the request is to set => change the tracked range and its options + const range = this._validateRangeRelaxedNoAllocations(newRange); + const startOffset = this._lineStarts.getAccumulatedValue(range.startLineNumber - 2) + range.startColumn - 1; + const endOffset = this._lineStarts.getAccumulatedValue(range.endLineNumber - 2) + range.endColumn - 1; + this._decorationsTree.delete(node); + node.reset(this.getVersionId(), startOffset, endOffset, range); + node.setOptions(TRACKED_RANGE_OPTIONS[newStickiness]); + this._decorationsTree.insert(node); + return node.id; } public removeAllDecorationsWithOwnerId(ownerId: number): void { - let toRemove: string[] = []; - - for (let decorationId in this._decorations) { - // No `hasOwnProperty` call due to using Object.create(null) - - let decoration = this._decorations[decorationId]; - - if (decoration.ownerId === ownerId) { - toRemove.push(decoration.id); - } + if (this._isDisposed) { + return; } + const nodes = this._decorationsTree.collectNodesFromOwner(ownerId); + for (let i = 0, len = nodes.length; i < len; i++) { + const node = nodes[i]; - this._removeDecorationsImpl(null, toRemove); + this._decorationsTree.delete(node); + delete this._decorations[node.id]; + } } public getDecorationOptions(decorationId: string): editorCommon.IModelDecorationOptions { - let decoration = this._decorations[decorationId]; - if (!decoration) { + const node = this._decorations[decorationId]; + if (!node) { return null; } - return decoration.options; + return node.options; } public getDecorationRange(decorationId: string): Range { - let decoration = this._decorations[decorationId]; - if (!decoration) { + const node = this._decorations[decorationId]; + if (!node) { return null; } - return decoration.range; + const versionId = this.getVersionId(); + if (node.cachedVersionId !== versionId) { + this._decorationsTree.resolveNode(node, versionId); + } + if (node.range === null) { + node.range = this._getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd); + } + return node.range; } public getLineDecorations(lineNumber: number, ownerId: number = 0, filterOutValidation: boolean = false): editorCommon.IModelDecoration[] { @@ -296,116 +287,6 @@ export class TextModelWithDecorations extends TextModelWithMarkers implements ed return this.getLinesDecorations(lineNumber, lineNumber, ownerId, filterOutValidation); } - /** - * Fetch only multi-line decorations that intersect with the given line number range - */ - private _getMultiLineDecorations(filterRange: Range, filterOwnerId: number, filterOutValidation: boolean): InternalDecoration[] { - const filterStartLineNumber = filterRange.startLineNumber; - const filterStartColumn = filterRange.startColumn; - const filterEndLineNumber = filterRange.endLineNumber; - const filterEndColumn = filterRange.endColumn; - - let result: InternalDecoration[] = [], resultLen = 0; - - for (let decorationId in this._multiLineDecorationsMap) { - // No `hasOwnProperty` call due to using Object.create(null) - let decoration = this._multiLineDecorationsMap[decorationId]; - - if (filterOwnerId && decoration.ownerId && decoration.ownerId !== filterOwnerId) { - continue; - } - - if (filterOutValidation && decoration.isForValidation) { - continue; - } - - let range = decoration.range; - - if (range.startLineNumber > filterEndLineNumber) { - continue; - } - if (range.startLineNumber === filterEndLineNumber && range.startColumn > filterEndColumn) { - continue; - } - if (range.endLineNumber < filterStartLineNumber) { - continue; - } - if (range.endLineNumber === filterStartLineNumber && range.endColumn < filterStartColumn) { - continue; - } - - result[resultLen++] = decoration; - } - - return result; - } - - private _getDecorationsInRange(filterRange: Range, filterOwnerId: number, filterOutValidation: boolean): InternalDecoration[] { - const filterStartLineNumber = filterRange.startLineNumber; - const filterStartColumn = filterRange.startColumn; - const filterEndLineNumber = filterRange.endLineNumber; - const filterEndColumn = filterRange.endColumn; - - let result = this._getMultiLineDecorations(filterRange, filterOwnerId, filterOutValidation); - let resultLen = result.length; - let resultMap: { [decorationId: string]: boolean; } = {}; - - for (let i = 0, len = resultLen; i < len; i++) { - resultMap[result[i].id] = true; - } - - for (let lineNumber = filterStartLineNumber; lineNumber <= filterEndLineNumber; lineNumber++) { - let lineMarkers = this._lines[lineNumber - 1].getMarkers(); - if (lineMarkers === null) { - continue; - } - for (let i = 0, len = lineMarkers.length; i < len; i++) { - let lineMarker = lineMarkers[i]; - let internalDecorationId = lineMarker.internalDecorationId; - - if (internalDecorationId === 0) { - // marker does not belong to any decoration - continue; - } - - let decoration = this._internalDecorations[internalDecorationId]; - - if (resultMap.hasOwnProperty(decoration.id)) { - // decoration already in result - continue; - } - - if (filterOwnerId && decoration.ownerId && decoration.ownerId !== filterOwnerId) { - continue; - } - - if (filterOutValidation && decoration.isForValidation) { - continue; - } - - let range = decoration.range; - - if (range.startLineNumber > filterEndLineNumber) { - continue; - } - if (range.startLineNumber === filterEndLineNumber && range.startColumn > filterEndColumn) { - continue; - } - if (range.endLineNumber < filterStartLineNumber) { - continue; - } - if (range.endLineNumber === filterStartLineNumber && range.endColumn < filterStartColumn) { - continue; - } - - result[resultLen++] = decoration; - resultMap[decoration.id] = true; - } - } - - return result; - } - public getLinesDecorations(_startLineNumber: number, _endLineNumber: number, ownerId: number = 0, filterOutValidation: boolean = false): editorCommon.IModelDecoration[] { let lineCount = this.getLineCount(); let startLineNumber = Math.min(lineCount, Math.max(1, _startLineNumber)); @@ -414,422 +295,150 @@ export class TextModelWithDecorations extends TextModelWithMarkers implements ed return this._getDecorationsInRange(new Range(startLineNumber, 1, endLineNumber, endColumn), ownerId, filterOutValidation); } - public getDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean): editorCommon.IModelDecoration[] { + public getDecorationsInRange(range: IRange, ownerId: number = 0, filterOutValidation: boolean = false): editorCommon.IModelDecoration[] { let validatedRange = this.validateRange(range); return this._getDecorationsInRange(validatedRange, ownerId, filterOutValidation); } + public getOverviewRulerDecorations(ownerId: number = 0, filterOutValidation: boolean = false): editorCommon.IModelDecoration[] { + const versionId = this.getVersionId(); + const result = this._decorationsTree.search(ownerId, filterOutValidation, true, versionId); + return this._ensureNodesHaveRanges(result); + } + public getAllDecorations(ownerId: number = 0, filterOutValidation: boolean = false): editorCommon.IModelDecoration[] { - let result: InternalDecoration[] = [], resultLen = 0; - - for (let decorationId in this._decorations) { - // No `hasOwnProperty` call due to using Object.create(null) - let decoration = this._decorations[decorationId]; - - if (ownerId && decoration.ownerId && decoration.ownerId !== ownerId) { - continue; - } - - if (filterOutValidation && decoration.isForValidation) { - continue; - } - - result[resultLen++] = decoration; - } - - return result; + const versionId = this.getVersionId(); + const result = this._decorationsTree.search(ownerId, filterOutValidation, false, versionId); + return this._ensureNodesHaveRanges(result); } - protected _acquireMarkersTracker(): MarkersTracker { - if (this._currentMarkersTrackerCnt === 0) { - this._currentMarkersTracker = new MarkersTracker(); - } - this._currentMarkersTrackerCnt++; - return this._currentMarkersTracker; - } - - protected _releaseMarkersTracker(): void { - this._currentMarkersTrackerCnt--; - if (this._currentMarkersTrackerCnt === 0) { - let markersTracker = this._currentMarkersTracker; - this._currentMarkersTracker = null; - this._handleTrackedMarkers(markersTracker); - } - } - - /** - * Handle changed markers (i.e. update decorations ranges and return the changed decorations, unique and sorted by id) - */ - private _handleTrackedMarkers(markersTracker: MarkersTracker): void { - let changedInternalDecorationIds = markersTracker.getDecorationIds(); - if (changedInternalDecorationIds.length === 0) { - return; - } - - changedInternalDecorationIds.sort(); - - let uniqueChangedDecorations: string[] = [], uniqueChangedDecorationsLen = 0; - let previousInternalDecorationId: number = 0; - for (let i = 0, len = changedInternalDecorationIds.length; i < len; i++) { - let internalDecorationId = changedInternalDecorationIds[i]; - if (internalDecorationId === previousInternalDecorationId) { - continue; - } - previousInternalDecorationId = internalDecorationId; - - let decoration = this._internalDecorations[internalDecorationId]; - if (!decoration) { - // perhaps the decoration was removed in the meantime - continue; - } - - let startMarker = decoration.startMarker.position; - let endMarker = decoration.endMarker.position; - let range = TextModelWithDecorations._createRangeFromMarkers(startMarker, endMarker); - decoration.setRange(this._multiLineDecorationsMap, range); - - uniqueChangedDecorations[uniqueChangedDecorationsLen++] = decoration.id; - } - - if (uniqueChangedDecorations.length > 0) { - let e: textModelEvents.IModelDecorationsChangedEvent = { - addedDecorations: [], - changedDecorations: uniqueChangedDecorations, - removedDecorations: [] - }; - this.emitModelDecorationsChangedEvent(e); - } - } - - private static _createRangeFromMarkers(startPosition: Position, endPosition: Position): Range { - if (endPosition.isBefore(startPosition)) { - // This tracked range has turned in on itself (end marker before start marker) - // This can happen in extreme editing conditions where lots of text is removed and lots is added - - // Treat it as a collapsed range - return new Range(startPosition.lineNumber, startPosition.column, startPosition.lineNumber, startPosition.column); - } - return new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column); - } - - private _acquireDecorationsTracker(): DecorationsTracker { - if (this._currentDecorationsTrackerCnt === 0) { - this._currentDecorationsTracker = new DecorationsTracker(); - } - this._currentDecorationsTrackerCnt++; - return this._currentDecorationsTracker; - } - - private _releaseDecorationsTracker(): void { - this._currentDecorationsTrackerCnt--; - if (this._currentDecorationsTrackerCnt === 0) { - let decorationsTracker = this._currentDecorationsTracker; - this._currentDecorationsTracker = null; - this._handleTrackedDecorations(decorationsTracker); - } - } - - private _handleTrackedDecorations(decorationsTracker: DecorationsTracker): void { - if ( - decorationsTracker.addedDecorationsLen === 0 - && decorationsTracker.changedDecorationsLen === 0 - && decorationsTracker.removedDecorationsLen === 0 - ) { - return; - } - - let e: textModelEvents.IModelDecorationsChangedEvent = { - addedDecorations: decorationsTracker.addedDecorations, - changedDecorations: decorationsTracker.changedDecorations, - removedDecorations: decorationsTracker.removedDecorations - }; - this.emitModelDecorationsChangedEvent(e); - } - - private emitModelDecorationsChangedEvent(e: textModelEvents.IModelDecorationsChangedEvent): void { + private _emitModelDecorationsChangedEvent(): void { if (!this._isDisposing) { + let e: textModelEvents.IModelDecorationsChangedEvent = {}; this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelDecorationsChanged, e); } } - private _normalizeDeltaDecorations(deltaDecorations: editorCommon.IModelDeltaDecoration[]): ModelDeltaDecoration[] { - let result: ModelDeltaDecoration[] = []; - for (let i = 0, len = deltaDecorations.length; i < len; i++) { - let deltaDecoration = deltaDecorations[i]; - result.push(new ModelDeltaDecoration(i, this.validateRange(deltaDecoration.range), _normalizeOptions(deltaDecoration.options))); - } - return result; + private _getDecorationsInRange(filterRange: Range, filterOwnerId: number, filterOutValidation: boolean): IntervalNode[] { + const startOffset = this._lineStarts.getAccumulatedValue(filterRange.startLineNumber - 2) + filterRange.startColumn - 1; + const endOffset = this._lineStarts.getAccumulatedValue(filterRange.endLineNumber - 2) + filterRange.endColumn - 1; + + const versionId = this.getVersionId(); + const result = this._decorationsTree.intervalSearch(startOffset, endOffset, filterOwnerId, filterOutValidation, versionId); + + return this._ensureNodesHaveRanges(result); } - private _externalDecorationId(internalId: number): string { - return `${this._instanceId};${internalId}`; - } - - private _addDecorationImpl(decorationsTracker: DecorationsTracker, ownerId: number, _range: Range, options: ModelDecorationOptions): string { - let range = this.validateRange(_range); - - let internalDecorationId = (++this._lastDecorationId); - let decorationId = this._externalDecorationId(internalDecorationId); - - let markers = this._addMarkers([ - { - internalDecorationId: internalDecorationId, - position: new Position(range.startLineNumber, range.startColumn), - stickToPreviousCharacter: TextModelWithDecorations._shouldStartMarkerSticksToPreviousCharacter(options.stickiness) - }, - { - internalDecorationId: internalDecorationId, - position: new Position(range.endLineNumber, range.endColumn), - stickToPreviousCharacter: TextModelWithDecorations._shouldEndMarkerSticksToPreviousCharacter(options.stickiness) + private _ensureNodesHaveRanges(nodes: IntervalNode[]): IntervalNode[] { + for (let i = 0, len = nodes.length; i < len; i++) { + const node = nodes[i]; + if (node.range === null) { + node.range = this._getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd); } - ]); - - let decoration = new InternalDecoration(decorationId, internalDecorationId, ownerId, range, markers[0], markers[1], options); - this._decorations[decorationId] = decoration; - this._internalDecorations[internalDecorationId] = decoration; - if (range.startLineNumber !== range.endLineNumber) { - this._multiLineDecorationsMap[decorationId] = decoration; } - - decorationsTracker.addNewDecoration(decorationId); - - return decorationId; + return nodes; } - private _addDecorationsImpl(decorationsTracker: DecorationsTracker, ownerId: number, newDecorations: ModelDeltaDecoration[]): string[] { - let internalDecorationIds: number[] = []; - let decorationIds: string[] = []; - let newMarkers: INewMarker[] = []; + private _getRangeAt(start: number, end: number): Range { + const startResult = this._lineStarts.getIndexOf(start); + const startLineLength = this._lines[startResult.index].text.length; + const startColumn = Math.min(startResult.remainder + 1, startLineLength + 1); - for (let i = 0, len = newDecorations.length; i < len; i++) { - let newDecoration = newDecorations[i]; - let range = newDecoration.range; - let stickiness = newDecoration.options.stickiness; + const endResult = this._lineStarts.getIndexOf(end); + const endLineLength = this._lines[endResult.index].text.length; + const endColumn = Math.min(endResult.remainder + 1, endLineLength + 1); - let internalDecorationId = (++this._lastDecorationId); - let decorationId = this._externalDecorationId(internalDecorationId); - - internalDecorationIds[i] = internalDecorationId; - decorationIds[i] = decorationId; - - newMarkers[2 * i] = { - internalDecorationId: internalDecorationId, - position: new Position(range.startLineNumber, range.startColumn), - stickToPreviousCharacter: TextModelWithDecorations._shouldStartMarkerSticksToPreviousCharacter(stickiness) - }; - - newMarkers[2 * i + 1] = { - internalDecorationId: internalDecorationId, - position: new Position(range.endLineNumber, range.endColumn), - stickToPreviousCharacter: TextModelWithDecorations._shouldEndMarkerSticksToPreviousCharacter(stickiness) - }; - } - - let markerIds = this._addMarkers(newMarkers); - - for (let i = 0, len = newDecorations.length; i < len; i++) { - let newDecoration = newDecorations[i]; - let range = newDecoration.range; - let internalDecorationId = internalDecorationIds[i]; - let decorationId = decorationIds[i]; - let startMarker = markerIds[2 * i]; - let endMarker = markerIds[2 * i + 1]; - - let decoration = new InternalDecoration(decorationId, internalDecorationId, ownerId, range, startMarker, endMarker, newDecoration.options); - this._decorations[decorationId] = decoration; - this._internalDecorations[internalDecorationId] = decoration; - if (range.startLineNumber !== range.endLineNumber) { - this._multiLineDecorationsMap[decorationId] = decoration; - } - - decorationsTracker.addNewDecoration(decorationId); - } - - return decorationIds; + return new Range(startResult.index + 1, startColumn, endResult.index + 1, endColumn); } - private _changeDecorationImpl(decorationsTracker: DecorationsTracker, decorationId: string, newRange: Range): void { - let decoration = this._decorations[decorationId]; - if (!decoration) { + private _changeDecorationImpl(decorationId: string, _range: IRange): void { + const node = this._decorations[decorationId]; + if (!node) { + return; + } + const range = this._validateRangeRelaxedNoAllocations(_range); + const startOffset = this._lineStarts.getAccumulatedValue(range.startLineNumber - 2) + range.startColumn - 1; + const endOffset = this._lineStarts.getAccumulatedValue(range.endLineNumber - 2) + range.endColumn - 1; + + this._decorationsTree.delete(node); + node.reset(this.getVersionId(), startOffset, endOffset, range); + this._decorationsTree.insert(node); + } + + private _changeDecorationOptionsImpl(decorationId: string, options: ModelDecorationOptions): void { + const node = this._decorations[decorationId]; + if (!node) { return; } - let startMarker = decoration.startMarker; - if (newRange.startLineNumber !== startMarker.position.lineNumber) { - // move marker between lines - this._lines[startMarker.position.lineNumber - 1].removeMarker(startMarker); - this._lines[newRange.startLineNumber - 1].addMarker(startMarker); - } - startMarker.setPosition(new Position(newRange.startLineNumber, newRange.startColumn)); + const nodeWasInOverviewRuler = (node.options.overviewRuler.color ? true : false); + const nodeIsInOverviewRuler = (options.overviewRuler.color ? true : false); - let endMarker = decoration.endMarker; - if (newRange.endLineNumber !== endMarker.position.lineNumber) { - // move marker between lines - this._lines[endMarker.position.lineNumber - 1].removeMarker(endMarker); - this._lines[newRange.endLineNumber - 1].addMarker(endMarker); - } - endMarker.setPosition(new Position(newRange.endLineNumber, newRange.endColumn)); - - decoration.setRange(this._multiLineDecorationsMap, newRange); - - decorationsTracker.addMovedDecoration(decorationId); - } - - private _changeDecorationOptionsImpl(decorationsTracker: DecorationsTracker, decorationId: string, options: ModelDecorationOptions): void { - let decoration = this._decorations[decorationId]; - if (!decoration) { - return; - } - - if (decoration.options.stickiness !== options.stickiness) { - decoration.startMarker.stickToPreviousCharacter = TextModelWithDecorations._shouldStartMarkerSticksToPreviousCharacter(options.stickiness); - decoration.endMarker.stickToPreviousCharacter = TextModelWithDecorations._shouldEndMarkerSticksToPreviousCharacter(options.stickiness); - } - - decoration.setOptions(options); - - decorationsTracker.addUpdatedDecoration(decorationId); - } - - private _removeDecorationImpl(decorationsTracker: DecorationsTracker, decorationId: string): void { - let decoration = this._decorations[decorationId]; - if (!decoration) { - return; - } - - this._removeMarkers([decoration.startMarker, decoration.endMarker]); - - delete this._multiLineDecorationsMap[decorationId]; - delete this._decorations[decorationId]; - delete this._internalDecorations[decoration.internalId]; - - if (decorationsTracker) { - decorationsTracker.addRemovedDecoration(decorationId); + if (nodeWasInOverviewRuler !== nodeIsInOverviewRuler) { + // Delete + Insert due to an overview ruler status change + this._decorationsTree.delete(node); + node.setOptions(options); + this._decorationsTree.insert(node); + } else { + node.setOptions(options); } } - private _removeDecorationsImpl(decorationsTracker: DecorationsTracker, decorationIds: string[]): void { - let removeMarkers: LineMarker[] = [], removeMarkersLen = 0; + private _deltaDecorationsImpl(ownerId: number, oldDecorationsIds: string[], newDecorations: editorCommon.IModelDeltaDecoration[]): string[] { + const versionId = this.getVersionId(); - for (let i = 0, len = decorationIds.length; i < len; i++) { - let decorationId = decorationIds[i]; - let decoration = this._decorations[decorationId]; - if (!decoration) { - continue; + const oldDecorationsLen = oldDecorationsIds.length; + let oldDecorationIndex = 0; + + const newDecorationsLen = newDecorations.length; + let newDecorationIndex = 0; + + let result = new Array(newDecorationsLen); + while (oldDecorationIndex < oldDecorationsLen || newDecorationIndex < newDecorationsLen) { + + let node: IntervalNode = null; + + if (oldDecorationIndex < oldDecorationsLen) { + // (1) get ourselves an old node + do { + node = this._decorations[oldDecorationsIds[oldDecorationIndex++]]; + } while (!node && oldDecorationIndex < oldDecorationsLen); + + // (2) remove the node from the tree (if it exists) + if (node) { + this._decorationsTree.delete(node); + } } - if (decorationsTracker) { - decorationsTracker.addRemovedDecoration(decorationId); - } + if (newDecorationIndex < newDecorationsLen) { + // (3) create a new node if necessary + if (!node) { + const internalDecorationId = (++this._lastDecorationId); + const decorationId = `${this._instanceId};${internalDecorationId}`; + node = new IntervalNode(decorationId, 0, 0); + this._decorations[decorationId] = node; + } - removeMarkers[removeMarkersLen++] = decoration.startMarker; - removeMarkers[removeMarkersLen++] = decoration.endMarker; - delete this._multiLineDecorationsMap[decorationId]; - delete this._decorations[decorationId]; - delete this._internalDecorations[decoration.internalId]; - } + // (4) initialize node + const newDecoration = newDecorations[newDecorationIndex]; + const range = this._validateRangeRelaxedNoAllocations(newDecoration.range); + const options = _normalizeOptions(newDecoration.options); + const startOffset = this._lineStarts.getAccumulatedValue(range.startLineNumber - 2) + range.startColumn - 1; + const endOffset = this._lineStarts.getAccumulatedValue(range.endLineNumber - 2) + range.endColumn - 1; - if (removeMarkers.length > 0) { - this._removeMarkers(removeMarkers); - } - } + node.ownerId = ownerId; + node.reset(versionId, startOffset, endOffset, range); + node.setOptions(options); - private _resolveOldDecorations(oldDecorations: string[]): InternalDecoration[] { - let result: InternalDecoration[] = []; - for (let i = 0, len = oldDecorations.length; i < len; i++) { - let id = oldDecorations[i]; - let decoration = this._decorations[id]; - if (!decoration) { - continue; - } + this._decorationsTree.insert(node); - result.push(decoration); - } - return result; - } + result[newDecorationIndex] = node.id; - private _deltaDecorationsImpl(decorationsTracker: DecorationsTracker, ownerId: number, oldDecorationsIds: string[], newDecorations: ModelDeltaDecoration[]): string[] { - - if (oldDecorationsIds.length === 0) { - // Nothing to remove - return this._addDecorationsImpl(decorationsTracker, ownerId, newDecorations); - } - - if (newDecorations.length === 0) { - // Nothing to add - this._removeDecorationsImpl(decorationsTracker, oldDecorationsIds); - return []; - } - - let oldDecorations = this._resolveOldDecorations(oldDecorationsIds); - - oldDecorations.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); - newDecorations.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); - - let result: string[] = [], - oldDecorationsIndex = 0, - oldDecorationsLength = oldDecorations.length, - newDecorationsIndex = 0, - newDecorationsLength = newDecorations.length, - decorationsToAdd: ModelDeltaDecoration[] = [], - decorationsToRemove: string[] = []; - - while (oldDecorationsIndex < oldDecorationsLength && newDecorationsIndex < newDecorationsLength) { - let oldDecoration = oldDecorations[oldDecorationsIndex]; - let newDecoration = newDecorations[newDecorationsIndex]; - let comparison = Range.compareRangesUsingStarts(oldDecoration.range, newDecoration.range); - - if (comparison < 0) { - // `oldDecoration` is before `newDecoration` => remove `oldDecoration` - decorationsToRemove.push(oldDecoration.id); - oldDecorationsIndex++; - continue; - } - - if (comparison > 0) { - // `newDecoration` is before `oldDecoration` => add `newDecoration` - decorationsToAdd.push(newDecoration); - newDecorationsIndex++; - continue; - } - - // The ranges of `oldDecoration` and `newDecoration` are equal - - if (!oldDecoration.options.equals(newDecoration.options)) { - // The options do not match => remove `oldDecoration` - decorationsToRemove.push(oldDecoration.id); - oldDecorationsIndex++; - continue; - } - - // Bingo! We can reuse `oldDecoration` for `newDecoration` - result[newDecoration.index] = oldDecoration.id; - oldDecorationsIndex++; - newDecorationsIndex++; - } - - while (oldDecorationsIndex < oldDecorationsLength) { - // No more new decorations => remove decoration at `oldDecorationsIndex` - decorationsToRemove.push(oldDecorations[oldDecorationsIndex].id); - oldDecorationsIndex++; - } - - while (newDecorationsIndex < newDecorationsLength) { - // No more old decorations => add decoration at `newDecorationsIndex` - decorationsToAdd.push(newDecorations[newDecorationsIndex]); - newDecorationsIndex++; - } - - // Remove `decorationsToRemove` - if (decorationsToRemove.length > 0) { - this._removeDecorationsImpl(decorationsTracker, decorationsToRemove); - } - - // Add `decorationsToAdd` - if (decorationsToAdd.length > 0) { - let newIds = this._addDecorationsImpl(decorationsTracker, ownerId, decorationsToAdd); - for (let i = 0, len = decorationsToAdd.length; i < len; i++) { - result[decorationsToAdd[i].index] = newIds[i]; + newDecorationIndex++; + } else { + if (node) { + delete this._decorations[node.id]; + } } } @@ -837,6 +446,87 @@ export class TextModelWithDecorations extends TextModelWithMarkers implements ed } } +class DecorationsTrees { + + /** + * This tree holds decorations that do not show up in the overview ruler. + */ + private _decorationsTree0: IntervalTree; + + /** + * This tree holds decorations that show up in the overview ruler. + */ + private _decorationsTree1: IntervalTree; + + constructor() { + this._decorationsTree0 = new IntervalTree(); + this._decorationsTree1 = new IntervalTree(); + } + + public intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] { + const r0 = this._decorationsTree0.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId); + const r1 = this._decorationsTree1.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId); + return r0.concat(r1); + } + + public search(filterOwnerId: number, filterOutValidation: boolean, overviewRulerOnly: boolean, cachedVersionId: number): IntervalNode[] { + if (overviewRulerOnly) { + return this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId); + } else { + const r0 = this._decorationsTree0.search(filterOwnerId, filterOutValidation, cachedVersionId); + const r1 = this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId); + return r0.concat(r1); + } + } + + public count(): number { + const c0 = this._decorationsTree0.count(); + const c1 = this._decorationsTree1.count(); + return c0 + c1; + } + + public collectNodesFromOwner(ownerId: number): IntervalNode[] { + const r0 = this._decorationsTree0.collectNodesFromOwner(ownerId); + const r1 = this._decorationsTree1.collectNodesFromOwner(ownerId); + return r0.concat(r1); + } + + public collectNodesPostOrder(): IntervalNode[] { + const r0 = this._decorationsTree0.collectNodesPostOrder(); + const r1 = this._decorationsTree1.collectNodesPostOrder(); + return r0.concat(r1); + } + + public insert(node: IntervalNode): void { + if (getNodeIsInOverviewRuler(node)) { + this._decorationsTree1.insert(node); + } else { + this._decorationsTree0.insert(node); + } + } + + public delete(node: IntervalNode): void { + if (getNodeIsInOverviewRuler(node)) { + this._decorationsTree1.delete(node); + } else { + this._decorationsTree0.delete(node); + } + } + + public resolveNode(node: IntervalNode, cachedVersionId: number): void { + if (getNodeIsInOverviewRuler(node)) { + this._decorationsTree1.resolveNode(node, cachedVersionId); + } else { + this._decorationsTree0.resolveNode(node, cachedVersionId); + } + } + + public acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void { + this._decorationsTree0.acceptReplace(offset, length, textLength, forceMoveMarkers); + this._decorationsTree1.acceptReplace(offset, length, textLength, forceMoveMarkers); + } +} + function cleanClassName(className: string): string { return className.replace(/[^a-z0-9\-]/gi, ' '); } @@ -846,12 +536,14 @@ export class ModelDecorationOverviewRulerOptions implements editorCommon.IModelD readonly darkColor: string | ThemeColor; readonly hcColor: string | ThemeColor; readonly position: editorCommon.OverviewRulerLane; + _resolvedColor: string; constructor(options: editorCommon.IModelDecorationOverviewRulerOptions) { this.color = strings.empty; this.darkColor = strings.empty; this.hcColor = strings.empty; this.position = editorCommon.OverviewRulerLane.Center; + this._resolvedColor = null; if (options && options.color) { this.color = options.color; @@ -948,18 +640,15 @@ export class ModelDecorationOptions implements editorCommon.IModelDecorationOpti } ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({}); -class ModelDeltaDecoration implements editorCommon.IModelDeltaDecoration { - - index: number; - range: Range; - options: ModelDecorationOptions; - - constructor(index: number, range: Range, options: ModelDecorationOptions) { - this.index = index; - this.range = range; - this.options = options; - } -} +/** + * The order carefully matches the values of the enum. + */ +const TRACKED_RANGE_OPTIONS = [ + ModelDecorationOptions.register({ stickiness: editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }), + ModelDecorationOptions.register({ stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }), + ModelDecorationOptions.register({ stickiness: editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }), + ModelDecorationOptions.register({ stickiness: editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }), +]; function _normalizeOptions(options: editorCommon.IModelDecorationOptions): ModelDecorationOptions { if (options instanceof ModelDecorationOptions) { diff --git a/src/vs/editor/common/model/textModelWithMarkers.ts b/src/vs/editor/common/model/textModelWithMarkers.ts deleted file mode 100644 index 6100bfc3999..00000000000 --- a/src/vs/editor/common/model/textModelWithMarkers.ts +++ /dev/null @@ -1,174 +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 { IdGenerator } from 'vs/base/common/idGenerator'; -import { Position } from 'vs/editor/common/core/position'; -import { ITextModelWithMarkers, ITextModelCreationOptions } from 'vs/editor/common/editorCommon'; -import { LineMarker } from 'vs/editor/common/model/modelLine'; -import { TextModelWithTokens } from 'vs/editor/common/model/textModelWithTokens'; -import { LanguageIdentifier } from 'vs/editor/common/modes'; -import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource'; - -export interface IMarkerIdToMarkerMap { - [key: string]: LineMarker; -} - -export interface INewMarker { - internalDecorationId: number; - position: Position; - stickToPreviousCharacter: boolean; -} - -var _INSTANCE_COUNT = 0; - -export class TextModelWithMarkers extends TextModelWithTokens implements ITextModelWithMarkers { - - private _markerIdGenerator: IdGenerator; - protected _markerIdToMarker: IMarkerIdToMarkerMap; - - constructor(rawTextSource: IRawTextSource, creationOptions: ITextModelCreationOptions, languageIdentifier: LanguageIdentifier) { - super(rawTextSource, creationOptions, languageIdentifier); - this._markerIdGenerator = new IdGenerator((++_INSTANCE_COUNT) + ';'); - this._markerIdToMarker = Object.create(null); - } - - public dispose(): void { - this._markerIdToMarker = null; - super.dispose(); - } - - protected _resetValue(newValue: ITextSource): void { - super._resetValue(newValue); - - // Destroy all my markers - this._markerIdToMarker = Object.create(null); - } - - _addMarker(internalDecorationId: number, lineNumber: number, column: number, stickToPreviousCharacter: boolean): string { - var pos = this.validatePosition(new Position(lineNumber, column)); - - var marker = new LineMarker(this._markerIdGenerator.nextId(), internalDecorationId, pos, stickToPreviousCharacter); - this._markerIdToMarker[marker.id] = marker; - - this._lines[pos.lineNumber - 1].addMarker(marker); - - return marker.id; - } - - protected _addMarkers(newMarkers: INewMarker[]): LineMarker[] { - if (newMarkers.length === 0) { - return []; - } - - let markers: LineMarker[] = []; - for (let i = 0, len = newMarkers.length; i < len; i++) { - let newMarker = newMarkers[i]; - - let marker = new LineMarker(this._markerIdGenerator.nextId(), newMarker.internalDecorationId, newMarker.position, newMarker.stickToPreviousCharacter); - this._markerIdToMarker[marker.id] = marker; - - markers[i] = marker; - } - - let sortedMarkers = markers.slice(0); - sortedMarkers.sort((a, b) => { - return a.position.lineNumber - b.position.lineNumber; - }); - - let currentLineNumber = 0; - let currentMarkers: LineMarker[] = [], currentMarkersLen = 0; - for (let i = 0, len = sortedMarkers.length; i < len; i++) { - let marker = sortedMarkers[i]; - - if (marker.position.lineNumber !== currentLineNumber) { - if (currentLineNumber !== 0) { - this._lines[currentLineNumber - 1].addMarkers(currentMarkers); - } - currentLineNumber = marker.position.lineNumber; - currentMarkers.length = 0; - currentMarkersLen = 0; - } - - currentMarkers[currentMarkersLen++] = marker; - } - this._lines[currentLineNumber - 1].addMarkers(currentMarkers); - - return markers; - } - - _changeMarker(id: string, lineNumber: number, column: number): void { - let marker = this._markerIdToMarker[id]; - if (!marker) { - return; - } - - let newPos = this.validatePosition(new Position(lineNumber, column)); - - if (newPos.lineNumber !== marker.position.lineNumber) { - // Move marker between lines - this._lines[marker.position.lineNumber - 1].removeMarker(marker); - this._lines[newPos.lineNumber - 1].addMarker(marker); - } - - marker.setPosition(newPos); - } - - _changeMarkerStickiness(id: string, newStickToPreviousCharacter: boolean): void { - let marker = this._markerIdToMarker[id]; - if (!marker) { - return; - } - - marker.stickToPreviousCharacter = newStickToPreviousCharacter; - } - - _getMarker(id: string): Position { - let marker = this._markerIdToMarker[id]; - if (!marker) { - return null; - } - - return marker.position; - } - - _getMarkersCount(): number { - return Object.keys(this._markerIdToMarker).length; - } - - _removeMarker(id: string): void { - let marker = this._markerIdToMarker[id]; - if (!marker) { - return; - } - - this._lines[marker.position.lineNumber - 1].removeMarker(marker); - delete this._markerIdToMarker[id]; - } - - protected _removeMarkers(markers: LineMarker[]): void { - markers.sort((a, b) => { - return a.position.lineNumber - b.position.lineNumber; - }); - - let currentLineNumber = 0; - let currentMarkers: { [markerId: string]: boolean; } = null; - for (let i = 0, len = markers.length; i < len; i++) { - let marker = markers[i]; - delete this._markerIdToMarker[marker.id]; - - if (marker.position.lineNumber !== currentLineNumber) { - if (currentLineNumber !== 0) { - this._lines[currentLineNumber - 1].removeMarkers(currentMarkers); - } - currentLineNumber = marker.position.lineNumber; - currentMarkers = Object.create(null); - } - - currentMarkers[marker.id] = true; - } - this._lines[currentLineNumber - 1].removeMarkers(currentMarkers); - } -} diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index d4f31ffcc58..8d7b85746b9 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -22,6 +22,8 @@ import { getWordAtText } from 'vs/editor/common/model/wordHelper'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; +import { IndentRanges, computeRanges } from 'vs/editor/common/model/indentRanges'; +import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; class ModelTokensChangedEventBuilder { @@ -69,6 +71,9 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke private _invalidLineStartIndex: number; private _lastState: IState; + private _indentRanges: IndentRanges; + private _languageRegistryListener: IDisposable; + private _revalidateTokensTimeout: number; constructor(rawTextSource: IRawTextSource, creationOptions: editorCommon.ITextModelCreationOptions, languageIdentifier: LanguageIdentifier) { @@ -95,11 +100,20 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke this._revalidateTokensTimeout = -1; + this._languageRegistryListener = LanguageConfigurationRegistry.onDidChange((e) => { + if (e.languageIdentifier.id === this._languageIdentifier.id) { + this._resetIndentRanges(); + this._emitModelLanguageConfigurationEvent({}); + } + }); + this._resetTokenizationState(); + this._resetIndentRanges(); } public dispose(): void { this._tokenizationListener.dispose(); + this._languageRegistryListener.dispose(); this._clearTimers(); this._lastState = null; @@ -114,6 +128,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke super._resetValue(newValue); // Cancel tokenization, clear all tokens and begin tokenizing this._resetTokenizationState(); + this._resetIndentRanges(); } protected _resetTokenizationState(): void { @@ -225,6 +240,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke // Cancel tokenization, clear all tokens and begin tokenizing this._resetTokenizationState(); + this._resetIndentRanges(); this.emitModelTokensChangedEvent({ ranges: [{ @@ -233,6 +249,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke }] }); this._emitModelModeChangedEvent(e); + this._emitModelLanguageConfigurationEvent({}); } public getLanguageIdAtPosition(_lineNumber: number, _column: number): LanguageId { @@ -398,6 +415,12 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke } } + private _emitModelLanguageConfigurationEvent(e: textModelEvents.IModelLanguageConfigurationChangedEvent): void { + if (!this._isDisposing) { + this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged, e); + } + } + private _emitModelModeChangedEvent(e: textModelEvents.IModelLanguageChangedEvent): void { if (!this._isDisposing) { this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelLanguageChanged, e); @@ -814,4 +837,118 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke isOpen: modeBrackets.textIsOpenBracket[text] }; } + + protected _resetIndentRanges(): void { + this._indentRanges = null; + } + + private _getIndentRanges(): IndentRanges { + if (!this._indentRanges) { + let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id); + let offSide = foldingRules && foldingRules.offSide; + let markers = foldingRules && foldingRules.markers; + this._indentRanges = computeRanges(this, offSide, markers); + } + return this._indentRanges; + } + + public getIndentRanges(): IndentRanges { + return this._getIndentRanges(); + } + + private _computeIndentLevel(lineIndex: number): number { + return computeIndentLevel(this._lines[lineIndex].text, this._options.tabSize); + } + + public getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] { + this._assertNotDisposed(); + const lineCount = this.getLineCount(); + + if (startLineNumber < 1 || startLineNumber > lineCount) { + throw new Error('Illegal value ' + startLineNumber + ' for `startLineNumber`'); + } + if (endLineNumber < 1 || endLineNumber > lineCount) { + throw new Error('Illegal value ' + endLineNumber + ' for `endLineNumber`'); + } + + const foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id); + const offSide = foldingRules && foldingRules.offSide; + + let result: number[] = new Array(endLineNumber - startLineNumber + 1); + + let aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */ + let aboveContentLineIndent = -1; + + let belowContentLineIndex = -2; /* -2 is a marker for not having computed it */ + let belowContentLineIndent = -1; + + for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { + let resultIndex = lineNumber - startLineNumber; + + const currentIndent = this._computeIndentLevel(lineNumber - 1); + if (currentIndent >= 0) { + // This line has content (besides whitespace) + // Use the line's indent + aboveContentLineIndex = lineNumber - 1; + aboveContentLineIndent = currentIndent; + result[resultIndex] = Math.ceil(currentIndent / this._options.tabSize); + continue; + } + + if (aboveContentLineIndex === -2) { + aboveContentLineIndex = -1; + aboveContentLineIndent = -1; + + // must find previous line with content + for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) { + let indent = this._computeIndentLevel(lineIndex); + if (indent >= 0) { + aboveContentLineIndex = lineIndex; + aboveContentLineIndent = indent; + break; + } + } + } + + if (belowContentLineIndex !== -1 && (belowContentLineIndex === -2 || belowContentLineIndex < lineNumber - 1)) { + belowContentLineIndex = -1; + belowContentLineIndent = -1; + + // must find next line with content + for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) { + let indent = this._computeIndentLevel(lineIndex); + if (indent >= 0) { + belowContentLineIndex = lineIndex; + belowContentLineIndent = indent; + break; + } + } + } + + if (aboveContentLineIndent === -1 || belowContentLineIndent === -1) { + // At the top or bottom of the file + result[resultIndex] = 0; + + } else if (aboveContentLineIndent < belowContentLineIndent) { + // we are inside the region above + result[resultIndex] = (1 + Math.floor(aboveContentLineIndent / this._options.tabSize)); + + } else if (aboveContentLineIndent === belowContentLineIndent) { + // we are in between two regions + result[resultIndex] = Math.ceil(belowContentLineIndent / this._options.tabSize); + + } else { + + if (offSide) { + // same level as region below + result[resultIndex] = Math.ceil(belowContentLineIndent / this._options.tabSize); + } else { + // we are inside the region that ends below + result[resultIndex] = (1 + Math.floor(belowContentLineIndent / this._options.tabSize)); + } + + } + } + return result; + } } diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index da7802aaecd..9184a639da4 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -226,7 +226,7 @@ export interface ISuggestion { insertText: string; type: SuggestionType; detail?: string; - documentation?: string; + documentation?: string | IMarkdownString; filterText?: string; sortText?: string; noAutoAccept?: boolean; @@ -244,6 +244,23 @@ export interface ISuggestion { export interface ISuggestResult { suggestions: ISuggestion[]; incomplete?: boolean; + dispose?(): void; +} + +/** + * How a suggest provider was triggered. + */ +export enum SuggestTriggerKind { + Invoke = 0, + TriggerCharacter = 1 +} + +/** + * @internal + */ +export interface SuggestContext { + triggerKind: SuggestTriggerKind; + triggerCharacter?: string; } /** @@ -253,7 +270,7 @@ export interface ISuggestSupport { triggerCharacters?: string[]; - provideCompletionItems(model: editorCommon.IModel, position: Position, token: CancellationToken): ISuggestResult | Thenable; + provideCompletionItems(model: editorCommon.IModel, position: Position, context: SuggestContext, token: CancellationToken): ISuggestResult | Thenable; resolveCompletionItem?(model: editorCommon.IModel, position: Position, item: ISuggestion, token: CancellationToken): ISuggestion | Thenable; } @@ -284,7 +301,7 @@ export interface ParameterInformation { * The human-readable doc-comment of this signature. Will be shown * in the UI but can be omitted. */ - documentation?: string; + documentation?: string | IMarkdownString; } /** * Represents the signature of something callable. A signature @@ -301,7 +318,7 @@ export interface SignatureInformation { * The human-readable doc-comment of this signature. Will be shown * in the UI but can be omitted. */ - documentation?: string; + documentation?: string | IMarkdownString; /** * The parameters of this signature. */ @@ -679,17 +696,31 @@ export interface IColor { } /** - * A color formatter. + * String representations for a color */ -export interface IColorFormatter { - readonly supportsTransparency: boolean; - format(color: IColor): string; +export interface IColorPresentation { + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + label: string; + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. + */ + textEdit?: TextEdit; + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. + */ + additionalTextEdits?: TextEdit[]; } /** * A color range is a range in a text model which represents a color. */ -export interface IColorRange { +export interface IColorInformation { /** * The range within the model. @@ -700,11 +731,6 @@ export interface IColorRange { * The color represented in this range. */ color: IColor; - - /** - * The available formats for this specific color. - */ - formatters: IColorFormatter[]; } /** @@ -714,7 +740,11 @@ export interface DocumentColorProvider { /** * Provides the color ranges for a specific model. */ - provideColorRanges(model: editorCommon.IReadOnlyModel, token: CancellationToken): IColorRange[] | Thenable; + provideDocumentColors(model: editorCommon.IReadOnlyModel, token: CancellationToken): IColorInformation[] | Thenable; + /** + * Provide the string representations for a color. + */ + provideColorPresentations(model: editorCommon.IReadOnlyModel, colorInfo: IColorInformation, token: CancellationToken): IColorPresentation[] | Thenable; } export interface IResourceEdit { diff --git a/src/vs/editor/common/modes/languageConfiguration.ts b/src/vs/editor/common/modes/languageConfiguration.ts index 1fec47f4806..aaf139ee7ba 100644 --- a/src/vs/editor/common/modes/languageConfiguration.ts +++ b/src/vs/editor/common/modes/languageConfiguration.ts @@ -61,6 +61,12 @@ export interface LanguageConfiguration { * settings will be used. */ surroundingPairs?: IAutoClosingPair[]; + + /** + * The language's folding rules. + */ + folding?: FoldingRules; + /** * **Deprecated** Do not use. * @@ -89,6 +95,36 @@ export interface IndentationRule { * If a line matches this pattern, then its indentation should not be changed and it should not be evaluated against the other rules. */ unIndentedLinePattern?: RegExp; + +} + +/** + * Describes language specific folding markers such as '#region' and '#endregion'. + * The start and end regexes will be tested against the contents of all lines and must be designed efficiently: + * - the regex should start with '^' + * - regexp flags (i, g) are ignored + */ +export interface FoldingMarkers { + start: RegExp; + end: RegExp; +} + +/** + * Describes folding rules for a language. + */ +export interface FoldingRules { + /** + * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. + * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. + * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. + * If not set, `false` is used and empty lines belong to the previous block. + */ + offSide?: boolean; + + /** + * Region markers used by the language. + */ + markers?: FoldingMarkers; } /** diff --git a/src/vs/editor/common/modes/languageConfigurationRegistry.ts b/src/vs/editor/common/modes/languageConfigurationRegistry.ts index dd3e1ec8acc..f069921add2 100644 --- a/src/vs/editor/common/modes/languageConfigurationRegistry.ts +++ b/src/vs/editor/common/modes/languageConfigurationRegistry.ts @@ -18,7 +18,7 @@ import { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from 'vs/editor/common import { createScopedLineTokens } from 'vs/editor/common/modes/supports'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Range } from 'vs/editor/common/core/range'; -import { IndentAction, EnterAction, IAutoClosingPair, LanguageConfiguration, IndentationRule } from 'vs/editor/common/modes/languageConfiguration'; +import { IndentAction, EnterAction, IAutoClosingPair, LanguageConfiguration, IndentationRule, FoldingRules } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageIdentifier, LanguageId } from 'vs/editor/common/modes'; /** @@ -55,6 +55,7 @@ export class RichEditSupport { public readonly indentRulesSupport: IndentRulesSupport; public readonly brackets: RichEditBrackets; public readonly indentationRules: IndentationRule; + public readonly foldingRules: FoldingRules; constructor(languageIdentifier: LanguageIdentifier, previous: RichEditSupport, rawConf: LanguageConfiguration) { @@ -82,6 +83,8 @@ export class RichEditSupport { if (this._conf.indentationRules) { this.indentRulesSupport = new IndentRulesSupport(this._conf.indentationRules); } + + this.foldingRules = this._conf.folding || {}; } private static _mergeConf(prev: LanguageConfiguration, current: LanguageConfiguration): LanguageConfiguration { @@ -93,6 +96,7 @@ export class RichEditSupport { onEnterRules: (prev ? current.onEnterRules || prev.onEnterRules : current.onEnterRules), autoClosingPairs: (prev ? current.autoClosingPairs || prev.autoClosingPairs : current.autoClosingPairs), surroundingPairs: (prev ? current.surroundingPairs || prev.surroundingPairs : current.surroundingPairs), + folding: (prev ? current.folding || prev.folding : current.folding), __electricCharacterSupport: (prev ? current.__electricCharacterSupport || prev.__electricCharacterSupport : current.__electricCharacterSupport), }; } @@ -143,12 +147,16 @@ export class RichEditSupport { } } +export class LanguageConfigurationChangeEvent { + languageIdentifier: LanguageIdentifier; +} + export class LanguageConfigurationRegistryImpl { private _entries: RichEditSupport[]; - private _onDidChange: Emitter = new Emitter(); - public onDidChange: Event = this._onDidChange.event; + private _onDidChange: Emitter = new Emitter(); + public onDidChange: Event = this._onDidChange.event; constructor() { this._entries = []; @@ -158,12 +166,12 @@ export class LanguageConfigurationRegistryImpl { let previous = this._getRichEditSupport(languageIdentifier.id); let current = new RichEditSupport(languageIdentifier, previous, configuration); this._entries[languageIdentifier.id] = current; - this._onDidChange.fire(void 0); + this._onDidChange.fire({ languageIdentifier }); return { dispose: () => { if (this._entries[languageIdentifier.id] === current) { this._entries[languageIdentifier.id] = previous; - this._onDidChange.fire(void 0); + this._onDidChange.fire({ languageIdentifier }); } } }; @@ -268,9 +276,15 @@ export class LanguageConfigurationRegistryImpl { return ensureValidWordDefinition(value.wordDefinition || null); } + public getFoldingRules(languageId: LanguageId): FoldingRules { + let value = this._getRichEditSupport(languageId); + if (!value) { + return {}; + } + return value.foldingRules; + } - - // beigin Indent Rules + // begin Indent Rules public getIndentRulesSupport(languageId: LanguageId): IndentRulesSupport { let value = this._getRichEditSupport(languageId); diff --git a/src/vs/editor/common/modes/languageSelector.ts b/src/vs/editor/common/modes/languageSelector.ts index 335e08e8b2e..356f454ecf4 100644 --- a/src/vs/editor/common/modes/languageSelector.ts +++ b/src/vs/editor/common/modes/languageSelector.ts @@ -6,12 +6,12 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import { match as matchGlobPattern } from 'vs/base/common/glob'; // TODO@Alex +import { match as matchGlobPattern, IRelativePattern } from 'vs/base/common/glob'; // TODO@Alex export interface LanguageFilter { language?: string; scheme?: string; - pattern?: string; + pattern?: string | IRelativePattern; } export type LanguageSelector = string | LanguageFilter | (string | LanguageFilter)[]; diff --git a/src/vs/editor/common/modes/linkComputer.ts b/src/vs/editor/common/modes/linkComputer.ts index 43d08b55be2..a44b8970af3 100644 --- a/src/vs/editor/common/modes/linkComputer.ts +++ b/src/vs/editor/common/modes/linkComputer.ts @@ -156,6 +156,23 @@ class LinkComputer { lastIncludedCharIndex--; } while (lastIncludedCharIndex > linkBeginIndex); + // Handle links enclosed in parens, square brackets and curlys. + if (linkBeginIndex > 0) { + const charCodeBeforeLink = line.charCodeAt(linkBeginIndex - 1); + const lastCharCodeInLink = line.charCodeAt(lastIncludedCharIndex); + + if ( + (charCodeBeforeLink === CharCode.OpenParen && lastCharCodeInLink === CharCode.CloseParen) + || (charCodeBeforeLink === CharCode.OpenSquareBracket && lastCharCodeInLink === CharCode.CloseSquareBracket) + || (charCodeBeforeLink === CharCode.OpenCurlyBrace && lastCharCodeInLink === CharCode.CloseCurlyBrace) + ) { + // Do not end in ) if ( is before the link start + // Do not end in ] if [ is before the link start + // Do not end in } if { is before the link start + lastIncludedCharIndex--; + } + } + return { range: { startLineNumber: lineNumber, diff --git a/src/vs/editor/common/modes/supports/indentRules.ts b/src/vs/editor/common/modes/supports/indentRules.ts index b88860741b1..607c3ad1be3 100644 --- a/src/vs/editor/common/modes/supports/indentRules.ts +++ b/src/vs/editor/common/modes/supports/indentRules.ts @@ -12,7 +12,7 @@ export const enum IndentConsts { DECREASE_MASK = 0b00000010, INDENT_NEXTLINE_MASK = 0b00000100, UNINDENT_MASK = 0b00001000, -}; +} export class IndentRulesSupport { diff --git a/src/vs/editor/common/modes/supports/onEnter.ts b/src/vs/editor/common/modes/supports/onEnter.ts index 2287829bb1d..be11c521278 100644 --- a/src/vs/editor/common/modes/supports/onEnter.ts +++ b/src/vs/editor/common/modes/supports/onEnter.ts @@ -24,6 +24,7 @@ interface IProcessedBracketPair { export class OnEnterSupport { private readonly _brackets: IProcessedBracketPair[]; + // @ts-ignore unused property private readonly _indentationRules: IndentationRule; private readonly _regExpRules: OnEnterRule[]; diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index 5654bd38526..21b1a45c5ff 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -344,7 +344,7 @@ export abstract class BaseEditorSimpleWorker { private static _diffLimit = 10000; - public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[], ranges: IRange[]): TPromise { + public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): TPromise { const model = this._getModel(modelUrl); if (!model) { return TPromise.as(edits); diff --git a/src/vs/editor/common/services/editorWorkerService.ts b/src/vs/editor/common/services/editorWorkerService.ts index 430f7b9d1b6..e1141d43846 100644 --- a/src/vs/editor/common/services/editorWorkerService.ts +++ b/src/vs/editor/common/services/editorWorkerService.ts @@ -23,7 +23,7 @@ export interface IEditorWorkerService { canComputeDirtyDiff(original: URI, modified: URI): boolean; computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): TPromise; - computeMoreMinimalEdits(resource: URI, edits: TextEdit[], ranges: IRange[]): TPromise; + computeMoreMinimalEdits(resource: URI, edits: TextEdit[]): TPromise; canNavigateValueSet(resource: URI): boolean; navigateValueSet(resource: URI, range: IRange, up: boolean): TPromise; diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index 830c9ea99cd..ed44a216e56 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -90,14 +90,14 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker return this._workerManager.withWorker().then(client => client.computeDirtyDiff(original, modified, ignoreTrimWhitespace)); } - public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[], ranges: IRange[]): TPromise { + public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[]): TPromise { if (!Array.isArray(edits) || edits.length === 0) { return TPromise.as(edits); } else { if (!canSyncModel(this._modelService, resource)) { return TPromise.as(edits); // File too large } - return this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits, ranges)); + return this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits)); } } @@ -114,6 +114,7 @@ class WordBasedCompletionItemProvider implements modes.ISuggestSupport { private readonly _workerManager: WorkerManager; private readonly _configurationService: ITextResourceConfigurationService; + // @ts-ignore unused injected service private readonly _modeService: IModeService; private readonly _modelService: IModelService; @@ -395,9 +396,9 @@ export class EditorWorkerClient extends Disposable { }); } - public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[], ranges: IRange[]): TPromise { + public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[]): TPromise { return this._withSyncedResources([resource]).then(proxy => { - return proxy.computeMoreMinimalEdits(resource.toString(), edits, ranges); + return proxy.computeMoreMinimalEdits(resource.toString(), edits); }); } diff --git a/src/vs/editor/common/services/languagesRegistry.ts b/src/vs/editor/common/services/languagesRegistry.ts index 0159f694c70..33a9ecd1c6f 100644 --- a/src/vs/editor/common/services/languagesRegistry.ts +++ b/src/vs/editor/common/services/languagesRegistry.ts @@ -36,13 +36,16 @@ export class LanguagesRegistry { private _nameMap: { [name: string]: LanguageIdentifier; }; private _lowercaseNameMap: { [name: string]: LanguageIdentifier; }; - constructor(useModesRegistry = true) { + private _warnOnOverwrite: boolean; + + constructor(useModesRegistry = true, warnOnOverwrite = false) { this._nextLanguageId = 1; this._languages = {}; this._mimeTypesMap = {}; this._nameMap = {}; this._lowercaseNameMap = {}; this._languageIds = []; + this._warnOnOverwrite = warnOnOverwrite; if (useModesRegistry) { this._registerLanguages(ModesRegistry.getLanguages()); @@ -100,10 +103,10 @@ export class LanguagesRegistry { this._languages[langId] = resolvedLanguage; } - LanguagesRegistry._mergeLanguage(resolvedLanguage, lang); + this._mergeLanguage(resolvedLanguage, lang); } - private static _mergeLanguage(resolvedLanguage: IResolvedLanguage, lang: ILanguageExtensionPoint): void { + private _mergeLanguage(resolvedLanguage: IResolvedLanguage, lang: ILanguageExtensionPoint): void { const langId = lang.id; let primaryMime: string = null; @@ -124,21 +127,21 @@ export class LanguagesRegistry { if (Array.isArray(lang.extensions)) { for (let extension of lang.extensions) { - mime.registerTextMime({ id: langId, mime: primaryMime, extension: extension }); + mime.registerTextMime({ id: langId, mime: primaryMime, extension: extension }, this._warnOnOverwrite); resolvedLanguage.extensions.push(extension); } } if (Array.isArray(lang.filenames)) { for (let filename of lang.filenames) { - mime.registerTextMime({ id: langId, mime: primaryMime, filename: filename }); + mime.registerTextMime({ id: langId, mime: primaryMime, filename: filename }, this._warnOnOverwrite); resolvedLanguage.filenames.push(filename); } } if (Array.isArray(lang.filenamePatterns)) { for (let filenamePattern of lang.filenamePatterns) { - mime.registerTextMime({ id: langId, mime: primaryMime, filepattern: filenamePattern }); + mime.registerTextMime({ id: langId, mime: primaryMime, filepattern: filenamePattern }, this._warnOnOverwrite); } } @@ -150,7 +153,7 @@ export class LanguagesRegistry { try { let firstLineRegex = new RegExp(firstLineRegexStr); if (!strings.regExpLeadsToEndlessLoop(firstLineRegex)) { - mime.registerTextMime({ id: langId, mime: primaryMime, firstline: firstLineRegex }); + mime.registerTextMime({ id: langId, mime: primaryMime, firstline: firstLineRegex }, this._warnOnOverwrite); } } catch (err) { // Most likely, the regex was bad diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index d75ed1aafb6..70cfd572e22 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -21,10 +21,10 @@ export class ModeServiceImpl implements IModeService { private readonly _onDidCreateMode: Emitter = new Emitter(); public readonly onDidCreateMode: Event = this._onDidCreateMode.event; - constructor() { + constructor(warnOnOverwrite = false) { this._instantiatedModes = {}; - this._registry = new LanguagesRegistry(); + this._registry = new LanguagesRegistry(true, warnOnOverwrite); } protected _onReady(): TPromise { diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 3436b8653c4..caaa8470b7e 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -26,11 +26,11 @@ import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegistry'; import { IRawTextSource, TextSource, RawTextSource, ITextSource } from 'vs/editor/common/model/textSource'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; -import { ClassName } from 'vs/editor/common/model/textModelWithDecorations'; +import { ClassName } from 'vs/editor/common/model/intervalTree'; import { ISequence, LcsDiff } from 'vs/base/common/diff/diff'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService'; -import { overviewRulerWarning, overviewRulerError } from 'vs/editor/common/view/editorColorRegistry'; +import { overviewRulerWarning, overviewRulerError, overviewRulerInfo } from 'vs/editor/common/view/editorColorRegistry'; function MODEL_ID(resource: URI): string { return resource.toString(); @@ -125,11 +125,15 @@ class ModelMarkerHandler { // do something break; case Severity.Warning: - case Severity.Info: className = ClassName.EditorWarningDecoration; color = themeColorFromId(overviewRulerWarning); darkColor = themeColorFromId(overviewRulerWarning); break; + case Severity.Info: + className = ClassName.EditorInfoDecoration; + color = themeColorFromId(overviewRulerInfo); + darkColor = themeColorFromId(overviewRulerInfo); + break; case Severity.Error: default: className = ClassName.EditorErrorDecoration; @@ -220,7 +224,7 @@ export class ModelServiceImpl implements IModelService { this._markerServiceSubscription = this._markerService.onMarkerChanged(this._handleMarkerChange, this); } - this._configurationServiceSubscription = this._configurationService.onDidUpdateConfiguration(e => this._updateModelOptions()); + this._configurationServiceSubscription = this._configurationService.onDidChangeConfiguration(e => this._updateModelOptions()); this._updateModelOptions(); } @@ -268,7 +272,7 @@ export class ModelServiceImpl implements IModelService { public getCreationOptions(language: string, resource: URI): editorCommon.ITextModelCreationOptions { let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource]; if (!creationOptions) { - creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getConfiguration(null, { overrideIdentifier: language, resource })); + creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getConfiguration({ overrideIdentifier: language, resource })); this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions; } return creationOptions; diff --git a/src/vs/editor/common/services/resourceConfiguration.ts b/src/vs/editor/common/services/resourceConfiguration.ts index 2a959539e9b..e65c4a12104 100644 --- a/src/vs/editor/common/services/resourceConfiguration.ts +++ b/src/vs/editor/common/services/resourceConfiguration.ts @@ -7,6 +7,7 @@ import Event from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IPosition } from 'vs/editor/common/core/position'; +import { IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; export const ITextResourceConfigurationService = createDecorator('textResourceConfigurationService'); @@ -17,7 +18,7 @@ export interface ITextResourceConfigurationService { /** * Event that fires when the configuration changes. */ - onDidUpdateConfiguration: Event; + onDidChangeConfiguration: Event; /** * Fetches the appropriate section of the for the given resource with appropriate overrides (e.g. language). diff --git a/src/vs/editor/common/services/resourceConfigurationImpl.ts b/src/vs/editor/common/services/resourceConfigurationImpl.ts index 453395b6488..00c24a097a8 100644 --- a/src/vs/editor/common/services/resourceConfigurationImpl.ts +++ b/src/vs/editor/common/services/resourceConfigurationImpl.ts @@ -6,7 +6,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -16,8 +16,8 @@ export class TextResourceConfigurationService extends Disposable implements ITex public _serviceBrand: any; - private readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; constructor( @IConfigurationService private configurationService: IConfigurationService, @@ -25,11 +25,11 @@ export class TextResourceConfigurationService extends Disposable implements ITex @IModeService private modeService: IModeService, ) { super(); - this._register(this.configurationService.onDidUpdateConfiguration(() => this._onDidUpdateConfiguration.fire())); + this._register(this.configurationService.onDidChangeConfiguration(e => this._onDidChangeConfiguration.fire(e))); } - getConfiguration(resource: URI, section?: string): T - getConfiguration(resource: URI, at?: IPosition, section?: string): T + getConfiguration(resource: URI, section?: string): T; + getConfiguration(resource: URI, at?: IPosition, section?: string): T; getConfiguration(resource: URI, arg2?: any, arg3?: any): T { const position: IPosition = Position.isIPosition(arg2) ? arg2 : null; const section: string = position ? (typeof arg3 === 'string' ? arg3 : void 0) : (typeof arg2 === 'string' ? arg2 : void 0); diff --git a/src/vs/editor/common/services/webWorker.ts b/src/vs/editor/common/services/webWorker.ts index f44ecfe24db..670357d8030 100644 --- a/src/vs/editor/common/services/webWorker.ts +++ b/src/vs/editor/common/services/webWorker.ts @@ -84,7 +84,7 @@ class MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWork }; }; - let foreignProxy = {}; + let foreignProxy = {} as T; for (let i = 0; i < foreignMethods.length; i++) { foreignProxy[foreignMethods[i]] = createProxyMethod(foreignMethods[i], proxyMethodRequest); } diff --git a/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts index 794b815d4fd..3fae633c29b 100644 --- a/src/vs/editor/common/view/editorColorRegistry.ts +++ b/src/vs/editor/common/view/editorColorRegistry.ts @@ -36,6 +36,9 @@ export const editorErrorBorder = registerColor('editorError.border', { dark: nul export const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#008000', light: '#008000', hc: null }, nls.localize('warningForeground', 'Foreground color of warning squigglies in the editor.')); export const editorWarningBorder = registerColor('editorWarning.border', { dark: null, light: null, hc: Color.fromHex('#71B771').transparent(0.8) }, nls.localize('warningBorder', 'Border color of warning squigglies in the editor.')); +export const editorInfoForeground = registerColor('editorInfo.foreground', { dark: '#008000', light: '#008000', hc: null }, nls.localize('infoForeground', 'Foreground color of info squigglies in the editor.')); +export const editorInfoBorder = registerColor('editorInfo.border', { dark: null, light: null, hc: Color.fromHex('#71B771').transparent(0.8) }, nls.localize('infoBorder', 'Border color of info squigglies in the editor.')); + const rulerRangeDefault = new Color(new RGBA(0, 122, 204, 0.6)); export const overviewRulerRangeHighlight = registerColor('editorOverviewRuler.rangeHighlightForeground', { dark: rulerRangeDefault, light: rulerRangeDefault, hc: rulerRangeDefault }, nls.localize('overviewRulerRangeHighlight', 'Overview ruler marker color for range highlights.')); export const overviewRulerError = registerColor('editorOverviewRuler.errorForeground', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hc: new Color(new RGBA(255, 50, 50, 1)) }, nls.localize('overviewRuleError', 'Overview ruler marker color for errors.')); diff --git a/src/vs/editor/common/view/viewEvents.ts b/src/vs/editor/common/view/viewEvents.ts index 4034473fa40..46244956a30 100644 --- a/src/vs/editor/common/view/viewEvents.ts +++ b/src/vs/editor/common/view/viewEvents.ts @@ -27,7 +27,8 @@ export const enum ViewEventType { ViewTokensChanged = 12, ViewTokensColorsChanged = 13, ViewZonesChanged = 14, - ViewThemeChanged = 15 + ViewThemeChanged = 15, + ViewLanguageConfigurationChanged = 16 } export class ViewConfigurationChangedEvent { @@ -282,6 +283,14 @@ export class ViewZonesChangedEvent { } } +export class ViewLanguageConfigurationEvent { + + public readonly type = ViewEventType.ViewLanguageConfigurationChanged; + + constructor() { + } +} + export type ViewEvent = ( ViewConfigurationChangedEvent | ViewCursorStateChangedEvent @@ -298,6 +307,7 @@ export type ViewEvent = ( | ViewTokensColorsChangedEvent | ViewZonesChangedEvent | ViewThemeChangedEvent + | ViewLanguageConfigurationEvent ); export interface IViewEventListener { diff --git a/src/vs/editor/common/viewLayout/lineDecorations.ts b/src/vs/editor/common/viewLayout/lineDecorations.ts index 23e06adf2cd..bb94266103c 100644 --- a/src/vs/editor/common/viewLayout/lineDecorations.ts +++ b/src/vs/editor/common/viewLayout/lineDecorations.ts @@ -6,6 +6,7 @@ import { InlineDecoration } from 'vs/editor/common/viewModel/viewModel'; import { Constants } from 'vs/editor/common/core/uint'; +import * as strings from 'vs/base/common/strings'; export class LineDecoration { _lineDecorationBrand: void; @@ -172,7 +173,7 @@ export class LineDecorationsNormalizer { /** * Normalize line decorations. Overlapping decorations will generate multiple segments */ - public static normalize(lineDecorations: LineDecoration[]): DecorationSegment[] { + public static normalize(lineContent: string, lineDecorations: LineDecoration[]): DecorationSegment[] { if (lineDecorations.length === 0) { return []; } @@ -184,16 +185,34 @@ export class LineDecorationsNormalizer { for (let i = 0, len = lineDecorations.length; i < len; i++) { let d = lineDecorations[i]; + let startColumn = d.startColumn; + let endColumn = d.endColumn; + let className = d.className; - let currentStartOffset = d.startColumn - 1; - let currentEndOffset = d.endColumn - 2; + // If the position would end up in the middle of a high-low surrogate pair, we move it to before the pair + if (startColumn > 1) { + const charCodeBefore = lineContent.charCodeAt(startColumn - 2); + if (strings.isHighSurrogate(charCodeBefore)) { + startColumn--; + } + } + + if (endColumn > 1) { + const charCodeBefore = lineContent.charCodeAt(endColumn - 2); + if (strings.isHighSurrogate(charCodeBefore)) { + endColumn--; + } + } + + let currentStartOffset = startColumn - 1; + let currentEndOffset = endColumn - 2; nextStartOffset = stack.consumeLowerThan(currentStartOffset, nextStartOffset, result); if (stack.count === 0) { nextStartOffset = currentStartOffset; } - stack.insert(currentEndOffset, d.className); + stack.insert(currentEndOffset, className); } stack.consumeLowerThan(Constants.MAX_SAFE_SMALL_INTEGER, nextStartOffset, result); diff --git a/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts index db18c17a890..f0923f2e775 100644 --- a/src/vs/editor/common/viewLayout/viewLineRenderer.ts +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -531,7 +531,7 @@ function _applyRenderWhitespace(lineContent: string, len: number, tokens: LinePa */ function _applyInlineDecorations(lineContent: string, len: number, tokens: LinePart[], _lineDecorations: LineDecoration[]): LinePart[] { _lineDecorations.sort(LineDecoration.compare); - const lineDecorations = LineDecorationsNormalizer.normalize(_lineDecorations); + const lineDecorations = LineDecorationsNormalizer.normalize(lineContent, _lineDecorations); const lineDecorationsLen = lineDecorations.length; let lineDecorationIndex = 0; @@ -618,7 +618,6 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render { let _charIndex = charIndex; let _tabsCharDelta = tabsCharDelta; - let _charOffsetInPart = charOffsetInPart; for (; _charIndex < partEndIndex; _charIndex++) { const charCode = lineContent.charCodeAt(_charIndex); @@ -626,20 +625,20 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render if (charCode === CharCode.Tab) { let insertSpacesCount = tabSize - (_charIndex + _tabsCharDelta) % tabSize; _tabsCharDelta += insertSpacesCount - 1; - _charOffsetInPart += insertSpacesCount - 1; partContentCnt += insertSpacesCount; } else { partContentCnt++; } - - _charOffsetInPart++; } } - if (!fontIsMonospace && !containsForeignElements) { - sb.appendASCIIString(' style="width:'); - sb.appendASCIIString(String(spaceWidth * partContentCnt)); - sb.appendASCIIString('px"'); + if (!fontIsMonospace) { + const partIsOnlyWhitespace = (partType === 'vs-whitespace'); + if (partIsOnlyWhitespace || !containsForeignElements) { + sb.appendASCIIString(' style="width:'); + sb.appendASCIIString(String(spaceWidth * partContentCnt)); + sb.appendASCIIString('px"'); + } } sb.appendASCII(CharCode.GreaterThan); diff --git a/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts b/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts index d301593e8c1..b3e04d5a0af 100644 --- a/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts +++ b/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts @@ -100,8 +100,8 @@ export class CharacterHardWrappingLineMapperFactory implements ILineMapperFactor wrappedTextIndent += '\t'; wrappedTextIndentVisibleColumn = CharacterHardWrappingLineMapperFactory.nextVisibleColumn(wrappedTextIndentVisibleColumn, tabSize, true, 1); } - // Force sticking to beginning of line if indentColumn > 66% breakingColumn - if (wrappedTextIndentVisibleColumn > 1 / 2 * breakingColumn) { + // Force sticking to beginning of line if no character would fit except for the indentation + if (wrappedTextIndentVisibleColumn + columnsForFullWidthChar > breakingColumn) { wrappedTextIndent = ''; wrappedTextIndentVisibleColumn = 0; } diff --git a/src/vs/editor/common/viewModel/splitLinesCollection.ts b/src/vs/editor/common/viewModel/splitLinesCollection.ts index 5cf9d2c728a..2ee75a1ea59 100644 --- a/src/vs/editor/common/viewModel/splitLinesCollection.ts +++ b/src/vs/editor/common/viewModel/splitLinesCollection.ts @@ -10,10 +10,12 @@ import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { PrefixSumComputerWithCache } from 'vs/editor/common/viewModel/prefixSumComputer'; -import { ViewLineData, ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel'; +import { ViewLineData, ICoordinatesConverter, IOverviewRulerDecorations } from 'vs/editor/common/viewModel/viewModel'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { WrappingIndent } from 'vs/editor/common/config/editorOptions'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { ModelDecorationOptions, ModelDecorationOverviewRulerOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { ThemeColor, ITheme } from 'vs/platform/theme/common/themeService'; +import { Color } from 'vs/base/common/color'; export class OutputPosition { _outputPositionBrand: void; @@ -57,6 +59,7 @@ export interface ISplitLine { getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number; getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position; + getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number; } export interface IViewModelLinesCollection { @@ -76,12 +79,15 @@ export interface IViewModelLinesCollection { getViewLineCount(): number; warmUpLookupCache(viewStartLineNumber: number, viewEndLineNumber: number): void; - getViewLineIndentGuide(viewLineNumber: number): number; + getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[]; getViewLineContent(viewLineNumber: number): string; getViewLineMinColumn(viewLineNumber: number): number; getViewLineMaxColumn(viewLineNumber: number): number; getViewLineData(viewLineNumber: number): ViewLineData; getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): ViewLineData[]; + + getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: ITheme): IOverviewRulerDecorations; + getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): editorCommon.IModelDecoration[]; } export class CoordinatesConverter implements ICoordinatesConverter { @@ -493,11 +499,63 @@ export class SplitLinesCollection implements IViewModelLinesCollection { this.prefixSumComputer.warmUpCache(viewStartLineNumber - 1, viewEndLineNumber - 1); } - public getViewLineIndentGuide(viewLineNumber: number): number { + public getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] { this._ensureValidState(); - viewLineNumber = this._toValidViewLineNumber(viewLineNumber); - let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); - return this.model.getLineIndentGuide(r.index + 1); + viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber); + viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber); + + const modelStart = this.convertViewPositionToModelPosition(viewStartLineNumber, this.getViewLineMinColumn(viewStartLineNumber)); + const modelEnd = this.convertViewPositionToModelPosition(viewEndLineNumber, this.getViewLineMaxColumn(viewEndLineNumber)); + + let result: number[] = []; + let resultRepeatCount: number[] = []; + const modelStartLineIndex = modelStart.lineNumber - 1; + const modelEndLineIndex = modelEnd.lineNumber - 1; + + let reqStart: Position = null; + for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) { + const line = this.lines[modelLineIndex]; + if (line.isVisible()) { + let count = 0; + if (modelLineIndex === modelStartLineIndex) { + let viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, modelStart.column); + let viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1)); + count = viewLineEndIndex - viewLineStartIndex + 1; + } else { + let viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, 1); + let viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1)); + count = viewLineEndIndex - viewLineStartIndex + 1; + } + resultRepeatCount.push(count); + // merge into previous request + if (reqStart === null) { + reqStart = new Position(modelLineIndex + 1, 0); + } + } else { + // hit invisible line => flush request + if (reqStart !== null) { + result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelLineIndex)); + reqStart = null; + } + } + } + + if (reqStart !== null) { + result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelEnd.lineNumber)); + reqStart = null; + } + + const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1; + let viewIndents = new Array(viewLineCount); + let currIndex = 0; + for (let i = 0, len = result.length; i < len; i++) { + let value = result[i]; + let count = Math.min(viewLineCount - currIndex, resultRepeatCount[i]); + for (let j = 0; j < count; j++) { + viewIndents[currIndex++] = value; + } + } + return viewIndents; } public getViewLineContent(viewLineNumber: number): string { @@ -650,6 +708,84 @@ export class SplitLinesCollection implements IViewModelLinesCollection { // console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r); return r; } + + private _getViewLineNumberForModelPosition(inputLineNumber: number, inputColumn: number): number { + let lineIndex = inputLineNumber - 1; + if (this.lines[lineIndex].isVisible()) { + // this model line is visible + const deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1)); + return this.lines[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, inputColumn); + } + + // this model line is not visible + while (lineIndex > 0 && !this.lines[lineIndex].isVisible()) { + lineIndex--; + } + if (lineIndex === 0 && !this.lines[lineIndex].isVisible()) { + // Could not reach a real line + return 1; + } + const deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1)); + return this.lines[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1)); + } + + public getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: ITheme): IOverviewRulerDecorations { + const decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation); + const result = new OverviewRulerDecorations(); + for (let i = 0, len = decorations.length; i < len; i++) { + const decoration = decorations[i]; + const opts = decoration.options.overviewRuler; + const lane = opts.position; + if (lane === 0) { + continue; + } + const color = resolveColor(opts, theme); + const viewStartLineNumber = this._getViewLineNumberForModelPosition(decoration.range.startLineNumber, decoration.range.startColumn); + const viewEndLineNumber = this._getViewLineNumberForModelPosition(decoration.range.endLineNumber, decoration.range.endColumn); + + result.accept(color, viewStartLineNumber, viewEndLineNumber, lane); + } + return result.result; + } + + public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): editorCommon.IModelDecoration[] { + const modelStart = this.convertViewPositionToModelPosition(range.startLineNumber, range.startColumn); + const modelEnd = this.convertViewPositionToModelPosition(range.endLineNumber, range.endColumn); + + if (modelEnd.lineNumber - modelStart.lineNumber <= range.endLineNumber - range.startLineNumber) { + // most likely there are no hidden lines => fast path + return this.model.getDecorationsInRange(new Range(modelStart.lineNumber, modelStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation); + } + + let result: editorCommon.IModelDecoration[] = []; + const modelStartLineIndex = modelStart.lineNumber - 1; + const modelEndLineIndex = modelEnd.lineNumber - 1; + + let reqStart: Position = null; + for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) { + const line = this.lines[modelLineIndex]; + if (line.isVisible()) { + // merge into previous request + if (reqStart === null) { + reqStart = new Position(modelLineIndex + 1, modelLineIndex === modelStartLineIndex ? modelStart.column : 1); + } + } else { + // hit invisible line => flush request + if (reqStart !== null) { + const maxLineColumn = this.model.getLineMaxColumn(modelLineIndex); + result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex, maxLineColumn), ownerId, filterOutValidation)); + reqStart = null; + } + } + } + + if (reqStart !== null) { + result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation)); + reqStart = null; + } + + return result; + } } class VisibleIdentitySplitLine implements ISplitLine { @@ -711,6 +847,10 @@ class VisibleIdentitySplitLine implements ISplitLine { public getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position { return new Position(deltaLineNumber, inputColumn); } + + public getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number { + return deltaLineNumber; + } } class InvisibleIdentitySplitLine implements ISplitLine { @@ -761,6 +901,10 @@ class InvisibleIdentitySplitLine implements ISplitLine { public getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position { throw new Error('Not supported'); } + + public getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number { + throw new Error('Not supported'); + } } export class SplitLine implements ISplitLine { @@ -914,6 +1058,14 @@ export class SplitLine implements ISplitLine { // console.log('in -> out ' + deltaLineNumber + ',' + inputColumn + ' ===> ' + (deltaLineNumber+outputLineIndex) + ',' + outputColumn); return new Position(deltaLineNumber + outputLineIndex, outputColumn); } + + public getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number { + if (!this._isVisible) { + throw new Error('Not supported'); + } + const r = this.positionMapper.getOutputPositionOfInputOffset(inputColumn - 1); + return (deltaLineNumber + r.outputLineIndex); + } } function createSplitLine(linePositionMapperFactory: ILineMapperFactory, text: string, tabSize: number, wrappingColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent, isVisible: boolean): ISplitLine { @@ -1050,8 +1202,13 @@ export class IdentityLinesCollection implements IViewModelLinesCollection { public warmUpLookupCache(viewStartLineNumber: number, viewEndLineNumber: number): void { } - public getViewLineIndentGuide(viewLineNumber: number): number { - return 0; + public getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] { + const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1; + let result = new Array(viewLineCount); + for (let i = 0; i < viewLineCount; i++) { + result[i] = 0; + } + return result; } public getViewLineContent(viewLineNumber: number): string { @@ -1093,4 +1250,77 @@ export class IdentityLinesCollection implements IViewModelLinesCollection { return result; } + + public getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: ITheme): IOverviewRulerDecorations { + const decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation); + const result = new OverviewRulerDecorations(); + for (let i = 0, len = decorations.length; i < len; i++) { + const decoration = decorations[i]; + const opts = decoration.options.overviewRuler; + const lane = opts.position; + if (lane === 0) { + continue; + } + const color = resolveColor(opts, theme); + const viewStartLineNumber = decoration.range.startLineNumber; + const viewEndLineNumber = decoration.range.endLineNumber; + + result.accept(color, viewStartLineNumber, viewEndLineNumber, lane); + } + return result.result; + } + + public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): editorCommon.IModelDecoration[] { + return this.model.getDecorationsInRange(range, ownerId, filterOutValidation); + } +} + +class OverviewRulerDecorations { + + readonly result: IOverviewRulerDecorations = Object.create(null); + + constructor() { + } + + public accept(color: string, startLineNumber: number, endLineNumber: number, lane: number): void { + let prev = this.result[color]; + + if (prev) { + const prevLane = prev[prev.length - 3]; + const prevEndLineNumber = prev[prev.length - 1]; + if (prevLane === lane && prevEndLineNumber + 1 >= startLineNumber) { + // merge into prev + if (endLineNumber > prevEndLineNumber) { + prev[prev.length - 1] = endLineNumber; + } + return; + } + + // push + prev.push(lane, startLineNumber, endLineNumber); + } else { + this.result[color] = [lane, startLineNumber, endLineNumber]; + } + } +} + + +function resolveColor(opts: ModelDecorationOverviewRulerOptions, theme: ITheme): string { + if (!opts._resolvedColor) { + const themeType = theme.type; + const color = (themeType === 'dark' ? opts.darkColor : themeType === 'light' ? opts.color : opts.hcColor); + opts._resolvedColor = resolveRulerColor(color, theme); + } + return opts._resolvedColor; +} + +function resolveRulerColor(color: string | ThemeColor, theme: ITheme): string { + if (typeof color === 'string') { + return color; + } + let c = color ? theme.getColor(color.id) : null; + if (!c) { + c = Color.transparent; + } + return c.toString(); } diff --git a/src/vs/editor/common/viewModel/viewEventHandler.ts b/src/vs/editor/common/viewModel/viewEventHandler.ts index a3e03e9005d..874b206787e 100644 --- a/src/vs/editor/common/viewModel/viewEventHandler.ts +++ b/src/vs/editor/common/viewModel/viewEventHandler.ts @@ -49,6 +49,9 @@ export class ViewEventHandler extends Disposable { public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { return false; } + public onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean { + return false; + } public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean { return false; } @@ -121,6 +124,12 @@ export class ViewEventHandler extends Disposable { } break; + case viewEvents.ViewEventType.ViewLanguageConfigurationChanged: + if (this.onLanguageConfigurationChanged(e)) { + shouldRender = true; + } + break; + case viewEvents.ViewEventType.ViewLineMappingChanged: if (this.onLineMappingChanged(e)) { shouldRender = true; @@ -175,7 +184,6 @@ export class ViewEventHandler extends Disposable { } break; - case viewEvents.ViewEventType.ViewThemeChanged: if (this.onThemeChanged(e)) { shouldRender = true; diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 2890bf9314f..74e92e94582 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { INewScrollPosition, IModelDecoration, EndOfLinePreference, IViewState } from 'vs/editor/common/editorCommon'; +import { INewScrollPosition, EndOfLinePreference, IViewState, IModelDecorationOptions } from 'vs/editor/common/editorCommon'; import { ViewLineToken } from 'vs/editor/common/core/viewLineToken'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -14,6 +14,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { Scrollable, IScrollPosition } from 'vs/base/common/scrollable'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; +import { ITheme } from 'vs/platform/theme/common/themeService'; export interface IViewWhitespaceViewportData { readonly id: number; @@ -133,12 +134,13 @@ export interface IViewModel { getTabSize(): number; getLineCount(): number; getLineContent(lineNumber: number): string; - getLineIndentGuide(lineNumber: number): number; + getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[]; getLineMinColumn(lineNumber: number): number; getLineMaxColumn(lineNumber: number): number; getLineFirstNonWhitespaceColumn(lineNumber: number): number; getLineLastNonWhitespaceColumn(lineNumber: number): number; - getAllOverviewRulerDecorations(): ViewModelDecoration[]; + getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations; + invalidateOverviewRulerColorCache(): void; getValueInRange(range: Range, eol: EndOfLinePreference): string; getModelLineMaxColumn(modelLineNumber: number): number; @@ -267,15 +269,25 @@ export class InlineDecoration { export class ViewModelDecoration { _viewModelDecorationBrand: void; - public range: Range; - public readonly source: IModelDecoration; + public readonly range: Range; + public readonly options: IModelDecorationOptions; - constructor(source: IModelDecoration) { - this.range = null; - this.source = source; + constructor(range: Range, options: IModelDecorationOptions) { + this.range = range; + this.options = options; } } +/** + * Decorations are encoded in a number array using the following scheme: + * - 3*i = lane + * - 3*i+1 = startLineNumber + * - 3*i+2 = endLineNumber + */ +export interface IOverviewRulerDecorations { + [color: string]: number[]; +} + export class ViewEventsCollector { private _events: ViewEvent[]; diff --git a/src/vs/editor/common/viewModel/viewModelDecorations.ts b/src/vs/editor/common/viewModel/viewModelDecorations.ts index f4311681f82..b5c6aa4b5ba 100644 --- a/src/vs/editor/common/viewModel/viewModelDecorations.ts +++ b/src/vs/editor/common/viewModel/viewModelDecorations.ts @@ -9,7 +9,7 @@ import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { InlineDecoration, ViewModelDecoration, ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel'; -import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents'; +import { IViewModelLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection'; export interface IDecorationsViewportData { /** @@ -27,6 +27,7 @@ export class ViewModelDecorations implements IDisposable { private readonly editorId: number; private readonly model: editorCommon.IModel; private readonly configuration: editorCommon.IConfiguration; + private readonly _linesCollection: IViewModelLinesCollection; private readonly _coordinatesConverter: ICoordinatesConverter; private _decorationsCache: { [decorationId: string]: ViewModelDecoration; }; @@ -34,10 +35,11 @@ export class ViewModelDecorations implements IDisposable { private _cachedModelDecorationsResolver: IDecorationsViewportData; private _cachedModelDecorationsResolverViewRange: Range; - constructor(editorId: number, model: editorCommon.IModel, configuration: editorCommon.IConfiguration, coordinatesConverter: ICoordinatesConverter) { + constructor(editorId: number, model: editorCommon.IModel, configuration: editorCommon.IConfiguration, linesCollection: IViewModelLinesCollection, coordinatesConverter: ICoordinatesConverter) { this.editorId = editorId; this.model = model; this.configuration = configuration; + this._linesCollection = linesCollection; this._coordinatesConverter = coordinatesConverter; this._decorationsCache = Object.create(null); this._clearCachedModelDecorationsResolver(); @@ -58,26 +60,8 @@ export class ViewModelDecorations implements IDisposable { this._clearCachedModelDecorationsResolver(); } - public onModelDecorationsChanged(e: IModelDecorationsChangedEvent): void { - let changedDecorations = e.changedDecorations; - for (let i = 0, len = changedDecorations.length; i < len; i++) { - let changedDecoration = changedDecorations[i]; - let myDecoration = this._decorationsCache[changedDecoration]; - if (!myDecoration) { - continue; - } - - myDecoration.range = null; - } - - let removedDecorations = e.removedDecorations; - if (this._decorationsCache !== null && this._decorationsCache !== undefined) { - for (let i = 0, len = removedDecorations.length; i < len; i++) { - let removedDecoration = removedDecorations[i]; - delete this._decorationsCache[removedDecoration]; - } - } - + public onModelDecorationsChanged(): void { + this._decorationsCache = Object.create(null); this._clearCachedModelDecorationsResolver(); } @@ -88,42 +72,25 @@ export class ViewModelDecorations implements IDisposable { } private _getOrCreateViewModelDecoration(modelDecoration: editorCommon.IModelDecoration): ViewModelDecoration { - let id = modelDecoration.id; + const id = modelDecoration.id; let r = this._decorationsCache[id]; if (!r) { - r = new ViewModelDecoration(modelDecoration); + const modelRange = modelDecoration.range; + const options = modelDecoration.options; + let viewRange: Range; + if (options.isWholeLine) { + const start = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.startLineNumber, 1)); + const end = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.endLineNumber, this.model.getLineMaxColumn(modelRange.endLineNumber))); + viewRange = new Range(start.lineNumber, start.column, end.lineNumber, end.column); + } else { + viewRange = this._coordinatesConverter.convertModelRangeToViewRange(modelRange); + } + r = new ViewModelDecoration(viewRange, options); this._decorationsCache[id] = r; } - if (r.range === null) { - const modelRange = modelDecoration.range; - if (modelDecoration.options.isWholeLine) { - let start = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.startLineNumber, 1)); - let end = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.endLineNumber, this.model.getLineMaxColumn(modelRange.endLineNumber))); - r.range = new Range(start.lineNumber, start.column, end.lineNumber, end.column); - } else { - r.range = this._coordinatesConverter.convertModelRangeToViewRange(modelRange); - } - } return r; } - public getAllOverviewRulerDecorations(): ViewModelDecoration[] { - let modelDecorations = this.model.getAllDecorations(this.editorId, this.configuration.editor.readOnly); - let result: ViewModelDecoration[] = [], resultLen = 0; - for (let i = 0, len = modelDecorations.length; i < len; i++) { - let modelDecoration = modelDecorations[i]; - let decorationOptions = modelDecoration.options; - - if (!decorationOptions.overviewRuler.color) { - continue; - } - - let viewModelDecoration = this._getOrCreateViewModelDecoration(modelDecoration); - result[resultLen++] = viewModelDecoration; - } - return result; - } - public getDecorationsViewportData(viewRange: Range): IDecorationsViewportData { var cacheIsValid = true; cacheIsValid = cacheIsValid && (this._cachedModelDecorationsResolver !== null); @@ -136,10 +103,9 @@ export class ViewModelDecorations implements IDisposable { } private _getDecorationsViewportData(viewportRange: Range): IDecorationsViewportData { - let viewportModelRange = this._coordinatesConverter.convertViewRangeToModelRange(viewportRange); - let startLineNumber = viewportRange.startLineNumber; - let endLineNumber = viewportRange.endLineNumber; - let modelDecorations = this.model.getDecorationsInRange(viewportModelRange, this.editorId, this.configuration.editor.readOnly); + const modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, this.configuration.editor.readOnly); + const startLineNumber = viewportRange.startLineNumber; + const endLineNumber = viewportRange.endLineNumber; let decorationsInViewport: ViewModelDecoration[] = [], decorationsInViewportLen = 0; let inlineDecorations: InlineDecoration[][] = []; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 20b51a429b4..d5b4c9225b4 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -12,7 +12,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { TokenizationRegistry, ColorId, LanguageId } from 'vs/editor/common/modes'; import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer'; import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations'; -import { MinimapLinesRenderingData, ViewLineRenderingData, ViewModelDecoration, IViewModel, ICoordinatesConverter, ViewEventsCollector } from 'vs/editor/common/viewModel/viewModel'; +import { MinimapLinesRenderingData, ViewLineRenderingData, ViewModelDecoration, IViewModel, ICoordinatesConverter, ViewEventsCollector, IOverviewRulerDecorations } from 'vs/editor/common/viewModel/viewModel'; import { SplitLinesCollection, IViewModelLinesCollection, IdentityLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { MinimapTokensColorTracker } from 'vs/editor/common/view/minimapCharRenderer'; @@ -22,6 +22,8 @@ import { CharacterHardWrappingLineMapperFactory } from 'vs/editor/common/viewMod import { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout'; import { Color } from 'vs/base/common/color'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { ITheme } from 'vs/platform/theme/common/themeService'; +import { ModelDecorationOverviewRulerOptions } from 'vs/editor/common/model/textModelWithDecorations'; const USE_IDENTITY_LINES_COLLECTION = true; @@ -80,7 +82,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel this._isDisposing = false; this._centeredViewLine = -1; - this.decorations = new ViewModelDecorations(this.editorId, this.model, this.configuration, this.coordinatesConverter); + this.decorations = new ViewModelDecorations(this.editorId, this.model, this.configuration, this.lines, this.coordinatesConverter); this._register(this.model.addBulkListener((events: EmitterEvent[]) => { if (this._isDisposing) { @@ -261,6 +263,10 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel // That's ok, a model tokens changed event will follow shortly break; } + case textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged: { + eventsCollector.emit(new viewEvents.ViewLanguageConfigurationEvent()); + break; + } case textModelEvents.TextModelEventType.ModelContentChanged: { // Ignore break; @@ -278,8 +284,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel break; } case textModelEvents.TextModelEventType.ModelDecorationsChanged: { - const e = data; - this.decorations.onModelDecorationsChanged(e); + this.decorations.onModelDecorationsChanged(); eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent()); break; } @@ -361,8 +366,8 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel this.lines.warmUpLookupCache(startLineNumber, endLineNumber); } - public getLineIndentGuide(lineNumber: number): number { - return this.lines.getViewLineIndentGuide(lineNumber); + public getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] { + return this.lines.getViewLinesIndentGuides(startLineNumber, endLineNumber); } public getLineContent(lineNumber: number): string { @@ -425,8 +430,17 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel ); } - public getAllOverviewRulerDecorations(): ViewModelDecoration[] { - return this.decorations.getAllOverviewRulerDecorations(); + public getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations { + return this.lines.getAllOverviewRulerDecorations(this.editorId, this.configuration.editor.readOnly, theme); + } + + public invalidateOverviewRulerColorCache(): void { + const decorations = this.model.getOverviewRulerDecorations(); + for (let i = 0, len = decorations.length; i < len; i++) { + const decoration = decorations[i]; + const opts = decoration.options.overviewRuler; + opts._resolvedColor = null; + } } public getValueInRange(range: Range, eol: editorCommon.EndOfLinePreference): string { @@ -459,29 +473,37 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } public getPlainTextToCopy(ranges: Range[], emptySelectionClipboard: boolean): string { - let newLineCharacter = this.model.getEOL(); + const newLineCharacter = this.model.getEOL(); - if (ranges.length === 1) { - let range: Range = ranges[0]; - if (range.isEmpty()) { - if (emptySelectionClipboard) { - let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber; - return this.model.getLineContent(modelLineNumber) + newLineCharacter; - } else { - return ''; + ranges = ranges.slice(0); + ranges.sort(Range.compareRangesUsingStarts); + const nonEmptyRanges = ranges.filter((r) => !r.isEmpty()); + + if (nonEmptyRanges.length === 0) { + if (!emptySelectionClipboard) { + return ''; + } + + const modelLineNumbers = ranges.map((r) => { + const viewLineStart = new Position(r.startLineNumber, 1); + return this.coordinatesConverter.convertViewPositionToModelPosition(viewLineStart).lineNumber; + }); + + let result = ''; + for (let i = 0; i < modelLineNumbers.length; i++) { + if (i > 0 && modelLineNumbers[i - 1] === modelLineNumbers[i]) { + continue; } + result += this.model.getLineContent(modelLineNumbers[i]) + newLineCharacter; } - - return this.getValueInRange(range, editorCommon.EndOfLinePreference.TextDefined); - } else { - ranges = ranges.slice(0).sort(Range.compareRangesUsingStarts); - let result: string[] = []; - for (let i = 0; i < ranges.length; i++) { - result.push(this.getValueInRange(ranges[i], editorCommon.EndOfLinePreference.TextDefined)); - } - - return result.join(newLineCharacter); + return result; } + + let result: string[] = []; + for (let i = 0; i < nonEmptyRanges.length; i++) { + result.push(this.getValueInRange(nonEmptyRanges[i], editorCommon.EndOfLinePreference.TextDefined)); + } + return result.join(newLineCharacter); } public getHTMLToCopy(viewRanges: Range[], emptySelectionClipboard: boolean): string { diff --git a/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts index 4f19027988b..666bfdafc1f 100644 --- a/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts @@ -20,6 +20,7 @@ import { editorBracketMatchBackground, editorBracketMatchBorder } from 'vs/edito import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; @editorAction +// @ts-ignore @editorAction uses the class class SelectBracketAction extends EditorAction { constructor() { super({ @@ -94,6 +95,10 @@ export class BracketMatchingController extends Disposable implements editorCommo this._updateBracketsSoon.schedule(); })); this._register(editor.onDidChangeModel((e) => { this._decorations = []; this._updateBracketsSoon.schedule(); })); + this._register(editor.onDidChangeModelLanguageConfiguration((e) => { + this._lastBracketsData = []; + this._updateBracketsSoon.schedule(); + })); this._register(editor.onDidChangeConfiguration((e) => { this._matchBrackets = this._editor.getConfiguration().contribInfo.matchBrackets; if (!this._matchBrackets && this._decorations.length > 0) { @@ -141,6 +146,7 @@ export class BracketMatchingController extends Disposable implements editorCommo }); this._editor.setSelections(newSelections); + this._editor.revealRange(newSelections[0]); } private static _DECORATION_OPTIONS = ModelDecorationOptions.register({ diff --git a/src/vs/editor/contrib/caretOperations/common/caretOperations.ts b/src/vs/editor/contrib/caretOperations/common/caretOperations.ts index 96e935bd69d..c31ae66f389 100644 --- a/src/vs/editor/contrib/caretOperations/common/caretOperations.ts +++ b/src/vs/editor/contrib/caretOperations/common/caretOperations.ts @@ -36,6 +36,7 @@ class MoveCaretAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class MoveCaretLeftAction extends MoveCaretAction { constructor() { super(true, { @@ -48,6 +49,7 @@ class MoveCaretLeftAction extends MoveCaretAction { } @editorAction +// @ts-ignore @editorAction uses the class class MoveCaretRightAction extends MoveCaretAction { constructor() { super(false, { diff --git a/src/vs/editor/contrib/caretOperations/common/transpose.ts b/src/vs/editor/contrib/caretOperations/common/transpose.ts index 5ca66ce287d..28bab72bba4 100644 --- a/src/vs/editor/contrib/caretOperations/common/transpose.ts +++ b/src/vs/editor/contrib/caretOperations/common/transpose.ts @@ -13,6 +13,7 @@ import { editorAction, EditorAction, ServicesAccessor } from 'vs/editor/common/e import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; @editorAction +// @ts-ignore @editorAction uses the class class TransposeLettersAction extends EditorAction { constructor() { diff --git a/src/vs/editor/contrib/clipboard/browser/clipboard.ts b/src/vs/editor/contrib/clipboard/browser/clipboard.ts index 84cb6cc3167..828d4ff7d4c 100644 --- a/src/vs/editor/contrib/clipboard/browser/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/browser/clipboard.ts @@ -64,6 +64,7 @@ abstract class ExecCommandAction extends EditorAction { } @conditionalEditorAction(supportsCut) +// @ts-ignore @editorAction uses the class class ExecCommandCutAction extends ExecCommandAction { constructor() { @@ -102,6 +103,7 @@ class ExecCommandCutAction extends ExecCommandAction { } @conditionalEditorAction(supportsCopy) +// @ts-ignore @editorAction uses the class class ExecCommandCopyAction extends ExecCommandAction { constructor() { @@ -141,6 +143,7 @@ class ExecCommandCopyAction extends ExecCommandAction { } @conditionalEditorAction(supportsPaste) +// @ts-ignore @editorAction uses the class class ExecCommandPasteAction extends ExecCommandAction { constructor() { @@ -170,6 +173,7 @@ class ExecCommandPasteAction extends ExecCommandAction { } @conditionalEditorAction(supportsCopyWithSyntaxHighlighting) +// @ts-ignore @editorAction uses the class class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction { constructor() { diff --git a/src/vs/editor/contrib/codelens/browser/codelensWidget.ts b/src/vs/editor/contrib/codelens/browser/codelensWidget.ts index ac7b103cd55..b98a31d4fa7 100644 --- a/src/vs/editor/contrib/codelens/browser/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/browser/codelensWidget.ts @@ -65,6 +65,7 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { private readonly _disposables: IDisposable[] = []; private readonly _editor: editorBrowser.ICodeEditor; + // @ts-ignore unused property private _symbolRange: Range; private _widgetPosition: editorBrowser.IContentWidgetPosition; private _commands: { [id: string]: Command } = Object.create(null); diff --git a/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts b/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts index 95551219ade..9c004bf9f19 100644 --- a/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts @@ -12,9 +12,9 @@ import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; -import { ColorProviderRegistry, IColorRange } from 'vs/editor/common/modes'; +import { ColorProviderRegistry } from 'vs/editor/common/modes'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; -import { getColors } from 'vs/editor/contrib/colorPicker/common/color'; +import { getColors, IColorData } from 'vs/editor/contrib/colorPicker/common/color'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const MAX_DECORATORS = 500; @@ -32,7 +32,7 @@ export class ColorDetector implements IEditorContribution { private _timeoutPromise: TPromise; private _decorationsIds: string[] = []; - private _colorRanges = new Map(); + private _colorDatas = new Map(); private _colorDecoratorIds: string[] = []; private _decorationsTypes: { [key: string]: boolean } = {}; @@ -146,35 +146,29 @@ export class ColorDetector implements IEditorContribution { this._localToDispose = dispose(this._localToDispose); } - private updateDecorations(colorInfos: IColorRange[]): void { - const decorations = colorInfos.map(c => ({ + private updateDecorations(colorDatas: IColorData[]): void { + const decorations = colorDatas.map(c => ({ range: { - startLineNumber: c.range.startLineNumber, - startColumn: c.range.startColumn, - endLineNumber: c.range.endLineNumber, - endColumn: c.range.endColumn + startLineNumber: c.colorInfo.range.startLineNumber, + startColumn: c.colorInfo.range.startColumn, + endLineNumber: c.colorInfo.range.endLineNumber, + endColumn: c.colorInfo.range.endColumn }, options: {} })); - const colorRanges = colorInfos.map(c => ({ - range: c.range, - color: c.color, - formatters: c.formatters - })); - this._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, decorations); - this._colorRanges = new Map(); - this._decorationsIds.forEach((id, i) => this._colorRanges.set(id, colorRanges[i])); + this._colorDatas = new Map(); + this._decorationsIds.forEach((id, i) => this._colorDatas.set(id, colorDatas[i])); } - private updateColorDecorators(colorInfos: IColorRange[]): void { + private updateColorDecorators(colorData: IColorData[]): void { let decorations = []; let newDecorationsTypes: { [key: string]: boolean } = {}; - for (let i = 0; i < colorInfos.length && decorations.length < MAX_DECORATORS; i++) { - const { red, green, blue, alpha } = colorInfos[i].color; + for (let i = 0; i < colorData.length && decorations.length < MAX_DECORATORS; i++) { + const { red, green, blue, alpha } = colorData[i].colorInfo.color; const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha); let subKey = hash(rgba).toString(16); let color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`; @@ -201,10 +195,10 @@ export class ColorDetector implements IEditorContribution { newDecorationsTypes[key] = true; decorations.push({ range: { - startLineNumber: colorInfos[i].range.startLineNumber, - startColumn: colorInfos[i].range.startColumn, - endLineNumber: colorInfos[i].range.endLineNumber, - endColumn: colorInfos[i].range.endColumn + startLineNumber: colorData[i].colorInfo.range.startLineNumber, + startColumn: colorData[i].colorInfo.range.startColumn, + endLineNumber: colorData[i].colorInfo.range.endLineNumber, + endColumn: colorData[i].colorInfo.range.endColumn }, options: this._codeEditorService.resolveDecorationOptions(key, true) }); @@ -228,15 +222,15 @@ export class ColorDetector implements IEditorContribution { } } - getColorRange(position: Position): IColorRange | null { + getColorData(position: Position): IColorData | null { const decorations = this._editor.getModel() .getDecorationsInRange(Range.fromPositions(position, position)) - .filter(d => this._colorRanges.has(d.id)); + .filter(d => this._colorDatas.has(d.id)); if (decorations.length === 0) { return null; } - return this._colorRanges.get(decorations[0].id); + return this._colorDatas.get(decorations[0].id); } } diff --git a/src/vs/editor/contrib/colorPicker/browser/colorPickerModel.ts b/src/vs/editor/contrib/colorPicker/browser/colorPickerModel.ts index af4d256bbd3..c10f8e26360 100644 --- a/src/vs/editor/contrib/colorPicker/browser/colorPickerModel.ts +++ b/src/vs/editor/contrib/colorPicker/browser/colorPickerModel.ts @@ -5,11 +5,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { Color } from 'vs/base/common/color'; -import { IColorFormatter } from 'vs/editor/common/modes'; - -function canFormat(formatter: IColorFormatter, color: Color): boolean { - return color.isOpaque() || formatter.supportsTransparency; -} +import { IColorPresentation } from 'vs/editor/common/modes'; export class ColorPickerModel { @@ -26,13 +22,24 @@ export class ColorPickerModel { } this._color = color; - this._checkFormat(); this._onDidChangeColor.fire(color); } - get formatter(): IColorFormatter { return this.formatters[this.formatterIndex]; } + get presentation(): IColorPresentation { return this.colorPresentations[this.presentationIndex]; } - readonly formatters: IColorFormatter[]; + private _colorPresentations: IColorPresentation[]; + + get colorPresentations(): IColorPresentation[] { + return this._colorPresentations; + } + + set colorPresentations(colorPresentations: IColorPresentation[]) { + this._colorPresentations = colorPresentations; + if (this.presentationIndex > colorPresentations.length - 1) { + this.presentationIndex = 0; + } + this._onDidChangePresentation.fire(this.presentation); + } private _onColorFlushed = new Emitter(); readonly onColorFlushed: Event = this._onColorFlushed.event; @@ -40,49 +47,32 @@ export class ColorPickerModel { private _onDidChangeColor = new Emitter(); readonly onDidChangeColor: Event = this._onDidChangeColor.event; - private _onDidChangeFormatter = new Emitter(); - readonly onDidChangeFormatter: Event = this._onDidChangeFormatter.event; - - constructor(color: Color, availableFormatters: IColorFormatter[], private formatterIndex: number) { - if (availableFormatters.length === 0) { - throw new Error('Color picker needs formats'); - } - - if (formatterIndex < 0 || formatterIndex >= availableFormatters.length) { - throw new Error('Formatter index out of bounds'); - } + private _onDidChangePresentation = new Emitter(); + readonly onDidChangePresentation: Event = this._onDidChangePresentation.event; + constructor(color: Color, availableColorPresentations: IColorPresentation[], private presentationIndex: number) { this.originalColor = color; - this.formatters = availableFormatters; this._color = color; + this._colorPresentations = availableColorPresentations; } - selectNextColorFormat(): void { - const oldFomatterIndex = this.formatterIndex; - this._checkFormat((this.formatterIndex + 1) % this.formatters.length); - if (oldFomatterIndex !== this.formatterIndex) { - this.flushColor(); + selectNextColorPresentation(): void { + this.presentationIndex = (this.presentationIndex + 1) % this.colorPresentations.length; + this.flushColor(); + this._onDidChangePresentation.fire(this.presentation); + } + + guessColorPresentation(color: Color, originalText: string): void { + for (let i = 0; i < this.colorPresentations.length; i++) { + if (originalText === this.colorPresentations[i].label) { + this.presentationIndex = i; + this._onDidChangePresentation.fire(this.presentation); + break; + } } } flushColor(): void { this._onColorFlushed.fire(this._color); } - - private _checkFormat(start = this.formatterIndex): void { - let isNewFormat = this.formatterIndex !== start; - this.formatterIndex = start; - - while (!canFormat(this.formatter, this._color)) { - this.formatterIndex = (this.formatterIndex + 1) % this.formatters.length; - - if (this.formatterIndex === start) { - return; - } - } - - if (isNewFormat) { - this._onDidChangeFormatter.fire(this.formatter); - } - } } diff --git a/src/vs/editor/contrib/colorPicker/browser/colorPickerWidget.ts b/src/vs/editor/contrib/colorPicker/browser/colorPickerWidget.ts index 9e416c5cac3..1b461696a68 100644 --- a/src/vs/editor/contrib/colorPicker/browser/colorPickerWidget.ts +++ b/src/vs/editor/contrib/colorPicker/browser/colorPickerWidget.ts @@ -38,29 +38,25 @@ export class ColorPickerHeader extends Disposable { this.backgroundColor = theme.getColor(editorHoverBackground) || Color.white; })); - this._register(dom.addDisposableListener(this.pickedColorNode, dom.EventType.CLICK, () => this.model.selectNextColorFormat())); + this._register(dom.addDisposableListener(this.pickedColorNode, dom.EventType.CLICK, () => this.model.selectNextColorPresentation())); this._register(dom.addDisposableListener(colorBox, dom.EventType.CLICK, () => { this.model.color = this.model.originalColor; this.model.flushColor(); })); this._register(model.onDidChangeColor(this.onDidChangeColor, this)); - this._register(model.onDidChangeFormatter(this.onDidChangeFormatter, this)); - this.onDidChangeColor(this.model.color); + this._register(model.onDidChangePresentation(this.onDidChangePresentation, this)); + this.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(model.color); + dom.toggleClass(this.pickedColorNode, 'light', model.color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : model.color.isLighter()); } private onDidChangeColor(color: Color): void { this.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(color); dom.toggleClass(this.pickedColorNode, 'light', color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : color.isLighter()); - this.onDidChangeFormatter(); + this.onDidChangePresentation(); } - private onDidChangeFormatter(): void { - this.pickedColorNode.textContent = this.model.formatter.format({ - red: this.model.color.rgba.r / 255, - green: this.model.color.rgba.g / 255, - blue: this.model.color.rgba.b / 255, - alpha: this.model.color.rgba.a - }); + private onDidChangePresentation(): void { + this.pickedColorNode.textContent = this.model.presentation.label; } } @@ -70,7 +66,7 @@ export class ColorPickerBody extends Disposable { private saturationBox: SaturationBox; private hueStrip: Strip; private opacityStrip: Strip; - + // @ts-ignore unused property constructor(private container: HTMLElement, private model: ColorPickerModel, private pixelRatio: number) { super(); diff --git a/src/vs/editor/contrib/colorPicker/common/color.ts b/src/vs/editor/contrib/colorPicker/common/color.ts index 666c21bacf9..14309923337 100644 --- a/src/vs/editor/contrib/colorPicker/common/color.ts +++ b/src/vs/editor/contrib/colorPicker/common/color.ts @@ -4,15 +4,29 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import { ColorProviderRegistry, IColorRange } from 'vs/editor/common/modes'; +import { ColorProviderRegistry, DocumentColorProvider, IColorInformation, IColorPresentation } from 'vs/editor/common/modes'; import { asWinJsPromise } from 'vs/base/common/async'; import { IReadOnlyModel } from 'vs/editor/common/editorCommon'; -import { flatten } from 'vs/base/common/arrays'; -export function getColors(model: IReadOnlyModel): TPromise { - const providers = ColorProviderRegistry.ordered(model).reverse(); - const promises = providers.map(p => asWinJsPromise(token => p.provideColorRanges(model, token))); - - return TPromise.join(promises) - .then(ranges => flatten(ranges.filter(r => Array.isArray(r)))); +export interface IColorData { + colorInfo: IColorInformation; + provider: DocumentColorProvider; +} + +export function getColors(model: IReadOnlyModel): TPromise { + const colors: IColorData[] = []; + const providers = ColorProviderRegistry.ordered(model).reverse(); + const promises = providers.map(provider => asWinJsPromise(token => provider.provideDocumentColors(model, token)).then(result => { + if (Array.isArray(result)) { + for (let colorInfo of result) { + colors.push({ colorInfo, provider }); + } + } + })); + + return TPromise.join(promises).then(() => colors); +} + +export function getColorPresentations(model: IReadOnlyModel, colorInfo: IColorInformation, provider: DocumentColorProvider): TPromise { + return asWinJsPromise(token => provider.provideColorPresentations(model, colorInfo, token)); } diff --git a/src/vs/editor/contrib/colorPicker/common/colorFormatter.ts b/src/vs/editor/contrib/colorPicker/common/colorFormatter.ts deleted file mode 100644 index b65a85c5403..00000000000 --- a/src/vs/editor/contrib/colorPicker/common/colorFormatter.ts +++ /dev/null @@ -1,144 +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 { IColorFormatter, IColor } from 'vs/editor/common/modes'; -import { Color, RGBA } from 'vs/base/common/color'; - -function roundFloat(number: number, decimalPoints: number): number { - const decimal = Math.pow(10, decimalPoints); - return Math.round(number * decimal) / decimal; -} - -interface Node { - (color: Color): string; -} - -function createLiteralNode(value: string): Node { - return () => value; -} - -function normalize(value: number, min: number, max: number): number { - return value * (max - min) + min; -} - -function getPropertyValue(color: Color, variable: string): number | undefined { - switch (variable) { - case 'red': - return color.rgba.r / 255; - case 'green': - return color.rgba.g / 255; - case 'blue': - return color.rgba.b / 255; - case 'alpha': - return color.rgba.a; - case 'hue': - return color.hsla.h / 360; - case 'saturation': - return color.hsla.s; - case 'luminance': - return color.hsla.l; - default: - return undefined; - } -} - -function createPropertyNode(variable: string, fractionDigits: number, type: string, min: number | undefined, max: number | undefined): Node { - return color => { - let value = getPropertyValue(color, variable); - - if (value === undefined) { - return ''; - } - - if (type === 'd') { - min = typeof min === 'number' ? min : 0; - max = typeof max === 'number' ? max : 255; - - return (normalize(value, min, max).toFixed(0)).toString(); - } else if (type === 'x' || type === 'X') { - min = typeof min === 'number' ? min : 0; - max = typeof max === 'number' ? max : 255; - - let result = normalize(value, min, max).toString(16); - - if (type === 'X') { - result = result.toUpperCase(); - } - - return result.length < 2 ? `0${result}` : result; - } - - min = typeof min === 'number' ? min : 0; - max = typeof max === 'number' ? max : 1; - return roundFloat(normalize(value, min, max), 2).toString(); - }; -} - -export class ColorFormatter implements IColorFormatter { - - readonly supportsTransparency: boolean = false; - private tree: Node[] = []; - - // Group 0: variable - // Group 1: decimal digits - // Group 2: floating/integer/hex - // Group 3: range begin - // Group 4: range end - private static PATTERN = /{(\w+)(?::(\d*)(\w)+(?:\[(\d+)-(\d+)\])?)?}/g; - - constructor(format: string) { - let match = ColorFormatter.PATTERN.exec(format); - let startIndex = 0; - - // if no match -> erroor throw new Error(`${format} is not consistent with color format syntax.`); - while (match !== null) { - const index = match.index; - - if (startIndex < index) { - this.tree.push(createLiteralNode(format.substring(startIndex, index))); - } - - // add more parser catches - const variable = match[1]; - if (!variable) { - throw new Error(`${variable} is not defined.`); - } - - this.supportsTransparency = this.supportsTransparency || (variable === 'alpha'); - - const decimals = match[2] && parseInt(match[2]); - const type = match[3]; - const startRange = match[4] && parseInt(match[4]); - const endRange = match[5] && parseInt(match[5]); - - this.tree.push(createPropertyNode(variable, decimals, type, startRange, endRange)); - - startIndex = index + match[0].length; - match = ColorFormatter.PATTERN.exec(format); - } - - this.tree.push(createLiteralNode(format.substring(startIndex, format.length))); - } - - format(color: IColor): string { - const richColor = new Color(new RGBA(Math.round(color.red * 255), Math.round(color.green * 255), Math.round(color.blue * 255), color.alpha)); - return this.tree.map(node => node(richColor)).join(''); - } -} - -export class CombinedColorFormatter implements IColorFormatter { - - readonly supportsTransparency: boolean = true; - - constructor(private opaqueFormatter: IColorFormatter, private transparentFormatter: IColorFormatter) { - if (!transparentFormatter.supportsTransparency) { - throw new Error('Invalid transparent formatter'); - } - } - - format(color: IColor): string { - return color.alpha === 1 ? this.opaqueFormatter.format(color) : this.transparentFormatter.format(color); - } -} \ No newline at end of file diff --git a/src/vs/editor/contrib/colorPicker/test/common/colorFormatter.test.ts b/src/vs/editor/contrib/colorPicker/test/common/colorFormatter.test.ts deleted file mode 100644 index 29d7c964393..00000000000 --- a/src/vs/editor/contrib/colorPicker/test/common/colorFormatter.test.ts +++ /dev/null @@ -1,83 +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 { Color, RGBA, HSLA } from 'vs/base/common/color'; -import { IColor } from 'vs/editor/common/modes'; -import { ColorFormatter } from 'vs/editor/contrib/colorPicker/common/colorFormatter'; - -function convert2IColor(color: Color): IColor { - return { - red: color.rgba.r / 255, - green: color.rgba.g / 255, - blue: color.rgba.b / 255, - alpha: color.rgba.a - }; -} -suite('ColorFormatter', () => { - test('empty formatter', () => { - const formatter = new ColorFormatter(''); - assert.equal(formatter.supportsTransparency, false); - - assert.equal(formatter.format(convert2IColor(Color.white)), ''); - assert.equal(formatter.format(convert2IColor(Color.transparent)), ''); - }); - - test('no placeholder', () => { - const formatter = new ColorFormatter('hello'); - assert.equal(formatter.supportsTransparency, false); - - assert.equal(formatter.format(convert2IColor(Color.white)), 'hello'); - assert.equal(formatter.format(convert2IColor(Color.transparent)), 'hello'); - }); - - test('supportsTransparency', () => { - const formatter = new ColorFormatter('hello'); - assert.equal(formatter.supportsTransparency, false); - - const transparentFormatter = new ColorFormatter('{alpha}'); - assert.equal(transparentFormatter.supportsTransparency, true); - }); - - test('default number format is float', () => { - const formatter = new ColorFormatter('{red}'); - assert.equal(formatter.format(convert2IColor(Color.red)), '1'); - }); - - test('default decimal range is [0-255]', () => { - const formatter = new ColorFormatter('{red:d}'); - assert.equal(formatter.format(convert2IColor(Color.red)), '255'); - }); - - test('default hex range is [0-FF]', () => { - const formatter = new ColorFormatter('{red:X}'); - assert.equal(formatter.format(convert2IColor(Color.red)), 'FF'); - }); - - test('documentation', () => { - const color = new Color(new RGBA(255, 127, 0)); - - const rgb = new ColorFormatter('rgb({red:d[0-255]}, {green:d[0-255]}, {blue:d[0-255]})'); - assert.equal(rgb.format(convert2IColor(color)), 'rgb(255, 127, 0)'); - - const rgba = new ColorFormatter('rgba({red:d[0-255]}, {green:d[0-255]}, {blue:d[0-255]}, {alpha})'); - assert.equal(rgba.format(convert2IColor(color)), 'rgba(255, 127, 0, 1)'); - - const hex = new ColorFormatter('#{red:X}{green:X}{blue:X}'); - assert.equal(hex.format(convert2IColor(color)), '#FF7F00'); - - const hsla = new ColorFormatter('hsla({hue:d[0-360]}, {saturation:d[0-100]}%, {luminance:d[0-100]}%, {alpha})'); - assert.equal(hsla.format(convert2IColor(color)), 'hsla(30, 100%, 50%, 1)'); - }); - - test('bug#32323', () => { - const color = new Color(new HSLA(121, 0.45, 0.29, 0.61)); - const rgba = color.rgba; - const color2 = new Color(new RGBA(rgba.r, rgba.g, rgba.b, rgba.a)); - const hsla = new ColorFormatter('hsla({hue:d[0-360]}, {saturation:d[0-100]}%, {luminance:d[0-100]}%, {alpha})'); - assert.equal(hsla.format(convert2IColor(color2)), 'hsla(121, 45%, 29%, 0.61)'); - }); -}); \ No newline at end of file diff --git a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts index ffefd02ed8c..933dff3f46b 100644 --- a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts @@ -26,12 +26,12 @@ export class BlockCommentCommand implements editorCommon.ICommand { if (offset < 0) { return false; } - var needleLength = needle.length; - var haystackLength = haystack.length; + const needleLength = needle.length; + const haystackLength = haystack.length; if (offset + needleLength > haystackLength) { return false; } - for (var i = 0; i < needleLength; i++) { + for (let i = 0; i < needleLength; i++) { if (haystack.charCodeAt(offset + i) !== needle.charCodeAt(i)) { return false; } @@ -40,51 +40,75 @@ export class BlockCommentCommand implements editorCommon.ICommand { } private _createOperationsForBlockComment(selection: Range, config: ICommentsConfiguration, model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void { - var startLineNumber = selection.startLineNumber; - var startColumn = selection.startColumn; - var endLineNumber = selection.endLineNumber; - var endColumn = selection.endColumn; + const startLineNumber = selection.startLineNumber; + const startColumn = selection.startColumn; + const endLineNumber = selection.endLineNumber; + const endColumn = selection.endColumn; - var startToken = config.blockCommentStartToken; - var endToken = config.blockCommentEndToken; + const startLineText = model.getLineContent(startLineNumber); + const endLineText = model.getLineContent(endLineNumber); - var startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startColumn - 1 + startToken.length); - var endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, endColumn - 1 - endToken.length); + let startToken = config.blockCommentStartToken; + let endToken = config.blockCommentEndToken; - var ops: editorCommon.IIdentifiedSingleEditOperation[]; + let startTokenIndex = startLineText.lastIndexOf(startToken, startColumn - 1 + startToken.length); + let endTokenIndex = endLineText.indexOf(endToken, endColumn - 1 - endToken.length); if (startTokenIndex !== -1 && endTokenIndex !== -1) { - var endTokenBeforeCursorIndex = model.getLineContent(startLineNumber).lastIndexOf(endToken, startColumn - 1 + endToken.length); - if (endTokenBeforeCursorIndex > startTokenIndex + startToken.length - 1) { - ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken); - this._usedEndToken = ops.length === 1 ? endToken : null; - } else { - // We have to adjust to possible inner white space - // For Space after startToken, add Space to startToken - range math will work out - if (model.getLineContent(startLineNumber).charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) { - startToken += ' '; + + if (startLineNumber === endLineNumber) { + const lineBetweenTokens = startLineText.substring(startTokenIndex + startToken.length, endTokenIndex); + + if (lineBetweenTokens.indexOf(endToken) >= 0) { + // force to add a block comment + startTokenIndex = -1; + endTokenIndex = -1; } - // For Space before endToken, add Space before endToken and shift index one left - if (model.getLineContent(endLineNumber).charCodeAt(endTokenIndex - 1) === CharCode.Space) { + } else { + const startLineAfterStartToken = startLineText.substring(startTokenIndex + startToken.length); + const endLineBeforeEndToken = endLineText.substring(0, endTokenIndex); + + if (startLineAfterStartToken.indexOf(endToken) >= 0 || endLineBeforeEndToken.indexOf(endToken) >= 0) { + // force to add a block comment + startTokenIndex = -1; + endTokenIndex = -1; + } + } + } + + let ops: editorCommon.IIdentifiedSingleEditOperation[]; + + if (startTokenIndex !== -1 && endTokenIndex !== -1) { + // Consider spaces as part of the comment tokens + if (startTokenIndex + startToken.length < startLineText.length) { + if (startLineText.charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) { + // Pretend the start token contains a trailing space + startToken = startToken + ' '; + } + } + + if (endTokenIndex > 0) { + if (endLineText.charCodeAt(endTokenIndex - 1) === CharCode.Space) { + // Pretend the end token contains a leading space endToken = ' ' + endToken; endTokenIndex -= 1; } - ops = BlockCommentCommand._createRemoveBlockCommentOperations( - new Range(startLineNumber, startTokenIndex + 1 + startToken.length, endLineNumber, endTokenIndex + 1), startToken, endToken - ); } + ops = BlockCommentCommand._createRemoveBlockCommentOperations( + new Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken + ); } else { ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken); this._usedEndToken = ops.length === 1 ? endToken : null; } - for (var i = 0; i < ops.length; i++) { + for (let i = 0; i < ops.length; i++) { builder.addTrackedEditOperation(ops[i].range, ops[i].text); } } public static _createRemoveBlockCommentOperations(r: Range, startToken: string, endToken: string): editorCommon.IIdentifiedSingleEditOperation[] { - var res: editorCommon.IIdentifiedSingleEditOperation[] = []; + let res: editorCommon.IIdentifiedSingleEditOperation[] = []; if (!Range.isEmpty(r)) { // Remove block comment start @@ -110,7 +134,7 @@ export class BlockCommentCommand implements editorCommon.ICommand { } public static _createAddBlockCommentOperations(r: Range, startToken: string, endToken: string): editorCommon.IIdentifiedSingleEditOperation[] { - var res: editorCommon.IIdentifiedSingleEditOperation[] = []; + let res: editorCommon.IIdentifiedSingleEditOperation[] = []; if (!Range.isEmpty(r)) { // Insert block comment start @@ -130,29 +154,27 @@ export class BlockCommentCommand implements editorCommon.ICommand { } public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void { - var startLineNumber = this._selection.startLineNumber; - var startColumn = this._selection.startColumn; - var endLineNumber = this._selection.endLineNumber; - var endColumn = this._selection.endColumn; + const startLineNumber = this._selection.startLineNumber; + const startColumn = this._selection.startColumn; model.tokenizeIfCheap(startLineNumber); - let languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn); - let config = LanguageConfigurationRegistry.getComments(languageId); + const languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn); + const config = LanguageConfigurationRegistry.getComments(languageId); if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) { // Mode does not support block comments return; } this._createOperationsForBlockComment( - new Range(startLineNumber, startColumn, endLineNumber, endColumn), config, model, builder + this._selection, config, model, builder ); } public computeCursorState(model: editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData): Selection { - var inverseEditOperations = helper.getInverseEditOperations(); + const inverseEditOperations = helper.getInverseEditOperations(); if (inverseEditOperations.length === 2) { - var startTokenEditOperation = inverseEditOperations[0]; - var endTokenEditOperation = inverseEditOperations[1]; + const startTokenEditOperation = inverseEditOperations[0]; + const endTokenEditOperation = inverseEditOperations[1]; return new Selection( startTokenEditOperation.range.endLineNumber, @@ -161,8 +183,8 @@ export class BlockCommentCommand implements editorCommon.ICommand { endTokenEditOperation.range.startColumn ); } else { - var srcRange = inverseEditOperations[0].range; - var deltaColumn = this._usedEndToken ? -this._usedEndToken.length - 1 : 0; // minus 1 space before endToken + const srcRange = inverseEditOperations[0].range; + const deltaColumn = this._usedEndToken ? -this._usedEndToken.length - 1 : 0; // minus 1 space before endToken return new Selection( srcRange.endLineNumber, srcRange.endColumn + deltaColumn, diff --git a/src/vs/editor/contrib/comment/common/comment.ts b/src/vs/editor/contrib/comment/common/comment.ts index 898e1aa89d0..e722543179f 100644 --- a/src/vs/editor/contrib/comment/common/comment.ts +++ b/src/vs/editor/contrib/comment/common/comment.ts @@ -43,6 +43,7 @@ abstract class CommentLineAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class ToggleCommentLineAction extends CommentLineAction { constructor() { super(Type.Toggle, { @@ -59,6 +60,7 @@ class ToggleCommentLineAction extends CommentLineAction { } @editorAction +// @ts-ignore @editorAction uses the class class AddLineCommentAction extends CommentLineAction { constructor() { super(Type.ForceAdd, { @@ -75,6 +77,7 @@ class AddLineCommentAction extends CommentLineAction { } @editorAction +// @ts-ignore @editorAction uses the class class RemoveLineCommentAction extends CommentLineAction { constructor() { super(Type.ForceRemove, { @@ -91,6 +94,7 @@ class RemoveLineCommentAction extends CommentLineAction { } @editorAction +// @ts-ignore @editorAction uses the class class BlockCommentAction extends EditorAction { constructor() { diff --git a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts index 8dd881a6c40..e1d5bec1202 100644 --- a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts @@ -200,12 +200,15 @@ export class LineCommentCommand implements editorCommon.ICommand { ops = LineCommentCommand._createAddLineCommentsOperations(data.lines, s.startLineNumber); } - var cursorPosition = new Position(s.positionLineNumber, s.positionColumn); + const cursorPosition = new Position(s.positionLineNumber, s.positionColumn); for (var i = 0, len = ops.length; i < len; i++) { builder.addEditOperation(ops[i].range, ops[i].text); if (ops[i].range.isEmpty() && ops[i].range.getStartPosition().equals(cursorPosition)) { - this._deltaColumn = ops[i].text.length; + const lineContent = model.getLineContent(cursorPosition.lineNumber); + if (lineContent.length + 1 === cursorPosition.column) { + this._deltaColumn = ops[i].text.length; + } } } @@ -267,7 +270,7 @@ export class LineCommentCommand implements editorCommon.ICommand { */ private _executeBlockComment(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder, s: Selection): void { model.tokenizeIfCheap(s.startLineNumber); - let languageId = model.getLanguageIdAtPosition(s.startLineNumber, s.startColumn); + let languageId = model.getLanguageIdAtPosition(s.startLineNumber, 1); let config = LanguageConfigurationRegistry.getComments(languageId); if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) { // Mode does not support block comments diff --git a/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts index e204aa44255..4b5ea60286d 100644 --- a/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts @@ -457,4 +457,17 @@ suite('Editor Contrib - Block Comment Command', () => { new Selection(1, 16, 1, 22) ); }); + + test('issue #34618', function () { + testBlockCommentCommand( + [ + '<0 0> middle end', + ], + new Selection(1, 4, 1, 4), + [ + ' middle end' + ], + new Selection(1, 1, 1, 1) + ); + }); }); diff --git a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts index 55596067286..743652c37a7 100644 --- a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts @@ -41,7 +41,7 @@ suite('Editor Contrib - Line Comment Command', () => { '!@# some text', '\tsome more text' ], - new Selection(1, 9, 1, 9) + new Selection(1, 5, 1, 5) ); }); @@ -335,7 +335,7 @@ suite('Editor Contrib - Line Comment Command', () => { '!@# first!@#', '\tsecond line' ], - new Selection(1, 9, 1, 9) + new Selection(1, 5, 1, 5) ); }); @@ -371,7 +371,7 @@ suite('Editor Contrib - Line Comment Command', () => { 'fourth line', 'fifth' ], - new Selection(1, 9, 2, 5) + new Selection(1, 5, 2, 1) ); }); @@ -392,7 +392,7 @@ suite('Editor Contrib - Line Comment Command', () => { 'fourth line', 'fifth' ], - new Selection(1, 9, 2, 12) + new Selection(1, 5, 2, 8) ); }); @@ -413,7 +413,7 @@ suite('Editor Contrib - Line Comment Command', () => { '!@# fourth line', 'fifth' ], - new Selection(3, 9, 4, 12) + new Selection(3, 5, 4, 8) ); }); @@ -434,7 +434,7 @@ suite('Editor Contrib - Line Comment Command', () => { 'fourth line', 'fifth' ], - new Selection(1, 9, 1, 9) + new Selection(1, 5, 1, 5) ); testLineCommentCommand( @@ -474,7 +474,7 @@ suite('Editor Contrib - Line Comment Command', () => { 'fourth line', 'fifth' ], - new Selection(1, 9, 2, 12) + new Selection(1, 5, 2, 8) ); testLineCommentCommand( @@ -497,6 +497,71 @@ suite('Editor Contrib - Line Comment Command', () => { ); }); + test('issue #5964: Ctrl+/ to create comment when cursor is at the beginning of the line puts the cursor in a strange position', () => { + testLineCommentCommand( + [ + 'first', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(1, 1, 1, 1), + [ + '!@# first', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(1, 5, 1, 5) + ); + }); + + test('issue #35673: Comment hotkeys throws the cursor before the comment', () => { + testLineCommentCommand( + [ + 'first', + '', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 1, 2, 1), + [ + 'first', + '!@# ', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 5, 2, 5) + ); + + testLineCommentCommand( + [ + 'first', + '\t', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 2, 2, 2), + [ + 'first', + '\t!@# ', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 6, 2, 6) + ); + }); + test('issue #2837 "Add Line Comment" fault when blank lines involved', function () { testAddLineCommentCommand( [ @@ -937,4 +1002,20 @@ suite('Editor Contrib - Line Comment in mixed modes', () => { ); }); + test('issue #36173: Commenting code in JSX tag body', () => { + testLineCommentCommand( + [ + '
', + ' {123}', + '
', + ], + new Selection(2, 4, 2, 4), + [ + '
', + ' {/* {123} */}', + '
', + ], + new Selection(2, 8, 2, 8), + ); + }); }); diff --git a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts index 2a726ea915e..8f08c79e111 100644 --- a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts @@ -218,6 +218,7 @@ export class ContextMenuController implements IEditorContribution { } @editorAction +// @ts-ignore @editorAction uses the class class ShowContextMenu extends EditorAction { constructor() { diff --git a/src/vs/editor/contrib/cursorUndo/browser/cursorUndo.ts b/src/vs/editor/contrib/cursorUndo/browser/cursorUndo.ts index b47435cafbe..01d602facda 100644 --- a/src/vs/editor/contrib/cursorUndo/browser/cursorUndo.ts +++ b/src/vs/editor/contrib/cursorUndo/browser/cursorUndo.ts @@ -8,7 +8,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { editorCommand, ServicesAccessor, EditorCommand } from 'vs/editor/common/editorCommonExtensions'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ICommonCodeEditor, IEditorContribution } from 'vs/editor/common/editorCommon'; +import { ICommonCodeEditor, IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; @@ -72,7 +72,7 @@ export class CursorUndoController extends Disposable implements IEditorContribut this._undoStack.push(this._prevState); if (this._undoStack.length > 50) { // keep the cursor undo stack bounded - this._undoStack = this._undoStack.splice(0, this._undoStack.length - 50); + this._undoStack.shift(); } } @@ -102,6 +102,7 @@ export class CursorUndoController extends Disposable implements IEditorContribut if (!prevState.equals(currState)) { this._isCursorUndo = true; this._editor.setSelections(prevState.selections); + this._editor.revealRangeInCenterIfOutsideViewport(prevState.selections[0], ScrollType.Smooth); this._isCursorUndo = false; return; } diff --git a/src/vs/editor/contrib/find/browser/findOptionsWidget.ts b/src/vs/editor/contrib/find/browser/findOptionsWidget.ts index 7634aa1ca30..8cc1a442e0e 100644 --- a/src/vs/editor/contrib/find/browser/findOptionsWidget.ts +++ b/src/vs/editor/contrib/find/browser/findOptionsWidget.ts @@ -147,7 +147,7 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this._revealTemporarily(); } - private _hideSoon = this._register(new RunOnceScheduler(() => this._hide(), 1000)); + private _hideSoon = this._register(new RunOnceScheduler(() => this._hide(), 2000)); private _revealTemporarily(): void { this._show(); diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index 726c2451eef..77c25acb251 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -48,7 +48,7 @@ const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Repla const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace"); const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All"); const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode"); -const NLS_MATCHES_COUNT_LIMIT_TITLE = nls.localize('title.matchesCountLimit', "Only the first 999 results are highlighted, but all find operations work on the entire text."); +const NLS_MATCHES_COUNT_LIMIT_TITLE = nls.localize('title.matchesCountLimit', "Only the first {0} results are highlighted, but all find operations work on the entire text.", MATCHES_LIMIT); const NLS_MATCHES_LOCATION = nls.localize('label.matchesLocation', "{0} of {1}"); const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results"); @@ -921,7 +921,7 @@ class SimpleCheckbox extends Widget { this._label = document.createElement('label'); this._label.className = 'label'; - // Connect the label and the checkbox. Checkbox will get checked when the label recieves a click. + // Connect the label and the checkbox. Checkbox will get checked when the label receives a click. this._label.htmlFor = this._checkbox.id; this._label.tabIndex = -1; diff --git a/src/vs/editor/contrib/find/browser/simpleFindWidget.css b/src/vs/editor/contrib/find/browser/simpleFindWidget.css index c4e79f0eea3..526b08a05b1 100644 --- a/src/vs/editor/contrib/find/browser/simpleFindWidget.css +++ b/src/vs/editor/contrib/find/browser/simpleFindWidget.css @@ -3,16 +3,25 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .simple-find-part { +.monaco-workbench .simple-find-part-wrapper { + overflow: hidden; z-index: 10; position: absolute; - top: -40px; + top: 0; right: 28px; + width: 220px; + max-width: calc(100% - 28px - 28px - 8px); + pointer-events: none; +} + +.monaco-workbench .simple-find-part { + z-index: 10; + position: relative; + top: -40px; display: flex; padding: 4px; align-items: center; - width: 220px; - max-width: calc(100% - 28px - 28px - 8px); + pointer-events: all; -webkit-transition: top 200ms linear; -o-transition: top 200ms linear; diff --git a/src/vs/editor/contrib/find/browser/simpleFindWidget.ts b/src/vs/editor/contrib/find/browser/simpleFindWidget.ts index d9fb0b3ca12..808391b32d0 100644 --- a/src/vs/editor/contrib/find/browser/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/browser/simpleFindWidget.ts @@ -25,6 +25,7 @@ const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); export abstract class SimpleFindWidget extends Widget { protected _findInput: FindInput; protected _domNode: HTMLElement; + protected _innerDomNode: HTMLElement; protected _isVisible: boolean; protected _focusTracker: dom.IFocusTracker; protected _findInputFocusTracker: dom.IFocusTracker; @@ -91,14 +92,19 @@ export abstract class SimpleFindWidget extends Widget { onKeyDown: (e) => { } }); - this._domNode = document.createElement('div'); - this._domNode.classList.add('simple-find-part'); - this._domNode.appendChild(this._findInput.domNode); - this._domNode.appendChild(prevBtn.domNode); - this._domNode.appendChild(nextBtn.domNode); - this._domNode.appendChild(closeBtn.domNode); + this._innerDomNode = document.createElement('div'); + this._innerDomNode.classList.add('simple-find-part'); + this._innerDomNode.appendChild(this._findInput.domNode); + this._innerDomNode.appendChild(prevBtn.domNode); + this._innerDomNode.appendChild(nextBtn.domNode); + this._innerDomNode.appendChild(closeBtn.domNode); - this.onkeyup(this._domNode, e => { + // _domNode wraps _innerDomNode, ensuring that + this._domNode = document.createElement('div'); + this._domNode.classList.add('simple-find-part-wrapper'); + this._domNode.appendChild(this._innerDomNode); + + this.onkeyup(this._innerDomNode, e => { if (e.equals(KeyCode.Escape)) { this.hide(); e.preventDefault(); @@ -106,7 +112,7 @@ export abstract class SimpleFindWidget extends Widget { } }); - this._focusTracker = this._register(dom.trackFocus(this._domNode)); + this._focusTracker = this._register(dom.trackFocus(this._innerDomNode)); this._register(this._focusTracker.addFocusListener(this.onFocusTrackerFocus.bind(this))); this._register(this._focusTracker.addBlurListener(this.onFocusTrackerBlur.bind(this))); @@ -114,7 +120,7 @@ export abstract class SimpleFindWidget extends Widget { this._register(this._findInputFocusTracker.addFocusListener(this.onFindInputFocusTrackerFocus.bind(this))); this._register(this._findInputFocusTracker.addBlurListener(this.onFindInputFocusTrackerBlur.bind(this))); - this._register(dom.addDisposableListener(this._domNode, 'click', (event) => { + this._register(dom.addDisposableListener(this._innerDomNode, 'click', (event) => { event.stopPropagation(); })); } @@ -163,13 +169,13 @@ export abstract class SimpleFindWidget extends Widget { this._isVisible = true; setTimeout(() => { - dom.addClass(this._domNode, 'visible'); - this._domNode.setAttribute('aria-hidden', 'false'); + dom.addClass(this._innerDomNode, 'visible'); + this._innerDomNode.setAttribute('aria-hidden', 'false'); if (!this.animate) { - dom.addClass(this._domNode, 'noanimation'); + dom.addClass(this._innerDomNode, 'noanimation'); } setTimeout(() => { - dom.removeClass(this._domNode, 'noanimation'); + dom.removeClass(this._innerDomNode, 'noanimation'); this._findInput.select(); }, 200); }, 0); @@ -179,8 +185,8 @@ export abstract class SimpleFindWidget extends Widget { if (this._isVisible) { this._isVisible = false; - dom.removeClass(this._domNode, 'visible'); - this._domNode.setAttribute('aria-hidden', 'true'); + dom.removeClass(this._innerDomNode, 'visible'); + this._innerDomNode.setAttribute('aria-hidden', 'true'); } } diff --git a/src/vs/editor/contrib/find/common/findController.ts b/src/vs/editor/contrib/find/common/findController.ts index 09536d1f5f8..4ead5ef999c 100644 --- a/src/vs/editor/contrib/find/common/findController.ts +++ b/src/vs/editor/contrib/find/common/findController.ts @@ -6,25 +6,18 @@ import * as nls from 'vs/nls'; import { HistoryNavigator } from 'vs/base/common/history'; -import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable } from 'vs/base/common/lifecycle'; import { ContextKeyExpr, RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { Range } from 'vs/editor/common/core/range'; -import { Selection } from 'vs/editor/common/core/selection'; import * as strings from 'vs/base/common/strings'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { editorAction, commonEditorContribution, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; +import { editorAction, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding, ToggleSearchScopeKeybinding, ShowPreviousFindTermKeybinding, ShowNextFindTermKeybinding } from 'vs/editor/contrib/find/common/findModel'; import { FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState } from 'vs/editor/contrib/find/common/findState'; import { getSelectionSearchString } from 'vs/editor/contrib/find/common/find'; -import { DocumentHighlightProviderRegistry } from 'vs/editor/common/modes'; -import { RunOnceScheduler, Delayer } from 'vs/base/common/async'; -import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; +import { Delayer } from 'vs/base/common/async'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; -import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; -import { themeColorFromId } from 'vs/platform/theme/common/themeService'; export const enum FindStartFocusAction { NoFocusChange, @@ -514,614 +507,6 @@ export class StartFindReplaceAction extends EditorAction { } } -export interface IMultiCursorFindInput { - changeFindSearchString: boolean; - allowMultiline: boolean; - highlightFindOptions: boolean; -} - -export interface IMultiCursorFindResult { - searchText: string; - matchCase: boolean; - wholeWord: boolean; - - currentMatch: Selection; -} - -function multiCursorFind(editor: editorCommon.ICommonCodeEditor, input: IMultiCursorFindInput): IMultiCursorFindResult { - let controller = CommonFindController.get(editor); - if (!controller) { - return null; - } - let state = controller.getState(); - let searchText: string; - let currentMatch: Selection; - - // In any case, if the find widget was ever opened, the options are taken from it - let wholeWord = state.wholeWord; - let matchCase = state.matchCase; - - // Find widget owns what we search for if: - // - focus is not in the editor (i.e. it is in the find widget) - // - and the search widget is visible - // - and the search string is non-empty - if (!editor.isFocused() && state.isRevealed && state.searchString.length > 0) { - // Find widget owns what is searched for - searchText = state.searchString; - } else { - // Selection owns what is searched for - let s = editor.getSelection(); - - if (s.startLineNumber !== s.endLineNumber && !input.allowMultiline) { - // multiline forbidden - return null; - } - - if (s.isEmpty()) { - // selection is empty => expand to current word - let word = editor.getModel().getWordAtPosition(s.getStartPosition()); - if (!word) { - return null; - } - searchText = word.word; - currentMatch = new Selection(s.startLineNumber, word.startColumn, s.startLineNumber, word.endColumn); - } else { - searchText = editor.getModel().getValueInRange(s).replace(/\r\n/g, '\n'); - } - if (input.changeFindSearchString) { - controller.setSearchString(searchText); - } - } - - if (input.highlightFindOptions) { - controller.highlightFindOptions(); - } - - return { - searchText: searchText, - matchCase: matchCase, - wholeWord: wholeWord, - currentMatch: currentMatch - }; -} - -export abstract class SelectNextFindMatchAction extends EditorAction { - protected _getNextMatch(editor: editorCommon.ICommonCodeEditor): Selection { - let r = multiCursorFind(editor, { - changeFindSearchString: true, - allowMultiline: true, - highlightFindOptions: true - }); - if (!r) { - return null; - } - if (r.currentMatch) { - return r.currentMatch; - } - - let allSelections = editor.getSelections(); - let lastAddedSelection = allSelections[allSelections.length - 1]; - - let nextMatch = editor.getModel().findNextMatch(r.searchText, lastAddedSelection.getEndPosition(), false, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null, false); - - if (!nextMatch) { - return null; - } - - return new Selection(nextMatch.range.startLineNumber, nextMatch.range.startColumn, nextMatch.range.endLineNumber, nextMatch.range.endColumn); - } -} - -export abstract class SelectPreviousFindMatchAction extends EditorAction { - protected _getPreviousMatch(editor: editorCommon.ICommonCodeEditor): Selection { - let r = multiCursorFind(editor, { - changeFindSearchString: true, - allowMultiline: true, - highlightFindOptions: true - }); - if (!r) { - return null; - } - if (r.currentMatch) { - return r.currentMatch; - } - - let allSelections = editor.getSelections(); - let lastAddedSelection = allSelections[allSelections.length - 1]; - - let previousMatch = editor.getModel().findPreviousMatch(r.searchText, lastAddedSelection.getStartPosition(), false, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null, false); - - if (!previousMatch) { - return null; - } - - return new Selection(previousMatch.range.startLineNumber, previousMatch.range.startColumn, previousMatch.range.endLineNumber, previousMatch.range.endColumn); - } -} - -@editorAction -export class AddSelectionToNextFindMatchAction extends SelectNextFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.AddSelectionToNextFindMatchAction, - label: nls.localize('addSelectionToNextFindMatch', "Add Selection To Next Find Match"), - alias: 'Add Selection To Next Find Match', - precondition: null, - kbOpts: { - kbExpr: EditorContextKeys.focus, - primary: KeyMod.CtrlCmd | KeyCode.KEY_D - } - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - const allSelections = editor.getSelections(); - - // If there are mulitple cursors, handle the case where they do not all select the same text. - if (allSelections.length > 1) { - const model = editor.getModel(); - const controller = CommonFindController.get(editor); - if (!controller) { - return; - } - const findState = controller.getState(); - const caseSensitive = findState.matchCase; - - let selectionsContainSameText = true; - - let selectedText = model.getValueInRange(allSelections[0]); - if (!caseSensitive) { - selectedText = selectedText.toLowerCase(); - } - for (let i = 1, len = allSelections.length; i < len; i++) { - let selection = allSelections[i]; - if (selection.isEmpty()) { - selectionsContainSameText = false; - break; - } - - let thisSelectedText = model.getValueInRange(selection); - if (!caseSensitive) { - thisSelectedText = thisSelectedText.toLowerCase(); - } - if (selectedText !== thisSelectedText) { - selectionsContainSameText = false; - break; - } - } - - if (!selectionsContainSameText) { - let resultingSelections: Selection[] = []; - for (let i = 0, len = allSelections.length; i < len; i++) { - let selection = allSelections[i]; - if (selection.isEmpty()) { - let word = editor.getModel().getWordAtPosition(selection.getStartPosition()); - if (word) { - resultingSelections[i] = new Selection(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn); - continue; - } - } - resultingSelections[i] = selection; - } - editor.setSelections(resultingSelections); - return; - } - } - - let nextMatch = this._getNextMatch(editor); - - if (!nextMatch) { - return; - } - - editor.setSelections(allSelections.concat(nextMatch)); - editor.revealRangeInCenterIfOutsideViewport(nextMatch, editorCommon.ScrollType.Smooth); - } -} - -@editorAction -export class AddSelectionToPreviousFindMatchAction extends SelectPreviousFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.AddSelectionToPreviousFindMatchAction, - label: nls.localize('addSelectionToPreviousFindMatch', "Add Selection To Previous Find Match"), - alias: 'Add Selection To Previous Find Match', - precondition: null - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let previousMatch = this._getPreviousMatch(editor); - - if (!previousMatch) { - return; - } - - let allSelections = editor.getSelections(); - editor.setSelections(allSelections.concat(previousMatch)); - editor.revealRangeInCenterIfOutsideViewport(previousMatch, editorCommon.ScrollType.Smooth); - } -} - -@editorAction -export class MoveSelectionToNextFindMatchAction extends SelectNextFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.MoveSelectionToNextFindMatchAction, - label: nls.localize('moveSelectionToNextFindMatch', "Move Last Selection To Next Find Match"), - alias: 'Move Last Selection To Next Find Match', - precondition: null, - kbOpts: { - kbExpr: EditorContextKeys.focus, - primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D) - } - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let nextMatch = this._getNextMatch(editor); - - if (!nextMatch) { - return; - } - - let allSelections = editor.getSelections(); - editor.setSelections(allSelections.slice(0, allSelections.length - 1).concat(nextMatch)); - editor.revealRangeInCenterIfOutsideViewport(nextMatch, editorCommon.ScrollType.Smooth); - } -} - -@editorAction -export class MoveSelectionToPreviousFindMatchAction extends SelectPreviousFindMatchAction { - - constructor() { - super({ - id: FIND_IDS.MoveSelectionToPreviousFindMatchAction, - label: nls.localize('moveSelectionToPreviousFindMatch', "Move Last Selection To Previous Find Match"), - alias: 'Move Last Selection To Previous Find Match', - precondition: null - }); - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let previousMatch = this._getPreviousMatch(editor); - - if (!previousMatch) { - return; - } - - let allSelections = editor.getSelections(); - editor.setSelections(allSelections.slice(0, allSelections.length - 1).concat(previousMatch)); - editor.revealRangeInCenterIfOutsideViewport(previousMatch, editorCommon.ScrollType.Smooth); - } -} - -export abstract class AbstractSelectHighlightsAction extends EditorAction { - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let controller = CommonFindController.get(editor); - if (!controller) { - return null; - } - - let matches: Range[] = null; - - const findState = controller.getState(); - if (findState.isRevealed && findState.isRegex && findState.searchString.length > 0) { - - matches = editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? editor.getConfiguration().wordSeparators : null, false).map(m => m.range); - - } else { - - let r = multiCursorFind(editor, { - changeFindSearchString: true, - allowMultiline: true, - highlightFindOptions: true - }); - if (!r) { - return; - } - - matches = editor.getModel().findMatches(r.searchText, true, false, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null, false).map(m => m.range); - } - - if (matches.length > 0) { - let editorSelection = editor.getSelection(); - for (let i = 0, len = matches.length; i < len; i++) { - let match = matches[i]; - let intersection = match.intersectRanges(editorSelection); - if (intersection) { - // bingo! - matches.splice(i, 1); - matches.unshift(match); - break; - } - } - editor.setSelections(matches.map(m => new Selection(m.startLineNumber, m.startColumn, m.endLineNumber, m.endColumn))); - } - } -} - -@editorAction -export class SelectHighlightsAction extends AbstractSelectHighlightsAction { - constructor() { - super({ - id: 'editor.action.selectHighlights', - label: nls.localize('selectAllOccurrencesOfFindMatch', "Select All Occurrences of Find Match"), - alias: 'Select All Occurrences of Find Match', - precondition: null, - kbOpts: { - kbExpr: EditorContextKeys.focus, - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L - } - }); - } -} - -@editorAction -export class CompatChangeAll extends AbstractSelectHighlightsAction { - constructor() { - super({ - id: 'editor.action.changeAll', - label: nls.localize('changeAll.label', "Change All Occurrences"), - alias: 'Change All Occurrences', - precondition: EditorContextKeys.writable, - kbOpts: { - kbExpr: EditorContextKeys.textFocus, - primary: KeyMod.CtrlCmd | KeyCode.F2 - }, - menuOpts: { - group: '1_modification', - order: 1.2 - } - }); - } -} - -class SelectionHighlighterState { - public readonly lastWordUnderCursor: Selection; - public readonly searchText: string; - public readonly matchCase: boolean; - public readonly wordSeparators: string; - - constructor(lastWordUnderCursor: Selection, searchText: string, matchCase: boolean, wordSeparators: string) { - this.searchText = searchText; - this.matchCase = matchCase; - this.wordSeparators = wordSeparators; - } - - /** - * Everything equals except for `lastWordUnderCursor` - */ - public static softEquals(a: SelectionHighlighterState, b: SelectionHighlighterState): boolean { - if (!a && !b) { - return true; - } - if (!a || !b) { - return false; - } - return ( - a.searchText === b.searchText - && a.matchCase === b.matchCase - && a.wordSeparators === b.wordSeparators - ); - } -} - -@commonEditorContribution -export class SelectionHighlighter extends Disposable implements editorCommon.IEditorContribution { - private static ID = 'editor.contrib.selectionHighlighter'; - - private editor: editorCommon.ICommonCodeEditor; - private _isEnabled: boolean; - private decorations: string[]; - private updateSoon: RunOnceScheduler; - private state: SelectionHighlighterState; - - constructor(editor: editorCommon.ICommonCodeEditor) { - super(); - this.editor = editor; - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; - this.decorations = []; - this.updateSoon = this._register(new RunOnceScheduler(() => this._update(), 300)); - this.state = null; - - this._register(editor.onDidChangeConfiguration((e) => { - this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; - })); - this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { - - if (!this._isEnabled) { - // Early exit if nothing needs to be done! - // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;) - return; - } - - if (e.selection.isEmpty()) { - if (e.reason === CursorChangeReason.Explicit) { - if (this.state && (!this.state.lastWordUnderCursor || !this.state.lastWordUnderCursor.containsPosition(e.selection.getStartPosition()))) { - // no longer valid - this._setState(null); - } - this.updateSoon.schedule(); - } else { - this._setState(null); - - } - } else { - this._update(); - } - })); - this._register(editor.onDidChangeModel((e) => { - this._setState(null); - })); - this._register(CommonFindController.get(editor).getState().addChangeListener((e) => { - this._update(); - })); - } - - public getId(): string { - return SelectionHighlighter.ID; - } - - private _update(): void { - this._setState(SelectionHighlighter._createState(this._isEnabled, this.editor)); - } - - private static _createState(isEnabled: boolean, editor: editorCommon.ICommonCodeEditor): SelectionHighlighterState { - const model = editor.getModel(); - if (!model) { - return null; - } - - const config = editor.getConfiguration(); - - let lastWordUnderCursor: Selection = null; - if (!isEnabled) { - return null; - } - - const r = multiCursorFind(editor, { - changeFindSearchString: false, - allowMultiline: false, - highlightFindOptions: false - }); - if (!r) { - return null; - } - - const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); - if (r.currentMatch) { - // This is an empty selection - if (hasFindOccurrences) { - // Do not interfere with semantic word highlighting in the no selection case - return null; - } - - if (!config.contribInfo.occurrencesHighlight) { - return null; - } - - lastWordUnderCursor = r.currentMatch; - } - if (/^[ \t]+$/.test(r.searchText)) { - // whitespace only selection - return null; - } - if (r.searchText.length > 200) { - // very long selection - return null; - } - - const controller = CommonFindController.get(editor); - if (!controller) { - return null; - } - const findState = controller.getState(); - const caseSensitive = findState.matchCase; - - const selections = editor.getSelections(); - let firstSelectedText = model.getValueInRange(selections[0]); - if (!caseSensitive) { - firstSelectedText = firstSelectedText.toLowerCase(); - } - for (let i = 1; i < selections.length; i++) { - let selectedText = model.getValueInRange(selections[i]); - if (!caseSensitive) { - selectedText = selectedText.toLowerCase(); - } - if (firstSelectedText !== selectedText) { - // not all selections have the same text - return null; - } - } - - return new SelectionHighlighterState(lastWordUnderCursor, r.searchText, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null); - } - - - private _setState(state: SelectionHighlighterState): void { - if (SelectionHighlighterState.softEquals(this.state, state)) { - this.state = state; - return; - } - this.state = state; - - if (!this.state) { - if (this.decorations.length > 0) { - this.decorations = this.editor.deltaDecorations(this.decorations, []); - } - return; - } - - const model = this.editor.getModel(); - const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); - - let allMatches = model.findMatches(this.state.searchText, true, false, this.state.matchCase, this.state.wordSeparators, false).map(m => m.range); - allMatches.sort(Range.compareRangesUsingStarts); - - let selections = this.editor.getSelections(); - selections.sort(Range.compareRangesUsingStarts); - - // do not overlap with selection (issue #64 and #512) - let matches: Range[] = []; - for (let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len;) { - const match = allMatches[i]; - - if (j >= lenJ) { - // finished all editor selections - matches.push(match); - i++; - } else { - const cmp = Range.compareRangesUsingStarts(match, selections[j]); - if (cmp < 0) { - // match is before sel - matches.push(match); - i++; - } else if (cmp > 0) { - // sel is before match - j++; - } else { - // sel is equal to match - i++; - j++; - } - } - } - - const decorations = matches.map(r => { - return { - range: r, - // Show in overviewRuler only if model has no semantic highlighting - options: (hasFindOccurrences ? SelectionHighlighter._SELECTION_HIGHLIGHT : SelectionHighlighter._SELECTION_HIGHLIGHT_OVERVIEW) - }; - }); - - this.decorations = this.editor.deltaDecorations(this.decorations, decorations); - } - - private static _SELECTION_HIGHLIGHT_OVERVIEW = ModelDecorationOptions.register({ - stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'selectionHighlight', - overviewRuler: { - color: themeColorFromId(overviewRulerSelectionHighlightForeground), - darkColor: themeColorFromId(overviewRulerSelectionHighlightForeground), - position: editorCommon.OverviewRulerLane.Center - } - }); - - private static _SELECTION_HIGHLIGHT = ModelDecorationOptions.register({ - stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'selectionHighlight', - }); - - public dispose(): void { - this._setState(null); - super.dispose(); - } -} @editorAction export class ShowNextFindTermAction extends MatchFindAction { diff --git a/src/vs/editor/contrib/find/common/findDecorations.ts b/src/vs/editor/contrib/find/common/findDecorations.ts index 24e13040b12..09cb7eb07d0 100644 --- a/src/vs/editor/contrib/find/common/findDecorations.ts +++ b/src/vs/editor/contrib/find/common/findDecorations.ts @@ -16,6 +16,7 @@ export class FindDecorations implements IDisposable { private _editor: editorCommon.ICommonCodeEditor; private _decorations: string[]; + private _overviewRulerApproximateDecorations: string[]; private _findScopeDecorationId: string; private _rangeHighlightDecorationId: string; private _highlightedDecorationId: string; @@ -24,6 +25,7 @@ export class FindDecorations implements IDisposable { constructor(editor: editorCommon.ICommonCodeEditor) { this._editor = editor; this._decorations = []; + this._overviewRulerApproximateDecorations = []; this._findScopeDecorationId = null; this._rangeHighlightDecorationId = null; this._highlightedDecorationId = null; @@ -35,6 +37,7 @@ export class FindDecorations implements IDisposable { this._editor = null; this._decorations = []; + this._overviewRulerApproximateDecorations = []; this._findScopeDecorationId = null; this._rangeHighlightDecorationId = null; this._highlightedDecorationId = null; @@ -43,6 +46,7 @@ export class FindDecorations implements IDisposable { public reset(): void { this._decorations = []; + this._overviewRulerApproximateDecorations = []; this._findScopeDecorationId = null; this._rangeHighlightDecorationId = null; this._highlightedDecorationId = null; @@ -68,11 +72,21 @@ export class FindDecorations implements IDisposable { this.setCurrentFindMatch(null); } + private _getDecorationIndex(decorationId: string): number { + const index = this._decorations.indexOf(decorationId); + if (index >= 0) { + return index + 1; + } + return 1; + } + public getCurrentMatchesPosition(desiredRange: Range): number { - for (let i = 0, len = this._decorations.length; i < len; i++) { - let range = this._editor.getModel().getDecorationRange(this._decorations[i]); - if (desiredRange.equalsRange(range)) { - return (i + 1); + let candidates = this._editor.getModel().getDecorationsInRange(desiredRange); + for (let i = 0, len = candidates.length; i < len; i++) { + const candidate = candidates[i]; + const candidateOpts = candidate.options; + if (candidateOpts === FindDecorations._FIND_MATCH_DECORATION || candidateOpts === FindDecorations._CURRENT_FIND_MATCH_DECORATION) { + return this._getDecorationIndex(candidate.id); } } return 1; @@ -95,12 +109,12 @@ export class FindDecorations implements IDisposable { if (this._highlightedDecorationId !== null || newCurrentDecorationId !== null) { this._editor.changeDecorations((changeAccessor: editorCommon.IModelDecorationsChangeAccessor) => { if (this._highlightedDecorationId !== null) { - changeAccessor.changeDecorationOptions(this._highlightedDecorationId, FindDecorations.createFindMatchDecorationOptions(false)); + changeAccessor.changeDecorationOptions(this._highlightedDecorationId, FindDecorations._FIND_MATCH_DECORATION); this._highlightedDecorationId = null; } if (newCurrentDecorationId !== null) { this._highlightedDecorationId = newCurrentDecorationId; - changeAccessor.changeDecorationOptions(this._highlightedDecorationId, FindDecorations.createFindMatchDecorationOptions(true)); + changeAccessor.changeDecorationOptions(this._highlightedDecorationId, FindDecorations._CURRENT_FIND_MATCH_DECORATION); } if (this._rangeHighlightDecorationId !== null) { changeAccessor.removeDecoration(this._rangeHighlightDecorationId); @@ -108,6 +122,11 @@ export class FindDecorations implements IDisposable { } if (newCurrentDecorationId !== null) { let rng = this._editor.getModel().getDecorationRange(newCurrentDecorationId); + if (rng.startLineNumber !== rng.endLineNumber && rng.endColumn === 1) { + let lineBeforeEnd = rng.endLineNumber - 1; + let lineBeforeEndMaxColumn = this._editor.getModel().getLineMaxColumn(lineBeforeEnd); + rng = new Range(rng.startLineNumber, rng.startColumn, lineBeforeEnd, lineBeforeEndMaxColumn); + } this._rangeHighlightDecorationId = changeAccessor.addDecoration(rng, FindDecorations._RANGE_HIGHLIGHT_DECORATION); } }); @@ -116,34 +135,82 @@ export class FindDecorations implements IDisposable { return matchPosition; } - public set(matches: Range[], findScope: Range): void { - let newDecorations: editorCommon.IModelDeltaDecoration[] = matches.map((match) => { - return { - range: match, - options: FindDecorations.createFindMatchDecorationOptions(false) - }; - }); - if (findScope) { - newDecorations.unshift({ - range: findScope, - options: FindDecorations._FIND_SCOPE_DECORATION - }); - } - let tmpDecorations = this._editor.deltaDecorations(this._allDecorations(), newDecorations); + public set(findMatches: editorCommon.FindMatch[], findScope: Range): void { + this._editor.changeDecorations((accessor) => { - if (findScope) { - this._findScopeDecorationId = tmpDecorations.shift(); - } else { - this._findScopeDecorationId = null; - } - this._decorations = tmpDecorations; - this._rangeHighlightDecorationId = null; - this._highlightedDecorationId = null; + let findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION; + let newOverviewRulerApproximateDecorations: editorCommon.IModelDeltaDecoration[] = []; + + if (findMatches.length > 1000) { + // we go into a mode where the overview ruler gets "approximate" decorations + // the reason is that the overview ruler paints all the decorations in the file and we don't want to cause freezes + findMatchesOptions = FindDecorations._FIND_MATCH_NO_OVERVIEW_DECORATION; + + // approximate a distance in lines where matches should be merged + const lineCount = this._editor.getModel().getLineCount(); + const height = this._editor.getLayoutInfo().height; + const approxPixelsPerLine = height / lineCount; + const mergeLinesDelta = Math.max(2, Math.ceil(3 / approxPixelsPerLine)); + + // merge decorations as much as possible + let prevStartLineNumber = findMatches[0].range.startLineNumber; + let prevEndLineNumber = findMatches[0].range.endLineNumber; + for (let i = 1, len = findMatches.length; i < len; i++) { + const range = findMatches[i].range; + if (prevEndLineNumber + mergeLinesDelta >= range.startLineNumber) { + if (range.endLineNumber > prevEndLineNumber) { + prevEndLineNumber = range.endLineNumber; + } + } else { + newOverviewRulerApproximateDecorations.push({ + range: new Range(prevStartLineNumber, 1, prevEndLineNumber, 1), + options: FindDecorations._FIND_MATCH_ONLY_OVERVIEW_DECORATION + }); + prevStartLineNumber = range.startLineNumber; + prevEndLineNumber = range.endLineNumber; + } + } + + newOverviewRulerApproximateDecorations.push({ + range: new Range(prevStartLineNumber, 1, prevEndLineNumber, 1), + options: FindDecorations._FIND_MATCH_ONLY_OVERVIEW_DECORATION + }); + } + + // Find matches + let newFindMatchesDecorations: editorCommon.IModelDeltaDecoration[] = new Array(findMatches.length); + for (let i = 0, len = findMatches.length; i < len; i++) { + newFindMatchesDecorations[i] = { + range: findMatches[i].range, + options: findMatchesOptions + }; + } + this._decorations = accessor.deltaDecorations(this._decorations, newFindMatchesDecorations); + + // Overview ruler approximate decorations + this._overviewRulerApproximateDecorations = accessor.deltaDecorations(this._overviewRulerApproximateDecorations, newOverviewRulerApproximateDecorations); + + // Range highlight + if (this._rangeHighlightDecorationId) { + accessor.removeDecoration(this._rangeHighlightDecorationId); + this._rangeHighlightDecorationId = null; + } + + // Find scope + if (this._findScopeDecorationId) { + accessor.removeDecoration(this._findScopeDecorationId); + this._findScopeDecorationId = null; + } + if (findScope) { + this._findScopeDecorationId = accessor.addDecoration(findScope, FindDecorations._FIND_SCOPE_DECORATION); + } + }); } private _allDecorations(): string[] { let result: string[] = []; result = result.concat(this._decorations); + result = result.concat(this._overviewRulerApproximateDecorations); if (this._findScopeDecorationId) { result.push(this._findScopeDecorationId); } @@ -153,10 +220,6 @@ export class FindDecorations implements IDisposable { return result; } - private static createFindMatchDecorationOptions(isCurrent: boolean): ModelDecorationOptions { - return (isCurrent ? this._CURRENT_FIND_MATCH_DECORATION : this._FIND_MATCH_DECORATION); - } - private static _CURRENT_FIND_MATCH_DECORATION = ModelDecorationOptions.register({ stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'currentFindMatch', @@ -179,6 +242,21 @@ export class FindDecorations implements IDisposable { } }); + private static _FIND_MATCH_NO_OVERVIEW_DECORATION = ModelDecorationOptions.register({ + stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'findMatch', + showIfCollapsed: true + }); + + private static _FIND_MATCH_ONLY_OVERVIEW_DECORATION = ModelDecorationOptions.register({ + stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + overviewRuler: { + color: themeColorFromId(editorFindMatchHighlight), + darkColor: themeColorFromId(editorFindMatchHighlight), + position: editorCommon.OverviewRulerLane.Center + } + }); + private static _RANGE_HIGHLIGHT_DECORATION = ModelDecorationOptions.register({ stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'rangeHighlight', diff --git a/src/vs/editor/contrib/find/common/findModel.ts b/src/vs/editor/contrib/find/common/findModel.ts index 156e525f5e6..1536e8c9541 100644 --- a/src/vs/editor/contrib/find/common/findModel.ts +++ b/src/vs/editor/contrib/find/common/findModel.ts @@ -50,10 +50,6 @@ export const FIND_IDS = { PreviousMatchFindAction: 'editor.action.previousMatchFindAction', NextSelectionMatchFindAction: 'editor.action.nextSelectionMatchFindAction', PreviousSelectionMatchFindAction: 'editor.action.previousSelectionMatchFindAction', - AddSelectionToNextFindMatchAction: 'editor.action.addSelectionToNextFindMatch', - AddSelectionToPreviousFindMatchAction: 'editor.action.addSelectionToPreviousFindMatch', - MoveSelectionToNextFindMatchAction: 'editor.action.moveSelectionToNextFindMatch', - MoveSelectionToPreviousFindMatchAction: 'editor.action.moveSelectionToPreviousFindMatch', StartFindReplaceAction: 'editor.action.startFindReplaceAction', CloseFindWidgetCommand: 'closeFindWidget', ToggleCaseSensitiveCommand: 'toggleFindCaseSensitive', @@ -67,7 +63,7 @@ export const FIND_IDS = { ShowNextFindTermAction: 'find.history.showNext' }; -export const MATCHES_LIMIT = 999; +export const MATCHES_LIMIT = 19999; export class FindModelBoundToEditorModel { @@ -130,6 +126,10 @@ export class FindModelBoundToEditorModel { // The find model is disposed during a find state changed event return; } + if (!this._editor.getModel()) { + // The find model will be disposed momentarily + return; + } if (e.searchString || e.isReplaceRevealed || e.isRegex || e.wholeWord || e.matchCase || e.searchScope) { if (e.searchScope) { this.research(e.moveCursor, this._state.searchScope); @@ -171,7 +171,7 @@ export class FindModelBoundToEditorModel { } let findMatches = this._findMatches(findScope, false, MATCHES_LIMIT); - this._decorations.set(findMatches.map(match => match.range), findScope); + this._decorations.set(findMatches, findScope); this._state.changeMatchInfo( this._decorations.getCurrentMatchesPosition(this._editor.getSelection()), @@ -409,6 +409,18 @@ export class FindModelBoundToEditorModel { return; } + let searchRegex = searchData.regex; + if (!searchRegex.multiline) { + let mod = 'm'; + if (searchRegex.ignoreCase) { + mod += 'i'; + } + if (searchRegex.global) { + mod += 'g'; + } + searchRegex = new RegExp(searchRegex.source, mod); + } + const model = this._editor.getModel(); const modelText = model.getValue(editorCommon.EndOfLinePreference.LF); const fullModelRange = model.getFullModelRange(); @@ -416,11 +428,11 @@ export class FindModelBoundToEditorModel { const replacePattern = this._getReplacePattern(); let resultText: string; if (replacePattern.hasReplacementPatterns) { - resultText = modelText.replace(searchData.regex, function () { + resultText = modelText.replace(searchRegex, function () { return replacePattern.buildReplaceString(arguments); }); } else { - resultText = modelText.replace(searchData.regex, replacePattern.buildReplaceString(null)); + resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null)); } let command = new ReplaceCommandThatPreservesSelection(fullModelRange, resultText, this._editor.getSelection()); diff --git a/src/vs/editor/contrib/find/common/findState.ts b/src/vs/editor/contrib/find/common/findState.ts index 0dccd531f7a..000ee49bfd5 100644 --- a/src/vs/editor/contrib/find/common/findState.ts +++ b/src/vs/editor/contrib/find/common/findState.ts @@ -25,17 +25,36 @@ export interface FindReplaceStateChangedEvent { currentMatch: boolean; } +export const enum FindOptionOverride { + NotSet = 0, + True = 1, + False = 2 +} + export interface INewFindReplaceState { searchString?: string; replaceString?: string; isRevealed?: boolean; isReplaceRevealed?: boolean; isRegex?: boolean; + isRegexOverride?: FindOptionOverride; wholeWord?: boolean; + wholeWordOverride?: FindOptionOverride; matchCase?: boolean; + matchCaseOverride?: FindOptionOverride; searchScope?: Range; } +function effectiveOptionValue(override: FindOptionOverride, value: boolean): boolean { + if (override === FindOptionOverride.True) { + return true; + } + if (override === FindOptionOverride.False) { + return false; + } + return value; +} + export class FindReplaceState implements IDisposable { private static _CHANGED_EVENT = 'changed'; @@ -45,8 +64,11 @@ export class FindReplaceState implements IDisposable { private _isRevealed: boolean; private _isReplaceRevealed: boolean; private _isRegex: boolean; + private _isRegexOverride: FindOptionOverride; private _wholeWord: boolean; + private _wholeWordOverride: FindOptionOverride; private _matchCase: boolean; + private _matchCaseOverride: FindOptionOverride; private _searchScope: Range; private _matchesPosition: number; private _matchesCount: number; @@ -57,9 +79,9 @@ export class FindReplaceState implements IDisposable { public get replaceString(): string { return this._replaceString; } public get isRevealed(): boolean { return this._isRevealed; } public get isReplaceRevealed(): boolean { return this._isReplaceRevealed; } - public get isRegex(): boolean { return this._isRegex; } - public get wholeWord(): boolean { return this._wholeWord; } - public get matchCase(): boolean { return this._matchCase; } + public get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); } + public get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); } + public get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); } public get searchScope(): Range { return this._searchScope; } public get matchesPosition(): number { return this._matchesPosition; } public get matchesCount(): number { return this._matchesCount; } @@ -71,8 +93,11 @@ export class FindReplaceState implements IDisposable { this._isRevealed = false; this._isReplaceRevealed = false; this._isRegex = false; + this._isRegexOverride = FindOptionOverride.NotSet; this._wholeWord = false; + this._wholeWordOverride = FindOptionOverride.NotSet; this._matchCase = false; + this._matchCaseOverride = FindOptionOverride.NotSet; this._searchScope = null; this._matchesPosition = 0; this._matchesCount = 0; @@ -155,6 +180,10 @@ export class FindReplaceState implements IDisposable { }; let somethingChanged = false; + const oldEffectiveIsRegex = this.isRegex; + const oldEffectiveWholeWords = this.wholeWord; + const oldEffectiveMatchCase = this.matchCase; + if (typeof newState.searchString !== 'undefined') { if (this._searchString !== newState.searchString) { this._searchString = newState.searchString; @@ -184,25 +213,13 @@ export class FindReplaceState implements IDisposable { } } if (typeof newState.isRegex !== 'undefined') { - if (this._isRegex !== newState.isRegex) { - this._isRegex = newState.isRegex; - changeEvent.isRegex = true; - somethingChanged = true; - } + this._isRegex = newState.isRegex; } if (typeof newState.wholeWord !== 'undefined') { - if (this._wholeWord !== newState.wholeWord) { - this._wholeWord = newState.wholeWord; - changeEvent.wholeWord = true; - somethingChanged = true; - } + this._wholeWord = newState.wholeWord; } if (typeof newState.matchCase !== 'undefined') { - if (this._matchCase !== newState.matchCase) { - this._matchCase = newState.matchCase; - changeEvent.matchCase = true; - somethingChanged = true; - } + this._matchCase = newState.matchCase; } if (typeof newState.searchScope !== 'undefined') { if (!Range.equalsRange(this._searchScope, newState.searchScope)) { @@ -212,6 +229,24 @@ export class FindReplaceState implements IDisposable { } } + // Overrides get set when they explicitly come in and get reset anytime something else changes + this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet); + this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet); + this._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet); + + if (oldEffectiveIsRegex !== this.isRegex) { + somethingChanged = true; + changeEvent.isRegex = true; + } + if (oldEffectiveWholeWords !== this.wholeWord) { + somethingChanged = true; + changeEvent.wholeWord = true; + } + if (oldEffectiveMatchCase !== this.matchCase) { + somethingChanged = true; + changeEvent.matchCase = true; + } + if (somethingChanged) { this._eventEmitter.emit(FindReplaceState._CHANGED_EVENT, changeEvent); } diff --git a/src/vs/editor/contrib/find/test/common/findController.test.ts b/src/vs/editor/contrib/find/test/common/findController.test.ts index 20559f5713b..4a0f9c37130 100644 --- a/src/vs/editor/contrib/find/test/common/findController.test.ts +++ b/src/vs/editor/contrib/find/test/common/findController.test.ts @@ -11,20 +11,16 @@ import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; import { Range } from 'vs/editor/common/core/range'; -import { EndOfLineSequence, ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon'; -import { - CommonFindController, FindStartFocusAction, IFindStartOptions, - NextMatchFindAction, StartFindAction, SelectHighlightsAction, - AddSelectionToNextFindMatchAction -} from 'vs/editor/contrib/find/common/findController'; -import { MockCodeEditor, withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; +import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; +import { CommonFindController, FindStartFocusAction, IFindStartOptions, NextMatchFindAction, StartFindAction } from 'vs/editor/contrib/find/common/findController'; +import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; import { HistoryNavigator } from 'vs/base/common/history'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { Delayer } from 'vs/base/common/async'; -class TestFindController extends CommonFindController { +export class TestFindController extends CommonFindController { public hasFocus: boolean; public delayUpdateHistory: boolean = false; @@ -75,11 +71,11 @@ function fromRange(rng: Range): number[] { suite('FindController', () => { let queryState: { [key: string]: any; } = {}; let serviceCollection = new ServiceCollection(); - serviceCollection.set(IStorageService, { + serviceCollection.set(IStorageService, { get: (key: string) => queryState[key], getBoolean: (key: string) => !!queryState[key], store: (key: string, value: any) => { queryState[key] = value; } - }); + } as IStorageService); test('issue #1857: F3, Find Next, acts like "Find Under Cursor"', () => { withMockCodeEditor([ @@ -188,60 +184,6 @@ suite('FindController', () => { }); }); - test('issue #8817: Cursor position changes when you cancel multicursor', () => { - withMockCodeEditor([ - 'var x = (3 * 5)', - 'var y = (3 * 5)', - 'var z = (3 * 5)', - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let selectHighlightsAction = new SelectHighlightsAction(); - - editor.setSelection(new Selection(2, 9, 2, 16)); - - selectHighlightsAction.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [2, 9, 2, 16], - [1, 9, 1, 16], - [3, 9, 3, 16], - ]); - - editor.trigger('test', 'removeSecondaryCursors', null); - - assert.deepEqual(fromRange(editor.getSelection()), [2, 9, 2, 16]); - - findController.dispose(); - }); - }); - - test('issue #5400: "Select All Occurrences of Find Match" does not select all if find uses regex', () => { - withMockCodeEditor([ - 'something', - 'someething', - 'someeething', - 'nothing' - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let selectHighlightsAction = new SelectHighlightsAction(); - - editor.setSelection(new Selection(1, 1, 1, 1)); - findController.getState().change({ searchString: 'some+thing', isRegex: true, isRevealed: true }, false); - - selectHighlightsAction.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 1, 1, 10], - [2, 1, 2, 11], - [3, 1, 3, 12], - ]); - - assert.equal(findController.getState().searchString, 'some+thing'); - - findController.dispose(); - }); - }); - test('issue #9043: Clear search scope when find widget is hidden', () => { withMockCodeEditor([ 'var x = (3 * 5)', @@ -380,119 +322,6 @@ suite('FindController', () => { }); }); - test('AddSelectionToNextFindMatchAction can work with multiline', () => { - withMockCodeEditor([ - '', - 'qwe', - 'rty', - '', - 'qwe', - '', - 'rty', - 'qwe', - 'rty' - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); - - editor.setSelection(new Selection(2, 1, 3, 4)); - - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [2, 1, 3, 4], - [8, 1, 9, 4] - ]); - - editor.trigger('test', 'removeSecondaryCursors', null); - - assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); - - findController.dispose(); - }); - }); - - test('issue #6661: AddSelectionToNextFindMatchAction can work with touching ranges', () => { - withMockCodeEditor([ - 'abcabc', - 'abc', - 'abcabc', - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); - - editor.setSelection(new Selection(1, 1, 1, 4)); - - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 1, 1, 4], - [1, 4, 1, 7] - ]); - - addSelectionToNextFindMatch.run(null, editor); - addSelectionToNextFindMatch.run(null, editor); - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 1, 1, 4], - [1, 4, 1, 7], - [2, 1, 2, 4], - [3, 1, 3, 4], - [3, 4, 3, 7] - ]); - - editor.trigger('test', Handler.Type, { text: 'z' }); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [1, 2, 1, 2], - [1, 3, 1, 3], - [2, 2, 2, 2], - [3, 2, 3, 2], - [3, 3, 3, 3] - ]); - assert.equal(editor.getValue(), [ - 'zz', - 'z', - 'zz', - ].join('\n')); - - findController.dispose(); - }); - }); - - test('issue #23541: Multiline Ctrl+D does not work in CRLF files', () => { - withMockCodeEditor([ - '', - 'qwe', - 'rty', - '', - 'qwe', - '', - 'rty', - 'qwe', - 'rty' - ], { serviceCollection: serviceCollection }, (editor, cursor) => { - - editor.getModel().setEOL(EndOfLineSequence.CRLF); - - let findController = editor.registerAndInstantiateContribution(TestFindController); - let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); - - editor.setSelection(new Selection(2, 1, 3, 4)); - - addSelectionToNextFindMatch.run(null, editor); - assert.deepEqual(editor.getSelections().map(fromRange), [ - [2, 1, 3, 4], - [8, 1, 9, 4] - ]); - - editor.trigger('test', 'removeSecondaryCursors', null); - - assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); - - findController.dispose(); - }); - }); - test('issue #18111: Regex replace with single space replaces with no space', () => { withMockCodeEditor([ 'HRESULT OnAmbientPropertyChange(DISPID dispid);' @@ -555,237 +384,6 @@ suite('FindController', () => { } return result; } - - function testAddSelectionToNextFindMatchAction(text: string[], callback: (editor: MockCodeEditor, action: AddSelectionToNextFindMatchAction, findController: TestFindController) => void): void { - withMockCodeEditor(text, { serviceCollection: serviceCollection }, (editor, cursor) => { - - let findController = editor.registerAndInstantiateContribution(TestFindController); - - let action = new AddSelectionToNextFindMatchAction(); - - callback(editor, action, findController); - - findController.dispose(); - }); - } - - test('AddSelectionToNextFindMatchAction starting with single collapsed selection', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 2, 1, 2), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 1)', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 1, 1, 4), - new Selection(2, 2, 2, 2), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 2)', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 2, 1, 2), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with all collapsed selections', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 2, 1, 2), - new Selection(2, 2, 2, 2), - new Selection(3, 1, 3, 1), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 4), - new Selection(2, 1, 2, 4), - new Selection(3, 1, 3, 4), - ]); - }); - }); - - test('AddSelectionToNextFindMatchAction starting with all collapsed selections on different words', () => { - const text = [ - 'abc pizza', - 'abc house', - 'abc bar' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 6, 1, 6), - new Selection(2, 6, 2, 6), - new Selection(3, 6, 3, 6), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 5, 1, 10), - new Selection(2, 5, 2, 10), - new Selection(3, 5, 3, 8), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 5, 1, 10), - new Selection(2, 5, 2, 10), - new Selection(3, 5, 3, 8), - ]); - }); - }); - - test('issue #20651: AddSelectionToNextFindMatchAction case insensitive', () => { - const text = [ - 'test', - 'testte', - 'Test', - 'testte', - 'test' - ]; - testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { - editor.setSelections([ - new Selection(1, 1, 1, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - new Selection(4, 1, 4, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - new Selection(4, 1, 4, 5), - new Selection(5, 1, 5, 5), - ]); - - action.run(null, editor); - assert.deepEqual(editor.getSelections(), [ - new Selection(1, 1, 1, 5), - new Selection(2, 1, 2, 5), - new Selection(3, 1, 3, 5), - new Selection(4, 1, 4, 5), - new Selection(5, 1, 5, 5), - ]); - }); - }); }); suite('FindController query options persistence', () => { @@ -794,11 +392,11 @@ suite('FindController query options persistence', () => { queryState['editor.matchCase'] = false; queryState['editor.wholeWord'] = false; let serviceCollection = new ServiceCollection(); - serviceCollection.set(IStorageService, { + serviceCollection.set(IStorageService, { get: (key: string) => queryState[key], getBoolean: (key: string) => !!queryState[key], store: (key: string, value: any) => { queryState[key] = value; } - }); + } as IStorageService); test('matchCase', () => { withMockCodeEditor([ diff --git a/src/vs/editor/contrib/find/test/common/findModel.test.ts b/src/vs/editor/contrib/find/test/common/findModel.test.ts index 7dd3ee4ad4d..4e6d4dc3827 100644 --- a/src/vs/editor/contrib/find/test/common/findModel.test.ts +++ b/src/vs/editor/contrib/find/test/common/findModel.test.ts @@ -2004,6 +2004,29 @@ suite('FindModel', () => { findState.dispose(); }); + findTest('issue #32522 replaceAll with ^ on more than 1000 matches', (editor, cursor) => { + let initialText = ''; + for (let i = 0; i < 1100; i++) { + initialText += 'line' + i + '\n'; + } + editor.getModel().setValue(initialText); + let findState = new FindReplaceState(); + findState.change({ searchString: '^', replaceString: 'a ', isRegex: true }, false); + let findModel = new FindModelBoundToEditorModel(editor, findState); + + findModel.replaceAll(); + + let expectedText = ''; + for (let i = 0; i < 1100; i++) { + expectedText += 'a line' + i + '\n'; + } + expectedText += 'a '; + assert.equal(editor.getModel().getValue(), expectedText); + + findModel.dispose(); + findState.dispose(); + }); + findTest('issue #19740 Find and replace capture group/backreference inserts `undefined` instead of empty string', (editor, cursor) => { let findState = new FindReplaceState(); findState.change({ searchString: 'hello(z)?', replaceString: 'hi$1', isRegex: true, matchCase: true }, false); diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index bbe359dd428..60df213b7ba 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -9,67 +9,81 @@ import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; import * as dom from 'vs/base/browser/dom'; -import { RunOnceScheduler } from 'vs/base/common/async'; +import { RunOnceScheduler, Delayer } from 'vs/base/common/async'; import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; -import * as editorCommon from 'vs/editor/common/editorCommon'; -import { Range } from 'vs/editor/common/core/range'; +import { ICommonCodeEditor, ScrollType, IModel } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; -import { CollapsibleRegion, getCollapsibleRegionsToFoldAtLine, getCollapsibleRegionsToUnfoldAtLine, doesLineBelongsToCollapsibleRegion, IFoldingRange } from 'vs/editor/contrib/folding/common/foldingModel'; -import { computeRanges, limitByIndent } from 'vs/editor/contrib/folding/common/indentFoldStrategy'; -import { IFoldingController, ID } from 'vs/editor/contrib/folding/common/folding'; -import { Selection } from 'vs/editor/common/core/selection'; +import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/common/foldingModel'; +import { FoldingDecorationProvider } from './foldingDecorations'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; +import { HiddenRangeModel } from 'vs/editor/contrib/folding/common/hiddenRangeModel'; +import { IRange } from 'vs/editor/common/core/range'; + +export const ID = 'editor.contrib.folding'; @editorContribution -export class FoldingController implements IFoldingController { +export class FoldingController { static MAX_FOLDING_REGIONS = 5000; - public static get(editor: editorCommon.ICommonCodeEditor): FoldingController { + + public static get(editor: ICommonCodeEditor): FoldingController { return editor.getContribution(ID); } private editor: ICodeEditor; private _isEnabled: boolean; - private _showFoldingControls: 'always' | 'mouseover'; + private _autoHideFoldingControls: boolean; + + private foldingDecorationProvider: FoldingDecorationProvider; + + private foldingModel: FoldingModel; + private hiddenRangeModel: HiddenRangeModel; + + private foldingModelPromise: TPromise; + private updateScheduler: Delayer; + private globalToDispose: IDisposable[]; - private computeToken: number; private cursorChangedScheduler: RunOnceScheduler; - private contentChangedScheduler: RunOnceScheduler; - private localToDispose: IDisposable[]; - private decorations: CollapsibleRegion[]; + private localToDispose: IDisposable[]; constructor(editor: ICodeEditor) { this.editor = editor; this._isEnabled = this.editor.getConfiguration().contribInfo.folding; - this._showFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls; + this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; this.globalToDispose = []; this.localToDispose = []; - this.decorations = []; - this.computeToken = 0; + + this.foldingDecorationProvider = new FoldingDecorationProvider(); + this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls; this.globalToDispose.push(this.editor.onDidChangeModel(() => this.onModelChanged())); + this.globalToDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - let oldIsEnabled = this._isEnabled; - this._isEnabled = this.editor.getConfiguration().contribInfo.folding; - if (oldIsEnabled !== this._isEnabled) { - this.onModelChanged(); - } - let oldShowFoldingControls = this._showFoldingControls; - this._showFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls; - if (oldShowFoldingControls !== this._showFoldingControls) { - this.updateHideFoldIconClass(); + if (e.contribInfo) { + let oldIsEnabled = this._isEnabled; + this._isEnabled = this.editor.getConfiguration().contribInfo.folding; + if (oldIsEnabled !== this._isEnabled) { + this.onModelChanged(); + } + let oldShowFoldingControls = this._autoHideFoldingControls; + this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; + if (oldShowFoldingControls !== this._autoHideFoldingControls) { + this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls; + this.onModelContentChanged(); + } } })); - + this.globalToDispose.push({ dispose: () => dispose(this.localToDispose) }); this.onModelChanged(); } @@ -78,223 +92,125 @@ export class FoldingController implements IFoldingController { } public dispose(): void { - this.cleanState(); this.globalToDispose = dispose(this.globalToDispose); } - private updateHideFoldIconClass(): void { - let domNode = this.editor.getDomNode(); - if (domNode) { - dom.toggleClass(domNode, 'alwaysShowFoldIcons', this._showFoldingControls === 'always'); - } - } - /** * Store view state. */ - public saveViewState(): any { + public saveViewState(): { collapsedRegions?: CollapseMemento, lineCount?: number } { let model = this.editor.getModel(); - if (!model) { + if (!model || !this._isEnabled) { return {}; } - var collapsedRegions: IFoldingRange[] = []; - this.decorations.forEach(d => { - if (d.isCollapsed) { - var range = d.getDecorationRange(model); - if (range) { - collapsedRegions.push({ startLineNumber: range.startLineNumber, endLineNumber: range.endLineNumber, indent: d.indent, isCollapsed: true }); - } - } - }); - return { collapsedRegions: collapsedRegions, lineCount: model.getLineCount() }; + return { collapsedRegions: this.foldingModel.getMemento(), lineCount: model.getLineCount() }; } /** * Restore view state. */ - public restoreViewState(state: any): void { + public restoreViewState(state: { collapsedRegions?: CollapseMemento, lineCount?: number }): void { let model = this.editor.getModel(); - if (!model) { + if (!model || !this._isEnabled) { return; } - if (!this._isEnabled) { + if (!state || !state.collapsedRegions || state.lineCount !== model.getLineCount()) { return; } - if (!state || !Array.isArray(state.collapsedRegions) || state.collapsedRegions.length === 0 || state.lineCount !== model.getLineCount()) { - return; - } - let newFolded = state.collapsedRegions; - if (this.decorations.length > 0) { - let hasChanges = false; - let i = 0; - this.editor.changeDecorations(changeAccessor => { - this.decorations.forEach(d => { - if (i === newFolded.length || d.startLineNumber < newFolded[i].startLineNumber) { - if (d.isCollapsed) { - d.setCollapsed(false, changeAccessor); - hasChanges = true; - } - } else if (d.startLineNumber === newFolded[i].startLineNumber) { - if (!d.isCollapsed) { - d.setCollapsed(true, changeAccessor); - hasChanges = true; - } - i++; - } else { - return; // folding regions doesn't match, don't try to restore - } - }); - }); - if (hasChanges) { - this.updateHiddenAreas(void 0); - } - } - } - - private cleanState(): void { - this.localToDispose = dispose(this.localToDispose); - } - - private applyRegions(regions: IFoldingRange[]) { - let model = this.editor.getModel(); - if (!model) { - return; - } - let updateHiddenRegions = false; - regions = limitByIndent(regions, FoldingController.MAX_FOLDING_REGIONS).sort((r1, r2) => r1.startLineNumber - r2.startLineNumber); - - this.editor.changeDecorations(changeAccessor => { - - let newDecorations: CollapsibleRegion[] = []; - - let k = 0, i = 0; - while (i < this.decorations.length && k < regions.length) { - let dec = this.decorations[i]; - let decRange = dec.getDecorationRange(model); - if (!decRange) { - updateHiddenRegions = updateHiddenRegions || dec.isCollapsed; - dec.dispose(changeAccessor); - i++; - } else { - while (k < regions.length && decRange.startLineNumber > regions[k].startLineNumber) { - let region = regions[k]; - updateHiddenRegions = updateHiddenRegions || region.isCollapsed; - newDecorations.push(new CollapsibleRegion(region, model, changeAccessor)); - k++; - } - if (k < regions.length) { - let currRange = regions[k]; - if (decRange.startLineNumber < currRange.startLineNumber) { - updateHiddenRegions = updateHiddenRegions || dec.isCollapsed; - dec.dispose(changeAccessor); - i++; - } else if (decRange.startLineNumber === currRange.startLineNumber) { - if (dec.isCollapsed && (dec.startLineNumber !== currRange.startLineNumber || dec.endLineNumber !== currRange.endLineNumber)) { - updateHiddenRegions = true; - } - currRange.isCollapsed = dec.isCollapsed; // preserve collapse state - dec.update(currRange, model, changeAccessor); - newDecorations.push(dec); - i++; - k++; - } - } + // set the hidden ranges right away, before waiting for the folding model. + if (this.hiddenRangeModel.applyMemento(state.collapsedRegions)) { + this.getFoldingModel().then(foldingModel => { + if (foldingModel) { + foldingModel.applyMemento(state.collapsedRegions); } - } - while (i < this.decorations.length) { - let dec = this.decorations[i]; - updateHiddenRegions = updateHiddenRegions || dec.isCollapsed; - dec.dispose(changeAccessor); - i++; - } - while (k < regions.length) { - let region = regions[k]; - updateHiddenRegions = updateHiddenRegions || region.isCollapsed; - newDecorations.push(new CollapsibleRegion(region, model, changeAccessor)); - k++; - } - this.decorations = newDecorations; - }); - if (updateHiddenRegions) { - this.updateHiddenAreas(); + }); } - } private onModelChanged(): void { - this.cleanState(); - this.updateHideFoldIconClass(); + this.localToDispose = dispose(this.localToDispose); let model = this.editor.getModel(); if (!this._isEnabled || !model) { return; } - this.computeAndApplyCollapsibleRegions(); - this.contentChangedScheduler = new RunOnceScheduler(() => this.computeAndApplyCollapsibleRegions(), 200); + this.foldingModel = new FoldingModel(model, this.foldingDecorationProvider); + this.localToDispose.push(this.foldingModel); + + this.hiddenRangeModel = new HiddenRangeModel(this.foldingModel); + this.localToDispose.push(this.hiddenRangeModel); + this.localToDispose.push(this.hiddenRangeModel.onDidChange(hr => this.onHiddenRangesChanges(hr))); + + this.updateScheduler = new Delayer(200); + this.cursorChangedScheduler = new RunOnceScheduler(() => this.revealCursor(), 200); - this.localToDispose.push(this.contentChangedScheduler); this.localToDispose.push(this.cursorChangedScheduler); - - this.localToDispose.push(this.editor.onDidChangeModelContent(e => this.contentChangedScheduler.schedule())); - this.localToDispose.push(this.editor.onDidChangeCursorPosition((e) => { - - if (!this._isEnabled) { - // Early exit if nothing needs to be done! - // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;) - return; - } - - this.cursorChangedScheduler.schedule(); - })); + this.localToDispose.push(this.editor.onDidChangeModelLanguageConfiguration(e => this.onModelContentChanged())); // covers model language changes as well + this.localToDispose.push(this.editor.onDidChangeModelContent(e => this.onModelContentChanged())); + this.localToDispose.push(this.editor.onDidChangeCursorPosition(e => this.onCursorPositionChanged())); this.localToDispose.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); this.localToDispose.push(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); - - this.localToDispose.push({ dispose: () => this.disposeDecorations() }); - } - - private computeAndApplyCollapsibleRegions(): void { - let model = this.editor.getModel(); - this.applyRegions(model ? computeRanges(model) : []); - } - - private disposeDecorations() { - this.editor.changeDecorations(changeAccessor => { - this.decorations.forEach(dec => dec.dispose(changeAccessor)); + this.localToDispose.push({ + dispose: () => { + this.updateScheduler.cancel(); + this.updateScheduler = null; + this.foldingModel = null; + this.foldingModelPromise = null; + this.hiddenRangeModel = null; + this.cursorChangedScheduler = null; + } }); - this.decorations = []; - this.editor.setHiddenAreas([]); + this.onModelContentChanged(); + } + + private computeRanges(editorModel: IModel) { + let ranges = editorModel.getIndentRanges(); + return ranges; + } + + public getFoldingModel() { + return this.foldingModelPromise; + } + + private onModelContentChanged() { + this.foldingModelPromise = this.updateScheduler.trigger(() => { + if (this.foldingModel) { // null if editor has been disposed, or folding turned off + this.foldingModel.update(this.computeRanges(this.foldingModel.textModel)); + } + return this.foldingModel; + }); + } + + private onHiddenRangesChanges(hiddenRanges: IRange[]) { + let selections = this.editor.getSelections(); + if (this.hiddenRangeModel.adjustSelections(selections)) { + this.editor.setSelections(selections); + } + this.editor.setHiddenAreas(hiddenRanges); + } + + private onCursorPositionChanged() { + if (this.hiddenRangeModel.hasRanges()) { + this.cursorChangedScheduler.schedule(); + } } private revealCursor() { - let model = this.editor.getModel(); - if (!model) { - return; - } - let hasChanges = false; - let selections = this.editor.getSelections(); - - this.editor.changeDecorations(changeAccessor => { - return this.decorations.forEach(dec => { - if (dec.isCollapsed) { - let decRange = dec.getDecorationRange(model); - if (decRange) { - for (let selection of selections) { - // reveal if cursor in in one of the collapsed line (not the first) - if (decRange.startLineNumber < selection.selectionStartLineNumber && selection.selectionStartLineNumber <= decRange.endLineNumber) { - dec.setCollapsed(false, changeAccessor); - hasChanges = true; - break; - } - } + this.getFoldingModel().then(foldingModel => { // null is returned if folding got disabled in the meantime + if (foldingModel) { + let selections = this.editor.getSelections(); + for (let selection of selections) { + let lineNumber = selection.selectionStartLineNumber; + if (this.hiddenRangeModel.isHidden(lineNumber)) { + let toToggle = foldingModel.getAllRegionsAtLine(lineNumber, r => r.isCollapsed && lineNumber > r.startLineNumber); + foldingModel.toggleCollapseState(toToggle); } } - }); + } }); - if (hasChanges) { - this.updateHiddenAreas(this.editor.getPosition().lineNumber); - } + } private mouseDownInfo: { lineNumber: number, iconClicked: boolean }; @@ -302,9 +218,6 @@ export class FoldingController implements IFoldingController { private onEditorMouseDown(e: IEditorMouseEvent): void { this.mouseDownInfo = null; - if (this.decorations.length === 0) { - return; - } let range = e.target.range; if (!range) { return; @@ -312,20 +225,38 @@ export class FoldingController implements IFoldingController { if (!e.event.leftButton) { return; } - - let model = this.editor.getModel(); - let iconClicked = false; switch (e.target.type) { case MouseTargetType.GUTTER_LINE_DECORATIONS: + const data = e.target.detail as IMarginData; + const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth; + + // TODO@joao TODO@alex TODO@martin this is such that we don't collide with dirty diff + if (gutterOffsetX <= 10) { + return; + } + iconClicked = true; break; - case MouseTargetType.CONTENT_EMPTY: - case MouseTargetType.CONTENT_TEXT: + case MouseTargetType.CONTENT_EMPTY: { + let model = this.editor.getModel(); + if (range.startColumn === model.getLineMaxColumn(range.startLineNumber)) { + let editorCoords = dom.getDomNodePagePosition(this.editor.getDomNode()); + let pos = this.editor.getScrolledVisiblePosition(range.getEndPosition()); + if (e.event.posy > editorCoords.top + pos.top + pos.height) { + return; + } + break; + } + return; + } + case MouseTargetType.CONTENT_TEXT: { + let model = this.editor.getModel(); if (range.startColumn === model.getLineMaxColumn(range.startLineNumber)) { break; } return; + } default: return; } @@ -345,219 +276,71 @@ export class FoldingController implements IFoldingController { return; } - let model = this.editor.getModel(); - if (iconClicked) { if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) { return; } } else { + let model = this.editor.getModel(); if (range.startColumn !== model.getLineMaxColumn(lineNumber)) { return; } } - this.editor.changeDecorations(changeAccessor => { - for (let i = 0; i < this.decorations.length; i++) { - let dec = this.decorations[i]; - let decRange = dec.getDecorationRange(model); - if (decRange && decRange.startLineNumber === lineNumber) { - if (iconClicked || dec.isCollapsed) { - dec.setCollapsed(!dec.isCollapsed, changeAccessor); - this.updateHiddenAreas(lineNumber); + this.getFoldingModel().then(foldingModel => { + if (foldingModel) { + let region = foldingModel.getRegionAtLine(lineNumber); + if (region && region.startLineNumber === lineNumber) { + if (iconClicked || region.isCollapsed) { + foldingModel.toggleCollapseState([region]); + this.reveal(lineNumber); } - return; } } }); } - private updateHiddenAreas(focusLine?: number): void { - let model = this.editor.getModel(); - var selections: Selection[] = this.editor.getSelections(); - var updateSelections = false; - let hiddenAreas: Range[] = []; - this.decorations.filter(dec => dec.isCollapsed).forEach(dec => { - let decRange = dec.getDecorationRange(model); - if (!decRange) { - return; - } - let isLineHidden = (line: number) => line > decRange.startLineNumber && line <= decRange.endLineNumber; - hiddenAreas.push(new Range(decRange.startLineNumber + 1, 1, decRange.endLineNumber, 1)); - selections.forEach((selection, i) => { - if (isLineHidden(selection.getStartPosition().lineNumber)) { - selections[i] = selection = selection.setStartPosition(decRange.startLineNumber, model.getLineMaxColumn(decRange.startLineNumber)); - updateSelections = true; - } - if (isLineHidden(selection.getEndPosition().lineNumber)) { - selections[i] = selection.setEndPosition(decRange.startLineNumber, model.getLineMaxColumn(decRange.startLineNumber)); - updateSelections = true; - } - }); - }); - if (updateSelections) { - this.editor.setSelections(selections); - } - this.editor.setHiddenAreas(hiddenAreas); - if (focusLine) { - this.editor.revealPositionInCenterIfOutsideViewport({ lineNumber: focusLine, column: 1 }, editorCommon.ScrollType.Smooth); - } - } - - public unfold(levels: number): void { - let model = this.editor.getModel(); - let hasChanges = false; - let selections = this.editor.getSelections(); - let selectionsHasChanged = false; - selections.forEach((selection, index) => { - let toUnfold: CollapsibleRegion[] = getCollapsibleRegionsToUnfoldAtLine(this.decorations, model, selection.startLineNumber, levels); - if (toUnfold.length > 0) { - toUnfold.forEach((collapsibleRegion, index) => { - this.editor.changeDecorations(changeAccessor => { - collapsibleRegion.setCollapsed(false, changeAccessor); - hasChanges = true; - }); - }); - if (!doesLineBelongsToCollapsibleRegion(toUnfold[0].foldingRange, selection.startLineNumber)) { - let lineNumber = toUnfold[0].startLineNumber, column = model.getLineMaxColumn(toUnfold[0].startLineNumber); - selections[index] = selection.setEndPosition(lineNumber, column).setStartPosition(lineNumber, column); - selectionsHasChanged = true; - } - } - }); - if (selectionsHasChanged) { - this.editor.setSelections(selections); - } - if (hasChanges) { - this.updateHiddenAreas(selections[0].startLineNumber); - } - } - - public fold(levels: number, up: boolean): void { - let hasChanges = false; - let selections = this.editor.getSelections(); - selections.forEach(selection => { - let lineNumber = selection.startLineNumber; - let toFold: CollapsibleRegion[] = getCollapsibleRegionsToFoldAtLine(this.decorations, this.editor.getModel(), lineNumber, levels, up); - toFold.forEach(collapsibleRegion => this.editor.changeDecorations(changeAccessor => { - collapsibleRegion.setCollapsed(true, changeAccessor); - hasChanges = true; - })); - }); - if (hasChanges) { - this.updateHiddenAreas(selections[0].startLineNumber); - } - } - - public foldUnfoldRecursively(isFold: boolean): void { - let hasChanges = false; - let model = this.editor.getModel(); - let selections = this.editor.getSelections(); - selections.forEach(selection => { - let lineNumber = selection.startLineNumber; - let endLineNumber: number; - let decToFoldUnfold: CollapsibleRegion[] = []; - for (let i = 0, len = this.decorations.length; i < len; i++) { - let dec = this.decorations[i]; - let decRange = dec.getDecorationRange(model); - if (!decRange) { - continue; - } - if (decRange.startLineNumber >= lineNumber && (decRange.endLineNumber <= endLineNumber || typeof endLineNumber === 'undefined')) { - //Protect against cursor not being in decoration and lower decoration folding/unfolding - if (decRange.startLineNumber !== lineNumber && typeof endLineNumber === 'undefined') { - return; - } - endLineNumber = endLineNumber || decRange.endLineNumber; - decToFoldUnfold.push(dec); - } - }; - if (decToFoldUnfold.length > 0) { - decToFoldUnfold.forEach(dec => { - this.editor.changeDecorations(changeAccessor => { - dec.setCollapsed(isFold, changeAccessor); - hasChanges = true; - }); - }); - } - }); - if (hasChanges) { - this.updateHiddenAreas(selections[0].startLineNumber); - } - } - - public foldAll(): void { - this.changeAll(true); - } - - public unfoldAll(): void { - this.changeAll(false); - } - - private changeAll(collapse: boolean): void { - if (this.decorations.length > 0) { - let hasChanges = true; - this.editor.changeDecorations(changeAccessor => { - this.decorations.forEach(d => { - if (collapse !== d.isCollapsed) { - d.setCollapsed(collapse, changeAccessor); - hasChanges = true; - } - }); - }); - if (hasChanges) { - this.updateHiddenAreas(this.editor.getPosition().lineNumber); - } - } - } - - public foldLevel(foldLevel: number, selectedLineNumbers: number[]): void { - let model = this.editor.getModel(); - let foldingRegionStack: Range[] = [model.getFullModelRange()]; // sentinel - - let hasChanges = false; - this.editor.changeDecorations(changeAccessor => { - this.decorations.forEach(dec => { - let decRange = dec.getDecorationRange(model); - if (decRange) { - while (!Range.containsRange(foldingRegionStack[foldingRegionStack.length - 1], decRange)) { - foldingRegionStack.pop(); - } - foldingRegionStack.push(decRange); - if (foldingRegionStack.length === foldLevel + 1 && !dec.isCollapsed && !selectedLineNumbers.some(lineNumber => decRange.startLineNumber < lineNumber && lineNumber <= decRange.endLineNumber)) { - dec.setCollapsed(true, changeAccessor); - hasChanges = true; - } - } - }); - }); - if (hasChanges) { - this.updateHiddenAreas(selectedLineNumbers[0]); - } + public reveal(focusLine: number): void { + this.editor.revealPositionInCenterIfOutsideViewport({ lineNumber: focusLine, column: 1 }, ScrollType.Smooth); } } abstract class FoldingAction extends EditorAction { - abstract invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor, args: T): void; + abstract invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor, args: T): void; - public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: T): void | TPromise { + public runEditorCommand(accessor: ServicesAccessor, editor: ICommonCodeEditor, args: T): void | TPromise { let foldingController = FoldingController.get(editor); if (!foldingController) { return; } this.reportTelemetry(accessor, editor); - this.invoke(foldingController, editor, args); + return foldingController.getFoldingModel().then(foldingModel => { + if (foldingModel) { + this.invoke(foldingController, foldingModel, editor, args); + } + }); } - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { + protected getSelectedLines(editor: ICommonCodeEditor) { + return editor.getSelections().map(s => s.startLineNumber); + } + protected getLineNumbers(args: FoldingArguments, editor: ICommonCodeEditor) { + if (args && args.selectionLines) { + return args.selectionLines.map(l => l + 1); // to 0-bases line numbers + } + return this.getSelectedLines(editor); + } + + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { } } interface FoldingArguments { levels?: number; direction?: 'up' | 'down'; + selectionLines?: number[]; } function foldingArgumentsConstraint(args: any) { @@ -572,11 +355,15 @@ function foldingArgumentsConstraint(args: any) { if (!types.isUndefined(foldingArgs.direction) && !types.isString(foldingArgs.direction)) { return false; } + if (!types.isUndefined(foldingArgs.selectionLines) && (!types.isArray(foldingArgs.selectionLines) || !foldingArgs.selectionLines.every(types.isNumber))) { + return false; + } } return true; } @editorAction +// @ts-ignore @editorAction uses the class class UnfoldAction extends FoldingAction { constructor() { @@ -598,7 +385,9 @@ class UnfoldAction extends FoldingAction { { name: 'Unfold editor argument', description: `Property-value pairs that can be passed through this argument: - * 'level': Number of levels to unfold + * 'levels': Number of levels to unfold. If not set, defaults to 1. + * 'direction': If 'up', unfold given number of levels up otherwise unfolds down + * 'selectionLines': The start lines (0-based) of the editor selections to apply the unfold action to. If not set, the active selection(s) will be used. `, constraint: foldingArgumentsConstraint } @@ -607,12 +396,19 @@ class UnfoldAction extends FoldingAction { }); } - invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor, args: FoldingArguments): void { - foldingController.unfold(args ? args.levels || 1 : 1); + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor, args: FoldingArguments): void { + let levels = args && args.levels || 1; + let lineNumbers = this.getLineNumbers(args, editor); + if (args && args.direction === 'up') { + setCollapseStateLevelsUp(foldingModel, false, levels, lineNumbers); + } else { + setCollapseStateLevelsDown(foldingModel, false, levels, lineNumbers); + } } } @editorAction +// @ts-ignore @editorAction uses the class class UnFoldRecursivelyAction extends FoldingAction { constructor() { @@ -628,12 +424,13 @@ class UnFoldRecursivelyAction extends FoldingAction { }); } - invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor, args: any): void { - foldingController.foldUnfoldRecursively(false); + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor, args: any): void { + setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, this.getSelectedLines(editor)); } } @editorAction +// @ts-ignore @editorAction uses the class class FoldAction extends FoldingAction { constructor() { @@ -655,8 +452,9 @@ class FoldAction extends FoldingAction { { name: 'Fold editor argument', description: `Property-value pairs that can be passed through this argument: - * 'levels': Number of levels to fold - * 'up': If 'true', folds given number of levels up otherwise folds down + * 'levels': Number of levels to fold. Defauts to 1 + * 'direction': If 'up', folds given number of levels up otherwise folds down + * 'selectionLines': The start lines (0-based) of the editor selections to apply the fold action to. If not set, the active selection(s) will be used. `, constraint: foldingArgumentsConstraint } @@ -665,13 +463,19 @@ class FoldAction extends FoldingAction { }); } - invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor, args: FoldingArguments): void { - args = args ? args : { levels: 1, direction: 'up' }; - foldingController.fold(args.levels || 1, args.direction === 'up'); + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor, args: FoldingArguments): void { + let levels = args && args.levels || 1; + let lineNumbers = this.getLineNumbers(args, editor); + if (args && args.direction === 'up') { + setCollapseStateLevelsUp(foldingModel, true, levels, lineNumbers); + } else { + setCollapseStateLevelsDown(foldingModel, true, levels, lineNumbers); + } } } @editorAction +// @ts-ignore @editorAction uses the class class FoldRecursivelyAction extends FoldingAction { constructor() { @@ -687,12 +491,18 @@ class FoldRecursivelyAction extends FoldingAction { }); } - invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor): void { - foldingController.foldUnfoldRecursively(true); + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor): void { + let selectedLines = this.getSelectedLines(editor); + setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, selectedLines); + if (selectedLines.length > 0) { + foldingController.reveal(selectedLines[0]); + } + } } @editorAction +// @ts-ignore @editorAction uses the class class FoldAllAction extends FoldingAction { constructor() { @@ -708,12 +518,13 @@ class FoldAllAction extends FoldingAction { }); } - invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor): void { - foldingController.foldAll(); + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor): void { + setCollapseStateLevelsDown(foldingModel, true); } } @editorAction +// @ts-ignore @editorAction uses the class class UnfoldAllAction extends FoldingAction { constructor() { @@ -729,8 +540,8 @@ class UnfoldAllAction extends FoldingAction { }); } - invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor): void { - foldingController.unfoldAll(); + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor): void { + setCollapseStateLevelsDown(foldingModel, false); } } @@ -742,12 +553,8 @@ class FoldLevelAction extends FoldingAction { return parseInt(this.id.substr(FoldLevelAction.ID_PREFIX.length)); } - private getSelectedLines(editor: editorCommon.ICommonCodeEditor) { - return editor.getSelections().map(s => s.startLineNumber); - } - - invoke(foldingController: FoldingController, editor: editorCommon.ICommonCodeEditor): void { - foldingController.foldLevel(this.getFoldingLevel(), this.getSelectedLines(editor)); + invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICommonCodeEditor): void { + setCollapseStateAtLevel(foldingModel, this.getFoldingLevel(), true, this.getSelectedLines(editor)); } } @@ -764,4 +571,4 @@ for (let i = 1; i <= 9; i++) { } }) ); -}; +} diff --git a/src/vs/editor/contrib/folding/browser/foldingDecorations.ts b/src/vs/editor/contrib/folding/browser/foldingDecorations.ts new file mode 100644 index 00000000000..df965777690 --- /dev/null +++ b/src/vs/editor/contrib/folding/browser/foldingDecorations.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { FoldingRegion, IDecorationProvider } from 'vs/editor/contrib/folding/common/foldingModel'; + +export class FoldingDecorationProvider implements IDecorationProvider { + + private COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + afterContentClassName: 'inline-folded', + linesDecorationsClassName: 'folding collapsed' + }); + + private EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + linesDecorationsClassName: 'folding autoHide' + }); + + private EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + linesDecorationsClassName: 'folding' + }); + + public autoHideFoldingControls: boolean = true; + + getDecorationOption(region: FoldingRegion): ModelDecorationOptions { + if (region.isCollapsed) { + return this.COLLAPSED_VISUAL_DECORATION; + } else if (this.autoHideFoldingControls) { + return this.EXPANDED_AUTO_HIDE_VISUAL_DECORATION; + } else { + return this.EXPANDED_VISUAL_DECORATION; + } + } +} diff --git a/src/vs/editor/contrib/folding/common/foldingModel.ts b/src/vs/editor/contrib/folding/common/foldingModel.ts index 16a1b1c8cdc..fbf7c034ec1 100644 --- a/src/vs/editor/contrib/folding/common/foldingModel.ts +++ b/src/vs/editor/contrib/folding/common/foldingModel.ts @@ -3,293 +3,339 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as editorCommon from 'vs/editor/common/editorCommon'; -import { Range } from 'vs/editor/common/core/range'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { IModel, IModelDecorationOptions } from 'vs/editor/common/editorCommon'; +import Event, { Emitter } from 'vs/base/common/event'; +import { IndentRanges } from 'vs/editor/common/model/indentRanges'; -export interface IFoldingRange { +export interface ILineRange { startLineNumber: number; endLineNumber: number; - indent: number; - isCollapsed?: boolean; } -export function toString(range: IFoldingRange): string { - return (range ? range.startLineNumber + '/' + range.endLineNumber : 'null') + (range.isCollapsed ? ' (collapsed)' : '') + ' - ' + range.indent; +export interface IDecorationProvider { + getDecorationOption(region: FoldingRegion): IModelDecorationOptions; } -export class CollapsibleRegion { +export interface FoldingModelChangeEvent { + model: FoldingModel; + collapseStateChanged?: FoldingRegion[]; +} - private decorationIds: string[]; - private _isCollapsed: boolean; - private _indent: number; +export type CollapseMemento = ILineRange[]; - private _lastRange: IFoldingRange; +export class FoldingModel { + private _textModel: IModel; + private _decorationProvider: IDecorationProvider; - public constructor(range: IFoldingRange, model: editorCommon.IModel, changeAccessor: editorCommon.IModelDecorationsChangeAccessor) { - this.decorationIds = []; - this.update(range, model, changeAccessor); + private _regions: FoldingRegion[] = []; + private _ranges: IndentRanges; + + private _updateEventEmitter = new Emitter(); + + public get regions(): FoldingRegion[] { return this._regions; } + public get onDidChange(): Event { return this._updateEventEmitter.event; } + public get textModel() { return this._textModel; } + + constructor(textModel: IModel, decorationProvider: IDecorationProvider) { + this._textModel = textModel; + this._decorationProvider = decorationProvider; } - public get isCollapsed(): boolean { - return this._isCollapsed; - } - - public get isExpanded(): boolean { - return !this._isCollapsed; - } - - public get indent(): number { - return this._indent; - } - - public get foldingRange(): IFoldingRange { - return this._lastRange; - } - - public get startLineNumber(): number { - return this._lastRange ? this._lastRange.startLineNumber : void 0; - } - - public get endLineNumber(): number { - return this._lastRange ? this._lastRange.endLineNumber : void 0; - } - - public setCollapsed(isCollaped: boolean, changeAccessor: editorCommon.IModelDecorationsChangeAccessor): void { - this._isCollapsed = isCollaped; - if (this.decorationIds.length > 0) { - changeAccessor.changeDecorationOptions(this.decorationIds[0], this.getVisualDecorationOptions()); + public toggleCollapseState(regions: FoldingRegion[]) { + if (!regions.length) { + return; } + let processed = {}; + this._textModel.changeDecorations(accessor => { + for (let region of regions) { + if (region.editorDecorationId && !processed[region.editorDecorationId]) { + processed[region.editorDecorationId] = true; + region.isCollapsed = !region.isCollapsed; + accessor.changeDecorationOptions(region.editorDecorationId, this._decorationProvider.getDecorationOption(region)); + } + } + }); + this._updateEventEmitter.fire({ model: this, collapseStateChanged: regions }); } - public getDecorationRange(model: editorCommon.IModel): Range { - if (this.decorationIds.length > 0) { - return model.getDecorationRange(this.decorationIds[1]); + public update(newRanges: IndentRanges): void { + let editorDecorationIds = []; + let newEditorDecorations = []; + + // remember the latest start line numbers of the collapsed regions + let collapsedStartLineNumbers: number[] = []; + for (let region of this._regions) { + if (region.editorDecorationId) { + if (region.isCollapsed) { + let decRange = this._textModel.getDecorationRange(region.editorDecorationId); + if (decRange) { + collapsedStartLineNumbers.push(decRange.startLineNumber); + } + } + editorDecorationIds.push(region.editorDecorationId); + } + } + + let recycleBin = this._regions; + let newRegions = []; + + let newRegion = (ranges: IndentRanges, index: number, isCollapsed: boolean) => { + let region = recycleBin.length ? recycleBin.pop() : new FoldingRegion(); + region.init(ranges, index, isCollapsed); + newRegions.push(region); + + let startLineNumber = region.startLineNumber; + let maxColumn = this._textModel.getLineMaxColumn(startLineNumber); + let decorationRange = { + startLineNumber: startLineNumber, + startColumn: maxColumn, + endLineNumber: startLineNumber, + endColumn: maxColumn + }; + newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(region) }); + }; + + let k = 0, i = 0; + while (i < collapsedStartLineNumbers.length && k < newRanges.length) { + let collapsedStartLineNumber = collapsedStartLineNumbers[i]; + while (k < newRanges.length && collapsedStartLineNumber > newRanges.getStartLineNumber(k)) { + newRegion(newRanges, k, false); + k++; + } + if (k < newRanges.length) { + let currStartLineNumber = newRanges.getStartLineNumber(k); + if (collapsedStartLineNumber < currStartLineNumber) { + i++; + } else if (collapsedStartLineNumber === currStartLineNumber) { + newRegion(newRanges, k, true); + i++; + k++; + } + } + } + while (k < newRanges.length) { + newRegion(newRanges, k, false); + k++; + } + + let newEditorDecorationIds = this._textModel.deltaDecorations(editorDecorationIds, newEditorDecorations); + for (let i = 0; i < newEditorDecorations.length; i++) { + newRegions[i].editorDecorationId = newEditorDecorationIds[i]; + } + + this._regions = newRegions; + this._ranges = newRanges; + this._updateEventEmitter.fire({ model: this }); + } + + /** + * Collapse state memento, for persistence only + */ + public getMemento(): CollapseMemento { + let collapsedRanges: ILineRange[] = []; + for (let region of this._regions) { + if (region.isCollapsed && region.editorDecorationId) { + let range = this._textModel.getDecorationRange(region.editorDecorationId); + if (range) { + let startLineNumber = range.startLineNumber; + let endLineNumber = range.endLineNumber + region.endLineNumber - region.startLineNumber; + collapsedRanges.push({ startLineNumber, endLineNumber }); + } + } + } + if (collapsedRanges.length > 0) { + return collapsedRanges; } return null; } - private static _COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({ - stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - afterContentClassName: 'inline-folded', - linesDecorationsClassName: 'folding collapsed' - }); - - private static _EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({ - stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - linesDecorationsClassName: 'folding' - }); - - private getVisualDecorationOptions(): ModelDecorationOptions { - if (this._isCollapsed) { - return CollapsibleRegion._COLLAPSED_VISUAL_DECORATION; - } else { - return CollapsibleRegion._EXPANDED_VISUAL_DECORATION; + /** + * Apply persisted state, for persistence only + */ + public applyMemento(state: CollapseMemento) { + if (!Array.isArray(state)) { + return; } - } - - private static _RANGE_DECORATION = ModelDecorationOptions.register({ - stickiness: editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore - }); - - private getRangeDecorationOptions(): ModelDecorationOptions { - return CollapsibleRegion._RANGE_DECORATION; - } - - public update(newRange: IFoldingRange, model: editorCommon.IModel, changeAccessor: editorCommon.IModelDecorationsChangeAccessor): void { - this._lastRange = newRange; - this._isCollapsed = !!newRange.isCollapsed; - this._indent = newRange.indent; - - let newDecorations: editorCommon.IModelDeltaDecoration[] = []; - - let maxColumn = model.getLineMaxColumn(newRange.startLineNumber); - let visualRng = { - startLineNumber: newRange.startLineNumber, - startColumn: maxColumn, - endLineNumber: newRange.startLineNumber, - endColumn: maxColumn - }; - newDecorations.push({ range: visualRng, options: this.getVisualDecorationOptions() }); - - let colRng = { - startLineNumber: newRange.startLineNumber, - startColumn: 1, - endLineNumber: newRange.endLineNumber, - endColumn: model.getLineMaxColumn(newRange.endLineNumber) - }; - newDecorations.push({ range: colRng, options: this.getRangeDecorationOptions() }); - - this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, newDecorations); - } - - - public dispose(changeAccessor: editorCommon.IModelDecorationsChangeAccessor): void { - this._lastRange = null; - this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, []); - } - - public toString(): string { - let str = this.isCollapsed ? 'collapsed ' : 'expanded '; - if (this._lastRange) { - str += (this._lastRange.startLineNumber + '/' + this._lastRange.endLineNumber); - } else { - str += 'no range'; - } - - return str; - } -} - -export function getCollapsibleRegionsToFoldAtLine(allRegions: CollapsibleRegion[], model: editorCommon.IModel, lineNumber: number, levels: number, up: boolean): CollapsibleRegion[] { - let surroundingRegion: CollapsibleRegion = getCollapsibleRegionAtLine(allRegions, model, lineNumber); - if (!surroundingRegion) { - return []; - } - if (levels === 1) { - return [surroundingRegion]; - } - let result = getCollapsibleRegionsFor(surroundingRegion, allRegions, model, levels, up); - return result.filter(collapsibleRegion => !collapsibleRegion.isCollapsed); -} - -export function getCollapsibleRegionsToUnfoldAtLine(allRegions: CollapsibleRegion[], model: editorCommon.IModel, lineNumber: number, levels: number): CollapsibleRegion[] { - let surroundingRegion: CollapsibleRegion = getCollapsibleRegionAtLine(allRegions, model, lineNumber); - if (!surroundingRegion) { - return []; - } - if (levels === 1) { - let regionToUnfold = surroundingRegion.isCollapsed ? surroundingRegion : getFoldedCollapsibleRegionAfterLine(allRegions, model, surroundingRegion, lineNumber); - return regionToUnfold ? [regionToUnfold] : []; - } - let result = getCollapsibleRegionsFor(surroundingRegion, allRegions, model, levels, false); - return result.filter(collapsibleRegion => collapsibleRegion.isCollapsed); -} - -function getCollapsibleRegionAtLine(allRegions: CollapsibleRegion[], model: editorCommon.IModel, lineNumber: number): CollapsibleRegion { - let collapsibleRegion: CollapsibleRegion = null; - for (let i = 0, len = allRegions.length; i < len; i++) { - let dec = allRegions[i]; - let decRange = dec.getDecorationRange(model); - if (decRange) { - if (doesLineBelongsToCollapsibleRegion(decRange, lineNumber)) { - collapsibleRegion = dec; + let toToogle: FoldingRegion[] = []; + for (let range of state) { + let region = this.getRegionAtLine(range.startLineNumber); + if (region && !region.isCollapsed) { + toToogle.push(region); } - if (doesCollapsibleRegionIsAfterLine(decRange, lineNumber)) { + } + this.toggleCollapseState(toToogle); + } + + public dispose() { + let editorDecorationIds = []; + for (let region of this._regions) { + if (region.editorDecorationId) { + editorDecorationIds.push(region.editorDecorationId); + } + } + this._textModel.deltaDecorations(editorDecorationIds, []); + } + + getAllRegionsAtLine(lineNumber: number, filter?: (r: FoldingRegion, level: number) => boolean): FoldingRegion[] { + let result: FoldingRegion[] = []; + if (this._ranges) { + let index = this._ranges.findRange(lineNumber); + let level = 1; + while (index >= 0) { + let current = this._regions[index]; + if (!filter || filter(current, level)) { + result.push(current); + } + level++; + index = current.parentIndex; + } + } + return result; + } + + getRegionAtLine(lineNumber: number): FoldingRegion { + if (this._ranges) { + let index = this._ranges.findRange(lineNumber); + if (index >= 0) { + return this._regions[index]; + } + } + return null; + } + + getRegionsInside(region: FoldingRegion, filter?: (r: FoldingRegion, level?: number) => boolean): FoldingRegion[] { + let result = []; + let trackLevel = filter && filter.length === 2; + let levelStack: FoldingRegion[] = trackLevel ? [] : null; + let index = region ? region.regionIndex + 1 : 0; + let endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE; + for (let i = index, len = this.regions.length; i < len; i++) { + let current = this.regions[i]; + if (current.startLineNumber < endLineNumber) { + if (trackLevel) { + while (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) { + levelStack.pop(); + } + levelStack.push(current); + if (filter(current, levelStack.length)) { + result.push(current); + } + } else if (!filter || filter(current)) { + result.push(current); + } + } else { break; } } - } - return collapsibleRegion; -} - -function getFoldedCollapsibleRegionAfterLine(allRegions: CollapsibleRegion[], model: editorCommon.IModel, surroundingRegion: CollapsibleRegion, lineNumber: number): CollapsibleRegion { - let index = allRegions.indexOf(surroundingRegion); - for (let i = index + 1; i < allRegions.length; i++) { - let dec = allRegions[i]; - let decRange = dec.getDecorationRange(model); - if (decRange) { - if (doesCollapsibleRegionIsAfterLine(decRange, lineNumber)) { - if (!doesCollapsibleRegionContains(surroundingRegion.foldingRange, decRange)) { - return null; - } - if (dec.isCollapsed) { - return dec; - } - } - } - } - return null; -} - -export function doesLineBelongsToCollapsibleRegion(range: IFoldingRange | Range, lineNumber: number): boolean { - return lineNumber >= range.startLineNumber && lineNumber <= range.endLineNumber; -} - -function doesCollapsibleRegionIsAfterLine(range: IFoldingRange | Range, lineNumber: number): boolean { - return lineNumber < range.startLineNumber; -} -function doesCollapsibleRegionIsBeforeLine(range: IFoldingRange | Range, lineNumber: number): boolean { - return lineNumber > range.endLineNumber; -} - -function doesCollapsibleRegionContains(range1: IFoldingRange | Range, range2: IFoldingRange | Range): boolean { - if (range1 instanceof Range && range2 instanceof Range) { - return range1.containsRange(range2); - } - return range1.startLineNumber <= range2.startLineNumber && range1.endLineNumber >= range2.endLineNumber; -} - -function getCollapsibleRegionsFor(surroundingRegion: CollapsibleRegion, allRegions: CollapsibleRegion[], model: editorCommon.IModel, levels: number, up: boolean): CollapsibleRegion[] { - let collapsibleRegionsHierarchy: CollapsibleRegionsHierarchy = up ? new CollapsibleRegionsParentHierarchy(surroundingRegion, allRegions, model) : new CollapsibleRegionsChildrenHierarchy(surroundingRegion, allRegions, model); - return collapsibleRegionsHierarchy.getRegionsTill(levels); -} - -interface CollapsibleRegionsHierarchy { - getRegionsTill(level: number): CollapsibleRegion[]; -} - -class CollapsibleRegionsChildrenHierarchy implements CollapsibleRegionsHierarchy { - - children: CollapsibleRegionsChildrenHierarchy[] = []; - lastChildIndex: number; - - constructor(private region: CollapsibleRegion, allRegions: CollapsibleRegion[], model: editorCommon.IModel) { - for (let index = allRegions.indexOf(region) + 1; index < allRegions.length; index++) { - let dec = allRegions[index]; - let decRange = dec.getDecorationRange(model); - if (decRange) { - if (doesCollapsibleRegionContains(region.foldingRange, decRange)) { - index = this.processChildRegion(dec, allRegions, model, index); - } - if (doesCollapsibleRegionIsAfterLine(decRange, region.foldingRange.endLineNumber)) { - break; - } - } - } - } - - private processChildRegion(dec: CollapsibleRegion, allRegions: CollapsibleRegion[], model: editorCommon.IModel, index: number): number { - let childRegion = new CollapsibleRegionsChildrenHierarchy(dec, allRegions, model); - this.children.push(childRegion); - this.lastChildIndex = index; - return childRegion.children.length > 0 ? childRegion.lastChildIndex : index; - } - - public getRegionsTill(level: number): CollapsibleRegion[] { - let result = [this.region]; - if (level > 1) { - this.children.forEach(region => result = result.concat(region.getRegionsTill(level - 1))); - } return result; } + } -class CollapsibleRegionsParentHierarchy implements CollapsibleRegionsHierarchy { - parent: CollapsibleRegionsParentHierarchy; - lastChildIndex: number; +export class FoldingRegion { - constructor(private region: CollapsibleRegion, allRegions: CollapsibleRegion[], model: editorCommon.IModel) { - for (let index = allRegions.indexOf(region) - 1; index >= 0; index--) { - let dec = allRegions[index]; - let decRange = dec.getDecorationRange(model); - if (decRange) { - if (doesCollapsibleRegionContains(decRange, region.foldingRange)) { - this.parent = new CollapsibleRegionsParentHierarchy(dec, allRegions, model); - break; + public editorDecorationId: string; + public isCollapsed: boolean; + private index: number; + private indentRanges: IndentRanges; + + constructor() { + } + + public init(indentRanges: IndentRanges, index: number, isCollapsed: boolean): void { + this.indentRanges = indentRanges; + this.index = index; + this.isCollapsed = isCollapsed; + this.editorDecorationId = void 0; + } + + public get startLineNumber() { + return this.indentRanges.getStartLineNumber(this.index); + } + + public get endLineNumber() { + return this.indentRanges.getEndLineNumber(this.index); + } + + public get regionIndex() { + return this.index; + } + + public get parentIndex() { + return this.indentRanges.getParentIndex(this.index); + } + + isAfterLine(lineNumber: number): boolean { + return lineNumber < this.startLineNumber; + } + isBeforeLine(lineNumber: number): boolean { + return lineNumber > this.endLineNumber; + } + contains(range: ILineRange): boolean { + return this.startLineNumber <= range.startLineNumber && this.endLineNumber >= range.endLineNumber; + } + containedBy(range: ILineRange): boolean { + return range.startLineNumber <= this.startLineNumber && range.endLineNumber >= this.endLineNumber; + } + containsLine(lineNumber: number) { + return this.startLineNumber <= lineNumber && lineNumber <= this.endLineNumber; + } + hidesLine(lineNumber: number) { + return this.startLineNumber < lineNumber && lineNumber <= this.endLineNumber; + } +} + +/** + * Collapse or expand the regions at the given locations including all children. + * @param doCollapse Wheter to collase or expand + * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels. + * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model. + */ +export function setCollapseStateLevelsDown(foldingModel: FoldingModel, doCollapse: boolean, levels = Number.MAX_VALUE, lineNumbers?: number[]) { + let toToggle = []; + if (lineNumbers && lineNumbers.length > 0) { + for (let lineNumber of lineNumbers) { + let region = foldingModel.getRegionAtLine(lineNumber); + if (region) { + if (region.isCollapsed !== doCollapse) { + toToggle.push(region); } - if (doesCollapsibleRegionIsBeforeLine(decRange, region.foldingRange.endLineNumber)) { - break; + if (levels > 1) { + let regionsInside = foldingModel.getRegionsInside(region, (r, level) => r.isCollapsed !== doCollapse && level < levels); + toToggle.push(...regionsInside); } } } + } else { + let regionsInside = foldingModel.getRegionsInside(null, (r, level) => r.isCollapsed !== doCollapse && level < levels); + toToggle.push(...regionsInside); } + foldingModel.toggleCollapseState(toToggle); +} - public getRegionsTill(level: number): CollapsibleRegion[] { - let result = [this.region]; - if (this.parent && level > 1) { - result = result.concat(this.parent.getRegionsTill(level - 1)); - } - return result; +/** + * Collapse or expand the regions at the given locations including all parents. + * @param doCollapse Wheter to collase or expand + * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels. + * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model. + */ +export function setCollapseStateLevelsUp(foldingModel: FoldingModel, doCollapse: boolean, levels: number, lineNumbers: number[]) { + let toToggle = []; + for (let lineNumber of lineNumbers) { + let regions = foldingModel.getAllRegionsAtLine(lineNumber, (region, level) => region.isCollapsed !== doCollapse && level <= levels); + toToggle.push(...regions); } + foldingModel.toggleCollapseState(toToggle); +} + +/** + * Folds or unfolds all regions that have a given level, except if they contain one of the blocked lines. + * @param foldLevel level. Level == 1 is the top level + * @param doCollapse Wheter to collase or expand +* @param blockedLineNumbers +*/ +export function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: number, doCollapse: boolean, blockedLineNumbers: number[]): void { + let filter = (region, level) => level === foldLevel && region.isCollapsed !== doCollapse && !blockedLineNumbers.some(line => region.containsLine(line)); + let toToggle = foldingModel.getRegionsInside(null, filter); + foldingModel.toggleCollapseState(toToggle); } \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/common/hiddenRangeModel.ts b/src/vs/editor/contrib/folding/common/hiddenRangeModel.ts new file mode 100644 index 00000000000..0f8b93af245 --- /dev/null +++ b/src/vs/editor/contrib/folding/common/hiddenRangeModel.ts @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import Event, { Emitter } from 'vs/base/common/event'; +import { Range, IRange } from 'vs/editor/common/core/range'; +import { FoldingRegion, FoldingModel, CollapseMemento } from 'vs/editor/contrib/folding/common/foldingModel'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { Selection } from 'vs/editor/common/core/selection'; +import { findFirst } from 'vs/base/common/arrays'; + +export class HiddenRangeModel { + private _foldingModel: FoldingModel; + private _hiddenRanges: IRange[] = []; + private _foldingModelListener: IDisposable; + private _updateEventEmitter = new Emitter(); + + public get onDidChange(): Event { return this._updateEventEmitter.event; } + public get hiddenRanges() { return this._hiddenRanges; } + + public constructor(model: FoldingModel) { + this._foldingModel = model; + this._foldingModelListener = model.onDidChange(_ => this.updateHiddenRanges()); + if (model.regions.length) { + this.updateHiddenRanges(); + } + } + + private updateHiddenRanges(): void { + let updateHiddenAreas = false; + let newHiddenAreas: IRange[] = []; + let i = 0; // index into hidden + + let lastCollapsed: FoldingRegion = null; + + let regions = this._foldingModel.regions; + for (let region of regions) { + if (!region.isCollapsed || lastCollapsed && lastCollapsed.contains(region)) { + // ignore ranges contained in collapsed regions + continue; + } + lastCollapsed = region; + let range = region; + + if (!updateHiddenAreas && i < this._hiddenRanges.length && matchesHiddenRange(this._hiddenRanges[i], range)) { + newHiddenAreas.push(this._hiddenRanges[i]); + i++; + } else { + updateHiddenAreas = true; + newHiddenAreas.push(new Range(range.startLineNumber + 1, 1, range.endLineNumber, 1)); + } + } + if (updateHiddenAreas || i < this._hiddenRanges.length) { + this.applyHiddenRanges(newHiddenAreas); + } + } + + public applyMemento(state: CollapseMemento): boolean { + if (!Array.isArray(state) || state.length === 0) { + return false; + } + let hiddenRanges = []; + for (let r of state) { + if (!r.startLineNumber || !r.endLineNumber) { + return false; + } + hiddenRanges.push(new Range(r.startLineNumber + 1, 1, r.endLineNumber, 1)); + } + this.applyHiddenRanges(hiddenRanges); + return true; + } + + private applyHiddenRanges(newHiddenAreas: IRange[]) { + this._hiddenRanges = newHiddenAreas; + this._updateEventEmitter.fire(newHiddenAreas); + } + + public hasRanges() { + return this._hiddenRanges.length > 0; + } + + public isHidden(line: number): boolean { + return findRange(this._hiddenRanges, line) !== null; + } + + public adjustSelections(selections: Selection[]): boolean { + let hasChanges = false; + let editorModel = this._foldingModel.textModel; + let lastRange = null; + + let adjustLine = (line: number) => { + if (!lastRange || !isInside(line, lastRange)) { + lastRange = findRange(this._hiddenRanges, line); + } + if (lastRange) { + return lastRange.startLineNumber - 1; + } + return null; + }; + for (let i = 0, len = selections.length; i < len; i++) { + let selection = selections[i]; + let adjustedStartLine = adjustLine(selection.startLineNumber); + if (adjustedStartLine) { + selection = selection.setStartPosition(adjustedStartLine, editorModel.getLineMaxColumn(adjustedStartLine)); + hasChanges = true; + } + let adjustedEndLine = adjustLine(selection.endLineNumber); + if (adjustedEndLine) { + selection = selection.setEndPosition(adjustedEndLine, editorModel.getLineMaxColumn(adjustedEndLine)); + hasChanges = true; + } + selections[i] = selection; + } + return hasChanges; + } + + + public dispose() { + if (this.hiddenRanges.length > 0) { + this._hiddenRanges = []; + this._updateEventEmitter.fire(this._hiddenRanges); + } + if (this._foldingModelListener) { + this._foldingModelListener.dispose(); + this._foldingModelListener = null; + } + } +} + +function matchesHiddenRange(hr: IRange, range: FoldingRegion) { + return hr.startLineNumber === range.startLineNumber + 1 && hr.endLineNumber === range.endLineNumber; +} +function isInside(line: number, range: IRange) { + return line >= range.startLineNumber && line <= range.endLineNumber; +} +function findRange(ranges: IRange[], line: number): IRange { + let i = findFirst(ranges, r => line < r.startLineNumber) - 1; + if (i >= 0 && ranges[i].endLineNumber >= line) { + return ranges[i]; + } + return null; +} \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/common/indentFoldStrategy.ts b/src/vs/editor/contrib/folding/common/indentFoldStrategy.ts deleted file mode 100644 index 39f3b5aa635..00000000000 --- a/src/vs/editor/contrib/folding/common/indentFoldStrategy.ts +++ /dev/null @@ -1,42 +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 { IModel } from 'vs/editor/common/editorCommon'; -import { IFoldingRange } from 'vs/editor/contrib/folding/common/foldingModel'; - -export function computeRanges(model: IModel): IFoldingRange[] { - // we get here a clone of the model's indent ranges - return model.getIndentRanges(); -} - -/** - * Limits the number of folding ranges by removing ranges with larger indent levels - */ -export function limitByIndent(ranges: IFoldingRange[], maxEntries: number): IFoldingRange[] { - if (ranges.length <= maxEntries) { - return ranges; - } - - let indentOccurrences: number[] = []; - ranges.forEach(r => { - if (r.indent < 1000) { - indentOccurrences[r.indent] = (indentOccurrences[r.indent] || 0) + 1; - } - }); - let maxIndent = indentOccurrences.length; - for (let i = 0; i < indentOccurrences.length; i++) { - if (indentOccurrences[i]) { - maxEntries -= indentOccurrences[i]; - if (maxEntries < 0) { - maxIndent = i; - break; - } - } - - } - return ranges.filter(r => r.indent < maxIndent); -} \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/test/foldingModel.test.ts b/src/vs/editor/contrib/folding/test/foldingModel.test.ts new file mode 100644 index 00000000000..6e49943a64d --- /dev/null +++ b/src/vs/editor/contrib/folding/test/foldingModel.test.ts @@ -0,0 +1,514 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { FoldingModel, FoldingRegion, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/common/foldingModel'; +import { Model } from 'vs/editor/common/model/model'; +import { computeRanges } from 'vs/editor/common/model/indentRanges'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; +import { EditOperation } from 'vs/editor/common/core/editOperation'; +import { Position } from 'vs/editor/common/core/position'; + + +interface ExpectedRegion { + startLineNumber: number; + endLineNumber: number; + isCollapsed: boolean; +} + +export class TestDecorationProvider { + + private testDecorator = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + linesDecorationsClassName: 'folding' + }); + + getDecorationOption(region: FoldingRegion): ModelDecorationOptions { + return this.testDecorator; + } +} + +suite('Folding Model', () => { + function r(startLineNumber: number, endLineNumber: number, isCollapsed: boolean = false): ExpectedRegion { + return { startLineNumber, endLineNumber, isCollapsed }; + } + + function assertRegion(actual: FoldingRegion, expected: ExpectedRegion, message?: string) { + assert.equal(!!actual, !!expected, message); + if (actual) { + assert.equal(actual.startLineNumber, expected.startLineNumber, message); + assert.equal(actual.endLineNumber, expected.endLineNumber, message); + assert.equal(actual.isCollapsed, expected.isCollapsed, message); + } + } + + function assertFoldedRegions(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) { + assert.deepEqual(foldingModel.regions.filter(r => r.isCollapsed).map(r => ({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber, isCollapsed: false })), expectedRegions, message); + } + + function assertRegions(actual: FoldingRegion[], expectedRegions: ExpectedRegion[], message?: string) { + assert.deepEqual(actual.map(r => ({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber, isCollapsed: r.isCollapsed })), expectedRegions, message); + } + + test('getRegionAtLine', () => { + let lines = [ + /* 1*/ '/**', + /* 2*/ ' * Comment', + /* 3*/ ' */', + /* 4*/ 'class A {', + /* 5*/ ' void foo() {', + /* 6*/ ' // comment {', + /* 7*/ ' }', + /* 8*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); + + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); + + assertRegions(foldingModel.regions, [r1, r2, r3]); + + assertRegion(foldingModel.getRegionAtLine(1), r1, '1'); + assertRegion(foldingModel.getRegionAtLine(2), r1, '2'); + assertRegion(foldingModel.getRegionAtLine(3), r1, '3'); + assertRegion(foldingModel.getRegionAtLine(4), r2, '4'); + assertRegion(foldingModel.getRegionAtLine(5), r3, '5'); + assertRegion(foldingModel.getRegionAtLine(6), r3, '5'); + assertRegion(foldingModel.getRegionAtLine(7), r2, '6'); + assertRegion(foldingModel.getRegionAtLine(8), null, '7'); + } finally { + textModel.dispose(); + } + + + }); + + test('collapse', () => { + let lines = [ + /* 1*/ '/**', + /* 2*/ ' * Comment', + /* 3*/ ' */', + /* 4*/ 'class A {', + /* 5*/ ' void foo() {', + /* 6*/ ' // comment {', + /* 7*/ ' }', + /* 8*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); + + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); + + assertRegions(foldingModel.regions, [r1, r2, r3]); + + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)]); + foldingModel.update(ranges); + + assertRegions(foldingModel.regions, [r(1, 3, true), r2, r3]); + + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(5)]); + foldingModel.update(ranges); + + assertRegions(foldingModel.regions, [r(1, 3, true), r2, r(5, 6, true)]); + + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(7)]); + foldingModel.update(ranges); + + assertRegions(foldingModel.regions, [r(1, 3, true), r(4, 7, true), r(5, 6, true)]); + + textModel.dispose(); + } finally { + textModel.dispose(); + } + + }); + + test('update', () => { + let lines = [ + /* 1*/ '/**', + /* 2*/ ' * Comment', + /* 3*/ ' */', + /* 4*/ 'class A {', + /* 5*/ ' void foo() {', + /* 6*/ ' // comment {', + /* 7*/ ' }', + /* 8*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); + + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); + + assertRegions(foldingModel.regions, [r1, r2, r3]); + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(2), foldingModel.getRegionAtLine(5)]); + + textModel.applyEdits([EditOperation.insert(new Position(4, 1), '//hello\n')]); + + foldingModel.update(computeRanges(textModel, false, null)); + + assertRegions(foldingModel.regions, [r(1, 3, true), r(5, 8, false), r(6, 7, true)]); + } finally { + textModel.dispose(); + } + }); + + test('getRegionsInside', () => { + let lines = [ + /* 1*/ '/**', + /* 2*/ ' * Comment', + /* 3*/ ' */', + /* 4*/ 'class A {', + /* 5*/ ' void foo() {', + /* 6*/ ' // comment {', + /* 7*/ ' }', + /* 8*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); + + let r1 = r(1, 3, false); + let r2 = r(4, 7, false); + let r3 = r(5, 6, false); + + assertRegions(foldingModel.regions, [r1, r2, r3]); + let region1 = foldingModel.getRegionAtLine(r1.startLineNumber); + let region2 = foldingModel.getRegionAtLine(r2.startLineNumber); + let region3 = foldingModel.getRegionAtLine(r3.startLineNumber); + + assertRegions(foldingModel.getRegionsInside(null), [r1, r2, r3], '1'); + assertRegions(foldingModel.getRegionsInside(region1), [], '2'); + assertRegions(foldingModel.getRegionsInside(region2), [r3], '3'); + assertRegions(foldingModel.getRegionsInside(region3), [], '4'); + } finally { + textModel.dispose(); + } + + }); + + test('getRegionsInsideWithLevel', () => { + let lines = [ + /* 1*/ '//#region', + /* 2*/ '//#endregion', + /* 3*/ 'class A {', + /* 4*/ ' void foo() {', + /* 5*/ ' if (true) {', + /* 6*/ ' return;', + /* 7*/ ' }', + /* 8*/ ' if (true) {', + /* 9*/ ' return;', + /* 10*/ ' }', + /* 11*/ ' }', + /* 12*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); + + let r1 = r(1, 2, false); + let r2 = r(3, 11, false); + let r3 = r(4, 10, false); + let r4 = r(5, 6, false); + let r5 = r(8, 9, false); + + let region1 = foldingModel.getRegionAtLine(r1.startLineNumber); + let region2 = foldingModel.getRegionAtLine(r2.startLineNumber); + let region3 = foldingModel.getRegionAtLine(r3.startLineNumber); + + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + + assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 1), [r1, r2], '1'); + assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 2), [r3], '2'); + assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 3), [r4, r5], '3'); + + assertRegions(foldingModel.getRegionsInside(region2, (r, level) => level === 1), [r3], '4'); + assertRegions(foldingModel.getRegionsInside(region2, (r, level) => level === 2), [r4, r5], '5'); + assertRegions(foldingModel.getRegionsInside(region3, (r, level) => level === 1), [r4, r5], '6'); + + assertRegions(foldingModel.getRegionsInside(region2, (r, level) => r.hidesLine(9)), [r3, r5], '7'); + + assertRegions(foldingModel.getRegionsInside(region1, (r, level) => level === 1), [], '8'); + } finally { + textModel.dispose(); + } + + }); + + test('getRegionAtLine', () => { + let lines = [ + /* 1*/ '//#region', + /* 2*/ 'class A {', + /* 3*/ ' void foo() {', + /* 4*/ ' if (true) {', + /* 5*/ ' //hello', + /* 6*/ ' }', + /* 7*/ '', + /* 8*/ ' }', + /* 9*/ '}', + /* 10*/ '//#endregion', + /* 11*/ '']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); + + let r1 = r(1, 10, false); + let r2 = r(2, 8, false); + let r3 = r(3, 7, false); + let r4 = r(4, 5, false); + + assertRegions(foldingModel.regions, [r1, r2, r3, r4]); + + assertRegions(foldingModel.getAllRegionsAtLine(1), [r1], '1'); + assertRegions(foldingModel.getAllRegionsAtLine(2), [r1, r2].reverse(), '2'); + assertRegions(foldingModel.getAllRegionsAtLine(3), [r1, r2, r3].reverse(), '3'); + assertRegions(foldingModel.getAllRegionsAtLine(4), [r1, r2, r3, r4].reverse(), '4'); + assertRegions(foldingModel.getAllRegionsAtLine(5), [r1, r2, r3, r4].reverse(), '5'); + assertRegions(foldingModel.getAllRegionsAtLine(6), [r1, r2, r3].reverse(), '6'); + assertRegions(foldingModel.getAllRegionsAtLine(7), [r1, r2, r3].reverse(), '7'); + assertRegions(foldingModel.getAllRegionsAtLine(8), [r1, r2].reverse(), '8'); + assertRegions(foldingModel.getAllRegionsAtLine(9), [r1], '9'); + assertRegions(foldingModel.getAllRegionsAtLine(10), [r1], '10'); + assertRegions(foldingModel.getAllRegionsAtLine(11), [], '10'); + } finally { + textModel.dispose(); + } + }); + + test('setCollapseStateRecursivly', () => { + let lines = [ + /* 1*/ '//#region', + /* 2*/ '//#endregion', + /* 3*/ 'class A {', + /* 4*/ ' void foo() {', + /* 5*/ ' if (true) {', + /* 6*/ ' return;', + /* 7*/ ' }', + /* 8*/ '', + /* 9*/ ' if (true) {', + /* 10*/ ' return;', + /* 11*/ ' }', + /* 12*/ ' }', + /* 13*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); + + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + + setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, [4]); + assertFoldedRegions(foldingModel, [r3, r4, r5], '1'); + + setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, [8]); + assertFoldedRegions(foldingModel, [], '2'); + + setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, [12]); + assertFoldedRegions(foldingModel, [r2, r3, r4, r5], '1'); + + setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, [7]); + assertFoldedRegions(foldingModel, [r2], '1'); + + setCollapseStateLevelsDown(foldingModel, false); + assertFoldedRegions(foldingModel, [], '1'); + + setCollapseStateLevelsDown(foldingModel, true); + assertFoldedRegions(foldingModel, [r1, r2, r3, r4, r5], '1'); + } finally { + textModel.dispose(); + } + + }); + + test('setCollapseStateAtLevel', () => { + let lines = [ + /* 1*/ '//#region', + /* 2*/ '//#endregion', + /* 3*/ 'class A {', + /* 4*/ ' void foo() {', + /* 5*/ ' if (true) {', + /* 6*/ ' return;', + /* 7*/ ' }', + /* 8*/ '', + /* 9*/ ' if (true) {', + /* 10*/ ' return;', + /* 11*/ ' }', + /* 12*/ ' }', + /* 13*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); + + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + + setCollapseStateAtLevel(foldingModel, 1, true, []); + assertFoldedRegions(foldingModel, [r1, r2], '1'); + + setCollapseStateAtLevel(foldingModel, 1, false, [5]); + assertFoldedRegions(foldingModel, [r2], '1'); + + setCollapseStateAtLevel(foldingModel, 1, false, [1]); + assertFoldedRegions(foldingModel, [], '1'); + + setCollapseStateAtLevel(foldingModel, 2, true, []); + assertFoldedRegions(foldingModel, [r3], '1'); + + setCollapseStateAtLevel(foldingModel, 3, true, [4, 9]); + assertFoldedRegions(foldingModel, [r3, r4], '1'); + + setCollapseStateAtLevel(foldingModel, 3, false, [4, 9]); + assertFoldedRegions(foldingModel, [r3], '1'); + } finally { + textModel.dispose(); + } + }); + + test('setCollapseStateLevelsDown', () => { + let lines = [ + /* 1*/ '//#region', + /* 2*/ '//#endregion', + /* 3*/ 'class A {', + /* 4*/ ' void foo() {', + /* 5*/ ' if (true) {', + /* 6*/ ' return;', + /* 7*/ ' }', + /* 8*/ '', + /* 9*/ ' if (true) {', + /* 10*/ ' return;', + /* 11*/ ' }', + /* 12*/ ' }', + /* 13*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); + + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + + setCollapseStateLevelsDown(foldingModel, true, 1, [4]); + assertFoldedRegions(foldingModel, [r3], '1'); + + setCollapseStateLevelsDown(foldingModel, true, 2, [4]); + assertFoldedRegions(foldingModel, [r3, r4, r5], '2'); + + setCollapseStateLevelsDown(foldingModel, false, 2, [3]); + assertFoldedRegions(foldingModel, [r4, r5], '3'); + + setCollapseStateLevelsDown(foldingModel, false, 2, [2]); + assertFoldedRegions(foldingModel, [r4, r5], '4'); + + setCollapseStateLevelsDown(foldingModel, true, 4, [2]); + assertFoldedRegions(foldingModel, [r1, r4, r5], '5'); + + setCollapseStateLevelsDown(foldingModel, false, 4, [2, 3]); + assertFoldedRegions(foldingModel, [], '6'); + } finally { + textModel.dispose(); + } + }); + + test('setCollapseStateLevelsUp', () => { + let lines = [ + /* 1*/ '//#region', + /* 2*/ '//#endregion', + /* 3*/ 'class A {', + /* 4*/ ' void foo() {', + /* 5*/ ' if (true) {', + /* 6*/ ' return;', + /* 7*/ ' }', + /* 8*/ '', + /* 9*/ ' if (true) {', + /* 10*/ ' return;', + /* 11*/ ' }', + /* 12*/ ' }', + /* 13*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + + let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + foldingModel.update(ranges); + + let r1 = r(1, 2, false); + let r2 = r(3, 12, false); + let r3 = r(4, 11, false); + let r4 = r(5, 6, false); + let r5 = r(9, 10, false); + assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]); + + setCollapseStateLevelsUp(foldingModel, true, 1, [4]); + assertFoldedRegions(foldingModel, [r3], '1'); + + setCollapseStateLevelsUp(foldingModel, true, 2, [4]); + assertFoldedRegions(foldingModel, [r2, r3], '2'); + + setCollapseStateLevelsUp(foldingModel, false, 4, [1, 3, 4]); + assertFoldedRegions(foldingModel, [], '3'); + + setCollapseStateLevelsUp(foldingModel, true, 2, [10]); + assertFoldedRegions(foldingModel, [r3, r5], '4'); + } finally { + textModel.dispose(); + } + + }); + +}); \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts b/src/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts new file mode 100644 index 00000000000..e8c0c409e75 --- /dev/null +++ b/src/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts @@ -0,0 +1,99 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { FoldingModel } from 'vs/editor/contrib/folding/common/foldingModel'; +import { Model } from 'vs/editor/common/model/model'; +import { computeRanges } from 'vs/editor/common/model/indentRanges'; +import { TestDecorationProvider } from './foldingModel.test'; +import { HiddenRangeModel } from 'vs/editor/contrib/folding/common/hiddenRangeModel'; +import { IRange } from 'vs/editor/common/core/range'; + + +interface ExpectedRange { + startLineNumber: number; + endLineNumber: number; +} + +suite('Hidden Range Model', () => { + function r(startLineNumber: number, endLineNumber: number): ExpectedRange { + return { startLineNumber, endLineNumber }; + } + + function assertRanges(actual: IRange[], expectedRegions: ExpectedRange[], message?: string) { + assert.deepEqual(actual.map(r => ({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber })), expectedRegions, message); + } + + test('hasRanges', () => { + let lines = [ + /* 1*/ '/**', + /* 2*/ ' * Comment', + /* 3*/ ' */', + /* 4*/ 'class A {', + /* 5*/ ' void foo() {', + /* 6*/ ' if (true) {', + /* 7*/ ' //hello', + /* 8*/ ' }', + /* 9*/ ' }', + /* 10*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + let foldingModel = new FoldingModel(textModel, new TestDecorationProvider()); + let hiddenRangeModel = new HiddenRangeModel(foldingModel); + + assert.equal(hiddenRangeModel.hasRanges(), false); + + let ranges = computeRanges(textModel, false, null); + foldingModel.update(ranges); + + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1), foldingModel.getRegionAtLine(6)]); + assertRanges(hiddenRangeModel.hiddenRanges, [r(2, 3), r(7, 7)]); + + assert.equal(hiddenRangeModel.hasRanges(), true); + assert.equal(hiddenRangeModel.isHidden(1), false); + assert.equal(hiddenRangeModel.isHidden(2), true); + assert.equal(hiddenRangeModel.isHidden(3), true); + assert.equal(hiddenRangeModel.isHidden(4), false); + assert.equal(hiddenRangeModel.isHidden(5), false); + assert.equal(hiddenRangeModel.isHidden(6), false); + assert.equal(hiddenRangeModel.isHidden(7), true); + assert.equal(hiddenRangeModel.isHidden(8), false); + assert.equal(hiddenRangeModel.isHidden(9), false); + assert.equal(hiddenRangeModel.isHidden(10), false); + + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(4)]); + assertRanges(hiddenRangeModel.hiddenRanges, [r(2, 3), r(5, 9)]); + + assert.equal(hiddenRangeModel.hasRanges(), true); + assert.equal(hiddenRangeModel.isHidden(1), false); + assert.equal(hiddenRangeModel.isHidden(2), true); + assert.equal(hiddenRangeModel.isHidden(3), true); + assert.equal(hiddenRangeModel.isHidden(4), false); + assert.equal(hiddenRangeModel.isHidden(5), true); + assert.equal(hiddenRangeModel.isHidden(6), true); + assert.equal(hiddenRangeModel.isHidden(7), true); + assert.equal(hiddenRangeModel.isHidden(8), true); + assert.equal(hiddenRangeModel.isHidden(9), true); + assert.equal(hiddenRangeModel.isHidden(10), false); + + foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1), foldingModel.getRegionAtLine(6), foldingModel.getRegionAtLine(4)]); + assertRanges(hiddenRangeModel.hiddenRanges, []); + assert.equal(hiddenRangeModel.hasRanges(), false); + assert.equal(hiddenRangeModel.isHidden(1), false); + assert.equal(hiddenRangeModel.isHidden(2), false); + assert.equal(hiddenRangeModel.isHidden(3), false); + assert.equal(hiddenRangeModel.isHidden(4), false); + assert.equal(hiddenRangeModel.isHidden(5), false); + assert.equal(hiddenRangeModel.isHidden(6), false); + assert.equal(hiddenRangeModel.isHidden(7), false); + assert.equal(hiddenRangeModel.isHidden(8), false); + assert.equal(hiddenRangeModel.isHidden(9), false); + assert.equal(hiddenRangeModel.isHidden(10), false); + + }); + + +}); \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/test/indentFold.test.ts b/src/vs/editor/contrib/folding/test/indentFold.test.ts index bae8d357857..7109691b177 100644 --- a/src/vs/editor/contrib/folding/test/indentFold.test.ts +++ b/src/vs/editor/contrib/folding/test/indentFold.test.ts @@ -5,25 +5,73 @@ 'use strict'; import * as assert from 'assert'; -import { IFoldingRange } from 'vs/editor/contrib/folding/common/foldingModel'; -import { limitByIndent } from 'vs/editor/contrib/folding/common/indentFoldStrategy'; +import { computeRanges } from 'vs/editor/common/model/indentRanges'; +import { Model } from 'vs/editor/common/model/model'; + +interface IndentRange { + startLineNumber: number; + endLineNumber: number; +} suite('Indentation Folding', () => { - function r(startLineNumber: number, endLineNumber: number, indent: number): IFoldingRange { - return { startLineNumber, endLineNumber, indent }; + function r(startLineNumber: number, endLineNumber: number): IndentRange { + return { startLineNumber, endLineNumber }; } test('Limit By indent', () => { - let ranges = [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10), r(11, 12, 2000), r(14, 15, 2000)]; - assert.deepEqual(limitByIndent(ranges, 8), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10), r(11, 12, 2000), r(14, 15, 2000)]); - assert.deepEqual(limitByIndent(ranges, 7), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10)]); - assert.deepEqual(limitByIndent(ranges, 6), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10)]); - assert.deepEqual(limitByIndent(ranges, 5), [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0)]); - assert.deepEqual(limitByIndent(ranges, 4), [r(1, 4, 0), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0)]); - assert.deepEqual(limitByIndent(ranges, 3), [r(1, 4, 0), r(5, 8, 0), r(9, 15, 0)]); - assert.deepEqual(limitByIndent(ranges, 2), []); - assert.deepEqual(limitByIndent(ranges, 1), []); - assert.deepEqual(limitByIndent(ranges, 0), []); + + + let lines = [ + /* 1*/ 'A', + /* 2*/ ' A', + /* 3*/ ' A', + /* 4*/ ' A', + /* 5*/ ' A', + /* 6*/ ' A', + /* 7*/ ' A', + /* 8*/ ' A', + /* 9*/ ' A', + /* 10*/ ' A', + /* 11*/ ' A', + /* 12*/ ' A', + /* 13*/ ' A', + /* 14*/ ' A', + /* 15*/ 'A', + /* 16*/ ' A' + ]; + let r1 = r(1, 14); + let r2 = r(3, 11); + let r3 = r(4, 5); + let r4 = r(6, 11); + let r5 = r(8, 9); + let r6 = r(10, 11); + let r7 = r(12, 14); + let r8 = r(13, 14); + let r9 = r(15, 16); + + let model = Model.createFromString(lines.join('\n')); + + function assertLimit(maxEntries: number, expectedRanges: IndentRange[], message: string) { + let indentRanges = computeRanges(model, true, null, maxEntries); + assert.ok(indentRanges.length <= maxEntries, 'max ' + message); + assert.equal(indentRanges.length, expectedRanges.length, 'len ' + message); + for (let i = 0; i < expectedRanges.length; i++) { + assert.equal(indentRanges.getStartLineNumber(i), expectedRanges[i].startLineNumber, 'start ' + message); + assert.equal(indentRanges.getEndLineNumber(i), expectedRanges[i].endLineNumber, 'end ' + message); + } + } + + assertLimit(1000, [r1, r2, r3, r4, r5, r6, r7, r8, r9], '1'); + assertLimit(9, [r1, r2, r3, r4, r5, r6, r7, r8, r9], '2'); + assertLimit(8, [r1, r2, r3, r4, r5, r6, r7, r9], '3'); + assertLimit(7, [r1, r2, r3, r4, r7, r9], '4'); + assertLimit(6, [r1, r2, r3, r4, r7, r9], '5'); + assertLimit(5, [r1, r2, r7, r9], '6'); + assertLimit(4, [r1, r2, r7, r9], '7'); + assertLimit(3, [r1, r9], '8'); + assertLimit(2, [r1, r9], '9'); + assertLimit(1, [], '10'); + assertLimit(0, [], '11'); }); }); diff --git a/src/vs/editor/contrib/format/browser/formatActions.ts b/src/vs/editor/contrib/format/browser/formatActions.ts index de620bc090b..f663af59899 100644 --- a/src/vs/editor/contrib/format/browser/formatActions.ts +++ b/src/vs/editor/contrib/format/browser/formatActions.ts @@ -11,9 +11,9 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { editorAction, ServicesAccessor, EditorAction, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions'; +import { editorAction, ServicesAccessor, EditorAction, commonEditorContribution, IActionOptions } from 'vs/editor/common/editorCommonExtensions'; import { OnTypeFormattingEditProviderRegistry, DocumentRangeFormattingEditProviderRegistry } from 'vs/editor/common/modes'; -import { getOnTypeFormattingEdits, getDocumentFormattingEdits, getDocumentRangeFormattingEdits } from '../common/format'; +import { getOnTypeFormattingEdits, getDocumentFormattingEdits, getDocumentRangeFormattingEdits, NoProviderError } from '../common/format'; import { EditOperationsCommand } from '../common/formatCommand'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; @@ -23,6 +23,7 @@ import { Range } from 'vs/editor/common/core/range'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { EditorState, CodeEditorStateFlag } from 'vs/editor/common/core/editorState'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; function alertFormattingEdits(edits: editorCommon.ISingleEditOperation[]): void { @@ -53,6 +54,7 @@ function alertFormattingEdits(edits: editorCommon.ISingleEditOperation[]): void } @commonEditorContribution +// @ts-ignore @editorAction uses the class class FormatOnType implements editorCommon.IEditorContribution { private static ID = 'editor.contrib.autoFormat'; @@ -150,7 +152,7 @@ class FormatOnType implements editorCommon.IEditorContribution { tabSize: modelOpts.tabSize, insertSpaces: modelOpts.insertSpaces }).then(edits => { - return this.workerService.computeMoreMinimalEdits(model.uri, edits, []); + return this.workerService.computeMoreMinimalEdits(model.uri, edits); }).then(edits => { unbind.dispose(); @@ -179,6 +181,7 @@ class FormatOnType implements editorCommon.IEditorContribution { } @commonEditorContribution +// @ts-ignore @editorAction uses the class class FormatOnPaste implements editorCommon.IEditorContribution { private static ID = 'editor.contrib.formatOnPaste'; @@ -238,7 +241,7 @@ class FormatOnPaste implements editorCommon.IEditorContribution { const state = new EditorState(this.editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position); getDocumentRangeFormattingEdits(model, range, { tabSize, insertSpaces }).then(edits => { - return this.workerService.computeMoreMinimalEdits(model.uri, edits, []); + return this.workerService.computeMoreMinimalEdits(model.uri, edits); }).then(edits => { if (!state.validate(this.editor) || isFalsyOrEmpty(edits)) { return; @@ -263,6 +266,7 @@ export abstract class AbstractFormatAction extends EditorAction { public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): TPromise { const workerService = accessor.get(IEditorWorkerService); + const messageService = accessor.get(IMessageService); const formattingPromise = this._getFormattingEdits(editor); if (!formattingPromise) { @@ -273,7 +277,7 @@ export abstract class AbstractFormatAction extends EditorAction { const state = new EditorState(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position); // Receive formatted value from worker - return formattingPromise.then(edits => workerService.computeMoreMinimalEdits(editor.getModel().uri, edits, editor.getSelections())).then(edits => { + return formattingPromise.then(edits => workerService.computeMoreMinimalEdits(editor.getModel().uri, edits)).then(edits => { if (!state.validate(editor) || isFalsyOrEmpty(edits)) { return; } @@ -281,6 +285,15 @@ export abstract class AbstractFormatAction extends EditorAction { EditOperationsCommand.execute(editor, edits); alertFormattingEdits(edits); editor.focus(); + }, err => { + if (err instanceof Error && err.name === NoProviderError.Name) { + messageService.show( + Severity.Info, + nls.localize('no.provider', "Sorry, but there is no formatter for '{0}'-files installed.", editor.getModel().getLanguageIdentifier().language), + ); + } else { + throw err; + } }); } @@ -296,7 +309,7 @@ export class FormatDocumentAction extends AbstractFormatAction { id: 'editor.action.formatDocument', label: nls.localize('formatDocument.label', "Format Document"), alias: 'Format Document', - precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider), + precondition: EditorContextKeys.writable, kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F, @@ -304,6 +317,7 @@ export class FormatDocumentAction extends AbstractFormatAction { linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I } }, menuOpts: { + when: EditorContextKeys.hasDocumentFormattingProvider, group: '1_modification', order: 1.3 } @@ -325,12 +339,13 @@ export class FormatSelectionAction extends AbstractFormatAction { id: 'editor.action.formatSelection', label: nls.localize('formatSelection.label', "Format Selection"), alias: 'Format Code', - precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider, EditorContextKeys.hasNonEmptySelection), + precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasNonEmptySelection), kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F) }, menuOpts: { + when: ContextKeyExpr.and(EditorContextKeys.hasDocumentSelectionFormattingProvider, EditorContextKeys.hasNonEmptySelection), group: '1_modification', order: 1.31 } @@ -351,7 +366,7 @@ CommandsRegistry.registerCommand('editor.action.format', accessor => { if (editor) { return new class extends AbstractFormatAction { constructor() { - super({}); + super({} as IActionOptions); } _getFormattingEdits(editor: editorCommon.ICommonCodeEditor): TPromise { const model = editor.getModel(); diff --git a/src/vs/editor/contrib/format/common/format.ts b/src/vs/editor/contrib/format/common/format.ts index 0f8bb567719..37c0f0246fd 100644 --- a/src/vs/editor/contrib/format/common/format.ts +++ b/src/vs/editor/contrib/format/common/format.ts @@ -17,12 +17,23 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { asWinJsPromise, sequence } from 'vs/base/common/async'; import { Position } from 'vs/editor/common/core/position'; -export function getDocumentRangeFormattingEdits(model: IReadOnlyModel, range: Range, options: FormattingOptions): TPromise { +export class NoProviderError extends Error { + + static readonly Name = 'NOPRO'; + + constructor(message?: string) { + super(); + this.name = NoProviderError.Name; + this.message = message; + } +} + +export function getDocumentRangeFormattingEdits(model: IReadOnlyModel, range: Range, options: FormattingOptions): TPromise { const providers = DocumentRangeFormattingEditProviderRegistry.ordered(model); if (providers.length === 0) { - return TPromise.as(undefined); + return TPromise.wrapError(new NoProviderError()); } let result: TextEdit[]; diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts index 0cede0a44db..8aefedbf863 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationCommands.ts @@ -22,7 +22,7 @@ import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/ import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/browser/referencesModel'; import { PeekContext } from 'vs/editor/contrib/referenceSearch/browser/peekViewWidget'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { MessageController } from './messageController'; +import { MessageController } from 'vs/editor/contrib/message/messageController'; import * as corePosition from 'vs/editor/common/core/position'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IProgressService } from 'vs/platform/progress/common/progress'; @@ -150,7 +150,8 @@ export class DefinitionAction extends EditorAction { resource: uri, options: { selection: Range.collapseToStart(range), - revealIfVisible: !sideBySide + revealIfVisible: !sideBySide, + revealInCenterIfOutsideViewport: true } }, sideBySide).then(editor => { return editor && editor.getControl(); diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts index bb47505032e..872ce48705f 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts @@ -27,6 +27,7 @@ import { DefinitionAction, DefinitionActionConfig } from './goToDeclarationComma import { ClickLinkGesture, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from 'vs/editor/contrib/goToDeclaration/browser/clickLinkGesture'; @editorContribution +// @ts-ignore @editorAction uses the class class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorContribution { private static ID = 'editor.contrib.gotodefinitionwithmouse'; diff --git a/src/vs/editor/contrib/gotoError/browser/gotoError.css b/src/vs/editor/contrib/gotoError/browser/gotoError.css index e965155d98c..ad4b8d01ae4 100644 --- a/src/vs/editor/contrib/gotoError/browser/gotoError.css +++ b/src/vs/editor/contrib/gotoError/browser/gotoError.css @@ -7,7 +7,6 @@ .monaco-editor .marker-widget { padding-left: 2px; - overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } @@ -28,6 +27,7 @@ } .monaco-editor .marker-widget .descriptioncontainer { + position: relative; white-space: pre; -webkit-user-select: text; user-select: text; diff --git a/src/vs/editor/contrib/gotoError/browser/gotoError.ts b/src/vs/editor/contrib/gotoError/browser/gotoError.ts index ab9ecef7f0c..24a5d2dd690 100644 --- a/src/vs/editor/contrib/gotoError/browser/gotoError.ts +++ b/src/vs/editor/contrib/gotoError/browser/gotoError.ts @@ -28,7 +28,9 @@ import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { AccessibilitySupport } from 'vs/base/common/platform'; -import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder } from 'vs/editor/common/view/editorColorRegistry'; +import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoForeground, editorInfoBorder } from 'vs/editor/common/view/editorColorRegistry'; +import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import { ScrollbarVisibility } from 'vs/base/common/scrollable'; class MarkerModel { @@ -188,27 +190,68 @@ class MarkerModel { class MessageWidget { - domNode: HTMLDivElement; lines: number = 0; + longestLineLength: number = 0; - constructor(container: HTMLElement) { - this.domNode = document.createElement('div'); - this.domNode.className = 'block descriptioncontainer'; - this.domNode.setAttribute('aria-live', 'assertive'); - this.domNode.setAttribute('role', 'alert'); - container.appendChild(this.domNode); + private readonly _editor: ICodeEditor; + private readonly _domNode: HTMLElement; + private readonly _scrollable: ScrollableElement; + private readonly _disposables: IDisposable[] = []; + + constructor(parent: HTMLElement, editor: ICodeEditor) { + this._editor = editor; + + this._domNode = document.createElement('span'); + this._domNode.className = 'descriptioncontainer'; + this._domNode.setAttribute('aria-live', 'assertive'); + this._domNode.setAttribute('role', 'alert'); + + this._scrollable = new ScrollableElement(this._domNode, { + horizontal: ScrollbarVisibility.Auto, + vertical: ScrollbarVisibility.Hidden, + useShadows: false, + horizontalScrollbarSize: 3 + }); + dom.addClass(this._scrollable.getDomNode(), 'block'); + parent.appendChild(this._scrollable.getDomNode()); + this._disposables.push(this._scrollable.onScroll(e => this._domNode.style.left = `-${e.scrollLeft}px`)); + this._disposables.push(this._scrollable); + } + + dispose(): void { + dispose(this._disposables); } update({ source, message }: IMarker): void { - this.lines = 1; + if (source) { + this.lines = 0; + this.longestLineLength = 0; const indent = new Array(source.length + 3 + 1).join(' '); - message = `[${source}] ` + message.replace(/\r\n|\r|\n/g, () => { + const lines = message.split(/\r\n|\r|\n/g); + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; this.lines += 1; - return '\n' + indent; - }); + this.longestLineLength = Math.max(line.length, this.longestLineLength); + if (i === 0) { + message = `[${source}] ${line}`; + } else { + message += `\n${indent}${line}`; + } + } + } else { + this.lines = 1; + this.longestLineLength = message.length; } - this.domNode.innerText = message; + + this._domNode.innerText = message; + this._editor.applyFontInfo(this._domNode); + const width = Math.floor(this._editor.getConfiguration().fontInfo.typicalFullwidthCharacterWidth * this.longestLineLength); + this._scrollable.setScrollDimensions({ scrollWidth: width }); + } + + layout(height: number, width: number): void { + this._scrollable.setScrollDimensions({ width }); } } @@ -222,7 +265,11 @@ class MarkerNavigationWidget extends ZoneWidget { private _severity: Severity; private _backgroundColor: Color; - constructor(editor: ICodeEditor, private _model: MarkerModel, private _themeService: IThemeService) { + constructor( + editor: ICodeEditor, + private _model: MarkerModel, + private _themeService: IThemeService + ) { super(editor, { showArrow: true, showFrame: true, isAccessible: true }); this._severity = Severity.Warning; this._backgroundColor = Color.white; @@ -236,7 +283,13 @@ class MarkerNavigationWidget extends ZoneWidget { private _applyTheme(theme: ITheme) { this._backgroundColor = theme.getColor(editorMarkerNavigationBackground); - let frameColor = theme.getColor(this._severity === Severity.Error ? editorMarkerNavigationError : editorMarkerNavigationWarning); + let colorId = editorMarkerNavigationError; + if (this._severity === Severity.Warning) { + colorId = editorMarkerNavigationWarning; + } else if (this._severity === Severity.Info) { + colorId = editorMarkerNavigationInfo; + } + let frameColor = theme.getColor(colorId); this.style({ arrowColor: frameColor, frameColor: frameColor @@ -272,11 +325,11 @@ class MarkerNavigationWidget extends ZoneWidget { this._title.className = 'block title'; this._container.appendChild(this._title); - this._message = new MessageWidget(this._container); - this.editor.applyFontInfo(this._message.domNode); + this._message = new MessageWidget(this._container, this.editor); + this._disposables.push(this._message); } - public show(where: Position, heightInLines: number): void { + show(where: Position, heightInLines: number): void { super.show(where, heightInLines); if (this.editor.getConfiguration().accessibilitySupport !== AccessibilitySupport.Disabled) { this.focus(); @@ -322,6 +375,10 @@ class MarkerNavigationWidget extends ZoneWidget { this._relayout(); } + protected _doLayout(heightInPixel: number, widthInPixel: number): void { + this._message.layout(heightInPixel, widthInPixel); + } + protected _relayout(): void { super._relayout(this.computeRequiredHeight()); } @@ -349,6 +406,14 @@ class MarkerNavigationAction extends EditorAction { } let model = controller.getOrCreateModel(); + /* __GDPR__ + "zoneWidgetShown" : { + "mode" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "${include}": [ + "${EditorTelemetryData}" + ] + } + */ telemetryService.publicLog('zoneWidgetShown', { mode: 'go to error', ...editor.getTelemetryData() }); if (model) { if (this._isNext) { @@ -439,6 +504,7 @@ class MarkerController implements editorCommon.IEditorContribution { } @editorAction +// @ts-ignore @editorAction uses the class class NextMarkerAction extends MarkerNavigationAction { constructor() { super(true, { @@ -455,6 +521,7 @@ class NextMarkerAction extends MarkerNavigationAction { } @editorAction +// @ts-ignore @editorAction uses the class class PrevMarkerAction extends MarkerNavigationAction { constructor() { super(false, { @@ -490,7 +557,9 @@ CommonEditorRegistry.registerEditorCommand(new MarkerCommand({ let errorDefault = oneOf(editorErrorForeground, editorErrorBorder); let warningDefault = oneOf(editorWarningForeground, editorWarningBorder); +let infoDefault = oneOf(editorInfoForeground, editorInfoBorder); export const editorMarkerNavigationError = registerColor('editorMarkerNavigationError.background', { dark: errorDefault, light: errorDefault, hc: errorDefault }, nls.localize('editorMarkerNavigationError', 'Editor marker navigation widget error color.')); export const editorMarkerNavigationWarning = registerColor('editorMarkerNavigationWarning.background', { dark: warningDefault, light: warningDefault, hc: warningDefault }, nls.localize('editorMarkerNavigationWarning', 'Editor marker navigation widget warning color.')); +export const editorMarkerNavigationInfo = registerColor('editorMarkerNavigationInfo.background', { dark: infoDefault, light: infoDefault, hc: infoDefault }, nls.localize('editorMarkerNavigationInfo', 'Editor marker navigation widget info color.')); export const editorMarkerNavigationBackground = registerColor('editorMarkerNavigation.background', { dark: '#2D2D30', light: Color.white, hc: '#0C141F' }, nls.localize('editorMarkerNavigationBackground', 'Editor marker navigation widget background.')); diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index c895d1c9888..b7854831ac9 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -23,6 +23,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorHoverHighlight, editorHoverBackground, editorHoverBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; @editorContribution export class ModesHoverController implements editorCommon.IEditorContribution { @@ -64,9 +65,9 @@ export class ModesHoverController implements editorCommon.IEditorContribution { this._hideWidgets(); } })); - - this._contentWidget = new ModesContentHoverWidget(editor, openerService, modeService); - this._glyphWidget = new ModesGlyphHoverWidget(editor, openerService, modeService); + const renderer = new MarkdownRenderer(editor, modeService, openerService); + this._contentWidget = new ModesContentHoverWidget(editor, renderer); + this._glyphWidget = new ModesGlyphHoverWidget(editor, renderer); } } @@ -169,6 +170,7 @@ export class ModesHoverController implements editorCommon.IEditorContribution { } @editorAction +// @ts-ignore @editorAction uses the class class ShowHoverAction extends EditorAction { constructor() { @@ -218,5 +220,4 @@ registerThemingParticipant((theme, collector) => { if (codeBackground) { collector.addRule(`.monaco-editor .monaco-editor-hover code { background-color: ${codeBackground}; }`); } - }); diff --git a/src/vs/editor/contrib/hover/browser/hoverWidgets.ts b/src/vs/editor/contrib/hover/browser/hoverWidgets.ts index eacdbf64f4e..d11c154e171 100644 --- a/src/vs/editor/contrib/hover/browser/hoverWidgets.ts +++ b/src/vs/editor/contrib/hover/browser/hoverWidgets.ts @@ -130,10 +130,8 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent } private updateFont(): void { - const codeTags: HTMLElement[] = Array.prototype.slice.call(this._domNode.getElementsByTagName('code')); const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._domNode.getElementsByClassName('code')); - - [...codeTags, ...codeClasses].forEach(node => this._editor.applyFontInfo(node)); + codeClasses.forEach(node => this._editor.applyFontInfo(node)); } protected updateContents(node: Node): void { diff --git a/src/vs/editor/contrib/hover/browser/modesContentHover.ts b/src/vs/editor/contrib/hover/browser/modesContentHover.ts index d181229ba08..d6dc2864e1e 100644 --- a/src/vs/editor/contrib/hover/browser/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/browser/modesContentHover.ts @@ -5,28 +5,24 @@ 'use strict'; import * as nls from 'vs/nls'; -import URI from 'vs/base/common/uri'; -import { onUnexpectedError } from 'vs/base/common/errors'; import * as dom from 'vs/base/browser/dom'; import { TPromise } from 'vs/base/common/winjs.base'; -import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer'; -import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { IRange, Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; -import { HoverProviderRegistry, Hover, IColor, IColorFormatter } from 'vs/editor/common/modes'; -import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; +import { HoverProviderRegistry, Hover, IColor, DocumentColorProvider } from 'vs/editor/common/modes'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { getHover } from '../common/hover'; import { HoverOperation, IHoverComputer } from './hoverOperation'; import { ContentHoverWidget } from './hoverWidgets'; -import { IMarkdownString, MarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent'; +import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent'; +import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/browser/colorPickerModel'; import { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/browser/colorPickerWidget'; import { ColorDetector } from 'vs/editor/contrib/colorPicker/browser/colorDetector'; import { Color, RGBA } from 'vs/base/common/color'; import { IDisposable, empty as EmptyDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; +import { getColorPresentations } from 'vs/editor/contrib/colorPicker/common/color'; const $ = dom.$; class ColorHover { @@ -34,7 +30,7 @@ class ColorHover { constructor( public readonly range: IRange, public readonly color: IColor, - public readonly formatters: IColorFormatter[] + public readonly provider: DocumentColorProvider ) { } } @@ -95,13 +91,13 @@ class ModesContentComputer implements IHoverComputer { } const range = new Range(this._range.startLineNumber, startColumn, this._range.startLineNumber, endColumn); - const colorRange = colorDetector.getColorRange(d.range.getStartPosition()); + const colorData = colorDetector.getColorData(d.range.getStartPosition()); - if (!didFindColor && colorRange) { + if (!didFindColor && colorData) { didFindColor = true; - const { color, formatters } = colorRange; - return new ColorHover(d.range, color, formatters); + const { color, range } = colorData.colorInfo; + return new ColorHover(range, color, colorData.provider); } else { if (isEmptyMarkdownString(d.options.hoverMessage)) { return null; @@ -166,22 +162,20 @@ export class ModesContentHoverWidget extends ContentHoverWidget { private _hoverOperation: HoverOperation; private _highlightDecorations: string[]; private _isChangingDecorations: boolean; - private _openerService: IOpenerService; - private _modeService: IModeService; + private _markdownRenderer: MarkdownRenderer; private _shouldFocus: boolean; private _colorPicker: ColorPickerWidget; private renderDisposable: IDisposable = EmptyDisposable; private toDispose: IDisposable[]; - constructor(editor: ICodeEditor, openerService: IOpenerService, modeService: IModeService) { + constructor(editor: ICodeEditor, markdownRenderner: MarkdownRenderer) { super(ModesContentHoverWidget.ID, editor); this._computer = new ModesContentComputer(this._editor); this._highlightDecorations = []; this._isChangingDecorations = false; - this._openerService = openerService || NullOpenerService; - this._modeService = modeService; + this._markdownRenderer = markdownRenderner; this._hoverOperation = new HoverOperation( this._computer, @@ -249,6 +243,9 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } } if (filteredMessages.length > 0) { + if (hoverContentsEquals(filteredMessages, this._messages)) { + return; + } this._renderMessages(range, filteredMessages); } else { this.hide(); @@ -300,6 +297,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { highlightRange = messages[0].range, fragment = document.createDocumentFragment(); + let containColorPicker = false; messages.forEach((msg) => { if (!msg.range) { return; @@ -312,75 +310,91 @@ export class ModesContentHoverWidget extends ContentHoverWidget { msg.contents .filter(contents => !isEmptyMarkdownString(contents)) .forEach(contents => { - const renderedContents = renderMarkdown(contents, { - actionCallback: (content) => { - this._openerService.open(URI.parse(content)).then(void 0, onUnexpectedError); - }, - codeBlockRenderer: (languageAlias, value): string | TPromise => { - // In markdown, - // it is possible that we stumble upon language aliases (e.g.js instead of javascript) - // it is possible no alias is given in which case we fall back to the current editor lang - const modeId = languageAlias - ? this._modeService.getModeIdForLanguageName(languageAlias) - : this._editor.getModel().getLanguageIdentifier().language; - - return this._modeService.getOrCreateMode(modeId).then(_ => { - return tokenizeToString(value, modeId); - }); - } - }); - + const renderedContents = this._markdownRenderer.render(contents); fragment.appendChild($('div.hover-row', null, renderedContents)); }); } else { + containColorPicker = true; + const { red, green, blue, alpha } = msg.color; const rgba = new RGBA(red * 255, green * 255, blue * 255, alpha); const color = new Color(rgba); - const formatters = [...msg.formatters]; - const text = this._editor.getModel().getValueInRange(msg.range); - - let formatterIndex = 0; - - for (let i = 0; i < formatters.length; i++) { - if (text === formatters[i].format(msg.color)) { - formatterIndex = i; - break; - } - } - - const model = new ColorPickerModel(color, formatters, formatterIndex); - const widget = new ColorPickerWidget(fragment, model, this._editor.getConfiguration().pixelRatio); - const editorModel = this._editor.getModel(); let range = new Range(msg.range.startLineNumber, msg.range.startColumn, msg.range.endLineNumber, msg.range.endColumn); + let colorInfo = { range: msg.range, color: msg.color }; - const updateEditorModel = () => { - const text = model.formatter.format({ - red: model.color.rgba.r / 255, - green: model.color.rgba.g / 255, - blue: model.color.rgba.b / 255, - alpha: model.color.rgba.a + // create blank olor picker model and widget first to ensure it's positioned correctly. + const model = new ColorPickerModel(color, [], 0); + const widget = new ColorPickerWidget(fragment, model, this._editor.getConfiguration().pixelRatio); + + getColorPresentations(editorModel, colorInfo, msg.provider).then(colorPresentations => { + model.colorPresentations = colorPresentations; + const originalText = this._editor.getModel().getValueInRange(msg.range); + model.guessColorPresentation(color, originalText); + + const updateEditorModel = () => { + let textEdits; + let newRange; + if (model.presentation.textEdit) { + textEdits = [model.presentation.textEdit]; + newRange = new Range( + model.presentation.textEdit.range.startLineNumber, + model.presentation.textEdit.range.startColumn, + model.presentation.textEdit.range.endLineNumber, + model.presentation.textEdit.range.endColumn + ); + newRange = newRange.setEndPosition(newRange.endLineNumber, newRange.startColumn + model.presentation.textEdit.text.length); + } else { + textEdits = [{ identifier: null, range, text: model.presentation.label, forceMoveMarkers: false }]; + newRange = range.setEndPosition(range.endLineNumber, range.startColumn + model.presentation.label.length); + } + + editorModel.pushEditOperations([], textEdits, () => []); + + if (model.presentation.additionalTextEdits) { + textEdits = [...model.presentation.additionalTextEdits]; + editorModel.pushEditOperations([], textEdits, () => []); + this.hide(); + } + this._editor.pushUndoStop(); + range = newRange; + }; + + const updateColorPresentations = (color: Color) => { + return getColorPresentations(editorModel, { + range: range, + color: { + red: color.rgba.r / 255, + green: color.rgba.g / 255, + blue: color.rgba.b / 255, + alpha: color.rgba.a + } + }, msg.provider).then((colorPresentations) => { + model.colorPresentations = colorPresentations; + }); + }; + + const colorListener = model.onColorFlushed((color: Color) => { + updateColorPresentations(color).then(updateEditorModel); }); - editorModel.pushEditOperations([], [{ identifier: null, range, text, forceMoveMarkers: false }], () => []); - this._editor.pushUndoStop(); - range = range.setEndPosition(range.endLineNumber, range.startColumn + text.length); - }; + const colorChangeListener = model.onDidChangeColor(updateColorPresentations); - const colorListener = model.onColorFlushed(updateEditorModel); + this._colorPicker = widget; + this.showAt(new Position(renderRange.startLineNumber, renderColumn), this._shouldFocus); + this.updateContents(fragment); + this._colorPicker.layout(); - this._colorPicker = widget; - this.renderDisposable = combinedDisposable([colorListener, widget]); + this.renderDisposable = combinedDisposable([colorListener, colorChangeListener, widget]); + }); } }); // show - this.showAt(new Position(renderRange.startLineNumber, renderColumn), this._shouldFocus); - this.updateContents(fragment); - - if (this._colorPicker) { - this._colorPicker.layout(); + if (!containColorPicker) { + this.showAt(new Position(renderRange.startLineNumber, renderColumn), this._shouldFocus); + this.updateContents(fragment); } this._isChangingDecorations = true; @@ -395,3 +409,23 @@ export class ModesContentHoverWidget extends ContentHoverWidget { className: 'hoverHighlight' }); } + +function hoverContentsEquals(first: HoverPart[], second: HoverPart[]): boolean { + if ((!first && second) || (first && !second) || first.length !== second.length) { + return false; + } + for (let i = 0; i < first.length; i++) { + const firstElement = first[i]; + const secondElement = second[i]; + if (firstElement instanceof ColorHover) { + return false; + } + if (secondElement instanceof ColorHover) { + return false; + } + if (!markedStringsEquals(firstElement.contents, secondElement.contents)) { + return false; + } + } + return true; +} diff --git a/src/vs/editor/contrib/hover/browser/modesGlyphHover.ts b/src/vs/editor/contrib/hover/browser/modesGlyphHover.ts index 75eeb5c7504..522abe7a08e 100644 --- a/src/vs/editor/contrib/hover/browser/modesGlyphHover.ts +++ b/src/vs/editor/contrib/hover/browser/modesGlyphHover.ts @@ -8,13 +8,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { HoverOperation, IHoverComputer } from './hoverOperation'; import { GlyphHoverWidget } from './hoverWidgets'; import { $ } from 'vs/base/browser/dom'; -import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer'; -import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener'; -import URI from 'vs/base/common/uri'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; +import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; import { IMarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent'; export interface IHoverMessage { @@ -94,16 +88,16 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget { private _messages: IHoverMessage[]; private _lastLineNumber: number; + private _markdownRenderer: MarkdownRenderer; private _computer: MarginComputer; private _hoverOperation: HoverOperation; - constructor(editor: ICodeEditor, private openerService: IOpenerService, private modeService: IModeService) { + constructor(editor: ICodeEditor, markdownRenderer: MarkdownRenderer) { super(ModesGlyphHoverWidget.ID, editor); - this.openerService = openerService || NullOpenerService; - this._lastLineNumber = -1; + this._markdownRenderer = markdownRenderer; this._computer = new MarginComputer(this._editor); this._hoverOperation = new HoverOperation( @@ -166,17 +160,7 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget { const fragment = document.createDocumentFragment(); messages.forEach((msg) => { - const renderedContents = renderMarkdown(msg.value, { - actionCallback: content => this.openerService.open(URI.parse(content)).then(undefined, onUnexpectedError), - codeBlockRenderer: (languageAlias, value): string | TPromise => { - // In markdown, it is possible that we stumble upon language aliases (e.g. js instead of javascript) - const modeId = this.modeService.getModeIdForLanguageName(languageAlias); - return this.modeService.getOrCreateMode(modeId).then(_ => { - return tokenizeToString(value, modeId); - }); - } - }); - + const renderedContents = this._markdownRenderer.render(msg.value); fragment.appendChild($('div.hover-row', null, renderedContents)); }); diff --git a/src/vs/editor/contrib/inPlaceReplace/common/inPlaceReplace.ts b/src/vs/editor/contrib/inPlaceReplace/common/inPlaceReplace.ts index 3e9084e361a..4e5eba2cf32 100644 --- a/src/vs/editor/contrib/inPlaceReplace/common/inPlaceReplace.ts +++ b/src/vs/editor/contrib/inPlaceReplace/common/inPlaceReplace.ts @@ -34,7 +34,6 @@ class InPlaceReplaceController implements IEditorContribution { }); private editor: ICommonCodeEditor; - private requestIdPool: number; private currentRequest: TPromise; private decorationRemover: TPromise; private decorationIds: string[]; @@ -46,7 +45,6 @@ class InPlaceReplaceController implements IEditorContribution { ) { this.editor = editor; this.editorWorkerService = editorWorkerService; - this.requestIdPool = 0; this.currentRequest = TPromise.as(null); this.decorationRemover = TPromise.as(null); this.decorationIds = []; @@ -141,6 +139,7 @@ class InPlaceReplaceController implements IEditorContribution { } @editorAction +// @ts-ignore @editorAction uses the class class InPlaceReplaceUp extends EditorAction { constructor() { @@ -166,6 +165,7 @@ class InPlaceReplaceUp extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class InPlaceReplaceDown extends EditorAction { constructor() { diff --git a/src/vs/editor/contrib/indentation/common/indentation.ts b/src/vs/editor/contrib/indentation/common/indentation.ts index cd9add8748f..5530c97ef8e 100644 --- a/src/vs/editor/contrib/indentation/common/indentation.ts +++ b/src/vs/editor/contrib/indentation/common/indentation.ts @@ -323,7 +323,9 @@ export class ReindentLinesAction extends EditorAction { } let edits = getReindentEditOperations(model, 1, model.getLineCount()); if (edits) { + editor.pushUndoStop(); editor.executeEdits(this.id, edits); + editor.pushUndoStop(); } } } @@ -331,6 +333,7 @@ export class ReindentLinesAction extends EditorAction { export class AutoIndentOnPasteCommand implements ICommand { private _edits: TextEdit[]; + // @ts-ignore @editorAction unused property private _newEol: EndOfLineSequence; private _initialSelection: Selection; diff --git a/src/vs/editor/contrib/linesOperations/common/linesOperations.ts b/src/vs/editor/contrib/linesOperations/common/linesOperations.ts index 3c5229de450..05eeac34347 100644 --- a/src/vs/editor/contrib/linesOperations/common/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/common/linesOperations.ts @@ -14,6 +14,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; +import { Position } from 'vs/editor/common/core/position'; import { editorAction, ServicesAccessor, IActionOptions, EditorAction } from 'vs/editor/common/editorCommonExtensions'; import { CopyLinesCommand } from './copyLinesCommand'; import { DeleteLinesCommand } from './deleteLinesCommand'; @@ -48,6 +49,7 @@ abstract class AbstractCopyLinesAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class CopyLinesUpAction extends AbstractCopyLinesAction { constructor() { super(false, { @@ -65,6 +67,7 @@ class CopyLinesUpAction extends AbstractCopyLinesAction { } @editorAction +// @ts-ignore @editorAction uses the class class CopyLinesDownAction extends AbstractCopyLinesAction { constructor() { super(true, { @@ -109,6 +112,7 @@ abstract class AbstractMoveLinesAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class MoveLinesUpAction extends AbstractMoveLinesAction { constructor() { super(false, { @@ -126,6 +130,7 @@ class MoveLinesUpAction extends AbstractMoveLinesAction { } @editorAction +// @ts-ignore @editorAction uses the class class MoveLinesDownAction extends AbstractMoveLinesAction { constructor() { super(true, { @@ -165,6 +170,7 @@ abstract class AbstractSortLinesAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class SortLinesAscendingAction extends AbstractSortLinesAction { constructor() { super(false, { @@ -177,6 +183,7 @@ class SortLinesAscendingAction extends AbstractSortLinesAction { } @editorAction +// @ts-ignore @editorAction uses the class class SortLinesDescendingAction extends AbstractSortLinesAction { constructor() { super(true, { @@ -206,9 +213,17 @@ export class TrimTrailingWhitespaceAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor, args: any): void { - var command = new TrimTrailingWhitespaceCommand(editor.getSelection()); + let cursors: Position[] = []; + if (args.reason === 'auto-save') { + // See https://github.com/editorconfig/editorconfig-vscode/issues/47 + // It is very convenient for the editor config extension to invoke this action. + // So, if we get a reason:'auto-save' passed in, let's preserve cursor positions. + cursors = editor.getSelections().map(s => new Position(s.positionLineNumber, s.positionColumn)); + } + + var command = new TrimTrailingWhitespaceCommand(editor.getSelection(), cursors); editor.pushUndoStop(); editor.executeCommands(this.id, [command]); @@ -267,6 +282,7 @@ abstract class AbstractRemoveLinesAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class DeleteLinesAction extends AbstractRemoveLinesAction { constructor() { @@ -320,6 +336,7 @@ export class IndentLinesAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class OutdentLinesAction extends EditorAction { constructor() { super({ @@ -407,7 +424,9 @@ export abstract class AbstractDeleteAllToBoundaryAction extends EditorAction { return EditOperation.replace(range, ''); }); + editor.pushUndoStop(); editor.executeEdits(this.id, edits, endCursorState); + editor.pushUndoStop(); } /** @@ -673,8 +692,9 @@ export class JoinLinesAction extends EditorAction { } endCursorState.unshift(endPrimaryCursor); + editor.pushUndoStop(); editor.executeEdits(this.id, edits, endCursorState); - + editor.pushUndoStop(); } } diff --git a/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts b/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts index 64c67e2cb9a..3e7578ef9e8 100644 --- a/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts @@ -73,6 +73,32 @@ suite('Editor Contrib - Line Operations', () => { assert.equal(model.getLineContent(5), 'horlworld', '005'); }); }); + + test('issue #36234: should push undo stop', () => { + withMockCodeEditor( + [ + 'one', + 'two', + 'three' + ], {}, (editor, cursor) => { + let model = editor.getModel(); + let deleteAllLeftAction = new DeleteAllLeftAction(); + + editor.setSelection(new Selection(1, 1, 1, 1)); + + editor.trigger('keyboard', Handler.Type, { text: 'Typing some text here on line ' }); + assert.equal(model.getLineContent(1), 'Typing some text here on line one'); + assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31)); + + deleteAllLeftAction.run(null, editor); + assert.equal(model.getLineContent(1), 'one'); + assert.deepEqual(editor.getSelection(), new Selection(1, 1, 1, 1)); + + editor.trigger('keyboard', Handler.Undo, {}); + assert.equal(model.getLineContent(1), 'Typing some text here on line one'); + assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31)); + }); + }); }); suite('JoinLinesAction', () => { @@ -164,6 +190,31 @@ suite('Editor Contrib - Line Operations', () => { assert.deepEqual(editor.getSelection().toString(), new Selection(3, 4, 3, 8).toString(), '003'); }); }); + + test('should push undo stop', function () { + withMockCodeEditor( + [ + 'hello', + 'world' + ], {}, (editor, cursor) => { + let model = editor.getModel(); + let joinLinesAction = new JoinLinesAction(); + + editor.setSelection(new Selection(1, 6, 1, 6)); + + editor.trigger('keyboard', Handler.Type, { text: ' my dear' }); + assert.equal(model.getLineContent(1), 'hello my dear'); + assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14)); + + joinLinesAction.run(null, editor); + assert.equal(model.getLineContent(1), 'hello my dear world'); + assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14)); + + editor.trigger('keyboard', Handler.Undo, {}); + assert.equal(model.getLineContent(1), 'hello my dear'); + assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14)); + }); + }); }); test('transpose', function () { diff --git a/src/vs/editor/contrib/linesOperations/test/common/sortLinesCommand.test.ts b/src/vs/editor/contrib/linesOperations/test/common/sortLinesCommand.test.ts index ec19e7bbe0d..58aa224ff6c 100644 --- a/src/vs/editor/contrib/linesOperations/test/common/sortLinesCommand.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/common/sortLinesCommand.test.ts @@ -77,7 +77,7 @@ suite('Editor Contrib - Sort Lines Command', () => { 'third line', 'fifth' ], - new Selection(3, 3, 4, 2) + new Selection(3, 3, 4, 1) ); }); @@ -119,7 +119,7 @@ suite('Editor Contrib - Sort Lines Command', () => { 'second line', 'third line', ], - new Selection(1, 1, 5, 6) + new Selection(1, 1, 5, 11) ); }); diff --git a/src/vs/editor/contrib/links/browser/links.ts b/src/vs/editor/contrib/links/browser/links.ts index 4c6eceb7ff6..3b5c1d3532e 100644 --- a/src/vs/editor/contrib/links/browser/links.ts +++ b/src/vs/editor/contrib/links/browser/links.ts @@ -16,7 +16,6 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; import { LinkProviderRegistry } from 'vs/editor/common/modes'; -import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { ICodeEditor, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { getLinks, Link } from 'vs/editor/contrib/links/common/links'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -148,19 +147,16 @@ class LinkDetector implements editorCommon.IEditorContribution { private activeLinkDecorationId: string; private openerService: IOpenerService; private messageService: IMessageService; - private editorWorkerService: IEditorWorkerService; private currentOccurrences: { [decorationId: string]: LinkOccurrence; }; constructor( editor: ICodeEditor, @IOpenerService openerService: IOpenerService, - @IMessageService messageService: IMessageService, - @IEditorWorkerService editorWorkerService: IEditorWorkerService + @IMessageService messageService: IMessageService ) { this.editor = editor; this.openerService = openerService; this.messageService = messageService; - this.editorWorkerService = editorWorkerService; this.listenersToRemove = []; let clickLinkGesture = new ClickLinkGesture(editor); @@ -389,6 +385,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } @editorAction +// @ts-ignore @editorAction uses the class class OpenLinkAction extends EditorAction { constructor() { diff --git a/src/vs/editor/contrib/markdown/browser/markdownRenderer.ts b/src/vs/editor/contrib/markdown/browser/markdownRenderer.ts new file mode 100644 index 00000000000..29ce9afe931 --- /dev/null +++ b/src/vs/editor/contrib/markdown/browser/markdownRenderer.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { TPromise } from 'vs/base/common/winjs.base'; +import { IMarkdownString } from 'vs/base/common/htmlContent'; +import { renderMarkdown, RenderOptions } from 'vs/base/browser/htmlContentRenderer'; +import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import URI from 'vs/base/common/uri'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { optional } from 'vs/platform/instantiation/common/instantiation'; + +export class MarkdownRenderer { + + private readonly _options: RenderOptions; + + constructor( + editor: ICodeEditor, + @IModeService private readonly _modeService: IModeService, + @optional(IOpenerService) private readonly _openerService: IOpenerService = NullOpenerService, + ) { + this._options = { + actionCallback: (content) => { + this._openerService.open(URI.parse(content)).then(void 0, onUnexpectedError); + }, + codeBlockRenderer: (languageAlias, value): string | TPromise => { + // In markdown, + // it is possible that we stumble upon language aliases (e.g.js instead of javascript) + // it is possible no alias is given in which case we fall back to the current editor lang + const modeId = languageAlias + ? this._modeService.getModeIdForLanguageName(languageAlias) + : editor.getModel().getLanguageIdentifier().language; + + return this._modeService.getOrCreateMode(modeId).then(_ => { + return tokenizeToString(value, modeId); + }).then(code => { + return `${code}`; + }); + } + }; + } + + render(markdown: IMarkdownString, options?: RenderOptions): HTMLElement { + if (!markdown) { + return document.createElement('span'); + } + if (options) { + return renderMarkdown(markdown, { ...options, ...this._options }); + } else { + return renderMarkdown(markdown, this._options); + } + } +} diff --git a/src/vs/editor/contrib/goToDeclaration/browser/messageController.css b/src/vs/editor/contrib/message/messageController.css similarity index 100% rename from src/vs/editor/contrib/goToDeclaration/browser/messageController.css rename to src/vs/editor/contrib/message/messageController.css diff --git a/src/vs/editor/contrib/goToDeclaration/browser/messageController.ts b/src/vs/editor/contrib/message/messageController.ts similarity index 98% rename from src/vs/editor/contrib/goToDeclaration/browser/messageController.ts rename to src/vs/editor/contrib/message/messageController.ts index 693722e4c52..ce5d45af58c 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/messageController.ts +++ b/src/vs/editor/contrib/message/messageController.ts @@ -47,10 +47,14 @@ export class MessageController { this._visible = MessageController.CONTEXT_SNIPPET_MODE.bindTo(contextKeyService); } - dispose() { + dispose(): void { this._visible.reset(); } + isVisible() { + return this._visible.get(); + } + showMessage(message: string, position: IPosition): void { alert(message); diff --git a/src/vs/editor/contrib/multicursor/common/multicursor.ts b/src/vs/editor/contrib/multicursor/common/multicursor.ts index 0f6b2fdec41..f044ba0f0cf 100644 --- a/src/vs/editor/contrib/multicursor/common/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/common/multicursor.ts @@ -5,14 +5,24 @@ 'use strict'; import * as nls from 'vs/nls'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { ICommonCodeEditor, ScrollType } from 'vs/editor/common/editorCommon'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { ICommonCodeEditor, ScrollType, IEditorContribution, FindMatch, TrackedRangeStickiness, OverviewRulerLane, IModel } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; +import { editorAction, commonEditorContribution, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; +import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; +import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { CursorMoveCommands } from 'vs/editor/common/controller/cursorMoveCommands'; import { CursorState, RevealTarget } from 'vs/editor/common/controller/cursorCommon'; +import { Constants } from 'vs/editor/common/core/uint'; +import { DocumentHighlightProviderRegistry } from 'vs/editor/common/modes'; +import { CommonFindController } from 'vs/editor/contrib/find/common/findController'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; +import { themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { INewFindReplaceState, FindOptionOverride } from 'vs/editor/contrib/find/common/findState'; @editorAction export class InsertCursorAbove extends EditorAction { @@ -95,6 +105,7 @@ export class InsertCursorBelow extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class InsertCursorAtEndOfEachLineSelected extends EditorAction { constructor() { @@ -139,3 +150,764 @@ class InsertCursorAtEndOfEachLineSelected extends EditorAction { } } } + +export class MultiCursorSessionResult { + constructor( + public readonly selections: Selection[], + public readonly revealRange: Range, + public readonly revealScrollType: ScrollType + ) { } +} + +export class MultiCursorSession { + + public static create(editor: ICommonCodeEditor, findController: CommonFindController): MultiCursorSession { + const findState = findController.getState(); + + // Find widget owns entirely what we search for if: + // - focus is not in the editor (i.e. it is in the find widget) + // - and the search widget is visible + // - and the search string is non-empty + if (!editor.isFocused() && findState.isRevealed && findState.searchString.length > 0) { + // Find widget owns what is searched for + return new MultiCursorSession(editor, findController, false, findState.searchString, findState.wholeWord, findState.matchCase, null); + } + + // Otherwise, the selection gives the search text, and the find widget gives the search settings + // The exception is the find state disassociation case: when beginning with a single, collapsed selection + let isDisconnectedFromFindController = false; + let wholeWord: boolean; + let matchCase: boolean; + const selections = editor.getSelections(); + if (selections.length === 1 && selections[0].isEmpty()) { + isDisconnectedFromFindController = true; + wholeWord = true; + matchCase = true; + } else { + wholeWord = findState.wholeWord; + matchCase = findState.matchCase; + } + + // Selection owns what is searched for + const s = editor.getSelection(); + + let searchText: string; + let currentMatch: Selection = null; + + if (s.isEmpty()) { + // selection is empty => expand to current word + const word = editor.getModel().getWordAtPosition(s.getStartPosition()); + if (!word) { + return null; + } + searchText = word.word; + currentMatch = new Selection(s.startLineNumber, word.startColumn, s.startLineNumber, word.endColumn); + } else { + searchText = editor.getModel().getValueInRange(s).replace(/\r\n/g, '\n'); + } + + return new MultiCursorSession(editor, findController, isDisconnectedFromFindController, searchText, wholeWord, matchCase, currentMatch); + } + + constructor( + private readonly _editor: ICommonCodeEditor, + public readonly findController: CommonFindController, + public readonly isDisconnectedFromFindController: boolean, + public readonly searchText: string, + public readonly wholeWord: boolean, + public readonly matchCase: boolean, + public currentMatch: Selection + ) { } + + public addSelectionToNextFindMatch(): MultiCursorSessionResult { + const nextMatch = this._getNextMatch(); + if (!nextMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.concat(nextMatch), nextMatch, ScrollType.Smooth); + } + + public moveSelectionToNextFindMatch(): MultiCursorSessionResult { + const nextMatch = this._getNextMatch(); + if (!nextMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.slice(0, allSelections.length - 1).concat(nextMatch), nextMatch, ScrollType.Smooth); + } + + private _getNextMatch(): Selection { + if (this.currentMatch) { + const result = this.currentMatch; + this.currentMatch = null; + return result; + } + + this.findController.highlightFindOptions(); + + const allSelections = this._editor.getSelections(); + const lastAddedSelection = allSelections[allSelections.length - 1]; + const nextMatch = this._editor.getModel().findNextMatch(this.searchText, lastAddedSelection.getEndPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + + if (!nextMatch) { + return null; + } + return new Selection(nextMatch.range.startLineNumber, nextMatch.range.startColumn, nextMatch.range.endLineNumber, nextMatch.range.endColumn); + } + + public addSelectionToPreviousFindMatch(): MultiCursorSessionResult { + const previousMatch = this._getPreviousMatch(); + if (!previousMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.concat(previousMatch), previousMatch, ScrollType.Smooth); + } + + public moveSelectionToPreviousFindMatch(): MultiCursorSessionResult { + const previousMatch = this._getPreviousMatch(); + if (!previousMatch) { + return null; + } + + const allSelections = this._editor.getSelections(); + return new MultiCursorSessionResult(allSelections.slice(0, allSelections.length - 1).concat(previousMatch), previousMatch, ScrollType.Smooth); + } + + private _getPreviousMatch(): Selection { + if (this.currentMatch) { + const result = this.currentMatch; + this.currentMatch = null; + return result; + } + + this.findController.highlightFindOptions(); + + const allSelections = this._editor.getSelections(); + const lastAddedSelection = allSelections[allSelections.length - 1]; + const previousMatch = this._editor.getModel().findPreviousMatch(this.searchText, lastAddedSelection.getStartPosition(), false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false); + + if (!previousMatch) { + return null; + } + return new Selection(previousMatch.range.startLineNumber, previousMatch.range.startColumn, previousMatch.range.endLineNumber, previousMatch.range.endColumn); + } + + public selectAll(): FindMatch[] { + this.findController.highlightFindOptions(); + + return this._editor.getModel().findMatches(this.searchText, true, false, this.matchCase, this.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + } +} + +@commonEditorContribution +export class MultiCursorSelectionController extends Disposable implements IEditorContribution { + + private static ID = 'editor.contrib.multiCursorController'; + + private readonly _editor: ICommonCodeEditor; + private _ignoreSelectionChange: boolean; + private _session: MultiCursorSession; + private _sessionDispose: IDisposable[]; + + public static get(editor: ICommonCodeEditor): MultiCursorSelectionController { + return editor.getContribution(MultiCursorSelectionController.ID); + } + + constructor(editor: ICommonCodeEditor) { + super(); + this._editor = editor; + this._ignoreSelectionChange = false; + this._session = null; + this._sessionDispose = []; + } + + public dispose(): void { + this._endSession(); + super.dispose(); + } + + public getId(): string { + return MultiCursorSelectionController.ID; + } + + private _beginSessionIfNeeded(findController: CommonFindController): void { + if (!this._session) { + // Create a new session + const session = MultiCursorSession.create(this._editor, findController); + if (!session) { + return; + } + + this._session = session; + + const newState: INewFindReplaceState = { searchString: this._session.searchText }; + if (this._session.isDisconnectedFromFindController) { + newState.wholeWordOverride = FindOptionOverride.True; + newState.matchCaseOverride = FindOptionOverride.True; + newState.isRegexOverride = FindOptionOverride.False; + } + findController.getState().change(newState, false); + + this._sessionDispose = [ + this._editor.onDidChangeCursorSelection((e) => { + if (this._ignoreSelectionChange) { + return; + } + this._endSession(); + }), + this._editor.onDidBlurEditorText(() => { + this._endSession(); + }), + findController.getState().addChangeListener((e) => { + if (e.matchCase || e.wholeWord) { + this._endSession(); + } + }) + ]; + } + } + + private _endSession(): void { + this._sessionDispose = dispose(this._sessionDispose); + if (this._session && this._session.isDisconnectedFromFindController) { + const newState: INewFindReplaceState = { + wholeWordOverride: FindOptionOverride.NotSet, + matchCaseOverride: FindOptionOverride.NotSet, + isRegexOverride: FindOptionOverride.NotSet, + }; + this._session.findController.getState().change(newState, false); + } + this._session = null; + } + + private _setSelections(selections: Selection[]): void { + this._ignoreSelectionChange = true; + this._editor.setSelections(selections); + this._ignoreSelectionChange = false; + } + + private _expandEmptyToWord(model: IModel, selection: Selection): Selection { + if (!selection.isEmpty()) { + return selection; + } + const word = model.getWordAtPosition(selection.getStartPosition()); + if (!word) { + return selection; + } + return new Selection(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn); + } + + private _applySessionResult(result: MultiCursorSessionResult): void { + if (!result) { + return; + } + this._setSelections(result.selections); + if (result.revealRange) { + this._editor.revealRangeInCenterIfOutsideViewport(result.revealRange, result.revealScrollType); + } + } + + public getSession(findController: CommonFindController): MultiCursorSession { + return this._session; + } + + public addSelectionToNextFindMatch(findController: CommonFindController): void { + if (!this._session) { + // If there are multiple cursors, handle the case where they do not all select the same text. + const allSelections = this._editor.getSelections(); + if (allSelections.length > 1) { + const findState = findController.getState(); + const matchCase = findState.matchCase; + const selectionsContainSameText = modelRangesContainSameText(this._editor.getModel(), allSelections, matchCase); + if (!selectionsContainSameText) { + const model = this._editor.getModel(); + let resultingSelections: Selection[] = []; + for (let i = 0, len = allSelections.length; i < len; i++) { + resultingSelections[i] = this._expandEmptyToWord(model, allSelections[i]); + } + this._editor.setSelections(resultingSelections); + return; + } + } + } + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.addSelectionToNextFindMatch()); + } + } + + public addSelectionToPreviousFindMatch(findController: CommonFindController): void { + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.addSelectionToPreviousFindMatch()); + } + } + + public moveSelectionToNextFindMatch(findController: CommonFindController): void { + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.moveSelectionToNextFindMatch()); + } + } + + public moveSelectionToPreviousFindMatch(findController: CommonFindController): void { + this._beginSessionIfNeeded(findController); + if (this._session) { + this._applySessionResult(this._session.moveSelectionToPreviousFindMatch()); + } + } + + public selectAll(findController: CommonFindController): void { + let matches: FindMatch[] = null; + + const findState = findController.getState(); + + // Special case: find widget owns entirely what we search for if: + // - focus is not in the editor (i.e. it is in the find widget) + // - and the search widget is visible + // - and the search string is non-empty + // - and we're searching for a regex + if (!this._editor.isFocused() && findState.isRevealed && findState.searchString.length > 0 && findState.isRegex) { + + matches = this._editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? this._editor.getConfiguration().wordSeparators : null, false, Constants.MAX_SAFE_SMALL_INTEGER); + + } else { + + this._beginSessionIfNeeded(findController); + if (!this._session) { + return; + } + + matches = this._session.selectAll(); + } + + if (matches.length > 0) { + const editorSelection = this._editor.getSelection(); + // Have the primary cursor remain the one where the action was invoked + for (let i = 0, len = matches.length; i < len; i++) { + const match = matches[i]; + const intersection = match.range.intersectRanges(editorSelection); + if (intersection) { + // bingo! + matches[i] = matches[0]; + matches[0] = match; + break; + } + } + + this._setSelections(matches.map(m => new Selection(m.range.startLineNumber, m.range.startColumn, m.range.endLineNumber, m.range.endColumn))); + } + } +} + +export abstract class MultiCursorSelectionControllerAction extends EditorAction { + + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + const multiCursorController = MultiCursorSelectionController.get(editor); + if (!multiCursorController) { + return; + } + const findController = CommonFindController.get(editor); + if (!findController) { + return null; + } + this._run(multiCursorController, findController); + } + + protected abstract _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void; +} + +@editorAction +export class AddSelectionToNextFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.addSelectionToNextFindMatch', + label: nls.localize('addSelectionToNextFindMatch', "Add Selection To Next Find Match"), + alias: 'Add Selection To Next Find Match', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.focus, + primary: KeyMod.CtrlCmd | KeyCode.KEY_D + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.addSelectionToNextFindMatch(findController); + } +} + +@editorAction +export class AddSelectionToPreviousFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.addSelectionToPreviousFindMatch', + label: nls.localize('addSelectionToPreviousFindMatch', "Add Selection To Previous Find Match"), + alias: 'Add Selection To Previous Find Match', + precondition: null + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.addSelectionToPreviousFindMatch(findController); + } +} + +@editorAction +export class MoveSelectionToNextFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.moveSelectionToNextFindMatch', + label: nls.localize('moveSelectionToNextFindMatch', "Move Last Selection To Next Find Match"), + alias: 'Move Last Selection To Next Find Match', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.focus, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D) + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.moveSelectionToNextFindMatch(findController); + } +} + +@editorAction +export class MoveSelectionToPreviousFindMatchAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.moveSelectionToPreviousFindMatch', + label: nls.localize('moveSelectionToPreviousFindMatch', "Move Last Selection To Previous Find Match"), + alias: 'Move Last Selection To Previous Find Match', + precondition: null + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.moveSelectionToPreviousFindMatch(findController); + } +} + +@editorAction +export class SelectHighlightsAction extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.selectHighlights', + label: nls.localize('selectAllOccurrencesOfFindMatch', "Select All Occurrences of Find Match"), + alias: 'Select All Occurrences of Find Match', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.focus, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.selectAll(findController); + } +} + +@editorAction +export class CompatChangeAll extends MultiCursorSelectionControllerAction { + constructor() { + super({ + id: 'editor.action.changeAll', + label: nls.localize('changeAll.label', "Change All Occurrences"), + alias: 'Change All Occurrences', + precondition: EditorContextKeys.writable, + kbOpts: { + kbExpr: EditorContextKeys.textFocus, + primary: KeyMod.CtrlCmd | KeyCode.F2 + }, + menuOpts: { + group: '1_modification', + order: 1.2 + } + }); + } + protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { + multiCursorController.selectAll(findController); + } +} + +class SelectionHighlighterState { + public readonly lastWordUnderCursor: Selection; + public readonly searchText: string; + public readonly matchCase: boolean; + public readonly wordSeparators: string; + + constructor(lastWordUnderCursor: Selection, searchText: string, matchCase: boolean, wordSeparators: string) { + this.lastWordUnderCursor = lastWordUnderCursor; + this.searchText = searchText; + this.matchCase = matchCase; + this.wordSeparators = wordSeparators; + } + + /** + * Everything equals except for `lastWordUnderCursor` + */ + public static softEquals(a: SelectionHighlighterState, b: SelectionHighlighterState): boolean { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return ( + a.searchText === b.searchText + && a.matchCase === b.matchCase + && a.wordSeparators === b.wordSeparators + ); + } +} + +@commonEditorContribution +export class SelectionHighlighter extends Disposable implements IEditorContribution { + private static ID = 'editor.contrib.selectionHighlighter'; + + private editor: ICommonCodeEditor; + private _isEnabled: boolean; + private decorations: string[]; + private updateSoon: RunOnceScheduler; + private state: SelectionHighlighterState; + + constructor(editor: ICommonCodeEditor) { + super(); + this.editor = editor; + this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + this.decorations = []; + this.updateSoon = this._register(new RunOnceScheduler(() => this._update(), 300)); + this.state = null; + + this._register(editor.onDidChangeConfiguration((e) => { + this._isEnabled = editor.getConfiguration().contribInfo.selectionHighlight; + })); + this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { + + if (!this._isEnabled) { + // Early exit if nothing needs to be done! + // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;) + return; + } + + if (e.selection.isEmpty()) { + if (e.reason === CursorChangeReason.Explicit) { + if (this.state && (!this.state.lastWordUnderCursor || !this.state.lastWordUnderCursor.containsPosition(e.selection.getStartPosition()))) { + // no longer valid + this._setState(null); + } + this.updateSoon.schedule(); + } else { + this._setState(null); + + } + } else { + this._update(); + } + })); + this._register(editor.onDidChangeModel((e) => { + this._setState(null); + })); + this._register(CommonFindController.get(editor).getState().addChangeListener((e) => { + this._update(); + })); + } + + public getId(): string { + return SelectionHighlighter.ID; + } + + private _update(): void { + this._setState(SelectionHighlighter._createState(this._isEnabled, this.editor)); + } + + private static _createState(isEnabled: boolean, editor: ICommonCodeEditor): SelectionHighlighterState { + if (!isEnabled) { + return null; + } + const model = editor.getModel(); + if (!model) { + return null; + } + const s = editor.getSelection(); + if (s.startLineNumber !== s.endLineNumber) { + // multiline forbidden for perf reasons + return null; + } + const multiCursorController = MultiCursorSelectionController.get(editor); + if (!multiCursorController) { + return null; + } + const findController = CommonFindController.get(editor); + if (!findController) { + return null; + } + let r = multiCursorController.getSession(findController); + if (!r) { + const allSelections = editor.getSelections(); + if (allSelections.length > 1) { + const findState = findController.getState(); + const matchCase = findState.matchCase; + const selectionsContainSameText = modelRangesContainSameText(editor.getModel(), allSelections, matchCase); + if (!selectionsContainSameText) { + return null; + } + } + + r = MultiCursorSession.create(editor, findController); + } + if (!r) { + return null; + } + + let lastWordUnderCursor: Selection = null; + const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); + if (r.currentMatch) { + // This is an empty selection + if (hasFindOccurrences) { + // Do not interfere with semantic word highlighting in the no selection case + return null; + } + + const config = editor.getConfiguration(); + if (!config.contribInfo.occurrencesHighlight) { + return null; + } + + lastWordUnderCursor = r.currentMatch; + } + if (/^[ \t]+$/.test(r.searchText)) { + // whitespace only selection + return null; + } + if (r.searchText.length > 200) { + // very long selection + return null; + } + + // TODO: better handling of this case + const findState = findController.getState(); + const caseSensitive = findState.matchCase; + + // Return early if the find widget shows the exact same matches + if (findState.isRevealed) { + let findStateSearchString = findState.searchString; + if (!caseSensitive) { + findStateSearchString = findStateSearchString.toLowerCase(); + } + + let mySearchString = r.searchText; + if (!caseSensitive) { + mySearchString = mySearchString.toLowerCase(); + } + + if (findStateSearchString === mySearchString && r.matchCase === findState.matchCase && r.wholeWord === findState.wholeWord && !findState.isRegex) { + return null; + } + } + + return new SelectionHighlighterState(lastWordUnderCursor, r.searchText, r.matchCase, r.wholeWord ? editor.getConfiguration().wordSeparators : null); + } + + private _setState(state: SelectionHighlighterState): void { + if (SelectionHighlighterState.softEquals(this.state, state)) { + this.state = state; + return; + } + this.state = state; + + if (!this.state) { + if (this.decorations.length > 0) { + this.decorations = this.editor.deltaDecorations(this.decorations, []); + } + return; + } + + const model = this.editor.getModel(); + const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model); + + let allMatches = model.findMatches(this.state.searchText, true, false, this.state.matchCase, this.state.wordSeparators, false).map(m => m.range); + allMatches.sort(Range.compareRangesUsingStarts); + + let selections = this.editor.getSelections(); + selections.sort(Range.compareRangesUsingStarts); + + // do not overlap with selection (issue #64 and #512) + let matches: Range[] = []; + for (let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len;) { + const match = allMatches[i]; + + if (j >= lenJ) { + // finished all editor selections + matches.push(match); + i++; + } else { + const cmp = Range.compareRangesUsingStarts(match, selections[j]); + if (cmp < 0) { + // match is before sel + matches.push(match); + i++; + } else if (cmp > 0) { + // sel is before match + j++; + } else { + // sel is equal to match + i++; + j++; + } + } + } + + const decorations = matches.map(r => { + return { + range: r, + // Show in overviewRuler only if model has no semantic highlighting + options: (hasFindOccurrences ? SelectionHighlighter._SELECTION_HIGHLIGHT : SelectionHighlighter._SELECTION_HIGHLIGHT_OVERVIEW) + }; + }); + + this.decorations = this.editor.deltaDecorations(this.decorations, decorations); + } + + private static _SELECTION_HIGHLIGHT_OVERVIEW = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'selectionHighlight', + overviewRuler: { + color: themeColorFromId(overviewRulerSelectionHighlightForeground), + darkColor: themeColorFromId(overviewRulerSelectionHighlightForeground), + position: OverviewRulerLane.Center + } + }); + + private static _SELECTION_HIGHLIGHT = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'selectionHighlight', + }); + + public dispose(): void { + this._setState(null); + super.dispose(); + } +} + +function modelRangesContainSameText(model: IModel, ranges: Range[], matchCase: boolean): boolean { + const selectedText = getValueInRange(model, ranges[0], !matchCase); + for (let i = 1, len = ranges.length; i < len; i++) { + const range = ranges[i]; + if (range.isEmpty()) { + return false; + } + const thisSelectedText = getValueInRange(model, range, !matchCase); + if (selectedText !== thisSelectedText) { + return false; + } + } + return true; +} + +function getValueInRange(model: IModel, range: Range, toLowerCase: boolean): string { + const text = model.getValueInRange(range); + return (toLowerCase ? text.toLowerCase() : text); +} diff --git a/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts index 7824a0df71e..438ca8dd54f 100644 --- a/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts +++ b/src/vs/editor/contrib/multicursor/test/common/multicursor.test.ts @@ -5,11 +5,14 @@ 'use strict'; import * as assert from 'assert'; -import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; +import { withMockCodeEditor, MockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; import { Selection } from 'vs/editor/common/core/selection'; -import { InsertCursorAbove, InsertCursorBelow } from 'vs/editor/contrib/multicursor/common/multicursor'; -import { Handler } from 'vs/editor/common/editorCommon'; - +import { Range } from 'vs/editor/common/core/range'; +import { InsertCursorAbove, InsertCursorBelow, MultiCursorSelectionController, SelectHighlightsAction, AddSelectionToNextFindMatchAction } from 'vs/editor/contrib/multicursor/common/multicursor'; +import { Handler, EndOfLineSequence } from 'vs/editor/common/editorCommon'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { CommonFindController } from 'vs/editor/contrib/find/common/findController'; suite('Multicursor', () => { @@ -42,3 +45,525 @@ suite('Multicursor', () => { }); }); + +function fromRange(rng: Range): number[] { + return [rng.startLineNumber, rng.startColumn, rng.endLineNumber, rng.endColumn]; +} + +suite('Multicursor selection', () => { + let queryState: { [key: string]: any; } = {}; + let serviceCollection = new ServiceCollection(); + serviceCollection.set(IStorageService, { + get: (key: string) => queryState[key], + getBoolean: (key: string) => !!queryState[key], + store: (key: string, value: any) => { queryState[key] = value; } + } as IStorageService); + + test('issue #8817: Cursor position changes when you cancel multicursor', () => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let selectHighlightsAction = new SelectHighlightsAction(); + + editor.setSelection(new Selection(2, 9, 2, 16)); + + selectHighlightsAction.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [2, 9, 2, 16], + [1, 9, 1, 16], + [3, 9, 3, 16], + ]); + + editor.trigger('test', 'removeSecondaryCursors', null); + + assert.deepEqual(fromRange(editor.getSelection()), [2, 9, 2, 16]); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('issue #5400: "Select All Occurrences of Find Match" does not select all if find uses regex', () => { + withMockCodeEditor([ + 'something', + 'someething', + 'someeething', + 'nothing' + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let selectHighlightsAction = new SelectHighlightsAction(); + + editor._isFocused = false; + + editor.setSelection(new Selection(1, 1, 1, 1)); + findController.getState().change({ searchString: 'some+thing', isRegex: true, isRevealed: true }, false); + + selectHighlightsAction.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 1, 1, 10], + [2, 1, 2, 11], + [3, 1, 3, 12], + ]); + + assert.equal(findController.getState().searchString, 'some+thing'); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('AddSelectionToNextFindMatchAction can work with multiline', () => { + withMockCodeEditor([ + '', + 'qwe', + 'rty', + '', + 'qwe', + '', + 'rty', + 'qwe', + 'rty' + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); + + editor.setSelection(new Selection(2, 1, 3, 4)); + + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [2, 1, 3, 4], + [8, 1, 9, 4] + ]); + + editor.trigger('test', 'removeSecondaryCursors', null); + + assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('issue #6661: AddSelectionToNextFindMatchAction can work with touching ranges', () => { + withMockCodeEditor([ + 'abcabc', + 'abc', + 'abcabc', + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); + + editor.setSelection(new Selection(1, 1, 1, 4)); + + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 1, 1, 4], + [1, 4, 1, 7] + ]); + + addSelectionToNextFindMatch.run(null, editor); + addSelectionToNextFindMatch.run(null, editor); + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 1, 1, 4], + [1, 4, 1, 7], + [2, 1, 2, 4], + [3, 1, 3, 4], + [3, 4, 3, 7] + ]); + + editor.trigger('test', Handler.Type, { text: 'z' }); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [1, 2, 1, 2], + [1, 3, 1, 3], + [2, 2, 2, 2], + [3, 2, 3, 2], + [3, 3, 3, 3] + ]); + assert.equal(editor.getValue(), [ + 'zz', + 'z', + 'zz', + ].join('\n')); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + test('issue #23541: Multiline Ctrl+D does not work in CRLF files', () => { + withMockCodeEditor([ + '', + 'qwe', + 'rty', + '', + 'qwe', + '', + 'rty', + 'qwe', + 'rty' + ], { serviceCollection: serviceCollection }, (editor, cursor) => { + + editor.getModel().setEOL(EndOfLineSequence.CRLF); + + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); + + editor.setSelection(new Selection(2, 1, 3, 4)); + + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [2, 1, 3, 4], + [8, 1, 9, 4] + ]); + + editor.trigger('test', 'removeSecondaryCursors', null); + + assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + }); + + function testMulticursor(text: string[], callback: (editor: MockCodeEditor, findController: CommonFindController) => void): void { + withMockCodeEditor(text, { serviceCollection: serviceCollection }, (editor, cursor) => { + let findController = editor.registerAndInstantiateContribution(CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + + callback(editor, findController); + + multiCursorSelectController.dispose(); + findController.dispose(); + }); + } + + function testAddSelectionToNextFindMatchAction(text: string[], callback: (editor: MockCodeEditor, action: AddSelectionToNextFindMatchAction, findController: CommonFindController) => void): void { + testMulticursor(text, (editor, findController) => { + let action = new AddSelectionToNextFindMatchAction(); + callback(editor, action, findController); + }); + } + + test('AddSelectionToNextFindMatchAction starting with single collapsed selection', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 1)', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 1, 1, 4), + new Selection(2, 2, 2, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with two selections, one being collapsed 2)', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with all collapsed selections', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + new Selection(2, 2, 2, 2), + new Selection(3, 1, 3, 1), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + new Selection(3, 1, 3, 4), + ]); + }); + }); + + test('AddSelectionToNextFindMatchAction starting with all collapsed selections on different words', () => { + const text = [ + 'abc pizza', + 'abc house', + 'abc bar' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 6, 1, 6), + new Selection(2, 6, 2, 6), + new Selection(3, 6, 3, 6), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 5, 1, 10), + new Selection(2, 5, 2, 10), + new Selection(3, 5, 3, 8), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 5, 1, 10), + new Selection(2, 5, 2, 10), + new Selection(3, 5, 3, 8), + ]); + }); + }); + + test('issue #20651: AddSelectionToNextFindMatchAction case insensitive', () => { + const text = [ + 'test', + 'testte', + 'Test', + 'testte', + 'test' + ]; + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 1, 1, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + new Selection(5, 1, 5, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 5), + new Selection(2, 1, 2, 5), + new Selection(3, 1, 3, 5), + new Selection(4, 1, 4, 5), + new Selection(5, 1, 5, 5), + ]); + }); + }); + + suite('Find state disassociation', () => { + + const text = [ + 'app', + 'apples', + 'whatsapp', + 'app', + 'App', + ' app' + ]; + + test('enters mode', () => { + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + new Selection(6, 2, 6, 5), + ]); + }); + }); + + test('leaves mode when selection changes', () => { + testAddSelectionToNextFindMatchAction(text, (editor, action, findController) => { + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + ]); + + // change selection + editor.setSelections([ + new Selection(1, 1, 1, 4), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(2, 1, 2, 4), + ]); + }); + }); + + test('Select Highlights respects mode ', () => { + testMulticursor(text, (editor, findController) => { + let action = new SelectHighlightsAction(); + editor.setSelections([ + new Selection(1, 2, 1, 2), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + new Selection(6, 2, 6, 5), + ]); + + action.run(null, editor); + assert.deepEqual(editor.getSelections(), [ + new Selection(1, 1, 1, 4), + new Selection(4, 1, 4, 4), + new Selection(6, 2, 6, 5), + ]); + }); + }); + + }); +}); diff --git a/src/vs/editor/contrib/parameterHints/browser/parameterHints.css b/src/vs/editor/contrib/parameterHints/browser/parameterHints.css index abb195c2d0b..2f89fb1658c 100644 --- a/src/vs/editor/contrib/parameterHints/browser/parameterHints.css +++ b/src/vs/editor/contrib/parameterHints/browser/parameterHints.css @@ -48,6 +48,19 @@ white-space: pre-wrap; } +.monaco-editor .parameter-hints-widget .docs.markdown-docs { + white-space: initial; +} + +.monaco-editor .parameter-hints-widget .docs .code { + white-space: pre-wrap; +} + +.monaco-editor .parameter-hints-widget .docs code { + border-radius: 3px; + padding: 0 0.4em; +} + .monaco-editor .parameter-hints-widget .buttons { position: absolute; display: none; diff --git a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts index fd83ce1c00e..2d022f949a3 100644 --- a/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts @@ -25,7 +25,10 @@ import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { registerThemingParticipant, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; -import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; const $ = dom.$; @@ -170,6 +173,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { private static ID = 'editor.widget.parameterHintsWidget'; + private markdownRenderer: MarkdownRenderer; private model: ParameterHintsModel; private keyVisible: IContextKey; private keyMultipleSignatures: IContextKey; @@ -187,7 +191,13 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { // Editor.IContentWidget.allowEditorOverflow allowEditorOverflow = true; - constructor(private editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService) { + constructor( + private editor: ICodeEditor, + @IContextKeyService contextKeyService: IContextKeyService, + @IOpenerService openerService: IOpenerService, + @IModeService modeService: IModeService, + ) { + this.markdownRenderer = new MarkdownRenderer(editor, modeService, openerService); this.model = new ParameterHintsModel(editor); this.keyVisible = Context.Visible.bindTo(contextKeyService); this.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService); @@ -208,9 +218,6 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { this.element = $('.editor-widget.parameter-hints-widget'); const wrapper = dom.append(this.element, $('.wrapper')); - const onClick = stop(domEvent(this.element, 'click')); - onClick(this.next, this, this.disposables); - const buttons = dom.append(wrapper, $('.buttons')); const previous = dom.append(buttons, $('.button.previous')); const next = dom.append(buttons, $('.button.next')); @@ -325,14 +332,22 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { if (activeParameter && activeParameter.documentation) { const documentation = $('span.documentation'); - documentation.textContent = activeParameter.documentation; + if (typeof activeParameter.documentation === 'string') { + dom.removeClass(this.docs, 'markdown-docs'); + documentation.textContent = activeParameter.documentation; + } else { + dom.addClass(this.docs, 'markdown-docs'); + documentation.appendChild(this.markdownRenderer.render(activeParameter.documentation)); + } dom.append(this.docs, $('p', null, documentation)); } dom.toggleClass(this.signature, 'has-docs', !!signature.documentation); - if (signature.documentation) { + if (typeof signature.documentation === 'string') { dom.append(this.docs, $('p', null, signature.documentation)); + } else { + dom.append(this.docs, this.markdownRenderer.render(signature.documentation)); } let currentOverload = String(this.currentSignature + 1); @@ -491,4 +506,14 @@ registerThemingParticipant((theme, collector) => { if (background) { collector.addRule(`.monaco-editor .parameter-hints-widget { background-color: ${background}; }`); } -}); \ No newline at end of file + + const link = theme.getColor(textLinkForeground); + if (link) { + collector.addRule(`.monaco-editor .parameter-hints-widget a { color: ${link}; }`); + } + + let codeBackground = theme.getColor(textCodeBlockBackground); + if (codeBackground) { + collector.addRule(`.monaco-editor .parameter-hints-widget code { background-color: ${codeBackground}; }`); + } +}); diff --git a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts index 8bb2b4c2f02..b920ccb714d 100644 --- a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts +++ b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts @@ -12,6 +12,7 @@ import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveM import * as dom from 'vs/base/browser/dom'; import { ICodeEditor, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { QuickFixComputeEvent } from './quickFixModel'; +import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; export class LightBulbWidget implements IDisposable, IContentWidget { @@ -29,12 +30,14 @@ export class LightBulbWidget implements IDisposable, IContentWidget { private _futureFixes = new CancellationTokenSource(); constructor(editor: ICodeEditor) { - this._editor = editor; - this._editor.addContentWidget(this); - this._domNode = document.createElement('div'); this._domNode.className = 'lightbulb-glyph'; + this._editor = editor; + this._editor.addContentWidget(this); + + this._disposables.push(this._editor.onDidChangeModel(_ => this._futureFixes.cancel())); + this._disposables.push(this._editor.onDidChangeModelLanguage(_ => this._futureFixes.cancel())); this._disposables.push(dom.addStandardDisposableListener(this._domNode, 'click', e => { // a bit of extra work to make sure the menu // doesn't cover the line-text @@ -66,6 +69,12 @@ export class LightBulbWidget implements IDisposable, IContentWidget { dom.removeClass(this._domNode, 'hidden'); }); })); + this._disposables.push(this._editor.onDidChangeConfiguration(e => { + // hide when told to do so + if (e.contribInfo && !this._editor.getConfiguration().contribInfo.lightbulbEnabled) { + this.hide(); + } + })); } dispose(): void { @@ -124,11 +133,16 @@ export class LightBulbWidget implements IDisposable, IContentWidget { } private _show(): void { - const { fontInfo } = this._editor.getConfiguration(); + const config = this._editor.getConfiguration(); + if (!config.contribInfo.lightbulbEnabled) { + return; + } const { lineNumber } = this._model.position; const model = this._editor.getModel(); - const indent = model.getIndentLevel(lineNumber); - const lineHasSpace = fontInfo.spaceWidth * indent > 22; + const tabSize = model.getOptions().tabSize; + const lineContent = model.getLineContent(lineNumber); + const indent = computeIndentLevel(lineContent, tabSize); + const lineHasSpace = config.fontInfo.spaceWidth * indent > 22; let effectiveLineNumber = lineNumber; if (!lineHasSpace) { diff --git a/src/vs/editor/contrib/quickFix/browser/quickFixModel.ts b/src/vs/editor/contrib/quickFix/browser/quickFixModel.ts index 5b173774b49..d8e6b63ad67 100644 --- a/src/vs/editor/contrib/quickFix/browser/quickFixModel.ts +++ b/src/vs/editor/contrib/quickFix/browser/quickFixModel.ts @@ -28,7 +28,7 @@ export class QuickFixOracle { ) { this._disposables.push( debounceEvent(this._markerService.onMarkerChanged, (last, cur) => last ? last.concat(cur) : cur, delay / 2)(e => this._onMarkerChanges(e)), - debounceEvent(this._editor.onDidChangeCursorPosition, last => last, delay)(e => this._onCursorChange()) + debounceEvent(this._editor.onDidChangeCursorPosition, (last, cur) => cur, delay)(e => this._onCursorChange()) ); } @@ -38,7 +38,7 @@ export class QuickFixOracle { trigger(type: 'manual' | 'auto'): void { let rangeOrSelection = this._getRangeOfMarker() || this._getRangeOfSelectionUnlessWhitespaceEnclosed(); - if (type === 'manual') { + if (!rangeOrSelection && type === 'manual') { rangeOrSelection = this._editor.getSelection(); } this._createEventAndSignalChange(type, rangeOrSelection); diff --git a/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts b/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts index e7cfec81974..22bd31ed785 100644 --- a/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts +++ b/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts @@ -54,7 +54,8 @@ export class QuickFixContextMenu { return at; }, getActions: () => actions, - onHide: () => { this._visible = false; } + onHide: () => { this._visible = false; }, + autoSelectFirstItem: true }); } diff --git a/src/vs/editor/contrib/quickFix/test/browser/quickFixModel.test.ts b/src/vs/editor/contrib/quickFix/test/browser/quickFixModel.test.ts index adb843d7a0e..cf7e42f3322 100644 --- a/src/vs/editor/contrib/quickFix/test/browser/quickFixModel.test.ts +++ b/src/vs/editor/contrib/quickFix/test/browser/quickFixModel.test.ts @@ -171,21 +171,21 @@ suite('QuickFix', () => { editor.setSelection({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 }); }); - // case 2 - selection over multiple lines & manual trigger -> lightbulb - await new TPromise(resolve => { + // // case 2 - selection over multiple lines & manual trigger -> lightbulb + // await new TPromise(resolve => { - editor.setSelection({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 }); + // editor.setSelection({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 }); - let oracle = new QuickFixOracle(editor, markerService, e => { - assert.equal(e.type, 'manual'); - assert.ok(e.range.equalsRange({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 })); + // let oracle = new QuickFixOracle(editor, markerService, e => { + // assert.equal(e.type, 'manual'); + // assert.ok(e.range.equalsRange({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 })); - oracle.dispose(); - resolve(null); - }, 5); + // oracle.dispose(); + // resolve(null); + // }, 5); - oracle.trigger('manual'); - }); + // oracle.trigger('manual'); + // }); reg.dispose(); diff --git a/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css b/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css index 8ef899a7815..3e253ab57b7 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css +++ b/src/vs/editor/contrib/referenceSearch/browser/media/peekViewWidget.css @@ -9,6 +9,7 @@ -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; + display: flex; } .monaco-editor .peekview-widget .head .peekview-title { @@ -24,16 +25,35 @@ } .monaco-editor .peekview-widget .head .peekview-actions { - display: inline-block; - position: absolute; - right: 2px; - top: 2px; + flex: 1; + text-align: right; + padding-right: 2px; } -.monaco-editor .peekview-widget .head .peekview-actions .action-label { +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar { + display: inline-block; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar, +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar > .actions-container { + height: 100%; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-item { + margin-left: 4px; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label { width: 16px; - height: 16px; - margin: 2px 0; + height: 100%; + margin: 0; + line-height: inherit; + background-repeat: no-repeat; + background-position: center center; +} + +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label.octicon { + margin: 0; } .monaco-editor .peekview-widget .head .peekview-actions .action-label.icon.close-peekview-action { diff --git a/src/vs/editor/contrib/referenceSearch/browser/media/referencesWidget.css b/src/vs/editor/contrib/referenceSearch/browser/media/referencesWidget.css index 5b316141553..5c8996336c3 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/media/referencesWidget.css +++ b/src/vs/editor/contrib/referenceSearch/browser/media/referencesWidget.css @@ -37,21 +37,18 @@ } .monaco-editor .reference-zone-widget .ref-tree .reference-file { - display: flex; - justify-content: space-between; - align-items: center; + display: inline-flex; + width: 100%; + height: 100%; } -.monaco-editor .reference-zone-widget .monaco-count-badge { - margin-right: .5em; - height: 15px; - padding: 0 .5em .5em .5em +.monaco-editor .reference-zone-widget .ref-tree .reference-file .count { + margin-right: 12px; + margin-left: auto; } /* High Contrast Theming */ .monaco-editor.hc-black .reference-zone-widget .ref-tree .reference-file { font-weight: bold; - display: flex; - justify-content: space-between; } diff --git a/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts index 1d912e8d055..09aab8dcdcd 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/peekViewWidget.ts @@ -13,7 +13,7 @@ import * as objects from 'vs/base/common/objects'; import { $ } from 'vs/base/browser/builder'; import Event, { Emitter } from 'vs/base/common/event'; import * as dom from 'vs/base/browser/dom'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionBarOptions } from 'vs/base/browser/ui/actionbar/actionbar'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; @@ -132,10 +132,9 @@ export abstract class PeekViewWidget extends ZoneWidget { this._secondaryHeading = $('span.dirname').appendTo(titleElement).getHTMLElement(); this._metaHeading = $('span.meta').appendTo(titleElement).getHTMLElement(); - this._actionbarWidget = new ActionBar( - $('.peekview-actions'). - appendTo(this._headElement) - ); + const actionsContainer = $('.peekview-actions').appendTo(this._headElement); + const actionBarOptions = this._getActionBarOptions(); + this._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions); this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), 'close-peekview-action', true, () => { this.dispose(); @@ -143,6 +142,10 @@ export abstract class PeekViewWidget extends ZoneWidget { }), { label: false, icon: true }); } + protected _getActionBarOptions(): IActionBarOptions { + return {}; + } + protected _onTitleClick(event: MouseEvent): void { // implement me } @@ -165,16 +168,13 @@ export abstract class PeekViewWidget extends ZoneWidget { } } - protected _fillBody(container: HTMLElement): void { - // implement me - } + protected abstract _fillBody(container: HTMLElement): void; public _doLayout(heightInPixel: number, widthInPixel: number): void { if (!this._isShowing && heightInPixel < 0) { // Looks like the view zone got folded away! this.dispose(); - this._onDidClose.fire(this); return; } diff --git a/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts b/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts index d42aa9f1c77..6e66f807034 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referenceSearch.ts @@ -143,9 +143,13 @@ let showReferencesCommand: ICommandHandler = (accessor: ServicesAccessor, resour // register commands -CommandsRegistry.registerCommand('editor.action.findReferences', findReferencesCommand); +CommandsRegistry.registerCommand({ + id: 'editor.action.findReferences', + handler: findReferencesCommand +}); -CommandsRegistry.registerCommand('editor.action.showReferences', { +CommandsRegistry.registerCommand({ + id: 'editor.action.showReferences', handler: showReferencesCommand, description: { description: 'Show references at a position in a file', diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts index cf8da0f92a7..7678766238c 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts @@ -123,7 +123,7 @@ export class ReferencesController implements editorCommon.IEditorContribution { switch (kind) { case 'open': if (event.source === 'editor' - && this._configurationService.lookup('editor.stablePeek').value) { + && this._configurationService.getValue('editor.stablePeek')) { // when stable peek is configured we don't close // the peek window on selecting the editor @@ -161,6 +161,12 @@ export class ReferencesController implements editorCommon.IEditorContribution { const startTime = Date.now(); this._disposables.push({ dispose: () => { + /* __GDPR__ + "zoneWidgetShown" : { + "mode" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "elapsedTime": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this._telemetryService.publicLog('zoneWidgetShown', { mode: 'reference search', elapsedTime: Date.now() - startTime @@ -191,6 +197,12 @@ export class ReferencesController implements editorCommon.IEditorContribution { const onDone = stopwatch(fromPromise(promise)); const mode = this._editor.getModel().getLanguageIdentifier().language; + /* __GDPR__ + "findReferences" : { + "durarion" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "mode": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ onDone(duration => this._telemetryService.publicLog('findReferences', { duration, mode diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts index 0d299ca85af..0a48d7d2457 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts @@ -38,7 +38,6 @@ import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/r import { registerColor, activeContrastBorder, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant, ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { attachListStyler, attachBadgeStyler } from 'vs/platform/theme/common/styler'; -import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; @@ -81,7 +80,7 @@ class DecorationsManager implements IDisposable { } private _addDecorations(reference: FileReferences): void { - this._callOnModelChange.push(this._editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged(event))); + this._callOnModelChange.push(this._editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged())); this._editor.changeDecorations(accessor => { @@ -107,21 +106,20 @@ class DecorationsManager implements IDisposable { }); } - private _onDecorationChanged(event: IModelDecorationsChangedEvent): void { - const changedDecorations = event.changedDecorations, - toRemove: string[] = []; + private _onDecorationChanged(): void { + const toRemove: string[] = []; - for (let i = 0, len = changedDecorations.length; i < len; i++) { - let reference = this._decorations.get(changedDecorations[i]); - if (!reference) { - continue; + this._decorations.forEach((reference, decorationId) => { + const newRange = this._editor.getModel().getDecorationRange(decorationId); + + if (!newRange) { + return; } - const newRange = this._editor.getModel().getDecorationRange(changedDecorations[i]); let ignore = false; if (Range.equalsRange(newRange, reference.range)) { - continue; + return; } else if (Range.spansMultipleLines(newRange)) { ignore = true; @@ -137,11 +135,11 @@ class DecorationsManager implements IDisposable { if (ignore) { this._decorationIgnoreSet.add(reference.id); - toRemove.push(changedDecorations[i]); + toRemove.push(decorationId); } else { reference.range = newRange; } - } + }); this._editor.changeDecorations((accessor) => { for (let i = 0, len = toRemove.length; i < len; i++) { @@ -357,11 +355,15 @@ class FileReferencesTemplate { const parent = document.createElement('div'); dom.addClass(parent, 'reference-file'); container.appendChild(parent); - this.file = new FileLabel(parent, URI.parse('no:file'), this._contextService, this._environmentService); - this.badge = new CountBadge(parent); + + this.badge = new CountBadge($('.count').appendTo(parent).getHTMLElement()); const styler = attachBadgeStyler(this.badge, themeService); - this.dispose = () => styler.dispose(); + + this.dispose = () => { + this.file.dispose(); + styler.dispose(); + }; } set(element: FileReferences) { diff --git a/src/vs/editor/contrib/rename/browser/rename.ts b/src/vs/editor/contrib/rename/browser/rename.ts index 55c51b473cb..b0549f09324 100644 --- a/src/vs/editor/contrib/rename/browser/rename.ts +++ b/src/vs/editor/contrib/rename/browser/rename.ts @@ -6,7 +6,7 @@ 'use strict'; import * as nls from 'vs/nls'; -import { isPromiseCanceledError, onUnexpectedExternalError, illegalArgument } from 'vs/base/common/errors'; +import { isPromiseCanceledError, illegalArgument } from 'vs/base/common/errors'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -18,7 +18,7 @@ import { editorAction, ServicesAccessor, EditorAction, EditorCommand, CommonEdit import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { ICommonCodeEditor, IEditorContribution, IReadOnlyModel } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { BulkEdit, createBulkEdit } from 'vs/editor/common/services/bulkEdit'; +import { createBulkEdit } from 'vs/editor/common/services/bulkEdit'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import RenameInputField from './renameInputField'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -29,6 +29,8 @@ import { WorkspaceEdit, RenameProviderRegistry } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { Range } from 'vs/editor/common/core/range'; +import { MessageController } from 'vs/editor/contrib/message/messageController'; +import { EditorState, CodeEditorStateFlag } from 'vs/editor/common/core/editorState'; export function rename(model: IReadOnlyModel, position: Position, newName: string): TPromise { @@ -52,9 +54,6 @@ export function rename(model: IReadOnlyModel, position: Position, newName: strin rejects.push(result.rejectReason); } return undefined; - }, err => { - onUnexpectedExternalError(err); - return TPromise.wrapError(new Error('provider failed')); }); } return undefined; @@ -148,7 +147,21 @@ class RenameController implements IEditorContribution { this._renameInputVisible.reset(); this.editor.focus(); - const renameOperation = this._prepareRename(newName).then(edit => { + // start recording of file changes so that we can figure out if a file that + // is to be renamed conflicts with another (concurrent) modification + const edit = createBulkEdit(this._textModelResolverService, this.editor, this._fileService); + const state = new EditorState(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection | CodeEditorStateFlag.Scroll); + + const renameOperation = rename(this.editor.getModel(), this.editor.getPosition(), newName).then(result => { + if (result.rejectReason) { + if (state.validate(this.editor)) { + MessageController.get(this.editor).showMessage(result.rejectReason, this.editor.getPosition()); + } else { + this._messageService.show(Severity.Info, result.rejectReason); + } + return undefined; + } + edit.add(result.edits); return edit.finish().then(selection => { if (selection) { @@ -159,13 +172,8 @@ class RenameController implements IEditorContribution { }); }, err => { - if (typeof err === 'string') { - this._messageService.show(Severity.Info, err); - return undefined; - } else { - this._messageService.show(Severity.Error, nls.localize('rename.failed', "Sorry, rename failed to execute.")); - return TPromise.wrapError(err); - } + this._messageService.show(Severity.Error, nls.localize('rename.failed', "Sorry, rename failed to execute.")); + return TPromise.wrapError(err); }); this._progressService.showWhile(renameOperation, 250); @@ -189,21 +197,6 @@ class RenameController implements IEditorContribution { public cancelRenameInput(): void { this._renameInputField.cancelInput(); } - - private _prepareRename(newName: string): TPromise { - - // start recording of file changes so that we can figure out if a file that - // is to be renamed conflicts with another (concurrent) modification - let edit = createBulkEdit(this._textModelResolverService, this.editor, this._fileService); - - return rename(this.editor.getModel(), this.editor.getPosition(), newName).then(result => { - if (result.rejectReason) { - return TPromise.wrapError(new Error(result.rejectReason)); - } - edit.add(result.edits); - return edit; - }); - } } // ---- action implementation diff --git a/src/vs/editor/contrib/smartSelect/common/smartSelect.ts b/src/vs/editor/contrib/smartSelect/common/smartSelect.ts index 47b9d0f2f0b..eb7f99d771c 100644 --- a/src/vs/editor/contrib/smartSelect/common/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/common/smartSelect.ts @@ -164,6 +164,7 @@ abstract class AbstractSmartSelect extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class GrowSelectionAction extends AbstractSmartSelect { constructor() { super(true, { @@ -181,6 +182,7 @@ class GrowSelectionAction extends AbstractSmartSelect { } @editorAction +// @ts-ignore @editorAction uses the class class ShrinkSelectionAction extends AbstractSmartSelect { constructor() { super(false, { diff --git a/src/vs/editor/contrib/snippet/browser/snippet.md b/src/vs/editor/contrib/snippet/browser/snippet.md index f370f5cd339..403cda77438 100644 --- a/src/vs/editor/contrib/snippet/browser/snippet.md +++ b/src/vs/editor/contrib/snippet/browser/snippet.md @@ -17,7 +17,7 @@ Placeholders can have choices as values. The syntax is a comma-separated enumera Variables -- -With `$name` or `${name:default}` you can insert the value of a variable. When a variable isn’t set its *default* or the empty string is inserted. When a varibale is unknown (that is, its name isn’t defined) the name of the variable is inserted and it is transformed into a placeholder. The following variables can be used: +With `$name` or `${name:default}` you can insert the value of a variable. When a variable isn’t set its *default* or the empty string is inserted. When a variable is unknown (that is, its name isn’t defined) the name of the variable is inserted and it is transformed into a placeholder. The following variables can be used: * `TM_SELECTED_TEXT` The currently selected text or the empty string * `TM_CURRENT_LINE` The contents of the current line @@ -25,9 +25,34 @@ With `$name` or `${name:default}` you can insert the value of a variable. When a * `TM_LINE_INDEX` The zero-index based line number * `TM_LINE_NUMBER` The one-index based line number * `TM_FILENAME` The filename of the current document -* `TM_DIRECTORY` The direcorty of the current document +* `TM_DIRECTORY` The directory of the current document * `TM_FILEPATH` The full file path of the current document +Variable-Transform +-- + +Transformations allow to modify the value of a variable before it is being inserted. The definition of a transformation consists of three parts: + +1. A regular expression that is matched against the value of a variable, or the empty string when the variable cannot be resolved. +2. A "format string" that allows to reference matching groups from the regular expression. The format string allows for conditional inserts and simple modifications. +3. Options that are passed to the regular expression + +The following sample inserts the name of the current file without its ending, so from `foo.txt` it makes `foo`. + +``` +${TM_FILENAME/(.*)\..+$/$1/} + | | | | + | | | |-> no options + | | | + | | |-> references the contents of the first + | | capture group + | | + | |-> regex to capture everything before + | the final `.suffix` + | + |-> resolves to the filename +``` + Grammar -- @@ -39,7 +64,16 @@ any ::= tabstop | placeholder | choice | variable | text tabstop ::= '$' int | '${' int '}' placeholder ::= '${' int ':' any '}' choice ::= '${' int '|' text (',' text)* '|}' -variable ::= '$' var | '${' var }' | '${' var ':' any '}' +variable ::= '$' var | '${' var }' + | '${' var ':' any '}' + | '${' var '/' regex '/' (format | text)+ '/' options '}' +format ::= '$' int | '${' int '}' + | '${' int ':' '/upcase' | '/downcase' | '/capitalize' '}' + | '${' int ':+' if '}' + | '${' int ':?' if ':' else '}' + | '${' int ':-' else '}' | '${' int ':' else '}' +regex ::= JavaScript Regular Expression value (ctor-string) +options ::= JavaScript Regular Expression option (ctor-options) var ::= [_a-zA-Z] [_a-zA-Z0-9]* int ::= [0-9]+ text ::= .* diff --git a/src/vs/editor/contrib/snippet/browser/snippetController2.ts b/src/vs/editor/contrib/snippet/browser/snippetController2.ts index 28966159525..8a3c149379b 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetController2.ts @@ -87,6 +87,7 @@ export class SnippetController2 { this._updateState(); this._snippetListener = [ + this._editor.onDidChangeModelContent(e => e.isFlush && this.cancel()), this._editor.onDidChangeModel(() => this.cancel()), this._editor.onDidChangeCursorSelection(() => this._updateState()) ]; diff --git a/src/vs/editor/contrib/snippet/browser/snippetParser.ts b/src/vs/editor/contrib/snippet/browser/snippetParser.ts index 6f5d1bfcf89..9eefd58fefe 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetParser.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetParser.ts @@ -19,6 +19,9 @@ export enum TokenType { Int, VariableName, Format, + Plus, + Dash, + QuestionMark, EOF } @@ -40,6 +43,9 @@ export class Scanner { [CharCode.Backslash]: TokenType.Backslash, [CharCode.Slash]: TokenType.Forwardslash, [CharCode.Pipe]: TokenType.Pipe, + [CharCode.Plus]: TokenType.Plus, + [CharCode.Dash]: TokenType.Dash, + [CharCode.QuestionMark]: TokenType.QuestionMark, }; static isDigitCharacter(ch: number): boolean { @@ -186,6 +192,11 @@ export abstract class Marker { } export class Text extends Marker { + + static escape(value: string): string { + return value.replace(/\$|}|\\/g, '\\$&'); + } + constructor(public value: string) { super(); } @@ -193,7 +204,7 @@ export class Text extends Marker { return this.value; } toTextmateString(): string { - return this.value.replace(/\$|}|\\/g, '\\$&'); + return Text.escape(this.value); } len(): number { return this.value.length; @@ -285,6 +296,94 @@ export class Choice extends Marker { } } +export class Transform extends Marker { + + regexp: RegExp; + + resolve(value: string): string { + const _this = this; + return value.replace(this.regexp, function () { + let ret = ''; + for (const marker of _this._children) { + if (marker instanceof FormatString) { + let value = arguments.length - 2 > marker.index ? arguments[marker.index] : ''; + value = marker.resolve(value); + ret += value; + } else { + ret += marker.toString(); + } + } + return ret; + }); + } + + toString(): string { + return ''; + } + + toTextmateString(): string { + return `/${Text.escape(this.regexp.source)}/${this.children.map(c => c.toTextmateString())}/${this.regexp.ignoreCase ? 'i' : ''}`; + } + + clone(): Transform { + let ret = new Transform(); + ret.regexp = new RegExp(this.regexp.source, this.regexp.ignoreCase ? 'i' : ''); + ret._children = this.children.map(child => child.clone()); + return ret; + } + +} + +export class FormatString extends Marker { + + constructor( + readonly index: number, + readonly shorthandName?: string, + readonly ifValue?: string, + readonly elseValue?: string, + ) { + super(); + } + + resolve(value: string): string { + if (this.shorthandName === 'upcase') { + return !value ? '' : value.toLocaleUpperCase(); + } else if (this.shorthandName === 'downcase') { + return !value ? '' : value.toLocaleLowerCase(); + } else if (this.shorthandName === 'capitalize') { + return !value ? '' : (value[0].toLocaleUpperCase() + value.substr(1)); + } else if (Boolean(value) && typeof this.ifValue === 'string') { + return this.ifValue; + } else if (!Boolean(value) && typeof this.elseValue === 'string') { + return this.elseValue; + } else { + return value || ''; + } + } + + toTextmateString(): string { + let value = '${'; + value += this.index; + if (this.shorthandName) { + value += `:/${this.shorthandName}`; + + } else if (this.ifValue && this.elseValue) { + value += `:?${this.ifValue}:${this.elseValue}`; + } else if (this.ifValue) { + value += `:+${this.ifValue}`; + } else if (this.elseValue) { + value += `:-${this.elseValue}`; + } + value += '}'; + return value; + } + + clone(): FormatString { + let ret = new FormatString(this.index, this.shorthandName, this.ifValue, this.elseValue); + return ret; + } +} + export class Variable extends Marker { constructor(public name: string) { @@ -292,7 +391,11 @@ export class Variable extends Marker { } resolve(resolver: VariableResolver): boolean { - const value = resolver.resolve(this); + let value = resolver.resolve(this); + let [firstChild] = this._children; + if (firstChild instanceof Transform && this._children.length === 1) { + value = firstChild.resolve(value || ''); + } if (value !== undefined) { this._children = [new Text(value)]; return true; @@ -514,6 +617,19 @@ export class SnippetParser { return false; } + private _until(type: TokenType): false | string { + if (this._token.type === TokenType.EOF) { + return false; + } + let start = this._token; + while (this._token.type !== type) { + this._token = this._scanner.next(); + } + let value = this._scanner.value.substring(start.pos, this._token.pos); + this._token = this._scanner.next(); + return value; + } + private _parse(marker: Marker): boolean { return this._parseEscaped(marker) || this._parseTabstopOrVariableName(marker) @@ -692,6 +808,16 @@ export class SnippetParser { return true; } + } else if (this._accept(TokenType.Forwardslash)) { + // ${foo///} + if (this._parseTransform(variable)) { + parent.appendChild(variable); + return true; + } + + this._backTo(token); + return false; + } else if (this._accept(TokenType.CurlyClose)) { // ${foo} parent.appendChild(variable); @@ -703,6 +829,151 @@ export class SnippetParser { } } + private _parseTransform(parent: Variable): boolean { + // ...//} + + let transform = new Transform(); + let regexValue = ''; + let regexOptions = ''; + + // (1) /regex + while (true) { + if (this._accept(TokenType.Forwardslash)) { + break; + } + + let escaped: string; + if (escaped = this._accept(TokenType.Backslash, true)) { + escaped = this._accept(TokenType.Forwardslash, true) || escaped; + regexValue += escaped; + continue; + } + + if (this._token.type !== TokenType.EOF) { + regexValue += this._accept(undefined, true); + continue; + } + return false; + } + + // (2) /format + while (true) { + if (this._accept(TokenType.Forwardslash)) { + break; + } + if (this._parseFormatString(transform) || this._parseAnything(transform)) { + continue; + } + return false; + } + + // (3) /option + while (true) { + if (this._accept(TokenType.CurlyClose)) { + break; + } + if (this._token.type !== TokenType.EOF) { + regexOptions += this._accept(undefined, true); + continue; + } + return false; + } + + try { + transform.regexp = new RegExp(regexValue, regexOptions); + } catch (e) { + // invalid regexp + return false; + } + + parent.appendChild(transform); + return true; + } + + private _parseFormatString(parent: Transform): boolean { + + const token = this._token; + if (!this._accept(TokenType.Dollar)) { + return false; + } + + let complex = false; + if (this._accept(TokenType.CurlyOpen)) { + complex = true; + } + + let index = this._accept(TokenType.Int, true); + + if (!index) { + this._backTo(token); + return false; + + } else if (!complex) { + // $1 + parent.appendChild(new FormatString(Number(index))); + return true; + + } else if (this._accept(TokenType.CurlyClose)) { + // ${1} + parent.appendChild(new FormatString(Number(index))); + return true; + + } else if (!this._accept(TokenType.Colon)) { + this._backTo(token); + return false; + } + + if (this._accept(TokenType.Forwardslash)) { + // ${1:/upcase} + let shorthand = this._accept(TokenType.VariableName, true); + if (!shorthand || !this._accept(TokenType.CurlyClose)) { + this._backTo(token); + return false; + } else { + parent.appendChild(new FormatString(Number(index), shorthand)); + return true; + } + + } else if (this._accept(TokenType.Plus)) { + // ${1:+} + let ifValue = this._until(TokenType.CurlyClose); + if (ifValue) { + parent.appendChild(new FormatString(Number(index), undefined, ifValue, undefined)); + return true; + } + + } else if (this._accept(TokenType.Dash)) { + // ${2:-} + let elseValue = this._until(TokenType.CurlyClose); + if (elseValue) { + parent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue)); + return true; + } + + } else if (this._accept(TokenType.QuestionMark)) { + // ${2:?:} + let ifValue = this._until(TokenType.Colon); + if (ifValue) { + let elseValue = this._until(TokenType.CurlyClose); + if (elseValue) { + parent.appendChild(new FormatString(Number(index), undefined, ifValue, elseValue)); + return true; + } + } + + } else { + // ${1:} + let elseValue = this._until(TokenType.CurlyClose); + if (elseValue) { + parent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue)); + return true; + } + } + + this._backTo(token); + return false; + } + private _parseAnything(marker: Marker): boolean { if (this._token.type !== TokenType.EOF) { marker.appendChild(new Text(this._scanner.tokenText(this._token))); diff --git a/src/vs/editor/contrib/snippet/browser/snippetSession.ts b/src/vs/editor/contrib/snippet/browser/snippetSession.ts index 14c222c980b..17f23e3016e 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetSession.ts @@ -229,16 +229,18 @@ export class SnippetSession { static adjustSelection(model: IModel, selection: Selection, overwriteBefore: number, overwriteAfter: number): Selection { if (overwriteBefore !== 0 || overwriteAfter !== 0) { - let { startLineNumber, startColumn, endLineNumber, endColumn } = selection; - startColumn -= overwriteBefore; - endColumn += overwriteAfter; + // overwrite[Before|After] is compute using the position, not the whole + // selection. therefore we adjust the selection around that position + const { positionLineNumber, positionColumn } = selection; + const positionColumnBefore = positionColumn - overwriteBefore; + const positionColumnAfter = positionColumn + overwriteAfter; - const range = model.validateRange(Range.plusRange(selection, { - startLineNumber, - startColumn, - endLineNumber, - endColumn, - })); + const range = model.validateRange({ + startLineNumber: positionLineNumber, + startColumn: positionColumnBefore, + endLineNumber: positionLineNumber, + endColumn: positionColumnAfter + }); selection = Selection.createWithDirection( range.startLineNumber, range.startColumn, diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts index fc12236bd33..cffb2fd232f 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.test.ts @@ -40,7 +40,7 @@ suite('SnippetController', () => { '\t', '}' ]; - }; + } withMockCodeEditor(lines, {}, (editor, cursor) => { editor.getModel().updateOptions({ diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetParser.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetParser.test.ts index 47f19d1de89..483002020f1 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetParser.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetParser.test.ts @@ -5,8 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import { Scanner, TokenType, SnippetParser, Text, Placeholder, Variable, Marker, TextmateSnippet, Choice } from 'vs/editor/contrib/snippet/browser/snippetParser'; - +import { Scanner, TokenType, SnippetParser, Text, Placeholder, Variable, Marker, TextmateSnippet, Choice, FormatString } from 'vs/editor/contrib/snippet/browser/snippetParser'; suite('SnippetParser', () => { @@ -51,7 +50,7 @@ suite('SnippetParser', () => { scanner.text('$foo-bar'); assert.equal(scanner.next().type, TokenType.Dollar); assert.equal(scanner.next().type, TokenType.VariableName); - assert.equal(scanner.next().type, TokenType.Format); + assert.equal(scanner.next().type, TokenType.Dash); assert.equal(scanner.next().type, TokenType.VariableName); assert.equal(scanner.next().type, TokenType.EOF); @@ -210,6 +209,41 @@ suite('SnippetParser', () => { assertTextAndMarker('${1:bar${2:foobar}', '${1:barfoobar', Text, Placeholder); }); + test('Parser, variable transforms', function () { + assertTextAndMarker('${foo///}', '', Variable); + assertTextAndMarker('${foo/regex/format/gmi}', '', Variable); + assertTextAndMarker('${foo/([A-Z][a-z])/format/}', '', Variable); + + // invalid regex + assertTextAndMarker('${foo/([A-Z][a-z])/format/GMI}', '${foo/([A-Z][a-z])/format/GMI}', Text); + assertTextAndMarker('${foo/([A-Z][a-z])/format/funky}', '${foo/([A-Z][a-z])/format/funky}', Text); + assertTextAndMarker('${foo/([A-Z][a-z]/format/}', '${foo/([A-Z][a-z]/format/}', Text); + + // tricky regex + assertTextAndMarker('${foo/m\\/atch/$1/i}', '', Variable); + assertMarker('${foo/regex\/format/options}', Text); + + // incomplete + assertTextAndMarker('${foo///', '${foo///', Text); + assertTextAndMarker('${foo/regex/format/options', '${foo/regex/format/options', Text); + + // format string + assertMarker('${foo/.*/${0:fooo}/i}', Variable); + assertMarker('${foo/.*/${1}/i}', Variable); + assertMarker('${foo/.*/$1/i}', Variable); + assertMarker('${foo/.*/This-$1-encloses/i}', Variable); + assertMarker('${foo/.*/complex${1:else}/i}', Variable); + assertMarker('${foo/.*/complex${1:-else}/i}', Variable); + assertMarker('${foo/.*/complex${1:+if}/i}', Variable); + assertMarker('${foo/.*/complex${1:?if:else}/i}', Variable); + assertMarker('${foo/.*/complex${1:/upcase}/i}', Variable); + + }); + + test('No way to escape forward slash in snippet regex #36715', function () { + assertMarker('${TM_DIRECTORY/src\\//$1/}', Variable); + }); + test('Parser, placeholder with choice', () => { assertTextAndMarker('${1|one,two,three|}', 'one', Placeholder); @@ -535,6 +569,32 @@ suite('SnippetParser', () => { assertTextAndMarker('${1|foo,bar|}', 'foo', Placeholder); }); + + test('Transform -> FormatString#resolve', function () { + + // shorthand functions + assert.equal(new FormatString(1, 'upcase').resolve('foo'), 'FOO'); + assert.equal(new FormatString(1, 'downcase').resolve('FOO'), 'foo'); + assert.equal(new FormatString(1, 'capitalize').resolve('bar'), 'Bar'); + assert.equal(new FormatString(1, 'capitalize').resolve('bar no repeat'), 'Bar no repeat'); + assert.equal(new FormatString(1, 'notKnown').resolve('input'), 'input'); + + // if + assert.equal(new FormatString(1, undefined, 'foo', undefined).resolve(undefined), ''); + assert.equal(new FormatString(1, undefined, 'foo', undefined).resolve(''), ''); + assert.equal(new FormatString(1, undefined, 'foo', undefined).resolve('bar'), 'foo'); + + // else + assert.equal(new FormatString(1, undefined, undefined, 'foo').resolve(undefined), 'foo'); + assert.equal(new FormatString(1, undefined, undefined, 'foo').resolve(''), 'foo'); + assert.equal(new FormatString(1, undefined, undefined, 'foo').resolve('bar'), 'bar'); + + // if-else + assert.equal(new FormatString(1, undefined, 'bar', 'foo').resolve(undefined), 'foo'); + assert.equal(new FormatString(1, undefined, 'bar', 'foo').resolve(''), 'foo'); + assert.equal(new FormatString(1, undefined, 'bar', 'foo').resolve('baz'), 'bar'); + }); + test('[BUG] HTML attribute suggestions: Snippet session does not have end-position set, #33147', function () { const { placeholders } = new SnippetParser().parse('src="$1"', true); @@ -543,5 +603,6 @@ suite('SnippetParser', () => { assert.equal(placeholders.length, 2); assert.equal(first.index, 1); assert.equal(second.index, 0); + }); }); diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts index 26e401d6f6f..05d96ea0b30 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts @@ -234,9 +234,9 @@ suite('SnippetSession', function () { assertSelections(editor, new Selection(1, 10, 1, 10), new Selection(2, 14, 2, 14)); session.prev(); - assertSelections(editor, new Selection(1, 7, 1, 7), new Selection(2, 11, 2, 11)); + assertSelections(editor, new Selection(1, 7, 1, 10), new Selection(2, 11, 2, 14)); session.prev(); - assertSelections(editor, new Selection(1, 4, 1, 4), new Selection(2, 8, 2, 8)); + assertSelections(editor, new Selection(1, 4, 1, 7), new Selection(2, 8, 2, 11)); session.prev(); assertSelections(editor, new Selection(1, 1, 1, 4), new Selection(2, 5, 2, 8)); }); @@ -510,5 +510,20 @@ suite('SnippetSession', function () { assert.equal(editor.getModel().getValue(), expected); }); + + test('Selecting text from left to right, and choosing item messes up code, #31199', function () { + const model = editor.getModel(); + model.setValue('console.log'); + + let actual = SnippetSession.adjustSelection(model, new Selection(1, 12, 1, 9), 3, 0); + assert.ok(actual.equalsSelection(new Selection(1, 9, 1, 6))); + + actual = SnippetSession.adjustSelection(model, new Selection(1, 9, 1, 12), 3, 0); + assert.ok(actual.equalsSelection(new Selection(1, 9, 1, 12))); + + editor.setSelections([new Selection(1, 9, 1, 12)]); + new SnippetSession(editor, 'far', 3, 0).insert(); + assert.equal(model.getValue(), 'console.far'); + }); }); diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts index 79db655bddc..44259233ef8 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts @@ -135,4 +135,77 @@ suite('Snippet Variables Resolver', function () { ); assertVariableResolve(resolver, 'TM_FILENAME_BASE', 'foo'); }); + + + function assertVariableResolve2(input: string, expected: string, varValue?: string) { + const snippet = new SnippetParser().parse(input) + .resolveVariables({ resolve(variable) { return varValue || variable.name; } }); + + const actual = snippet.toString(); + assert.equal(actual, expected); + } + + test('Variable Snippet Transform', function () { + + const snippet = new SnippetParser().parse('name=${TM_FILENAME/(.*)\\..+$/$1/}', true); + snippet.resolveVariables(resolver); + assert.equal(snippet.toString(), 'name=text'); + + assertVariableResolve2('${ThisIsAVar/([A-Z]).*(Var)/$2/}', 'Var'); + assertVariableResolve2('${ThisIsAVar/([A-Z]).*(Var)/$2-${1:/downcase}/}', 'Var-t'); + assertVariableResolve2('${Foo/(.*)/${1:+Bar}/img}', 'Bar'); + + //https://github.com/Microsoft/vscode/issues/33162 + assertVariableResolve2('export default class ${TM_FILENAME/(\\w+)\\.js/$1/g}', 'export default class FooFile', 'FooFile.js'); + + assertVariableResolve2('${foobarfoobar/(foo)/${1:+FAR}/g}', 'FARbarFARbar'); // global + assertVariableResolve2('${foobarfoobar/(foo)/${1:+FAR}/}', 'FARbarfoobar'); // first match + assertVariableResolve2('${foobarfoobar/(bazz)/${1:+FAR}/g}', 'foobarfoobar'); // no match + + assertVariableResolve2('${foobarfoobar/(foo)/${2:+FAR}/g}', 'barbar'); // bad group reference + }); + + test('Snippet transforms do not handle regex with alternatives or optional matches, #36089', function () { + + assertVariableResolve2( + '${TM_FILENAME/^(.)|(?:-(.))|(\\.js)/${1:/upcase}${2:/upcase}/g}', + 'MyClass', + 'my-class.js' + ); + + // no hyphens + assertVariableResolve2( + '${TM_FILENAME/^(.)|(?:-(.))|(\\.js)/${1:/upcase}${2:/upcase}/g}', + 'Myclass', + 'myclass.js' + ); + + // none matching suffix + assertVariableResolve2( + '${TM_FILENAME/^(.)|(?:-(.))|(\\.js)/${1:/upcase}${2:/upcase}/g}', + 'Myclass.foo', + 'myclass.foo' + ); + + // more than one hyphen + assertVariableResolve2( + '${TM_FILENAME/^(.)|(?:-(.))|(\\.js)/${1:/upcase}${2:/upcase}/g}', + 'ThisIsAFile', + 'this-is-a-file.js' + ); + + // KEBAB CASE + assertVariableResolve2( + '${TM_FILENAME_BASE/([A-Z][a-z]+)([A-Z][a-z]+$)?/${1:/downcase}-${2:/downcase}/g}', + 'capital-case', + 'CapitalCase' + ); + + assertVariableResolve2( + '${TM_FILENAME_BASE/([A-Z][a-z]+)([A-Z][a-z]+$)?/${1:/downcase}-${2:/downcase}/g}', + 'capital-case-more', + 'CapitalCaseMore' + ); + }); + }); diff --git a/src/vs/editor/contrib/suggest/browser/completionModel.ts b/src/vs/editor/contrib/suggest/browser/completionModel.ts index 374d7b44626..45ca3b876a9 100644 --- a/src/vs/editor/contrib/suggest/browser/completionModel.ts +++ b/src/vs/editor/contrib/suggest/browser/completionModel.ts @@ -6,8 +6,9 @@ 'use strict'; import { fuzzyScore } from 'vs/base/common/filters'; -import { ISuggestSupport } from 'vs/editor/common/modes'; +import { ISuggestSupport, ISuggestResult } from 'vs/editor/common/modes'; import { ISuggestionItem, SnippetConfig } from './suggest'; +import { isDisposable } from 'vs/base/common/lifecycle'; export interface ICompletionItem extends ISuggestionItem { matches?: number[]; @@ -15,6 +16,15 @@ export interface ICompletionItem extends ISuggestionItem { idx?: number; } + +/* __GDPR__FRAGMENT__ + "ICompletionStats" : { + "suggestionCount" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "snippetCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "textCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ +// __GDPR__TODO__: This is a dynamically extensible structure which can not be declared statically. export interface ICompletionStats { suggestionCount: number; snippetCount: number; @@ -50,6 +60,18 @@ export class CompletionModel { } } + dispose(): void { + const seen = new Set(); + for (const { container } of this._items) { + if (!seen.has(container)) { + seen.add(container); + if (isDisposable(container)) { + container.dispose(); + } + } + } + } + get lineContext(): LineContext { return this._lineContext; } diff --git a/src/vs/editor/contrib/suggest/browser/media/suggest.css b/src/vs/editor/contrib/suggest/browser/media/suggest.css index 1dc662e65d5..f51c70d511a 100644 --- a/src/vs/editor/contrib/suggest/browser/media/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/media/suggest.css @@ -213,7 +213,6 @@ box-sizing: border-box; height: 100%; width: 100%; - white-space: pre-wrap; } .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .type { @@ -229,12 +228,26 @@ .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .docs { margin: 0; padding: 4px 5px; + white-space: pre-wrap; +} + +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .docs.markdown-docs { + white-space: initial; +} + +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .docs .code { + white-space: pre-wrap; + word-wrap: break-word; } .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > p:empty { display: none; } +.monaco-editor .suggest-widget .details code { + border-radius: 3px; + padding: 0 0.4em; +} /* High Contrast and Dark Theming */ diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index 3831064a10c..aea81522ddd 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -12,7 +12,7 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IModel, IEditorContribution, ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; -import { ISuggestResult, ISuggestSupport, ISuggestion, SuggestRegistry } from 'vs/editor/common/modes'; +import { ISuggestResult, ISuggestSupport, ISuggestion, SuggestRegistry, SuggestContext, SuggestTriggerKind } from 'vs/editor/common/modes'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -42,7 +42,7 @@ export function setSnippetSuggestSupport(support: ISuggestSupport): ISuggestSupp return old; } -export function provideSuggestionItems(model: IModel, position: Position, snippetConfig: SnippetConfig = 'bottom', onlyFrom?: ISuggestSupport[]): TPromise { +export function provideSuggestionItems(model: IModel, position: Position, snippetConfig: SnippetConfig = 'bottom', onlyFrom?: ISuggestSupport[], context?: SuggestContext): TPromise { const allSuggestions: ISuggestionItem[] = []; const acceptSuggestion = createSuggesionFilter(snippetConfig); @@ -57,6 +57,8 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe supports.unshift([_snippetSuggestSupport]); } + const suggestConext = context || { triggerKind: SuggestTriggerKind.Invoke }; + // add suggestions from contributed providers - providers are ordered in groups of // equal score and once a group produces a result the process stops let hasResult = false; @@ -73,7 +75,7 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe return undefined; } - return asWinJsPromise(token => support.provideCompletionItems(model, position, token)).then(container => { + return asWinJsPromise(token => support.provideCompletionItems(model, position, suggestConext, token)).then(container => { const len = allSuggestions.length; diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index ea769144c92..bfb3d1ba742 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -104,10 +104,7 @@ export class SuggestController implements IEditorContribution { let acceptSuggestionsOnEnter = SuggestContext.AcceptSuggestionsOnEnter.bindTo(_contextKeyService); let updateFromConfig = () => { const { acceptSuggestionOnEnter } = this._editor.getConfiguration().contribInfo; - acceptSuggestionsOnEnter.set( - acceptSuggestionOnEnter === 'on' || acceptSuggestionOnEnter === 'smart' - || (acceptSuggestionOnEnter) === true - ); + acceptSuggestionsOnEnter.set(acceptSuggestionOnEnter === 'on' || acceptSuggestionOnEnter === 'smart'); }; this._toDispose.push(this._editor.onDidChangeConfiguration((e) => updateFromConfig())); updateFromConfig(); @@ -173,37 +170,55 @@ export class SuggestController implements IEditorContribution { } private _onDidSelectItem(item: ICompletionItem): void { - if (item) { - const { suggestion, position } = item; - const columnDelta = this._editor.getPosition().column - position.column; - - if (Array.isArray(suggestion.additionalTextEdits)) { - this._editor.pushUndoStop(); - this._editor.executeEdits('suggestController.additionalTextEdits', suggestion.additionalTextEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text))); - this._editor.pushUndoStop(); - } - - let { insertText } = suggestion; - if (suggestion.snippetType !== 'textmate') { - insertText = SnippetParser.escape(insertText); - } - - SnippetController2.get(this._editor).insert( - insertText, - suggestion.overwriteBefore + columnDelta, - suggestion.overwriteAfter - ); - - - if (suggestion.command) { - this._commandService.executeCommand(suggestion.command.id, ...suggestion.command.arguments).done(undefined, onUnexpectedError); - } - - this._alertCompletionItem(item); - this._telemetryService.publicLog('suggestSnippetInsert', { ...this._editor.getTelemetryData(), suggestionType: suggestion.type }); + if (!item) { + this._model.cancel(); + return; } - this._model.cancel(); + const { suggestion, position } = item; + const columnDelta = this._editor.getPosition().column - position.column; + + if (Array.isArray(suggestion.additionalTextEdits)) { + this._editor.pushUndoStop(); + this._editor.executeEdits('suggestController.additionalTextEdits', suggestion.additionalTextEdits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text))); + this._editor.pushUndoStop(); + } + + let { insertText } = suggestion; + if (suggestion.snippetType !== 'textmate') { + insertText = SnippetParser.escape(insertText); + } + + SnippetController2.get(this._editor).insert( + insertText, + suggestion.overwriteBefore + columnDelta, + suggestion.overwriteAfter + ); + + if (!suggestion.command) { + // done + this._model.cancel(); + + } else if (suggestion.command.id === TriggerSuggestAction.id) { + // retigger + this._model.trigger({ auto: this._model.state === State.Auto }, true); + + } else { + // exec command, done + this._commandService.executeCommand(suggestion.command.id, ...suggestion.command.arguments).done(undefined, onUnexpectedError); + this._model.cancel(); + } + + this._alertCompletionItem(item); + /* __GDPR__ + "suggestSnippetInsert" : { + "suggestionType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "${include}": [ + "${EditorTelemetryData}" + ] + } + */ + this._telemetryService.publicLog('suggestSnippetInsert', { ...this._editor.getTelemetryData(), suggestionType: suggestion.type }); } private _alertCompletionItem({ suggestion }: ICompletionItem): void { @@ -212,7 +227,7 @@ export class SuggestController implements IEditorContribution { } triggerSuggest(onlyFrom?: ISuggestSupport[]): void { - this._model.trigger(false, false, onlyFrom); + this._model.trigger({ auto: false }, false, onlyFrom); this._editor.revealLine(this._editor.getPosition().lineNumber, ScrollType.Smooth); this._editor.focus(); } @@ -283,9 +298,11 @@ export class SuggestController implements IEditorContribution { @editorAction export class TriggerSuggestAction extends EditorAction { + static readonly id = 'editor.action.triggerSuggest'; + constructor() { super({ - id: 'editor.action.triggerSuggest', + id: TriggerSuggestAction.id, label: nls.localize('suggest.trigger.label', "Trigger Suggest"), alias: 'Trigger Suggest', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCompletionItemProvider), diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index fd4a068db38..5dbb40de524 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -11,7 +11,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { ICommonCodeEditor, IModel, IWordAtPosition } from 'vs/editor/common/editorCommon'; -import { ISuggestSupport, SuggestRegistry, StandardTokenType } from 'vs/editor/common/modes'; +import { ISuggestSupport, SuggestRegistry, StandardTokenType, SuggestTriggerKind } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import { provideSuggestionItems, getSuggestionComparator, ISuggestionItem } from './suggest'; import { CompletionModel } from './completionModel'; @@ -31,6 +31,11 @@ export interface ISuggestEvent { auto: boolean; } +export interface SuggestTriggerContext { + auto: boolean; + triggerCharacter?: string; +} + export class LineContext { static shouldAutoTrigger(editor: ICommonCodeEditor): boolean { @@ -88,90 +93,94 @@ export const enum State { export class SuggestModel implements IDisposable { - private toDispose: IDisposable[] = []; - private quickSuggestDelay: number; - private triggerCharacterListener: IDisposable; - private triggerAutoSuggestPromise: TPromise; - private triggerRefilter = new TimeoutTimer(); + private _editor: ICommonCodeEditor; + private _toDispose: IDisposable[] = []; + private _quickSuggestDelay: number; + private _triggerCharacterListener: IDisposable; + private _triggerAutoSuggestPromise: TPromise; + private _triggerRefilter = new TimeoutTimer(); private _state: State; - private requestPromise: TPromise; - private context: LineContext; - private currentPosition: Position; - - private completionModel: CompletionModel; + private _requestPromise: TPromise; + private _context: LineContext; + private _currentPosition: Position; + private _completionModel: CompletionModel; private _onDidCancel: Emitter = new Emitter(); - get onDidCancel(): Event { return this._onDidCancel.event; } - private _onDidTrigger: Emitter = new Emitter(); - get onDidTrigger(): Event { return this._onDidTrigger.event; } - private _onDidSuggest: Emitter = new Emitter(); - get onDidSuggest(): Event { return this._onDidSuggest.event; } - constructor(private editor: ICommonCodeEditor) { + readonly onDidCancel: Event = this._onDidCancel.event; + readonly onDidTrigger: Event = this._onDidTrigger.event; + readonly onDidSuggest: Event = this._onDidSuggest.event; + + constructor(editor: ICommonCodeEditor) { + this._editor = editor; this._state = State.Idle; - this.triggerAutoSuggestPromise = null; - this.requestPromise = null; - this.completionModel = null; - this.context = null; - this.currentPosition = editor.getPosition() || new Position(1, 1); + this._triggerAutoSuggestPromise = null; + this._requestPromise = null; + this._completionModel = null; + this._context = null; + this._currentPosition = this._editor.getPosition() || new Position(1, 1); // wire up various listeners - this.toDispose.push(this.editor.onDidChangeModel(() => { - this.updateTriggerCharacters(); + this._toDispose.push(this._editor.onDidChangeModel(() => { + this._updateTriggerCharacters(); this.cancel(); })); - this.toDispose.push(editor.onDidChangeModelLanguage(() => { - this.updateTriggerCharacters(); + this._toDispose.push(this._editor.onDidChangeModelLanguage(() => { + this._updateTriggerCharacters(); this.cancel(); })); - this.toDispose.push(this.editor.onDidChangeConfiguration(() => { - this.updateTriggerCharacters(); - this.updateQuickSuggest(); + this._toDispose.push(this._editor.onDidChangeConfiguration(() => { + this._updateTriggerCharacters(); + this._updateQuickSuggest(); })); - this.toDispose.push(SuggestRegistry.onDidChange(() => { - this.updateTriggerCharacters(); - this.updateActiveSuggestSession(); + this._toDispose.push(SuggestRegistry.onDidChange(() => { + this._updateTriggerCharacters(); + this._updateActiveSuggestSession(); })); - this.toDispose.push(this.editor.onDidChangeCursorSelection(e => { - this.onCursorChange(e); + this._toDispose.push(this._editor.onDidChangeCursorSelection(e => { + this._onCursorChange(e); + })); + this._toDispose.push(this._editor.onDidChangeModelContent(e => { + this._refilterCompletionItems(); })); - this.updateTriggerCharacters(); - this.updateQuickSuggest(); + this._updateTriggerCharacters(); + this._updateQuickSuggest(); } dispose(): void { - dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this.triggerCharacterListener, this.triggerRefilter]); - this.toDispose = dispose(this.toDispose); + dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this._triggerCharacterListener, this._triggerRefilter]); + this._toDispose = dispose(this._toDispose); + dispose(this._completionModel); this.cancel(); } // --- handle configuration & precondition changes - private updateQuickSuggest(): void { - this.quickSuggestDelay = this.editor.getConfiguration().contribInfo.quickSuggestionsDelay; + private _updateQuickSuggest(): void { + this._quickSuggestDelay = this._editor.getConfiguration().contribInfo.quickSuggestionsDelay; - if (isNaN(this.quickSuggestDelay) || (!this.quickSuggestDelay && this.quickSuggestDelay !== 0) || this.quickSuggestDelay < 0) { - this.quickSuggestDelay = 10; + if (isNaN(this._quickSuggestDelay) || (!this._quickSuggestDelay && this._quickSuggestDelay !== 0) || this._quickSuggestDelay < 0) { + this._quickSuggestDelay = 10; } } - private updateTriggerCharacters(): void { + private _updateTriggerCharacters(): void { - dispose(this.triggerCharacterListener); + dispose(this._triggerCharacterListener); - if (this.editor.getConfiguration().readOnly - || !this.editor.getModel() - || !this.editor.getConfiguration().contribInfo.suggestOnTriggerCharacters) { + if (this._editor.getConfiguration().readOnly + || !this._editor.getModel() + || !this._editor.getConfiguration().contribInfo.suggestOnTriggerCharacters) { return; } const supportsByTriggerCharacter: { [ch: string]: ISuggestSupport[] } = Object.create(null); - for (const support of SuggestRegistry.all(this.editor.getModel())) { + for (const support of SuggestRegistry.all(this._editor.getModel())) { if (isFalsyOrEmpty(support.triggerCharacters)) { continue; } @@ -185,7 +194,7 @@ export class SuggestModel implements IDisposable { } } - this.triggerCharacterListener = this.editor.onDidType(text => { + this._triggerCharacterListener = this._editor.onDidType(text => { const lastChar = text.charAt(text.length - 1); const supports = supportsByTriggerCharacter[lastChar]; @@ -193,14 +202,14 @@ export class SuggestModel implements IDisposable { // keep existing items that where not computed by the // supports/providers that want to trigger now const items: ISuggestionItem[] = []; - if (this.completionModel) { - for (const item of this.completionModel.items) { + if (this._completionModel) { + for (const item of this._completionModel.items) { if (supports.indexOf(item.support) < 0) { items.push(item); } } } - this.trigger(true, Boolean(this.completionModel), supports, items); + this.trigger({ auto: true, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, items); } }); } @@ -213,41 +222,43 @@ export class SuggestModel implements IDisposable { cancel(retrigger: boolean = false): void { - if (this.triggerAutoSuggestPromise) { - this.triggerAutoSuggestPromise.cancel(); - this.triggerAutoSuggestPromise = null; + if (this._triggerAutoSuggestPromise) { + this._triggerAutoSuggestPromise.cancel(); + this._triggerAutoSuggestPromise = null; } - if (this.requestPromise) { - this.requestPromise.cancel(); - this.requestPromise = null; + if (this._requestPromise) { + this._requestPromise.cancel(); + this._requestPromise = null; } this._state = State.Idle; - this.completionModel = null; - this.context = null; + dispose(this._completionModel); + this._completionModel = null; + this._context = null; this._onDidCancel.fire({ retrigger }); } - private updateActiveSuggestSession(): void { + private _updateActiveSuggestSession(): void { if (this._state !== State.Idle) { - if (!SuggestRegistry.has(this.editor.getModel())) { + if (!SuggestRegistry.has(this._editor.getModel())) { this.cancel(); } else { - this.trigger(this._state === State.Auto, true); + this.trigger({ auto: this._state === State.Auto }, true); } } } - private onCursorChange(e: ICursorSelectionChangedEvent): void { + private _onCursorChange(e: ICursorSelectionChangedEvent): void { - const prevPosition = this.currentPosition; - this.currentPosition = this.editor.getPosition(); + const prevPosition = this._currentPosition; + this._currentPosition = this._editor.getPosition(); if (!e.selection.isEmpty() || e.source !== 'keyboard' - || e.reason !== CursorChangeReason.NotSet) { + || e.reason !== CursorChangeReason.NotSet + ) { if (this._state === State.Idle) { // Early exit if nothing needs to be done! @@ -259,11 +270,11 @@ export class SuggestModel implements IDisposable { return; } - if (!SuggestRegistry.has(this.editor.getModel())) { + if (!SuggestRegistry.has(this._editor.getModel())) { return; } - const model = this.editor.getModel(); + const model = this._editor.getModel(); if (!model) { return; } @@ -272,33 +283,33 @@ export class SuggestModel implements IDisposable { // trigger 24x7 IntelliSense when idle, enabled, when cursor // moved RIGHT, and when at a good position - if (this.editor.getConfiguration().contribInfo.quickSuggestions !== false - && prevPosition.isBefore(this.currentPosition) + if (this._editor.getConfiguration().contribInfo.quickSuggestions !== false + && prevPosition.isBefore(this._currentPosition) ) { this.cancel(); - if (LineContext.shouldAutoTrigger(this.editor)) { - this.triggerAutoSuggestPromise = TPromise.timeout(this.quickSuggestDelay); - this.triggerAutoSuggestPromise.then(() => { - const model = this.editor.getModel(); - const pos = this.editor.getPosition(); + if (LineContext.shouldAutoTrigger(this._editor)) { + this._triggerAutoSuggestPromise = TPromise.timeout(this._quickSuggestDelay); + this._triggerAutoSuggestPromise.then(() => { + const model = this._editor.getModel(); + const pos = this._editor.getPosition(); if (!model) { return; } // validate enabled now - const { quickSuggestions } = this.editor.getConfiguration().contribInfo; + const { quickSuggestions } = this._editor.getConfiguration().contribInfo; if (quickSuggestions === false) { return; } else if (quickSuggestions === true) { // all good } else { + // Check the type of the token that triggered this model.tokenizeIfCheap(pos.lineNumber); const { tokenType } = model .getLineTokens(pos.lineNumber) - .findTokenAtOffset(pos.column - 1); - + .findTokenAtOffset(Math.max(pos.column - 1 - 1, 0)); const inValidScope = quickSuggestions.other && tokenType === StandardTokenType.Other || quickSuggestions.comments && tokenType === StandardTokenType.Comment || quickSuggestions.strings && tokenType === StandardTokenType.String; @@ -308,33 +319,40 @@ export class SuggestModel implements IDisposable { } } - this.triggerAutoSuggestPromise = null; - this.trigger(true); + this._triggerAutoSuggestPromise = null; + this.trigger({ auto: true }); }); } } + } + } - } else { + private _refilterCompletionItems(): void { + if (this._state === State.Idle) { + return; + } + const model = this._editor.getModel(); + if (model) { // refine active suggestion - this.triggerRefilter.cancelAndSet(() => { - const position = this.editor.getPosition(); + this._triggerRefilter.cancelAndSet(() => { + const position = this._editor.getPosition(); const ctx = new LineContext(model, position, this._state === State.Auto); - this.onNewContext(ctx); + this._onNewContext(ctx); }, 25); } } - public trigger(auto: boolean, retrigger: boolean = false, onlyFrom?: ISuggestSupport[], existingItems?: ISuggestionItem[]): void { + trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: ISuggestSupport[], existingItems?: ISuggestionItem[]): void { - const model = this.editor.getModel(); + const model = this._editor.getModel(); if (!model) { return; } + const auto = context.auto; + const ctx = new LineContext(model, this._editor.getPosition(), auto); - const ctx = new LineContext(model, this.editor.getPosition(), auto); - - if (!LineContext.isInEditableRange(this.editor)) { + if (!LineContext.isInEditableRange(this._editor)) { return; } @@ -344,92 +362,97 @@ export class SuggestModel implements IDisposable { this._onDidTrigger.fire({ auto }); // Capture context when request was sent - this.context = ctx; + this._context = ctx; - this.requestPromise = provideSuggestionItems(model, this.editor.getPosition(), - this.editor.getConfiguration().contribInfo.snippetSuggestions, - onlyFrom + this._requestPromise = provideSuggestionItems(model, this._editor.getPosition(), + this._editor.getConfiguration().contribInfo.snippetSuggestions, + onlyFrom, + { + triggerCharacter: context.triggerCharacter, + triggerKind: context.triggerCharacter ? SuggestTriggerKind.TriggerCharacter : SuggestTriggerKind.Invoke + } ).then(items => { - this.requestPromise = null; + this._requestPromise = null; if (this._state === State.Idle) { return; } - const model = this.editor.getModel(); + const model = this._editor.getModel(); if (!model) { return; } if (!isFalsyOrEmpty(existingItems)) { - const cmpFn = getSuggestionComparator(this.editor.getConfiguration().contribInfo.snippetSuggestions); + const cmpFn = getSuggestionComparator(this._editor.getConfiguration().contribInfo.snippetSuggestions); items = items.concat(existingItems).sort(cmpFn); } - const ctx = new LineContext(model, this.editor.getPosition(), auto); - this.completionModel = new CompletionModel(items, this.context.column, { + const ctx = new LineContext(model, this._editor.getPosition(), auto); + dispose(this._completionModel); + this._completionModel = new CompletionModel(items, this._context.column, { leadingLineContent: ctx.leadingLineContent, - characterCountDelta: this.context ? ctx.column - this.context.column : 0 - }, this.editor.getConfiguration().contribInfo.snippetSuggestions); - this.onNewContext(ctx); + characterCountDelta: this._context ? ctx.column - this._context.column : 0 + }, this._editor.getConfiguration().contribInfo.snippetSuggestions); + this._onNewContext(ctx); }).then(null, onUnexpectedError); } - private onNewContext(ctx: LineContext): void { + private _onNewContext(ctx: LineContext): void { - if (!this.context) { + if (!this._context) { // happens when 24x7 IntelliSense is enabled and still in its delay return; } - if (ctx.lineNumber !== this.context.lineNumber) { + if (ctx.lineNumber !== this._context.lineNumber) { // e.g. happens when pressing Enter while IntelliSense is computed this.cancel(); return; } - if (ctx.column < this.context.column) { + if (ctx.column < this._context.column) { // typed -> moved cursor LEFT -> retrigger if still on a word if (ctx.leadingWord.word) { - this.trigger(this.context.auto, true); + this.trigger({ auto: this._context.auto }, true); } else { this.cancel(); } return; } - if (!this.completionModel) { + if (!this._completionModel) { // happens when IntelliSense is not yet computed return; } - if (ctx.column > this.context.column && this.completionModel.incomplete && ctx.leadingWord.word.length !== 0) { + if (ctx.column > this._context.column && this._completionModel.incomplete && ctx.leadingWord.word.length !== 0) { // typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger - const { complete, incomplete } = this.completionModel.resolveIncompleteInfo(); - this.trigger(this._state === State.Auto, true, incomplete, complete); + const { complete, incomplete } = this._completionModel.resolveIncompleteInfo(); + this.trigger({ auto: this._state === State.Auto }, true, incomplete, complete); } else { // typed -> moved cursor RIGHT -> update UI - let oldLineContext = this.completionModel.lineContext; + let oldLineContext = this._completionModel.lineContext; let isFrozen = false; - this.completionModel.lineContext = { + this._completionModel.lineContext = { leadingLineContent: ctx.leadingLineContent, - characterCountDelta: ctx.column - this.context.column + characterCountDelta: ctx.column - this._context.column }; - if (this.completionModel.items.length === 0) { + if (this._completionModel.items.length === 0) { - if (LineContext.shouldAutoTrigger(this.editor) && this.context.leadingWord.endColumn < ctx.leadingWord.startColumn) { + if (LineContext.shouldAutoTrigger(this._editor) && this._context.leadingWord.endColumn < ctx.leadingWord.startColumn) { // retrigger when heading into a new word - this.trigger(this.context.auto, true); + this.trigger({ auto: this._context.auto }, true); return; } - if (!this.context.auto) { + if (!this._context.auto) { // freeze when IntelliSense was manually requested - this.completionModel.lineContext = oldLineContext; - isFrozen = this.completionModel.items.length > 0; + this._completionModel.lineContext = oldLineContext; + isFrozen = this._completionModel.items.length > 0; if (isFrozen && ctx.leadingWord.word.length === 0) { // there were results before but now there aren't @@ -446,8 +469,8 @@ export class SuggestModel implements IDisposable { } this._onDidSuggest.fire({ - completionModel: this.completionModel, - auto: this.context.auto, + completionModel: this._completionModel, + auto: this._context.auto, isFrozen, }); } diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 231c88d023b..aa88e693c8c 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -28,10 +28,13 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { attachListStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { registerColor, editorWidgetBackground, listFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, editorWidgetBackground, listFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { MarkdownRenderer } from 'vs/editor/contrib/markdown/browser/markdownRenderer'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; -const sticky = false; // for development purposes +const sticky = true; // for development purposes const expandSuggestionDocsByDefault = false; const maxSuggestionsToShow = 12; @@ -142,7 +145,7 @@ class Renderer implements IRenderer { data.colorspan.style.backgroundColor = ''; if (suggestion.type === 'color') { - let color = matchesColor(suggestion.label) || matchesColor(suggestion.documentation); + let color = matchesColor(suggestion.label) || typeof suggestion.documentation === 'string' && matchesColor(suggestion.documentation); if (color) { data.icon.className = 'icon customcolor'; data.colorspan.style.backgroundColor = color; @@ -203,6 +206,7 @@ class SuggestionDetails { container: HTMLElement, private widget: SuggestWidget, private editor: ICodeEditor, + private markdownRenderer: MarkdownRenderer, private triggerKeybindingLabel: string ) { this.disposables = []; @@ -218,7 +222,7 @@ class SuggestionDetails { this.header = append(this.body, $('.header')); this.close = append(this.header, $('span.close')); - this.close.title = nls.localize('readLess', "Read less...{0}", triggerKeybindingLabel); + this.close.title = nls.localize('readLess', "Read less...{0}", this.triggerKeybindingLabel); this.type = append(this.header, $('p.type')); this.docs = append(this.body, $('p.docs')); @@ -244,7 +248,14 @@ class SuggestionDetails { return; } removeClass(this.el, 'no-docs'); - this.docs.textContent = item.suggestion.documentation; + if (typeof item.suggestion.documentation === 'string') { + removeClass(this.docs, 'markdown-docs'); + this.docs.textContent = item.suggestion.documentation; + } else { + addClass(this.docs, 'markdown-docs'); + this.docs.innerHTML = ''; + this.docs.appendChild(this.markdownRenderer.render(item.suggestion.documentation)); + } if (item.suggestion.detail) { this.type.innerText = item.suggestion.detail; @@ -382,10 +393,13 @@ export class SuggestWidget implements IContentWidget, IDelegate @IContextKeyService contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @IStorageService storageService: IStorageService, - @IKeybindingService keybindingService: IKeybindingService + @IKeybindingService keybindingService: IKeybindingService, + @IModeService modeService: IModeService, + @IOpenerService openerService: IOpenerService ) { const kb = keybindingService.lookupKeybinding('editor.action.triggerSuggest'); const triggerKeybindingLabel = !kb ? '' : ` (${kb.getLabel()})`; + const markdownRenderer = new MarkdownRenderer(editor, modeService, openerService); this.isAuto = false; this.focusedItem = null; @@ -405,13 +419,14 @@ export class SuggestWidget implements IContentWidget, IDelegate this.messageElement = append(this.element, $('.message')); this.listElement = append(this.element, $('.tree')); - this.details = new SuggestionDetails(this.element, this, this.editor, triggerKeybindingLabel); + this.details = new SuggestionDetails(this.element, this, this.editor, markdownRenderer, triggerKeybindingLabel); let renderer = new Renderer(this, this.editor, triggerKeybindingLabel); this.list = new List(this.listElement, this, [renderer], { useShadows: false, - selectOnMouseDown: true + selectOnMouseDown: true, + focusOnMouseDown: false }); this.toDispose = [ @@ -715,6 +730,15 @@ export class SuggestWidget implements IContentWidget, IDelegate } else { const { stats } = this.completionModel; stats['wasAutomaticallyTriggered'] = !!isAuto; + /* __GDPR__ + "suggestWidget" : { + "wasAutomaticallyTriggered" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "${include}": [ + "${ICompletionStats}", + "${EditorTelemetryData}" + ] + } + */ this.telemetryService.publicLog('suggestWidget', { ...stats, ...this.editor.getTelemetryData() }); this.focusedItem = null; @@ -842,6 +866,13 @@ export class SuggestWidget implements IContentWidget, IDelegate this.details.element.style.borderColor = this.detailsFocusBorderColor; } } + /* __GDPR__ + "suggestWidget:toggleDetailsFocus" : { + "${include}": [ + "${EditorTelemetryData}" + ] + } + */ this.telemetryService.publicLog('suggestWidget:toggleDetailsFocus', this.editor.getTelemetryData()); } @@ -856,6 +887,13 @@ export class SuggestWidget implements IContentWidget, IDelegate removeClass(this.element, 'docs-side'); removeClass(this.element, 'docs-below'); this.editor.layoutContentWidget(this); + /* __GDPR__ + "suggestWidget:collapseDetails" : { + "${include}": [ + "${EditorTelemetryData}" + ] + } + */ this.telemetryService.publicLog('suggestWidget:collapseDetails', this.editor.getTelemetryData()); } else { if (this.state !== State.Open && this.state !== State.Details) { @@ -864,6 +902,13 @@ export class SuggestWidget implements IContentWidget, IDelegate this.updateExpandDocsSetting(true); this.showDetails(); + /* __GDPR__ + "suggestWidget:expandDetails" : { + "${include}": [ + "${EditorTelemetryData}" + ] + } + */ this.telemetryService.publicLog('suggestWidget:expandDetails', this.editor.getTelemetryData()); } @@ -1062,10 +1107,20 @@ export class SuggestWidget implements IContentWidget, IDelegate registerThemingParticipant((theme, collector) => { let matchHighlight = theme.getColor(editorSuggestWidgetHighlightForeground); if (matchHighlight) { - collector.addRule(`.monaco-editor .suggest-widget:not(.frozen) .monaco-highlighted-label .highlight { color: ${matchHighlight}; }`); + collector.addRule(`.monaco-editor .suggest-widget:not(.frozen) .monaco-list .monaco-list-row .monaco-highlighted-label .highlight { color: ${matchHighlight}; }`); } let foreground = theme.getColor(editorSuggestWidgetForeground); if (foreground) { collector.addRule(`.monaco-editor .suggest-widget { color: ${foreground}; }`); } + + const link = theme.getColor(textLinkForeground); + if (link) { + collector.addRule(`.monaco-editor .suggest-widget a { color: ${link}; }`); + } + + let codeBackground = theme.getColor(textCodeBlockBackground); + if (codeBackground) { + collector.addRule(`.monaco-editor .suggest-widget code { background-color: ${codeBackground}; }`); + } }); diff --git a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts index 6bba3555808..46e5ec05e2d 100644 --- a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts @@ -11,7 +11,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { Model } from 'vs/editor/common/model/model'; import { ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon'; -import { ISuggestSupport, ISuggestResult, SuggestRegistry } from 'vs/editor/common/modes'; +import { ISuggestSupport, ISuggestResult, SuggestRegistry, SuggestTriggerKind } from 'vs/editor/common/modes'; import { SuggestModel, LineContext } from 'vs/editor/contrib/suggest/browser/suggestModel'; import { MockCodeEditor, MockScopeLocation } from 'vs/editor/test/common/mocks/mockCodeEditor'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -20,6 +20,8 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; +import { EditOperation } from 'vs/editor/common/core/editOperation'; +import { Range } from 'vs/editor/common/core/range'; function createMockEditor(model: Model): MockCodeEditor { const contextKeyService = new MockContextKeyService(); @@ -149,25 +151,25 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { // cancel on trigger assertEvent(model.onDidCancel, function () { - model.trigger(false); + model.trigger({ auto: false }); }, function (event) { assert.equal(event.retrigger, false); }), assertEvent(model.onDidCancel, function () { - model.trigger(false, true); + model.trigger({ auto: false }, true); }, function (event) { assert.equal(event.retrigger, true); }), assertEvent(model.onDidTrigger, function () { - model.trigger(true); + model.trigger({ auto: true }); }, function (event) { assert.equal(event.auto, true); }), assertEvent(model.onDidTrigger, function () { - model.trigger(false); + model.trigger({ auto: false }); }, function (event) { assert.equal(event.auto, false); }) @@ -183,12 +185,12 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return withOracle(model => { return TPromise.join([ assertEvent(model.onDidCancel, function () { - model.trigger(true); + model.trigger({ auto: true }); }, function (event) { assert.equal(event.retrigger, false); }), assertEvent(model.onDidSuggest, function () { - model.trigger(false); + model.trigger({ auto: false }); }, function (event) { assert.equal(event.auto, false); assert.equal(event.isFrozen, false); @@ -239,7 +241,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return assertEvent(model.onDidSuggest, () => { // make sure completionModel starts here! - model.trigger(true); + model.trigger({ auto: true }); }, event => { return assertEvent(model.onDidSuggest, () => { @@ -338,7 +340,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 3 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.isFrozen, false); @@ -363,7 +365,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 3 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.isFrozen, false); @@ -400,7 +402,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 4 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.completionModel.incomplete, true); @@ -437,7 +439,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 4 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.completionModel.incomplete, true); @@ -457,4 +459,82 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { }); }); }); + + test('Trigger character is provided in suggest context', function () { + let triggerCharacter = ''; + disposables.push(SuggestRegistry.register({ scheme: 'test' }, { + triggerCharacters: ['.'], + provideCompletionItems(doc, pos, context) { + assert.equal(context.triggerKind, SuggestTriggerKind.TriggerCharacter); + triggerCharacter = context.triggerCharacter; + return { + currentWord: '', + incomplete: false, + suggestions: [ + { + label: 'foo.bar', + type: 'property', + insertText: 'foo.bar', + overwriteBefore: pos.column - 1 + } + ] + }; + } + })); + + model.setValue(''); + + return withOracle((model, editor) => { + + return assertEvent(model.onDidSuggest, () => { + editor.setPosition({ lineNumber: 1, column: 1 }); + editor.trigger('keyboard', Handler.Type, { text: 'foo.' }); + }, event => { + assert.equal(triggerCharacter, '.'); + }); + }); + }); + + test('Mac press and hold accent character insertion does not update suggestions, #35269', function () { + disposables.push(SuggestRegistry.register({ scheme: 'test' }, { + provideCompletionItems(doc, pos) { + return { + incomplete: true, + suggestions: [{ + label: 'abc', + type: 'property', + insertText: 'abc', + overwriteBefore: pos.column - 1 + }, { + label: 'Ƥbc', + type: 'property', + insertText: 'Ƥbc', + overwriteBefore: pos.column - 1 + }] + }; + } + })); + + model.setValue(''); + return withOracle((model, editor) => { + + return assertEvent(model.onDidSuggest, () => { + editor.setPosition({ lineNumber: 1, column: 1 }); + editor.trigger('keyboard', Handler.Type, { text: 'a' }); + }, event => { + assert.equal(event.completionModel.items.length, 1); + assert.equal(event.completionModel.items[0].suggestion.label, 'abc'); + + return assertEvent(model.onDidSuggest, () => { + editor.executeEdits('test', [EditOperation.replace(new Range(1, 1, 1, 2), 'Ƥ')]); + + }, event => { + // suggest model changed to Ƥbc + assert.equal(event.completionModel.items.length, 1); + assert.equal(event.completionModel.items[0].suggestion.label, 'Ƥbc'); + + }); + }); + }); + }); }); diff --git a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts index 2cd8cab8f8c..2017bae8de2 100644 --- a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts @@ -11,7 +11,7 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { CommonEditorRegistry, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions'; +import { CommonEditorRegistry, commonEditorContribution, EditorAction, IActionOptions, editorAction } from 'vs/editor/common/editorCommonExtensions'; import { DocumentHighlight, DocumentHighlightKind, DocumentHighlightProviderRegistry } from 'vs/editor/common/modes'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Position } from 'vs/editor/common/core/position'; @@ -19,6 +19,11 @@ import { registerColor, editorSelectionHighlight, activeContrastBorder, overview import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService'; import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; +import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { firstIndex } from 'vs/base/common/arrays'; export const editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable.')); export const editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable.')); @@ -26,6 +31,8 @@ export const editorWordHighlightStrong = registerColor('editor.wordHighlightStro export const overviewRulerWordHighlightForeground = registerColor('editorOverviewRuler.wordHighlightForeground', { dark: '#A0A0A0', light: '#A0A0A0', hc: '#A0A0A0' }, nls.localize('overviewRulerWordHighlightForeground', 'Overview ruler marker color for symbol highlights.')); export const overviewRulerWordHighlightStrongForeground = registerColor('editorOverviewRuler.wordHighlightStrongForeground', { dark: '#C0A0C0', light: '#C0A0C0', hc: '#C0A0C0' }, nls.localize('overviewRulerWordHighlightStrongForeground', 'Overview ruler marker color for write-access symbol highlights.')); +export const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false); + export function getOccurrencesAtPosition(model: editorCommon.IReadOnlyModel, position: Position): TPromise { const orderedByScore = DocumentHighlightProviderRegistry.ordered(model); @@ -76,13 +83,23 @@ class WordHighlighter { private lastCursorPositionChangeTime: number = 0; private renderDecorationsTimer: number = -1; - constructor(editor: editorCommon.ICommonCodeEditor) { + private _hasWordHighlights: IContextKey; + private _ignorePositionChangeEvent: boolean; + + constructor(editor: editorCommon.ICommonCodeEditor, contextKeyService: IContextKeyService) { this.editor = editor; + this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService); + this._ignorePositionChangeEvent = false; this.occurrencesHighlight = this.editor.getConfiguration().contribInfo.occurrencesHighlight; this.model = this.editor.getModel(); this.toUnhook = []; this.toUnhook.push(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { + if (this._ignorePositionChangeEvent) { + // We are changing the position => ignore this event + return; + } + if (!this.occurrencesHighlight) { // Early exit if nothing needs to be done! // Leave some form of early exit check here if you wish to continue being a cursor position change listener ;) @@ -116,10 +133,56 @@ class WordHighlighter { this.renderDecorationsTimer = -1; } + public hasDecorations(): boolean { + return (this._decorationIds.length > 0); + } + + public restore(): void { + if (!this.occurrencesHighlight) { + return; + } + this._run(); + } + + private _getSortedHighlights(): Range[] { + return this._decorationIds + .map((id) => this.model.getDecorationRange(id)) + .sort(Range.compareRangesUsingStarts); + } + + public moveNext() { + let highlights = this._getSortedHighlights(); + let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); + let newIndex = ((index + 1) % highlights.length); + let dest = highlights[newIndex]; + try { + this._ignorePositionChangeEvent = true; + this.editor.setPosition(dest.getStartPosition()); + this.editor.revealRangeInCenter(dest); + } finally { + this._ignorePositionChangeEvent = false; + } + } + + public moveBack() { + let highlights = this._getSortedHighlights(); + let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); + let newIndex = ((index - 1 + highlights.length) % highlights.length); + let dest = highlights[newIndex]; + try { + this._ignorePositionChangeEvent = true; + this.editor.setPosition(dest.getStartPosition()); + this.editor.revealRangeInCenter(dest); + } finally { + this._ignorePositionChangeEvent = false; + } + } + private _removeDecorations(): void { if (this._decorationIds.length > 0) { // remove decorations this._decorationIds = this.editor.deltaDecorations(this._decorationIds, []); + this._hasWordHighlights.set(false); } } @@ -162,6 +225,10 @@ class WordHighlighter { return; } + this._run(); + } + + private _run(): void { // no providers for this model if (!DocumentHighlightProviderRegistry.has(this.model)) { this._stopAll(); @@ -281,6 +348,7 @@ class WordHighlighter { } this._decorationIds = this.editor.deltaDecorations(this._decorationIds, decorations); + this._hasWordHighlights.set(this.hasDecorations()); } private static _getDecorationOptions(kind: DocumentHighlightKind): ModelDecorationOptions { @@ -329,21 +397,48 @@ class WordHighlighter { } } + + @commonEditorContribution class WordHighlighterContribution implements editorCommon.IEditorContribution { private static ID = 'editor.contrib.wordHighlighter'; + public static get(editor: editorCommon.ICommonCodeEditor): WordHighlighterContribution { + return editor.getContribution(WordHighlighterContribution.ID); + } + private wordHighligher: WordHighlighter; - constructor(editor: editorCommon.ICommonCodeEditor) { - this.wordHighligher = new WordHighlighter(editor); + constructor(editor: editorCommon.ICommonCodeEditor, @IContextKeyService contextKeyService: IContextKeyService) { + this.wordHighligher = new WordHighlighter(editor, contextKeyService); } public getId(): string { return WordHighlighterContribution.ID; } + public saveViewState(): boolean { + if (this.wordHighligher.hasDecorations()) { + return true; + } + return false; + } + + public moveNext() { + this.wordHighligher.moveNext(); + } + + public moveBack() { + this.wordHighligher.moveBack(); + } + + public restoreViewState(state: boolean | undefined): void { + if (state) { + this.wordHighligher.restore(); + } + } + public dispose(): void { this.wordHighligher.dispose(); } @@ -370,4 +465,61 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-editor .wordHighlightStrong { border: 1px dashed ${hcOutline}; box-sizing: border-box; }`); } -}); \ No newline at end of file +}); + +class WordHighlightNavigationAction extends EditorAction { + + private _isNext: boolean; + + constructor(next: boolean, opts: IActionOptions) { + super(opts); + this._isNext = next; + } + + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { + const controller = WordHighlighterContribution.get(editor); + if (!controller) { + return; + } + + if (this._isNext) { + controller.moveNext(); + } else { + controller.moveBack(); + } + } +} + +@editorAction +// @ts-ignore @editorAction uses the class +class NextWordHighlightAction extends WordHighlightNavigationAction { + constructor() { + super(true, { + id: 'editor.action.wordHighlight.next', + label: nls.localize('wordHighlight.next.label', "Go to Next Symbol Highlight"), + alias: 'Go to Next Symbol Highlight', + precondition: ctxHasWordHighlights, + kbOpts: { + kbExpr: EditorContextKeys.textFocus, + primary: KeyCode.F7 + } + }); + } +} + +@editorAction +// @ts-ignore @editorAction uses the class +class PrevWordHighlightAction extends WordHighlightNavigationAction { + constructor() { + super(false, { + id: 'editor.action.wordHighlight.prev', + label: nls.localize('wordHighlight.previous.label', "Go to Previous Symbol Highlight"), + alias: 'Go to Previous Symbol Highlight', + precondition: ctxHasWordHighlights, + kbOpts: { + kbExpr: EditorContextKeys.textFocus, + primary: KeyMod.Shift | KeyCode.F7 + } + }); + } +} \ No newline at end of file diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index 53c35db2f3b..da7e44b07dd 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -7,7 +7,6 @@ import 'vs/css!./zoneWidget'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { Widget } from 'vs/base/browser/ui/widget'; import * as objects from 'vs/base/common/objects'; import * as dom from 'vs/base/browser/dom'; import { Sash, Orientation, IHorizontalSashLayoutProvider, ISashEvent } from 'vs/base/browser/ui/sash/sash'; @@ -18,7 +17,7 @@ import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { ScrollType } from 'vs/editor/common/editorCommon'; +import { ScrollType, TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; export interface IOptions { showFrame?: boolean; @@ -148,7 +147,7 @@ class Arrow { show(where: IPosition): void { this._decorations = this._editor.deltaDecorations( this._decorations, - [{ range: Range.fromPositions(where), options: { className: this._ruleName } }] + [{ range: Range.fromPositions(where), options: { className: this._ruleName, stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges } }] ); } @@ -157,7 +156,7 @@ class Arrow { } } -export abstract class ZoneWidget extends Widget implements IHorizontalSashLayoutProvider { +export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { private _arrow: Arrow; private _overlayWidget: OverlayWidgetDelegate; @@ -174,7 +173,6 @@ export abstract class ZoneWidget extends Widget implements IHorizontalSashLayout constructor(editor: ICodeEditor, options: IOptions = {}) { - super(); this.editor = editor; this.options = objects.clone(options); objects.mixin(this.options, defaultOptions, false); @@ -397,7 +395,11 @@ export abstract class ZoneWidget extends Widget implements IHorizontalSashLayout // Reveal the line above or below the zone widget, to get the zone widget in the viewport const revealLineNumber = Math.min(this.editor.getModel().getLineCount(), Math.max(1, where.endLineNumber + 1)); - this.editor.revealLine(revealLineNumber, ScrollType.Smooth); + this.revealLine(revealLineNumber); + } + + protected revealLine(lineNumber: number) { + this.editor.revealLine(lineNumber, ScrollType.Smooth); } protected setCssClass(className: string, classToReplace?: string): void { diff --git a/src/vs/editor/editor.main.ts b/src/vs/editor/editor.main.ts index 2bb862cb86f..96e342b7cb0 100644 --- a/src/vs/editor/editor.main.ts +++ b/src/vs/editor/editor.main.ts @@ -19,6 +19,16 @@ import { createMonacoEditorAPI } from 'vs/editor/standalone/browser/standaloneEd import { createMonacoLanguagesAPI } from 'vs/editor/standalone/browser/standaloneLanguages'; import { EDITOR_DEFAULTS, WrappingIndent } from 'vs/editor/common/config/editorOptions'; +var global: any = self; +global.monaco = exports; + +// When missing, polyfill the native promise +// with our winjs-based polyfill +import { PolyfillPromise } from 'vs/base/common/winjs.polyfill.promise'; +if (typeof global.Promise === 'undefined') { + global.Promise = PolyfillPromise; +} + // Set defaults for standalone editor (EDITOR_DEFAULTS).wrappingIndent = WrappingIndent.None; (EDITOR_DEFAULTS.contribInfo).folding = false; @@ -34,9 +44,6 @@ for (let prop in base) { exports.editor = createMonacoEditorAPI(); exports.languages = createMonacoLanguagesAPI(); -var global: any = self; -global.monaco = exports; - if (typeof global.require !== 'undefined' && typeof global.require.config === 'function') { global.require.config({ ignoreDuplicateModules: [ diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index b60bdaf2f80..c35a8d0a5b6 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -335,6 +335,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } @editorAction +// @ts-ignore @editorAction uses the class class ShowAccessibilityHelpAction extends EditorAction { constructor() { super({ diff --git a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts index cbcd2a853d2..50f8cab07b9 100644 --- a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts +++ b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts @@ -83,6 +83,7 @@ class InspectTokensController extends Disposable implements IEditorContribution } @editorAction +// @ts-ignore @editorAction uses the class class InspectTokens extends EditorAction { constructor() { @@ -169,7 +170,6 @@ class InspectTokensWidget extends Disposable implements IContentWidget { public allowEditorOverflow = true; private _editor: ICodeEditor; - private _standaloneThemeService: IStandaloneThemeService; private _modeService: IModeService; private _tokenizationSupport: ITokenizationSupport; private _model: IModel; @@ -182,7 +182,6 @@ class InspectTokensWidget extends Disposable implements IContentWidget { ) { super(); this._editor = editor; - this._standaloneThemeService = standaloneThemeService; this._modeService = modeService; this._model = this._editor.getModel(); this._domNode = document.createElement('div'); diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 7863e391781..a6c1766d569 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -8,7 +8,8 @@ import { Schemas } from 'vs/base/common/network'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, IConfigurationKeys, IConfigurationValues, Configuration, IConfigurationData, ConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IEditor, IEditorInput, IEditorOptions, IEditorService, IResourceInput, Position } from 'vs/platform/editor/common/editor'; import { ICommandService, ICommand, ICommandEvent, ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; @@ -16,13 +17,13 @@ import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayo import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { IKeybindingEvent, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IConfirmation, IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService, ILegacyWorkspace, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IConfirmation, IMessageService, IConfirmationResult } from 'vs/platform/message/common/message'; +import { IWorkspaceContextService, IWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; import Event, { Emitter } from 'vs/base/common/event'; -import { DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; +import { Configuration, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; @@ -138,7 +139,7 @@ export class SimpleEditorService implements IEditorService { let schema = data.resource.scheme; if (schema === Schemas.http || schema === Schemas.https) { // This is a fully qualified http or https URL - window.open(data.resource.toString()); + dom.windowOpenNoOpener(data.resource.toString()); return this.editor; } } @@ -235,6 +236,7 @@ export class SimpleProgressService implements IProgressService { } export class SimpleMessageService implements IMessageService { + public _serviceBrand: any; private static Empty = function () { /* nothing */ }; @@ -260,7 +262,7 @@ export class SimpleMessageService implements IMessageService { // No-op } - public confirm(confirmation: IConfirmation): boolean { + public confirmSync(confirmation: IConfirmation): boolean { let messageText = confirmation.message; if (confirmation.detail) { messageText = messageText + '\n\n' + confirmation.detail; @@ -268,6 +270,10 @@ export class SimpleMessageService implements IMessageService { return window.confirm(messageText); } + + public confirm(confirmation: IConfirmation): TPromise { + return TPromise.as({ confirmed: this.confirmSync(confirmation) } as IConfirmationResult); + } } export class StandaloneCommandService implements ICommandService { @@ -284,7 +290,8 @@ export class StandaloneCommandService implements ICommandService { this._dynamicCommands = Object.create(null); } - public addCommand(id: string, command: ICommand): IDisposable { + public addCommand(command: ICommand): IDisposable { + const { id } = command; this._dynamicCommands[id] = command; return { dispose: () => { @@ -316,10 +323,11 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { constructor( contextKeyService: IContextKeyService, commandService: ICommandService, + telemetryService: ITelemetryService, messageService: IMessageService, domNode: HTMLElement ) { - super(contextKeyService, commandService, messageService); + super(contextKeyService, commandService, telemetryService, messageService); this._cachedResolver = null; this._dynamicKeybindings = []; @@ -359,7 +367,8 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { let commandService = this._commandService; if (commandService instanceof StandaloneCommandService) { - toDispose.push(commandService.addCommand(commandId, { + toDispose.push(commandService.addCommand({ + id: commandId, handler: handler })); } else { @@ -425,45 +434,68 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { } } +function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides { + return thing + && typeof thing === 'object' + && (!thing.overrideIdentifier || typeof thing.overrideIdentifier === 'string') + && (!thing.resource || thing.resource instanceof URI); +} + export class SimpleConfigurationService implements IConfigurationService { _serviceBrand: any; - private _onDidUpdateConfiguration = new Emitter(); - public onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private _onDidChangeConfiguration = new Emitter(); + public onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; - private _configuration: Configuration; + private _configuration: Configuration; constructor() { this._configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel()); } - private configuration(): Configuration { + private configuration(): Configuration { return this._configuration; } - public reloadConfiguration(section?: string): TPromise { - return TPromise.as(this.getConfiguration(section)); + getConfiguration(): T; + getConfiguration(section: string): T; + getConfiguration(overrides: IConfigurationOverrides): T; + getConfiguration(section: string, overrides: IConfigurationOverrides): T; + getConfiguration(arg1?: any, arg2?: any): any { + const section = typeof arg1 === 'string' ? arg1 : void 0; + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : {}; + return this.configuration().getSection(section, overrides, null); } - public getConfiguration(section?: string, options?: IConfigurationOverrides): C { - return this.configuration().getValue(section, options); + public getValue(key: string, options: IConfigurationOverrides = {}): C { + return this.configuration().getValue(key, options, null); } - public lookup(key: string, options?: IConfigurationOverrides): IConfigurationValue { - return this.configuration().lookup(key, options); + public updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { + return TPromise.as(null); } - public keys(): IConfigurationKeys { - return this.configuration().keys(); + public inspect(key: string, options: IConfigurationOverrides = {}): { + default: C, + user: C, + workspace: C, + workspaceFolder: C + value: C, + } { + return this.configuration().lookup(key, options, null); } - public values(): IConfigurationValues { - return this._configuration.values(); + public keys() { + return this.configuration().keys(null); } - public getConfigurationData(): IConfigurationData { - return this.configuration().toData(); + public reloadConfiguration(): TPromise { + return TPromise.as(null); + } + + public getConfigurationData() { + return null; } } @@ -471,12 +503,12 @@ export class SimpleResourceConfigurationService implements ITextResourceConfigur _serviceBrand: any; - public readonly onDidUpdateConfiguration: Event; - private readonly _onDidUpdateConfigurationEmitter = new Emitter(); + public readonly onDidChangeConfiguration: Event; + private readonly _onDidChangeConfigurationEmitter = new Emitter(); constructor(private configurationService: SimpleConfigurationService) { - this.configurationService.onDidUpdateConfiguration(() => { - this._onDidUpdateConfigurationEmitter.fire(); + this.configurationService.onDidChangeConfiguration((e) => { + this._onDidChangeConfigurationEmitter.fire(e); }); } @@ -524,46 +556,46 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService { private readonly _onDidChangeWorkspaceName: Emitter = new Emitter(); public readonly onDidChangeWorkspaceName: Event = this._onDidChangeWorkspaceName.event; - private readonly _onDidChangeWorkspaceRoots: Emitter = new Emitter(); - public readonly onDidChangeWorkspaceRoots: Event = this._onDidChangeWorkspaceRoots.event; + private readonly _onDidChangeWorkspaceFolders: Emitter = new Emitter(); + public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; + + private readonly _onDidChangeWorkbenchState: Emitter = new Emitter(); + public readonly onDidChangeWorkbenchState: Event = this._onDidChangeWorkbenchState.event; - private readonly legacyWorkspace: ILegacyWorkspace; private readonly workspace: IWorkspace; constructor() { - this.legacyWorkspace = { resource: URI.from({ scheme: SimpleWorkspaceContextService.SCHEME, authority: 'model', path: '/' }) }; - this.workspace = { id: '4064f6ec-cb38-4ad0-af64-ee6467e63c82', roots: [this.legacyWorkspace.resource], name: this.legacyWorkspace.resource.fsPath }; - } - - public getLegacyWorkspace(): ILegacyWorkspace { - return this.legacyWorkspace; + const resource = URI.from({ scheme: SimpleWorkspaceContextService.SCHEME, authority: 'model', path: '/' }); + this.workspace = { id: '4064f6ec-cb38-4ad0-af64-ee6467e63c82', folders: [new WorkspaceFolder({ uri: resource, name: '', index: 0 })], name: resource.fsPath }; } public getWorkspace(): IWorkspace { return this.workspace; } - public getRoot(resource: URI): URI { - return resource && resource.scheme === SimpleWorkspaceContextService.SCHEME ? this.workspace.roots[0] : void 0; + public getWorkbenchState(): WorkbenchState { + if (this.workspace) { + if (this.workspace.configuration) { + return WorkbenchState.WORKSPACE; + } + return WorkbenchState.FOLDER; + } + return WorkbenchState.EMPTY; } - public hasWorkspace(): boolean { - return true; - } - - public hasFolderWorkspace(): boolean { - return true; - } - - public hasMultiFolderWorkspace(): boolean { - return false; + public getWorkspaceFolder(resource: URI): IWorkspaceFolder { + return resource && resource.scheme === SimpleWorkspaceContextService.SCHEME ? this.workspace.folders[0] : void 0; } public isInsideWorkspace(resource: URI): boolean { return resource && resource.scheme === SimpleWorkspaceContextService.SCHEME; } - public toResource(workspaceRelativePath: string): URI { + public toResource(workspaceRelativePath: string, workspaceFolder: IWorkspaceFolder): URI { return URI.file(workspaceRelativePath); } + + public isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean { + return true; + } } diff --git a/src/vs/editor/standalone/browser/standalone-tokens.css b/src/vs/editor/standalone/browser/standalone-tokens.css index 09fa35644b2..0bea05f2164 100644 --- a/src/vs/editor/standalone/browser/standalone-tokens.css +++ b/src/vs/editor/standalone/browser/standalone-tokens.css @@ -192,13 +192,17 @@ } /* squiggles */ - .monaco-editor.vs .redsquiggly, - .monaco-editor.vs-dark .redsquiggly { + .monaco-editor.vs .errorsquiggly, + .monaco-editor.vs-dark .errorsquiggly { background: transparent !important; border-bottom: 4px double #E47777; } - .monaco-editor.vs .greensquiggly, - .monaco-editor.vs-dark .greensquiggly { + .monaco-editor.vs .warningsquiggly, + .monaco-editor.vs-dark .warningsquiggly { + border-bottom: 4px double #71B771; + } + .monaco-editor.vs .infosquiggly, + .monaco-editor.vs-dark .infosquiggly { border-bottom: 4px double #71B771; } diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 7ff286ade85..bb23be19f3c 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -306,7 +306,6 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon export class StandaloneDiffEditor extends DiffEditorWidget implements IStandaloneDiffEditor { private _contextViewService: IEditorContextViewService; - private _standaloneKeybindingService: StandaloneKeybindingService; constructor( domElement: HTMLElement, @@ -328,10 +327,6 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon super(domElement, options, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, messageService); - if (keybindingService instanceof StandaloneKeybindingService) { - this._standaloneKeybindingService = keybindingService; - } - this._contextViewService = contextViewService; this._register(toDispose); diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index 894e651ba19..eae91566515 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -373,8 +373,8 @@ export function registerCompletionItemProvider(languageId: string, provider: Com let adapter = new SuggestAdapter(provider); return modes.SuggestRegistry.register(languageId, { triggerCharacters: provider.triggerCharacters, - provideCompletionItems: (model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Thenable => { - return adapter.provideCompletionItems(model, position, token); + provideCompletionItems: (model: editorCommon.IReadOnlyModel, position: Position, context: modes.SuggestContext, token: CancellationToken): Thenable => { + return adapter.provideCompletionItems(model, position, context, token); }, resolveCompletionItem: (model: editorCommon.IReadOnlyModel, position: Position, suggestion: modes.ISuggestion, token: CancellationToken): Thenable => { return adapter.resolveCompletionItem(model, position, suggestion, token); @@ -482,6 +482,10 @@ export interface CompletionItem { * A human-readable string that represents a doc-comment. */ documentation?: string; + /** + * A command that should be run upon acceptance of this item. + */ + command?: modes.Command; /** * A string that should be used when comparing this item * with other items. When `falsy` the [label](#CompletionItem.label) @@ -537,6 +541,25 @@ export interface CompletionList { */ items: CompletionItem[]; } + +/** + * Contains additional information about the context in which + * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + */ +export interface CompletionContext { + /** + * How the completion was triggered. + */ + triggerKind: modes.SuggestTriggerKind; + + /** + * Character that triggered the completion item provider. + * + * `undefined` if provider was not triggered by a character. + */ + triggerCharacter?: string; +} + /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -553,7 +576,8 @@ export interface CompletionItemProvider { /** * Provide completion items for the given position and document. */ - provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems(document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken, context: CompletionContext): CompletionItem[] | Thenable | CompletionList | Thenable; + /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). @@ -590,6 +614,7 @@ function convertKind(kind: CompletionItemKind): modes.SuggestionType { } return 'property'; } + class SuggestAdapter { private _provider: CompletionItemProvider; @@ -606,6 +631,7 @@ class SuggestAdapter { type: convertKind(item.kind), detail: item.detail, documentation: item.documentation, + command: item.command, sortText: item.sortText, filterText: item.filterText, snippetType: 'internal' @@ -639,9 +665,9 @@ class SuggestAdapter { return suggestion; } - provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Thenable { - - return toThenable(this._provider.provideCompletionItems(model, position, token)).then(value => { + provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, context: modes.SuggestContext, token: CancellationToken): Thenable { + const result = this._provider.provideCompletionItems(model, position, token, context); + return toThenable(result).then(value => { const result: modes.ISuggestResult = { suggestions: [] }; @@ -739,5 +765,6 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages { CompletionItemKind: CompletionItemKind, SymbolKind: modes.SymbolKind, IndentAction: IndentAction, + SuggestTriggerKind: modes.SuggestTriggerKind }; } diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 17ed8f6e8f1..7fac82dc12b 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -176,7 +176,7 @@ export class DynamicStandaloneServices extends Disposable { let commandService = ensure(ICommandService, () => new StandaloneCommandService(this._instantiationService)); - ensure(IKeybindingService, () => this._register(new StandaloneKeybindingService(contextKeyService, commandService, messageService, domElement))); + ensure(IKeybindingService, () => this._register(new StandaloneKeybindingService(contextKeyService, commandService, telemetryService, messageService, domElement))); let contextViewService = ensure(IContextViewService, () => this._register(new ContextViewService(domElement, telemetryService, messageService))); diff --git a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts index 17197a6f7d3..3b48b9eab9e 100644 --- a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts +++ b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts @@ -10,6 +10,7 @@ import { editorAction, EditorAction, ServicesAccessor } from 'vs/editor/common/e import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; @editorAction +// @ts-ignore @editorAction uses the class class ToggleHighContrast extends EditorAction { private _originalThemeName: string; diff --git a/src/vs/editor/standalone/test/browser/simpleServices.test.ts b/src/vs/editor/standalone/test/browser/simpleServices.test.ts index 12aaaad2825..e2a6120ec59 100644 --- a/src/vs/editor/standalone/test/browser/simpleServices.test.ts +++ b/src/vs/editor/standalone/test/browser/simpleServices.test.ts @@ -11,6 +11,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { KeyCode } from 'vs/base/common/keyCodes'; import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; +import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; suite('StandaloneKeybindingService', () => { @@ -35,7 +36,7 @@ suite('StandaloneKeybindingService', () => { let domElement = document.createElement('div'); - let keybindingService = new TestStandaloneKeybindingService(contextKeyService, commandService, messageService, domElement); + let keybindingService = new TestStandaloneKeybindingService(contextKeyService, commandService, NullTelemetryService, messageService, domElement); let commandInvoked = false; keybindingService.addDynamicKeybinding('testCommand', KeyCode.F9, () => { diff --git a/src/vs/editor/test/browser/controller/imeTester.ts b/src/vs/editor/test/browser/controller/imeTester.ts index a306aa952c8..6d80c9f7d5f 100644 --- a/src/vs/editor/test/browser/controller/imeTester.ts +++ b/src/vs/editor/test/browser/controller/imeTester.ts @@ -17,6 +17,7 @@ import * as browser from 'vs/base/browser/browser'; class SingleLineTestModel implements ISimpleModel { private _line: string; + // @ts-ignore unused property private _eol: string; constructor(line: string) { @@ -100,7 +101,7 @@ function doCreateTest(description: string, inputStr: string, expectedStr: string const selection = new Range(1, 1 + cursorOffset, 1, 1 + cursorOffset + cursorLength); - return PagedScreenReaderStrategy.fromEditorSelection(currentState, model, selection); + return PagedScreenReaderStrategy.fromEditorSelection(currentState, model, selection, true); }, deduceModelPosition: (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position => { return null; diff --git a/src/vs/editor/test/browser/controller/textAreaState.test.ts b/src/vs/editor/test/browser/controller/textAreaState.test.ts index 84ea1b06c73..f63f52aadc3 100644 --- a/src/vs/editor/test/browser/controller/textAreaState.test.ts +++ b/src/vs/editor/test/browser/controller/textAreaState.test.ts @@ -500,7 +500,7 @@ suite('TextAreaState', () => { function testPagedScreenReaderStrategy(lines: string[], selection: Selection, expected: TextAreaState): void { const model = Model.createFromString(lines.join('\n')); - const actual = PagedScreenReaderStrategy.fromEditorSelection(TextAreaState.EMPTY, model, selection); + const actual = PagedScreenReaderStrategy.fromEditorSelection(TextAreaState.EMPTY, model, selection, true); assert.ok(actual.equals(expected)); model.dispose(); } @@ -588,6 +588,7 @@ suite('TextAreaState', () => { }); }); +// @ts-ignore unused class class SimpleModel implements ISimpleModel { private _lines: string[]; diff --git a/src/vs/editor/test/common/commands/sideEditing.test.ts b/src/vs/editor/test/common/commands/sideEditing.test.ts index 08fe4e0c5e7..ceaa7df8265 100644 --- a/src/vs/editor/test/common/commands/sideEditing.test.ts +++ b/src/vs/editor/test/common/commands/sideEditing.test.ts @@ -10,10 +10,11 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon'; -import { ILineEdit, ModelLine, LineMarker, MarkersTracker } from 'vs/editor/common/model/modelLine'; import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; - -const NO_TAB_SIZE = 0; +import { Model } from 'vs/editor/common/model/model'; +import { TestConfiguration } from 'vs/editor/test/common/mocks/testConfiguration'; +import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; +import { Cursor } from 'vs/editor/common/controller/cursor'; function testCommand(lines: string[], selections: Selection[], edits: IIdentifiedSingleEditOperation[], expectedLines: string[], expectedSelections: Selection[]): void { withMockCodeEditor(lines, {}, (editor, cursor) => { @@ -31,15 +32,6 @@ function testCommand(lines: string[], selections: Selection[], edits: IIdentifie }); } -function testLineEditMarker(text: string, column: number, stickToPreviousCharacter: boolean, edit: ILineEdit, expectedColumn: number): void { - var line = new ModelLine(text, NO_TAB_SIZE); - line.addMarker(new LineMarker('1', 0, new Position(0, column), stickToPreviousCharacter)); - - line.applyEdits(new MarkersTracker(), [edit], NO_TAB_SIZE); - - assert.equal(line.getMarkers()[0].position.column, expectedColumn); -} - suite('Editor Side Editing - collapsed selection', () => { test('replace at selection', () => { @@ -86,14 +78,6 @@ suite('Editor Side Editing - collapsed selection', () => { ); }); - test('ModelLine.applyEdits uses `isReplace`', () => { - testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: false }, 1); - testLineEditMarker('something', 1, true, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: true }, 4); - - testLineEditMarker('something', 1, false, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: false }, 4); - testLineEditMarker('something', 1, false, { startColumn: 1, endColumn: 1, text: 'asd', forceMoveMarkers: true }, 4); - }); - test('insert at selection', () => { testCommand( [ @@ -204,5 +188,699 @@ suite('Editor Side Editing - collapsed selection', () => { [new Selection(1, 1, 1, 1), new Selection(1, 3, 1, 3)] ); }); +}); +suite('SideEditing', () => { + + const LINES = [ + 'My First Line', + 'My Second Line', + 'Third Line' + ]; + + function _runTest(selection: Selection, editRange: Range, editText: string, editForceMoveMarkers: boolean, expected: Selection, msg: string): void { + const model = Model.createFromString(LINES.join('\n')); + const config = new TestConfiguration(null); + const viewModel = new ViewModel(0, config, model, null); + const cursor = new Cursor(config, model, viewModel); + + cursor.setSelections('tests', [selection]); + model.applyEdits([{ range: editRange, text: editText, forceMoveMarkers: editForceMoveMarkers, identifier: null }]); + const actual = cursor.getSelection(); + assert.deepEqual(actual.toString(), expected.toString(), msg); + + cursor.dispose(); + viewModel.dispose(); + config.dispose(); + model.dispose(); + } + + function runTest(selection: Range, editRange: Range, editText: string, expected: Selection[][]): void { + const sel1 = new Selection(selection.startLineNumber, selection.startColumn, selection.endLineNumber, selection.endColumn); + _runTest(sel1, editRange, editText, false, expected[0][0], '0-0-regular-no-force'); + _runTest(sel1, editRange, editText, true, expected[1][0], '1-0-regular-force'); + + // RTL selection + const sel2 = new Selection(selection.endLineNumber, selection.endColumn, selection.startLineNumber, selection.startColumn); + _runTest(sel2, editRange, editText, false, expected[0][1], '0-1-inverse-no-force'); + _runTest(sel2, editRange, editText, true, expected[1][1], '1-1-inverse-force'); + } + + suite('insert', () => { + suite('collapsed sel', () => { + test('before', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 3), 'xx', + [ + [new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)], + [new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)], + ] + ); + }); + test('equal', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 4), 'xx', + [ + [new Selection(1, 4, 1, 6), new Selection(1, 4, 1, 6)], + [new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)], + ] + ); + }); + test('after', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 5), 'xx', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('before', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 3), 'xx', + [ + [new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)], + [new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)], + ] + ); + }); + test('start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 4), 'xx', + [ + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + [new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)], + ] + ); + }); + test('inside', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 5), 'xx', + [ + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + ] + ); + }); + test('end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 9), 'xx', + [ + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + ] + ); + }); + test('after', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 10), 'xx', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + ] + ); + }); + }); + }); + + suite('delete', () => { + suite('collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 1, 1, 3), '', + [ + [new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)], + [new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 2, 1, 4), '', + [ + [new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)], + [new Selection(1, 2, 1, 2), new Selection(1, 2, 1, 2)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 5), '', + [ + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + ] + ); + }); + test('edit.start >= range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 6), '', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 7), '', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 1, 1, 3), '', + [ + [new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)], + [new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 2, 1, 4), '', + [ + [new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)], + [new Selection(1, 2, 1, 7), new Selection(1, 7, 1, 2)], + ] + ); + }); + test('edit.start < range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 5), '', + [ + [new Selection(1, 3, 1, 7), new Selection(1, 7, 1, 3)], + [new Selection(1, 3, 1, 7), new Selection(1, 7, 1, 3)], + ] + ); + }); + + test('edit.start < range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 9), '', + [ + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + ] + ); + }); + + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 10), '', + [ + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + ] + ); + }); + + test('edit.start == range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 6), '', + [ + [new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)], + [new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)], + ] + ); + }); + + test('edit.start == range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 9), '', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + + test('edit.start == range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 10), '', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + + test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 7), '', + [ + [new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)], + [new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)], + ] + ); + }); + + test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 9), '', + [ + [new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)], + [new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)], + ] + ); + }); + + test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 10), '', + [ + [new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)], + [new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)], + ] + ); + }); + + test('edit.start == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 11), '', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + ] + ); + }); + + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 11), '', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + ] + ); + }); + }); + }); + + suite('replace short', () => { + suite('collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 1, 1, 3), 'c', + [ + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 2, 1, 4), 'c', + [ + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + [new Selection(1, 3, 1, 3), new Selection(1, 3, 1, 3)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 5), 'c', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + test('edit.start >= range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 6), 'c', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 5, 1, 5), new Selection(1, 5, 1, 5)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 7), 'c', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 1, 1, 3), 'c', + [ + [new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)], + [new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 2, 1, 4), 'c', + [ + [new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)], + [new Selection(1, 3, 1, 8), new Selection(1, 8, 1, 3)], + ] + ); + }); + test('edit.start < range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 5), 'c', + [ + [new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)], + [new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)], + ] + ); + }); + test('edit.start < range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 9), 'c', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 10), 'c', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + test('edit.start == range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 6), 'c', + [ + [new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)], + [new Selection(1, 5, 1, 8), new Selection(1, 8, 1, 5)], + ] + ); + }); + test('edit.start == range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 9), 'c', + [ + [new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)], + [new Selection(1, 5, 1, 5), new Selection(1, 5, 1, 5)], + ] + ); + }); + test('edit.start == range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 10), 'c', + [ + [new Selection(1, 4, 1, 5), new Selection(1, 5, 1, 4)], + [new Selection(1, 5, 1, 5), new Selection(1, 5, 1, 5)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 7), 'c', + [ + [new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)], + [new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 9), 'c', + [ + [new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)], + [new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 10), 'c', + [ + [new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)], + [new Selection(1, 4, 1, 6), new Selection(1, 6, 1, 4)], + ] + ); + }); + test('edit.start == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 11), 'c', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 10), new Selection(1, 10, 1, 4)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 11), 'c', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + ] + ); + }); + }); + }); + + suite('replace long', () => { + suite('collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 1, 1, 3), 'cccc', + [ + [new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)], + [new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 2, 1, 4), 'cccc', + [ + [new Selection(1, 4, 1, 6), new Selection(1, 4, 1, 6)], + [new Selection(1, 6, 1, 6), new Selection(1, 6, 1, 6)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 5), 'cccc', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 7, 1, 7), new Selection(1, 7, 1, 7)], + ] + ); + }); + test('edit.start >= range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 6), 'cccc', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 8, 1, 8), new Selection(1, 8, 1, 8)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 7), 'cccc', + [ + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + [new Selection(1, 4, 1, 4), new Selection(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 1, 1, 3), 'cccc', + [ + [new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)], + [new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 2, 1, 4), 'cccc', + [ + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + [new Selection(1, 6, 1, 11), new Selection(1, 11, 1, 6)], + ] + ); + }); + test('edit.start < range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 5), 'cccc', + [ + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + [new Selection(1, 7, 1, 11), new Selection(1, 11, 1, 7)], + ] + ); + }); + test('edit.start < range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 9), 'cccc', + [ + [new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)], + [new Selection(1, 7, 1, 7), new Selection(1, 7, 1, 7)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 10), 'cccc', + [ + [new Selection(1, 4, 1, 7), new Selection(1, 7, 1, 4)], + [new Selection(1, 7, 1, 7), new Selection(1, 7, 1, 7)], + ] + ); + }); + test('edit.start == range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 6), 'cccc', + [ + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + [new Selection(1, 8, 1, 11), new Selection(1, 11, 1, 8)], + ] + ); + }); + test('edit.start == range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 9), 'cccc', + [ + [new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)], + [new Selection(1, 8, 1, 8), new Selection(1, 8, 1, 8)], + ] + ); + }); + test('edit.start == range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 10), 'cccc', + [ + [new Selection(1, 4, 1, 8), new Selection(1, 8, 1, 4)], + [new Selection(1, 8, 1, 8), new Selection(1, 8, 1, 8)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 7), 'cccc', + [ + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + [new Selection(1, 4, 1, 11), new Selection(1, 11, 1, 4)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 9), 'cccc', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 10), 'cccc', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + ] + ); + }); + test('edit.start == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 11), 'cccc', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 13), new Selection(1, 13, 1, 4)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 11), 'cccc', + [ + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + [new Selection(1, 4, 1, 9), new Selection(1, 9, 1, 4)], + ] + ); + }); + }); + }); }); \ No newline at end of file diff --git a/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts b/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts index 08a1664cbe0..e780615c263 100644 --- a/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts +++ b/src/vs/editor/test/common/commands/trimTrailingWhitespaceCommand.test.ts @@ -14,7 +14,7 @@ import { withEditorModel } from 'vs/editor/test/common/editorTestUtils'; function assertTrimTrailingWhitespaceCommand(text: string[], expected: IIdentifiedSingleEditOperation[]): void { return withEditorModel(text, (model) => { - var op = new TrimTrailingWhitespaceCommand(new Selection(1, 1, 1, 1)); + var op = new TrimTrailingWhitespaceCommand(new Selection(1, 1, 1, 1), []); var actual = getEditOperation(model, op); assert.deepEqual(actual, expected); }); diff --git a/src/vs/editor/test/common/controller/cursor.test.ts b/src/vs/editor/test/common/controller/cursor.test.ts index b71db2b9c93..63eae2816d3 100644 --- a/src/vs/editor/test/common/controller/cursor.test.ts +++ b/src/vs/editor/test/common/controller/cursor.test.ts @@ -1453,9 +1453,9 @@ suite('Editor Controller - Regression tests', () => { cursorCommand(cursor, H.Undo); assert.equal(model.getValue(), [ - 'some lines', - 'and more lines', - 'just some text', + ' some lines', + ' and more lines', + ' just some text', ].join('\n'), '002'); cursorCommand(cursor, H.Undo); @@ -1464,6 +1464,13 @@ suite('Editor Controller - Regression tests', () => { 'and more lines', 'just some text', ].join('\n'), '003'); + + cursorCommand(cursor, H.Undo); + assert.equal(model.getValue(), [ + 'some lines', + 'and more lines', + 'just some text', + ].join('\n'), '004'); }); model.dispose(); @@ -1622,6 +1629,24 @@ suite('Editor Controller - Regression tests', () => { }); }); + test('issue #33788: Wrong cursor position when double click to select a word', () => { + let model = Model.createFromString( + [ + 'Just some text' + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + CoreNavigationCommands.WordSelect.runCoreEditorCommand(cursor, { position: new Position(1, 8) }); + assert.deepEqual(cursor.getSelection(), new Selection(1, 6, 1, 10)); + + CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(cursor, { position: new Position(1, 8) }); + assert.deepEqual(cursor.getSelection(), new Selection(1, 6, 1, 10)); + }); + + model.dispose(); + }); + test('issue #9675: Undo/Redo adds a stop in between CHN Characters', () => { usingCursor({ text: [ @@ -1651,7 +1676,8 @@ suite('Editor Controller - Regression tests', () => { }); }); - test('issue #23913: Greater than 1000+ multi cursor typing replacement text appears inverted, lines begin to drop off selection', () => { + test('issue #23913: Greater than 1000+ multi cursor typing replacement text appears inverted, lines begin to drop off selection', function () { + this.timeout(10000); const LINE_CNT = 2000; let text = []; @@ -1715,6 +1741,49 @@ suite('Editor Controller - Regression tests', () => { assertCursor(cursor, new Selection(1, 1, 1, 1)); }); }); + + test('issue #36740: wordwrap creates an extra step / character at the wrapping point', () => { + // a single model line => 4 view lines + withMockCodeEditor([ + [ + 'Lorem ipsum ', + 'dolor sit amet ', + 'consectetur ', + 'adipiscing elit', + ].join('') + ], { wordWrap: 'wordWrapColumn', wordWrapColumn: 16 }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 7, 1, 7)]); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 9, 1, 9)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 10, 1, 10)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 11, 1, 11)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 12, 1, 12)); + + moveRight(cursor); + assertCursor(cursor, new Selection(1, 13, 1, 13)); + + // moving to view line 2 + moveRight(cursor); + assertCursor(cursor, new Selection(1, 14, 1, 14)); + + moveLeft(cursor); + assertCursor(cursor, new Selection(1, 13, 1, 13)); + + // moving back to view line 1 + moveLeft(cursor); + assertCursor(cursor, new Selection(1, 12, 1, 12)); + }); + }); }); suite('Editor Controller - Cursor Configuration', () => { @@ -3105,6 +3174,93 @@ suite('Editor Controller - Indentation Rules', () => { assert.equal(model.getLineContent(3), '}'); }); }); + + test('issue #36090: JS: editor.autoIndent seems to be broken', () => { + class JSMode extends MockMode { + private static _id = new LanguageIdentifier('indentRulesMode', 4); + constructor() { + super(JSMode._id); + this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), { + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + indentationRules: { + // ^(.*\*/)?\s*\}.*$ + decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]\)].*$/, + // ^.*\{[^}"']*$ + increaseIndentPattern: /^((?!\/\/).)*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/ + }, + onEnterRules: [ + { + // e.g. /** | */ + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' } + }, { + // e.g. /** ...| + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction: IndentAction.None, appendText: ' * ' } + }, { + // e.g. * ...| + beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction: IndentAction.None, appendText: '* ' } + }, { + // e.g. */| + beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, + action: { indentAction: IndentAction.None, removeText: 1 } + }, + { + // e.g. *-----*/| + beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/, + action: { indentAction: IndentAction.None, removeText: 1 } + } + ] + })); + } + } + + let mode = new JSMode(); + let model = Model.createFromString( + [ + 'class ItemCtrl {', + ' getPropertiesByItemId(id) {', + ' return this.fetchItem(id)', + ' .then(item => {', + ' return this.getPropertiesOfItem(item);', + ' });', + ' }', + '}', + ].join('\n'), + undefined, + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model, autoIndent: false }, (editor, cursor) => { + moveTo(cursor, 7, 6, false); + assertCursor(cursor, new Selection(7, 6, 7, 6)); + + cursorCommand(cursor, H.Type, { text: '\n' }, 'keyboard'); + assert.equal(model.getValue(), + [ + 'class ItemCtrl {', + ' getPropertiesByItemId(id) {', + ' return this.fetchItem(id)', + ' .then(item => {', + ' return this.getPropertiesOfItem(item);', + ' });', + ' }', + ' ', + '}', + ].join('\n') + ); + assertCursor(cursor, new Selection(8, 5, 8, 5)); + }); + + model.dispose(); + mode.dispose(); + }); }); interface ICursorOpts { @@ -3699,4 +3855,260 @@ suite('autoClosingPairs', () => { model.dispose(); mode.dispose(); }); + + test('issue #7100: Mouse word selection is strange when non-word character is at the end of line', () => { + let model = Model.createFromString( + [ + 'before.a', + 'before', + 'hello:', + 'there:', + 'this is strange:', + 'here', + 'it', + 'is', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + CoreNavigationCommands.WordSelect.runEditorCommand(null, editor, { + position: new Position(3, 7) + }); + assertCursor(cursor, new Selection(3, 7, 3, 7)); + + CoreNavigationCommands.WordSelectDrag.runEditorCommand(null, editor, { + position: new Position(4, 7) + }); + assertCursor(cursor, new Selection(3, 7, 4, 7)); + }); + }); +}); + +suite('Undo stops', () => { + + test('there is an undo stop between typing and deleting left', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + cursorCommand(cursor, H.Type, { text: 'first' }, 'keyboard'); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(1), 'A fir line'); + assertCursor(cursor, new Selection(1, 6, 1, 6)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A line'); + assertCursor(cursor, new Selection(1, 3, 1, 3)); + }); + }); + + test('there is an undo stop between typing and deleting right', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + cursorCommand(cursor, H.Type, { text: 'first' }, 'keyboard'); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(1), 'A firstine'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A line'); + assertCursor(cursor, new Selection(1, 3, 1, 3)); + }); + }); + + test('there is an undo stop between deleting left and typing', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 8, 2, 8)]); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Type, { text: 'Second' }, 'keyboard'); + assert.equal(model.getLineContent(2), 'Second line'); + assertCursor(cursor, new Selection(2, 7, 2, 7)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 8, 2, 8)); + }); + }); + + test('there is an undo stop between deleting left and deleting right', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 8, 2, 8)]); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), ''); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), ' line'); + assertCursor(cursor, new Selection(2, 1, 2, 1)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 8, 2, 8)); + }); + }); + + test('there is an undo stop between deleting right and typing', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 9, 2, 9)]); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + cursorCommand(cursor, H.Type, { text: 'text' }, 'keyboard'); + assert.equal(model.getLineContent(2), 'Another text'); + assertCursor(cursor, new Selection(2, 13, 2, 13)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + }); + }); + + test('there is an undo stop between deleting right and deleting left', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(2, 9, 2, 9)]); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(2), 'An'); + assertCursor(cursor, new Selection(2, 3, 2, 3)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another '); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(2), 'Another line'); + assertCursor(cursor, new Selection(2, 9, 2, 9)); + }); + }); + + test('inserts undo stop when typing space', () => { + let model = Model.createFromString( + [ + 'A line', + 'Another line', + ].join('\n') + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + cursorCommand(cursor, H.Type, { text: 'first and interesting' }, 'keyboard'); + assert.equal(model.getLineContent(1), 'A first and interesting line'); + assertCursor(cursor, new Selection(1, 24, 1, 24)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first and line'); + assertCursor(cursor, new Selection(1, 12, 1, 12)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A first line'); + assertCursor(cursor, new Selection(1, 8, 1, 8)); + + cursorCommand(cursor, H.Undo, {}); + assert.equal(model.getLineContent(1), 'A line'); + assertCursor(cursor, new Selection(1, 3, 1, 3)); + }); + }); + }); diff --git a/src/vs/editor/test/common/core/editorState.test.ts b/src/vs/editor/test/common/core/editorState.test.ts index d629a01987d..f5ca66e9dd4 100644 --- a/src/vs/editor/test/common/core/editorState.test.ts +++ b/src/vs/editor/test/common/core/editorState.test.ts @@ -91,13 +91,13 @@ suite('Editor Core - Editor State', () => { function createEditor({ model, position, selection, scroll }: IStubEditorState = {}): ICommonCodeEditor { let mappedModel = model ? { uri: model.uri ? model.uri : URI.parse('http://dummy.org'), getVersionId: () => model.version } : null; - return { + return { getModel: (): IModel => mappedModel, getPosition: (): Position => position, getSelection: (): Selection => selection, getScrollLeft: (): number => scroll && scroll.left, getScrollTop: (): number => scroll && scroll.top - }; + } as ICommonCodeEditor; } }); diff --git a/src/vs/editor/test/common/mocks/mockCodeEditor.ts b/src/vs/editor/test/common/mocks/mockCodeEditor.ts index afb99c73774..599112cbb1c 100644 --- a/src/vs/editor/test/common/mocks/mockCodeEditor.ts +++ b/src/vs/editor/test/common/mocks/mockCodeEditor.ts @@ -18,6 +18,9 @@ import * as editorOptions from 'vs/editor/common/config/editorOptions'; import { IDisposable } from 'vs/base/common/lifecycle'; export class MockCodeEditor extends CommonCodeEditor { + + public _isFocused = true; + protected _createConfiguration(options: editorOptions.IEditorOptions): CommonEditorConfiguration { return new TestConfiguration(options); } @@ -25,8 +28,8 @@ export class MockCodeEditor extends CommonCodeEditor { public layout(dimension?: editorCommon.IDimension): void { } public focus(): void { } - public isFocused(): boolean { return true; } - public hasWidgetFocus(): boolean { return true; }; + public isFocused(): boolean { return this._isFocused; } + public hasWidgetFocus(): boolean { return true; } protected _enableEmptySelectionClipboard(): boolean { return false; } protected _scheduleAtNextAnimationFrame(callback: () => void): IDisposable { throw new Error('Notimplemented'); } diff --git a/src/vs/editor/test/common/model/editableTextModel.test.ts b/src/vs/editor/test/common/model/editableTextModel.test.ts index 6166f3eb8e5..d04e5269cad 100644 --- a/src/vs/editor/test/common/model/editableTextModel.test.ts +++ b/src/vs/editor/test/common/model/editableTextModel.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { Range } from 'vs/editor/common/core/range'; -import { EndOfLinePreference, EndOfLineSequence, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon'; +import { EndOfLineSequence, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon'; import { EditableTextModel, IValidatedEditOperation } from 'vs/editor/common/model/editableTextModel'; import { MirrorModel } from 'vs/editor/common/model/mirrorModel'; import { assertSyncedModels, testApplyEditsWithSyncedModels } from 'vs/editor/test/common/model/editableTextModelTestUtils'; @@ -15,12 +15,13 @@ import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvent suite('EditorModel - EditableTextModel._getInverseEdits', () => { - function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeLength: number, text: string[]): IValidatedEditOperation { + function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text: string[]): IValidatedEditOperation { return { sortIndex: 0, identifier: null, range: new Range(startLineNumber, startColumn, endLineNumber, endColumn), - rangeLength: rangeLength, + rangeOffset: 0, + rangeLength: 0, lines: text, forceMoveMarkers: false, isAutoWhitespaceEdit: false @@ -39,7 +40,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('single insert', () => { assertInverseEdits( [ - editOp(1, 1, 1, 1, 0, ['hello']) + editOp(1, 1, 1, 1, ['hello']) ], [ inverseEditOp(1, 1, 1, 6) @@ -50,8 +51,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('Bug 19872: Undo is funky', () => { assertInverseEdits( [ - editOp(2, 1, 2, 2, 0, ['']), - editOp(3, 1, 4, 2, 0, ['']) + editOp(2, 1, 2, 2, ['']), + editOp(3, 1, 4, 2, ['']) ], [ inverseEditOp(2, 1, 2, 1), @@ -63,8 +64,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two single unrelated inserts', () => { assertInverseEdits( [ - editOp(1, 1, 1, 1, 0, ['hello']), - editOp(2, 1, 2, 1, 0, ['world']) + editOp(1, 1, 1, 1, ['hello']), + editOp(2, 1, 2, 1, ['world']) ], [ inverseEditOp(1, 1, 1, 6), @@ -76,8 +77,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two single inserts 1', () => { assertInverseEdits( [ - editOp(1, 1, 1, 1, 0, ['hello']), - editOp(1, 2, 1, 2, 0, ['world']) + editOp(1, 1, 1, 1, ['hello']), + editOp(1, 2, 1, 2, ['world']) ], [ inverseEditOp(1, 1, 1, 6), @@ -89,8 +90,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two single inserts 2', () => { assertInverseEdits( [ - editOp(1, 1, 1, 1, 0, ['hello']), - editOp(1, 4, 1, 4, 0, ['world']) + editOp(1, 1, 1, 1, ['hello']), + editOp(1, 4, 1, 4, ['world']) ], [ inverseEditOp(1, 1, 1, 6), @@ -102,7 +103,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('multiline insert', () => { assertInverseEdits( [ - editOp(1, 1, 1, 1, 0, ['hello', 'world']) + editOp(1, 1, 1, 1, ['hello', 'world']) ], [ inverseEditOp(1, 1, 2, 6) @@ -113,8 +114,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two unrelated multiline inserts', () => { assertInverseEdits( [ - editOp(1, 1, 1, 1, 0, ['hello', 'world']), - editOp(2, 1, 2, 1, 0, ['how', 'are', 'you?']), + editOp(1, 1, 1, 1, ['hello', 'world']), + editOp(2, 1, 2, 1, ['how', 'are', 'you?']), ], [ inverseEditOp(1, 1, 2, 6), @@ -126,8 +127,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two multiline inserts 1', () => { assertInverseEdits( [ - editOp(1, 1, 1, 1, 0, ['hello', 'world']), - editOp(1, 2, 1, 2, 0, ['how', 'are', 'you?']), + editOp(1, 1, 1, 1, ['hello', 'world']), + editOp(1, 2, 1, 2, ['how', 'are', 'you?']), ], [ inverseEditOp(1, 1, 2, 6), @@ -139,7 +140,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('single delete', () => { assertInverseEdits( [ - editOp(1, 1, 1, 6, 0, null) + editOp(1, 1, 1, 6, null) ], [ inverseEditOp(1, 1, 1, 1) @@ -150,8 +151,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two single unrelated deletes', () => { assertInverseEdits( [ - editOp(1, 1, 1, 6, 0, null), - editOp(2, 1, 2, 6, 0, null) + editOp(1, 1, 1, 6, null), + editOp(2, 1, 2, 6, null) ], [ inverseEditOp(1, 1, 1, 1), @@ -163,8 +164,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two single deletes 1', () => { assertInverseEdits( [ - editOp(1, 1, 1, 6, 0, null), - editOp(1, 7, 1, 12, 0, null) + editOp(1, 1, 1, 6, null), + editOp(1, 7, 1, 12, null) ], [ inverseEditOp(1, 1, 1, 1), @@ -176,8 +177,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two single deletes 2', () => { assertInverseEdits( [ - editOp(1, 1, 1, 6, 0, null), - editOp(1, 9, 1, 14, 0, null) + editOp(1, 1, 1, 6, null), + editOp(1, 9, 1, 14, null) ], [ inverseEditOp(1, 1, 1, 1), @@ -189,7 +190,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('multiline delete', () => { assertInverseEdits( [ - editOp(1, 1, 2, 6, 0, null) + editOp(1, 1, 2, 6, null) ], [ inverseEditOp(1, 1, 1, 1) @@ -200,8 +201,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two unrelated multiline deletes', () => { assertInverseEdits( [ - editOp(1, 1, 2, 6, 0, null), - editOp(3, 1, 5, 5, 0, null), + editOp(1, 1, 2, 6, null), + editOp(3, 1, 5, 5, null), ], [ inverseEditOp(1, 1, 1, 1), @@ -213,8 +214,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two multiline deletes 1', () => { assertInverseEdits( [ - editOp(1, 1, 2, 6, 0, null), - editOp(2, 7, 4, 5, 0, null), + editOp(1, 1, 2, 6, null), + editOp(2, 7, 4, 5, null), ], [ inverseEditOp(1, 1, 1, 1), @@ -226,7 +227,7 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('single replace', () => { assertInverseEdits( [ - editOp(1, 1, 1, 6, 0, ['Hello world']) + editOp(1, 1, 1, 6, ['Hello world']) ], [ inverseEditOp(1, 1, 1, 12) @@ -237,8 +238,8 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('two replaces', () => { assertInverseEdits( [ - editOp(1, 1, 1, 6, 0, ['Hello world']), - editOp(1, 7, 1, 8, 0, ['How are you?']), + editOp(1, 1, 1, 6, ['Hello world']), + editOp(1, 7, 1, 8, ['How are you?']), ], [ inverseEditOp(1, 1, 1, 12), @@ -250,9 +251,9 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { test('many edits', () => { assertInverseEdits( [ - editOp(1, 2, 1, 2, 0, ['', ' ']), - editOp(1, 5, 1, 6, 0, ['']), - editOp(1, 9, 1, 9, 0, ['', '']) + editOp(1, 2, 1, 2, ['', ' ']), + editOp(1, 5, 1, 6, ['']), + editOp(1, 9, 1, 9, ['', '']) ], [ inverseEditOp(1, 2, 2, 3), @@ -265,11 +266,12 @@ suite('EditorModel - EditableTextModel._getInverseEdits', () => { suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { - function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeLength: number, text: string[]): IValidatedEditOperation { + function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeOffset: number, rangeLength: number, text: string[]): IValidatedEditOperation { return { sortIndex: 0, identifier: null, range: new Range(startLineNumber, startColumn, endLineNumber, endColumn), + rangeOffset: rangeOffset, rangeLength: rangeLength, lines: text, forceMoveMarkers: false, @@ -297,9 +299,9 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '1' ], [ - editOp(1, 3, 1, 3, 0, [' new line', 'No longer']) + editOp(1, 3, 1, 3, 2, 0, [' new line', 'No longer']) ], - editOp(1, 3, 1, 3, 0, [' new line', 'No longer']) + editOp(1, 3, 1, 3, 2, 0, [' new line', 'No longer']) ); }); @@ -311,11 +313,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '', '1' ], [ - editOp(1, 1, 1, 3, 0, ['Your']), - editOp(1, 4, 1, 4, 0, ['Interesting ']), - editOp(2, 3, 2, 6, 0, null) + editOp(1, 1, 1, 3, 0, 2, ['Your']), + editOp(1, 4, 1, 4, 3, 0, ['Interesting ']), + editOp(2, 3, 2, 6, 16, 3, null) ], - editOp(1, 1, 2, 6, 19, [ + editOp(1, 1, 2, 6, 0, 19, [ 'Your Interesting First Line', '\t\t' ])); @@ -331,10 +333,10 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '1' ], [ - editOp(1, 3, 1, 3, 0, ['', '', '', '', '']), - editOp(3, 15, 3, 15, 0, ['a', 'b']) + editOp(1, 3, 1, 3, 2, 0, ['', '', '', '', '']), + editOp(3, 15, 3, 15, 45, 0, ['a', 'b']) ], - editOp(1, 3, 3, 15, 43, [ + editOp(1, 3, 3, 15, 2, 43, [ '', '', '', @@ -357,9 +359,9 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '1' ], [ - editOp(1, 1, 1, 1, 0, ['']) + editOp(1, 1, 1, 1, 0, 0, ['']) ], - editOp(1, 1, 1, 1, 0, ['']) + editOp(1, 1, 1, 1, 0, 0, ['']) ); }); @@ -373,10 +375,10 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '123' ], [ - editOp(2, 1, 2, 3, 0, ['\t']), - editOp(3, 1, 3, 5, 0, ['']) + editOp(2, 1, 2, 3, 14, 2, ['\t']), + editOp(3, 1, 3, 5, 31, 4, ['']) ], - editOp(2, 1, 3, 5, 21, ['\tMy Second Line', '']) + editOp(2, 1, 3, 5, 14, 21, ['\tMy Second Line', '']) ); }); @@ -386,11 +388,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '{"x" : 1}' ], [ - editOp(1, 2, 1, 2, 0, ['\n ']), - editOp(1, 5, 1, 6, 0, ['']), - editOp(1, 9, 1, 9, 0, ['\n']) + editOp(1, 2, 1, 2, 1, 0, ['\n ']), + editOp(1, 5, 1, 6, 4, 1, ['']), + editOp(1, 9, 1, 9, 8, 0, ['\n']) ], - editOp(1, 2, 1, 9, 7, [ + editOp(1, 2, 1, 9, 1, 7, [ '', ' "x": 1', '' @@ -406,11 +408,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '}' ], [ - editOp(1, 2, 2, 3, 0, ['']), - editOp(2, 6, 2, 6, 0, [' ']), - editOp(2, 9, 3, 1, 0, ['']) + editOp(1, 2, 2, 3, 1, 3, ['']), + editOp(2, 6, 2, 6, 7, 0, [' ']), + editOp(2, 9, 3, 1, 10, 1, ['']) ], - editOp(1, 2, 3, 1, 10, ['"x" : 1']) + editOp(1, 2, 3, 1, 1, 10, ['"x" : 1']) ); }); @@ -424,10 +426,10 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { '}' ], [ - editOp(1, 2, 2, 1, 0, ['', '\t']), - editOp(2, 11, 4, 1, 0, ['', '\t']) + editOp(1, 2, 2, 1, 1, 1, ['', '\t']), + editOp(2, 11, 4, 1, 12, 2, ['', '\t']) ], - editOp(1, 2, 4, 1, 13, [ + editOp(1, 2, 4, 1, 1, 13, [ '', '\t"a": true,', '\t' @@ -446,12 +448,12 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { 'and the last line' ], [ - editOp(1, 5, 3, 1, 0, [' text', 'some more text', 'some more text']), - editOp(3, 2, 4, 1, 0, ['o more lines', 'asd', 'asd', 'asd']), - editOp(5, 1, 5, 6, 0, ['zzzzzzzz']), - editOp(5, 11, 6, 16, 0, ['1', '2', '3', '4']) + editOp(1, 5, 3, 1, 4, 21, [' text', 'some more text', 'some more text']), + editOp(3, 2, 4, 1, 26, 23, ['o more lines', 'asd', 'asd', 'asd']), + editOp(5, 1, 5, 6, 50, 5, ['zzzzzzzz']), + editOp(5, 11, 6, 16, 60, 22, ['1', '2', '3', '4']) ], - editOp(1, 5, 6, 16, 78, [ + editOp(1, 5, 6, 16, 4, 78, [ ' text', 'some more text', 'some more textno more lines', @@ -475,17 +477,17 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { ' ,"e": /*comment*/ [null] }', ], [ - editOp(1, 1, 1, 2, 0, ['']), - editOp(1, 3, 1, 10, 0, ['', ' ']), - editOp(1, 16, 2, 14, 0, ['', ' ']), - editOp(2, 18, 3, 9, 0, ['', ' ']), - editOp(3, 22, 4, 9, 0, ['']), - editOp(4, 10, 4, 10, 0, ['', ' ']), - editOp(4, 28, 4, 28, 0, ['', ' ']), - editOp(4, 32, 4, 32, 0, ['', ' ']), - editOp(4, 33, 4, 34, 0, ['', '']) + editOp(1, 1, 1, 2, 0, 1, ['']), + editOp(1, 3, 1, 10, 2, 7, ['', ' ']), + editOp(1, 16, 2, 14, 15, 14, ['', ' ']), + editOp(2, 18, 3, 9, 33, 9, ['', ' ']), + editOp(3, 22, 4, 9, 55, 9, ['']), + editOp(4, 10, 4, 10, 65, 0, ['', ' ']), + editOp(4, 28, 4, 28, 83, 0, ['', ' ']), + editOp(4, 32, 4, 32, 87, 0, ['', ' ']), + editOp(4, 33, 4, 34, 88, 1, ['', '']) ], - editOp(1, 1, 4, 34, 89, [ + editOp(1, 1, 4, 34, 0, 89, [ '{', ' "d": [', ' null', @@ -505,11 +507,11 @@ suite('EditorModel - EditableTextModel._toSingleEditOperation', () => { ' ,def' ], [ - editOp(1, 1, 1, 4, 0, ['']), - editOp(1, 7, 2, 2, 0, ['']), - editOp(2, 3, 2, 3, 0, ['', '']) + editOp(1, 1, 1, 4, 0, 3, ['']), + editOp(1, 7, 2, 2, 6, 2, ['']), + editOp(2, 3, 2, 3, 9, 0, ['', '']) ], - editOp(1, 1, 2, 3, 9, [ + editOp(1, 1, 2, 3, 0, 9, [ 'abc,', '' ]) @@ -1567,7 +1569,6 @@ suite('EditorModel - EditableTextModel.applyEdits', () => { }); let assertMirrorModels = () => { - model._assertLineNumbersOK(); assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK'); assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK'); }; @@ -1579,257 +1580,3 @@ suite('EditorModel - EditableTextModel.applyEdits', () => { mirrorModel2.dispose(); }); }); - -interface ILightWeightMarker { - id: string; - lineNumber: number; - column: number; - stickToPreviousCharacter: boolean; -} - -suite('EditorModel - EditableTextModel.applyEdits & markers', () => { - - function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text: string[]): IIdentifiedSingleEditOperation { - return { - identifier: null, - range: new Range(startLineNumber, startColumn, endLineNumber, endColumn), - text: text.join('\n'), - forceMoveMarkers: false - }; - } - - function marker(id: string, lineNumber: number, column: number, stickToPreviousCharacter: boolean): ILightWeightMarker { - return { - id: id, - lineNumber: lineNumber, - column: column, - stickToPreviousCharacter: stickToPreviousCharacter - }; - } - - function toMarkersMap(markers: ILightWeightMarker[]): { [markerId: string]: ILightWeightMarker } { - var result: { [markerId: string]: ILightWeightMarker } = {}; - markers.forEach(m => { - result[m.id] = m; - }); - return result; - } - - function testApplyEditsAndMarkers(text: string[], markers: ILightWeightMarker[], edits: IIdentifiedSingleEditOperation[], changedMarkers: string[], expectedText: string[], expectedMarkers: ILightWeightMarker[]): void { - var textStr = text.join('\n'); - var expectedTextStr = expectedText.join('\n'); - var markersMap = toMarkersMap(markers); - // var expectedMarkersMap = toMarkersMap(expectedMarkers); - var markerId2ModelMarkerId = Object.create(null); - - var model = EditableTextModel.createFromString(textStr); - model.setEOL(EndOfLineSequence.LF); - - // Add markers - markers.forEach((m) => { - let modelMarkerId = model._addMarker(0, m.lineNumber, m.column, m.stickToPreviousCharacter); - markerId2ModelMarkerId[m.id] = modelMarkerId; - }); - - // Apply edits & collect inverse edits - model.applyEdits(edits); - model._assertLineNumbersOK(); - - // Assert edits produced expected result - assert.deepEqual(model.getValue(EndOfLinePreference.LF), expectedTextStr); - - let actualChangedMarkers: string[] = []; - for (let i = 0, len = expectedMarkers.length; i < len; i++) { - let expectedMarker = expectedMarkers[i]; - let initialMarker = markersMap[expectedMarker.id]; - let expectedMarkerModelMarkerId = markerId2ModelMarkerId[expectedMarker.id]; - let actualMarker = model._getMarker(expectedMarkerModelMarkerId); - - if (actualMarker.lineNumber !== initialMarker.lineNumber || actualMarker.column !== initialMarker.column) { - actualChangedMarkers.push(initialMarker.id); - } - - assert.equal(actualMarker.lineNumber, expectedMarker.lineNumber, 'marker lineNumber of marker ' + expectedMarker.id); - assert.equal(actualMarker.column, expectedMarker.column, 'marker column of marker ' + expectedMarker.id); - } - - changedMarkers.sort(); - actualChangedMarkers.sort(); - assert.deepEqual(actualChangedMarkers, changedMarkers, 'changed markers'); - - model.dispose(); - } - - test('no markers changed', () => { - testApplyEditsAndMarkers( - [ - 'Hello world,', - 'this is a short text', - 'that is used in testing' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 2, 1, false), - marker('f', 2, 16, true), - marker('g', 2, 21, true), - marker('h', 3, 24, false) - ], - [ - editOp(1, 13, 1, 13, [' how are you?']) - ], - [], - [ - 'Hello world, how are you?', - 'this is a short text', - 'that is used in testing' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 2, 1, false), - marker('f', 2, 16, true), - marker('g', 2, 21, true), - marker('h', 3, 24, false) - ] - ); - }); - - test('first line changes', () => { - testApplyEditsAndMarkers( - [ - 'Hello world,', - 'this is a short text', - 'that is used in testing' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 2, 1, false), - marker('f', 2, 16, true), - marker('g', 2, 21, true), - marker('h', 3, 24, false) - ], - [ - editOp(1, 7, 1, 12, ['friends']) - ], - [], - [ - 'Hello friends,', - 'this is a short text', - 'that is used in testing' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 2, 1, false), - marker('f', 2, 16, true), - marker('g', 2, 21, true), - marker('h', 3, 24, false) - ] - ); - }); - - test('inserting lines', () => { - testApplyEditsAndMarkers( - [ - 'Hello world,', - 'this is a short text', - 'that is used in testing' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 2, 1, false), - marker('f', 2, 16, true), - marker('g', 2, 21, true), - marker('h', 3, 24, false) - ], - [ - editOp(1, 7, 1, 12, ['friends']), - editOp(1, 13, 1, 13, ['', 'this is an inserted line', 'and another one. By the way,']) - ], - ['e', 'f', 'g', 'h'], - [ - 'Hello friends,', - 'this is an inserted line', - 'and another one. By the way,', - 'this is a short text', - 'that is used in testing' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 4, 1, false), - marker('f', 4, 16, true), - marker('g', 4, 21, true), - marker('h', 5, 24, false) - ] - ); - }); - - test('replacing a lot', () => { - testApplyEditsAndMarkers( - [ - 'Hello world,', - 'this is a short text', - 'that is used in testing', - 'more lines...', - 'more lines...', - 'more lines...', - 'more lines...' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 2, 1, false), - marker('f', 2, 16, true), - marker('g', 2, 21, true), - marker('h', 3, 24, false), - marker('i', 5, 1, false), - marker('j', 6, 1, false), - marker('k', 7, 14, false), - ], - [ - editOp(1, 7, 1, 12, ['friends']), - editOp(1, 13, 1, 13, ['', 'this is an inserted line', 'and another one. By the way,', 'This is another line']), - editOp(2, 1, 7, 14, ['Some new text here']) - ], - ['e', 'f', 'g', 'h', 'i', 'j', 'k'], - [ - 'Hello friends,', - 'this is an inserted line', - 'and another one. By the way,', - 'This is another line', - 'Some new text here' - ], - [ - marker('a', 1, 1, true), - marker('b', 1, 1, false), - marker('c', 1, 7, false), - marker('d', 1, 12, true), - marker('e', 5, 1, false), - marker('f', 5, 16, true), - marker('g', 5, 19, true), - marker('h', 5, 19, false), - marker('i', 5, 19, false), - marker('j', 5, 19, false), - marker('k', 5, 19, false), - ] - ); - }); -}); diff --git a/src/vs/editor/test/common/model/editableTextModelTestUtils.ts b/src/vs/editor/test/common/model/editableTextModelTestUtils.ts index a901d29fcd3..b0b18723062 100644 --- a/src/vs/editor/test/common/model/editableTextModelTestUtils.ts +++ b/src/vs/editor/test/common/model/editableTextModelTestUtils.ts @@ -105,7 +105,6 @@ export function assertSyncedModels(text: string, callback: (model: EditableTextM var assertMirrorModels = () => { assertLineMapping(model, 'model'); - model._assertLineNumbersOK(); assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK'); assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK'); }; diff --git a/src/vs/editor/test/common/model/indentRanges.test.ts b/src/vs/editor/test/common/model/indentRanges.test.ts index 55b5e1ad6dd..a703fcc42d5 100644 --- a/src/vs/editor/test/common/model/indentRanges.test.ts +++ b/src/vs/editor/test/common/model/indentRanges.test.ts @@ -7,62 +7,76 @@ import * as assert from 'assert'; import { Model } from 'vs/editor/common/model/model'; -import { computeRanges } from 'vs/editor/common/model/indentRanges'; +import { computeRanges, MAX_FOLDING_REGIONS } from 'vs/editor/common/model/indentRanges'; +import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration'; -export interface IndentRange { +export interface ExpectedIndentRange { startLineNumber: number; endLineNumber: number; indent: number; + parentIndex: number; +} + +function assertRanges(lines: string[], expected: ExpectedIndentRange[], offside: boolean, markers?: FoldingMarkers): void { + let model = Model.createFromString(lines.join('\n')); + let actual = computeRanges(model, offside, markers); + + let actualRanges = []; + for (let i = 0; i < actual.length; i++) { + actualRanges[i] = r(actual.getStartLineNumber(i), actual.getEndLineNumber(i), actual.getIndent(i), actual.getParentIndex(i)); + } + assert.deepEqual(actualRanges, expected); + model.dispose(); +} + +function r(startLineNumber: number, endLineNumber: number, indent: number, parentIndex: number, marker = false): ExpectedIndentRange { + return { startLineNumber, endLineNumber, indent, parentIndex }; } suite('Indentation Folding', () => { - function assertRanges(lines: string[], expected: IndentRange[]): void { - let model = Model.createFromString(lines.join('\n')); - let actual = computeRanges(model); - actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber); - assert.deepEqual(actual, expected); - model.dispose(); - } - - function r(startLineNumber: number, endLineNumber: number, indent: number): IndentRange { - return { startLineNumber, endLineNumber, indent }; - } - test('Fold one level', () => { - assertRanges([ + let range = [ 'A', ' A', ' A', ' A' - ], [r(1, 4, 0)]); + ]; + assertRanges(range, [r(1, 4, 0, -1)], true); + assertRanges(range, [r(1, 4, 0, -1)], false); }); test('Fold two levels', () => { - assertRanges([ + let range = [ 'A', ' A', ' A', ' A', ' A' - ], [r(1, 5, 0), r(3, 5, 2)]); + ]; + assertRanges(range, [r(1, 5, 0, -1), r(3, 5, 2, 0)], true); + assertRanges(range, [r(1, 5, 0, -1), r(3, 5, 2, 0)], false); }); test('Fold three levels', () => { - assertRanges([ + let range = [ 'A', ' A', ' A', ' A', 'A' - ], [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)]); + ]; + assertRanges(range, [r(1, 4, 0, -1), r(2, 4, 2, 0), r(3, 4, 4, 1)], true); + assertRanges(range, [r(1, 4, 0, -1), r(2, 4, 2, 0), r(3, 4, 4, 1)], false); }); test('Fold decreasing indent', () => { - assertRanges([ + let range = [ ' A', ' A', 'A' - ], []); + ]; + assertRanges(range, [], true); + assertRanges(range, [], false); }); test('Fold Java', () => { @@ -80,7 +94,7 @@ suite('Indentation Folding', () => { /*11*/ 'interface B {', /*12*/ ' void bar();', /*13*/ '}', - ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)]); + ], [r(1, 9, 0, -1), r(2, 4, 2, 0), r(7, 8, 2, 0), r(11, 12, 0, -1)], false); }); test('Fold Javadoc', () => { @@ -92,9 +106,9 @@ suite('Indentation Folding', () => { /* 5*/ ' void foo() {', /* 6*/ ' }', /* 7*/ '}', - ], [r(1, 3, 0), r(4, 6, 0)]); + ], [r(1, 3, 0, -1), r(4, 6, 0, -1)], false); }); - test('Fold Whitespace', () => { + test('Fold Whitespace Java', () => { assertRanges([ /* 1*/ 'class A {', /* 2*/ '', @@ -104,7 +118,20 @@ suite('Indentation Folding', () => { /* 6*/ ' }', /* 7*/ ' ', /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 2)]); + ], [r(1, 7, 0, -1), r(3, 5, 2, 0)], false); + }); + + test('Fold Whitespace Python', () => { + assertRanges([ + /* 1*/ 'def a:', + /* 2*/ ' pass', + /* 3*/ ' ', + /* 4*/ ' def b:', + /* 5*/ ' pass', + /* 6*/ ' ', + /* 7*/ ' ', + /* 8*/ 'def c: # since there was a deintent here' + ], [r(1, 5, 0, -1), r(4, 5, 2, 0)], true); }); test('Fold Tabs', () => { @@ -117,6 +144,245 @@ suite('Indentation Folding', () => { /* 6*/ ' \t}', /* 7*/ ' ', /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 4)]); + ], [r(1, 7, 0, -1), r(3, 5, 4, 0)], false); }); }); + +let markers: FoldingMarkers = { + start: /^\s*#region\b/, + end: /^\s*#endregion\b/ +}; + +suite('Folding with regions', () => { + test('Inside region, indented', () => { + assertRanges([ + /* 1*/ 'class A {', + /* 2*/ ' #region', + /* 3*/ ' void foo() {', + /* 4*/ ' ', + /* 5*/ ' return 0;', + /* 6*/ ' }', + /* 7*/ ' #endregion', + /* 8*/ '}', + ], [r(1, 7, 0, -1), r(2, 7, 2, 0, true), r(3, 5, 2, 1)], false, markers); + }); + test('Inside region, not indented', () => { + assertRanges([ + /* 1*/ 'var x;', + /* 2*/ '#region', + /* 3*/ 'void foo() {', + /* 4*/ ' ', + /* 5*/ ' return 0;', + /* 6*/ ' }', + /* 7*/ '#endregion', + /* 8*/ '', + ], [r(2, 7, 0, -1, true), r(3, 6, 0, 0)], false, markers); + }); + test('Empty Regions', () => { + assertRanges([ + /* 1*/ 'var x;', + /* 2*/ '#region', + /* 3*/ '#endregion', + /* 4*/ '#region', + /* 5*/ '', + /* 6*/ '#endregion', + /* 7*/ 'var y;', + ], [r(2, 3, 0, -1, true), r(4, 6, 0, -1, true)], false, markers); + }); + test('Nested Regions', () => { + assertRanges([ + /* 1*/ 'var x;', + /* 2*/ '#region', + /* 3*/ '#region', + /* 4*/ '', + /* 5*/ '#endregion', + /* 6*/ '#endregion', + /* 7*/ 'var y;', + ], [r(2, 6, 0, -1, true), r(3, 5, 0, 0, true)], false, markers); + }); + test('Nested Regions 2', () => { + assertRanges([ + /* 1*/ 'class A {', + /* 2*/ ' #region', + /* 3*/ '', + /* 4*/ ' #region', + /* 5*/ '', + /* 6*/ ' #endregion', + /* 7*/ ' // comment', + /* 8*/ ' #endregion', + /* 9*/ '}', + ], [r(1, 8, 0, -1), r(2, 8, 2, 0, true), r(4, 6, 2, 1, true)], false, markers); + }); + test('Incomplete Regions', () => { + assertRanges([ + /* 1*/ 'class A {', + /* 2*/ '#region', + /* 3*/ ' // comment', + /* 4*/ '}', + ], [r(2, 3, 0, -1)], false, markers); + }); + test('Incomplete Regions 2', () => { + assertRanges([ + /* 1*/ '', + /* 2*/ '#region', + /* 3*/ '#region', + /* 4*/ '#region', + /* 5*/ ' // comment', + /* 6*/ '#endregion', + /* 7*/ '#endregion', + /* 8*/ ' // hello', + ], [r(3, 7, 0, -1, true), r(4, 6, 0, 0, true)], false, markers); + }); + test('Indented region before', () => { + assertRanges([ + /* 1*/ 'if (x)', + /* 2*/ ' return;', + /* 3*/ '', + /* 4*/ '#region', + /* 5*/ ' // comment', + /* 6*/ '#endregion', + ], [r(1, 3, 0, -1), r(4, 6, 0, -1, true)], false, markers); + }); + test('Indented region before 2', () => { + assertRanges([ + /* 1*/ 'if (x)', + /* 2*/ ' log();', + /* 3*/ '', + /* 4*/ ' #region', + /* 5*/ ' // comment', + /* 6*/ ' #endregion', + ], [r(1, 6, 0, -1), r(2, 6, 2, 0), r(4, 6, 4, 1, true)], false, markers); + }); + test('Indented region in-between', () => { + assertRanges([ + /* 1*/ '#region', + /* 2*/ ' // comment', + /* 3*/ ' if (x)', + /* 4*/ ' return;', + /* 5*/ '', + /* 6*/ '#endregion', + ], [r(1, 6, 0, -1, true), r(3, 5, 2, 0)], false, markers); + }); + test('Indented region after', () => { + assertRanges([ + /* 1*/ '#region', + /* 2*/ ' // comment', + /* 3*/ '', + /* 4*/ '#endregion', + /* 5*/ ' if (x)', + /* 6*/ ' return;', + ], [r(1, 4, 0, -1, true), r(5, 6, 2, -1)], false, markers); + }); + test('With off-side', () => { + assertRanges([ + /* 1*/ '#region', + /* 2*/ ' ', + /* 3*/ '', + /* 4*/ '#endregion', + /* 5*/ '', + ], [r(1, 4, 0, -1, true)], true, markers); + }); + test('Nested with off-side', () => { + assertRanges([ + /* 1*/ '#region', + /* 2*/ ' ', + /* 3*/ '#region', + /* 4*/ '', + /* 5*/ '#endregion', + /* 6*/ '', + /* 7*/ '#endregion', + /* 8*/ '', + ], [r(1, 7, 0, -1, true), r(3, 5, 0, 0, true)], true, markers); + }); + test('Issue 35981', () => { + assertRanges([ + /* 1*/ 'function thisFoldsToEndOfPage() {', + /* 2*/ ' const variable = []', + /* 3*/ ' // #region', + /* 4*/ ' .reduce((a, b) => a,[]);', + /* 5*/ '}', + /* 6*/ '', + /* 7*/ 'function thisFoldsProperly() {', + /* 8*/ ' const foo = "bar"', + /* 9*/ '}', + ], [r(1, 4, 0, -1), r(2, 4, 2, 0), r(7, 8, 0, -1)], false, markers); + }); + test('Misspelled Markers', () => { + assertRanges([ + /* 1*/ '#Region', + /* 2*/ '#endregion', + /* 3*/ '#regionsandmore', + /* 4*/ '#endregion', + /* 5*/ '#region', + /* 6*/ '#end region', + /* 7*/ '#region', + /* 8*/ '#endregionff', + ], [], true, markers); + }); + + test('test max folding regions', () => { + let lines = []; + let nRegions = MAX_FOLDING_REGIONS; + for (let i = 0; i < nRegions; i++) { + lines.push('#region'); + } + for (let i = 0; i < nRegions; i++) { + lines.push('#endregion'); + } + let model = Model.createFromString(lines.join('\n')); + let actual = computeRanges(model, false, markers, MAX_FOLDING_REGIONS); + assert.equal(actual.length, nRegions, 'len'); + for (let i = 0; i < nRegions; i++) { + assert.equal(actual.getStartLineNumber(i), i + 1, 'start' + i); + assert.equal(actual.getEndLineNumber(i), nRegions * 2 - i, 'end' + i); + assert.equal(actual.getParentIndex(i), i - 1, 'parent' + i); + } + + }); + + test('findRange', () => { + let lines = [ + /* 1*/ '#region', + /* 2*/ '#endregion', + /* 3*/ 'class A {', + /* 4*/ ' void foo() {', + /* 5*/ ' if (true) {', + /* 6*/ ' return;', + /* 7*/ ' }', + /* 8*/ '', + /* 9*/ ' if (true) {', + /* 10*/ ' return;', + /* 11*/ ' }', + /* 12*/ ' }', + /* 13*/ '}']; + + let textModel = Model.createFromString(lines.join('\n')); + try { + let actual = computeRanges(textModel, false, markers); + // let r0 = r(1, 2); + // let r1 = r(3, 12); + // let r2 = r(4, 11); + // let r3 = r(5, 6); + // let r4 = r(9, 10); + + assert.equal(actual.findRange(1), 0, '1'); + assert.equal(actual.findRange(2), 0, '2'); + assert.equal(actual.findRange(3), 1, '3'); + assert.equal(actual.findRange(4), 2, '4'); + assert.equal(actual.findRange(5), 3, '5'); + assert.equal(actual.findRange(6), 3, '6'); + assert.equal(actual.findRange(7), 2, '7'); + assert.equal(actual.findRange(8), 2, '8'); + assert.equal(actual.findRange(9), 4, '9'); + assert.equal(actual.findRange(10), 4, '10'); + assert.equal(actual.findRange(11), 2, '11'); + assert.equal(actual.findRange(12), 1, '12'); + assert.equal(actual.findRange(13), -1, '13'); + } finally { + textModel.dispose(); + } + + + }); + +}); \ No newline at end of file diff --git a/src/vs/editor/test/common/model/intervalTree.test.ts b/src/vs/editor/test/common/model/intervalTree.test.ts new file mode 100644 index 00000000000..29a5978432e --- /dev/null +++ b/src/vs/editor/test/common/model/intervalTree.test.ts @@ -0,0 +1,555 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IntervalTree, IntervalNode } from 'vs/editor/common/model/intervalTree'; + +const GENERATE_TESTS = false; +let TEST_COUNT = GENERATE_TESTS ? 10000 : 0; +let PRINT_TREE = false; +const MIN_INTERVAL_START = 1; +const MAX_INTERVAL_END = 100; +const MIN_INSERTS = 1; +const MAX_INSERTS = 30; +const MIN_CHANGE_CNT = 10; +const MAX_CHANGE_CNT = 20; + +suite('IntervalTree', () => { + + class Interval { + _intervalBrand: void; + + public start: number; + public end: number; + + constructor(start: number, end: number) { + this.start = start; + this.end = end; + } + } + + class Oracle { + public intervals: Interval[]; + + constructor() { + this.intervals = []; + } + + public insert(interval: Interval): Interval { + this.intervals.push(interval); + this.intervals.sort((a, b) => { + if (a.start === b.start) { + return a.end - b.end; + } + return a.start - b.start; + }); + return interval; + } + + public delete(interval: Interval): void { + for (let i = 0, len = this.intervals.length; i < len; i++) { + if (this.intervals[i] === interval) { + this.intervals.splice(i, 1); + return; + } + } + } + + public search(interval: Interval): Interval[] { + let result: Interval[] = []; + for (let i = 0, len = this.intervals.length; i < len; i++) { + let int = this.intervals[i]; + if (int.start <= interval.end && int.end >= interval.start) { + result.push(int); + } + } + return result; + } + } + + class TestState { + private _oracle: Oracle = new Oracle(); + private _tree: IntervalTree = new IntervalTree(); + private _lastNodeId = -1; + private _treeNodes: IntervalNode[] = []; + private _oracleNodes: Interval[] = []; + + public acceptOp(op: IOperation): void { + + if (op.type === 'insert') { + if (PRINT_TREE) { + console.log(`insert: {${JSON.stringify(new Interval(op.begin, op.end))}}`); + } + let nodeId = (++this._lastNodeId); + this._treeNodes[nodeId] = new IntervalNode(null, op.begin, op.end); + this._tree.insert(this._treeNodes[nodeId]); + this._oracleNodes[nodeId] = this._oracle.insert(new Interval(op.begin, op.end)); + } else if (op.type === 'delete') { + if (PRINT_TREE) { + console.log(`delete: {${JSON.stringify(this._oracleNodes[op.id])}}`); + } + this._tree.delete(this._treeNodes[op.id]); + this._oracle.delete(this._oracleNodes[op.id]); + + this._treeNodes[op.id] = null; + this._oracleNodes[op.id] = null; + } else if (op.type === 'change') { + + this._tree.delete(this._treeNodes[op.id]); + this._treeNodes[op.id].reset(0, op.begin, op.end, null); + this._tree.insert(this._treeNodes[op.id]); + + this._oracle.delete(this._oracleNodes[op.id]); + this._oracleNodes[op.id].start = op.begin; + this._oracleNodes[op.id].end = op.end; + this._oracle.insert(this._oracleNodes[op.id]); + + } else { + let actualNodes = this._tree.intervalSearch(op.begin, op.end, 0, false, 0); + let actual = actualNodes.map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd)); + let expected = this._oracle.search(new Interval(op.begin, op.end)); + assert.deepEqual(actual, expected); + return; + } + + if (PRINT_TREE) { + this._tree.print(); + } + + this._tree.assertInvariants(); + + let actual = this._tree.getAllInOrder().map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd)); + let expected = this._oracle.intervals; + assert.deepEqual(actual, expected); + } + + public getExistingNodeId(index: number): number { + let currIndex = -1; + for (let i = 0; i < this._treeNodes.length; i++) { + if (this._treeNodes[i] === null) { + continue; + } + currIndex++; + if (currIndex === index) { + return i; + } + } + throw new Error('unexpected'); + } + } + + interface IInsertOperation { + type: 'insert'; + begin: number; + end: number; + } + + interface IDeleteOperation { + type: 'delete'; + id: number; + } + + interface IChangeOperation { + type: 'change'; + id: number; + begin: number; + end: number; + } + + interface ISearchOperation { + type: 'search'; + begin: number; + end: number; + } + + type IOperation = IInsertOperation | IDeleteOperation | IChangeOperation | ISearchOperation; + + function testIntervalTree(ops: IOperation[]): void { + let state = new TestState(); + for (let i = 0; i < ops.length; i++) { + state.acceptOp(ops[i]); + } + } + + function getRandomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + function getRandomRange(min: number, max: number): [number, number] { + let begin = getRandomInt(min, max); + let length: number; + if (getRandomInt(1, 10) <= 2) { + // large range + length = getRandomInt(0, max - begin); + } else { + // small range + length = getRandomInt(0, Math.min(max - begin, 10)); + } + return [begin, begin + length]; + } + + class AutoTest { + private _ops: IOperation[] = []; + private _state: TestState = new TestState(); + private _insertCnt: number; + private _deleteCnt: number; + private _changeCnt: number; + + constructor() { + this._insertCnt = getRandomInt(MIN_INSERTS, MAX_INSERTS); + this._changeCnt = getRandomInt(MIN_CHANGE_CNT, MAX_CHANGE_CNT); + this._deleteCnt = 0; + } + + private _doRandomInsert(): void { + let range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END); + this._run({ + type: 'insert', + begin: range[0], + end: range[1] + }); + } + + private _doRandomDelete(): void { + let idx = getRandomInt(Math.floor(this._deleteCnt / 2), this._deleteCnt - 1); + this._run({ + type: 'delete', + id: this._state.getExistingNodeId(idx) + }); + } + + private _doRandomChange(): void { + let idx = getRandomInt(0, this._deleteCnt - 1); + let range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END); + this._run({ + type: 'change', + id: this._state.getExistingNodeId(idx), + begin: range[0], + end: range[1] + }); + } + + public run() { + while (this._insertCnt > 0 || this._deleteCnt > 0 || this._changeCnt > 0) { + if (this._insertCnt > 0) { + this._doRandomInsert(); + this._insertCnt--; + this._deleteCnt++; + } else if (this._changeCnt > 0) { + this._doRandomChange(); + this._changeCnt--; + } else { + this._doRandomDelete(); + this._deleteCnt--; + } + + // Let's also search for something... + let searchRange = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END); + this._run({ + type: 'search', + begin: searchRange[0], + end: searchRange[1] + }); + } + } + + private _run(op: IOperation): void { + this._ops.push(op); + this._state.acceptOp(op); + } + + public print(): void { + console.log(`testIntervalTree(${JSON.stringify(this._ops)})`); + } + + } + + suite('generated', () => { + test('gen01', () => { + testIntervalTree([ + { type: 'insert', begin: 28, end: 35 }, + { type: 'insert', begin: 52, end: 54 }, + { type: 'insert', begin: 63, end: 69 } + ]); + }); + + test('gen02', () => { + testIntervalTree([ + { type: 'insert', begin: 80, end: 89 }, + { type: 'insert', begin: 92, end: 100 }, + { type: 'insert', begin: 99, end: 99 } + ]); + }); + + test('gen03', () => { + testIntervalTree([ + { type: 'insert', begin: 89, end: 96 }, + { type: 'insert', begin: 71, end: 74 }, + { type: 'delete', id: 1 } + ]); + }); + + test('gen04', () => { + testIntervalTree([ + { type: 'insert', begin: 44, end: 46 }, + { type: 'insert', begin: 85, end: 88 }, + { type: 'delete', id: 0 } + ]); + }); + + test('gen05', () => { + testIntervalTree([ + { type: 'insert', begin: 82, end: 90 }, + { type: 'insert', begin: 69, end: 73 }, + { type: 'delete', id: 0 }, + { type: 'delete', id: 1 } + ]); + }); + + test('gen06', () => { + testIntervalTree([ + { type: 'insert', begin: 41, end: 63 }, + { type: 'insert', begin: 98, end: 98 }, + { type: 'insert', begin: 47, end: 51 }, + { type: 'delete', id: 2 } + ]); + }); + + test('gen07', () => { + testIntervalTree([ + { type: 'insert', begin: 24, end: 26 }, + { type: 'insert', begin: 11, end: 28 }, + { type: 'insert', begin: 27, end: 30 }, + { type: 'insert', begin: 80, end: 85 }, + { type: 'delete', id: 1 } + ]); + }); + + test('gen08', () => { + testIntervalTree([ + { type: 'insert', begin: 100, end: 100 }, + { type: 'insert', begin: 100, end: 100 } + ]); + }); + + test('gen09', () => { + testIntervalTree([ + { type: 'insert', begin: 58, end: 65 }, + { type: 'insert', begin: 82, end: 96 }, + { type: 'insert', begin: 58, end: 65 } + ]); + }); + + test('gen10', () => { + testIntervalTree([ + { type: 'insert', begin: 32, end: 40 }, + { type: 'insert', begin: 25, end: 29 }, + { type: 'insert', begin: 24, end: 32 } + ]); + }); + + test('gen11', () => { + testIntervalTree([ + { type: 'insert', begin: 25, end: 70 }, + { type: 'insert', begin: 99, end: 100 }, + { type: 'insert', begin: 46, end: 51 }, + { type: 'insert', begin: 57, end: 57 }, + { type: 'delete', id: 2 } + ]); + }); + + test('gen12', () => { + testIntervalTree([ + { type: 'insert', begin: 20, end: 26 }, + { type: 'insert', begin: 10, end: 18 }, + { type: 'insert', begin: 99, end: 99 }, + { type: 'insert', begin: 37, end: 59 }, + { type: 'delete', id: 2 } + ]); + }); + + test('gen13', () => { + testIntervalTree([ + { type: 'insert', begin: 3, end: 91 }, + { type: 'insert', begin: 57, end: 57 }, + { type: 'insert', begin: 35, end: 44 }, + { type: 'insert', begin: 72, end: 81 }, + { type: 'delete', id: 2 } + ]); + }); + + test('gen14', () => { + testIntervalTree([ + { type: 'insert', begin: 58, end: 61 }, + { type: 'insert', begin: 34, end: 35 }, + { type: 'insert', begin: 56, end: 62 }, + { type: 'insert', begin: 69, end: 78 }, + { type: 'delete', id: 0 } + ]); + }); + + test('gen15', () => { + testIntervalTree([ + { type: 'insert', begin: 63, end: 69 }, + { type: 'insert', begin: 17, end: 24 }, + { type: 'insert', begin: 3, end: 13 }, + { type: 'insert', begin: 84, end: 94 }, + { type: 'insert', begin: 18, end: 23 }, + { type: 'insert', begin: 96, end: 98 }, + { type: 'delete', id: 1 } + ]); + }); + + test('gen16', () => { + testIntervalTree([ + { type: 'insert', begin: 27, end: 27 }, + { type: 'insert', begin: 42, end: 87 }, + { type: 'insert', begin: 42, end: 49 }, + { type: 'insert', begin: 69, end: 71 }, + { type: 'insert', begin: 20, end: 27 }, + { type: 'insert', begin: 8, end: 9 }, + { type: 'insert', begin: 42, end: 49 }, + { type: 'delete', id: 1 } + ]); + }); + + test('gen17', () => { + testIntervalTree([ + { type: 'insert', begin: 21, end: 23 }, + { type: 'insert', begin: 83, end: 87 }, + { type: 'insert', begin: 56, end: 58 }, + { type: 'insert', begin: 1, end: 55 }, + { type: 'insert', begin: 56, end: 59 }, + { type: 'insert', begin: 58, end: 60 }, + { type: 'insert', begin: 56, end: 65 }, + { type: 'delete', id: 1 }, + { type: 'delete', id: 0 }, + { type: 'delete', id: 6 } + ]); + }); + + test('gen18', () => { + testIntervalTree([ + { type: 'insert', begin: 25, end: 25 }, + { type: 'insert', begin: 67, end: 79 }, + { type: 'delete', id: 0 }, + { type: 'search', begin: 65, end: 75 } + ]); + }); + + test('force delta overflow', () => { + // Search the IntervalNode ctor for FORCE_OVERFLOWING_TEST + // to force that this test leads to a delta normalization + testIntervalTree([ + { type: 'insert', begin: 686081138593427, end: 733009856502260 }, + { type: 'insert', begin: 591031326181669, end: 591031326181672 }, + { type: 'insert', begin: 940037682731896, end: 940037682731903 }, + { type: 'insert', begin: 598413641151120, end: 598413641151128 }, + { type: 'insert', begin: 800564156553344, end: 800564156553351 }, + { type: 'insert', begin: 894198957565481, end: 894198957565491 } + ]); + }); + }); + + // TEST_COUNT = 0; + // PRINT_TREE = true; + + for (let i = 0; i < TEST_COUNT; i++) { + if (i % 100 === 0) { + console.log(`TEST ${i + 1}/${TEST_COUNT}`); + } + let test = new AutoTest(); + + try { + test.run(); + } catch (err) { + console.log(err); + test.print(); + return; + } + } + + suite('searching', () => { + + function createCormenTree(): IntervalTree { + let r = new IntervalTree(); + let data: [number, number][] = [ + [16, 21], + [8, 9], + [25, 30], + [5, 8], + [15, 23], + [17, 19], + [26, 26], + [0, 3], + [6, 10], + [19, 20] + ]; + data.forEach((int) => { + let node = new IntervalNode(null, int[0], int[1]); + r.insert(node); + }); + return r; + } + + const T = createCormenTree(); + + function assertIntervalSearch(start: number, end: number, expected: [number, number][]): void { + let actualNodes = T.intervalSearch(start, end, 0, false, 0); + let actual = actualNodes.map((n) => <[number, number]>[n.cachedAbsoluteStart, n.cachedAbsoluteEnd]); + assert.deepEqual(actual, expected); + } + + test('cormen 1->2', () => { + assertIntervalSearch( + 1, 2, + [ + [0, 3], + ] + ); + }); + + test('cormen 4->8', () => { + assertIntervalSearch( + 4, 8, + [ + [5, 8], + [6, 10], + [8, 9], + ] + ); + }); + + test('cormen 10->15', () => { + assertIntervalSearch( + 10, 15, + [ + [6, 10], + [15, 23], + ] + ); + }); + + test('cormen 21->25', () => { + assertIntervalSearch( + 21, 25, + [ + [15, 23], + [16, 21], + [25, 30], + ] + ); + }); + + test('cormen 24->24', () => { + assertIntervalSearch( + 24, 24, + [ + ] + ); + }); + }); +}); diff --git a/src/vs/editor/test/common/model/model.line.test.ts b/src/vs/editor/test/common/model/model.line.test.ts index 81dbba468d5..b493063ecf5 100644 --- a/src/vs/editor/test/common/model/model.line.test.ts +++ b/src/vs/editor/test/common/model/model.line.test.ts @@ -6,9 +6,8 @@ import * as assert from 'assert'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; -import { ModelLine, ILineEdit, LineMarker, MarkersTracker } from 'vs/editor/common/model/modelLine'; +import { ModelLine, ILineEdit, computeIndentLevel } from 'vs/editor/common/model/modelLine'; import { MetadataConsts } from 'vs/editor/common/modes'; -import { Position } from 'vs/editor/common/core/position'; import { ViewLineToken, ViewLineTokenFactory } from 'vs/editor/common/core/viewLineToken'; function assertLineTokens(_actual: LineTokens, _expected: TestToken[]): void { @@ -23,12 +22,9 @@ function assertLineTokens(_actual: LineTokens, _expected: TestToken[]): void { assert.deepEqual(actual.map(decode), expected.map(decode)); } -const NO_TAB_SIZE = 0; - suite('ModelLine - getIndentLevel', () => { function assertIndentLevel(text: string, expected: number, tabSize: number = 4): void { - let modelLine = new ModelLine(text, tabSize); - let actual = modelLine.getIndentLevel(); + let actual = computeIndentLevel(text, tabSize); assert.equal(actual, expected, text); } @@ -53,8 +49,8 @@ suite('ModelLine - getIndentLevel', () => { suite('Editor Model - modelLine.applyEdits text', () => { function testEdits(initial: string, edits: ILineEdit[], expected: string): void { - var line = new ModelLine(initial, NO_TAB_SIZE); - line.applyEdits(new MarkersTracker(), edits, NO_TAB_SIZE); + var line = new ModelLine(initial); + line.applyEdits(edits); assert.equal(line.text, expected); } @@ -62,8 +58,7 @@ suite('Editor Model - modelLine.applyEdits text', () => { return { startColumn: startColumn, endColumn: endColumn, - text: text, - forceMoveMarkers: false + text: text }; } @@ -200,8 +195,8 @@ suite('Editor Model - modelLine.applyEdits text', () => { suite('Editor Model - modelLine.split text', () => { function testLineSplit(initial: string, splitColumn: number, expected1: string, expected2: string): void { - var line = new ModelLine(initial, NO_TAB_SIZE); - var newLine = line.split(new MarkersTracker(), splitColumn, false, NO_TAB_SIZE); + var line = new ModelLine(initial); + var newLine = line.split(splitColumn); assert.equal(line.text, expected1); assert.equal(newLine.text, expected2); } @@ -237,9 +232,9 @@ suite('Editor Model - modelLine.split text', () => { suite('Editor Model - modelLine.append text', () => { function testLineAppend(a: string, b: string, expected: string): void { - var line1 = new ModelLine(a, NO_TAB_SIZE); - var line2 = new ModelLine(b, NO_TAB_SIZE); - line1.append(new MarkersTracker(), 1, line2, NO_TAB_SIZE); + var line1 = new ModelLine(a); + var line2 = new ModelLine(b); + line1.append(line2); assert.equal(line1.text, expected); } @@ -298,23 +293,23 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { function testLineEditTokens(initialText: string, initialTokens: TestToken[], edits: ILineEdit[], expectedText: string, expectedTokens: TestToken[]): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); + let line = new ModelLine(initialText); line.setTokens(0, TestToken.toTokens(initialTokens)); - line.applyEdits(new MarkersTracker(), edits, NO_TAB_SIZE); + line.applyEdits(edits); assert.equal(line.text, expectedText); assertLineTokens(line.getTokens(0), expectedTokens); } test('insertion on empty line', () => { - let line = new ModelLine('some text', NO_TAB_SIZE); + let line = new ModelLine('some text'); line.setTokens(0, TestToken.toTokens([new TestToken(0, 1)])); - line.applyEdits(new MarkersTracker(), [{ startColumn: 1, endColumn: 10, text: '', forceMoveMarkers: false }], NO_TAB_SIZE); + line.applyEdits([{ startColumn: 1, endColumn: 10, text: '' }]); line.setTokens(0, new Uint32Array(0)); - line.applyEdits(new MarkersTracker(), [{ startColumn: 1, endColumn: 1, text: 'a', forceMoveMarkers: false }], NO_TAB_SIZE); + line.applyEdits([{ startColumn: 1, endColumn: 1, text: 'a' }]); assertLineTokens(line.getTokens(0), [new TestToken(0, 1)]); }); @@ -330,7 +325,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }], 'aabcd efgh', [ @@ -353,7 +347,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 2, endColumn: 2, text: 'x', - forceMoveMarkers: false }], 'axabcd efgh', [ @@ -376,7 +369,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 3, endColumn: 3, text: 'stu', - forceMoveMarkers: false }], 'axstuabcd efgh', [ @@ -399,7 +391,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 10, endColumn: 10, text: '\t', - forceMoveMarkers: false }], 'axstuabcd\t efgh', [ @@ -422,7 +413,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 12, endColumn: 12, text: 'dd', - forceMoveMarkers: false }], 'axstuabcd\t ddefgh', [ @@ -445,7 +435,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 18, endColumn: 18, text: 'xyz', - forceMoveMarkers: false }], 'axstuabcd\t ddefghxyz', [ @@ -468,7 +457,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 1, text: 'x', - forceMoveMarkers: false }], 'xaxstuabcd\t ddefghxyz', [ @@ -491,7 +479,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 22, endColumn: 22, text: 'x', - forceMoveMarkers: false }], 'xaxstuabcd\t ddefghxyzx', [ @@ -514,7 +501,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 2, endColumn: 2, text: '', - forceMoveMarkers: false }], 'xaxstuabcd\t ddefghxyzx', [ @@ -533,7 +519,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }], 'a', [ @@ -554,7 +539,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 4, endColumn: 7, text: '', - forceMoveMarkers: false }], 'abcghij', [ @@ -576,7 +560,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 4, endColumn: 4, text: 'hello', - forceMoveMarkers: false }], 'abchellodefghij', [ @@ -599,7 +582,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 2, text: '', - forceMoveMarkers: false }], 'bcd efgh', [ @@ -622,7 +604,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 2, endColumn: 4, text: '', - forceMoveMarkers: false }], 'ad efgh', [ @@ -645,7 +626,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 5, text: '', - forceMoveMarkers: false }], ' efgh', [ @@ -667,7 +647,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 5, endColumn: 6, text: '', - forceMoveMarkers: false }], 'abcdefgh', [ @@ -689,7 +668,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 5, endColumn: 7, text: '', - forceMoveMarkers: false }], 'abcdfgh', [ @@ -711,7 +689,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 5, endColumn: 10, text: '', - forceMoveMarkers: false }], 'abcd', [ @@ -732,7 +709,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 10, text: '', - forceMoveMarkers: false }], '', [ @@ -753,7 +729,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 1, text: '', - forceMoveMarkers: false }], 'abcd efgh', [ @@ -776,7 +751,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 3, text: '', - forceMoveMarkers: false }], 'cd efgh', [ @@ -799,7 +773,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 5, endColumn: 10, text: '', - forceMoveMarkers: false }], 'abcd', [ @@ -822,7 +795,6 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 6, text: 'Hi', - forceMoveMarkers: false }], 'Hi world, ciao', [ @@ -849,12 +821,10 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { startColumn: 1, endColumn: 6, text: 'Hi', - forceMoveMarkers: false }, { startColumn: 8, endColumn: 12, text: 'my friends', - forceMoveMarkers: false }], 'Hi wmy friends, ciao', [ @@ -870,10 +840,10 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { suite('Editor Model - modelLine.split text & tokens', () => { function testLineSplitTokens(initialText: string, initialTokens: TestToken[], splitColumn: number, expectedText1: string, expectedText2: string, expectedTokens: TestToken[]): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); + let line = new ModelLine(initialText); line.setTokens(0, TestToken.toTokens(initialTokens)); - let other = line.split(new MarkersTracker(), splitColumn, false, NO_TAB_SIZE); + let other = line.split(splitColumn); assert.equal(line.text, expectedText1); assert.equal(other.text, expectedText2); @@ -954,13 +924,13 @@ suite('Editor Model - modelLine.split text & tokens', () => { suite('Editor Model - modelLine.append text & tokens', () => { function testLineAppendTokens(aText: string, aTokens: TestToken[], bText: string, bTokens: TestToken[], expectedText: string, expectedTokens: TestToken[]): void { - let a = new ModelLine(aText, NO_TAB_SIZE); + let a = new ModelLine(aText); a.setTokens(0, TestToken.toTokens(aTokens)); - let b = new ModelLine(bText, NO_TAB_SIZE); + let b = new ModelLine(bText); b.setTokens(0, TestToken.toTokens(bTokens)); - a.append(new MarkersTracker(), 1, b, NO_TAB_SIZE); + a.append(b); assert.equal(a.text, expectedText); assertLineTokens(a.getTokens(0), expectedTokens); @@ -1071,1260 +1041,483 @@ suite('Editor Model - modelLine.append text & tokens', () => { }); }); -interface ILightWeightMarker { - id: string; - lineNumber: number; - column: number; - stickToPreviousCharacter: boolean; -} +suite('Editor Model - modelLine.applyEdits', () => { -suite('Editor Model - modelLine.applyEdits text & markers', () => { + function testLineEdit(initialText: string, edits: ILineEdit[], expectedText: string): void { + let line = new ModelLine(initialText); - function marker(id: number, column: number, stickToPreviousCharacter: boolean): LineMarker { - return new LineMarker(String(id), id, new Position(0, column), stickToPreviousCharacter); - } - - function toLightWeightMarker(marker: LineMarker): ILightWeightMarker { - return { - id: marker.id, - lineNumber: marker.position.lineNumber, - column: marker.position.column, - stickToPreviousCharacter: marker.stickToPreviousCharacter - }; - } - - function testLineEditMarkers(initialText: string, initialMarkers: LineMarker[], edits: ILineEdit[], expectedText: string, expectedChangedMarkers: number[], _expectedMarkers: LineMarker[]): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); - line.addMarkers(initialMarkers); - - let changedMarkers = new MarkersTracker(); - line.applyEdits(changedMarkers, edits, NO_TAB_SIZE); + line.applyEdits(edits); assert.equal(line.text, expectedText, 'text'); - - let actualMarkers = line.getMarkers().map(toLightWeightMarker); - let expectedMarkers = _expectedMarkers.map(toLightWeightMarker); - assert.deepEqual(actualMarkers, expectedMarkers, 'markers'); - - let actualChangedMarkers = changedMarkers.getDecorationIds(); - actualChangedMarkers.sort(); - assert.deepEqual(actualChangedMarkers, expectedChangedMarkers, 'changed markers'); } test('insertion: updates markers 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 1, endColumn: 1, text: 'abc', - forceMoveMarkers: false }], 'abcabcd efgh', - [2, 3, 4, 5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 4, false), - marker(3, 5, true), - marker(4, 5, false), - marker(5, 8, true), - marker(6, 8, false), - marker(7, 13, true), - marker(8, 13, false) - ] ); }); test('insertion: updates markers 2', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 2, endColumn: 2, text: 'abc', - forceMoveMarkers: false }], 'aabcbcd efgh', - [4, 5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 5, false), - marker(5, 8, true), - marker(6, 8, false), - marker(7, 13, true), - marker(8, 13, false) - ] ); }); test('insertion: updates markers 3', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 3, endColumn: 3, text: 'abc', - forceMoveMarkers: false }], 'ababccd efgh', - [5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 8, true), - marker(6, 8, false), - marker(7, 13, true), - marker(8, 13, false) - ] ); }); test('insertion: updates markers 4', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 5, endColumn: 5, text: 'abc', - forceMoveMarkers: false }], 'abcdabc efgh', - [6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 8, false), - marker(7, 13, true), - marker(8, 13, false) - ] ); }); test('insertion: updates markers 5', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 10, endColumn: 10, text: 'abc', - forceMoveMarkers: false }], 'abcd efghabc', - [8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 13, false) - ] ); }); test('insertion bis: updates markers 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }], 'aabcd efgh', - [2, 3, 4, 5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 2, false), - marker(3, 3, true), - marker(4, 3, false), - marker(5, 6, true), - marker(6, 6, false), - marker(7, 11, true), - marker(8, 11, false) - ] ); }); test('insertion bis: updates markers 2', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 2, endColumn: 2, text: 'a', - forceMoveMarkers: false }], 'aabcd efgh', - [4, 5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 3, false), - marker(5, 6, true), - marker(6, 6, false), - marker(7, 11, true), - marker(8, 11, false) - ] ); }); test('insertion bis: updates markers 3', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 3, endColumn: 3, text: 'a', - forceMoveMarkers: false }], 'abacd efgh', - [5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 6, true), - marker(6, 6, false), - marker(7, 11, true), - marker(8, 11, false) - ] ); }); test('insertion bis: updates markers 4', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 5, endColumn: 5, text: 'a', - forceMoveMarkers: false }], 'abcda efgh', - [6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 6, false), - marker(7, 11, true), - marker(8, 11, false) - ] ); }); test('insertion bis: updates markers 5', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 10, endColumn: 10, text: 'a', - forceMoveMarkers: false }], 'abcd efgha', - [8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 11, false) - ] ); }); test('insertion: does not move marker at column 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [marker(1, 1, true)], [{ startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }], 'aabcd efgh', - [], - [marker(1, 1, true)] ); }); test('insertion: does move marker at column 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [marker(1, 1, false)], [{ startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }], 'aabcd efgh', - [1], - [marker(1, 2, false)] ); }); test('insertion: two markers at column 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - ], [{ startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }], 'aabcd efgh', - [2], - [ - marker(1, 1, true), - marker(2, 2, false) - ] ); }); test('insertion: two markers at column 1 unsorted', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(2, 1, false), - marker(1, 1, true), - ], [{ startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }], 'aabcd efgh', - [2], - [ - marker(1, 1, true), - marker(2, 2, false) - ] ); }); test('deletion: updates markers 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 1, endColumn: 2, text: '', - forceMoveMarkers: false }], 'bcd efgh', - [3, 4, 5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 1, true), - marker(4, 1, false), - marker(5, 4, true), - marker(6, 4, false), - marker(7, 9, true), - marker(8, 9, false) - ] ); }); test('deletion: updates markers 2', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 1, endColumn: 4, text: '', - forceMoveMarkers: false }], 'd efgh', - [3, 4, 5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 1, true), - marker(4, 1, false), - marker(5, 2, true), - marker(6, 2, false), - marker(7, 7, true), - marker(8, 7, false) - ] ); }); test('deletion: updates markers 3', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 5, endColumn: 6, text: '', - forceMoveMarkers: false }], 'abcdefgh', - [7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 9, true), - marker(8, 9, false) - ] ); }); test('replace: updates markers 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], [{ startColumn: 1, endColumn: 1, text: 'a', - forceMoveMarkers: false }, { startColumn: 2, endColumn: 3, text: '', - forceMoveMarkers: false }], 'aacd efgh', - [2, 3, 4], - [ - marker(1, 1, true), - marker(2, 2, false), - marker(3, 3, true), - marker(4, 3, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ] ); }); test('delete near markers', () => { - testLineEditMarkers( + testLineEdit( 'abcd', - [ - marker(1, 3, true), - marker(2, 3, false) - ], [{ startColumn: 3, endColumn: 4, text: '', - forceMoveMarkers: false }], 'abd', - [], - [ - marker(1, 3, true), - marker(2, 3, false) - ] ); }); test('replace: updates markers 2', () => { - testLineEditMarkers( + testLineEdit( 'Hello world, how are you', - [ - marker(1, 1, false), - marker(2, 6, true), - marker(3, 14, false), - marker(4, 21, true) - ], [{ startColumn: 1, endColumn: 1, text: ' - ', - forceMoveMarkers: false }, { startColumn: 6, endColumn: 12, text: '', - forceMoveMarkers: false }, { startColumn: 22, endColumn: 25, text: 'things', - forceMoveMarkers: false }], ' - Hello, how are things', - [1, 2, 3, 4], - [ - marker(1, 4, false), - marker(2, 9, true), - marker(3, 11, false), - marker(4, 18, true) - ] ); }); test('sorts markers', () => { - testLineEditMarkers( + testLineEdit( 'Hello world, how are you', - [ - marker(4, 21, true), - marker(2, 6, true), - marker(1, 1, false), - marker(3, 14, false) - ], [{ startColumn: 1, endColumn: 1, text: ' - ', - forceMoveMarkers: false }, { startColumn: 6, endColumn: 12, text: '', - forceMoveMarkers: false }, { startColumn: 22, endColumn: 25, text: 'things', - forceMoveMarkers: false }], ' - Hello, how are things', - [1, 2, 3, 4], - [ - marker(1, 4, false), - marker(2, 9, true), - marker(3, 11, false), - marker(4, 18, true) - ] ); }); test('change text inside markers', () => { - testLineEditMarkers( + testLineEdit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 6, false), - marker(4, 10, true) - ], [{ startColumn: 6, endColumn: 10, text: '1234567', - forceMoveMarkers: false }], 'abcd 1234567', - [], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 6, false), - marker(4, 10, true) - ] ); }); test('inserting is different than replacing for markers part 1', () => { - testLineEditMarkers( + testLineEdit( 'abcd', - [ - marker(1, 2, false) - ], [{ startColumn: 2, endColumn: 2, text: 'INSERT', - forceMoveMarkers: false }], 'aINSERTbcd', - [1], - [ - marker(1, 8, false) - ] ); }); test('inserting is different than replacing for markers part 2', () => { - testLineEditMarkers( + testLineEdit( 'abcd', - [ - marker(1, 2, false) - ], [{ startColumn: 2, endColumn: 3, text: 'REPLACED', - forceMoveMarkers: false }], 'aREPLACEDcd', - [], - [ - marker(1, 2, false) - ] ); }); test('replacing the entire line with more text', () => { - testLineEditMarkers( + testLineEdit( 'this is a short text', - [ - marker(1, 1, false), - marker(2, 16, true), - ], [{ startColumn: 1, endColumn: 21, text: 'Some new text here', - forceMoveMarkers: false }], 'Some new text here', - [], - [ - marker(1, 1, false), - marker(2, 16, true), - ] ); }); test('replacing the entire line with less text', () => { - testLineEditMarkers( + testLineEdit( 'this is a short text', - [ - marker(1, 1, false), - marker(2, 16, true), - ], [{ startColumn: 1, endColumn: 21, text: 'ttt', - forceMoveMarkers: false }], 'ttt', - [2], - [ - marker(1, 1, false), - marker(2, 4, true), - ] ); }); test('replace selection', () => { - testLineEditMarkers( + testLineEdit( 'first', - [ - marker(1, 1, true), - marker(2, 6, false), - ], [{ startColumn: 1, endColumn: 6, text: 'something', - forceMoveMarkers: false }], 'something', - [2], - [ - marker(1, 1, true), - marker(2, 10, false), - ] ); }); }); -suite('Editor Model - modelLine.split text & markers', () => { +suite('Editor Model - modelLine.split', () => { - function marker(id: number, column: number, stickToPreviousCharacter: boolean): LineMarker { - return new LineMarker(String(id), id, new Position(0, column), stickToPreviousCharacter); - } + function testLineSplit(initialText: string, splitColumn: number, forceMoveMarkers: boolean, expectedText1: string, expectedText2: string): void { + let line = new ModelLine(initialText); - function toLightWeightMarker(marker: LineMarker): ILightWeightMarker { - return { - id: marker.id, - lineNumber: marker.position.lineNumber, - column: marker.position.column, - stickToPreviousCharacter: marker.stickToPreviousCharacter - }; - } - - function testLineSplitMarkers(initialText: string, initialMarkers: LineMarker[], splitColumn: number, forceMoveMarkers: boolean, expectedText1: string, expectedText2: string, expectedChangedMarkers: number[], _expectedMarkers1: LineMarker[], _expectedMarkers2: LineMarker[]): void { - let line = new ModelLine(initialText, NO_TAB_SIZE); - line.addMarkers(initialMarkers); - - let changedMarkers = new MarkersTracker(); - let otherLine = line.split(changedMarkers, splitColumn, forceMoveMarkers, NO_TAB_SIZE); + let otherLine = line.split(splitColumn); assert.equal(line.text, expectedText1, 'text'); assert.equal(otherLine.text, expectedText2, 'text'); - - let actualMarkers1 = line.getMarkers().map(toLightWeightMarker); - let expectedMarkers1 = _expectedMarkers1.map(toLightWeightMarker); - assert.deepEqual(actualMarkers1, expectedMarkers1, 'markers'); - - let actualMarkers2 = otherLine.getMarkers().map(toLightWeightMarker); - let expectedMarkers2 = _expectedMarkers2.map(toLightWeightMarker); - assert.deepEqual(actualMarkers2, expectedMarkers2, 'markers'); - - let actualChangedMarkers = changedMarkers.getDecorationIds(); - actualChangedMarkers.sort(); - assert.deepEqual(actualChangedMarkers, expectedChangedMarkers, 'changed markers'); } test('split at the beginning', () => { - testLineSplitMarkers( + testLineSplit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], 1, false, '', 'abcd efgh', - [], - [ - marker(1, 1, true) - ], - [ - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ] ); }); test('split at the beginning 2', () => { - testLineSplitMarkers( + testLineSplit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], 1, true, '', 'abcd efgh', - [], - [], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ] ); }); test('split at the end', () => { - testLineSplitMarkers( + testLineSplit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], 10, false, 'abcd efgh', '', - [8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - ], - [ - marker(8, 1, false) - ] ); }); test('split it the middle 1', () => { - testLineSplitMarkers( + testLineSplit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], 2, false, 'a', 'bcd efgh', - [4, 5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - ], - [ - marker(4, 1, false), - marker(5, 4, true), - marker(6, 4, false), - marker(7, 9, true), - marker(8, 9, false) - ] ); }); test('split it the middle 2', () => { - testLineSplitMarkers( + testLineSplit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], 3, false, 'ab', 'cd efgh', - [5, 6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - ], - [ - marker(5, 3, true), - marker(6, 3, false), - marker(7, 8, true), - marker(8, 8, false) - ] ); }); test('split it the middle 3', () => { - testLineSplitMarkers( + testLineSplit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], 5, false, 'abcd', ' efgh', - [6, 7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - ], - [ - marker(6, 1, false), - marker(7, 6, true), - marker(8, 6, false) - ] ); }); test('split it the middle 4', () => { - testLineSplitMarkers( + testLineSplit( 'abcd efgh', - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - marker(7, 10, true), - marker(8, 10, false) - ], 6, false, 'abcd ', 'efgh', - [7, 8], - [ - marker(1, 1, true), - marker(2, 1, false), - marker(3, 2, true), - marker(4, 2, false), - marker(5, 5, true), - marker(6, 5, false), - ], - [ - marker(7, 5, true), - marker(8, 5, false) - ] ); }); }); -suite('Editor Model - modelLine.append text & markers', () => { +suite('Editor Model - modelLine.append', () => { - function markerOnFirstLine(id: number, column: number, stickToPreviousCharacter: boolean): LineMarker { - return new LineMarker(String(id), id, new Position(1, column), stickToPreviousCharacter); - } + function testLinePrependMarkers(aText: string, bText: string, expectedText: string): void { + let a = new ModelLine(aText); + let b = new ModelLine(bText); - function markerOnSecondLine(id: number, column: number, stickToPreviousCharacter: boolean): LineMarker { - return new LineMarker(String(id), id, new Position(2, column), stickToPreviousCharacter); - } - - function toLightWeightMarker(marker: LineMarker): ILightWeightMarker { - return { - id: marker.id, - lineNumber: marker.position.lineNumber, - column: marker.position.column, - stickToPreviousCharacter: marker.stickToPreviousCharacter - }; - } - - function testLinePrependMarkers(aText: string, aMarkers: LineMarker[], bText: string, bMarkers: LineMarker[], expectedText: string, expectedChangedMarkers: number[], _expectedMarkers: LineMarker[]): void { - let a = new ModelLine(aText, NO_TAB_SIZE); - a.addMarkers(aMarkers); - - let b = new ModelLine(bText, NO_TAB_SIZE); - b.addMarkers(bMarkers); - - let changedMarkers = new MarkersTracker(); - a.append(changedMarkers, 1, b, NO_TAB_SIZE); + a.append(b); assert.equal(a.text, expectedText, 'text'); - - let actualMarkers = a.getMarkers().map(toLightWeightMarker); - let expectedMarkers = _expectedMarkers.map(toLightWeightMarker); - assert.deepEqual(actualMarkers, expectedMarkers, 'markers'); - - let actualChangedMarkers = changedMarkers.getDecorationIds(); - actualChangedMarkers.sort(); - assert.deepEqual(actualChangedMarkers, expectedChangedMarkers, 'changed markers'); } test('append to an empty', () => { testLinePrependMarkers( 'abcd efgh', - [ - markerOnFirstLine(1, 1, true), - markerOnFirstLine(2, 1, false), - markerOnFirstLine(3, 2, true), - markerOnFirstLine(4, 2, false), - markerOnFirstLine(5, 5, true), - markerOnFirstLine(6, 5, false), - markerOnFirstLine(7, 10, true), - markerOnFirstLine(8, 10, false), - ], '', - [ - ], 'abcd efgh', - [], - [ - markerOnFirstLine(1, 1, true), - markerOnFirstLine(2, 1, false), - markerOnFirstLine(3, 2, true), - markerOnFirstLine(4, 2, false), - markerOnFirstLine(5, 5, true), - markerOnFirstLine(6, 5, false), - markerOnFirstLine(7, 10, true), - markerOnFirstLine(8, 10, false) - ] ); }); test('append an empty', () => { testLinePrependMarkers( '', - [ - ], 'abcd efgh', - [ - markerOnSecondLine(1, 1, true), - markerOnSecondLine(2, 1, false), - markerOnSecondLine(3, 2, true), - markerOnSecondLine(4, 2, false), - markerOnSecondLine(5, 5, true), - markerOnSecondLine(6, 5, false), - markerOnSecondLine(7, 10, true), - markerOnSecondLine(8, 10, false), - ], 'abcd efgh', - [1, 2, 3, 4, 5, 6, 7, 8], - [ - markerOnFirstLine(1, 1, true), - markerOnFirstLine(2, 1, false), - markerOnFirstLine(3, 2, true), - markerOnFirstLine(4, 2, false), - markerOnFirstLine(5, 5, true), - markerOnFirstLine(6, 5, false), - markerOnFirstLine(7, 10, true), - markerOnFirstLine(8, 10, false) - ] ); }); test('append 1', () => { testLinePrependMarkers( 'abcd', - [ - markerOnFirstLine(1, 1, true), - markerOnFirstLine(2, 1, false), - markerOnFirstLine(3, 2, true), - markerOnFirstLine(4, 2, false) - ], ' efgh', - [ - markerOnSecondLine(5, 1, true), - markerOnSecondLine(6, 1, false), - markerOnSecondLine(7, 6, true), - markerOnSecondLine(8, 6, false), - ], 'abcd efgh', - [5, 6, 7, 8], - [ - markerOnFirstLine(1, 1, true), - markerOnFirstLine(2, 1, false), - markerOnFirstLine(3, 2, true), - markerOnFirstLine(4, 2, false), - markerOnFirstLine(5, 5, true), - markerOnFirstLine(6, 5, false), - markerOnFirstLine(7, 10, true), - markerOnFirstLine(8, 10, false) - ] ); }); test('append 2', () => { testLinePrependMarkers( 'abcd e', - [ - markerOnFirstLine(1, 1, true), - markerOnFirstLine(2, 1, false), - markerOnFirstLine(3, 2, true), - markerOnFirstLine(4, 2, false), - markerOnFirstLine(5, 5, true), - markerOnFirstLine(6, 5, false) - ], 'fgh', - [ - markerOnSecondLine(7, 4, true), - markerOnSecondLine(8, 4, false), - ], 'abcd efgh', - [7, 8], - [ - markerOnFirstLine(1, 1, true), - markerOnFirstLine(2, 1, false), - markerOnFirstLine(3, 2, true), - markerOnFirstLine(4, 2, false), - markerOnFirstLine(5, 5, true), - markerOnFirstLine(6, 5, false), - markerOnFirstLine(7, 10, true), - markerOnFirstLine(8, 10, false) - ] ); }); }); diff --git a/src/vs/editor/test/common/model/modelDecorations.test.ts b/src/vs/editor/test/common/model/modelDecorations.test.ts index 1b2264090f0..ea402ff32c4 100644 --- a/src/vs/editor/test/common/model/modelDecorations.test.ts +++ b/src/vs/editor/test/common/model/modelDecorations.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; +import { IModelDeltaDecoration, TrackedRangeStickiness, EndOfLineSequence } from 'vs/editor/common/editorCommon'; import { Model } from 'vs/editor/common/model/model'; // --------- utils @@ -27,7 +27,8 @@ function modelHasDecorations(model: Model, decorations: ILightWeightDecoration2[ className: actualDecorations[i].options.className }); } - assert.deepEqual(modelDecorations, decorations, 'Model decorations'); + modelDecorations.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); + assert.deepEqual(modelDecorations, decorations); } function modelHasDecoration(model: Model, startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, className: string) { @@ -168,13 +169,13 @@ suite('Editor Model - Model Decorations', () => { var decId1 = addDecoration(thisModel, 1, 2, 3, 2, 'myType1'); var decId2 = addDecoration(thisModel, 1, 2, 3, 1, 'myType2'); modelHasDecorations(thisModel, [ - { - range: new Range(1, 2, 3, 2), - className: 'myType1' - }, { range: new Range(1, 2, 3, 1), className: 'myType2' + }, + { + range: new Range(1, 2, 3, 2), + className: 'myType1' } ]); thisModel.changeDecorations((changeAccessor) => { @@ -207,9 +208,6 @@ suite('Editor Model - Model Decorations', () => { let listenerCalled = 0; thisModel.onDidChangeDecorations((e) => { listenerCalled++; - assert.equal(e.addedDecorations.length, 1); - assert.equal(e.changedDecorations.length, 0); - assert.equal(e.removedDecorations.length, 0); }); addDecoration(thisModel, 1, 2, 3, 2, 'myType'); assert.equal(listenerCalled, 1, 'listener called'); @@ -220,10 +218,6 @@ suite('Editor Model - Model Decorations', () => { let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType'); thisModel.onDidChangeDecorations((e) => { listenerCalled++; - assert.equal(e.addedDecorations.length, 0); - assert.equal(e.changedDecorations.length, 1); - assert.equal(e.changedDecorations[0], decId); - assert.equal(e.removedDecorations.length, 0); }); thisModel.changeDecorations((changeAccessor) => { changeAccessor.changeDecoration(decId, new Range(1, 1, 1, 2)); @@ -236,10 +230,6 @@ suite('Editor Model - Model Decorations', () => { let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType'); thisModel.onDidChangeDecorations((e) => { listenerCalled++; - assert.equal(e.addedDecorations.length, 0); - assert.equal(e.changedDecorations.length, 0); - assert.equal(e.removedDecorations.length, 1); - assert.equal(e.removedDecorations[0], decId); }); thisModel.changeDecorations((changeAccessor) => { changeAccessor.removeDecoration(decId); @@ -249,20 +239,31 @@ suite('Editor Model - Model Decorations', () => { test('decorations emit event when inserting one line text before it', () => { let listenerCalled = 0; - let decId = addDecoration(thisModel, 1, 2, 3, 2, 'myType'); + addDecoration(thisModel, 1, 2, 3, 2, 'myType'); thisModel.onDidChangeDecorations((e) => { listenerCalled++; - assert.equal(e.addedDecorations.length, 0); - assert.equal(e.changedDecorations.length, 1); - assert.equal(e.changedDecorations[0], decId); - assert.equal(e.removedDecorations.length, 0); }); thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'Hallo ')]); assert.equal(listenerCalled, 1, 'listener called'); }); + test('decorations do not emit event on no-op deltaDecorations', () => { + let listenerCalled = 0; + + thisModel.onDidChangeDecorations((e) => { + listenerCalled++; + }); + + thisModel.deltaDecorations([], []); + thisModel.changeDecorations((accessor) => { + accessor.deltaDecorations([], []); + }); + + assert.equal(listenerCalled, 0, 'listener not called'); + }); + // --------- editing text & effects on decorations test('decorations are updated when inserting one line text before it', () => { @@ -365,6 +366,740 @@ suite('Editor Model - Model Decorations', () => { thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 1))]); modelHasDecoration(thisModel, 1, 1, 2, 1, 'myType'); }); + + test('decorations are updated when changing EOL', () => { + addDecoration(thisModel, 1, 2, 4, 1, 'myType1'); + addDecoration(thisModel, 1, 3, 4, 1, 'myType2'); + addDecoration(thisModel, 1, 4, 4, 1, 'myType3'); + addDecoration(thisModel, 1, 5, 4, 1, 'myType4'); + addDecoration(thisModel, 1, 6, 4, 1, 'myType5'); + addDecoration(thisModel, 1, 7, 4, 1, 'myType6'); + addDecoration(thisModel, 1, 8, 4, 1, 'myType7'); + addDecoration(thisModel, 1, 9, 4, 1, 'myType8'); + addDecoration(thisModel, 1, 10, 4, 1, 'myType9'); + thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'x')]); + thisModel.setEOL(EndOfLineSequence.CRLF); + thisModel.applyEdits([EditOperation.insert(new Position(1, 1), 'x')]); + modelHasDecorations(thisModel, [ + { range: new Range(1, 4, 4, 1), className: 'myType1' }, + { range: new Range(1, 5, 4, 1), className: 'myType2' }, + { range: new Range(1, 6, 4, 1), className: 'myType3' }, + { range: new Range(1, 7, 4, 1), className: 'myType4' }, + { range: new Range(1, 8, 4, 1), className: 'myType5' }, + { range: new Range(1, 9, 4, 1), className: 'myType6' }, + { range: new Range(1, 10, 4, 1), className: 'myType7' }, + { range: new Range(1, 11, 4, 1), className: 'myType8' }, + { range: new Range(1, 12, 4, 1), className: 'myType9' }, + ]); + }); + + test('an apparently simple edit', () => { + addDecoration(thisModel, 1, 2, 4, 1, 'myType1'); + thisModel.applyEdits([EditOperation.replace(new Range(1, 14, 2, 1), 'x')]); + modelHasDecorations(thisModel, [ + { range: new Range(1, 2, 3, 1), className: 'myType1' }, + ]); + }); + + test('removeAllDecorationsWithOwnerId can be called after model dispose', () => { + let model = Model.createFromString('asd'); + model.dispose(); + model.removeAllDecorationsWithOwnerId(1); + }); + + test('removeAllDecorationsWithOwnerId works', () => { + thisModel.deltaDecorations([], [{ range: new Range(1, 2, 4, 1), options: { className: 'myType1' } }], 1); + thisModel.removeAllDecorationsWithOwnerId(1); + modelHasNoDecorations(thisModel); + }); +}); + +suite('Decorations and editing', () => { + + function _runTest(decRange: Range, stickiness: TrackedRangeStickiness, editRange: Range, editText: string, editForceMoveMarkers: boolean, expectedDecRange: Range, msg: string): void { + let model = Model.createFromString([ + 'My First Line', + 'My Second Line', + 'Third Line' + ].join('\n')); + + const id = model.deltaDecorations([], [{ range: decRange, options: { stickiness: stickiness } }])[0]; + model.applyEdits([{ range: editRange, text: editText, forceMoveMarkers: editForceMoveMarkers, identifier: null }]); + const actual = model.getDecorationRange(id); + assert.deepEqual(actual, expectedDecRange, msg); + + model.dispose(); + } + + function runTest(decRange: Range, editRange: Range, editText: string, expectedDecRange: Range[][]): void { + _runTest(decRange, 0, editRange, editText, false, expectedDecRange[0][0], 'no-0-AlwaysGrowsWhenTypingAtEdges'); + _runTest(decRange, 1, editRange, editText, false, expectedDecRange[0][1], 'no-1-NeverGrowsWhenTypingAtEdges'); + _runTest(decRange, 2, editRange, editText, false, expectedDecRange[0][2], 'no-2-GrowsOnlyWhenTypingBefore'); + _runTest(decRange, 3, editRange, editText, false, expectedDecRange[0][3], 'no-3-GrowsOnlyWhenTypingAfter'); + + _runTest(decRange, 0, editRange, editText, true, expectedDecRange[1][0], 'force-0-AlwaysGrowsWhenTypingAtEdges'); + _runTest(decRange, 1, editRange, editText, true, expectedDecRange[1][1], 'force-1-NeverGrowsWhenTypingAtEdges'); + _runTest(decRange, 2, editRange, editText, true, expectedDecRange[1][2], 'force-2-GrowsOnlyWhenTypingBefore'); + _runTest(decRange, 3, editRange, editText, true, expectedDecRange[1][3], 'force-3-GrowsOnlyWhenTypingAfter'); + } + + suite('insert', () => { + suite('collapsed dec', () => { + test('before', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 3), 'xx', + [ + [new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)], + [new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)], + ] + ); + }); + test('equal', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 4), 'xx', + [ + [new Range(1, 4, 1, 6), new Range(1, 6, 1, 6), new Range(1, 4, 1, 4), new Range(1, 6, 1, 6)], + [new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)], + ] + ); + }); + test('after', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 5), 'xx', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('before', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 3), 'xx', + [ + [new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)], + [new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)], + ] + ); + }); + test('start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 4), 'xx', + [ + [new Range(1, 4, 1, 11), new Range(1, 6, 1, 11), new Range(1, 4, 1, 11), new Range(1, 6, 1, 11)], + [new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)], + ] + ); + }); + test('inside', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 5), 'xx', + [ + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)], + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)], + ] + ); + }); + test('end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 9), 'xx', + [ + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 11)], + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)], + ] + ); + }); + test('after', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 10), 'xx', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + ] + ); + }); + }); + }); + + suite('delete', () => { + suite('collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 1, 1, 3), '', + [ + [new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2)], + [new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 2, 1, 4), '', + [ + [new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2)], + [new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2), new Range(1, 2, 1, 2)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 5), '', + [ + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + ] + ); + }); + test('edit.start >= range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 6), '', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 7), '', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 1, 1, 3), '', + [ + [new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)], + [new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 2, 1, 4), '', + [ + [new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)], + [new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7), new Range(1, 2, 1, 7)], + ] + ); + }); + test('edit.start < range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 5), '', + [ + [new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7)], + [new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7), new Range(1, 3, 1, 7)], + ] + ); + }); + + test('edit.start < range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 9), '', + [ + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + ] + ); + }); + + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 10), '', + [ + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + ] + ); + }); + + test('edit.start == range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 6), '', + [ + [new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)], + [new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)], + ] + ); + }); + + test('edit.start == range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 9), '', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + + test('edit.start == range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 10), '', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + + test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 7), '', + [ + [new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)], + [new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)], + ] + ); + }); + + test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 9), '', + [ + [new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)], + [new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)], + ] + ); + }); + + test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 10), '', + [ + [new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)], + [new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)], + ] + ); + }); + + test('edit.start == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 11), '', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + ] + ); + }); + + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 11), '', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + ] + ); + }); + }); + }); + + suite('replace short', () => { + suite('collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 1, 1, 3), 'c', + [ + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 2, 1, 4), 'c', + [ + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + [new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3), new Range(1, 3, 1, 3)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 5), 'c', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + test('edit.start >= range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 6), 'c', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 7), 'c', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 1, 1, 3), 'c', + [ + [new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)], + [new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 2, 1, 4), 'c', + [ + [new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)], + [new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8), new Range(1, 3, 1, 8)], + ] + ); + }); + test('edit.start < range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 5), 'c', + [ + [new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)], + [new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)], + ] + ); + }); + test('edit.start < range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 9), 'c', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 10), 'c', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + test('edit.start == range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 6), 'c', + [ + [new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)], + [new Range(1, 5, 1, 8), new Range(1, 5, 1, 8), new Range(1, 5, 1, 8), new Range(1, 5, 1, 8)], + ] + ); + }); + test('edit.start == range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 9), 'c', + [ + [new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)], + [new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5)], + ] + ); + }); + test('edit.start == range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 10), 'c', + [ + [new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5), new Range(1, 4, 1, 5)], + [new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5), new Range(1, 5, 1, 5)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 7), 'c', + [ + [new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)], + [new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 9), 'c', + [ + [new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)], + [new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 10), 'c', + [ + [new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)], + [new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6), new Range(1, 4, 1, 6)], + ] + ); + }); + test('edit.start == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 11), 'c', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 10), new Range(1, 4, 1, 10), new Range(1, 4, 1, 10), new Range(1, 4, 1, 10)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 11), 'c', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + ] + ); + }); + }); + }); + + suite('replace long', () => { + suite('collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 1, 1, 3), 'cccc', + [ + [new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)], + [new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 2, 1, 4), 'cccc', + [ + [new Range(1, 4, 1, 6), new Range(1, 6, 1, 6), new Range(1, 4, 1, 4), new Range(1, 6, 1, 6)], + [new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6), new Range(1, 6, 1, 6)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 3, 1, 5), 'cccc', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7)], + ] + ); + }); + test('edit.start >= range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 4, 1, 6), 'cccc', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 4), + new Range(1, 5, 1, 7), 'cccc', + [ + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + [new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4), new Range(1, 4, 1, 4)], + ] + ); + }); + }); + suite('non-collapsed dec', () => { + test('edit.end < range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 1, 1, 3), 'cccc', + [ + [new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)], + [new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)], + ] + ); + }); + test('edit.end <= range.start', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 2, 1, 4), 'cccc', + [ + [new Range(1, 4, 1, 11), new Range(1, 6, 1, 11), new Range(1, 4, 1, 11), new Range(1, 6, 1, 11)], + [new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11), new Range(1, 6, 1, 11)], + ] + ); + }); + test('edit.start < range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 5), 'cccc', + [ + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)], + [new Range(1, 7, 1, 11), new Range(1, 7, 1, 11), new Range(1, 7, 1, 11), new Range(1, 7, 1, 11)], + ] + ); + }); + test('edit.start < range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 9), 'cccc', + [ + [new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)], + [new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7)], + ] + ); + }); + test('edit.start < range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 3, 1, 10), 'cccc', + [ + [new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7), new Range(1, 4, 1, 7)], + [new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7), new Range(1, 7, 1, 7)], + ] + ); + }); + test('edit.start == range.start && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 6), 'cccc', + [ + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)], + [new Range(1, 8, 1, 11), new Range(1, 8, 1, 11), new Range(1, 8, 1, 11), new Range(1, 8, 1, 11)], + ] + ); + }); + test('edit.start == range.start && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 9), 'cccc', + [ + [new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)], + [new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8)], + ] + ); + }); + test('edit.start == range.start && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 4, 1, 10), 'cccc', + [ + [new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8), new Range(1, 4, 1, 8)], + [new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8), new Range(1, 8, 1, 8)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end < range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 7), 'cccc', + [ + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)], + [new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11), new Range(1, 4, 1, 11)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 9), 'cccc', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + ] + ); + }); + test('edit.start > range.start && edit.start < range.end && edit.end > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 5, 1, 10), 'cccc', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + ] + ); + }); + test('edit.start == range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 9, 1, 11), 'cccc', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 13), new Range(1, 4, 1, 13), new Range(1, 4, 1, 13), new Range(1, 4, 1, 13)], + ] + ); + }); + test('edit.start > range.end', () => { + runTest( + new Range(1, 4, 1, 9), + new Range(1, 10, 1, 11), 'cccc', + [ + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + [new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9), new Range(1, 4, 1, 9)], + ] + ); + }); + }); + }); }); interface ILightWeightDecoration { @@ -420,7 +1155,6 @@ suite('deltaDecorations', () => { assert.equal(initialIds.length, decorations.length, 'returns expected cnt of ids'); assert.equal(initialIds.length, model.getAllDecorations().length, 'does not leak decorations'); assert.equal(initialIds.length, model._getTrackedRangesCount(), 'does not leak tracked ranges'); - assert.equal(2 * initialIds.length, model._getMarkersCount(), 'does not leak markers'); actualDecorations.sort((a, b) => strcmp(a.id, b.id)); decorations.sort((a, b) => strcmp(a.id, b.id)); assert.deepEqual(actualDecorations, decorations); @@ -431,7 +1165,6 @@ suite('deltaDecorations', () => { assert.equal(newIds.length, newDecorations.length, 'returns expected cnt of ids'); assert.equal(newIds.length, model.getAllDecorations().length, 'does not leak decorations'); assert.equal(newIds.length, model._getTrackedRangesCount(), 'does not leak tracked ranges'); - assert.equal(2 * newIds.length, model._getMarkersCount(), 'does not leak markers'); actualNewDecorations.sort((a, b) => strcmp(a.id, b.id)); newDecorations.sort((a, b) => strcmp(a.id, b.id)); assert.deepEqual(actualDecorations, decorations); diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index cba2a056eba..e36e11308e5 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -820,178 +820,4 @@ suite('TextModel.mightContainRTL', () => { assert.equal(model.mightContainRTL(), false); }); -}); - -suite('TextModel.getLineIndentGuide', () => { - function assertIndentGuides(lines: [number, string][]): void { - let text = lines.map(l => l[1]).join('\n'); - let model = TextModel.createFromString(text); - - let actual: [number, string][] = []; - for (let line = 1; line <= model.getLineCount(); line++) { - actual[line - 1] = [model.getLineIndentGuide(line), model.getLineContent(line)]; - } - - // let expected = lines.map(l => l[0]); - - assert.deepEqual(actual, lines); - - model.dispose(); - } - - test('getLineIndentGuide one level', () => { - assertIndentGuides([ - [0, 'A'], - [1, ' A'], - [1, ' A'], - [1, ' A'], - ]); - }); - - test('getLineIndentGuide two levels', () => { - assertIndentGuides([ - [0, 'A'], - [1, ' A'], - [1, ' A'], - [1, ' A'], - [1, ' A'], - ]); - }); - - test('getLineIndentGuide three levels', () => { - assertIndentGuides([ - [0, 'A'], - [1, ' A'], - [1, ' A'], - [2, ' A'], - [0, 'A'], - ]); - }); - - test('getLineIndentGuide decreasing indent', () => { - assertIndentGuides([ - [0, ' A'], - [0, ' A'], - [0, 'A'], - ]); - }); - - test('getLineIndentGuide Java', () => { - assertIndentGuides([ - /* 1*/[0, 'class A {'], - /* 2*/[1, ' void foo() {'], - /* 3*/[1, ' console.log(1);'], - /* 4*/[1, ' console.log(2);'], - /* 5*/[1, ' }'], - /* 6*/[1, ''], - /* 7*/[1, ' void bar() {'], - /* 8*/[1, ' console.log(3);'], - /* 9*/[1, ' }'], - /*10*/[0, '}'], - /*11*/[0, 'interface B {'], - /*12*/[1, ' void bar();'], - /*13*/[0, '}'], - ]); - }); - - test('getLineIndentGuide Javadoc', () => { - assertIndentGuides([ - [0, '/**'], - [1, ' * Comment'], - [1, ' */'], - [0, 'class A {'], - [1, ' void foo() {'], - [1, ' }'], - [0, '}'], - ]); - }); - - test('getLineIndentGuide Whitespace', () => { - assertIndentGuides([ - [0, 'class A {'], - [1, ''], - [1, ' void foo() {'], - [1, ' '], - [1, ' return 1;'], - [1, ' }'], - [1, ' '], - [0, '}'], - ]); - }); - - test('getLineIndentGuide Tabs', () => { - assertIndentGuides([ - [0, 'class A {'], - [1, '\t\t'], - [1, '\tvoid foo() {'], - [2, '\t \t//hello'], - [2, '\t return 2;'], - [1, ' \t}'], - [1, ' '], - [0, '}'], - ]); - }); - - test('getLineIndentGuide checker.ts', () => { - assertIndentGuides([ - /* 1*/[0, '/// '], - /* 2*/[0, ''], - /* 3*/[0, '/* @internal */'], - /* 4*/[0, 'namespace ts {'], - /* 5*/[1, ' let nextSymbolId = 1;'], - /* 6*/[1, ' let nextNodeId = 1;'], - /* 7*/[1, ' let nextMergeId = 1;'], - /* 8*/[1, ' let nextFlowId = 1;'], - /* 9*/[1, ''], - /*10*/[1, ' export function getNodeId(node: Node): number {'], - /*11*/[2, ' if (!node.id) {'], - /*12*/[3, ' node.id = nextNodeId;'], - /*13*/[3, ' nextNodeId++;'], - /*14*/[2, ' }'], - /*15*/[2, ' return node.id;'], - /*16*/[1, ' }'], - /*17*/[0, '}'], - ]); - }); - - test('issue #8425 - Missing indentation lines for first level indentation', () => { - assertIndentGuides([ - [1, '\tindent1'], - [2, '\t\tindent2'], - [2, '\t\tindent2'], - [1, '\tindent1'], - ]); - }); - - test('issue #8952 - Indentation guide lines going through text on .yml file', () => { - assertIndentGuides([ - [0, 'properties:'], - [1, ' emailAddress:'], - [2, ' - bla'], - [2, ' - length:'], - [3, ' max: 255'], - [0, 'getters:'], - ]); - }); - - test('issue #11892 - Indent guides look funny', () => { - assertIndentGuides([ - [0, 'function test(base) {'], - [1, '\tswitch (base) {'], - [2, '\t\tcase 1:'], - [3, '\t\t\treturn 1;'], - [2, '\t\tcase 2:'], - [3, '\t\t\treturn 2;'], - [1, '\t}'], - [0, '}'], - ]); - }); - - test('issue #12398 - Problem in indent guidelines', () => { - assertIndentGuides([ - [2, '\t\t.bla'], - [3, '\t\t\tlabel(for)'], - [0, 'include script'], - ]); - }); -}); +}); \ No newline at end of file diff --git a/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts index 6ac512096dd..1ee24bc97c7 100644 --- a/src/vs/editor/test/common/model/textModelWithTokens.test.ts +++ b/src/vs/editor/test/common/model/textModelWithTokens.test.ts @@ -359,3 +359,179 @@ suite('TextModelWithTokens regression tests', () => { registration.dispose(); }); }); + +suite('TextModel.getLineIndentGuide', () => { + function assertIndentGuides(lines: [number, string][]): void { + let text = lines.map(l => l[1]).join('\n'); + let model = Model.createFromString(text); + + let actualIndents = model.getLinesIndentGuides(1, model.getLineCount()); + + let actual: [number, string][] = []; + for (let line = 1; line <= model.getLineCount(); line++) { + actual[line - 1] = [actualIndents[line - 1], model.getLineContent(line)]; + } + + // let expected = lines.map(l => l[0]); + + assert.deepEqual(actual, lines); + + model.dispose(); + } + + test('getLineIndentGuide one level', () => { + assertIndentGuides([ + [0, 'A'], + [1, ' A'], + [1, ' A'], + [1, ' A'], + ]); + }); + + test('getLineIndentGuide two levels', () => { + assertIndentGuides([ + [0, 'A'], + [1, ' A'], + [1, ' A'], + [1, ' A'], + [1, ' A'], + ]); + }); + + test('getLineIndentGuide three levels', () => { + assertIndentGuides([ + [0, 'A'], + [1, ' A'], + [1, ' A'], + [2, ' A'], + [0, 'A'], + ]); + }); + + test('getLineIndentGuide decreasing indent', () => { + assertIndentGuides([ + [1, ' A'], + [1, ' A'], + [0, 'A'], + ]); + }); + + test('getLineIndentGuide Java', () => { + assertIndentGuides([ + /* 1*/[0, 'class A {'], + /* 2*/[1, ' void foo() {'], + /* 3*/[1, ' console.log(1);'], + /* 4*/[1, ' console.log(2);'], + /* 5*/[1, ' }'], + /* 6*/[1, ''], + /* 7*/[1, ' void bar() {'], + /* 8*/[1, ' console.log(3);'], + /* 9*/[1, ' }'], + /*10*/[0, '}'], + /*11*/[0, 'interface B {'], + /*12*/[1, ' void bar();'], + /*13*/[0, '}'], + ]); + }); + + test('getLineIndentGuide Javadoc', () => { + assertIndentGuides([ + [0, '/**'], + [1, ' * Comment'], + [1, ' */'], + [0, 'class A {'], + [1, ' void foo() {'], + [1, ' }'], + [0, '}'], + ]); + }); + + test('getLineIndentGuide Whitespace', () => { + assertIndentGuides([ + [0, 'class A {'], + [1, ''], + [1, ' void foo() {'], + [1, ' '], + [2, ' return 1;'], + [1, ' }'], + [1, ' '], + [0, '}'], + ]); + }); + + test('getLineIndentGuide Tabs', () => { + assertIndentGuides([ + [0, 'class A {'], + [1, '\t\t'], + [1, '\tvoid foo() {'], + [2, '\t \t//hello'], + [2, '\t return 2;'], + [1, ' \t}'], + [1, ' '], + [0, '}'], + ]); + }); + + test('getLineIndentGuide checker.ts', () => { + assertIndentGuides([ + /* 1*/[0, '/// '], + /* 2*/[0, ''], + /* 3*/[0, '/* @internal */'], + /* 4*/[0, 'namespace ts {'], + /* 5*/[1, ' let nextSymbolId = 1;'], + /* 6*/[1, ' let nextNodeId = 1;'], + /* 7*/[1, ' let nextMergeId = 1;'], + /* 8*/[1, ' let nextFlowId = 1;'], + /* 9*/[1, ''], + /*10*/[1, ' export function getNodeId(node: Node): number {'], + /*11*/[2, ' if (!node.id) {'], + /*12*/[3, ' node.id = nextNodeId;'], + /*13*/[3, ' nextNodeId++;'], + /*14*/[2, ' }'], + /*15*/[2, ' return node.id;'], + /*16*/[1, ' }'], + /*17*/[0, '}'], + ]); + }); + + test('issue #8425 - Missing indentation lines for first level indentation', () => { + assertIndentGuides([ + [1, '\tindent1'], + [2, '\t\tindent2'], + [2, '\t\tindent2'], + [1, '\tindent1'], + ]); + }); + + test('issue #8952 - Indentation guide lines going through text on .yml file', () => { + assertIndentGuides([ + [0, 'properties:'], + [1, ' emailAddress:'], + [2, ' - bla'], + [2, ' - length:'], + [3, ' max: 255'], + [0, 'getters:'], + ]); + }); + + test('issue #11892 - Indent guides look funny', () => { + assertIndentGuides([ + [0, 'function test(base) {'], + [1, '\tswitch (base) {'], + [2, '\t\tcase 1:'], + [3, '\t\t\treturn 1;'], + [2, '\t\tcase 2:'], + [3, '\t\t\treturn 2;'], + [1, '\t}'], + [0, '}'], + ]); + }); + + test('issue #12398 - Problem in indent guidelines', () => { + assertIndentGuides([ + [2, '\t\t.bla'], + [3, '\t\t\tlabel(for)'], + [0, 'include script'], + ]); + }); +}); diff --git a/src/vs/editor/test/common/modes/linkComputer.test.ts b/src/vs/editor/test/common/modes/linkComputer.test.ts index 6dcbc3c62a8..2988b948ac6 100644 --- a/src/vs/editor/test/common/modes/linkComputer.test.ts +++ b/src/vs/editor/test/common/modes/linkComputer.test.ts @@ -190,4 +190,11 @@ suite('Editor Modes - Link Computer', () => { ' http://***/_api/web/lists/GetByTitle(\'Teambuildingaanvragen\')/items ' ); }); + + test('issue #7855', () => { + assertLink( + '7. At this point, ServiceMain has been called. There is no functionality presently in ServiceMain, but you can consult the [MSDN documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms687414(v=vs.85).aspx) to add functionality as desired!', + ' https://msdn.microsoft.com/en-us/library/windows/desktop/ms687414(v=vs.85).aspx ' + ); + }); }); diff --git a/src/vs/editor/test/common/services/editorSimpleWorker.test.ts b/src/vs/editor/test/common/services/editorSimpleWorker.test.ts index a2ef365ea0b..0923605e55d 100644 --- a/src/vs/editor/test/common/services/editorSimpleWorker.test.ts +++ b/src/vs/editor/test/common/services/editorSimpleWorker.test.ts @@ -88,7 +88,7 @@ suite('EditorSimpleWorker', () => { test('MoreMinimal', function () { - return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: 'This is line One', range: new Range(1, 1, 1, 17) }], []).then(edits => { + return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: 'This is line One', range: new Range(1, 1, 1, 17) }]).then(edits => { assert.equal(edits.length, 1); const [first] = edits; assert.equal(first.text, 'O'); @@ -104,7 +104,7 @@ suite('EditorSimpleWorker', () => { '}' ], '\n'); - return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"a":1\r\n}', range: new Range(1, 1, 3, 2) }], []).then(edits => { + return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"a":1\r\n}', range: new Range(1, 1, 3, 2) }]).then(edits => { assert.equal(edits.length, 0); }); }); @@ -117,7 +117,7 @@ suite('EditorSimpleWorker', () => { '}' ], '\n'); - return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"b":1\r\n}', range: new Range(1, 1, 3, 2) }], []).then(edits => { + return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"b":1\r\n}', range: new Range(1, 1, 3, 2) }]).then(edits => { assert.equal(edits.length, 1); const [first] = edits; assert.equal(first.text, 'b'); @@ -133,7 +133,7 @@ suite('EditorSimpleWorker', () => { '}' // 3 ]); - return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '\n', range: new Range(3, 2, 4, 1000) }], []).then(edits => { + return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '\n', range: new Range(3, 2, 4, 1000) }]).then(edits => { assert.equal(edits.length, 1); const [first] = edits; assert.equal(first.text, '\n'); diff --git a/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts b/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts index 97397be1310..5ff3ab305e5 100644 --- a/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts +++ b/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts @@ -17,7 +17,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { test('Bug 9827:Overlapping inline decorations can cause wrong inline class to be applied', () => { - var result = LineDecorationsNormalizer.normalize([ + var result = LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 11, 'c1', false), new LineDecoration(3, 4, 'c2', false) ]); @@ -31,7 +31,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { test('issue #3462: no whitespace shown at the end of a decorated line', () => { - var result = LineDecorationsNormalizer.normalize([ + var result = LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(15, 21, 'vs-whitespace', false), new LineDecoration(20, 21, 'inline-folded', false), ]); @@ -55,7 +55,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { test('ViewLineParts', () => { - assert.deepEqual(LineDecorationsNormalizer.normalize([ + assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 2, 'c1', false), new LineDecoration(3, 4, 'c2', false) ]), [ @@ -63,7 +63,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { new DecorationSegment(2, 2, 'c2') ]); - assert.deepEqual(LineDecorationsNormalizer.normalize([ + assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 3, 'c1', false), new LineDecoration(3, 4, 'c2', false) ]), [ @@ -71,7 +71,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { new DecorationSegment(2, 2, 'c2') ]); - assert.deepEqual(LineDecorationsNormalizer.normalize([ + assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', false), new LineDecoration(3, 4, 'c2', false) ]), [ @@ -79,7 +79,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { new DecorationSegment(2, 2, 'c1 c2') ]); - assert.deepEqual(LineDecorationsNormalizer.normalize([ + assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', false), new LineDecoration(1, 4, 'c1*', false), new LineDecoration(3, 4, 'c2', false) @@ -88,7 +88,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { new DecorationSegment(2, 2, 'c1 c1* c2') ]); - assert.deepEqual(LineDecorationsNormalizer.normalize([ + assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', false), new LineDecoration(1, 4, 'c1*', false), new LineDecoration(1, 4, 'c1**', false), @@ -98,7 +98,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { new DecorationSegment(2, 2, 'c1 c1* c1** c2') ]); - assert.deepEqual(LineDecorationsNormalizer.normalize([ + assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', false), new LineDecoration(1, 4, 'c1*', false), new LineDecoration(1, 4, 'c1**', false), @@ -109,7 +109,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { new DecorationSegment(2, 2, 'c1 c1* c1** c2 c2*') ]); - assert.deepEqual(LineDecorationsNormalizer.normalize([ + assert.deepEqual(LineDecorationsNormalizer.normalize('abcabcabcabcabcabcabcabcabcabc', [ new LineDecoration(1, 4, 'c1', false), new LineDecoration(1, 4, 'c1*', false), new LineDecoration(1, 4, 'c1**', false), diff --git a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts index 6a0764cb3bd..132751193ef 100644 --- a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts +++ b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts @@ -1052,6 +1052,36 @@ suite('viewLineRenderer.renderLine 2', () => { assert.deepEqual(actual.html, expected); }); + test('issue #32436: Non-monospace font + visible whitespace + After decorator causes line to "jump"', () => { + + let lineContent = '\tbla'; + + let actual = renderViewLine(new RenderLineInput( + false, + lineContent, + false, + 0, + [createPart(4, 3)], + [new LineDecoration(2, 3, 'before', true)], + 4, + 10, + -1, + 'all', + false, + true + )); + + let expected = [ + '', + '\u2192\u00a0\u00a0\u00a0', + 'b', + 'la', + '' + ].join(''); + + assert.deepEqual(actual.html, expected); + }); + test('issue #30133: Empty lines don\'t render inline decorations', () => { let lineContent = ''; @@ -1080,6 +1110,33 @@ suite('viewLineRenderer.renderLine 2', () => { assert.deepEqual(actual.html, expected); }); + test('issue #37208: Collapsing bullet point containing emoji in Markdown document results in [??] character', () => { + + let actual = renderViewLine(new RenderLineInput( + true, + ' 1. šŸ™', + false, + 0, + [createPart(7, 3)], + [new LineDecoration(7, 8, 'inline-folded', true)], + 2, + 10, + 10000, + 'none', + false, + false + )); + + let expected = [ + '', + '\u00a0\u00a01.\u00a0', + 'šŸ™', + '' + ].join(''); + + assert.deepEqual(actual.html, expected); + }); + function createTestGetColumnOfLinePartOffset(lineContent: string, tabSize: number, parts: ViewLineToken[], expectedPartLengths: number[]): (partIndex: number, partLength: number, offset: number, expected: number) => void { let renderLineOutput = renderViewLine(new RenderLineInput( false, diff --git a/src/vs/editor/test/common/viewModel/characterHardWrappingLineMapper.test.ts b/src/vs/editor/test/common/viewModel/characterHardWrappingLineMapper.test.ts index 614295413ff..fb9c6978e74 100644 --- a/src/vs/editor/test/common/viewModel/characterHardWrappingLineMapper.test.ts +++ b/src/vs/editor/test/common/viewModel/characterHardWrappingLineMapper.test.ts @@ -7,9 +7,9 @@ import * as assert from 'assert'; import { WrappingIndent } from 'vs/editor/common/config/editorOptions'; import { CharacterHardWrappingLineMapperFactory } from 'vs/editor/common/viewModel/characterHardWrappingLineMapper'; -import { ILineMapperFactory } from 'vs/editor/common/viewModel/splitLinesCollection'; +import { ILineMapperFactory, ILineMapping } from 'vs/editor/common/viewModel/splitLinesCollection'; -function assertLineMapping(factory: ILineMapperFactory, tabSize: number, breakAfter: number, annotatedText: string, wrappingIndent = WrappingIndent.None) { +function assertLineMapping(factory: ILineMapperFactory, tabSize: number, breakAfter: number, annotatedText: string, wrappingIndent = WrappingIndent.None): ILineMapping { let rawText = ''; let currentLineIndex = 0; @@ -42,6 +42,8 @@ function assertLineMapping(factory: ILineMapperFactory, tabSize: number, breakAf } assert.equal(actualAnnotatedText, annotatedText); + + return mapper; } suite('Editor ViewModel - CharacterHardWrappingLineMapper', () => { @@ -106,4 +108,10 @@ suite('Editor ViewModel - CharacterHardWrappingLineMapper', () => { let factory = new CharacterHardWrappingLineMapperFactory('', ' ', ''); assertLineMapping(factory, 4, 24, 'a/ very/long/line/of/tex|t/that/expands/beyon|d/your/typical/line/|of/code/', WrappingIndent.Indent); }); + + test('issue #35162: wrappingIndent not consistently working', () => { + let factory = new CharacterHardWrappingLineMapperFactory('', ' ', ''); + let mapper = assertLineMapping(factory, 4, 24, ' t h i s |i s |a l |o n |g l |i n |e', WrappingIndent.Indent); + assert.equal(mapper.getWrappedLinesIndent(), ' \t'); + }); }); diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index cca084b0918..9b187cf4a63 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -136,15 +136,17 @@ suite('Editor ViewModel - SplitLinesCollection', () => { assert.equal(linesCollection.getViewLineCount(), 6); // getOutputIndentGuide - assert.equal(linesCollection.getViewLineIndentGuide(-1), 0); - assert.equal(linesCollection.getViewLineIndentGuide(0), 0); - assert.equal(linesCollection.getViewLineIndentGuide(1), 0); - assert.equal(linesCollection.getViewLineIndentGuide(2), 1); - assert.equal(linesCollection.getViewLineIndentGuide(3), 0); - assert.equal(linesCollection.getViewLineIndentGuide(4), 0); - assert.equal(linesCollection.getViewLineIndentGuide(5), 1); - assert.equal(linesCollection.getViewLineIndentGuide(6), 0); - assert.equal(linesCollection.getViewLineIndentGuide(7), 0); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(-1, -1), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(0, 0), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(1, 1), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(2, 2), [1]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(3, 3), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(4, 4), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(5, 5), [1]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(6, 6), [0]); + assert.deepEqual(linesCollection.getViewLinesIndentGuides(7, 7), [0]); + + assert.deepEqual(linesCollection.getViewLinesIndentGuides(0, 7), [0, 1, 0, 0, 1, 0]); // getOutputLineContent assert.equal(linesCollection.getViewLineContent(-1), 'int main() {'); diff --git a/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts index 0f52c5129c3..290e750f645 100644 --- a/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts +++ b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts @@ -25,21 +25,8 @@ suite('ViewModelDecorations', () => { assert.equal(viewModel.getLineContent(4), 'will be '); assert.equal(viewModel.getLineContent(5), 'wrapped'); - let dec1: string; - let dec2: string; - let dec3: string; - let dec4: string; - let dec5: string; - let dec6: string; - let dec7: string; - let dec8: string; - let dec9: string; - let dec10: string; - let dec11: string; - let dec12: string; - let dec13: string; - let dec14: string; - let dec15: string; + //@ts-ignore + let dec1, dec2, dec3, dec4, dec5, dec6, dec7, dec8, dec9, dec10, dec11, dec12, dec13, dec14, dec15: string; model.changeDecorations((accessor) => { let createOpts = (id: string) => { return { @@ -91,23 +78,23 @@ suite('ViewModelDecorations', () => { let actualDecorations = viewModel.getDecorationsInViewport( new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)) ).map((dec) => { - return dec.source.id; + return dec.options.className; }); assert.deepEqual(actualDecorations, [ - dec2, - dec3, - dec4, - dec5, - dec6, - dec7, - dec8, - dec9, - dec10, - dec11, - dec12, - dec13, - dec14, + 'dec2', + 'dec3', + 'dec4', + 'dec5', + 'dec6', + 'dec7', + 'dec8', + 'dec9', + 'dec10', + 'dec11', + 'dec12', + 'dec13', + 'dec14', ]); let inlineDecorations1 = viewModel.getViewLineRenderingData( @@ -280,6 +267,7 @@ suite('ViewModelDecorations', () => { assert.equal(viewModel.getLineContent(4), 'will be '); assert.equal(viewModel.getLineContent(5), 'wrapped'); + // @ts-ignore unused local let dec1: string; model.changeDecorations((accessor) => { dec1 = accessor.addDecoration( diff --git a/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts b/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts index 40c071085cd..665f07f72ef 100644 --- a/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts +++ b/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts @@ -41,4 +41,148 @@ suite('ViewModel', () => { assert.equal(viewModel.getLineCount(), 10); }); }); + + function assertGetPlainTextToCopy(text: string[], ranges: Range[], emptySelectionClipboard: boolean, expected: string): void { + testViewModel(text, {}, (viewModel, model) => { + let actual = viewModel.getPlainTextToCopy(ranges, emptySelectionClipboard); + assert.equal(actual, expected); + }); + } + + const USUAL_TEXT = [ + '', + 'line2', + 'line3', + 'line4', + '' + ]; + + test('getPlainTextToCopy 0/1', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2) + ], + false, + '' + ); + }); + + test('getPlainTextToCopy 0/1 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2) + ], + true, + 'line2\n' + ); + }); + + test('getPlainTextToCopy 1/1', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6) + ], + false, + 'ine2' + ); + }); + + test('getPlainTextToCopy 1/1 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6) + ], + true, + 'ine2' + ); + }); + + test('getPlainTextToCopy 0/2', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2), + new Range(3, 2, 3, 2), + ], + false, + '' + ); + }); + + test('getPlainTextToCopy 0/2 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2), + new Range(3, 2, 3, 2), + ], + true, + 'line2\nline3\n' + ); + }); + + test('getPlainTextToCopy 1/2', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6), + new Range(3, 2, 3, 2), + ], + false, + 'ine2' + ); + }); + + test('getPlainTextToCopy 1/2 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6), + new Range(3, 2, 3, 2), + ], + true, + 'ine2' + ); + }); + + test('getPlainTextToCopy 2/2', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6), + new Range(3, 2, 3, 6), + ], + false, + 'ine2\nine3' + ); + }); + + test('getPlainTextToCopy 2/2 reversed', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(3, 2, 3, 6), + new Range(2, 2, 2, 6), + ], + false, + 'ine2\nine3' + ); + }); + + test('getPlainTextToCopy 0/3 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2), + new Range(2, 3, 2, 3), + new Range(3, 2, 3, 2), + ], + true, + 'line2\nline3\n' + ); + }); }); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 6dafcfb3478..9142f59537b 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -61,7 +61,7 @@ declare module monaco { public static as(value: null): Promise; public static as(value: undefined): Promise; - public static as>(value: TPromise): TPromise; + public static as>(value: SomePromise): SomePromise; public static as(value: T): Promise; public static is(value: any): value is PromiseLike; @@ -109,7 +109,7 @@ declare module monaco { * * */ - export class Uri { + export class Uri implements UriComponents { static isUri(thing: any): thing is Uri; /** * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'. @@ -161,8 +161,16 @@ declare module monaco { * @param skipEncoding Do not encode the result, default is `false` */ toString(skipEncoding?: boolean): string; - toJSON(): any; - static revive(data: any): Uri; + toJSON(): object; + static revive(data: UriComponents | any): Uri; + } + + export interface UriComponents { + scheme: string; + authority: string; + path: string; + query: string; + fragment: string; } /** @@ -1188,10 +1196,6 @@ declare module monaco.editor { * Options associated with this decoration. */ readonly options: IModelDecorationOptions; - /** - * A flag describing if this is a problem decoration (e.g. warning/error). - */ - readonly isForValidation: boolean; } /** @@ -1641,12 +1645,6 @@ declare module monaco.editor { getWordUntilPosition(position: IPosition): IWordAtPosition; } - /** - * A model that can track markers. - */ - export interface ITextModelWithMarkers extends ITextModel { - } - /** * Describes the behavior of decorations when typing/editing near their edges. * Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior` @@ -1717,12 +1715,18 @@ declare module monaco.editor { * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors). */ getAllDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[]; + /** + * Gets all the decorations that should be rendered in the overview ruler as an array. + * @param ownerId If set, it will ignore decorations belonging to other owners. + * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors). + */ + getOverviewRulerDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[]; } /** * An editable text model. */ - export interface IEditableTextModel extends ITextModelWithMarkers { + export interface IEditableTextModel extends ITextModel { /** * Normalize a string containing whitespace according to indentation rules (converts to spaces or to tabs). */ @@ -1766,7 +1770,7 @@ declare module monaco.editor { /** * A model. */ - export interface IModel extends IReadOnlyModel, IEditableTextModel, ITextModelWithMarkers, ITokenizedModel, ITextModelWithDecorations { + export interface IModel extends IReadOnlyModel, IEditableTextModel, ITokenizedModel, ITextModelWithDecorations { /** * An event emitted when the contents of the model have changed. * @event @@ -1787,6 +1791,11 @@ declare module monaco.editor { * @event */ onDidChangeLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration associated with the model has changed. + * @event + */ + onDidChangeLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted right before disposing the model. * @event @@ -2185,6 +2194,11 @@ declare module monaco.editor { * @event */ onDidChangeModelLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration of the current model has changed. + * @event + */ + onDidChangeModelLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the options of the current model has changed. * @event @@ -2419,6 +2433,12 @@ declare module monaco.editor { readonly newLanguage: string; } + /** + * An event describing that the language configuration associated with a model has changed. + */ + export interface IModelLanguageConfigurationChangedEvent { + } + export interface IModelContentChange { /** * The range that got replaced. @@ -2466,18 +2486,6 @@ declare module monaco.editor { * An event describing that model decorations have changed. */ export interface IModelDecorationsChangedEvent { - /** - * Lists of ids for added decorations. - */ - readonly addedDecorations: string[]; - /** - * Lists of ids for changed decorations. - */ - readonly changedDecorations: string[]; - /** - * List of ids for removed decorations. - */ - readonly removedDecorations: string[]; } /** @@ -2683,6 +2691,17 @@ declare module monaco.editor { maxColumn?: number; } + /** + * Configuration options for editor minimap + */ + export interface IEditorLightbulbOptions { + /** + * Enable the lightbulb code action. + * Defaults to true. + */ + enabled?: boolean; + } + /** * Configuration options for the editor. */ @@ -2975,7 +2994,7 @@ declare module monaco.editor { * Accept suggestions on ENTER. * Defaults to 'on'. */ - acceptSuggestionOnEnter?: 'on' | 'smart' | 'off'; + acceptSuggestionOnEnter?: boolean | 'on' | 'smart' | 'off'; /** * Accept suggestions on provider defined characters. * Defaults to true. @@ -3018,6 +3037,10 @@ declare module monaco.editor { * Defaults to true. */ codeLens?: boolean; + /** + * Control the behavior and rendering of the code action lightbulb. + */ + lightbulb?: IEditorLightbulbOptions; /** * Enable code folding * Defaults to true in vscode and to false in monaco-editor. @@ -3296,6 +3319,7 @@ declare module monaco.editor { readonly matchBrackets: boolean; readonly find: InternalEditorFindOptions; readonly colorDecorators: boolean; + readonly lightbulbEnabled: boolean; } /** @@ -4140,6 +4164,10 @@ declare module monaco.languages { * A human-readable string that represents a doc-comment. */ documentation?: string; + /** + * A command that should be run upon acceptance of this item. + */ + command?: Command; /** * A string that should be used when comparing this item * with other items. When `falsy` the [label](#CompletionItem.label) @@ -4197,6 +4225,23 @@ declare module monaco.languages { items: CompletionItem[]; } + /** + * Contains additional information about the context in which + * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + */ + export interface CompletionContext { + /** + * How the completion was triggered. + */ + triggerKind: SuggestTriggerKind; + /** + * Character that triggered the completion item provider. + * + * `undefined` if provider was not triggered by a character. + */ + triggerCharacter?: string; + } + /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -4213,7 +4258,7 @@ declare module monaco.languages { /** * Provide completion items for the given position and document. */ - provideCompletionItems(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems(document: editor.IReadOnlyModel, position: Position, token: CancellationToken, context: CompletionContext): CompletionItem[] | Thenable | CompletionList | Thenable; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). @@ -4278,6 +4323,10 @@ declare module monaco.languages { * settings will be used. */ surroundingPairs?: IAutoClosingPair[]; + /** + * The language's folding rules. + */ + folding?: FoldingRules; /** * **Deprecated** Do not use. * @@ -4308,6 +4357,34 @@ declare module monaco.languages { unIndentedLinePattern?: RegExp; } + /** + * Describes language specific folding markers such as '#region' and '#endregion'. + * The start and end regexes will be tested against the contents of all lines and must be designed efficiently: + * - the regex should start with '^' + * - regexp flags (i, g) are ignored + */ + export interface FoldingMarkers { + start: RegExp; + end: RegExp; + } + + /** + * Describes folding rules for a language. + */ + export interface FoldingRules { + /** + * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. + * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. + * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. + * If not set, `false` is used and empty lines belong to the previous block. + */ + offSide?: boolean; + /** + * Region markers used by the language. + */ + markers?: FoldingMarkers; + } + /** * Describes a rule to be evaluated when pressing Enter. */ @@ -4445,6 +4522,14 @@ declare module monaco.languages { provideHover(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Hover | Thenable; } + /** + * How a suggest provider was triggered. + */ + export enum SuggestTriggerKind { + Invoke = 0, + TriggerCharacter = 1, + } + /** * Represents a parameter of a callable-signature. A parameter can * have a label and a doc-comment. @@ -4459,7 +4544,7 @@ declare module monaco.languages { * The human-readable doc-comment of this signature. Will be shown * in the UI but can be omitted. */ - documentation?: string; + documentation?: string | IMarkdownString; } /** @@ -4477,7 +4562,7 @@ declare module monaco.languages { * The human-readable doc-comment of this signature. Will be shown * in the UI but can be omitted. */ - documentation?: string; + documentation?: string | IMarkdownString; /** * The parameters of this signature. */ @@ -4807,17 +4892,31 @@ declare module monaco.languages { } /** - * A color formatter. + * String representations for a color */ - export interface IColorFormatter { - readonly supportsTransparency: boolean; - format(color: IColor): string; + export interface IColorPresentation { + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + label: string; + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. + */ + textEdit?: TextEdit; + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. + */ + additionalTextEdits?: TextEdit[]; } /** * A color range is a range in a text model which represents a color. */ - export interface IColorRange { + export interface IColorInformation { /** * The range within the model. */ @@ -4826,10 +4925,6 @@ declare module monaco.languages { * The color represented in this range. */ color: IColor; - /** - * The available formats for this specific color. - */ - formatters: IColorFormatter[]; } /** @@ -4839,7 +4934,11 @@ declare module monaco.languages { /** * Provides the color ranges for a specific model. */ - provideColorRanges(model: editor.IReadOnlyModel, token: CancellationToken): IColorRange[] | Thenable; + provideDocumentColors(model: editor.IReadOnlyModel, token: CancellationToken): IColorInformation[] | Thenable; + /** + * Provide the string representations for a color. + */ + provideColorPresentations(model: editor.IReadOnlyModel, colorInfo: IColorInformation, token: CancellationToken): IColorPresentation[] | Thenable; } export interface IResourceEdit { diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index e85b6fdd2a8..4f7f950ec97 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -24,6 +24,7 @@ export interface ICommandAction { title: string | ILocalizedString; category?: string | ILocalizedString; iconClass?: string; + iconPath?: string; } export interface IMenuItem { @@ -36,30 +37,29 @@ export interface IMenuItem { export class MenuId { - static readonly EditorTitle = new MenuId('1'); - static readonly EditorTitleContext = new MenuId('2'); - static readonly EditorContext = new MenuId('3'); - static readonly ExplorerContext = new MenuId('4'); - static readonly ProblemsPanelContext = new MenuId('5'); - static readonly DebugVariablesContext = new MenuId('6'); - static readonly DebugWatchContext = new MenuId('7'); - static readonly DebugCallStackContext = new MenuId('8'); - static readonly DebugBreakpointsContext = new MenuId('9'); - static readonly DebugConsoleContext = new MenuId('10'); - static readonly SCMTitle = new MenuId('11'); - static readonly SCMResourceGroupContext = new MenuId('12'); - static readonly SCMResourceContext = new MenuId('13'); - static readonly CommandPalette = new MenuId('14'); - static readonly ViewTitle = new MenuId('15'); - static readonly ViewItemContext = new MenuId('16'); + private static ID = 1; - constructor(private _id: string) { + static readonly EditorTitle = new MenuId(); + static readonly EditorTitleContext = new MenuId(); + static readonly EditorContext = new MenuId(); + static readonly ExplorerContext = new MenuId(); + static readonly ProblemsPanelContext = new MenuId(); + static readonly DebugVariablesContext = new MenuId(); + static readonly DebugWatchContext = new MenuId(); + static readonly DebugCallStackContext = new MenuId(); + static readonly DebugBreakpointsContext = new MenuId(); + static readonly DebugConsoleContext = new MenuId(); + static readonly SCMTitle = new MenuId(); + static readonly SCMSourceControl = new MenuId(); + static readonly SCMResourceGroupContext = new MenuId(); + static readonly SCMResourceContext = new MenuId(); + static readonly SCMChangeContext = new MenuId(); + static readonly CommandPalette = new MenuId(); + static readonly ViewTitle = new MenuId(); + static readonly ViewItemContext = new MenuId(); + static readonly TouchBarContext = new MenuId(); - } - - get id(): string { - return this._id; - } + readonly id: string = String(MenuId.ID++); } export interface IMenuActionOptions { @@ -88,7 +88,7 @@ export interface IMenuRegistry { getMenuItems(loc: MenuId): IMenuItem[]; } -export const MenuRegistry: IMenuRegistry = new class { +export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry { private _commands: { [id: string]: ICommandAction } = Object.create(null); diff --git a/src/vs/platform/actions/common/menu.ts b/src/vs/platform/actions/common/menu.ts index 1ea2c643b7f..6d0273668c0 100644 --- a/src/vs/platform/actions/common/menu.ts +++ b/src/vs/platform/actions/common/menu.ts @@ -21,6 +21,7 @@ export class Menu implements IMenu { private _onDidChange = new Emitter(); constructor( + // @ts-ignore unused property private _id: MenuId, startupSignal: TPromise, @ICommandService private _commandService: ICommandService, diff --git a/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts b/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts index 7801cc6e557..ca45e187101 100644 --- a/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/electron-browser/menusExtensionPoint.ts @@ -30,14 +30,17 @@ namespace schema { export function parseMenuId(value: string): MenuId { switch (value) { case 'commandPalette': return MenuId.CommandPalette; + case 'touchBar': return MenuId.TouchBarContext; case 'editor/title': return MenuId.EditorTitle; case 'editor/context': return MenuId.EditorContext; case 'explorer/context': return MenuId.ExplorerContext; case 'editor/title/context': return MenuId.EditorTitleContext; case 'debug/callstack/context': return MenuId.DebugCallStackContext; case 'scm/title': return MenuId.SCMTitle; + case 'scm/sourceControl': return MenuId.SCMSourceControl; case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext; case 'scm/resourceState/context': return MenuId.SCMResourceContext; + case 'scm/change/title': return MenuId.SCMChangeContext; case 'view/title': return MenuId.ViewTitle; case 'view/item/context': return MenuId.ViewItemContext; } @@ -104,6 +107,11 @@ namespace schema { type: 'array', items: menuItem }, + 'touchBar': { + description: localize('menus.touchBar', "The touch bar (macOS only)"), + type: 'array', + items: menuItem + }, 'editor/title': { description: localize('menus.editorTitle', "The editor title menu"), type: 'array', @@ -134,6 +142,11 @@ namespace schema { type: 'array', items: menuItem }, + 'scm/sourceControl': { + description: localize('menus.scmSourceControl', "The Source Control menu"), + type: 'array', + items: menuItem + }, 'scm/resourceGroup/context': { description: localize('menus.resourceGroupContext', "The Source Control resource group context menu"), type: 'array', @@ -278,20 +291,23 @@ ExtensionsRegistry.registerExtensionPoint { - const parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); + const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupservice'); const backupHome = path.join(parentDir, 'Backups'); const backupWorkspacesPath = path.join(backupHome, 'workspaces.json'); const environmentService = new EnvironmentService(parseArgs(process.argv), process.execPath); - const logService = new LogMainService(environmentService); class TestBackupMainService extends BackupMainService { constructor(backupHome: string, backupWorkspacesPath: string, configService: TestConfigurationService) { - super(environmentService, configService, new LogMainService(environmentService), new WorkspacesMainService(environmentService, logService)); + super(environmentService, configService, new LogMainService(environmentService)); this.backupHome = backupHome; this.workspacesJsonPath = backupWorkspacesPath; @@ -208,6 +207,33 @@ suite('BackupMainService', () => { assert.ok(fs.existsSync(path.join(workspaceBackupPath, 'backup.txt'))); assert.ok(!fs.existsSync(backupPathToMigrate)); + const emptyBackups = service.getEmptyWindowBackupPaths(); + assert.equal(0, emptyBackups.length); + + done(); + }); + + test('service backup migration makes sure to preserve existing backups', done => { + const backupPathToMigrate = service.toBackupPath(fooFile.fsPath); + fs.mkdirSync(backupPathToMigrate); + fs.writeFileSync(path.join(backupPathToMigrate, 'backup.txt'), 'Some Data'); + service.registerFolderBackupSync(backupPathToMigrate); + + const backupPathToPreserve = service.toBackupPath(barFile.fsPath); + fs.mkdirSync(backupPathToPreserve); + fs.writeFileSync(path.join(backupPathToPreserve, 'backup.txt'), 'Some Data'); + service.registerFolderBackupSync(backupPathToPreserve); + + const workspaceBackupPath = service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath), backupPathToMigrate); + + assert.ok(fs.existsSync(workspaceBackupPath)); + assert.ok(fs.existsSync(path.join(workspaceBackupPath, 'backup.txt'))); + assert.ok(!fs.existsSync(backupPathToMigrate)); + + const emptyBackups = service.getEmptyWindowBackupPaths(); + assert.equal(1, emptyBackups.length); + assert.equal(1, fs.readdirSync(path.join(backupHome, emptyBackups[0])).length); + done(); }); @@ -337,7 +363,8 @@ suite('BackupMainService', () => { assert.deepEqual(service.getEmptyWindowBackupPaths(), []); }); - test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => { + test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', function () { + this.timeout(5000); fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}'); service.loadSync(); assert.deepEqual(service.getEmptyWindowBackupPaths(), []); diff --git a/src/vs/platform/commands/common/commandService.ts b/src/vs/platform/commands/common/commandService.ts index fd249a6598d..59365d20b37 100644 --- a/src/vs/platform/commands/common/commandService.ts +++ b/src/vs/platform/commands/common/commandService.ts @@ -10,6 +10,7 @@ import { ICommandService, ICommand, ICommandEvent, CommandsRegistry } from 'vs/p import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import Event, { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export class CommandService extends Disposable implements ICommandService { @@ -22,7 +23,8 @@ export class CommandService extends Disposable implements ICommandService { constructor( @IInstantiationService private _instantiationService: IInstantiationService, - @IExtensionService private _extensionService: IExtensionService + @IExtensionService private _extensionService: IExtensionService, + @IContextKeyService private _contextKeyService: IContextKeyService ) { super(); this._extensionService.onReady().then(value => this._extensionHostIsReady = value); @@ -46,6 +48,11 @@ export class CommandService extends Disposable implements ICommandService { return TPromise.wrapError(new Error(`command '${id}' not found`)); } + if (command.precondition && !this._contextKeyService.contextMatchesRules(command.precondition)) { + // not enabled + return TPromise.wrapError(new Error('NOT_ENABLED')); + } + try { this._onWillExecuteCommand.fire({ commandId: id }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler].concat(args)); @@ -55,7 +62,7 @@ export class CommandService extends Disposable implements ICommandService { } } - protected _getCommand(id: string): ICommand { + private _getCommand(id: string): ICommand { return CommandsRegistry.getCommand(id); } } diff --git a/src/vs/platform/commands/common/commands.ts b/src/vs/platform/commands/common/commands.ts index b7539c0114b..bc6522256c0 100644 --- a/src/vs/platform/commands/common/commands.ts +++ b/src/vs/platform/commands/common/commands.ts @@ -9,6 +9,8 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { TypeConstraint, validateConstraints } from 'vs/base/common/types'; import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { LinkedList } from 'vs/base/common/linkedList'; export const ICommandService = createDecorator('commandService'); @@ -19,8 +21,7 @@ export interface ICommandEvent { export interface ICommandService { _serviceBrand: any; onWillExecuteCommand: Event; - executeCommand(commandId: string, ...args: any[]): TPromise; - executeCommand(commandId: string, ...args: any[]): TPromise; + executeCommand(commandId: string, ...args: any[]): TPromise; } export interface ICommandsMap { @@ -32,7 +33,9 @@ export interface ICommandHandler { } export interface ICommand { + id: string; handler: ICommandHandler; + precondition?: ContextKeyExpr; description?: ICommandHandlerDescription; } @@ -44,78 +47,56 @@ export interface ICommandHandlerDescription { export interface ICommandRegistry { registerCommand(id: string, command: ICommandHandler): IDisposable; - registerCommand(id: string, command: ICommand): IDisposable; + registerCommand(command: ICommand): IDisposable; getCommand(id: string): ICommand; getCommands(): ICommandsMap; } -function isCommand(thing: any): thing is ICommand { - return typeof thing === 'object' - && typeof (thing).handler === 'function' - && (!(thing).description || typeof (thing).description === 'object'); -} - export const CommandsRegistry: ICommandRegistry = new class implements ICommandRegistry { - private _commands = new Map(); + private _commands = new Map>(); - registerCommand(id: string, commandOrDesc: ICommandHandler | ICommand): IDisposable { + registerCommand(idOrCommand: string | ICommand, handler?: ICommandHandler): IDisposable { - if (!commandOrDesc) { + if (!idOrCommand) { throw new Error(`invalid command`); } - let command: ICommand; - if (!isCommand(commandOrDesc)) { - // simple handler - command = { handler: commandOrDesc }; - - } else { - const { handler, description } = commandOrDesc; - if (description) { - // add argument validation if rich command metadata is provided - const constraints: TypeConstraint[] = []; - for (let arg of description.args) { - constraints.push(arg.constraint); - } - command = { - description, - handler(accessor, ...args: any[]) { - validateConstraints(args, constraints); - return handler(accessor, ...args); - } - }; - } else { - // add as simple handler - command = { handler }; + if (typeof idOrCommand === 'string') { + if (!handler) { + throw new Error(`invalid command`); } + return this.registerCommand({ id: idOrCommand, handler }); + } + + // add argument validation if rich command metadata is provided + if (idOrCommand.description) { + const constraints: TypeConstraint[] = []; + for (let arg of idOrCommand.description.args) { + constraints.push(arg.constraint); + } + const actualHandler = idOrCommand.handler; + idOrCommand.handler = function (accessor, ...args: any[]) { + validateConstraints(args, constraints); + return actualHandler(accessor, ...args); + }; } // find a place to store the command - const commandOrArray = this._commands.get(id); - if (commandOrArray === void 0) { - this._commands.set(id, command); - } else if (Array.isArray(commandOrArray)) { - commandOrArray.unshift(command); - } else { - this._commands.set(id, [command, commandOrArray]); + const { id } = idOrCommand; + + let commands = this._commands.get(id); + if (!commands) { + commands = new LinkedList(); + this._commands.set(id, commands); } + let removeFn = commands.unshift(idOrCommand); + return { dispose: () => { - const commandOrArray = this._commands.get(id); - if (Array.isArray(commandOrArray)) { - // remove from array, remove array - // if last element removed - const idx = commandOrArray.indexOf(command); - if (idx >= 0) { - commandOrArray.splice(idx, 1); - if (commandOrArray.length === 0) { - this._commands.delete(id); - } - } - } else if (isCommand(commandOrArray)) { - // remove from map + removeFn(); + if (this._commands.get(id).isEmpty()) { this._commands.delete(id); } } @@ -123,12 +104,11 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR } getCommand(id: string): ICommand { - const commandOrArray = this._commands.get(id); - if (Array.isArray(commandOrArray)) { - return commandOrArray[0]; - } else { - return commandOrArray; + const list = this._commands.get(id); + if (!list || list.isEmpty()) { + return undefined; } + return list.iterator().next().value; } getCommands(): ICommandsMap { diff --git a/src/vs/platform/commands/test/commandService.test.ts b/src/vs/platform/commands/test/commandService.test.ts index c027ea01257..2cc8f0ce2af 100644 --- a/src/vs/platform/commands/test/commandService.test.ts +++ b/src/vs/platform/commands/test/commandService.test.ts @@ -12,6 +12,9 @@ import { CommandService } from 'vs/platform/commands/common/commandService'; import { IExtensionService, ExtensionPointContribution, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry'; +import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; +import { SimpleConfigurationService } from 'vs/editor/standalone/browser/simpleServices'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; class SimpleExtensionService implements IExtensionService { _serviceBrand: any; @@ -35,6 +38,10 @@ class SimpleExtensionService implements IExtensionService { } restartExtensionHost(): void { } + startExtensionHost(): void { + } + stopExtensionHost(): void { + } } suite('CommandService', function () { @@ -58,7 +65,7 @@ suite('CommandService', function () { lastEvent = activationEvent; return super.activateByEvent(activationEvent); } - }); + }, new ContextKeyService(new SimpleConfigurationService())); return service.executeCommand('foo').then(() => { assert.ok(lastEvent, 'onCommand:foo'); @@ -76,7 +83,7 @@ suite('CommandService', function () { activateByEvent(activationEvent: string): TPromise { return TPromise.wrapError(new Error('bad_activate')); } - }); + }, new ContextKeyService(new SimpleConfigurationService())); return service.executeCommand('foo').then(() => assert.ok(false), err => { assert.equal(err.message, 'bad_activate'); @@ -88,12 +95,13 @@ suite('CommandService', function () { let callCounter = 0; let reg = CommandsRegistry.registerCommand('bar', () => callCounter += 1); + // @ts-ignore unused local let resolve: Function; let service = new CommandService(new InstantiationService(), new class extends SimpleExtensionService { onReady() { return new TPromise(_resolve => { resolve = _resolve; }); } - }); + }, new ContextKeyService(new SimpleConfigurationService())); return service.executeCommand('bar').then(() => { reg.dispose(); @@ -101,4 +109,30 @@ suite('CommandService', function () { }); }); -}); \ No newline at end of file + test('honor command-precondition', function () { + let contextKeyService = new ContextKeyService(new SimpleConfigurationService()); + let commandService = new CommandService( + new InstantiationService(), + new SimpleExtensionService(), + contextKeyService + ); + + let counter = 0; + let reg = CommandsRegistry.registerCommand({ + id: 'bar', + handler: () => { counter += 1; }, + precondition: ContextKeyExpr.has('foocontext') + }); + + return commandService.executeCommand('bar').then(() => { + assert.throws(() => { }); + }, () => { + contextKeyService.setContext('foocontext', true); + return commandService.executeCommand('bar'); + }).then(() => { + assert.equal(counter, 1); + reg.dispose(); + }); + + }); +}); diff --git a/src/vs/platform/commands/test/commands.test.ts b/src/vs/platform/commands/test/commands.test.ts index a99a5ec2b61..3cfc5ba6a41 100644 --- a/src/vs/platform/commands/test/commands.test.ts +++ b/src/vs/platform/commands/test/commands.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; - +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; suite('Command Tests', function () { @@ -60,7 +60,8 @@ suite('Command Tests', function () { assert.ok(typeof args === 'string'); }); - CommandsRegistry.registerCommand('test3', { + CommandsRegistry.registerCommand({ + id: 'test3', handler: function (accessor, args) { return true; }, @@ -76,4 +77,21 @@ suite('Command Tests', function () { assert.equal(CommandsRegistry.getCommands()['test3'].handler.apply(undefined, [undefined, 1]), true); }); + + test('CommandsRegistry with precondition', function () { + let r1 = CommandsRegistry.registerCommand('foo', () => { }); + + const precondition = new RawContextKey('ddd', false); + let r2 = CommandsRegistry.registerCommand({ + id: 'bar', + handler: () => { }, + precondition + }); + + assert.ok(CommandsRegistry.getCommand('bar').precondition === precondition); + assert.equal(CommandsRegistry.getCommand('foo').precondition, undefined); + + r1.dispose(); + r2.dispose(); + }); }); diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 85e3e00ff4c..6ebb51245d6 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -4,94 +4,186 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import * as arrays from 'vs/base/common/arrays'; -import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; +import * as types from 'vs/base/common/types'; import URI from 'vs/base/common/uri'; -import { StrictResourceMap } from 'vs/base/common/map'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { StrictResourceMap } from 'vs/base/common/map'; export const IConfigurationService = createDecorator('configurationService'); +export function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides { + return thing + && typeof thing === 'object' + && (!thing.overrideIdentifier || typeof thing.overrideIdentifier === 'string') + && (!thing.resource || thing.resource instanceof URI); +} + export interface IConfigurationOverrides { overrideIdentifier?: string; resource?: URI; } -export type IConfigurationValues = { [key: string]: IConfigurationValue }; +export enum ConfigurationTarget { + USER = 1, + WORKSPACE, + WORKSPACE_FOLDER, + DEFAULT, + MEMORY +} + +export interface IConfigurationChangeEvent { + + source: ConfigurationTarget; + affectedKeys: string[]; + affectsConfiguration(configuration: string, resource?: URI): boolean; + + // Following data is used for telemetry + sourceConfig: any; + + // Following data is used for Extension host configuration event + changedConfiguration: IConfigurationModel; + changedConfigurationByResource: StrictResourceMap; +} export interface IConfigurationService { _serviceBrand: any; - getConfigurationData(): IConfigurationData; + onDidChangeConfiguration: Event; - /** - * Fetches the appropriate section of the configuration JSON file. - * This will be an object keyed off the section name. - */ - getConfiguration(section?: string, overrides?: IConfigurationOverrides): T; + getConfigurationData(): IConfigurationData; - /** - * Resolves a configuration key to its values in the different scopes - * the setting is defined. - */ - lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue; + getConfiguration(): T; + getConfiguration(section: string): T; + getConfiguration(overrides: IConfigurationOverrides): T; + getConfiguration(section: string, overrides: IConfigurationOverrides): T; - /** - * Returns the defined keys of configurations in the different scopes - * the key is defined. - */ - keys(overrides?: IConfigurationOverrides): IConfigurationKeys; + getValue(key: string, overrides?: IConfigurationOverrides): T; - /** - * Similar to #getConfiguration() but ensures that the latest configuration - * from disk is fetched. - */ - reloadConfiguration(section?: string): TPromise; + updateValue(key: string, value: any): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise; + updateValue(key: string, value: any, target: ConfigurationTarget): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget, donotNotifyError?: boolean): TPromise; - /** - * Event that fires when the configuration changes. - */ - onDidUpdateConfiguration: Event; + reloadConfiguration(): TPromise; + reloadConfiguration(folder: IWorkspaceFolder): TPromise; - /** - * Returns the defined values of configurations in the different scopes. - */ - values(): IConfigurationValues; + inspect(key: string): { + default: T, + user: T, + workspace: T, + workspaceFolder: T, + memory?: T, + value: T, + }; + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + memory?: string[]; + }; } -export enum ConfigurationSource { - Default = 1, - User, - Workspace +export interface IConfigurationModel { + contents: any; + keys: string[]; + overrides: IOverrides[]; } -export interface IConfigurationServiceEvent { - /** - * The type of source that triggered this event. - */ - source: ConfigurationSource; - /** - * The part of the configuration contributed by the source of this event. - */ - sourceConfig: any; +export interface IOverrides { + contents: any; + identifiers: string[]; } -export interface IConfigurationValue { - value: T; - default: T; - user: T; - workspace: T; - folder: T; +export interface IConfigurationData { + defaults: IConfigurationModel; + user: IConfigurationModel; + workspace: IConfigurationModel; + folders: { [folder: string]: IConfigurationModel }; } -export interface IConfigurationKeys { - default: string[]; - user: string[]; - workspace: string[]; - folder: string[]; +export function compare(from: IConfigurationModel, to: IConfigurationModel): { added: string[], removed: string[], updated: string[] } { + const added = to.keys.filter(key => from.keys.indexOf(key) === -1); + const removed = from.keys.filter(key => to.keys.indexOf(key) === -1); + const updated = []; + + for (const key of from.keys) { + const value1 = getConfigurationValue(from.contents, key); + const value2 = getConfigurationValue(to.contents, key); + if (!objects.equals(value1, value2)) { + updated.push(key); + } + } + + return { added, removed, updated }; +} + +export function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any { + const root = Object.create(null); + + for (let key in properties) { + addToValueTree(root, key, properties[key], conflictReporter); + } + + return root; +} + +export function addToValueTree(settingsTreeRoot: any, key: string, value: any, conflictReporter: (message: string) => void): void { + const segments = key.split('.'); + const last = segments.pop(); + + let curr = settingsTreeRoot; + for (let i = 0; i < segments.length; i++) { + let s = segments[i]; + let obj = curr[s]; + switch (typeof obj) { + case 'undefined': + obj = curr[s] = Object.create(null); + break; + case 'object': + break; + default: + conflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is ${JSON.stringify(obj)}`); + return; + } + curr = obj; + } + + if (typeof curr === 'object') { + curr[last] = value; // workaround https://github.com/Microsoft/vscode/issues/13606 + } else { + conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`); + } +} + +export function removeFromValueTree(valueTree: any, key: string): void { + const segments = key.split('.'); + doRemoveFromValueTree(valueTree, segments); +} + +function doRemoveFromValueTree(valueTree: any, segments: string[]): void { + const first = segments.shift(); + if (segments.length === 0) { + // Reached last segment + delete valueTree[first]; + return; + } + + if (Object.keys(valueTree).indexOf(first) !== -1) { + const value = valueTree[first]; + if (typeof value === 'object' && !Array.isArray(value)) { + doRemoveFromValueTree(value, segments); + if (Object.keys(value).length === 0) { + delete valueTree[first]; + } + } + } } /** @@ -129,256 +221,27 @@ export function merge(base: any, add: any, overwrite: boolean): void { }); } -export interface IConfiguraionModel { - contents: T; - keys: string[]; - overrides: IOverrides[]; +export function getConfigurationKeys(): string[] { + const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + return Object.keys(properties); } -export interface IOverrides { - contents: T; - identifiers: string[]; +export function getDefaultValues(): any { + const valueTreeRoot: any = Object.create(null); + const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + + for (let key in properties) { + let value = properties[key].default; + addToValueTree(valueTreeRoot, key, value, message => console.error(`Conflict in default settings: ${message}`)); + } + + return valueTreeRoot; } -export class ConfigurationModel implements IConfiguraionModel { - - constructor(protected _contents: T = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) { - } - - public get contents(): T { - return this._contents; - } - - public get overrides(): IOverrides[] { - return this._overrides; - } - - public get keys(): string[] { - return this._keys; - } - - public getContentsFor(section: string): V { - return objects.clone(this.contents[section]); - } - - public override(identifier: string): ConfigurationModel { - const result = new ConfigurationModel(); - const contents = objects.clone(this.contents); - if (this._overrides) { - for (const override of this._overrides) { - if (override.identifiers.indexOf(identifier) !== -1) { - merge(contents, override.contents, true); - } - } - } - result._contents = contents; - return result; - } - - public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { - const mergedModel = new ConfigurationModel(); - this.doMerge(mergedModel, this, overwrite); - this.doMerge(mergedModel, other, overwrite); - return mergedModel; - } - - protected doMerge(source: ConfigurationModel, target: ConfigurationModel, overwrite: boolean = true) { - merge(source.contents, objects.clone(target.contents), overwrite); - const overrides = objects.clone(source._overrides); - for (const override of target._overrides) { - const [sourceOverride] = overrides.filter(o => arrays.equals(o.identifiers, override.identifiers)); - if (sourceOverride) { - merge(sourceOverride.contents, override.contents, overwrite); - } else { - overrides.push(override); - } - } - source._overrides = overrides; - } +export function overrideIdentifierFromKey(key: string): string { + return key.substring(1, key.length - 1); } -export interface IConfigurationData { - defaults: IConfiguraionModel; - user: IConfiguraionModel; - workspace: IConfiguraionModel; - folders: { [folder: string]: IConfiguraionModel }; +export function keyFromOverrideIdentifier(overrideIdentifier: string): string { + return `[${overrideIdentifier}]`; } - -export class Configuration { - - private _globalConfiguration: ConfigurationModel; - private _workspaceConsolidatedConfiguration: ConfigurationModel; - private _legacyWorkspaceConsolidatedConfiguration: ConfigurationModel; - protected _foldersConsolidatedConfigurations: StrictResourceMap>; - - constructor(protected _defaults: ConfigurationModel, protected _user: ConfigurationModel, protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(), protected folders: StrictResourceMap> = new StrictResourceMap>(), protected _workspace?: Workspace) { - this.merge(); - } - - get defaults(): ConfigurationModel { - return this._defaults; - } - - get user(): ConfigurationModel { - return this._user; - } - - protected merge(): void { - this._globalConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); - this._workspaceConsolidatedConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this._workspaceConfiguration); - this._legacyWorkspaceConsolidatedConfiguration = null; - this._foldersConsolidatedConfigurations = new StrictResourceMap>(); - for (const folder of this.folders.keys()) { - this.mergeFolder(folder); - } - } - - protected mergeFolder(folder: URI) { - this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConsolidatedConfiguration).merge(this.folders.get(folder))); - } - - getValue(section: string = '', overrides: IConfigurationOverrides = {}): C { - const configModel = this.getConsolidateConfigurationModel(overrides); - return section ? configModel.getContentsFor(section) : configModel.contents; - } - - lookup(key: string, overrides: IConfigurationOverrides = {}): IConfigurationValue { - // make sure to clone the configuration so that the receiver does not tamper with the values - const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides); - const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); - return { - default: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key)), - user: objects.clone(getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key)), - workspace: objects.clone(this._workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0), //Check on workspace exists or not because _workspaceConfiguration is never null - folder: objects.clone(folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0), - value: objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)) - }; - } - - lookupLegacy(key: string): IConfigurationValue { - if (!this._legacyWorkspaceConsolidatedConfiguration) { - this._legacyWorkspaceConsolidatedConfiguration = this._workspace ? new ConfigurationModel().merge(this._workspaceConfiguration).merge(this.folders.get(this._workspace.roots[0])) : null; - } - const consolidateConfigurationModel = this.getConsolidateConfigurationModel({}); - return { - default: objects.clone(getConfigurationValue(this._defaults.contents, key)), - user: objects.clone(getConfigurationValue(this._user.contents, key)), - workspace: objects.clone(this._legacyWorkspaceConsolidatedConfiguration ? getConfigurationValue(this._legacyWorkspaceConsolidatedConfiguration.contents, key) : void 0), - folder: void 0, - value: objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)) - }; - } - - keys(overrides: IConfigurationOverrides = {}): IConfigurationKeys { - const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource); - return { - default: this._defaults.keys, - user: this._user.keys, - workspace: this._workspaceConfiguration.keys, - folder: folderConfigurationModel ? folderConfigurationModel.keys : [] - }; - } - - values(): IConfigurationValues { - const result = Object.create(null); - const keyset = this.keys(); - const keys = [...keyset.workspace, ...keyset.user, ...keyset.default].sort(); - - let lastKey: string; - for (const key of keys) { - if (key !== lastKey) { - lastKey = key; - result[key] = this.lookup(key); - } - } - - return result; - } - - values2(): Map> { - const result: Map> = new Map>(); - const keyset = this.keys(); - const keys = [...keyset.workspace, ...keyset.user, ...keyset.default].sort(); - - let lastKey: string; - for (const key of keys) { - if (key !== lastKey) { - lastKey = key; - result.set(key, this.lookup(key)); - } - } - - return result; - } - - private getConsolidateConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { - let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides); - return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; - } - - private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides): ConfigurationModel { - if (!this._workspace) { - return this._globalConfiguration; - } - - if (!resource) { - return this._workspaceConsolidatedConfiguration; - } - - const root = this._workspace.getRoot(resource); - if (!root) { - return this._workspaceConsolidatedConfiguration; - } - - return this._foldersConsolidatedConfigurations.get(root) || this._workspaceConsolidatedConfiguration; - } - - private getFolderConfigurationModelForResource(resource: URI): ConfigurationModel { - if (!this._workspace || !resource) { - return null; - } - - const root = this._workspace.getRoot(resource); - return root ? this.folders.get(root) : null; - } - - public toData(): IConfigurationData { - return { - defaults: { - contents: this._defaults.contents, - overrides: this._defaults.overrides, - keys: this._defaults.keys - }, - user: { - contents: this._user.contents, - overrides: this._user.overrides, - keys: this._user.keys - }, - workspace: { - contents: this._workspaceConfiguration.contents, - overrides: this._workspaceConfiguration.overrides, - keys: this._workspaceConfiguration.keys - }, - folders: this.folders.keys().reduce((result, folder) => { - const { contents, overrides, keys } = this.folders.get(folder); - result[folder.toString()] = { contents, overrides, keys }; - return result; - }, Object.create({})) - }; - } - - public static parse(data: IConfigurationData, workspace: Workspace): Configuration { - const defaultConfiguration = Configuration.parseConfigurationModel(data.defaults); - const userConfiguration = Configuration.parseConfigurationModel(data.user); - const workspaceConfiguration = Configuration.parseConfigurationModel(data.workspace); - const folders: StrictResourceMap> = Object.keys(data.folders).reduce((result, key) => { - result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key])); - return result; - }, new StrictResourceMap>()); - return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, workspace); - } - - private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { - return new ConfigurationModel(model.contents, model.keys, model.overrides); - } -} \ No newline at end of file diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts new file mode 100644 index 00000000000..6ae3de36627 --- /dev/null +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -0,0 +1,602 @@ +/*--------------------------------------------------------------------------------------------- + * 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 json from 'vs/base/common/json'; +import { StrictResourceMap } from 'vs/base/common/map'; +import * as arrays from 'vs/base/common/arrays'; +import * as objects from 'vs/base/common/objects'; +import URI from 'vs/base/common/uri'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; +import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, merge, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; +import { Workspace } from 'vs/platform/workspace/common/workspace'; + +export class ConfigurationModel implements IConfigurationModel { + + constructor(protected _contents: any = {}, protected _keys: string[] = [], protected _overrides: IOverrides[] = []) { + } + + public get contents(): any { + return this._contents; + } + + public get overrides(): IOverrides[] { + return this._overrides; + } + + public get keys(): string[] { + return this._keys; + } + + public getSectionContents(section: string): V { + return this.contents[section]; + } + + public setValue(key: string, value: any) { + this.addKey(key); + addToValueTree(this._contents, key, value, e => { throw new Error(e); }); + } + + public removeValue(key: string): void { + if (this.removeKey(key)) { + removeFromValueTree(this._contents, key); + } + } + + public setValueInOverrides(overrideIdentifier: string, key: string, value: any): void { + let override = this._overrides.filter(override => override.identifiers.indexOf(overrideIdentifier) !== -1)[0]; + if (!override) { + override = { identifiers: [overrideIdentifier], contents: {} }; + this._overrides.push(override); + } + addToValueTree(override.contents, key, value, e => { throw new Error(e); }); + } + + public override(identifier: string): ConfigurationModel { + const overrideContents = this.getContentsForOverrideIdentifer(identifier); + + if (!overrideContents || typeof overrideContents !== 'object' || !Object.keys(overrideContents).length) { + // If there are no valid overrides, use base contents + return new ConfigurationModel(this._contents); + } + + let contents = {}; + for (const key of arrays.distinct([...Object.keys(this._contents), ...Object.keys(overrideContents)])) { + + let contentsForKey = this._contents[key]; + let overrideContentsForKey = overrideContents[key]; + + // If there are override contents for the key, clone and merge otherwise use base contents + if (overrideContentsForKey) { + // Clone and merge only if base contents and override contents are of type object otherwise just override + if (typeof contentsForKey === 'object' && typeof overrideContentsForKey === 'object') { + contentsForKey = objects.clone(contentsForKey); + merge(contentsForKey, overrideContentsForKey, true); + } else { + contentsForKey = overrideContentsForKey; + } + } + + contents[key] = contentsForKey; + } + return new ConfigurationModel(contents); + } + + public merge(other: ConfigurationModel, overwrite: boolean = true): ConfigurationModel { + const mergedModel = new ConfigurationModel(); + this.doMerge(mergedModel, this, overwrite); + this.doMerge(mergedModel, other, overwrite); + return mergedModel; + } + + protected doMerge(source: ConfigurationModel, target: ConfigurationModel, overwrite: boolean = true) { + merge(source.contents, objects.clone(target.contents), overwrite); + const overrides = objects.clone(source._overrides); + for (const override of target._overrides) { + const [sourceOverride] = overrides.filter(o => arrays.equals(o.identifiers, override.identifiers)); + if (sourceOverride) { + merge(sourceOverride.contents, override.contents, overwrite); + } else { + overrides.push(override); + } + } + source._overrides = overrides; + source._keys = arrays.distinct([...source._keys, ...target.keys]); + } + + private getContentsForOverrideIdentifer(identifier: string): any { + for (const override of this._overrides) { + if (override.identifiers.indexOf(identifier) !== -1) { + return override.contents; + } + } + return null; + } + + private addKey(key: string): void { + let index = this._keys.length; + for (let i = 0; i < index; i++) { + if (key.indexOf(this._keys[i]) === 0) { + index = i; + } + } + this._keys.splice(index, 1, key); + } + + private removeKey(key: string): boolean { + let index = this._keys.indexOf(key); + if (index !== -1) { + this._keys.splice(index, 1); + return true; + } + return false; + } + + toJSON(): IConfigurationModel { + return { + contents: this.contents, + overrides: this.overrides, + keys: this.keys + }; + } +} + +export class DefaultConfigurationModel extends ConfigurationModel { + + constructor() { + super(getDefaultValues()); + this._keys = getConfigurationKeys(); + this._overrides = Object.keys(this._contents) + .filter(key => OVERRIDE_PROPERTY_PATTERN.test(key)) + .map(key => { + return { + identifiers: [overrideIdentifierFromKey(key).trim()], + contents: toValuesTree(this._contents[key], message => console.error(`Conflict in default settings file: ${message}`)) + }; + }); + } + + public get keys(): string[] { + return this._keys; + } +} + +interface Overrides extends IOverrides { + raw: any; +} + +export class CustomConfigurationModel extends ConfigurationModel { + + protected _parseErrors: any[] = []; + + constructor(content: string = '', private name: string = '') { + super(); + if (content) { + this.update(content); + } + } + + public get errors(): any[] { + return this._parseErrors; + } + + public update(content: string): void { + let parsed: any = {}; + let overrides: Overrides[] = []; + let currentProperty: string = null; + let currentParent: any = []; + let previousParents: any[] = []; + let parseErrors: json.ParseError[] = []; + + function onValue(value: any) { + if (Array.isArray(currentParent)) { + (currentParent).push(value); + } else if (currentProperty) { + currentParent[currentProperty] = value; + } + if (OVERRIDE_PROPERTY_PATTERN.test(currentProperty)) { + onOverrideSettingsValue(currentProperty, value); + } + } + + function onOverrideSettingsValue(property: string, value: any): void { + overrides.push({ + identifiers: [overrideIdentifierFromKey(property).trim()], + raw: value, + contents: null + }); + } + + let visitor: json.JSONVisitor = { + onObjectBegin: () => { + let object = {}; + onValue(object); + previousParents.push(currentParent); + currentParent = object; + currentProperty = null; + }, + onObjectProperty: (name: string) => { + currentProperty = name; + }, + onObjectEnd: () => { + currentParent = previousParents.pop(); + }, + onArrayBegin: () => { + let array: any[] = []; + onValue(array); + previousParents.push(currentParent); + currentParent = array; + currentProperty = null; + }, + onArrayEnd: () => { + currentParent = previousParents.pop(); + }, + onLiteralValue: onValue, + onError: (error: json.ParseErrorCode) => { + parseErrors.push({ error: error }); + } + }; + if (content) { + try { + json.visit(content, visitor); + parsed = currentParent[0] || {}; + } catch (e) { + console.error(`Error while parsing settings file ${this.name}: ${e}`); + this._parseErrors = [e]; + } + } + this.processRaw(parsed); + + const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + this._overrides = overrides.map(override => { + // Filter unknown and non-overridable properties + const raw = {}; + for (const key in override.raw) { + if (configurationProperties[key] && configurationProperties[key].overridable) { + raw[key] = override.raw[key]; + } + } + return { + identifiers: override.identifiers, + contents: toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)) + }; + }); + } + + protected processRaw(raw: any): void { + this._contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)); + this._keys = Object.keys(raw); + } +} + +export class Configuration { + + private _globalConfiguration: ConfigurationModel; + private _workspaceConsolidatedConfiguration: ConfigurationModel; + protected _foldersConsolidatedConfigurations: StrictResourceMap; + + constructor(protected _defaults: ConfigurationModel, + protected _user: ConfigurationModel, + protected _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(), + protected folders: StrictResourceMap = new StrictResourceMap(), + protected _memoryConfiguration: ConfigurationModel = new ConfigurationModel(), + protected _memoryConfigurationByResource: StrictResourceMap = new StrictResourceMap()) { + this.merge(); + } + + get defaults(): ConfigurationModel { + return this._defaults; + } + + get user(): ConfigurationModel { + return this._user; + } + + get workspace(): ConfigurationModel { + return this._workspaceConfiguration; + } + + protected merge(): void { + this._globalConfiguration = this._defaults.merge(this._user); + this.updateWorkspaceConsolidateConfiguration(); + this._foldersConsolidatedConfigurations = new StrictResourceMap(); + for (const folder of this.folders.keys()) { + this.mergeFolder(folder); + } + } + + private updateWorkspaceConsolidateConfiguration() { + this._workspaceConsolidatedConfiguration = this._globalConfiguration.merge(this._workspaceConfiguration).merge(this._memoryConfiguration); + } + + protected mergeFolder(folder: URI) { + this._foldersConsolidatedConfigurations.set(folder, this._workspaceConsolidatedConfiguration.merge(this.folders.get(folder))); + } + + getSection(section: string = '', overrides: IConfigurationOverrides, workspace: Workspace): C { + const configModel = this.getConsolidateConfigurationModel(overrides, workspace); + return objects.clone(section ? configModel.getSectionContents(section) : configModel.contents); + } + + getValue(key: string, overrides: IConfigurationOverrides, workspace: Workspace): any { + const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides, workspace); + return objects.clone(getConfigurationValue(consolidateConfigurationModel.contents, key)); + } + + updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void { + let memoryConfiguration: ConfigurationModel; + if (overrides.resource) { + memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource); + if (!memoryConfiguration) { + memoryConfiguration = new ConfigurationModel(); + this._memoryConfigurationByResource.set(overrides.resource, memoryConfiguration); + } + } else { + memoryConfiguration = this._memoryConfiguration; + } + + if (value === void 0) { + memoryConfiguration.removeValue(key); + } else { + memoryConfiguration.setValue(key, value); + } + + if (!overrides.resource) { + this.updateWorkspaceConsolidateConfiguration(); + } + } + + lookup(key: string, overrides: IConfigurationOverrides, workspace: Workspace): { + default: C, + user: C, + workspace: C, + workspaceFolder: C + memory?: C + value: C, + } { + const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides, workspace); + const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace); + const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration; + return objects.clone({ + default: getConfigurationValue(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key), + user: getConfigurationValue(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key), + workspace: workspace ? getConfigurationValue(overrides.overrideIdentifier ? this._workspaceConfiguration.override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.contents, key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null + workspaceFolder: folderConfigurationModel ? getConfigurationValue(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0, + memory: getConfigurationValue(overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).contents : memoryConfigurationModel.contents, key), + value: getConfigurationValue(consolidateConfigurationModel.contents, key) + }); + } + + keys(workspace: Workspace): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + const folderConfigurationModel = this.getFolderConfigurationModelForResource(null, workspace); + return objects.clone({ + default: this._defaults.keys, + user: this._user.keys, + workspace: this._workspaceConfiguration.keys, + workspaceFolder: folderConfigurationModel ? folderConfigurationModel.keys : [] + }); + } + + private getConsolidateConfigurationModel(overrides: IConfigurationOverrides, workspace: Workspace): ConfigurationModel { + let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace); + return overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel; + } + + private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides, workspace: Workspace): ConfigurationModel { + if (!workspace) { + return this._globalConfiguration; + } + + if (!resource) { + return this._workspaceConsolidatedConfiguration; + } + + let consolidateConfiguration = this._workspaceConsolidatedConfiguration; + const root = workspace.getFolder(resource); + if (root) { + consolidateConfiguration = this._foldersConsolidatedConfigurations.get(root.uri) || this._workspaceConsolidatedConfiguration; + } + + const memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource); + if (memoryConfigurationForResource) { + consolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource); + } + + return consolidateConfiguration; + } + + private getFolderConfigurationModelForResource(resource: URI, workspace: Workspace): ConfigurationModel { + if (!workspace || !resource) { + return null; + } + + const root = workspace.getFolder(resource); + return root ? this.folders.get(root.uri) : null; + } + + public toData(): IConfigurationData { + return { + defaults: { + contents: this._defaults.contents, + overrides: this._defaults.overrides, + keys: this._defaults.keys + }, + user: { + contents: this._user.contents, + overrides: this._user.overrides, + keys: this._user.keys + }, + workspace: { + contents: this._workspaceConfiguration.contents, + overrides: this._workspaceConfiguration.overrides, + keys: this._workspaceConfiguration.keys + }, + folders: this.folders.keys().reduce((result, folder) => { + const { contents, overrides, keys } = this.folders.get(folder); + result[folder.toString()] = { contents, overrides, keys }; + return result; + }, Object.create({})) + }; + } + + public static parse(data: IConfigurationData): Configuration { + const defaultConfiguration = Configuration.parseConfigurationModel(data.defaults); + const userConfiguration = Configuration.parseConfigurationModel(data.user); + const workspaceConfiguration = Configuration.parseConfigurationModel(data.workspace); + const folders: StrictResourceMap = Object.keys(data.folders).reduce((result, key) => { + result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key])); + return result; + }, new StrictResourceMap()); + return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, folders, new ConfigurationModel(), new StrictResourceMap()); + } + + private static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel { + return new ConfigurationModel(model.contents, model.keys, model.overrides); + } +} + +export class AbstractConfigurationChangeEvent { + + protected doesConfigurationContains(configuration: ConfigurationModel, config: string): boolean { + let changedKeysTree = configuration.contents; + let requestedTree = toValuesTree({ [config]: true }, () => { }); + + let key; + while (typeof requestedTree === 'object' && (key = Object.keys(requestedTree)[0])) { // Only one key should present, since we added only one property + changedKeysTree = changedKeysTree[key]; + if (!changedKeysTree) { + return false; // Requested tree is not found + } + requestedTree = requestedTree[key]; + } + return true; + } + + protected updateKeys(configuration: ConfigurationModel, keys: string[], resource?: URI): void { + for (const key of keys) { + configuration.setValue(key, {}); + } + } +} + +export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent { + + private _changedConfiguration: ConfigurationModel = null; + + constructor(readonly affectedKeys: string[], readonly source: ConfigurationTarget, readonly sourceConfig: any) { super(); } + + get changedConfiguration(): ConfigurationModel { + if (!this._changedConfiguration) { + this._changedConfiguration = new ConfigurationModel(); + this.updateKeys(this._changedConfiguration, this.affectedKeys); + } + return this._changedConfiguration; + } + + get changedConfigurationByResource(): StrictResourceMap { + return new StrictResourceMap(); + } + + affectsConfiguration(config: string, resource?: URI): boolean { + return this.doesConfigurationContains(this.changedConfiguration, config); + } +} + +export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent { + + private _source: ConfigurationTarget; + private _sourceConfig: any; + + constructor( + private _changedConfiguration: ConfigurationModel = new ConfigurationModel(), + private _changedConfigurationByResource: StrictResourceMap = new StrictResourceMap()) { + super(); + } + + get changedConfiguration(): IConfigurationModel { + return this._changedConfiguration; + } + + get changedConfigurationByResource(): StrictResourceMap { + return this._changedConfigurationByResource; + } + + change(event: ConfigurationChangeEvent): ConfigurationChangeEvent; + change(keys: string[], resource?: URI): ConfigurationChangeEvent; + change(arg1: any, arg2?: any): ConfigurationChangeEvent { + if (arg1 instanceof ConfigurationChangeEvent) { + this._changedConfiguration = this._changedConfiguration.merge(arg1._changedConfiguration); + for (const resource of arg1._changedConfigurationByResource.keys()) { + let changedConfigurationByResource = this.getOrSetChangedConfigurationForResource(resource); + changedConfigurationByResource = changedConfigurationByResource.merge(arg1._changedConfigurationByResource.get(resource)); + this._changedConfigurationByResource.set(resource, changedConfigurationByResource); + } + } else { + this.changeWithKeys(arg1, arg2); + } + return this; + } + + telemetryData(source: ConfigurationTarget, sourceConfig: any): ConfigurationChangeEvent { + this._source = source; + this._sourceConfig = sourceConfig; + return this; + } + + get affectedKeys(): string[] { + const keys = [...this._changedConfiguration.keys]; + this._changedConfigurationByResource.forEach(model => keys.push(...model.keys)); + return keys; + } + + get source(): ConfigurationTarget { + return this._source; + } + + get sourceConfig(): any { + return this._sourceConfig; + } + + affectsConfiguration(config: string, resource?: URI): boolean { + let configurationModelsToSearch: ConfigurationModel[] = [this._changedConfiguration]; + + if (resource) { + let model = this._changedConfigurationByResource.get(resource); + if (model) { + configurationModelsToSearch.push(model); + } + } else { + configurationModelsToSearch.push(...this._changedConfigurationByResource.values()); + } + + for (const configuration of configurationModelsToSearch) { + if (this.doesConfigurationContains(configuration, config)) { + return true; + } + } + + return false; + } + + private changeWithKeys(keys: string[], resource?: URI): void { + let changedConfiguration = resource ? this.getOrSetChangedConfigurationForResource(resource) : this._changedConfiguration; + this.updateKeys(changedConfiguration, keys); + } + + private getOrSetChangedConfigurationForResource(resource: URI): ConfigurationModel { + let changedConfigurationByResource = this._changedConfigurationByResource.get(resource); + if (!changedConfigurationByResource) { + changedConfigurationByResource = new ConfigurationModel(); + this._changedConfigurationByResource.set(resource, changedConfigurationByResource); + } + return changedConfigurationByResource; + } +} \ No newline at end of file diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index d2495cce311..f0eb0575667 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -11,6 +11,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import types = require('vs/base/common/types'); import * as strings from 'vs/base/common/strings'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { clone } from 'vs/base/common/objects'; export const Extensions = { Configuration: 'base.contributions.configuration' @@ -28,13 +29,19 @@ export interface IConfigurationRegistry { */ registerConfigurations(configurations: IConfigurationNode[], validate?: boolean): void; + /** + * Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values. + * Property or default value changes are not allowed. + */ + notifyConfigurationSchemaUpdated(configuration: IConfigurationNode): void; + registerDefaultConfigurations(defaultConfigurations: IDefaultConfigurationExtension[]): void; /** - * Event that fires whenver a configuratio has been + * Event that fires whenver a configuration has been * registered. */ - onDidRegisterConfiguration: Event; + onDidRegisterConfiguration: Event; /** * Returns all configuration nodes contributed to this registry. @@ -61,6 +68,7 @@ export interface IConfigurationPropertySchema extends IJSONSchema { overridable?: boolean; isExecutable?: boolean; scope?: ConfigurationScope; + notMultiRootAdopted?: boolean; } export interface IConfigurationNode { @@ -81,37 +89,30 @@ export interface IDefaultConfigurationExtension { defaults: { [key: string]: {} }; } -export const schemaId = 'vscode://schemas/settings'; +export const settingsSchema: IJSONSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; +export const resourceSettingsSchema: IJSONSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + export const editorConfigurationSchemaId = 'vscode://schemas/settings/editor'; -export const resourceConfigurationSchemaId = 'vscode://schemas/settings/resource'; const contributionRegistry = Registry.as(JSONExtensions.JSONContribution); class ConfigurationRegistry implements IConfigurationRegistry { + private configurationContributors: IConfigurationNode[]; private configurationProperties: { [qualifiedKey: string]: IJSONSchema }; - private configurationSchema: IJSONSchema; private editorConfigurationSchema: IJSONSchema; - private resourceConfigurationSchema: IJSONSchema; - private _onDidRegisterConfiguration: Emitter; private overrideIdentifiers: string[] = []; private overridePropertyPattern: string; + private _onDidRegisterConfiguration: Emitter = new Emitter(); + readonly onDidRegisterConfiguration: Event = this._onDidRegisterConfiguration.event; + constructor() { this.configurationContributors = []; - this.configurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; this.editorConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting' }; - this.resourceConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Not a resource configuration setting' }; - this._onDidRegisterConfiguration = new Emitter(); this.configurationProperties = {}; this.computeOverridePropertyPattern(); - contributionRegistry.registerSchema(schemaId, this.configurationSchema); contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); - contributionRegistry.registerSchema(resourceConfigurationSchemaId, this.resourceConfigurationSchema); - } - - public get onDidRegisterConfiguration() { - return this._onDidRegisterConfiguration.event; } public registerConfiguration(configuration: IConfigurationNode, validate: boolean = true): void { @@ -119,14 +120,19 @@ class ConfigurationRegistry implements IConfigurationRegistry { } public registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void { + const properties: string[] = []; configurations.forEach(configuration => { - this.validateAndRegisterProperties(configuration, validate); // fills in defaults + properties.push(...this.validateAndRegisterProperties(configuration, validate)); // fills in defaults this.configurationContributors.push(configuration); this.registerJSONConfiguration(configuration); this.updateSchemaForOverrideSettingsConfiguration(configuration); }); - this._onDidRegisterConfiguration.fire(this); + this._onDidRegisterConfiguration.fire(properties); + } + + public notifyConfigurationSchemaUpdated(configuration: IConfigurationNode) { + contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); } public registerOverrideIdentifiers(overrideIdentifiers: string[]): void { @@ -158,9 +164,10 @@ class ConfigurationRegistry implements IConfigurationRegistry { } } - private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW, overridable: boolean = false) { + private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW, overridable: boolean = false): string[] { scope = configuration.scope !== void 0 && configuration.scope !== null ? configuration.scope : scope; overridable = configuration.overridable || overridable; + let propertyKeys = []; let properties = configuration.properties; if (properties) { for (let key in properties) { @@ -185,14 +192,16 @@ class ConfigurationRegistry implements IConfigurationRegistry { } // add to properties map this.configurationProperties[key] = properties[key]; + propertyKeys.push(key); } } let subNodes = configuration.allOf; if (subNodes) { for (let node of subNodes) { - this.validateAndRegisterProperties(node, validate, scope, overridable); + propertyKeys.push(...this.validateAndRegisterProperties(node, validate, scope, overridable)); } } + return propertyKeys; } validateProperty(property: string): boolean { @@ -208,33 +217,34 @@ class ConfigurationRegistry implements IConfigurationRegistry { } private registerJSONConfiguration(configuration: IConfigurationNode) { - let configurationSchema = this.configurationSchema; function register(configuration: IConfigurationNode) { let properties = configuration.properties; if (properties) { for (let key in properties) { - configurationSchema.properties[key] = properties[key]; + settingsSchema.properties[key] = properties[key]; + resourceSettingsSchema.properties[key] = clone(properties[key]); + if (properties[key].scope !== ConfigurationScope.RESOURCE) { + resourceSettingsSchema.properties[key].doNotSuggest = true; + } } } let subNodes = configuration.allOf; if (subNodes) { subNodes.forEach(register); } - }; + } register(configuration); - contributionRegistry.registerSchema(schemaId, configurationSchema); } private updateSchemaForOverrideSettingsConfiguration(configuration: IConfigurationNode): void { if (configuration.id !== SETTINGS_OVERRRIDE_NODE_ID) { this.update(configuration); contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); - contributionRegistry.registerSchema(resourceConfigurationSchemaId, this.resourceConfigurationSchema); } } private updateOverridePropertyPatternKey(): void { - let patternProperties: IJSONSchema = this.configurationSchema.patternProperties[this.overridePropertyPattern]; + let patternProperties: IJSONSchema = settingsSchema.patternProperties[this.overridePropertyPattern]; if (!patternProperties) { patternProperties = { type: 'object', @@ -243,10 +253,11 @@ class ConfigurationRegistry implements IConfigurationRegistry { $ref: editorConfigurationSchemaId }; } - delete this.configurationSchema.patternProperties[this.overridePropertyPattern]; + delete settingsSchema.patternProperties[this.overridePropertyPattern]; this.computeOverridePropertyPattern(); - this.configurationSchema.patternProperties[this.overridePropertyPattern] = patternProperties; - contributionRegistry.registerSchema(schemaId, this.configurationSchema); + + settingsSchema.patternProperties[this.overridePropertyPattern] = patternProperties; + resourceSettingsSchema.patternProperties[this.overridePropertyPattern] = patternProperties; } private update(configuration: IConfigurationNode): void { @@ -256,11 +267,6 @@ class ConfigurationRegistry implements IConfigurationRegistry { if (properties[key].overridable) { this.editorConfigurationSchema.properties[key] = this.getConfigurationProperties()[key]; } - switch (properties[key].scope) { - case ConfigurationScope.RESOURCE: - this.resourceConfigurationSchema.properties[key] = this.getConfigurationProperties()[key]; - break; - } } } let subNodes = configuration.allOf; @@ -311,3 +317,8 @@ export function validateProperty(property: string): string { } return null; } + +export function getScopes(keys: string[]): ConfigurationScope[] { + const configurationProperties = configurationRegistry.getConfigurationProperties(); + return keys.map(key => configurationProperties[key].scope); +} \ No newline at end of file diff --git a/src/vs/platform/configuration/common/model.ts b/src/vs/platform/configuration/common/model.ts deleted file mode 100644 index 53b122efd0e..00000000000 --- a/src/vs/platform/configuration/common/model.ts +++ /dev/null @@ -1,202 +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 { Registry } from 'vs/platform/registry/common/platform'; -import * as json from 'vs/base/common/json'; -import { IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; -import { ConfigurationModel, IOverrides } from 'vs/platform/configuration/common/configuration'; - -export function getDefaultValues(): any { - const valueTreeRoot: any = Object.create(null); - const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - - for (let key in properties) { - let value = properties[key].default; - addToValueTree(valueTreeRoot, key, value, message => console.error(`Conflict in default settings: ${message}`)); - } - - return valueTreeRoot; -} - -export function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any { - const root = Object.create(null); - - for (let key in properties) { - addToValueTree(root, key, properties[key], conflictReporter); - } - - return root; -} - -function addToValueTree(settingsTreeRoot: any, key: string, value: any, conflictReporter: (message: string) => void): void { - const segments = key.split('.'); - const last = segments.pop(); - - let curr = settingsTreeRoot; - for (let i = 0; i < segments.length; i++) { - let s = segments[i]; - let obj = curr[s]; - switch (typeof obj) { - case 'undefined': - obj = curr[s] = Object.create(null); - break; - case 'object': - break; - default: - conflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is ${JSON.stringify(obj)}`); - return; - } - curr = obj; - }; - - if (typeof curr === 'object') { - curr[last] = value; // workaround https://github.com/Microsoft/vscode/issues/13606 - } else { - conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`); - } -} - -export function getConfigurationKeys(): string[] { - const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - - return Object.keys(properties); -} - -export class DefaultConfigurationModel extends ConfigurationModel { - - constructor() { - super(getDefaultValues()); - this._keys = getConfigurationKeys(); - this._overrides = Object.keys(this._contents) - .filter(key => OVERRIDE_PROPERTY_PATTERN.test(key)) - .map(key => { - return >{ - identifiers: [overrideIdentifierFromKey(key).trim()], - contents: toValuesTree(this._contents[key], message => console.error(`Conflict in default settings file: ${message}`)) - }; - }); - } - - public get keys(): string[] { - return this._keys; - } -} - -interface Overrides extends IOverrides { - raw: any; -} - -export class CustomConfigurationModel extends ConfigurationModel { - - protected _parseErrors: any[] = []; - - constructor(content: string = '', private name: string = '') { - super(); - if (content) { - this.update(content); - } - } - - public get errors(): any[] { - return this._parseErrors; - } - - public update(content: string): void { - let parsed: T = {}; - let overrides: Overrides[] = []; - let currentProperty: string = null; - let currentParent: any = []; - let previousParents: any[] = []; - let parseErrors: json.ParseError[] = []; - - function onValue(value: any) { - if (Array.isArray(currentParent)) { - (currentParent).push(value); - } else if (currentProperty) { - currentParent[currentProperty] = value; - } - if (OVERRIDE_PROPERTY_PATTERN.test(currentProperty)) { - onOverrideSettingsValue(currentProperty, value); - } - } - - function onOverrideSettingsValue(property: string, value: any): void { - overrides.push({ - identifiers: [overrideIdentifierFromKey(property).trim()], - raw: value, - contents: null - }); - } - - let visitor: json.JSONVisitor = { - onObjectBegin: () => { - let object = {}; - onValue(object); - previousParents.push(currentParent); - currentParent = object; - currentProperty = null; - }, - onObjectProperty: (name: string) => { - currentProperty = name; - }, - onObjectEnd: () => { - currentParent = previousParents.pop(); - }, - onArrayBegin: () => { - let array: any[] = []; - onValue(array); - previousParents.push(currentParent); - currentParent = array; - currentProperty = null; - }, - onArrayEnd: () => { - currentParent = previousParents.pop(); - }, - onLiteralValue: onValue, - onError: (error: json.ParseErrorCode) => { - parseErrors.push({ error: error }); - } - }; - if (content) { - try { - json.visit(content, visitor); - parsed = currentParent[0] || {}; - } catch (e) { - console.error(`Error while parsing settings file ${this.name}: ${e}`); - this._parseErrors = [e]; - } - } - this.processRaw(parsed); - - const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - this._overrides = overrides.map>(override => { - // Filter unknown and non-overridable properties - const raw = {}; - for (const key in override.raw) { - if (configurationProperties[key] && configurationProperties[key].overridable) { - raw[key] = override.raw[key]; - } - } - return { - identifiers: override.identifiers, - contents: toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)) - }; - }); - } - - protected processRaw(raw: T): void { - this._contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this.name}: ${message}`)); - this._keys = Object.keys(raw); - } -} - -export function overrideIdentifierFromKey(key: string): string { - return key.substring(1, key.length - 1); -} - -export function keyFromOverrideIdentifier(overrideIdentifier: string): string { - return `[${overrideIdentifier}]`; -} \ No newline at end of file diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 2eff5bb204f..baa6c14f8d0 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -4,26 +4,28 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TPromise } from 'vs/base/common/winjs.base'; import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { ConfigurationSource, IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, IConfigurationKeys, ConfigurationModel, IConfigurationOverrides, Configuration, IConfigurationValues, IConfigurationData } from 'vs/platform/configuration/common/configuration'; -import { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration'; +import { CustomConfigurationModel, DefaultConfigurationModel, ConfigurationModel, Configuration, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { equals } from 'vs/base/common/objects'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { +export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { _serviceBrand: any; - private _configuration: Configuration; - private userConfigModelWatcher: ConfigWatcher>; + private _configuration: Configuration; + private userConfigModelWatcher: ConfigWatcher; - private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; + private _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; constructor( @IEnvironmentService environmentService: IEnvironmentService @@ -31,70 +33,111 @@ export class ConfigurationService extends Disposable implements IConfiguratio super(); this.userConfigModelWatcher = new ConfigWatcher(environmentService.appSettingsPath, { - changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new CustomConfigurationModel(null, environmentService.appSettingsPath), parse: (content: string, parseErrors: any[]) => { - const userConfigModel = new CustomConfigurationModel(content, environmentService.appSettingsPath); + changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new CustomConfigurationModel(null, environmentService.appSettingsPath), parse: (content: string, parseErrors: any[]) => { + const userConfigModel = new CustomConfigurationModel(content, environmentService.appSettingsPath); parseErrors = [...userConfigModel.errors]; return userConfigModel; } }); - this._register(toDisposable(() => this.userConfigModelWatcher.dispose())); + this._register(this.userConfigModelWatcher); + + this.reset(); // Listeners - this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this.onConfigurationChange(ConfigurationSource.User))); - this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(() => this.onConfigurationChange(ConfigurationSource.Default))); + this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this.onDidUpdateConfigModel())); + this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(configurationProperties => this.onDidRegisterConfiguration(configurationProperties))); } - public configuration(): Configuration { - return this._configuration || (this._configuration = this.consolidateConfigurations()); + get configuration(): Configuration { + return this._configuration; } - private onConfigurationChange(source: ConfigurationSource): void { + getConfigurationData(): IConfigurationData { + return this.configuration.toData(); + } + + getConfiguration(): T; + getConfiguration(section: string): T; + getConfiguration(overrides: IConfigurationOverrides): T; + getConfiguration(section: string, overrides: IConfigurationOverrides): T; + getConfiguration(arg1?: any, arg2?: any): any { + const section = typeof arg1 === 'string' ? arg1 : void 0; + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : {}; + return this.configuration.getSection(section, overrides, null); + } + + getValue(key: string, overrides: IConfigurationOverrides = {}): any { + return this.configuration.getValue(key, overrides, null); + } + + updateValue(key: string, value: any): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise; + updateValue(key: string, value: any, target: ConfigurationTarget): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise; + updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise { + return TPromise.wrapError(new Error('not supported')); + } + + inspect(key: string): { + default: T, + user: T, + workspace: T, + workspaceFolder: T + value: T + } { + return this.configuration.lookup(key, {}, null); + } + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + return this.configuration.keys(null); + } + + reloadConfiguration(folder?: IWorkspaceFolder): TPromise { + return folder ? TPromise.as(null) : + new TPromise((c, e) => this.userConfigModelWatcher.reload(() => c(this.onDidUpdateConfigModel()))); + } + + private onDidUpdateConfigModel(): void { + let changedKeys = []; + const { added, updated, removed } = compare(this._configuration.user, this.userConfigModelWatcher.getConfig()); + changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = this._configuration; + this.reset(); + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key, {}, null), this._configuration.getValue(key, {}, null))); + if (changedKeys.length) { + this.trigger(changedKeys, ConfigurationTarget.USER); + } + } + } + + private onDidRegisterConfiguration(keys: string[]): void { this.reset(); // reset our caches - - const cache = this.configuration(); - - this._onDidUpdateConfiguration.fire({ - source, - sourceConfig: source === ConfigurationSource.Default ? cache.defaults.contents : cache.user.contents - }); - } - - public reloadConfiguration(section?: string): TPromise { - return new TPromise(c => { - this.userConfigModelWatcher.reload(() => { - this.reset(); // reset our caches - c(this.getConfiguration(section)); - }); - }); - } - - public getConfiguration(section?: string, options?: IConfigurationOverrides): C { - return this.configuration().getValue(section, options); - } - - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { - return this.configuration().lookup(key, overrides); - } - - public keys(overrides?: IConfigurationOverrides): IConfigurationKeys { - return this.configuration().keys(overrides); - } - - public values(): IConfigurationValues { - return this._configuration.values(); - } - - public getConfigurationData(): IConfigurationData { - return this.configuration().toData(); + this.trigger(keys, ConfigurationTarget.DEFAULT); } private reset(): void { - this._configuration = this.consolidateConfigurations(); + const defaults = new DefaultConfigurationModel(); + const user = this.userConfigModelWatcher.getConfig(); + this._configuration = new Configuration(defaults, user); } - private consolidateConfigurations(): Configuration { - const defaults = new DefaultConfigurationModel(); - const user = this.userConfigModelWatcher.getConfig(); - return new Configuration(defaults, user); + private trigger(keys: string[], source: ConfigurationTarget): void { + this._onDidChangeConfiguration.fire(new ConfigurationChangeEvent().change(keys).telemetryData(source, this.getTargetConfiguration(source))); + } + + private getTargetConfiguration(target: ConfigurationTarget): any { + switch (target) { + case ConfigurationTarget.DEFAULT: + return this._configuration.defaults.contents; + case ConfigurationTarget.USER: + return this._configuration.user.contents; + } + return {}; } } \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/configuration.test.ts b/src/vs/platform/configuration/test/common/configuration.test.ts index dfdb42ffd4b..456df853e01 100644 --- a/src/vs/platform/configuration/test/common/configuration.test.ts +++ b/src/vs/platform/configuration/test/common/configuration.test.ts @@ -5,29 +5,10 @@ 'use strict'; import * as assert from 'assert'; -import { ConfigurationModel, merge } from 'vs/platform/configuration/common/configuration'; -import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; +import { merge, removeFromValueTree } from 'vs/platform/configuration/common/configuration'; suite('Configuration', () => { - suiteSetup(() => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'a', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - 'a': { - 'description': 'a', - 'type': 'boolean', - 'default': true, - 'overridable': true - } - } - }); - }); - test('simple merge', () => { let base = { 'a': 1, 'b': 2 }; merge(base, { 'a': 3, 'c': 4 }, true); @@ -37,43 +18,92 @@ suite('Configuration', () => { assert.deepEqual(base, { 'a': 1, 'b': 2, 'c': 4 }); }); - test('Recursive merge', () => { - const base = { 'a': { 'b': 1 } }; - merge(base, { 'a': { 'b': 2 } }, true); - assert.deepEqual(base, { 'a': { 'b': 2 } }); + test('removeFromValueTree: remove a non existing key', () => { + let target = { 'a': { 'b': 2 } }; + + removeFromValueTree(target, 'c'); + + assert.deepEqual(target, { 'a': { 'b': 2 } }); }); - test('simple merge using configuration', () => { - let base = new ConfigurationModel({ 'a': 1, 'b': 2 }); - let add = new ConfigurationModel({ 'a': 3, 'c': 4 }); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); + test('removeFromValueTree: remove a multi segmented key from an object that has only sub sections of the key', () => { + let target = { 'a': { 'b': 2 } }; + + removeFromValueTree(target, 'a.b.c'); + + assert.deepEqual(target, { 'a': { 'b': 2 } }); }); - test('Recursive merge using config models', () => { - let base = new ConfigurationModel({ 'a': { 'b': 1 } }); - let add = new ConfigurationModel({ 'a': { 'b': 2 } }); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); + test('removeFromValueTree: remove a single segemented key', () => { + let target = { 'a': 1 }; + + removeFromValueTree(target, 'a'); + + assert.deepEqual(target, {}); }); - test('Test contents while getting an existing property', () => { - let testObject = new ConfigurationModel({ 'a': 1 }); - assert.deepEqual(testObject.getContentsFor('a'), 1); + test('removeFromValueTree: remove a single segemented key when its value is undefined', () => { + let target = { 'a': void 0 }; - testObject = new ConfigurationModel({ 'a': { 'b': 1 } }); - assert.deepEqual(testObject.getContentsFor('a'), { 'b': 1 }); + removeFromValueTree(target, 'a'); + + assert.deepEqual(target, {}); }); - test('Test contents are undefined for non existing properties', () => { - const testObject = new ConfigurationModel({ awesome: true }); + test('removeFromValueTree: remove a multi segemented key when its value is undefined', () => { + let target = { 'a': { 'b': 1 } }; - assert.deepEqual(testObject.getContentsFor('unknownproperty'), undefined); + removeFromValueTree(target, 'a.b'); + + assert.deepEqual(target, {}); }); - test('Test override gives all content merged with overrides', () => { - const testObject = new ConfigurationModel({ 'a': 1, 'c': 1 }, [], [{ identifiers: ['b'], contents: { 'a': 2 } }]); + test('removeFromValueTree: remove a multi segemented key when its value is array', () => { + let target = { 'a': { 'b': [1] } }; - assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1 }); + removeFromValueTree(target, 'a.b'); + + assert.deepEqual(target, {}); }); + + test('removeFromValueTree: remove a multi segemented key first segment value is array', () => { + let target = { 'a': [1] }; + + removeFromValueTree(target, 'a.0'); + + assert.deepEqual(target, { 'a': [1] }); + }); + + test('removeFromValueTree: remove when key is the first segmenet', () => { + let target = { 'a': { 'b': 1 } }; + + removeFromValueTree(target, 'a'); + + assert.deepEqual(target, {}); + }); + + test('removeFromValueTree: remove a multi segemented key when the first node has more values', () => { + let target = { 'a': { 'b': { 'c': 1 }, 'd': 1 } }; + + removeFromValueTree(target, 'a.b.c'); + + assert.deepEqual(target, { 'a': { 'd': 1 } }); + }); + + test('removeFromValueTree: remove a multi segemented key when in between node has more values', () => { + let target = { 'a': { 'b': { 'c': { 'd': 1 }, 'd': 1 } } }; + + removeFromValueTree(target, 'a.b.c.d'); + + assert.deepEqual(target, { 'a': { 'b': { 'd': 1 } } }); + }); + + test('removeFromValueTree: remove a multi segemented key when the last but one node has more values', () => { + let target = { 'a': { 'b': { 'c': 1, 'd': 1 } } }; + + removeFromValueTree(target, 'a.b.c'); + + assert.deepEqual(target, { 'a': { 'b': { 'd': 1 } } }); + }); + }); \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts new file mode 100644 index 00000000000..0bf2c7ea154 --- /dev/null +++ b/src/vs/platform/configuration/test/common/configurationModels.test.ts @@ -0,0 +1,550 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ConfigurationModel, CustomConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; +import URI from 'vs/base/common/uri'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; + +suite('ConfigurationModel', () => { + + test('setValue for a key that has no sections and not defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b']); + + testObject.setValue('f', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'f']); + }); + + test('setValue for a key that has no sections and defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('f', 3); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'f': 3 }); + assert.deepEqual(testObject.keys, ['a.b', 'f']); + }); + + test('setValue for a key that has sections and not defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('b.c', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'b': { 'c': 1 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'f', 'b.c']); + }); + + test('setValue for a key that has sections and defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'b': { 'c': 1 }, 'f': 1 }, ['a.b', 'b.c', 'f']); + + testObject.setValue('b.c', 3); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1 }, 'b': { 'c': 3 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'b.c', 'f']); + }); + + test('setValue for a key that has sections and sub section not defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('a.c', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1, 'c': 1 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'f', 'a.c']); + }); + + test('setValue for a key that has sections and sub section defined', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1, 'c': 1 }, 'f': 1 }, ['a.b', 'a.c', 'f']); + + testObject.setValue('a.c', 3); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 1, 'c': 3 }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b', 'a.c', 'f']); + }); + + test('setValue for a key that has sections and last section is added', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': {} }, 'f': 1 }, ['a.b', 'f']); + + testObject.setValue('a.b.c', 1); + + assert.deepEqual(testObject.contents, { 'a': { 'b': { 'c': 1 } }, 'f': 1 }); + assert.deepEqual(testObject.keys, ['a.b.c', 'f']); + }); + + test('removeValue: remove a non existing key', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 2 } }, ['a.b']); + + testObject.removeValue('a.b.c'); + + assert.deepEqual(testObject.contents, { 'a': { 'b': 2 } }); + assert.deepEqual(testObject.keys, ['a.b']); + }); + + test('removeValue: remove a single segemented key', () => { + let testObject = new ConfigurationModel({ 'a': 1 }, ['a']); + + testObject.removeValue('a'); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + }); + + test('removeValue: remove a multi segemented key', () => { + let testObject = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b']); + + testObject.removeValue('a.b'); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + }); + + test('setValueInOverrides adds to overrides if does not exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a']); + + testObject.setValueInOverrides('or', 'a', 2); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': 2 }); + assert.deepEqual(testObject.override('or').contents, { 'a': 2, 'b': 1 }); + }); + + test('setValueInOverrides adds to overrides if exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or'], contents: { 'a': 2 } }]); + + testObject.setValueInOverrides('or', 'a', 3); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': 3 }); + assert.deepEqual(testObject.override('or').contents, { 'a': 3, 'b': 1 }); + }); + + test('setValueInOverrides adds a nested key to overrides if exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or'], contents: { 'a': { 'c': 1 } } }]); + + testObject.setValueInOverrides('or', 'a.c', 2); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': { 'c': 2 } }); + assert.deepEqual(testObject.override('or').contents, { 'a': { 'c': 2 }, 'b': 1 }); + }); + + test('setValueInOverrides adds new overrides if exist', () => { + let testObject = new ConfigurationModel({ 'a': 1, 'b': 1 }, ['a'], [{ identifiers: ['or1'], contents: { 'a': 2 } }]); + + testObject.setValueInOverrides('or2', 'b', 2); + + assert.deepEqual(testObject.overrides[0].contents, { 'a': 2 }); + assert.deepEqual(testObject.overrides[1].contents, { 'b': 2 }); + assert.deepEqual(testObject.override('or1').contents, { 'a': 2, 'b': 1 }); + assert.deepEqual(testObject.override('or2').contents, { 'a': 1, 'b': 2 }); + }); + + test('get overriding configuration model for an existing identifier', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': 1 }); + }); + + test('get overriding configuration model for an identifier that does not exist', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); + + assert.deepEqual(testObject.override('xyz').contents, { 'a': { 'b': 1 }, 'f': 1 }); + }); + + test('get overriding configuration when one of the keys does not exist in base', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 }, 'g': 1 } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': 1, 'g': 1 }); + }); + + test('get overriding configuration when one of the key in base is not of object type', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': 1 }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 }, 'f': { 'g': 1 } } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': { 'g': 1 } }); + }); + + test('get overriding configuration when one of the key in overriding contents is not of object type', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': { 'g': 1 } }, [], + [{ identifiers: ['c'], contents: { 'a': { 'd': 1 }, 'f': 1 } }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1, 'd': 1 }, 'f': 1 }); + }); + + test('get overriding configuration if the value of overriding identifier is not object', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': { 'g': 1 } }, [], + [{ identifiers: ['c'], contents: 'abc' }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1 }, 'f': { 'g': 1 } }); + }); + + test('get overriding configuration if the value of overriding identifier is an empty object', () => { + let testObject = new ConfigurationModel( + { 'a': { 'b': 1 }, 'f': { 'g': 1 } }, [], + [{ identifiers: ['c'], contents: {} }]); + + assert.deepEqual(testObject.override('c').contents, { 'a': { 'b': 1 }, 'f': { 'g': 1 } }); + }); + + test('simple merge', () => { + let base = new ConfigurationModel({ 'a': 1, 'b': 2 }, ['a', 'b']); + let add = new ConfigurationModel({ 'a': 3, 'c': 4 }, ['a', 'c']); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); + assert.deepEqual(result.keys, ['a', 'b', 'c']); + }); + + test('recursive merge', () => { + let base = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b']); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }, ['a.b']); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); + assert.deepEqual(result.getSectionContents('a'), { 'b': 2 }); + assert.deepEqual(result.keys, ['a.b']); + }); + + test('simple merge overrides', () => { + let base = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b'], [{ identifiers: ['c'], contents: { 'a': 2 } }]); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }, ['a.b'], [{ identifiers: ['c'], contents: { 'b': 2 } }]); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); + assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': 2, 'b': 2 } }]); + assert.deepEqual(result.override('c').contents, { 'a': 2, 'b': 2 }); + assert.deepEqual(result.keys, ['a.b']); + }); + + test('recursive merge overrides', () => { + let base = new ConfigurationModel({ 'a': { 'b': 1 }, 'f': 1 }, ['a.b', 'f'], [{ identifiers: ['c'], contents: { 'a': { 'd': 1 } } }]); + let add = new ConfigurationModel({ 'a': { 'b': 2 } }, ['a.b'], [{ identifiers: ['c'], contents: { 'a': { 'e': 2 } } }]); + let result = base.merge(add); + + assert.deepEqual(result.contents, { 'a': { 'b': 2 }, 'f': 1 }); + assert.deepEqual(result.overrides, [{ identifiers: ['c'], contents: { 'a': { 'd': 1, 'e': 2 } } }]); + assert.deepEqual(result.override('c').contents, { 'a': { 'b': 2, 'd': 1, 'e': 2 }, 'f': 1 }); + assert.deepEqual(result.keys, ['a.b', 'f']); + }); + + test('Test contents while getting an existing property', () => { + let testObject = new ConfigurationModel({ 'a': 1 }); + assert.deepEqual(testObject.getSectionContents('a'), 1); + + testObject = new ConfigurationModel({ 'a': { 'b': 1 } }); + assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); + }); + + test('Test contents are undefined for non existing properties', () => { + const testObject = new ConfigurationModel({ awesome: true }); + + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); + }); + + test('Test override gives all content merged with overrides', () => { + const testObject = new ConfigurationModel({ 'a': 1, 'c': 1 }, [], [{ identifiers: ['b'], contents: { 'a': 2 } }]); + + assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1 }); + }); +}); + +suite('CustomConfigurationModel', () => { + + suiteSetup(() => { + Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': 'a', + 'order': 1, + 'title': 'a', + 'type': 'object', + 'properties': { + 'a': { + 'description': 'a', + 'type': 'boolean', + 'default': true, + 'overridable': true + } + } + }); + }); + + test('simple merge using models', () => { + let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); + let add = new CustomConfigurationModel(JSON.stringify({ 'a': 3, 'c': 4 })); + let result = base.merge(add); + assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); + }); + + test('simple merge with an undefined contents', () => { + let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); + let add = new CustomConfigurationModel(null); + let result = base.merge(add); + assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); + + base = new CustomConfigurationModel(null); + add = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); + result = base.merge(add); + assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); + + base = new CustomConfigurationModel(null); + add = new CustomConfigurationModel(null); + result = base.merge(add); + assert.deepEqual(result.contents, {}); + }); + + test('Recursive merge using config models', () => { + let base = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); + let add = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 2 } })); + let result = base.merge(add); + assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); + }); + + test('Test contents while getting an existing property', () => { + let testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1 })); + assert.deepEqual(testObject.getSectionContents('a'), 1); + + testObject = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); + assert.deepEqual(testObject.getSectionContents('a'), { 'b': 1 }); + }); + + test('Test contents are undefined for non existing properties', () => { + const testObject = new CustomConfigurationModel(JSON.stringify({ + awesome: true + })); + + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); + }); + + test('Test contents are undefined for undefined config', () => { + const testObject = new CustomConfigurationModel(null); + + assert.deepEqual(testObject.getSectionContents('unknownproperty'), undefined); + }); + + test('Test configWithOverrides gives all content merged with overrides', () => { + const testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } })); + + assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } }); + }); + + test('Test configWithOverrides gives empty contents', () => { + const testObject = new CustomConfigurationModel(null); + + assert.deepEqual(testObject.override('b').contents, {}); + }); + + test('Test update with empty data', () => { + const testObject = new CustomConfigurationModel(); + testObject.update(''); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + + testObject.update(null); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + + testObject.update(undefined); + + assert.deepEqual(testObject.contents, {}); + assert.deepEqual(testObject.keys, []); + }); + + test('Test registering the same property again', () => { + Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': 'a', + 'order': 1, + 'title': 'a', + 'type': 'object', + 'properties': { + 'a': { + 'description': 'a', + 'type': 'boolean', + 'default': false, + } + } + }); + assert.equal(true, new DefaultConfigurationModel().getSectionContents('a')); + }); + + test('Test registering the language property', () => { + Registry.as(Extensions.Configuration).registerConfiguration({ + 'id': '[a]', + 'order': 1, + 'title': 'a', + 'type': 'object', + 'properties': { + '[a]': { + 'description': 'a', + 'type': 'boolean', + 'default': false, + } + } + }); + assert.equal(undefined, new DefaultConfigurationModel().getSectionContents('[a]')); + }); + +}); + +suite('ConfigurationChangeEvent', () => { + + test('changeEvent affecting keys for all resources', () => { + let testObject = new ConfigurationChangeEvent(); + + testObject.change(['window.zoomLevel', 'workbench.editor.enablePreview', 'files', '[markdown]']); + + assert.deepEqual(testObject.affectedKeys, ['window.zoomLevel', 'workbench.editor.enablePreview', 'files', '[markdown]']); + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files.exclude')); + assert.ok(testObject.affectsConfiguration('[markdown]')); + }); + + test('changeEvent affecting a root key and its children', () => { + let testObject = new ConfigurationChangeEvent(); + + testObject.change(['launch', 'launch.version', 'tasks']); + + assert.deepEqual(testObject.affectedKeys, ['launch.version', 'tasks']); + assert.ok(testObject.affectsConfiguration('launch')); + assert.ok(testObject.affectsConfiguration('launch.version')); + assert.ok(testObject.affectsConfiguration('tasks')); + }); + + test('changeEvent affecting keys for resources', () => { + let testObject = new ConfigurationChangeEvent(); + + testObject.change(['window.title']); + testObject.change(['window.zoomLevel'], URI.file('file1')); + testObject.change(['workbench.editor.enablePreview'], URI.file('file2')); + testObject.change(['window.restoreFullscreen'], URI.file('file1')); + testObject.change(['window.restoreWindows'], URI.file('file2')); + + assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); + + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('window.restoreWindows')); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file('file1'))); + + assert.ok(testObject.affectsConfiguration('window.title')); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file1'))); + + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file('file1'))); + + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('workbench', URI.file('file1'))); + + assert.ok(!testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file('file2'))); + }); + + test('merging change events', () => { + let event1 = new ConfigurationChangeEvent().change(['window.zoomLevel', 'files']); + let event2 = new ConfigurationChangeEvent().change(['window.title'], URI.file('file1')).change(['[markdown]']); + + let actual = event1.change(event2); + + assert.deepEqual(actual.affectedKeys, ['window.zoomLevel', 'files', '[markdown]', 'window.title']); + + assert.ok(actual.affectsConfiguration('window.zoomLevel')); + assert.ok(actual.affectsConfiguration('window.zoomLevel', URI.file('file1'))); + assert.ok(actual.affectsConfiguration('window.zoomLevel', URI.file('file2'))); + + assert.ok(actual.affectsConfiguration('window')); + assert.ok(actual.affectsConfiguration('window', URI.file('file1'))); + assert.ok(actual.affectsConfiguration('window', URI.file('file2'))); + + assert.ok(actual.affectsConfiguration('files')); + assert.ok(actual.affectsConfiguration('files', URI.file('file1'))); + assert.ok(actual.affectsConfiguration('files', URI.file('file2'))); + + assert.ok(actual.affectsConfiguration('window.title')); + assert.ok(actual.affectsConfiguration('window.title', URI.file('file1'))); + assert.ok(!actual.affectsConfiguration('window.title', URI.file('file2'))); + + assert.ok(actual.affectsConfiguration('[markdown]')); + assert.ok(actual.affectsConfiguration('[markdown]', URI.file('file1'))); + assert.ok(actual.affectsConfiguration('[markdown]', URI.file('file2'))); + }); + +}); + +suite('AllKeysConfigurationChangeEvent', () => { + + test('changeEvent affects keys for any resource', () => { + let testObject = new AllKeysConfigurationChangeEvent(['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows'], ConfigurationTarget.USER, null); + + assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); + + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('window.restoreWindows')); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file1'))); + + assert.ok(testObject.affectsConfiguration('window.title')); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file2'))); + + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file1'))); + + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file1'))); + + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('file1'))); + + assert.ok(!testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files', URI.file('file1'))); + }); +}); \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/model.test.ts b/src/vs/platform/configuration/test/common/model.test.ts deleted file mode 100644 index aa9597b6702..00000000000 --- a/src/vs/platform/configuration/test/common/model.test.ts +++ /dev/null @@ -1,148 +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 { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/model'; -import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; - -suite('Configuration', () => { - - suiteSetup(() => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'a', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - 'a': { - 'description': 'a', - 'type': 'boolean', - 'default': true, - 'overridable': true - } - } - }); - }); - - test('simple merge using models', () => { - let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); - let add = new CustomConfigurationModel(JSON.stringify({ 'a': 3, 'c': 4 })); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 }); - }); - - test('simple merge with an undefined contents', () => { - let base = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); - let add = new CustomConfigurationModel(null); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); - - base = new CustomConfigurationModel(null); - add = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'b': 2 })); - result = base.merge(add); - assert.deepEqual(result.contents, { 'a': 1, 'b': 2 }); - - base = new CustomConfigurationModel(null); - add = new CustomConfigurationModel(null); - result = base.merge(add); - assert.deepEqual(result.contents, {}); - }); - - test('Recursive merge using config models', () => { - let base = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); - let add = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 2 } })); - let result = base.merge(add); - assert.deepEqual(result.contents, { 'a': { 'b': 2 } }); - }); - - test('Test contents while getting an existing property', () => { - let testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1 })); - assert.deepEqual(testObject.getContentsFor('a'), 1); - - testObject = new CustomConfigurationModel(JSON.stringify({ 'a': { 'b': 1 } })); - assert.deepEqual(testObject.getContentsFor('a'), { 'b': 1 }); - }); - - test('Test contents are undefined for non existing properties', () => { - const testObject = new CustomConfigurationModel(JSON.stringify({ - awesome: true - })); - - assert.deepEqual(testObject.getContentsFor('unknownproperty'), undefined); - }); - - test('Test contents are undefined for undefined config', () => { - const testObject = new CustomConfigurationModel(null); - - assert.deepEqual(testObject.getContentsFor('unknownproperty'), undefined); - }); - - test('Test configWithOverrides gives all content merged with overrides', () => { - const testObject = new CustomConfigurationModel(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } })); - - assert.deepEqual(testObject.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } }); - }); - - test('Test configWithOverrides gives empty contents', () => { - const testObject = new CustomConfigurationModel(null); - - assert.deepEqual(testObject.override('b').contents, {}); - }); - - test('Test update with empty data', () => { - const testObject = new CustomConfigurationModel(); - testObject.update(''); - - assert.deepEqual(testObject.contents, {}); - assert.deepEqual(testObject.keys, []); - - testObject.update(null); - - assert.deepEqual(testObject.contents, {}); - assert.deepEqual(testObject.keys, []); - - testObject.update(undefined); - - assert.deepEqual(testObject.contents, {}); - assert.deepEqual(testObject.keys, []); - }); - - test('Test registering the same property again', () => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': 'a', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - 'a': { - 'description': 'a', - 'type': 'boolean', - 'default': false, - } - } - }); - assert.equal(true, new DefaultConfigurationModel().getContentsFor('a')); - }); - - test('Test registering the language property', () => { - Registry.as(Extensions.Configuration).registerConfiguration({ - 'id': '[a]', - 'order': 1, - 'title': 'a', - 'type': 'object', - 'properties': { - '[a]': { - 'description': 'a', - 'type': 'boolean', - 'default': false, - } - } - }); - assert.equal(undefined, new DefaultConfigurationModel().getContentsFor('[a]')); - }); - -}); \ No newline at end of file diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index e7f948d824c..dcb88e2eb1d 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -5,25 +5,25 @@ 'use strict'; -import { TrieMap } from 'vs/base/common/map'; +import { TernarySearchTree } from 'vs/base/common/map'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { getConfigurationKeys } from 'vs/platform/configuration/common/model'; -import { IConfigurationOverrides, IConfigurationService, getConfigurationValue, IConfigurationValue, IConfigurationKeys, IConfigurationValues, IConfigurationData, Configuration, ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue, isConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; export class TestConfigurationService extends EventEmitter implements IConfigurationService { public _serviceBrand: any; private configuration = Object.create(null); - private configurationByRoot: TrieMap = new TrieMap(); + private configurationByRoot: TernarySearchTree = TernarySearchTree.forPaths(); - public reloadConfiguration(section?: string): TPromise { + public reloadConfiguration(): TPromise { return TPromise.as(this.getConfiguration()); } - public getConfiguration(section?: string, overrides?: IConfigurationOverrides): any { + public getConfiguration(arg1?: any, arg2?: any): C { + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; if (overrides && overrides.resource) { const configForResource = this.configurationByRoot.findSubstr(overrides.resource.fsPath); return configForResource || this.configuration; @@ -32,15 +32,19 @@ export class TestConfigurationService extends EventEmitter implements IConfigura return this.configuration; } - public getConfigurationData(): IConfigurationData { - return new Configuration(new ConfigurationModel(), new ConfigurationModel(this.configuration)).toData(); + public getValue(key: string, overrides?: IConfigurationOverrides): any { + return this.inspect(key).value; + } + + public updateValue(key: string, overrides?: IConfigurationOverrides): TPromise { + return TPromise.as(null); } public setUserConfiguration(key: any, value: any, root?: URI): Thenable { if (root) { - const configForRoot = this.configurationByRoot.lookUp(root.fsPath) || Object.create(null); + const configForRoot = this.configurationByRoot.get(root.fsPath) || Object.create(null); configForRoot[key] = value; - this.configurationByRoot.insert(root.fsPath, configForRoot); + this.configurationByRoot.set(root.fsPath, configForRoot); } else { this.configuration[key] = value; } @@ -48,32 +52,38 @@ export class TestConfigurationService extends EventEmitter implements IConfigura return TPromise.as(null); } - public onDidUpdateConfiguration() { + public onDidChangeConfiguration() { return { dispose() { } }; } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { + public inspect(key: string, overrides?: IConfigurationOverrides): { + default: T, + user: T, + workspace: T, + workspaceFolder: T + value: T, + } { const config = this.getConfiguration(undefined, overrides); return { - value: getConfigurationValue(config, key), - default: getConfigurationValue(config, key), - user: getConfigurationValue(config, key), + value: getConfigurationValue(config, key), + default: getConfigurationValue(config, key), + user: getConfigurationValue(config, key), workspace: null, - folder: null + workspaceFolder: null }; } - public keys(): IConfigurationKeys { + public keys() { return { default: getConfigurationKeys(), user: Object.keys(this.configuration), workspace: [], - folder: [] + workspaceFolder: [] }; } - public values(): IConfigurationValues { - return {}; + public getConfigurationData() { + return null; } } diff --git a/src/vs/platform/configuration/test/node/configurationService.test.ts b/src/vs/platform/configuration/test/node/configurationService.test.ts index 594a6eb5287..60652d4b614 100644 --- a/src/vs/platform/configuration/test/node/configurationService.test.ts +++ b/src/vs/platform/configuration/test/node/configurationService.test.ts @@ -122,7 +122,8 @@ suite('ConfigurationService - Node', () => { assert.equal(config.foo, 'bar'); // force a reload to get latest - service.reloadConfiguration<{ foo: string }>().then(config => { + service.reloadConfiguration().then(() => { + config = service.getConfiguration<{ foo: string }>(); assert.ok(config); assert.equal(config.foo, 'changed'); @@ -202,12 +203,12 @@ suite('ConfigurationService - Node', () => { testFile((testFile, cleanUp) => { const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile)); - let res = service.lookup('something.missing'); + let res = service.inspect('something.missing'); assert.strictEqual(res.value, void 0); assert.strictEqual(res.default, void 0); assert.strictEqual(res.user, void 0); - res = service.lookup('lookup.service.testSetting'); + res = service.inspect('lookup.service.testSetting'); assert.strictEqual(res.default, 'isSet'); assert.strictEqual(res.value, 'isSet'); assert.strictEqual(res.user, void 0); @@ -215,7 +216,7 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(testFile, '{ "lookup.service.testSetting": "bar" }'); return service.reloadConfiguration().then(() => { - res = service.lookup('lookup.service.testSetting'); + res = service.inspect('lookup.service.testSetting'); assert.strictEqual(res.default, 'isSet'); assert.strictEqual(res.user, 'bar'); assert.strictEqual(res.value, 'bar'); @@ -242,7 +243,7 @@ suite('ConfigurationService - Node', () => { testFile((testFile, cleanUp) => { const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile)); - let res = service.lookup('lookup.service.testNullSetting'); + let res = service.inspect('lookup.service.testNullSetting'); assert.strictEqual(res.default, null); assert.strictEqual(res.value, null); assert.strictEqual(res.user, void 0); @@ -250,7 +251,7 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(testFile, '{ "lookup.service.testNullSetting": null }'); return service.reloadConfiguration().then(() => { - res = service.lookup('lookup.service.testNullSetting'); + res = service.inspect('lookup.service.testNullSetting'); assert.strictEqual(res.default, null); assert.strictEqual(res.value, null); assert.strictEqual(res.user, null); diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index df96f3c0c0d..3ae51a0edea 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -8,7 +8,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { IContextKey, IContext, IContextKeyServiceTarget, IContextKeyService, SET_CONTEXT_COMMAND_ID, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import Event, { Emitter, debounceEvent } from 'vs/base/common/event'; const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context'; @@ -37,7 +37,11 @@ export class Context implements IContext { public removeValue(key: string): boolean { // console.log('REMOVE ' + key + ' FROM ' + this._id); - return delete this._value[key]; + if (key in this._value) { + delete this._value[key]; + return true; + } + return false; } public getValue(key: string): T { @@ -51,22 +55,42 @@ export class Context implements IContext { class ConfigAwareContextValuesContainer extends Context { - private _emitter: Emitter; - private _subscription: IDisposable; + private readonly _emitter: Emitter; + private readonly _subscription: IDisposable; + private readonly _configurationService: IConfigurationService; constructor(id: number, configurationService: IConfigurationService, emitter: Emitter) { super(id, null); this._emitter = emitter; - this._subscription = configurationService.onDidUpdateConfiguration(e => this._updateConfigurationContext(configurationService.getConfiguration())); - this._updateConfigurationContext(configurationService.getConfiguration()); + this._configurationService = configurationService; + this._subscription = configurationService.onDidChangeConfiguration(this._onConfigurationUpdated, this); + this._initFromConfiguration(); } public dispose() { this._subscription.dispose(); } - private _updateConfigurationContext(config: any) { + private _onConfigurationUpdated(event: IConfigurationChangeEvent): void { + if (event.source === ConfigurationTarget.DEFAULT) { + // new setting, rebuild everything + this._initFromConfiguration(); + } else { + // update those that we know + for (const configKey of event.affectedKeys) { + const contextKey = `config.${configKey}`; + if (contextKey in this._value) { + this._value[contextKey] = this._configurationService.getValue(configKey); + this._emitter.fire(configKey); + } + } + } + } + + private _initFromConfiguration() { + + const config = this._configurationService.getConfiguration(); // remove old config.xyz values for (let key in this._value) { diff --git a/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts index 3a3b3e0e22c..3f7b444a829 100644 --- a/src/vs/platform/contextview/browser/contextMenuHandler.ts +++ b/src/vs/platform/contextview/browser/contextMenuHandler.ts @@ -44,6 +44,12 @@ export class ContextMenuHandler { this.toDispose.push(this.actionRunner.addListener(EventType.BEFORE_RUN, (e: any) => { if (this.telemetryService) { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'contextMenu' }); } @@ -74,7 +80,7 @@ export class ContextMenuHandler { } if (container) { this.$el = $(container); - this.$el.on('mousedown', (e: MouseEvent) => this.onMouseDown(e)); + this.$el.on('mousedown', (e: Event) => this.onMouseDown(e as MouseEvent)); } } diff --git a/src/vs/platform/contextview/browser/contextView.ts b/src/vs/platform/contextview/browser/contextView.ts index 867695d03d9..2ba1ac24e32 100644 --- a/src/vs/platform/contextview/browser/contextView.ts +++ b/src/vs/platform/contextview/browser/contextView.ts @@ -51,6 +51,7 @@ export interface IContextMenuDelegate { getMenuClassName?(): string; onHide?(didCancel: boolean): void; actionRunner?: IActionRunner; + autoSelectFirstItem?: boolean; } export class ContextSubMenu extends Action { diff --git a/src/vs/platform/credentials/node/credentialsService.ts b/src/vs/platform/credentials/node/credentialsService.ts index 9f723af119e..f3aa0dd3121 100644 --- a/src/vs/platform/credentials/node/credentialsService.ts +++ b/src/vs/platform/credentials/node/credentialsService.ts @@ -6,22 +6,29 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; -import * as keytar from 'keytar'; export class CredentialsService implements ICredentialsService { _serviceBrand: any; readSecret(service: string, account: string): TPromise { - return TPromise.wrap(keytar.getPassword(service, account)) + return this.getKeytar() + .then(keytar => TPromise.wrap(keytar.getPassword(service, account))) .then(result => result === null ? undefined : result); } writeSecret(service: string, account: string, secret: string): TPromise { - return TPromise.wrap(keytar.setPassword(service, account, secret)); + return this.getKeytar() + .then(keytar => TPromise.wrap(keytar.setPassword(service, account, secret))); } deleteSecret(service: string, account: string): TPromise { - return TPromise.wrap(keytar.deletePassword(service, account)); + return this.getKeytar() + .then(keytar => TPromise.wrap(keytar.deletePassword(service, account))); + } + + private getKeytar() { + // Avoids https://github.com/Microsoft/vscode/issues/33998 + return TPromise.wrap(import('keytar')); } } diff --git a/src/vs/platform/credentials/test/node/keytar.test.ts b/src/vs/platform/credentials/test/node/keytar.test.ts new file mode 100644 index 00000000000..5ae212f9b83 --- /dev/null +++ b/src/vs/platform/credentials/test/node/keytar.test.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as assert from 'assert'; +import * as platform from 'vs/base/common/platform'; + +suite('Keytar', () => { + + test('loads and is functional', done => { + if (platform.isLinux) { + // Skip test due to set up issue with Travis. + done(); + return; + } + (async () => { + const keytar = await import('keytar'); + await keytar.setPassword('VSCode Test', 'foo', 'bar'); + assert.equal(await keytar.getPassword('VSCode Test', 'foo'), 'bar'); + await keytar.deletePassword('VSCode Test', 'foo'); + assert.equal(await keytar.getPassword('VSCode Test', 'foo'), undefined); + })().then(done, done); + }); +}); \ No newline at end of file diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 08c7863ea17..be03bb99677 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -194,8 +194,16 @@ export enum Verbosity { export interface IEditorInput extends IDisposable { + /** + * Triggered when this input is disposed. + */ onDispose: Event; + /** + * Returns the associated resource of this input. + */ + getResource(): URI; + /** * Returns the display name of this input. */ @@ -204,7 +212,7 @@ export interface IEditorInput extends IDisposable { /** * Returns the display description of this input. */ - getDescription(verbose?: boolean): string; + getDescription(verbosity?: Verbosity): string; /** * Returns the display title of this input. @@ -275,17 +283,19 @@ export interface IEditorOptions { inactive?: boolean; } +export interface ITextEditorSelection { + startLineNumber: number; + startColumn: number; + endLineNumber?: number; + endColumn?: number; +} + export interface ITextEditorOptions extends IEditorOptions { /** * Text editor selection. */ - selection?: { - startLineNumber: number; - startColumn: number; - endLineNumber?: number; - endColumn?: number; - }; + selection?: ITextEditorSelection; /** * Text editor view state. diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index b4ee3dfcca3..82572aa5692 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -40,6 +40,12 @@ export interface ParsedArgs { 'enable-proposed-api'?: string | string[]; 'open-url'?: string | string[]; 'skip-getting-started'?: boolean; + 'sticky-quickopen'?: boolean; + 'disable-telemetry'?: boolean; + 'export-default-configuration'?: string; + 'install-source'?: string; + 'disable-updates'?: string; + 'disable-crash-reporter'?: string; } export const IEnvironmentService = createDecorator('environmentService'); @@ -70,6 +76,7 @@ export interface IEnvironmentService { appSettingsPath: string; appKeybindingsPath: string; machineUUID: string; + settingsSearchBuildId: number; backupHome: string; backupWorkspacesPath: string; @@ -100,4 +107,8 @@ export interface IEnvironmentService { sharedIPCHandle: string; nodeCachedDataDir: string; + + installSource: string; + disableUpdates: boolean; + disableCrashReporter: boolean; } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 7f81ffa9d2f..8914588e0da 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -9,7 +9,6 @@ import * as assert from 'assert'; import { firstIndex } from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; import { ParsedArgs } from '../common/environment'; -import product from 'vs/platform/node/product'; const options: minimist.Opts = { string: [ @@ -26,7 +25,9 @@ const options: minimist.Opts = { 'debugSearch', 'debugBrkSearch', 'open-url', - 'enable-proposed-api' + 'enable-proposed-api', + 'export-default-configuration', + 'install-source' ], boolean: [ 'help', @@ -46,7 +47,11 @@ const options: minimist.Opts = { 'list-extensions', 'show-versions', 'nolazy', - 'skip-getting-started' + 'skip-getting-started', + 'sticky-quickopen', + 'disable-telemetry', + 'disable-updates', + 'disable-crash-reporter' ], alias: { add: 'a', @@ -129,7 +134,7 @@ export const optionsHelp: { [name: string]: string; } = { '-r, --reuse-window': localize('reuseWindow', "Force opening a file or folder in the last active window."), '--user-data-dir
': localize('userDataDir', "Specifies the directory that user data is kept in, useful when running as root."), '--verbose': localize('verbose', "Print verbose output (implies --wait)."), - '-w, --wait': localize('wait', "Wait for the window to be closed before returning."), + '-w, --wait': localize('wait', "Wait for the files to be closed before returning."), '--extensions-dir ': localize('extensionHomePath', "Set the root path for extensions."), '--list-extensions': localize('listExtensions', "List the installed extensions."), '--show-versions': localize('showVersions', "Show versions of installed extensions, when using --list-extension."), @@ -142,11 +147,6 @@ export const optionsHelp: { [name: string]: string; } = { '-h, --help': localize('help', "Print usage.") }; -// TODO@Ben multi root -if (product.quality === 'stable') { - delete optionsHelp['-a, --add']; -} - export function formatOptions(options: { [name: string]: string; }, columns: number): string { let keys = Object.keys(options); let argLength = Math.max.apply(null, keys.map(k => k.length)) + 2/*left padding*/ + 1/*right padding*/; diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 9ba9802831a..3f73cf3fe4b 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -10,51 +10,40 @@ import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; import URI from 'vs/base/common/uri'; -import { generateUuid } from 'vs/base/common/uuid'; +import { generateUuid, isUUID } from 'vs/base/common/uuid'; import { memoize } from 'vs/base/common/decorators'; import pkg from 'vs/platform/node/package'; import product from 'vs/platform/node/product'; -function getUniqueUserId(): string { - let username: string; - if (process.platform === 'win32') { - username = process.env.USERNAME; - } else { - username = process.env.USER; - } - - if (!username) { - return ''; // fail gracefully if there is no user name - } - - // use sha256 to ensure the userid value can be used in filenames and are unique - return crypto.createHash('sha256').update(username).digest('hex').substr(0, 6); -} +// Read this before there's any chance it is overwritten +// Related to https://github.com/Microsoft/vscode/issues/30624 +const xdgRuntimeDir = process.env['XDG_RUNTIME_DIR']; function getNixIPCHandle(userDataPath: string, type: string): string { - if (process.env['XDG_RUNTIME_DIR']) { - return path.join(process.env['XDG_RUNTIME_DIR'], `${pkg.name}-${pkg.version}-${type}.sock`); + if (xdgRuntimeDir) { + return path.join(xdgRuntimeDir, `${pkg.name}-${pkg.version}-${type}.sock`); } + return path.join(userDataPath, `${pkg.version}-${type}.sock`); } -function getWin32IPCHandle(type: string): string { - // Support to run VS Code multiple times as different user - // by making the socket unique over the logged in user - const userId = getUniqueUserId(); - const name = product.applicationName + (userId ? `-${userId}` : ''); - - return `\\\\.\\pipe\\${name}-${pkg.version}-${type}-sock`; +function getWin32IPCHandle(userDataPath: string, type: string): string { + const scope = crypto.createHash('md5').update(userDataPath).digest('hex'); + return `\\\\.\\pipe\\${scope}-${pkg.version}-${type}-sock`; } function getIPCHandle(userDataPath: string, type: string): string { if (process.platform === 'win32') { - return getWin32IPCHandle(type); + return getWin32IPCHandle(userDataPath, type); } else { return getNixIPCHandle(userDataPath, type); } } +export function getInstallSourcePath(userDataPath: string): string { + return path.join(userDataPath, 'installSource'); +} + export class EnvironmentService implements IEnvironmentService { _serviceBrand: any; @@ -82,6 +71,9 @@ export class EnvironmentService implements IEnvironmentService { @memoize get appSettingsPath(): string { return path.join(this.appSettingsHome, 'settings.json'); } + @memoize + get settingsSearchBuildId(): number { return product.settingsSearchBuildId; } + @memoize get appKeybindingsPath(): string { return path.join(this.appSettingsHome, 'keybindings.json'); } @@ -142,24 +134,39 @@ export class EnvironmentService implements IEnvironmentService { get sharedIPCHandle(): string { return getIPCHandle(this.userDataPath, 'shared'); } @memoize - get nodeCachedDataDir(): string { return this.isBuilt ? path.join(this.userDataPath, 'CachedData', product.commit) : undefined; } + get nodeCachedDataDir(): string { return this.isBuilt ? path.join(this.userDataPath, 'CachedData', product.commit || new Array(41).join('0')) : undefined; } + + get disableUpdates(): boolean { return !!this._args['disable-updates']; } + get disableCrashReporter(): boolean { return !!this._args['disable-crash-reporter']; } readonly machineUUID: string; + readonly installSource: string; + constructor(private _args: ParsedArgs, private _execPath: string) { const machineIdPath = path.join(this.userDataPath, 'machineid'); try { this.machineUUID = fs.readFileSync(machineIdPath, 'utf8'); + + if (!isUUID(this.machineUUID)) { + throw new Error('Not a UUID'); + } } catch (err) { this.machineUUID = generateUuid(); try { - fs.writeFileSync(machineIdPath, this.machineUUID); + fs.writeFileSync(machineIdPath, this.machineUUID, 'utf8'); } catch (err) { - console.warn('Could not store machine ID'); + // noop } } + + try { + this.installSource = fs.readFileSync(getInstallSourcePath(this.userDataPath), 'utf8').slice(0, 30); + } catch (err) { + this.installSource = ''; + } } } diff --git a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts index 75606dd0a96..4db312fd0a1 100644 --- a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts @@ -5,16 +5,16 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { distinct } from 'vs/base/common/arrays'; +import { distinct, coalesce } from 'vs/base/common/arrays'; import Event, { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { adoptToGalleryExtensionId, getIdAndVersionFromLocalExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { adoptToGalleryExtensionId, getIdAndVersionFromLocalExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensions/disabled'; +const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled'; export class ExtensionEnablementService implements IExtensionEnablementService { @@ -22,44 +22,52 @@ export class ExtensionEnablementService implements IExtensionEnablementService { private disposables: IDisposable[] = []; - private _onEnablementChanged = new Emitter(); - public onEnablementChanged: Event = this._onEnablementChanged.event; + private _onEnablementChanged = new Emitter(); + public onEnablementChanged: Event = this._onEnablementChanged.event; constructor( @IStorageService private storageService: IStorageService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IEnvironmentService private environmentService: IEnvironmentService, + // @ts-ignore unused injected service @IExtensionManagementService private extensionManagementService: IExtensionManagementService ) { extensionManagementService.onDidUninstallExtension(this.onDidUninstallExtension, this, this.disposables); } private get hasWorkspace(): boolean { - return this.contextService.hasWorkspace(); + return this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY; } - public getGloballyDisabledExtensions(): string[] { + getGloballyDisabledExtensions(): IExtensionIdentifier[] { return this.getDisabledExtensions(StorageScope.GLOBAL); } - public getWorkspaceDisabledExtensions(): string[] { + getWorkspaceDisabledExtensions(): IExtensionIdentifier[] { return this.getDisabledExtensions(StorageScope.WORKSPACE); } - public canEnable(identifier: string): boolean { + canEnable(identifier: IExtensionIdentifier): boolean { if (this.environmentService.disableExtensions) { return false; } - if (this.getGloballyDisabledExtensions().indexOf(identifier) !== -1) { - return true; - } - if (this.getWorkspaceDisabledExtensions().indexOf(identifier) !== -1) { - return true; - } - return false; + return !this.isEnabled(identifier); } - public setEnablement(identifier: string, enable: boolean, workspace: boolean = false): TPromise { + isEnabled(identifier: IExtensionIdentifier): boolean { + if (this.environmentService.disableExtensions) { + return false; + } + if (this.getGloballyDisabledExtensions().some(d => areSameExtensions(d, identifier))) { + return false; + } + if (this.getWorkspaceDisabledExtensions().some(d => areSameExtensions(d, identifier))) { + return false; + } + return true; + } + + setEnablement(identifier: IExtensionIdentifier, enable: boolean, workspace: boolean = false): TPromise { if (workspace && !this.hasWorkspace) { return TPromise.wrapError(new Error(localize('noWorkspace', "No workspace."))); } @@ -83,10 +91,16 @@ export class ExtensionEnablementService implements IExtensionEnablementService { } } - private disableExtension(identifier: string, scope: StorageScope): TPromise { + migrateToIdentifiers(installed: IExtensionIdentifier[]): void { + this.migrateDisabledExtensions(installed, StorageScope.GLOBAL); + if (this.hasWorkspace) { + this.migrateDisabledExtensions(installed, StorageScope.WORKSPACE); + } + } + + private disableExtension(identifier: IExtensionIdentifier, scope: StorageScope): TPromise { let disabledExtensions = this.getDisabledExtensions(scope); - const index = disabledExtensions.indexOf(identifier); - if (index === -1) { + if (disabledExtensions.every(e => !areSameExtensions(e, identifier))) { disabledExtensions.push(identifier); this.setDisabledExtensions(disabledExtensions, scope, identifier); return TPromise.wrap(true); @@ -94,28 +108,30 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return TPromise.wrap(false); } - private enableExtension(identifier: string, scope: StorageScope, fireEvent = true): TPromise { + private enableExtension(identifier: IExtensionIdentifier, scope: StorageScope, fireEvent = true): TPromise { let disabledExtensions = this.getDisabledExtensions(scope); - const index = disabledExtensions.indexOf(identifier); - if (index !== -1) { - disabledExtensions.splice(index, 1); - this.setDisabledExtensions(disabledExtensions, scope, identifier, fireEvent); - return TPromise.wrap(true); + for (let index = 0; index < disabledExtensions.length; index++) { + const disabledExtension = disabledExtensions[index]; + if (areSameExtensions(disabledExtension, identifier)) { + disabledExtensions.splice(index, 1); + this.setDisabledExtensions(disabledExtensions, scope, identifier, fireEvent); + return TPromise.wrap(true); + } } return TPromise.wrap(false); } - private getDisabledExtensions(scope: StorageScope): string[] { + private getDisabledExtensions(scope: StorageScope): IExtensionIdentifier[] { if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) { return []; } const value = this.storageService.get(DISABLED_EXTENSIONS_STORAGE_PATH, scope, ''); - return value ? distinct(value.split(',')).map(id => adoptToGalleryExtensionId(id)) : []; + return value ? JSON.parse(value) : []; } - private setDisabledExtensions(disabledExtensions: string[], scope: StorageScope, extension: string, fireEvent = true): void { + private setDisabledExtensions(disabledExtensions: IExtensionIdentifier[], scope: StorageScope, extension: IExtensionIdentifier, fireEvent = true): void { if (disabledExtensions.length) { - this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, disabledExtensions.join(','), scope); + this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, JSON.stringify(disabledExtensions.map(({ id, uuid }) => ({ id, uuid }))), scope); } else { this.storageService.remove(DISABLED_EXTENSIONS_STORAGE_PATH, scope); } @@ -124,12 +140,28 @@ export class ExtensionEnablementService implements IExtensionEnablementService { } } - private onDidUninstallExtension({ id, error }: DidUninstallExtensionEvent): void { + private migrateDisabledExtensions(installedExtensions: IExtensionIdentifier[], scope: StorageScope): void { + const oldValue = this.storageService.get('extensions/disabled', scope, ''); + if (oldValue) { + const extensionIdentifiers = coalesce(distinct(oldValue.split(',')).map(id => { + id = adoptToGalleryExtensionId(id); + const matched = installedExtensions.filter(installed => areSameExtensions({ id }, { id: installed.id }))[0]; + return matched ? { id: matched.id, uuid: matched.uuid } : null; + })); + if (extensionIdentifiers.length) { + this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, JSON.stringify(extensionIdentifiers), scope); + } + } + this.storageService.remove('extensions/disabled', scope); + } + + private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void { if (!error) { - id = getIdAndVersionFromLocalExtensionId(id).id; + const id = getIdAndVersionFromLocalExtensionId(identifier.id).id; if (id) { - this.enableExtension(id, StorageScope.WORKSPACE, false); - this.enableExtension(id, StorageScope.GLOBAL, false); + const extension = { id, uuid: identifier.uuid }; + this.enableExtension(extension, StorageScope.WORKSPACE, false); + this.enableExtension(extension, StorageScope.GLOBAL, false); } } } diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index a1886d34b0c..8ced7d883f3 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -79,6 +79,12 @@ export interface IView { name: string; } +export interface IColor { + id: string; + description: string; + defaults: { light: string, dark: string, highContrast: string }; +} + export interface IExtensionContributions { commands?: ICommand[]; configuration?: IConfiguration; @@ -90,7 +96,9 @@ export interface IExtensionContributions { menus?: { [context: string]: IMenu[] }; snippets?: ISnippet[]; themes?: ITheme[]; + iconThemes?: ITheme[]; views?: { [location: string]: IView[] }; + colors: IColor[]; } export interface IExtensionManifest { @@ -127,10 +135,14 @@ export interface IGalleryExtensionAssets { license: IGalleryExtensionAsset; } -export interface IGalleryExtension { - uuid: string; +export interface IExtensionIdentifier { id: string; + uuid?: string; +} + +export interface IGalleryExtension { name: string; + identifier: IExtensionIdentifier; version: string; date: string; displayName: string; @@ -159,7 +171,7 @@ export enum LocalExtensionType { export interface ILocalExtension { type: LocalExtensionType; - id: string; + identifier: IExtensionIdentifier; manifest: IExtensionManifest; metadata: IGalleryMetadata; path: string; @@ -209,28 +221,28 @@ export interface IExtensionGalleryService { reportStatistic(publisher: string, name: string, version: string, type: StatisticType): TPromise; getReadme(extension: IGalleryExtension): TPromise; getManifest(extension: IGalleryExtension): TPromise; - getChangelog(extension: IGalleryMetadata): TPromise; + getChangelog(extension: IGalleryExtension): TPromise; loadCompatibleVersion(extension: IGalleryExtension): TPromise; getAllDependencies(extension: IGalleryExtension): TPromise; } export interface InstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; zipPath?: string; gallery?: IGalleryExtension; } export interface DidInstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; zipPath?: string; gallery?: IGalleryExtension; local?: ILocalExtension; - error?: Error; + error?: string; } export interface DidUninstallExtensionEvent { - id: string; - error?: Error; + identifier: IExtensionIdentifier; + error?: string; } export interface IExtensionManagementService { @@ -238,13 +250,15 @@ export interface IExtensionManagementService { onInstallExtension: Event; onDidInstallExtension: Event; - onUninstallExtension: Event; + onUninstallExtension: Event; onDidUninstallExtension: Event; install(zipPath: string): TPromise; - installFromGallery(extension: IGalleryExtension, promptToInstallDependencies?: boolean): TPromise; + installFromGallery(extension: IGalleryExtension): TPromise; uninstall(extension: ILocalExtension, force?: boolean): TPromise; getInstalled(type?: LocalExtensionType): TPromise; + + updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): TPromise; } export const IExtensionEnablementService = createDecorator('extensionEnablementService'); @@ -256,24 +270,29 @@ export interface IExtensionEnablementService { /** * Event to listen on for extension enablement changes */ - onEnablementChanged: Event; + onEnablementChanged: Event; /** * Returns all globally disabled extension identifiers. * Returns an empty array if none exist. */ - getGloballyDisabledExtensions(): string[]; + getGloballyDisabledExtensions(): IExtensionIdentifier[]; /** * Returns all workspace disabled extension identifiers. * Returns an empty array if none exist or workspace does not exist. */ - getWorkspaceDisabledExtensions(): string[]; + getWorkspaceDisabledExtensions(): IExtensionIdentifier[]; /** * Returns `true` if given extension can be enabled by calling `setEnablement`, otherwise false`. */ - canEnable(identifier: string): boolean; + canEnable(identifier: IExtensionIdentifier): boolean; + + /** + * Returns `true` if the given extension identifier is enabled. + */ + isEnabled(identifier: IExtensionIdentifier): boolean; /** * Enable or disable the given extension. @@ -284,14 +303,18 @@ export interface IExtensionEnablementService { * * Throws error if enablement is requested for workspace and there is no workspace */ - setEnablement(identifier: string, enable: boolean, workspace?: boolean): TPromise; + setEnablement(identifier: IExtensionIdentifier, enable: boolean, workspace?: boolean): TPromise; + + migrateToIdentifiers(installed: IExtensionIdentifier[]): void; } export const IExtensionTipsService = createDecorator('extensionTipsService'); export interface IExtensionTipsService { _serviceBrand: any; - getRecommendations(): string[]; + getAllRecommendationsWithReason(): { [id: string]: string; }; + getFileBasedRecommendations(): string[]; + getOtherRecommendations(): string[]; getWorkspaceRecommendations(): TPromise; getKeymapRecommendations(): string[]; getKeywordsForExtension(extension: string): string[]; diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index ecdb8c08816..15bb2aa58df 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, LocalExtensionType, DidUninstallExtensionEvent } from './extensionManagement'; +import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, LocalExtensionType, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata } from './extensionManagement'; import Event, { buffer } from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -26,7 +26,7 @@ export class ExtensionManagementChannel implements IExtensionManagementChannel { onInstallExtension: Event; onDidInstallExtension: Event; - onUninstallExtension: Event; + onUninstallExtension: Event; onDidUninstallExtension: Event; constructor(private service: IExtensionManagementService) { @@ -43,9 +43,10 @@ export class ExtensionManagementChannel implements IExtensionManagementChannel { case 'event:onUninstallExtension': return eventToCall(this.onUninstallExtension); case 'event:onDidUninstallExtension': return eventToCall(this.onDidUninstallExtension); case 'install': return this.service.install(arg); - case 'installFromGallery': return this.service.installFromGallery(arg[0], arg[1]); + case 'installFromGallery': return this.service.installFromGallery(arg[0]); case 'uninstall': return this.service.uninstall(arg[0], arg[1]); case 'getInstalled': return this.service.getInstalled(arg); + case 'updateMetadata': return this.service.updateMetadata(arg[0], arg[1]); } return undefined; } @@ -63,8 +64,8 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer private _onDidInstallExtension = eventFromCall(this.channel, 'event:onDidInstallExtension'); get onDidInstallExtension(): Event { return this._onDidInstallExtension; } - private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); - get onUninstallExtension(): Event { return this._onUninstallExtension; } + private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); + get onUninstallExtension(): Event { return this._onUninstallExtension; } private _onDidUninstallExtension = eventFromCall(this.channel, 'event:onDidUninstallExtension'); get onDidUninstallExtension(): Event { return this._onDidUninstallExtension; } @@ -73,8 +74,8 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer return this.channel.call('install', zipPath); } - installFromGallery(extension: IGalleryExtension, promptToInstallDependencies: boolean = true): TPromise { - return this.channel.call('installFromGallery', [extension, promptToInstallDependencies]); + installFromGallery(extension: IGalleryExtension): TPromise { + return this.channel.call('installFromGallery', [extension]); } uninstall(extension: ILocalExtension, force = false): TPromise { @@ -84,4 +85,8 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer getInstalled(type: LocalExtensionType = null): TPromise { return this.channel.call('getInstalled', type); } + + updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): TPromise { + return this.channel.call('updateMetadata', [local, metadata]); + } } \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts index 7b4a1690e71..23945ed58fb 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts @@ -5,10 +5,13 @@ 'use strict'; -import { ILocalExtension, IGalleryExtension, IExtensionManifest, EXTENSION_IDENTIFIER_REGEX, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension, EXTENSION_IDENTIFIER_REGEX, IExtensionEnablementService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -export function areSameExtensions(a: { id: string }, b: { id: string }): boolean { +export function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifier): boolean { + if (a.uuid && b.uuid) { + return a.uuid === b.uuid; + } if (a.id === b.id) { return true; } @@ -19,14 +22,6 @@ export function getGalleryExtensionId(publisher: string, name: string): string { return `${publisher}.${name.toLocaleLowerCase()}`; } -export function getLocalExtensionIdFromGallery(extension: IGalleryExtension, version: string): string { - return getLocalExtensionId(extension.id, version); -} - -export function getLocalExtensionIdFromManifest(manifest: IExtensionManifest): string { - return getLocalExtensionId(getGalleryExtensionId(manifest.publisher, manifest.name), manifest.version); -} - export function getGalleryExtensionIdFromLocal(local: ILocalExtension): string { return getGalleryExtensionId(local.manifest.publisher, local.manifest.name); } @@ -46,10 +41,6 @@ export function adoptToGalleryExtensionId(id: string): string { return id.replace(EXTENSION_IDENTIFIER_REGEX, (match, publisher: string, name: string) => getGalleryExtensionId(publisher, name)); } -function getLocalExtensionId(id: string, version: string): string { - return `${id}-${version}`; -} - export function getLocalExtensionTelemetryData(extension: ILocalExtension): any { return { id: getGalleryExtensionIdFromLocal(extension), @@ -62,11 +53,26 @@ export function getLocalExtensionTelemetryData(extension: ILocalExtension): any }; } + +/* __GDPR__FRAGMENT__ + "GalleryExtensionTelemetryData" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "name": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "galleryId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "publisherId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "publisherName": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "publisherDisplayName": { "classification": "PublicPersonalData", "purpose": "FeatureInsight" }, + "dependencies": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "${include}": [ + "${GalleryExtensionTelemetryData2}" + ] + } +*/ export function getGalleryExtensionTelemetryData(extension: IGalleryExtension): any { return { - id: extension.id, + id: extension.identifier.id, name: extension.name, - galleryId: extension.uuid, + galleryId: extension.identifier.uuid, publisherId: extension.publisherId, publisherName: extension.publisher, publisherDisplayName: extension.publisherDisplayName, @@ -87,9 +93,9 @@ export function getGloballyDisabledExtensions(extensionEnablementService: IExten const globallyDisabled = extensionEnablementService.getGloballyDisabledExtensions(); if (!storageService.getBoolean(BetterMergeCheckKey, StorageScope.GLOBAL, false)) { storageService.store(BetterMergeCheckKey, true); - if (globallyDisabled.indexOf(BetterMergeId) === -1 && installedExtensions.some(d => d.id === BetterMergeId)) { - globallyDisabled.push(BetterMergeId); - extensionEnablementService.setEnablement(BetterMergeId, false); + if (globallyDisabled.every(disabled => disabled.id !== BetterMergeId) && installedExtensions.some(d => d.id === BetterMergeId)) { + globallyDisabled.push({ id: BetterMergeId }); + extensionEnablementService.setEnablement({ id: BetterMergeId }, false); storageService.store(BetterMergeDisabledNowKey, true); } } diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 4381d85c570..d219de90a51 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -245,8 +245,10 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr }; return { - uuid: galleryExtension.extensionId, - id: getGalleryExtensionId(galleryExtension.publisher.publisherName, galleryExtension.extensionName), + identifier: { + id: getGalleryExtensionId(galleryExtension.publisher.publisherName, galleryExtension.extensionName), + uuid: galleryExtension.extensionId + }, name: galleryExtension.extensionName, version: version.version, date: version.lastUpdated, @@ -263,6 +265,13 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr dependencies: getDependencies(version), engine: getEngine(version) }, + /* __GDPR__FRAGMENT__ + "GalleryExtensionTelemetryData2" : { + "index" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "searchText": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "querySource": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ telemetryData: { index: ((query.pageNumber - 1) * query.pageSize) + index, searchText: query.searchText, @@ -283,6 +292,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { @IRequestService private requestService: IRequestService, @IEnvironmentService private environmentService: IEnvironmentService, @ITelemetryService private telemetryService: ITelemetryService, + // @ts-ignore unused injected service @IConfigurationService private configurationService: IConfigurationService ) { const config = product.extensionsGallery; @@ -311,6 +321,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService { let text = options.text || ''; const pageSize = getOrDefault(options, o => o.pageSize, 50); + /* __GDPR__ + "galleryService:query" : { + "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "text": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('galleryService:query', { type, text }); let query = new Query() @@ -336,6 +352,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { text = text.trim(); if (text) { + text = text.length < 200 ? text : text.substring(0, 200); query = query.withFilter(FilterType.SearchText, text); } @@ -369,8 +386,8 @@ export class ExtensionGalleryService implements IExtensionGalleryService { }); } - private async queryGallery(query: Query): TPromise<{ galleryExtensions: IRawGalleryExtension[], total: number; }> { - const commonHeaders = await this.commonHTTPHeaders; + private queryGallery(query: Query): TPromise<{ galleryExtensions: IRawGalleryExtension[], total: number; }> { + const commonHeaders = this.commonHTTPHeaders; const data = JSON.stringify(query.raw); const headers = assign({}, commonHeaders, { 'Content-Type': 'application/json', @@ -379,45 +396,40 @@ export class ExtensionGalleryService implements IExtensionGalleryService { 'Content-Length': data.length }); - const context = await this.requestService.request({ + return this.requestService.request({ type: 'POST', url: this.api('/extensionquery'), data, headers + }).then(context => { + + if (context.res.statusCode >= 400 && context.res.statusCode < 500) { + return { galleryExtensions: [], total: 0 }; + } + + return asJson(context).then(result => { + const r = result.results[0]; + const galleryExtensions = r.extensions; + const resultCount = r.resultMetadata && r.resultMetadata.filter(m => m.metadataType === 'ResultCount')[0]; + const total = resultCount && resultCount.metadataItems.filter(i => i.name === 'TotalCount')[0].count || 0; + + return { galleryExtensions, total }; + }); }); - - if (context.res.statusCode >= 400 && context.res.statusCode < 500) { - return { galleryExtensions: [], total: 0 }; - } - - const result = await asJson(context); - const r = result.results[0]; - const galleryExtensions = r.extensions; - const resultCount = r.resultMetadata && r.resultMetadata.filter(m => m.metadataType === 'ResultCount')[0]; - const total = resultCount && resultCount.metadataItems.filter(i => i.name === 'TotalCount')[0].count || 0; - - return { galleryExtensions, total }; } - async reportStatistic(publisher: string, name: string, version: string, type: StatisticType): TPromise { + reportStatistic(publisher: string, name: string, version: string, type: StatisticType): TPromise { if (!this.isEnabled()) { - return; + return TPromise.as(null); } - try { - const headers = { - ...await this.commonHTTPHeaders, - Accept: '*/*;api-version=4.0-preview.1' - }; + const headers = { ...this.commonHTTPHeaders, Accept: '*/*;api-version=4.0-preview.1' }; - await this.requestService.request({ - type: 'POST', - url: this.api(`/publishers/${publisher}/extensions/${name}/${version}/stats?statType=${type}`), - headers - }); - } catch (err) { - // noop - } + return this.requestService.request({ + type: 'POST', + url: this.api(`/publishers/${publisher}/extensions/${name}/${version}/stats?statType=${type}`), + headers + }).then(null, () => null); } download(extension: IGalleryExtension): TPromise { @@ -425,6 +437,14 @@ export class ExtensionGalleryService implements IExtensionGalleryService { const zipPath = path.join(tmpdir(), uuid.generateUuid()); const data = getGalleryExtensionTelemetryData(extension); const startTime = new Date().getTime(); + /* __GDPR__ + "galleryService:downloadVSIX" : { + "duration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ const log = (duration: number) => this.telemetryService.publicLog('galleryService:downloadVSIX', assign(data, { duration })); return this.getAsset(extension.assets.download) @@ -466,7 +486,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code') .withFilter(FilterType.ExcludeWithFlags, flagsToString(Flags.Unpublished)) .withAssetTypes(AssetType.Manifest, AssetType.VSIX) - .withFilter(FilterType.ExtensionId, extension.uuid); + .withFilter(FilterType.ExtensionId, extension.identifier.uuid); return this.queryGallery(query).then(({ galleryExtensions }) => { const [rawExtension] = galleryExtensions; @@ -506,7 +526,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { for (let index = 0; index < result.galleryExtensions.length; index++) { const rawExtension = result.galleryExtensions[index]; if (ids.indexOf(rawExtension.extensionId) === -1) { - dependencies.push(toExtension(rawExtension, this.extensionsGalleryUrl, index, query)); + dependencies.push(toExtension(rawExtension, this.extensionsGalleryUrl, index, query, 'dependencies')); ids.push(rawExtension.extensionId); } } @@ -534,7 +554,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { dep.properties.dependencies.forEach(d => dependenciesSet.add(d)); } } - result = distinct(result.concat(loadedDependencies), d => d.uuid); + result = distinct(result.concat(loadedDependencies), d => d.identifier.uuid); const dependencies: string[] = []; dependenciesSet.forEach(d => !ExtensionGalleryService.hasExtensionByName(result, d) && dependencies.push(d)); return this.getDependenciesReccursively(dependencies, result, root); @@ -565,7 +585,20 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } const message = getErrorMessage(err); + /* __GDPR__ + "galleryService:requestError" : { + "url" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "cdn": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "message": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('galleryService:requestError', { url, cdn: true, message }); + /* __GDPR__ + "galleryService:cdnFallback" : { + "url" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "message": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('galleryService:cdnFallback', { url, message }); const fallbackOptions = assign({}, options, { url: fallbackUrl }); @@ -575,6 +608,13 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } const message = getErrorMessage(err); + /* __GDPR__ + "galleryService:requestError" : { + "url" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "cdn": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "message": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('galleryService:requestError', { url: fallbackUrl, cdn: false, message }); return TPromise.wrapError(err); }); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index e019353ebce..837dd1497b7 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -18,9 +18,10 @@ import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IExtensionManifest, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, LocalExtensionType, - StatisticType + StatisticType, + IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest, getGalleryExtensionIdFromLocal, getIdAndVersionFromLocalExtensionId, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, getIdAndVersionFromLocalExtensionId, adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localizeManifest } from '../common/extensionNls'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Limiter } from 'vs/base/common/async'; @@ -31,6 +32,9 @@ import URI from 'vs/base/common/uri'; import { IChoiceService, Severity } from 'vs/platform/message/common/message'; const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions')); +const INSTALL_ERROR_OBSOLETE = 'obsolete'; +const INSTALL_ERROR_GALLERY = 'gallery'; +const INSTALL_ERROR_LOCAL = 'local'; function parseManifest(raw: string): TPromise<{ manifest: IExtensionManifest; metadata: IGalleryMetadata; }> { return new TPromise((c, e) => { @@ -68,6 +72,13 @@ function readManifest(extensionPath: string): TPromise<{ manifest: IExtensionMan }); } +interface InstallableExtension { + zipPath: string; + id: string; + metadata: IGalleryMetadata; + current?: ILocalExtension; +} + export class ExtensionManagementService implements IExtensionManagementService { _serviceBrand: any; @@ -83,13 +94,14 @@ export class ExtensionManagementService implements IExtensionManagementService { private _onDidInstallExtension = new Emitter(); onDidInstallExtension: Event = this._onDidInstallExtension.event; - private _onUninstallExtension = new Emitter(); - onUninstallExtension: Event = this._onUninstallExtension.event; + private _onUninstallExtension = new Emitter(); + onUninstallExtension: Event = this._onUninstallExtension.event; private _onDidUninstallExtension = new Emitter(); onDidUninstallExtension: Event = this._onDidUninstallExtension.event; constructor( + // @ts-ignore unused injected service @IEnvironmentService private environmentService: IEnvironmentService, @IChoiceService private choiceService: IChoiceService, @IExtensionGalleryService private galleryService: IExtensionGalleryService @@ -103,142 +115,121 @@ export class ExtensionManagementService implements IExtensionManagementService { zipPath = path.resolve(zipPath); return validate(zipPath).then(manifest => { - const id = getLocalExtensionIdFromManifest(manifest); + const identifier = { id: getLocalExtensionIdFromManifest(manifest) }; - return this.isObsolete(id).then(isObsolete => { + return this.isObsolete(identifier.id).then(isObsolete => { if (isObsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", manifest.displayName || manifest.name))); + return TPromise.wrapError(new Error(nls.localize('restartCodeLocal', "Please restart Code before reinstalling {0}.", manifest.displayName || manifest.name))); } - this._onInstallExtension.fire({ id, zipPath }); + this._onInstallExtension.fire({ identifier, zipPath }); - return this.installExtension(zipPath, id) - .then( - local => this._onDidInstallExtension.fire({ id, zipPath, local }), - error => { this._onDidInstallExtension.fire({ id, zipPath, error }); return TPromise.wrapError(error); } - ); - }); - }); - } - - installFromGallery(extension: IGalleryExtension, promptToInstallDependencies: boolean = true): TPromise { - const id = getLocalExtensionIdFromGallery(extension, extension.version); - - return this.isObsolete(id).then(isObsolete => { - if (isObsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.displayName || extension.name))); - } - this._onInstallExtension.fire({ id, gallery: extension }); - return this.installCompatibleVersion(extension, true, promptToInstallDependencies) - .then( - local => this._onDidInstallExtension.fire({ id, local, gallery: extension }), - error => { - this._onDidInstallExtension.fire({ id, gallery: extension, error }); - return TPromise.wrapError(error); - } - ); - }); - } - - private installCompatibleVersion(extension: IGalleryExtension, installDependencies: boolean, promptToInstallDependencies: boolean): TPromise { - return this.galleryService.loadCompatibleVersion(extension) - .then(compatibleVersion => this.getDependenciesToInstall(extension, installDependencies) - .then(dependencies => { - if (!dependencies.length) { - return this.downloadAndInstall(compatibleVersion); - } - if (promptToInstallDependencies) { - const message = nls.localize('installDependeciesConfirmation', "Installing '{0}' also installs its dependencies. Would you like to continue?", extension.displayName); - const options = [ - nls.localize('install', "Yes"), - nls.localize('doNotInstall', "No") - ]; - return this.choiceService.choose(Severity.Info, message, options, 1, true) - .then(value => { - if (value === 0) { - return this.installWithDependencies(compatibleVersion); - } - return TPromise.wrapError(errors.canceled()); - }, error => TPromise.wrapError(errors.canceled())); - } else { - return this.installWithDependencies(compatibleVersion); - } - }) - ); - } - - private getDependenciesToInstall(extension: IGalleryExtension, checkDependecies: boolean): TPromise { - if (!checkDependecies) { - return TPromise.wrap([]); - } - // Filter out self - const dependencies = extension.properties.dependencies ? extension.properties.dependencies.filter(id => id !== extension.id) : []; - if (!dependencies.length) { - return TPromise.wrap([]); - } - // Filter out installed dependencies - return this.getInstalled().then(installed => { - return dependencies.filter(dep => installed.every(i => `${i.manifest.publisher}.${i.manifest.name}` !== dep)); - }); - } - - private installWithDependencies(extension: IGalleryExtension): TPromise { - return this.galleryService.getAllDependencies(extension) - .then(allDependencies => this.filterDependenciesToInstall(extension, allDependencies)) - .then(toInstall => this.filterObsolete(...toInstall.map(i => getLocalExtensionIdFromGallery(i, i.version))) - .then((obsolete) => { - if (obsolete.length) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.displayName || extension.name))); - } - return this.bulkInstallWithDependencies(extension, toInstall); - }) - ); - } - - private bulkInstallWithDependencies(extension: IGalleryExtension, dependecies: IGalleryExtension[]): TPromise { - for (const dependency of dependecies) { - const id = getLocalExtensionIdFromGallery(dependency, dependency.version); - this._onInstallExtension.fire({ id, gallery: dependency }); - } - return this.downloadAndInstall(extension) - .then(localExtension => { - return TPromise.join(dependecies.map((dep) => this.installCompatibleVersion(dep, false, false))) - .then(installedLocalExtensions => { - for (const installedLocalExtension of installedLocalExtensions) { - const gallery = this.getGalleryExtensionForLocalExtension(dependecies, installedLocalExtension); - this._onDidInstallExtension.fire({ id: installedLocalExtension.id, local: installedLocalExtension, gallery }); - } - return localExtension; - }, error => { - return this.rollback(localExtension, dependecies).then(() => { - return TPromise.wrapError(Array.isArray(error) ? error[error.length - 1] : error); - }); + return this.galleryService.query({ names: [getGalleryExtensionId(manifest.publisher, manifest.name)], pageSize: 1 }) + .then(galleryResult => { + const galleryExtension = galleryResult.firstPage[0]; + const metadata = galleryExtension ? { id: galleryExtension.identifier.uuid, publisherDisplayName: galleryExtension.publisherDisplayName, publisherId: galleryExtension.publisherId } : null; + return this.installExtension({ zipPath, id: identifier.id, metadata }) + .then( + local => this._onDidInstallExtension.fire({ identifier, zipPath, local }), + error => { this._onDidInstallExtension.fire({ identifier, zipPath, error }); return TPromise.wrapError(error); } + ); }); - }) - .then(localExtension => localExtension, error => { - for (const dependency of dependecies) { - this._onDidInstallExtension.fire({ id: getLocalExtensionIdFromGallery(dependency, dependency.version), gallery: dependency, error }); - } - return TPromise.wrapError(error); + }); + }); } - private rollback(localExtension: ILocalExtension, dependecies: IGalleryExtension[]): TPromise { - return this.doUninstall(localExtension) - .then(() => this.filterOutUninstalled(dependecies)) - .then(installed => TPromise.join(installed.map((i) => this.doUninstall(i)))) - .then(() => null); + installFromGallery(extension: IGalleryExtension): TPromise { + return this.prepareAndCollectExtensionsToInstall(extension) + .then(extensionsToInstall => this.downloadAndInstallExtensions(extensionsToInstall) + .then(local => this.onDidInstallExtensions(extensionsToInstall, local))); + } + + private prepareAndCollectExtensionsToInstall(extension: IGalleryExtension): TPromise { + this.onInstallExtensions([extension]); + return this.collectExtensionsToInstall(extension) + .then( + extensionsToInstall => this.checkForObsolete(extensionsToInstall) + .then( + extensionsToInstall => { + if (extensionsToInstall.length > 1) { + this.onInstallExtensions(extensionsToInstall.slice(1)); + } + return extensionsToInstall; + }, + error => this.onDidInstallExtensions([extension], null, INSTALL_ERROR_OBSOLETE, error) + ), + error => this.onDidInstallExtensions([extension], null, INSTALL_ERROR_GALLERY, error) + ); + } + + private downloadAndInstallExtensions(extensions: IGalleryExtension[]): TPromise { + return this.getInstalled(LocalExtensionType.User) + .then(installed => TPromise.join(extensions.map(extensionToInstall => this.downloadInstallableExtension(extensionToInstall, installed))) + .then( + installableExtensions => TPromise.join(installableExtensions.map(installableExtension => this.installExtension(installableExtension))) + .then(null, error => this.rollback(extensions).then(() => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_LOCAL, error))), + error => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_GALLERY, error))); + } + + private collectExtensionsToInstall(extension: IGalleryExtension): TPromise { + return this.galleryService.loadCompatibleVersion(extension) + .then(extensionToInstall => this.galleryService.getAllDependencies(extension) + .then(allDependencies => this.filterDependenciesToInstall(extension, allDependencies)) + .then(dependenciesToInstall => [extensionToInstall, ...dependenciesToInstall])); + } + + private checkForObsolete(extensionsToInstall: IGalleryExtension[]): TPromise { + return this.filterObsolete(...extensionsToInstall.map(i => getLocalExtensionIdFromGallery(i, i.version))) + .then(obsolete => obsolete.length ? TPromise.wrapError(new Error(nls.localize('restartCodeGallery', "Please restart Code before reinstalling."))) : extensionsToInstall); + } + + private downloadInstallableExtension(extension: IGalleryExtension, installed: ILocalExtension[]): TPromise { + const current = installed.filter(i => i.identifier.uuid === extension.identifier.uuid)[0]; + const id = getLocalExtensionIdFromGallery(extension, extension.version); + const metadata = { + id: extension.identifier.uuid, + publisherId: extension.publisherId, + publisherDisplayName: extension.publisherDisplayName, + }; + return this.galleryService.download(extension) + .then(zipPath => validate(zipPath).then(() => ({ zipPath, id, metadata, current }))); + } + + private rollback(extensions: IGalleryExtension[]): TPromise { + return this.filterOutUninstalled(extensions) + .then(installed => TPromise.join(installed.map(local => this.uninstallExtension(local.identifier)))) + .then(() => null, () => null); + } + + private onInstallExtensions(extensions: IGalleryExtension[]): void { + for (const extension of extensions) { + const id = getLocalExtensionIdFromGallery(extension, extension.version); + this._onInstallExtension.fire({ identifier: { id, uuid: extension.identifier.uuid }, gallery: extension }); + } + } + + private onDidInstallExtensions(extensions: IGalleryExtension[], local: ILocalExtension[], errorCode?: string, error?: any): TPromise { + extensions.forEach((gallery, index) => { + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version), uuid: gallery.identifier.uuid }; + if (errorCode) { + this._onDidInstallExtension.fire({ identifier, gallery, error: errorCode }); + } else { + this._onDidInstallExtension.fire({ identifier, gallery, local: local[index] }); + } + }); + return error ? TPromise.wrapError(Array.isArray(error) ? this.joinErrors(error) : error) : TPromise.as(null); } private filterDependenciesToInstall(extension: IGalleryExtension, dependencies: IGalleryExtension[]): TPromise { return this.getInstalled() .then(local => { return dependencies.filter(d => { - if (extension.uuid === d.uuid) { + if (extension.identifier.uuid === d.identifier.uuid) { return false; } const extensionId = getLocalExtensionIdFromGallery(d, d.version); - return local.every(local => local.id !== extensionId); + return local.every(({ identifier }) => identifier.id !== extensionId); }); }); } @@ -249,24 +240,11 @@ export class ExtensionManagementService implements IExtensionManagementService { } private getGalleryExtensionForLocalExtension(galleryExtensions: IGalleryExtension[], localExtension: ILocalExtension): IGalleryExtension { - const filtered = galleryExtensions.filter(galleryExtension => getLocalExtensionIdFromGallery(galleryExtension, galleryExtension.version) === localExtension.id); + const filtered = galleryExtensions.filter(galleryExtension => areSameExtensions(localExtension.identifier, { id: getLocalExtensionIdFromGallery(galleryExtension, galleryExtension.version), uuid: galleryExtension.identifier.uuid })); return filtered.length ? filtered[0] : null; } - private downloadAndInstall(extension: IGalleryExtension): TPromise { - const id = getLocalExtensionIdFromGallery(extension, extension.version); - const metadata = { - id: extension.uuid, - publisherId: extension.publisherId, - publisherDisplayName: extension.publisherDisplayName, - }; - - return this.galleryService.download(extension) - .then(zipPath => validate(zipPath).then(() => zipPath)) - .then(zipPath => this.installExtension(zipPath, id, metadata)); - } - - private installExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { + private installExtension({ zipPath, id, metadata, current }: InstallableExtension): TPromise { const extensionPath = path.join(this.extensionsPath, id); return pfs.rimraf(extensionPath).then(() => { @@ -279,14 +257,12 @@ export class ExtensionManagementService implements IExtensionManagementService { const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; const changelogUrl = changelog ? URI.file(path.join(extensionPath, changelog)).toString() : null; const type = LocalExtensionType.User; + const identifier = { id, uuid: metadata ? metadata.id : null }; - const local: ILocalExtension = { type, id, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; - const manifestPath = path.join(extensionPath, 'package.json'); + const local: ILocalExtension = { type, identifier, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; - return pfs.readFile(manifestPath, 'utf8') - .then(raw => parseManifest(raw)) - .then(({ manifest }) => assign(manifest, { __metadata: metadata })) - .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) + return this.saveMetadataForLocalExtension(local) + .then(() => this.checkForRename(current, local)) .then(() => local); }); }); @@ -294,14 +270,52 @@ export class ExtensionManagementService implements IExtensionManagementService { } uninstall(extension: ILocalExtension, force = false): TPromise { - return this.removeOutdatedExtensions().then(() => { - return this.scanUserExtensions().then(installed => { - const promises = installed - .filter(e => e.manifest.publisher === extension.manifest.publisher && e.manifest.name === extension.manifest.name) - .map(e => this.checkForDependenciesAndUninstall(e, installed, force)); - return TPromise.join(promises); - }); - }).then(() => { /* drop resolved value */ }); + return this.removeOutdatedExtensions() + .then(() => + this.scanUserExtensions() + .then(installed => { + const promises = installed + .filter(e => e.manifest.publisher === extension.manifest.publisher && e.manifest.name === extension.manifest.name) + .map(e => this.checkForDependenciesAndUninstall(e, installed, force)); + return TPromise.join(promises).then(null, error => TPromise.wrapError(Array.isArray(error) ? this.joinErrors(error) : error)); + })) + .then(() => { /* drop resolved value */ }); + } + + updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): TPromise { + local.metadata = metadata; + return this.saveMetadataForLocalExtension(local); + } + + private saveMetadataForLocalExtension(local: ILocalExtension): TPromise { + if (!local.metadata) { + return TPromise.as(local); + } + const manifestPath = path.join(this.extensionsPath, local.identifier.id, 'package.json'); + return pfs.readFile(manifestPath, 'utf8') + .then(raw => parseManifest(raw)) + .then(({ manifest }) => assign(manifest, { __metadata: local.metadata })) + .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) + .then(() => local); + } + + private checkForRename(currentExtension: ILocalExtension, newExtension: ILocalExtension): TPromise { + // Check if the gallery id for current and new exensions are same, if not, remove the current one. + if (currentExtension && getGalleryExtensionIdFromLocal(currentExtension) !== getGalleryExtensionIdFromLocal(newExtension)) { + // return this.uninstallExtension(currentExtension.identifier); + return this.setObsolete(currentExtension.identifier.id); + } + return TPromise.as(null); + } + + private joinErrors(errors: (Error | string)[]): Error { + if (errors.length === 1) { + return errors[0] instanceof Error ? errors[0] : new Error(errors[0]); + } + + return errors.reduce((previousValue: Error, currentValue: Error | string) => { + return new Error(`${previousValue.message}${previousValue.message ? ',' : ''}${currentValue instanceof Error ? currentValue.message : currentValue}`); + }, new Error('')); } private checkForDependenciesAndUninstall(extension: ILocalExtension, installed: ILocalExtension[], force: boolean): TPromise { @@ -309,7 +323,7 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => this.hasDependencies(extension, installed) ? this.promptForDependenciesAndUninstall(extension, installed, force) : this.promptAndUninstall(extension, installed, force)) .then(() => this.postUninstallExtension(extension), error => { - this.postUninstallExtension(extension, error); + this.postUninstallExtension(extension, INSTALL_ERROR_LOCAL); return TPromise.wrapError(error); }); } @@ -371,7 +385,7 @@ export class ExtensionManagementService implements IExtensionManagementService { if (dependents.length) { return TPromise.wrapError(new Error(this.getDependentsErrorMessage(extension, dependents))); } - return TPromise.join([this.uninstallExtension(extension.id), ...dependenciesToUninstall.map(d => this.doUninstall(d))]).then(() => null); + return TPromise.join([this.uninstallExtension(extension.identifier), ...dependenciesToUninstall.map(d => this.doUninstall(d))]).then(() => null); } private getDependentsErrorMessage(extension: ILocalExtension, dependents: ILocalExtension[]): string { @@ -422,34 +436,37 @@ export class ExtensionManagementService implements IExtensionManagementService { private doUninstall(extension: ILocalExtension): TPromise { return this.preUninstallExtension(extension) - .then(() => this.uninstallExtension(extension.id)) + .then(() => this.uninstallExtension(extension.identifier)) .then(() => this.postUninstallExtension(extension), error => { - this.postUninstallExtension(extension, error); + this.postUninstallExtension(extension, INSTALL_ERROR_LOCAL); return TPromise.wrapError(error); }); } private preUninstallExtension(extension: ILocalExtension): TPromise { - const extensionPath = path.join(this.extensionsPath, extension.id); + const extensionPath = path.join(this.extensionsPath, extension.identifier.id); return pfs.exists(extensionPath) .then(exists => exists ? null : TPromise.wrapError(new Error(nls.localize('notExists', "Could not find extension")))) - .then(() => this._onUninstallExtension.fire(extension.id)); + .then(() => this._onUninstallExtension.fire(extension.identifier)); } - private uninstallExtension(id: string): TPromise { + private uninstallExtension({ id }: IExtensionIdentifier): TPromise { const extensionPath = path.join(this.extensionsPath, id); return this.setObsolete(id) .then(() => pfs.rimraf(extensionPath)) .then(() => this.unsetObsolete(id)); } - private async postUninstallExtension(extension: ILocalExtension, error?: any): TPromise { + private async postUninstallExtension(extension: ILocalExtension, error?: string): TPromise { if (!error) { - await this.galleryService.reportStatistic(extension.manifest.publisher, extension.manifest.name, extension.manifest.version, StatisticType.Uninstall); + // only report if extension has a mapped gallery extension. UUID identifies the gallery extension. + if (extension.identifier.uuid) { + await this.galleryService.reportStatistic(extension.manifest.publisher, extension.manifest.name, extension.manifest.version, StatisticType.Uninstall); + } } - this._onDidUninstallExtension.fire({ id: extension.id, error }); + this._onDidUninstallExtension.fire({ identifier: extension.identifier, error }); } getInstalled(type: LocalExtensionType = null): TPromise { @@ -495,7 +512,8 @@ export class ExtensionManagementService implements IExtensionManagementService { if (manifest.extensionDependencies) { manifest.extensionDependencies = manifest.extensionDependencies.map(id => adoptToGalleryExtensionId(id)); } - return { type, id, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; + const identifier = { id, uuid: metadata ? metadata.id : null }; + return { type, identifier, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; }); }).then(null, () => null); @@ -599,3 +617,15 @@ export class ExtensionManagementService implements IExtensionManagementService { this.disposables = dispose(this.disposables); } } + +export function getLocalExtensionIdFromGallery(extension: IGalleryExtension, version: string): string { + return getLocalExtensionId(extension.identifier.id, version); +} + +export function getLocalExtensionIdFromManifest(manifest: IExtensionManifest): string { + return getLocalExtensionId(getGalleryExtensionId(manifest.publisher, manifest.name), manifest.version); +} + +function getLocalExtensionId(id: string, version: string): string { + return `${id}-${version}`; +} \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts index e44ff52c8c9..c69181f4630 100644 --- a/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts +++ b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts @@ -12,7 +12,7 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { Emitter } from 'vs/base/common/event'; import { StorageService, InMemoryLocalStorage } from 'vs/platform/storage/common/storageService'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; function storageService(instantiationService: TestInstantiationService): IStorageService { @@ -21,9 +21,7 @@ function storageService(instantiationService: TestInstantiationService): IStorag let workspaceContextService = instantiationService.get(IWorkspaceContextService); if (!workspaceContextService) { workspaceContextService = instantiationService.stub(IWorkspaceContextService, { - hasWorkspace: () => { - return true; - }, + getWorkbenchState: () => WorkbenchState.FOLDER, }); } service = instantiationService.stub(IStorageService, instantiationService.createInstance(StorageService, new InMemoryLocalStorage(), new InMemoryLocalStorage())); @@ -71,22 +69,22 @@ suite('ExtensionEnablementService Test', () => { }); test('test when no extensions are disabled for workspace when there is no workspace', (done) => { - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => { - instantiationService.stub(IWorkspaceContextService, 'hasWorkspace', false); + instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); }) .then(done, done); }); test('test disable an extension globally', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions())) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions())) .then(done, done); }); test('test disable an extension globally should return truthy promise', (done) => { - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(value => assert.ok(value)) .then(done, done); }); @@ -94,184 +92,200 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension globally triggers the change event', (done) => { const target = sinon.spy(); testObject.onEnablementChanged(target); - testObject.setEnablement('pub.a', false) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension globally again should return a falsy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(value => assert.ok(!value)) .then(done, done); }); test('test disable an extension for workspace', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions())) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions())) .then(done, done); }); test('test disable an extension for workspace returns a truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension for workspace again should return a falsy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(value => assert.ok(!value)) .then(done, done); }); test('test disable an extension for workspace and then globally', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test disable an extension for workspace and then globally return a truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension for workspace and then globally triggers the change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension globally and then for workspace', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test disable an extension globally and then for workspace return a truthy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension globally and then for workspace triggers the change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', false, true)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension for workspace when there is no workspace throws error', (done) => { - instantiationService.stub(IWorkspaceContextService, 'hasWorkspace', false); - testObject.setEnablement('pub.a', false, true) + instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => assert.fail('should throw an error'), error => assert.ok(error)) .then(done, done); }); test('test enable an extension globally', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(() => assert.deepEqual([], testObject.getGloballyDisabledExtensions())) .then(done, done); }); test('test enable an extension globally return truthy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test enable an extension globally triggers change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', true)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test enable an extension globally when already enabled return falsy promise', (done) => { - testObject.setEnablement('pub.a', true) + testObject.setEnablement({ id: 'pub.a' }, true) .then(value => assert.ok(!value)) .then(done, done); }); test('test enable an extension for workspace', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(() => assert.deepEqual([], testObject.getWorkspaceDisabledExtensions())) .then(done, done); }); test('test enable an extension for workspace return truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test enable an extension for workspace triggers change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.b', false, true) + testObject.setEnablement({ id: 'pub.b' }, false, true) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.b', true, true)) - .then(() => assert.ok(target.calledWithExactly('pub.b'))) + .then(() => testObject.setEnablement({ id: 'pub.b' }, true, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.b' }))) .then(done, done); }); test('test enable an extension for workspace when already enabled return falsy promise', (done) => { - testObject.setEnablement('pub.a', true, true) + testObject.setEnablement({ id: 'pub.a' }, true, true) .then(value => assert.ok(!value)) .then(done, done); }); test('test enable an extension for workspace when disabled in workspace and gloablly', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); }) .then(done, done); }); test('test enable an extension globally when disabled in workspace and gloablly', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); assert.deepEqual([], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test remove an extension from disablement list when uninstalled', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => didUninstallEvent.fire({ id: 'pub.a-1.0.0' })) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => didUninstallEvent.fire({ identifier: { id: 'pub.a-1.0.0' } })) .then(() => { assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); assert.deepEqual([], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); + + test('test isEnabled return false extension is disabled globally', () => { + return testObject.setEnablement({ id: 'pub.a' }, false, false) + .then(() => assert.ok(!testObject.isEnabled({ id: 'pub.a' }))); + }); + + test('test isEnabled return false extension is disabled in workspace', () => { + return testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => assert.ok(!testObject.isEnabled({ id: 'pub.a' }))); + }); + + test('test isEnabled return true extension is not disabled', () => { + return testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.c' }, false, false)) + .then(() => assert.ok(testObject.isEnabled({ id: 'pub.b' }))); + }); }); \ No newline at end of file diff --git a/src/vs/platform/extensions/common/extensionHost.ts b/src/vs/platform/extensions/common/extensionHost.ts index 3466201a199..dd2d2ca92d2 100644 --- a/src/vs/platform/extensions/common/extensionHost.ts +++ b/src/vs/platform/extensions/common/extensionHost.ts @@ -11,10 +11,4 @@ export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog'; export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach'; export const EXTENSION_TERMINATE_BROADCAST_CHANNEL = 'vscode:extensionTerminate'; export const EXTENSION_RELOAD_BROADCAST_CHANNEL = 'vscode:extensionReload'; -export const EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL = 'vscode:extensionCloseExtensionHost'; - -export interface ILogEntry { - type: string; - severity: string; - arguments: any; -} \ No newline at end of file +export const EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL = 'vscode:extensionCloseExtensionHost'; \ No newline at end of file diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index 0aecc596e0a..ba33bb30403 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -12,6 +12,7 @@ import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistr export interface IExtensionDescription { readonly id: string; readonly name: string; + readonly uuid?: string; readonly displayName?: string; readonly version: string; readonly publisher: string; @@ -24,6 +25,7 @@ export interface IExtensionDescription { }; readonly main?: string; readonly contributes?: { [point: string]: any; }; + readonly keywords?: string[]; enableProposedApi?: boolean; } @@ -102,4 +104,14 @@ export interface IExtensionService { * Restarts the extension host. */ restartExtensionHost(): void; + + /** + * Starts the extension host. + */ + startExtensionHost(): void; + + /** + * Stops the extension host. + */ + stopExtensionHost(): void; } diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index dffe8bf803b..543bc5045f3 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -13,6 +13,9 @@ import { isLinux } from 'vs/base/common/platform'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; import { beginsWithIgnoreCase } from 'vs/base/common/strings'; +import { IProgress } from 'vs/platform/progress/common/progress'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { isEqualOrParent, isEqual } from 'vs/base/common/resources'; export const IFileService = createDecorator('fileService'); @@ -30,6 +33,16 @@ export interface IFileService { */ onAfterOperation: Event; + /** + * Registeres a file system provider for a certain scheme. + */ + registerProvider?(scheme: string, provider: IFileSystemProvider): IDisposable; + + /** + * Checks if this file service can handle the given resource. + */ + canHandleResource?(resource: URI): boolean; + /** * Resolve the properties of a file identified by the resource. * @@ -93,7 +106,7 @@ export interface IFileService { * * The optional parameter content can be used as value to fill into the new file. */ - createFile(resource: URI, content?: string): TPromise; + createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise; /** * Creates a new folder with the given path. The returned promise @@ -150,6 +163,37 @@ export interface IFileService { dispose(): void; } + +export enum FileType { + File = 0, + Dir = 1, + Symlink = 2 +} +export interface IStat { + id: number | string; + mtime: number; + size: number; + type: FileType; +} + +export interface IFileSystemProvider { + + onDidChange?: Event; + + // more... + // + utimes(resource: URI, mtime: number, atime: number): TPromise; + stat(resource: URI): TPromise; + read(resource: URI, offset: number, count: number, progress: IProgress): TPromise; + write(resource: URI, content: Uint8Array): TPromise; + move(from: URI, to: URI): TPromise; + mkdir(resource: URI): TPromise; + readdir(resource: URI): TPromise<[URI, IStat][]>; + rmdir(resource: URI): TPromise; + unlink(resource: URI): TPromise; +} + + export enum FileOperation { CREATE, DELETE, @@ -231,10 +275,10 @@ export class FileChangesEvent extends events.Event { // For deleted also return true when deleted folder is parent of target path if (type === FileChangeType.DELETED) { - return paths.isEqualOrParent(resource.fsPath, change.resource.fsPath, !isLinux /* ignorecase */); + return isEqualOrParent(resource, change.resource, !isLinux /* ignorecase */); } - return paths.isEqual(resource.fsPath, change.resource.fsPath, !isLinux /* ignorecase */); + return isEqual(resource, change.resource, !isLinux /* ignorecase */); }); } @@ -491,6 +535,15 @@ export interface IResolveFileOptions { resolveSingleChildDescendants?: boolean; } +export interface ICreateFileOptions { + + /** + * Overwrite the file to create if it already exists on disk. Otherwise + * an error will be thrown (FILE_MODIFIED_SINCE). + */ + overwrite?: boolean; +} + export interface IImportResult { stat: IFileStat; isNew: boolean; @@ -535,6 +588,9 @@ export const HotExitConfiguration = { export const CONTENT_CHANGE_EVENT_BUFFER_DELAY = 1000; +export const FILES_ASSOCIATIONS_CONFIG = 'files.associations'; +export const FILES_EXCLUDE_CONFIG = 'files.exclude'; + export interface IFilesConfiguration { files: { associations: { [filepattern: string]: string }; @@ -780,6 +836,16 @@ export const SUPPORTED_ENCODINGS: { [encoding: string]: { labelLong: string; lab labelLong: 'Simplified Chinese (GB 2312)', labelShort: 'GB 2312', order: 45 + }, + cp865: { + labelLong: 'Nordic DOS (CP 865)', + labelShort: 'CP 865', + order: 46 + }, + cp850: { + labelLong: 'Western European DOS (CP 850)', + labelShort: 'CP 850', + order: 47 } }; diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index 8e8519b730f..129df5fabce 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -154,15 +154,6 @@ export class HistoryMainService implements IHistoryMainService { files.unshift(...currentFiles.map(f => f.filePath)); } - // TODO@Ben migration to new workspace ID - workspaces.forEach(workspaceOrFile => { - if (isSingleFolderWorkspaceIdentifier(workspaceOrFile)) { - return; - } - - workspaceOrFile.id = this.workspacesService.getWorkspaceId(workspaceOrFile.configPath); - }); - // Clear those dupes workspaces = arrays.distinct(workspaces, workspace => this.distinctFn(workspace)); files = arrays.distinct(files, file => this.distinctFn(file)); diff --git a/src/vs/platform/instantiation/common/descriptors.ts b/src/vs/platform/instantiation/common/descriptors.ts index 162b4be497e..46cda3ca986 100644 --- a/src/vs/platform/instantiation/common/descriptors.ts +++ b/src/vs/platform/instantiation/common/descriptors.ts @@ -175,98 +175,4 @@ export interface SyncDescriptor8 { bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): SyncDescriptor2; bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): SyncDescriptor1; bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): SyncDescriptor0; -} - -export class AsyncDescriptor extends AbstractDescriptor implements AsyncDescriptor0 { - - public static create(moduleName: string, ctorName: string): AsyncDescriptor { - return new AsyncDescriptor(moduleName, ctorName); - } - - constructor(private _moduleName: string, private _ctorName?: string, ...staticArguments: any[]) { - super(staticArguments); - if (typeof _moduleName !== 'string') { - throw new Error('Invalid AsyncDescriptor arguments, expected `moduleName` to be a string!'); - } - } - - public get moduleName(): string { - return this._moduleName; - } - - public get ctorName(): string { - return this._ctorName; - } - - bind(...moreStaticArguments: any[]): AsyncDescriptor { - let allArgs: any[] = []; - allArgs = allArgs.concat(this.staticArguments()); - allArgs = allArgs.concat(moreStaticArguments); - return new AsyncDescriptor(this.moduleName, this.ctorName, ...allArgs); - } -} - -export interface AsyncDescriptor0 { - moduleName: string; - bind(): AsyncDescriptor0; -} -export interface AsyncDescriptor1 { - moduleName: string; - bind(a1: A1): AsyncDescriptor0; -} -export interface AsyncDescriptor2 { - moduleName: string; - bind(a1: A1): AsyncDescriptor1; - bind(a1: A1, a2: A2): AsyncDescriptor0; -} -export interface AsyncDescriptor3 { - moduleName: string; - bind(a1: A1): AsyncDescriptor2; - bind(a1: A1, a2: A2): AsyncDescriptor1; - bind(a1: A1, a2: A2, a3: A3): AsyncDescriptor0; -} -export interface AsyncDescriptor4 { - moduleName: string; - bind(a1: A1): AsyncDescriptor3; - bind(a1: A1, a2: A2): AsyncDescriptor2; - bind(a1: A1, a2: A2, a3: A3): AsyncDescriptor1; - bind(a1: A1, a2: A2, a3: A3, a4: A4): AsyncDescriptor0; -} -export interface AsyncDescriptor5 { - moduleName: string; - bind(a1: A1): AsyncDescriptor4; - bind(a1: A1, a2: A2): AsyncDescriptor3; - bind(a1: A1, a2: A2, a3: A3): AsyncDescriptor2; - bind(a1: A1, a2: A2, a3: A3, a4: A4): AsyncDescriptor1; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): AsyncDescriptor0; -} -export interface AsyncDescriptor6 { - moduleName: string; - bind(a1: A1): AsyncDescriptor5; - bind(a1: A1, a2: A2): AsyncDescriptor4; - bind(a1: A1, a2: A2, a3: A3): AsyncDescriptor3; - bind(a1: A1, a2: A2, a3: A3, a4: A4): AsyncDescriptor2; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): AsyncDescriptor1; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): AsyncDescriptor0; -} -export interface AsyncDescriptor7 { - moduleName: string; - bind(a1: A1): AsyncDescriptor6; - bind(a1: A1, a2: A2): AsyncDescriptor5; - bind(a1: A1, a2: A2, a3: A3): AsyncDescriptor4; - bind(a1: A1, a2: A2, a3: A3, a4: A4): AsyncDescriptor3; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): AsyncDescriptor2; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): AsyncDescriptor1; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): AsyncDescriptor0; -} -export interface AsyncDescriptor8 { - moduleName: string; - bind(a1: A1): AsyncDescriptor7; - bind(a1: A1, a2: A2): AsyncDescriptor6; - bind(a1: A1, a2: A2, a3: A3): AsyncDescriptor5; - bind(a1: A1, a2: A2, a3: A3, a4: A4): AsyncDescriptor4; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): AsyncDescriptor3; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): AsyncDescriptor2; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): AsyncDescriptor1; - bind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): AsyncDescriptor0; } \ No newline at end of file diff --git a/src/vs/platform/instantiation/common/instantiation.ts b/src/vs/platform/instantiation/common/instantiation.ts index 8d7c113e080..90f36fd412b 100644 --- a/src/vs/platform/instantiation/common/instantiation.ts +++ b/src/vs/platform/instantiation/common/instantiation.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TPromise } from 'vs/base/common/winjs.base'; import { ServiceCollection } from './serviceCollection'; import * as descriptors from './descriptors'; @@ -130,20 +129,6 @@ export interface IInstantiationService { createInstance(ctor: IConstructorSignature7, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7): T; createInstance(ctor: IConstructorSignature8, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8): T; - /** - * Asynchronously creates an instance that is denoted by - * the descriptor - */ - createInstance(descriptor: descriptors.AsyncDescriptor0): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor1, a1: A1): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor2, a1: A1, a2: A2): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor3, a1: A1, a2: A2, a3: A3): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor4, a1: A1, a2: A2, a3: A3, a4: A4): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor5, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor6, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor7, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): TPromise; - createInstance(descriptor: descriptors.AsyncDescriptor8, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): TPromise; - /** * */ diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index 27ffed19554..052e2eba90a 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -4,12 +4,11 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { illegalArgument, illegalState, canceled } from 'vs/base/common/errors'; +import { illegalState } from 'vs/base/common/errors'; import { create } from 'vs/base/common/types'; import * as assert from 'vs/base/common/assert'; import { Graph } from 'vs/base/common/graph'; -import { SyncDescriptor, AsyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ServiceIdentifier, IInstantiationService, ServicesAccessor, _util, optional } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -63,13 +62,9 @@ export class InstantiationService implements IInstantiationService { } } - createInstance(param: any, ...rest: any[]): any { + createInstance(param: any, ...rest: any[]): any { - if (param instanceof AsyncDescriptor) { - // async - return this._createInstanceAsync(param, rest); - - } else if (param instanceof SyncDescriptor) { + if (param instanceof SyncDescriptor) { // sync return this._createInstance(param, rest); @@ -79,43 +74,6 @@ export class InstantiationService implements IInstantiationService { } } - private _createInstanceAsync(descriptor: AsyncDescriptor, args: any[]): TPromise { - - let canceledError: Error; - - return new TPromise((c, e, p) => { - require([descriptor.moduleName], (_module?: any) => { - if (canceledError) { - e(canceledError); - } - - if (!_module) { - return e(illegalArgument('module not found: ' + descriptor.moduleName)); - } - - let ctor: Function; - if (!descriptor.ctorName) { - ctor = _module; - } else { - ctor = _module[descriptor.ctorName]; - } - - if (typeof ctor !== 'function') { - return e(illegalArgument('not a function: ' + descriptor.ctorName || descriptor.moduleName)); - } - - try { - args.unshift.apply(args, descriptor.staticArguments()); // instead of spread in ctor call - c(this._createInstance(new SyncDescriptor(ctor), args)); - } catch (error) { - return e(error); - } - }, e); - }, () => { - canceledError = canceled(); - }); - } - private _createInstance(desc: SyncDescriptor, args: any[]): T { // arguments given by createInstance-call and/or the descriptor diff --git a/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts b/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts index 68c03f70da4..da3a17eb8b0 100644 --- a/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts +++ b/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts @@ -39,18 +39,18 @@ export class TestInstantiationService extends InstantiationService { return this._create(service, { mock: true }); } - public stub(service?: ServiceIdentifier, ctor?: any): T - public stub(service?: ServiceIdentifier, obj?: any): T - public stub(service?: ServiceIdentifier, ctor?: any, property?: string, value?: any): sinon.SinonStub - public stub(service?: ServiceIdentifier, obj?: any, property?: string, value?: any): sinon.SinonStub - public stub(service?: ServiceIdentifier, property?: string, value?: any): sinon.SinonStub + public stub(service?: ServiceIdentifier, ctor?: any): T; + public stub(service?: ServiceIdentifier, obj?: any): T; + public stub(service?: ServiceIdentifier, ctor?: any, property?: string, value?: any): sinon.SinonStub; + public stub(service?: ServiceIdentifier, obj?: any, property?: string, value?: any): sinon.SinonStub; + public stub(service?: ServiceIdentifier, property?: string, value?: any): sinon.SinonStub; public stub(serviceIdentifier?: ServiceIdentifier, arg2?: any, arg3?: string, arg4?: any): sinon.SinonStub { let service = typeof arg2 !== 'string' ? arg2 : void 0; let serviceMock: IServiceMock = { id: serviceIdentifier, service: service }; let property = typeof arg2 === 'string' ? arg2 : arg3; let value = typeof arg2 === 'string' ? arg3 : arg4; - let stubObject = this._create(serviceMock, { stub: true }); + let stubObject = this._create(serviceMock, { stub: true }, service && !property); if (property) { if (stubObject[property]) { if (stubObject[property].hasOwnProperty('restore')) { @@ -70,10 +70,10 @@ export class TestInstantiationService extends InstantiationService { return stubObject; } - public stubPromise(service?: ServiceIdentifier, fnProperty?: string, value?: any): T | sinon.SinonStub - public stubPromise(service?: ServiceIdentifier, ctor?: any, fnProperty?: string, value?: any): sinon.SinonStub - public stubPromise(service?: ServiceIdentifier, obj?: any, fnProperty?: string, value?: any): sinon.SinonStub - public stubPromise(arg1?: any, arg2?: any, arg3?: any, arg4?: any): sinon.SinonStub { + public stubPromise(service?: ServiceIdentifier, fnProperty?: string, value?: any): T | sinon.SinonStub; + public stubPromise(service?: ServiceIdentifier, ctor?: any, fnProperty?: string, value?: any): sinon.SinonStub; + public stubPromise(service?: ServiceIdentifier, obj?: any, fnProperty?: string, value?: any): sinon.SinonStub; + public stubPromise(arg1?: any, arg2?: any, arg3?: any, arg4?: any): sinon.SinonStub { arg3 = typeof arg2 === 'string' ? TPromise.as(arg3) : arg3; arg4 = typeof arg2 !== 'string' && typeof arg3 === 'string' ? TPromise.as(arg4) : arg4; return this.stub(arg1, arg2, arg3, arg4); @@ -85,20 +85,20 @@ export class TestInstantiationService extends InstantiationService { return spy; } - private _create(serviceMock: IServiceMock, options: SinonOptions): any - private _create(ctor: any, options: SinonOptions): any - private _create(arg1: any, options: SinonOptions): any { + private _create(serviceMock: IServiceMock, options: SinonOptions, reset?: boolean): any; + private _create(ctor: any, options: SinonOptions): any; + private _create(arg1: any, options: SinonOptions, reset: boolean = false): any { if (this.isServiceMock(arg1)) { - let service = this._getOrCreateService(arg1, options); + let service = this._getOrCreateService(arg1, options, reset); this._serviceCollection.set(arg1.id, service); return service; } return options.mock ? sinon.mock(arg1) : this._createStub(arg1); } - private _getOrCreateService(serviceMock: IServiceMock, opts: SinonOptions): any { + private _getOrCreateService(serviceMock: IServiceMock, opts: SinonOptions, reset?: boolean): any { let service: any = this._serviceCollection.get(serviceMock.id); - if (service) { + if (!reset && service) { if (opts.mock && service['sinonOptions'] && !!service['sinonOptions'].mock) { return service; } diff --git a/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts b/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts index 5d4f91c0dff..b9c921d4505 100644 --- a/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts +++ b/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts @@ -5,9 +5,8 @@ 'use strict'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import platform = require('vs/platform/registry/common/platform'); -import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import * as platform from 'vs/platform/registry/common/platform'; +import Event, { Emitter } from 'vs/base/common/event'; export const Extensions = { JSONContribution: 'base.contributions.json' @@ -19,6 +18,8 @@ export interface ISchemaContributions { export interface IJSONContributionRegistry { + readonly onDidChangeSchema: Event; + /** * Register a schema to the registry. */ @@ -28,12 +29,6 @@ export interface IJSONContributionRegistry { * Get all schemas */ getSchemaContributions(): ISchemaContributions; - - /** - * Adds a change listener - */ - addRegistryChangedListener(callback: (e: IJSONContributionRegistryEvent) => void): IDisposable; - } export interface IJSONContributionRegistryEvent { @@ -50,21 +45,19 @@ function normalizeId(id: string) { class JSONContributionRegistry implements IJSONContributionRegistry { + private schemasById: { [id: string]: IJSONSchema }; - private eventEmitter: EventEmitter; + + private _onDidChangeSchema: Emitter = new Emitter(); + readonly onDidChangeSchema: Event = this._onDidChangeSchema.event; constructor() { this.schemasById = {}; - this.eventEmitter = new EventEmitter(); - } - - public addRegistryChangedListener(callback: (e: IJSONContributionRegistryEvent) => void): IDisposable { - return this.eventEmitter.addListener('registryChanged', callback); } public registerSchema(uri: string, unresolvedSchemaContent: IJSONSchema): void { this.schemasById[normalizeId(uri)] = unresolvedSchemaContent; - this.eventEmitter.emit('registryChanged', {}); + this._onDidChangeSchema.fire(uri); } public getSchemaContributions(): ISchemaContributions { diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index 176a15f5e27..85e8ad8165a 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -16,6 +16,7 @@ import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IMessageService } from 'vs/platform/message/common/message'; import Event, { Emitter } from 'vs/base/common/event'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; interface CurrentChord { keypress: string; @@ -32,18 +33,21 @@ export abstract class AbstractKeybindingService implements IKeybindingService { protected _onDidUpdateKeybindings: Emitter; private _contextKeyService: IContextKeyService; - protected _commandService: ICommandService; private _statusService: IStatusbarService; private _messageService: IMessageService; + protected _commandService: ICommandService; + protected _telemetryService: ITelemetryService; constructor( contextKeyService: IContextKeyService, commandService: ICommandService, + telemetryService: ITelemetryService, messageService: IMessageService, statusService?: IStatusbarService ) { this._contextKeyService = contextKeyService; this._commandService = commandService; + this._telemetryService = telemetryService; this._statusService = statusService; this._messageService = messageService; @@ -161,6 +165,13 @@ export abstract class AbstractKeybindingService implements IKeybindingService { this._commandService.executeCommand(resolveResult.commandId, resolveResult.commandArgs || {}).done(undefined, err => { this._messageService.show(Severity.Warning, err); }); + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this._telemetryService.publicLog('workbenchActionExecuted', { id: resolveResult.commandId, from: 'keybinding' }); } return shouldPreventDefault; diff --git a/src/vs/platform/keybinding/common/keybindingsRegistry.ts b/src/vs/platform/keybinding/common/keybindingsRegistry.ts index cc64c50bdc3..98736111499 100644 --- a/src/vs/platform/keybinding/common/keybindingsRegistry.ts +++ b/src/vs/platform/keybinding/common/keybindingsRegistry.ts @@ -162,7 +162,7 @@ class KeybindingsRegistryImpl implements IKeybindingsRegistry { public registerCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): void { this.registerKeybindingRule(desc); - CommandsRegistry.registerCommand(desc.id, desc); + CommandsRegistry.registerCommand(desc); } private static _mightProduceChar(keyCode: KeyCode): boolean { diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index f5cc9fb7984..e9468d0dd7b 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -19,6 +19,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { OS } from 'vs/base/common/platform'; import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; +import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; function createContext(ctx: any) { return { @@ -40,7 +41,7 @@ suite('AbstractKeybindingService', () => { messageService: IMessageService, statusService?: IStatusbarService ) { - super(contextKeyService, commandService, messageService, statusService); + super(contextKeyService, commandService, NullTelemetryService, messageService, statusService); this._resolver = resolver; } @@ -123,6 +124,7 @@ suite('AbstractKeybindingService', () => { let messageService: IMessageService = { _serviceBrand: undefined, hideAll: undefined, + confirmSync: undefined, confirm: undefined, show: (sev: Severity, message: any): () => void => { showMessageCalls.push({ diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index a050b92656c..62a40264836 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -14,6 +14,7 @@ import { OS } from 'vs/base/common/platform'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; class MockKeybindingContextKey implements IContextKey { + // @ts-ignore unused property private _key: string; private _defaultValue: T; private _value: T; diff --git a/src/vs/platform/lifecycle/common/lifecycle.ts b/src/vs/platform/lifecycle/common/lifecycle.ts index 0a413c08ce9..3f2cd9cde69 100644 --- a/src/vs/platform/lifecycle/common/lifecycle.ts +++ b/src/vs/platform/lifecycle/common/lifecycle.ts @@ -47,8 +47,9 @@ export enum StartupKind { export enum LifecyclePhase { Starting = 1, - Running = 2, - ShuttingDown = 3 + Restoring = 2, + Running = 3, + ShuttingDown = 4 } /** @@ -70,9 +71,10 @@ export interface ILifecycleService { readonly phase: LifecyclePhase; /** - * An event that fire when the lifecycle phase has changed + * Returns a promise that resolves when a certain lifecycle phase + * has started. */ - readonly onDidChangePhase: Event; + when(phase: LifecyclePhase): Thenable; /** * Fired before shutdown happens. Allows listeners to veto against the @@ -92,8 +94,8 @@ export interface ILifecycleService { export const NullLifecycleService: ILifecycleService = { _serviceBrand: null, phase: LifecyclePhase.Running, + when() { return Promise.resolve(); }, startupKind: StartupKind.NewWindow, - onDidChangePhase: Event.None, onWillShutdown: Event.None, onShutdown: Event.None }; @@ -127,4 +129,4 @@ export function handleVetos(vetos: (boolean | TPromise)[], onError: (er } return TPromise.join(promises).then(() => lazyValue); -} \ No newline at end of file +} diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts index 2f9dd792707..28bf62c5654 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts @@ -7,7 +7,6 @@ import { ipcMain as ipc, app } from 'electron'; import { TPromise, TValueCallback } from 'vs/base/common/winjs.base'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/node/storage'; import Event, { Emitter } from 'vs/base/common/event'; @@ -94,7 +93,6 @@ export class LifecycleService implements ILifecycleService { onBeforeWindowUnload: Event = this._onBeforeWindowUnload.event; constructor( - @IEnvironmentService private environmentService: IEnvironmentService, @ILogService private logService: ILogService, @IStorageService private storageService: IStorageService ) { @@ -141,8 +139,7 @@ export class LifecycleService implements ILifecycleService { // Windows/Linux: we quit when all windows have closed // Mac: we only quit when quit was requested - // --wait: we quit when all windows are closed - if (this.quitRequested || process.platform !== 'darwin' || this.environmentService.wait) { + if (this.quitRequested || process.platform !== 'darwin') { app.quit(); } }); diff --git a/src/vs/platform/markers/common/problemMatcher.ts b/src/vs/platform/markers/common/problemMatcher.ts index cf49ef05252..4c12f0ac481 100644 --- a/src/vs/platform/markers/common/problemMatcher.ts +++ b/src/vs/platform/markers/common/problemMatcher.ts @@ -1026,7 +1026,7 @@ class ProblemPatternRegistryImpl implements IProblemPatternRegistry { private fillDefaults(): void { this.add('msCompile', { - regexp: /^([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\)\s*:\s+(error|warning|info)\s+(\w{1,2}\d+)\s*:\s*(.*)$/, + regexp: /^(?:\s+\d+\>)?([^\s].*)\((\d+|\d+,\d+|\d+,\d+,\d+,\d+)\)\s*:\s+(error|warning|info)\s+(\w{1,2}\d+)\s*:\s*(.*)$/, file: 1, location: 2, severity: 3, @@ -1180,13 +1180,13 @@ export class ProblemMatcherParser extends Parser { let kind: FileLocationKind; if (Types.isUndefined(description.fileLocation)) { fileLocation = FileLocationKind.Relative; - filePrefix = '${cwd}'; + filePrefix = '${workspaceFolder}'; } else if (Types.isString(description.fileLocation)) { kind = FileLocationKind.fromString(description.fileLocation); if (kind) { fileLocation = kind; if (kind === FileLocationKind.Relative) { - filePrefix = '${cwd}'; + filePrefix = '${workspaceFolder}'; } } } else if (Types.isStringArray(description.fileLocation)) { @@ -1601,7 +1601,7 @@ class ProblemMatcherRegistryImpl implements IProblemMatcherRegistry { owner: 'typescript', applyTo: ApplyToKind.closedDocuments, fileLocation: FileLocationKind.Relative, - filePrefix: '${cwd}', + filePrefix: '${workspaceFolder}', pattern: ProblemPatternRegistry.get('gulp-tsc') }); @@ -1629,7 +1629,7 @@ class ProblemMatcherRegistryImpl implements IProblemMatcherRegistry { owner: 'eslint', applyTo: ApplyToKind.allDocuments, fileLocation: FileLocationKind.Relative, - filePrefix: '${cwd}', + filePrefix: '${workspaceFolder}', pattern: ProblemPatternRegistry.get('eslint-compact') }); @@ -1648,7 +1648,7 @@ class ProblemMatcherRegistryImpl implements IProblemMatcherRegistry { owner: 'go', applyTo: ApplyToKind.allDocuments, fileLocation: FileLocationKind.Relative, - filePrefix: '${cwd}', + filePrefix: '${workspaceFolder}', pattern: ProblemPatternRegistry.get('go') }); } diff --git a/src/vs/platform/message/common/message.ts b/src/vs/platform/message/common/message.ts index 627bbe0900b..cfe7e448854 100644 --- a/src/vs/platform/message/common/message.ts +++ b/src/vs/platform/message/common/message.ts @@ -23,6 +23,10 @@ export interface IConfirmation { detail?: string; primaryButton?: string; secondaryButton?: string; + checkbox?: { + label: string; + checked?: boolean; + }; } export const CloseAction = new Action('close.message', nls.localize('close', "Close"), null, true, () => TPromise.as(true)); @@ -31,6 +35,11 @@ export const CancelAction = new Action('cancel.message', nls.localize('cancel', export const IMessageService = createDecorator('messageService'); +export interface IConfirmationResult { + confirmed: boolean; + checkboxChecked?: boolean; +} + export interface IMessageService { _serviceBrand: any; @@ -53,7 +62,12 @@ export interface IMessageService { /** * Ask the user for confirmation. */ - confirm(confirmation: IConfirmation): boolean; + confirmSync(confirmation: IConfirmation): boolean; + + /** + * Ask the user for confirmation without blocking. + */ + confirm(confirmation: IConfirmation): TPromise; } export const IChoiceService = createDecorator('choiceService'); diff --git a/src/vs/platform/node/product.ts b/src/vs/platform/node/product.ts index 29c55f1e439..da463d7114d 100644 --- a/src/vs/platform/node/product.ts +++ b/src/vs/platform/node/product.ts @@ -18,7 +18,8 @@ export interface IProductConfiguration { downloadUrl: string; updateUrl?: string; quality?: string; - commit: string; + commit?: string; + settingsSearchBuildId?: number; date: string; extensionsGallery: { serviceUrl: string; @@ -26,7 +27,7 @@ export interface IProductConfiguration { }; extensionTips: { [id: string]: string; }; extensionImportantTips: { [id: string]: { name: string; pattern: string; }; }; - exeBasedExtensionTips: { [id: string]: string; }; + exeBasedExtensionTips: { [id: string]: any; }; extensionKeywords: { [extension: string]: string[]; }; extensionAllowedBadgeProviders: string[]; keymapExtensionTips: string[]; @@ -86,4 +87,4 @@ if (process.env['VSCODE_DEV']) { product.dataFolderName += '-dev'; } -export default product; \ No newline at end of file +export default product; diff --git a/src/vs/platform/opener/browser/openerService.ts b/src/vs/platform/opener/browser/openerService.ts index f6d6e7a0287..940eea38958 100644 --- a/src/vs/platform/opener/browser/openerService.ts +++ b/src/vs/platform/opener/browser/openerService.ts @@ -5,6 +5,7 @@ 'use strict'; import URI from 'vs/base/common/uri'; +import * as dom from 'vs/base/browser/dom'; import { parse } from 'vs/base/common/marshalling'; import { Schemas } from 'vs/base/common/network'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -30,14 +31,19 @@ export class OpenerService implements IOpenerService { open(resource: URI, options?: { openToSide?: boolean }): TPromise { + /* __GDPR__ + "openerService" : { + "scheme" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this._telemetryService.publicLog('openerService', { scheme: resource.scheme }); const { scheme, path, query, fragment } = resource; let promise: TPromise; - if (scheme === Schemas.http || scheme === Schemas.https) { - // open http - window.open(resource.toString(true)); + if (scheme === Schemas.http || scheme === Schemas.https || scheme === Schemas.mailto) { + // open http or default mail application + dom.windowOpenNoOpener(resource.toString(true)); } else if (scheme === 'command' && CommandsRegistry.getCommand(path)) { // execute as command let args: any = []; @@ -73,7 +79,7 @@ export class OpenerService implements IOpenerService { return TPromise.as(undefined); } else if (resource.scheme === Schemas.file) { - resource = URI.file(normalize(resource.fsPath)); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + resource = resource.with({ path: normalize(resource.path) }); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) } promise = this._editorService.openEditor({ resource, options: { selection, } }, options && options.openToSide); } diff --git a/src/vs/platform/quickOpen/common/quickOpen.ts b/src/vs/platform/quickOpen/common/quickOpen.ts index 82277c2212e..0b3bf170855 100644 --- a/src/vs/platform/quickOpen/common/quickOpen.ts +++ b/src/vs/platform/quickOpen/common/quickOpen.ts @@ -35,6 +35,7 @@ export interface IPickOpenEntry { } export interface IPickOpenItem { + index: number; remove: () => void; getId: () => string; getResource: () => uri; @@ -122,6 +123,7 @@ export interface IInputOptions { export interface IShowOptions { quickNavigateConfiguration?: IQuickNavigateConfiguration; inputSelection?: { start: number; end: number; }; + autoFocus?: IAutoFocus; } export const IQuickOpenService = createDecorator('quickOpenService'); diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index de5f75fbbd6..a6e58846724 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -29,7 +29,7 @@ export class RequestService implements IRequestService { @IConfigurationService configurationService: IConfigurationService ) { this.configure(configurationService.getConfiguration()); - configurationService.onDidUpdateConfiguration(() => this.configure(configurationService.getConfiguration()), this, this.disposables); + configurationService.onDidChangeConfiguration(() => this.configure(configurationService.getConfiguration()), this, this.disposables); } private configure(config: IHTTPConfiguration) { diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index ab315d50f0f..bdf36fa1dac 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -37,6 +37,7 @@ export interface IFolderQuery { excludePattern?: glob.IExpression; includePattern?: glob.IExpression; fileEncoding?: string; + disregardIgnoreFiles?: boolean; } export interface ICommonQueryOptions { @@ -44,11 +45,18 @@ export interface ICommonQueryOptions { filePattern?: string; // file search only fileEncoding?: string; maxResults?: number; + /** + * If true no results will be returned. Instead `limitHit` will indicate if at least one result exists or not. + * + * Currently does not work with queries including a 'siblings clause'. + */ + exists?: boolean; sortByScore?: boolean; cacheKey?: string; useRipgrep?: boolean; disregardIgnoreFiles?: boolean; disregardExcludeSettings?: boolean; + ignoreSymlinks?: boolean; } export interface IQueryOptions extends ICommonQueryOptions { @@ -70,7 +78,16 @@ export enum QueryType { File = 1, Text = 2 } - +/* __GDPR__FRAGMENT__ + "IPatternInfo" : { + "pattern" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "isRegExp": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "isWordMatch": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "wordSeparators": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "isMultiline": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "isCaseSensitive": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ export interface IPatternInfo { pattern: string; isRegExp?: boolean; @@ -157,7 +174,15 @@ export interface ISearchConfiguration extends IFilesConfiguration { search: { exclude: glob.IExpression; useRipgrep: boolean; + /** + * Use ignore file for text search. + */ useIgnoreFilesByDefault: boolean; + /** + * Use ignore file for file search. + */ + useIgnoreFiles: boolean; + followSymlinks: boolean; }; editor: { wordSeparators: string; diff --git a/src/vs/platform/storage/common/migration.ts b/src/vs/platform/storage/common/migration.ts index 9d8cd425185..652ad4fdf5a 100644 --- a/src/vs/platform/storage/common/migration.ts +++ b/src/vs/platform/storage/common/migration.ts @@ -170,12 +170,12 @@ export function parseStorage(storage: IStorage): IParsedStorage { }; } -export function migrateStorageToMultiRootWorkspace(fromWorkspaceId: string, toWorkspaceId: IWorkspaceIdentifier, storage: IStorage): void { +export function migrateStorageToMultiRootWorkspace(fromWorkspaceId: string, toWorkspace: IWorkspaceIdentifier, storage: IStorage): string { const parsed = parseStorage(storage); - const newStorageKey = URI.from({ path: toWorkspaceId.id, scheme: 'root' }).toString(); + const newWorkspaceId = URI.from({ path: toWorkspace.id, scheme: 'root' }).toString(); - // Find in which location the workspace storage is to be migrated rom + // Find in which location the workspace storage is to be migrated from let storageForWorkspace: StorageObject; if (parsed.multiRoot.has(fromWorkspaceId)) { storageForWorkspace = parsed.multiRoot.get(fromWorkspaceId); @@ -192,7 +192,9 @@ export function migrateStorageToMultiRootWorkspace(fromWorkspaceId: string, toWo return; // make sure to never migrate the workspace identifier } - storage.setItem(`${StorageService.WORKSPACE_PREFIX}${newStorageKey}/${key}`, storageForWorkspace[key]); + storage.setItem(`${StorageService.WORKSPACE_PREFIX}${newWorkspaceId}/${key}`, storageForWorkspace[key]); }); } + + return newWorkspaceId; } \ No newline at end of file diff --git a/src/vs/platform/storage/common/storageService.ts b/src/vs/platform/storage/common/storageService.ts index 199ba0c9dcf..6ed2e853c3a 100644 --- a/src/vs/platform/storage/common/storageService.ts +++ b/src/vs/platform/storage/common/storageService.ts @@ -33,16 +33,27 @@ export class StorageService implements IStorageService { private _globalStorage: IStorage; private workspaceKey: string; + private _workspaceId: string; constructor( globalStorage: IStorage, workspaceStorage: IStorage, - private workspaceId?: string, + workspaceId?: string, legacyWorkspaceId?: number ) { this._globalStorage = globalStorage; this._workspaceStorage = workspaceStorage || globalStorage; + this.setWorkspaceId(workspaceId, legacyWorkspaceId); + } + + public get workspaceId(): string { + return this._workspaceId; + } + + public setWorkspaceId(workspaceId: string, legacyWorkspaceId?: number): void { + this._workspaceId = workspaceId; + // Calculate workspace storage key this.workspaceKey = this.getWorkspaceKey(workspaceId); @@ -53,10 +64,6 @@ export class StorageService implements IStorageService { } } - public get storageId(): string { - return this.workspaceId; - } - public get globalStorage(): IStorage { return this._globalStorage; } diff --git a/src/vs/platform/storage/test/common/storageService.test.ts b/src/vs/platform/storage/test/common/storageService.test.ts index 2bd09689b54..f51d6957118 100644 --- a/src/vs/platform/storage/test/common/storageService.test.ts +++ b/src/vs/platform/storage/test/common/storageService.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { StorageScope } from 'vs/platform/storage/common/storage'; -import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { StorageService, InMemoryLocalStorage } from 'vs/platform/storage/common/storageService'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; @@ -19,9 +19,7 @@ suite('Workbench StorageSevice', () => { setup(() => { instantiationService = new TestInstantiationService(); contextService = instantiationService.stub(IWorkspaceContextService, { - hasWorkspace: () => { - return true; - }, + getWorkbenchState: () => WorkbenchState.FOLDER, getWorkspace: () => { return TestWorkspace; } diff --git a/src/vs/platform/telemetry/browser/errorTelemetry.ts b/src/vs/platform/telemetry/browser/errorTelemetry.ts index 5bf022e190c..976335c3d81 100644 --- a/src/vs/platform/telemetry/browser/errorTelemetry.ts +++ b/src/vs/platform/telemetry/browser/errorTelemetry.ts @@ -143,6 +143,17 @@ export default class ErrorTelemetry { private _flushBuffer(): void { for (let error of this._buffer) { + /* __GDPR__ + "UnhandledError" : { + "message" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "name": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "stack": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "id": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "line": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "column": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ + // __GDPR__TODO__ what's the complete set of properties? this._telemetryService.publicLog('UnhandledError', error); } this._buffer.length = 0; diff --git a/src/vs/platform/telemetry/common/experiments.ts b/src/vs/platform/telemetry/common/experiments.ts index 36961817a48..fa40eff9876 100644 --- a/src/vs/platform/telemetry/common/experiments.ts +++ b/src/vs/platform/telemetry/common/experiments.ts @@ -8,8 +8,12 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IStorageService } from 'vs/platform/storage/common/storage'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +/* __GDPR__FRAGMENT__ + "IExperiments" : { + "deployToAzureQuickLink" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ export interface IExperiments { - deployToAzureQuickLink: boolean; } export const IExperimentService = createDecorator('experimentService'); @@ -25,7 +29,7 @@ export class ExperimentService implements IExperimentService { _serviceBrand: any; - private experiments: IExperiments; + private experiments: IExperiments = {}; // Shortcut while there are no experiments. constructor( @IStorageService private storageService: IStorageService, @@ -57,12 +61,12 @@ function applyOverrides(experiments: IExperiments, configurationService: IConfig function splitExperimentsRandomness(storageService: IStorageService): IExperiments { const random1 = getExperimentsRandomness(storageService); - const [random2, /* showTaskDocumentation */] = splitRandom(random1); - const [/* random3 */, deployToAzureQuickLink] = splitRandom(random2); + const [/* random2 */, /* ripgrepQuickSearch */] = splitRandom(random1); + // const [/* random3 */, /* deployToAzureQuickLink */] = splitRandom(random2); // const [random4, /* mergeQuickLinks */] = splitRandom(random3); // const [random5, /* enableWelcomePage */] = splitRandom(random4); return { - deployToAzureQuickLink + // ripgrepQuickSearch, }; } @@ -84,6 +88,5 @@ function splitRandom(random: number): [number, boolean] { } function getExperimentsOverrides(configurationService: IConfigurationService): IExperiments { - const config: any = configurationService.getConfiguration('telemetry'); - return config && config.experiments || {}; + return configurationService.getConfiguration('experiments') || {}; } diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index b452e7f8342..45c89aa945a 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -64,7 +64,12 @@ export class TelemetryService implements ITelemetryService { if (this._configurationService) { this._updateUserOptIn(); - this._configurationService.onDidUpdateConfiguration(this._updateUserOptIn, this, this._disposables); + this._configurationService.onDidChangeConfiguration(this._updateUserOptIn, this, this._disposables); + /* __GDPR__ + "optInStatus" : { + "optIn" : { "classification": "SystemMetaData", "purpose": "BusinessInsight" } + } + */ this.publicLog('optInStatus', { optIn: this._userOptIn }); } } diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index d1c8b3db156..e3a5e9ec26d 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -9,17 +9,17 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { guessMimeTypes } from 'vs/base/common/mime'; import paths = require('vs/base/common/paths'); import URI from 'vs/base/common/uri'; -import { ConfigurationSource, IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/common/keybinding'; import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; -export const NullTelemetryService = { - _serviceBrand: undefined, +export const NullTelemetryService = new class implements ITelemetryService { + _serviceBrand: undefined; publicLog(eventName: string, data?: ITelemetryData) { return TPromise.as(null); - }, - isOptedIn: true, + } + isOptedIn: true; getTelemetryInfo(): TPromise { return TPromise.as({ instanceId: 'someValue.instanceId', @@ -39,42 +39,22 @@ export function combinedAppender(...appenders: ITelemetryAppender[]): ITelemetry export const NullAppender: ITelemetryAppender = { log: () => null }; -// --- util - -export function anonymize(input: string): string { - if (!input) { - return input; +/* __GDPR__FRAGMENT__ + "URIDescriptor" : { + "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "path": { "classification": "CustomerContent", "purpose": "FeatureInsight" } } - - let r = ''; - for (let i = 0; i < input.length; i++) { - let ch = input[i]; - if (ch >= '0' && ch <= '9') { - r += '0'; - continue; - } - if (ch >= 'a' && ch <= 'z') { - r += 'a'; - continue; - } - if (ch >= 'A' && ch <= 'Z') { - r += 'A'; - continue; - } - r += ch; - } - return r; -} - +*/ export interface URIDescriptor { mimeType?: string; ext?: string; path?: string; } -export function telemetryURIDescriptor(uri: URI): URIDescriptor { +export function telemetryURIDescriptor(uri: URI, hashPath: (path: string) => string): URIDescriptor { const fsPath = uri && uri.fsPath; - return fsPath ? { mimeType: guessMimeTypes(fsPath).join(', '), ext: paths.extname(fsPath), path: anonymize(fsPath) } : {}; + return fsPath ? { mimeType: guessMimeTypes(fsPath).join(', '), ext: paths.extname(fsPath), path: hashPath(fsPath) } : {}; } /** @@ -178,14 +158,26 @@ const configurationValueWhitelist = [ ]; export function configurationTelemetry(telemetryService: ITelemetryService, configurationService: IConfigurationService): IDisposable { - return configurationService.onDidUpdateConfiguration(event => { - if (event.source !== ConfigurationSource.Default) { + return configurationService.onDidChangeConfiguration(event => { + if (event.source !== ConfigurationTarget.DEFAULT) { + /* __GDPR__ + "updateConfiguration" : { + "configurationSource" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "configurationKeys": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ telemetryService.publicLog('updateConfiguration', { - configurationSource: ConfigurationSource[event.source], + configurationSource: ConfigurationTarget[event.source], configurationKeys: flattenKeys(event.sourceConfig) }); + /* __GDPR__ + "updateConfigurationValues" : { + "configurationSource" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "configurationValues": { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ telemetryService.publicLog('updateConfigurationValues', { - configurationSource: ConfigurationSource[event.source], + configurationSource: ConfigurationTarget[event.source], configurationValues: flattenValues(event.sourceConfig, configurationValueWhitelist) }); } @@ -194,6 +186,11 @@ export function configurationTelemetry(telemetryService: ITelemetryService, conf export function lifecycleTelemetry(telemetryService: ITelemetryService, lifecycleService: ILifecycleService): IDisposable { return lifecycleService.onShutdown(event => { + /* __GDPR__ + "shutdown" : { + "reason" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ telemetryService.publicLog('shutdown', { reason: ShutdownReason[event] }); }); } @@ -201,6 +198,11 @@ export function lifecycleTelemetry(telemetryService: ITelemetryService, lifecycl export function keybindingsTelemetry(telemetryService: ITelemetryService, keybindingService: IKeybindingService): IDisposable { return keybindingService.onDidUpdateKeybindings(event => { if (event.source === KeybindingSource.User && event.keybindings) { + /* __GDPR__ + "updateKeybindings" : { + "bindings": { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ telemetryService.publicLog('updateKeybindings', { bindings: event.keybindings.map(binding => ({ key: binding.key, diff --git a/src/vs/platform/telemetry/node/commonProperties.ts b/src/vs/platform/telemetry/node/commonProperties.ts index 5e6611497c3..3ee844f84e3 100644 --- a/src/vs/platform/telemetry/node/commonProperties.ts +++ b/src/vs/platform/telemetry/node/commonProperties.ts @@ -11,29 +11,41 @@ import * as uuid from 'vs/base/common/uuid'; export const machineIdStorageKey = 'telemetry.machineId'; export const machineIdIpcChannel = 'vscode:machineId'; -export function resolveCommonProperties(commit: string, version: string): TPromise<{ [name: string]: string; }> { +export function resolveCommonProperties(commit: string, version: string, source: string): TPromise<{ [name: string]: string; }> { const result: { [name: string]: string; } = Object.create(null); + // __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['sessionID'] = uuid.generateUuid() + Date.now(); + // __GDPR__COMMON__ "commitHash" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['commitHash'] = commit; + // __GDPR__COMMON__ "version" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['version'] = version; + // __GDPR__COMMON__ "common.osVersion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.osVersion'] = os.release(); + // __GDPR__COMMON__ "common.platform" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.platform'] = Platform.Platform[Platform.platform]; + // __GDPR__COMMON__ "common.nodePlatform" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.nodePlatform'] = process.platform; + // __GDPR__COMMON__ "common.nodeArch" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.nodeArch'] = process.arch; + // __GDPR__COMMON__ "common.source" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + result['common.source'] = source; // dynamic properties which value differs on each call let seq = 0; const startTime = Date.now(); Object.defineProperties(result, { + // __GDPR__COMMON__ "timestamp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } 'timestamp': { get: () => new Date(), enumerable: true }, + // __GDPR__COMMON__ "common.timesincesessionstart" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } 'common.timesincesessionstart': { get: () => Date.now() - startTime, enumerable: true }, + // __GDPR__COMMON__ "common.sequence" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } 'common.sequence': { get: () => seq++, enumerable: true diff --git a/src/vs/platform/telemetry/node/telemetryNodeUtils.ts b/src/vs/platform/telemetry/node/telemetryNodeUtils.ts new file mode 100644 index 00000000000..9f65136e10b --- /dev/null +++ b/src/vs/platform/telemetry/node/telemetryNodeUtils.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; +import URI from 'vs/base/common/uri'; +import product from 'vs/platform/node/product'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; + +export function addGAParameters(telemetryService: ITelemetryService, environmentService: IEnvironmentService, uri: URI, origin: string, experiment = '1'): TPromise { + if (environmentService.isBuilt && !environmentService.isExtensionDevelopment && !environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { + if (uri.scheme === 'https' && uri.authority === 'code.visualstudio.com') { + return telemetryService.getTelemetryInfo() + .then(info => { + return uri.with({ query: `${uri.query ? uri.query + '&' : ''}utm_source=VsCode&utm_medium=${encodeURIComponent(origin)}&utm_campaign=${encodeURIComponent(info.instanceId)}&utm_content=${encodeURIComponent(experiment)}` }); + }); + } + } + return TPromise.as(uri); +} diff --git a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts index 58443e27c9b..00dbb1346af 100644 --- a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts +++ b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts @@ -3,21 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as winreg from 'winreg'; import * as os from 'os'; import { TPromise } from 'vs/base/common/winjs.base'; -import * as errors from 'vs/base/common/errors'; import * as uuid from 'vs/base/common/uuid'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { getMachineId } from 'vs/base/node/id'; import { resolveCommonProperties, machineIdStorageKey } from '../node/commonProperties'; -const SQM_KEY: string = '\\Software\\Microsoft\\SQMClient'; -export function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string, version: string): TPromise<{ [name: string]: string }> { - return resolveCommonProperties(commit, version).then(result => { +export function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string, version: string, source: string): TPromise<{ [name: string]: string }> { + return resolveCommonProperties(commit, version, source).then(result => { + // __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.version.shell'] = process.versions && (process).versions['electron']; + // __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.version.renderer'] = process.versions && (process).versions['chrome']; + // __GDPR__COMMON__ "common.osVersion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.osVersion'] = os.release(); const lastSessionDate = storageService.get('telemetry.lastSessionDate'); @@ -25,19 +25,19 @@ export function resolveWorkbenchCommonProperties(storageService: IStorageService storageService.store('telemetry.firstSessionDate', firstSessionDate); storageService.store('telemetry.lastSessionDate', new Date().toUTCString()); + // __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.firstSessionDate'] = firstSessionDate; + // __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.lastSessionDate'] = lastSessionDate; + // __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } result['common.isNewSession'] = !lastSessionDate ? '1' : '0'; const promises: TPromise[] = []; + // __GDPR__COMMON__ "common.instanceId" : { "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } promises.push(getOrCreateInstanceId(storageService).then(value => result['common.instanceId'] = value)); + // __GDPR__COMMON__ "common.machineId" : { "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } promises.push(getOrCreateMachineId(storageService).then(value => result['common.machineId'] = value)); - if (process.platform === 'win32') { - promises.push(getSqmUserId(storageService).then(value => result['common.sqm.userid'] = value)); - promises.push(getSqmMachineId(storageService).then(value => result['common.sqm.machineid'] = value)); - } - return TPromise.join(promises).then(() => result); }); } @@ -60,56 +60,3 @@ export function getOrCreateMachineId(storageService: IStorageService): TPromise< return result; }); } - -function getSqmUserId(storageService: IStorageService): TPromise { - const sqmUserId = storageService.get('telemetry.sqm.userId'); - if (sqmUserId) { - return TPromise.as(sqmUserId); - } - return getWinRegKeyData(SQM_KEY, 'UserId', winreg.HKCU).then(result => { - if (result) { - storageService.store('telemetry.sqm.userId', result); - return result; - } - return undefined; - }); -} - -function getSqmMachineId(storageService: IStorageService): TPromise { - let sqmMachineId = storageService.get('telemetry.sqm.machineId'); - if (sqmMachineId) { - return TPromise.as(sqmMachineId); - } - return getWinRegKeyData(SQM_KEY, 'MachineId', winreg.HKLM).then(result => { - if (result) { - storageService.store('telemetry.sqm.machineId', result); - return result; - } - return undefined; - }); -} - -function getWinRegKeyData(key: string, name: string, hive: string): TPromise { - return new TPromise((resolve, reject) => { - if (process.platform === 'win32') { - try { - const reg = new winreg({ hive, key }); - reg.get(name, (e, result) => { - if (e || !result) { - reject(null); - } else { - resolve(result.value); - } - }); - } catch (err) { - errors.onUnexpectedError(err); - reject(err); - } - } else { - resolve(null); - } - }).then(undefined, err => { - // we only want success - return undefined; - }); -} diff --git a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts index 2522b642f74..67f985b052e 100644 --- a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts @@ -9,8 +9,8 @@ import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppen interface IAppInsightsEvent { eventName: string; - properties?: { string?: string; }; - measurements?: { string?: number; }; + properties?: { [x: string]: string; }; + measurements?: { [x: string]: number; }; } class AppInsightsMock { @@ -34,7 +34,7 @@ class AppInsightsMock { this.exceptions.push(exception); } - public sendPendingData(callback): void { + public sendPendingData(_callback: any): void { // called on dispose } } @@ -85,7 +85,7 @@ suite('AIAdapter', () => { } assert(reallyLongPropertyValue.length > 1024); - var data = {}; + var data = Object.create(null); data[reallyLongPropertyName] = '1234'; data['reallyLongPropertyValue'] = reallyLongPropertyValue; adapter.log('testEvent', data); diff --git a/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts b/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts index 810f50728c5..ff36faa14f5 100644 --- a/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts @@ -12,9 +12,10 @@ import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; suite('Telemetry - common properties', function () { - const commit = void 0; - const version = void 0; - let storageService; + const commit: string = void 0; + const version: string = void 0; + const source: string = void 0; + let storageService: StorageService; setup(() => { storageService = new StorageService(new InMemoryLocalStorage(), null, TestWorkspace.id); @@ -22,7 +23,7 @@ suite('Telemetry - common properties', function () { test('default', function () { - return resolveWorkbenchCommonProperties(storageService, commit, version).then(props => { + return resolveWorkbenchCommonProperties(storageService, commit, version, source).then(props => { assert.ok('commitHash' in props); assert.ok('sessionID' in props); @@ -37,6 +38,7 @@ suite('Telemetry - common properties', function () { // assert.ok('common.version.renderer' in first.data); assert.ok('common.osVersion' in props, 'osVersion'); assert.ok('version' in props); + assert.ok('common.source' in props); assert.ok('common.firstSessionDate' in props, 'firstSessionDate'); assert.ok('common.lastSessionDate' in props, 'lastSessionDate'); // conditional, see below, 'lastSessionDate'ow @@ -45,10 +47,6 @@ suite('Telemetry - common properties', function () { // machine id et al assert.ok('common.instanceId' in props, 'instanceId'); assert.ok('common.machineId' in props, 'machineId'); - if (process.platform === 'win32') { // SQM only on windows - assert.ok('common.sqm.userid' in props, 'userid'); - assert.ok('common.sqm.machineid' in props, 'machineid'); - } }); }); @@ -57,7 +55,7 @@ suite('Telemetry - common properties', function () { storageService.store('telemetry.lastSessionDate', new Date().toUTCString()); - return resolveWorkbenchCommonProperties(storageService, commit, version).then(props => { + return resolveWorkbenchCommonProperties(storageService, commit, version, source).then(props => { assert.ok('common.lastSessionDate' in props); // conditional, see below assert.ok('common.isNewSession' in props); @@ -66,7 +64,7 @@ suite('Telemetry - common properties', function () { }); test('values chance on ask', function () { - return resolveWorkbenchCommonProperties(storageService, commit, version).then(props => { + return resolveWorkbenchCommonProperties(storageService, commit, version, source).then(props => { let value1 = props['common.sequence']; let value2 = props['common.sequence']; assert.ok(value1 !== value2, 'seq'); diff --git a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts index 494159a5f56..341ba75b477 100644 --- a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts @@ -40,16 +40,16 @@ class TestTelemetryAppender implements ITelemetryAppender { } class ErrorTestingSettings { - public personalInfo; - public importantInfo; - public filePrefix; - public dangerousPathWithoutImportantInfo; - public dangerousPathWithImportantInfo; - public missingModelPrefix; - public missingModelMessage; - public noSuchFilePrefix; - public noSuchFileMessage; - public stack; + public personalInfo: string; + public importantInfo: string; + public filePrefix: string; + public dangerousPathWithoutImportantInfo: string; + public dangerousPathWithImportantInfo: string; + public missingModelPrefix: string; + public missingModelMessage: string; + public noSuchFilePrefix: string; + public noSuchFileMessage: string; + public stack: string[]; constructor() { this.personalInfo = 'DANGEROUS/PATH'; @@ -203,7 +203,7 @@ suite('TelemetryService', () => { }); })); - test('Error events', sinon.test(function () { + test('Error events', sinon.test(function (this: any) { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -262,7 +262,7 @@ suite('TelemetryService', () => { // } // })); - test('Handle global errors', sinon.test(function () { + test('Handle global errors', sinon.test(function (this: any) { let errorStub = sinon.stub(); window.onerror = errorStub; @@ -289,7 +289,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Uncaught Error Telemetry removes PII from filename', sinon.test(function () { + test('Uncaught Error Telemetry removes PII from filename', sinon.test(function (this: any) { let errorStub = sinon.stub(); window.onerror = errorStub; let settings = new ErrorTestingSettings(); @@ -318,7 +318,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII', sinon.test(function () { + test('Unexpected Error Telemetry removes PII', sinon.test(function (this: any) { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); try { @@ -348,7 +348,7 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII', sinon.test(function () { + test('Uncaught Error Telemetry removes PII', sinon.test(function (this: any) { let errorStub = sinon.stub(); window.onerror = errorStub; let settings = new ErrorTestingSettings(); @@ -374,7 +374,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves Code file path', sinon.test(function () { + test('Unexpected Error Telemetry removes PII but preserves Code file path', sinon.test(function (this: any) { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -409,7 +409,7 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves Code file path', sinon.test(function () { + test('Uncaught Error Telemetry removes PII but preserves Code file path', sinon.test(function (this: any) { let errorStub = sinon.stub(); window.onerror = errorStub; let settings = new ErrorTestingSettings(); @@ -437,7 +437,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(function () { + test('Unexpected Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(function (this: any) { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -472,7 +472,7 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(function () { + test('Uncaught Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(function (this: any) { let errorStub = sinon.stub(); window.onerror = errorStub; let settings = new ErrorTestingSettings(); @@ -500,7 +500,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves Missing Model error message', sinon.test(function () { + test('Unexpected Error Telemetry removes PII but preserves Missing Model error message', sinon.test(function (this: any) { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -535,7 +535,7 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves Missing Model error message', sinon.test(function () { + test('Uncaught Error Telemetry removes PII but preserves Missing Model error message', sinon.test(function (this: any) { let errorStub = sinon.stub(); window.onerror = errorStub; let settings = new ErrorTestingSettings(); @@ -564,7 +564,7 @@ suite('TelemetryService', () => { service.dispose(); })); - test('Unexpected Error Telemetry removes PII but preserves No Such File error message', sinon.test(function () { + test('Unexpected Error Telemetry removes PII but preserves No Such File error message', sinon.test(function (this: any) { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -599,7 +599,7 @@ suite('TelemetryService', () => { } })); - test('Uncaught Error Telemetry removes PII but preserves No Such File error message', sinon.test(function () { + test('Uncaught Error Telemetry removes PII but preserves No Such File error message', sinon.test(function (this: any) { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); Errors.setUnexpectedErrorHandler(() => { }); @@ -681,24 +681,25 @@ suite('TelemetryService', () => { enableTelemetry: enableTelemetry } as any; }, - getConfigurationData(): any { + getValue(key) { + return getConfigurationValue(this.getConfiguration(), key); + }, + updateValue(): TPromise { return null; }, - reloadConfiguration() { - return TPromise.as(this.getConfiguration()); - }, - lookup(key: string) { + inspect(key: string) { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: null, - folder: null + workspaceFolder: null }; }, - keys() { return { default: [], user: [], workspace: [], folder: [] }; }, - values() { return {}; }, - onDidUpdateConfiguration: emitter.event + keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; }, + onDidChangeConfiguration: emitter.event, + reloadConfiguration(): TPromise { return null; }, + getConfigurationData() { return null; } }); assert.equal(service.isOptedIn, false); diff --git a/src/vs/platform/theme/common/colorExtensionPoint.ts b/src/vs/platform/theme/common/colorExtensionPoint.ts index 3d4c8e8551d..d9e077db578 100644 --- a/src/vs/platform/theme/common/colorExtensionPoint.ts +++ b/src/vs/platform/theme/common/colorExtensionPoint.ts @@ -42,7 +42,7 @@ const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint { if (typeof extension.id !== 'string' || extension.id.length === 0) { - collector.error(nls.localize('invalid.id', "'configuration.colors.id' must be defined an can not be empty")); + collector.error(nls.localize('invalid.id', "'configuration.colors.id' must be defined and can not be empty")); return; } if (!extension.id.match(colorIdPattern)) { @@ -101,11 +101,11 @@ export class ColorExtensionPoint { return; } if (typeof extension.description !== 'string' || extension.id.length === 0) { - collector.error(nls.localize('invalid.description', "'configuration.colors.description' must be defined an can not be empty")); + collector.error(nls.localize('invalid.description', "'configuration.colors.description' must be defined and can not be empty")); return; } let defaults = extension.defaults; - if (typeof defaults !== 'object' || typeof defaults.light !== 'string' || typeof defaults.dark !== 'string' || typeof defaults.highContrast !== 'string') { + if (!defaults || typeof defaults !== 'object' || typeof defaults.light !== 'string' || typeof defaults.dark !== 'string' || typeof defaults.highContrast !== 'string') { collector.error(nls.localize('invalid.defaults', "'configuration.colors.defaults' must be defined and must contain 'light', 'dark' and 'highContrast'")); return; } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 0d21ee0e7a9..a30413c4706 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -74,8 +74,7 @@ export interface IColorRegistry { } -const colorPattern = '^#([0-9A-Fa-f]{3,4}|([0-9A-Fa-f]{2}){3,4})$'; -const colorPatternErrorMessage = nls.localize('invalid.color', 'Invalid color format. Use #RGB, #RGBA, #RRGGBB or #RRGGBBAA'); + class ColorRegistry implements IColorRegistry { private colorsById: { [key: string]: ColorContribution }; @@ -89,7 +88,7 @@ class ColorRegistry implements IColorRegistry { public registerColor(id: string, defaults: ColorDefaults, description: string): ColorIdentifier { let colorContribution = { id, description, defaults }; this.colorsById[id] = colorContribution; - this.colorSchema.properties[id] = { type: 'string', description, format: 'color', pattern: colorPattern, patternErrorMessage: colorPatternErrorMessage }; + this.colorSchema.properties[id] = { type: 'string', description, format: 'color-hex', default: '#ff0000' }; this.colorReferenceSchema.enum.push(id); this.colorReferenceSchema.enumDescriptions.push(description); return id; @@ -197,6 +196,7 @@ export const listHoverBackground = registerColor('list.hoverBackground', { dark: export const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hc: null }, nls.localize('listHoverForeground', "List/Tree foreground when hovering over items using the mouse.")); export const listDropBackground = registerColor('list.dropBackground', { dark: listFocusBackground, light: listFocusBackground, hc: null }, nls.localize('listDropBackground', "List/Tree drag and drop background when moving items around using the mouse.")); export const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#0097fb', light: '#007acc', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.')); +export const listInvalidItemForeground = registerColor('list.invalidItemForeground', { dark: '#B89500', light: '#B89500', hc: '#B89500' }, nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.')); export const pickerGroupForeground = registerColor('pickerGroup.foreground', { dark: Color.fromHex('#0097FB').transparent(0.6), light: Color.fromHex('#007ACC').transparent(0.6), hc: Color.white }, nls.localize('pickerGroupForeground', "Quick picker color for grouping labels.")); export const pickerGroupBorder = registerColor('pickerGroup.border', { dark: '#3F3F46', light: '#CCCEDB', hc: Color.white }, nls.localize('pickerGroupBorder', "Quick picker color for grouping borders.")); diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index 243d6c820ac..0e7ca7a5177 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -11,15 +11,23 @@ import { IDisposable } from 'vs/base/common/lifecycle'; export type styleFn = (colors: { [name: string]: ColorIdentifier }) => void; +export interface IStyleOverrides { + [color: string]: ColorIdentifier; +} + export interface IThemable { style: styleFn; } -export function attachStyler(themeService: IThemeService, optionsMapping: { [optionsKey: string]: ColorIdentifier | ColorFunction }, widgetOrCallback: IThemable | styleFn): IDisposable { +export interface IColorMapping { + [optionsKey: string]: ColorIdentifier | ColorFunction | undefined; +} + +export function attachStyler(themeService: IThemeService, optionsMapping: T, widgetOrCallback: IThemable | styleFn): IDisposable { function applyStyles(theme: ITheme): void { const styles = Object.create(null); for (let key in optionsMapping) { - const value = optionsMapping[key]; + const value = optionsMapping[key as string]; if (typeof value === 'string') { styles[key] = theme.getColor(value); } else if (typeof value === 'function') { @@ -39,36 +47,43 @@ export function attachStyler(themeService: IThemeService, optionsMapping: { [opt return themeService.onThemeChange(applyStyles); } -export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: { inputActiveOptionBorderColor?: ColorIdentifier }): IDisposable { - return attachStyler(themeService, { - inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder - }, widget); +export interface ICheckboxStyleOverrides extends IStyleOverrides { + inputActiveOptionBorderColor?: ColorIdentifier; } -export function attachBadgeStyler(widget: IThemable, themeService: IThemeService, style?: - { - badgeBackground?: ColorIdentifier, - badgeForeground?: ColorIdentifier - }): IDisposable { +export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: ICheckboxStyleOverrides): IDisposable { + return attachStyler(themeService, { + inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder + } as ICheckboxStyleOverrides, widget); +} + +export interface IBadgeStyleOverrides extends IStyleOverrides { + badgeBackground?: ColorIdentifier; + badgeForeground?: ColorIdentifier; +} + +export function attachBadgeStyler(widget: IThemable, themeService: IThemeService, style?: IBadgeStyleOverrides): IDisposable { return attachStyler(themeService, { badgeBackground: (style && style.badgeBackground) || badgeBackground, badgeForeground: (style && style.badgeForeground) || badgeForeground, badgeBorder: contrastBorder - }, widget); + } as IBadgeStyleOverrides, widget); } -export function attachInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: - { - inputBackground?: ColorIdentifier, - inputForeground?: ColorIdentifier, - inputBorder?: ColorIdentifier, - inputValidationInfoBorder?: ColorIdentifier, - inputValidationInfoBackground?: ColorIdentifier, - inputValidationWarningBorder?: ColorIdentifier, - inputValidationWarningBackground?: ColorIdentifier, - inputValidationErrorBorder?: ColorIdentifier, - inputValidationErrorBackground?: ColorIdentifier - }): IDisposable { +export interface IInputBoxStyleOverrides extends IStyleOverrides { + inputBackground?: ColorIdentifier; + inputForeground?: ColorIdentifier; + inputBorder?: ColorIdentifier; + inputActiveOptionBorder?: ColorIdentifier; + inputValidationInfoBorder?: ColorIdentifier; + inputValidationInfoBackground?: ColorIdentifier; + inputValidationWarningBorder?: ColorIdentifier; + inputValidationWarningBackground?: ColorIdentifier; + inputValidationErrorBorder?: ColorIdentifier; + inputValidationErrorBackground?: ColorIdentifier; +} + +export function attachInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: IInputBoxStyleOverrides): IDisposable { return attachStyler(themeService, { inputBackground: (style && style.inputBackground) || inputBackground, inputForeground: (style && style.inputForeground) || inputForeground, @@ -79,30 +94,24 @@ export function attachInputBoxStyler(widget: IThemable, themeService: IThemeServ inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || inputValidationWarningBackground, inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || inputValidationErrorBorder, inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || inputValidationErrorBackground - }, widget); + } as IInputBoxStyleOverrides, widget); } -export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?: { selectBackground?: ColorIdentifier, selectForeground?: ColorIdentifier, selectBorder?: ColorIdentifier }): IDisposable { +export interface ISelectBoxStyleOverrides extends IStyleOverrides { + selectBackground?: ColorIdentifier; + selectForeground?: ColorIdentifier; + selectBorder?: ColorIdentifier; +} + +export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?: ISelectBoxStyleOverrides): IDisposable { return attachStyler(themeService, { selectBackground: (style && style.selectBackground) || selectBackground, selectForeground: (style && style.selectForeground) || selectForeground, selectBorder: (style && style.selectBorder) || selectBorder - }, widget); + } as ISelectBoxStyleOverrides, widget); } -export function attachFindInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: - { - inputBackground?: ColorIdentifier, - inputForeground?: ColorIdentifier, - inputBorder?: ColorIdentifier, - inputActiveOptionBorder?: ColorIdentifier, - inputValidationInfoBorder?: ColorIdentifier, - inputValidationInfoBackground?: ColorIdentifier, - inputValidationWarningBorder?: ColorIdentifier, - inputValidationWarningBackground?: ColorIdentifier, - inputValidationErrorBorder?: ColorIdentifier, - inputValidationErrorBackground?: ColorIdentifier - }): IDisposable { +export function attachFindInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: IInputBoxStyleOverrides): IDisposable { return attachStyler(themeService, { inputBackground: (style && style.inputBackground) || inputBackground, inputForeground: (style && style.inputForeground) || inputForeground, @@ -114,43 +123,19 @@ export function attachFindInputBoxStyler(widget: IThemable, themeService: ITheme inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || inputValidationWarningBackground, inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || inputValidationErrorBorder, inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || inputValidationErrorBackground - }, widget); + } as IInputBoxStyleOverrides, widget); } -export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeService, style?: { - foreground?: ColorIdentifier, - background?: ColorIdentifier, - borderColor?: ColorIdentifier, - widgetShadow?: ColorIdentifier, - progressBarBackground?: ColorIdentifier, - inputBackground?: ColorIdentifier, - inputForeground?: ColorIdentifier, - inputBorder?: ColorIdentifier, - inputValidationInfoBorder?: ColorIdentifier, - inputValidationInfoBackground?: ColorIdentifier, - inputValidationWarningBorder?: ColorIdentifier, - inputValidationWarningBackground?: ColorIdentifier, - inputValidationErrorBorder?: ColorIdentifier, - inputValidationErrorBackground?: ColorIdentifier - pickerGroupForeground?: ColorIdentifier, - pickerGroupBorder?: ColorIdentifier, - listFocusBackground?: ColorIdentifier, - listFocusForeground?: ColorIdentifier, - listActiveSelectionBackground?: ColorIdentifier, - listActiveSelectionForeground?: ColorIdentifier, - listFocusAndSelectionBackground?: ColorIdentifier, - listFocusAndSelectionForeground?: ColorIdentifier, - listInactiveSelectionBackground?: ColorIdentifier, - listInactiveSelectionForeground?: ColorIdentifier, - listInactiveFocusBackground?: ColorIdentifier, - listInactiveFocusForeground?: ColorIdentifier, - listHoverBackground?: ColorIdentifier, - listHoverForeground?: ColorIdentifier, - listDropBackground?: ColorIdentifier, - listFocusOutline?: ColorIdentifier, - listSelectionOutline?: ColorIdentifier, - listHoverOutline?: ColorIdentifier -}): IDisposable { +export interface IQuickOpenStyleOverrides extends IListStyleOverrides, IInputBoxStyleOverrides, IProgressBarStyleOverrides { + foreground?: ColorIdentifier; + background?: ColorIdentifier; + borderColor?: ColorIdentifier; + widgetShadow?: ColorIdentifier; + pickerGroupForeground?: ColorIdentifier; + pickerGroupBorder?: ColorIdentifier; +} + +export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeService, style?: IQuickOpenStyleOverrides): IDisposable { return attachStyler(themeService, { foreground: (style && style.foreground) || foreground, background: (style && style.background) || editorBackground, @@ -184,28 +169,30 @@ export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeSer listFocusOutline: (style && style.listFocusOutline) || activeContrastBorder, listSelectionOutline: (style && style.listSelectionOutline) || activeContrastBorder, listHoverOutline: (style && style.listHoverOutline) || activeContrastBorder - }, widget); + } as IQuickOpenStyleOverrides, widget); } -export function attachListStyler(widget: IThemable, themeService: IThemeService, style?: { - listFocusBackground?: ColorIdentifier, - listFocusForeground?: ColorIdentifier, - listActiveSelectionBackground?: ColorIdentifier, - listActiveSelectionForeground?: ColorIdentifier, - listFocusAndSelectionBackground?: ColorIdentifier, - listFocusAndSelectionForeground?: ColorIdentifier, - listInactiveSelectionBackground?: ColorIdentifier, - listInactiveSelectionForeground?: ColorIdentifier, - listInactiveFocusBackground?: ColorIdentifier, - listInactiveFocusForeground?: ColorIdentifier, - listHoverBackground?: ColorIdentifier, - listHoverForeground?: ColorIdentifier, - listDropBackground?: ColorIdentifier, - listFocusOutline?: ColorIdentifier, - listInactiveFocusOutline?: ColorIdentifier, - listSelectionOutline?: ColorIdentifier, - listHoverOutline?: ColorIdentifier, -}): IDisposable { +export interface IListStyleOverrides extends IStyleOverrides { + listFocusBackground?: ColorIdentifier; + listFocusForeground?: ColorIdentifier; + listActiveSelectionBackground?: ColorIdentifier; + listActiveSelectionForeground?: ColorIdentifier; + listFocusAndSelectionBackground?: ColorIdentifier; + listFocusAndSelectionForeground?: ColorIdentifier; + listInactiveSelectionBackground?: ColorIdentifier; + listInactiveSelectionForeground?: ColorIdentifier; + listInactiveFocusBackground?: ColorIdentifier; + listInactiveFocusForeground?: ColorIdentifier; + listHoverBackground?: ColorIdentifier; + listHoverForeground?: ColorIdentifier; + listDropBackground?: ColorIdentifier; + listFocusOutline?: ColorIdentifier; + listInactiveFocusOutline?: ColorIdentifier; + listSelectionOutline?: ColorIdentifier; + listHoverOutline?: ColorIdentifier; +} + +export function attachListStyler(widget: IThemable, themeService: IThemeService, style?: IListStyleOverrides): IDisposable { return attachStyler(themeService, { listFocusBackground: (style && style.listFocusBackground) || listFocusBackground, listFocusForeground: (style && style.listFocusForeground) || listFocusForeground, @@ -224,22 +211,32 @@ export function attachListStyler(widget: IThemable, themeService: IThemeService, listSelectionOutline: (style && style.listSelectionOutline) || activeContrastBorder, listHoverOutline: (style && style.listHoverOutline) || activeContrastBorder, listInactiveFocusOutline: style && style.listInactiveFocusOutline // not defined by default, only opt-in - }, widget); + } as IListStyleOverrides, widget); } -export function attachButtonStyler(widget: IThemable, themeService: IThemeService, style?: { buttonForeground?: ColorIdentifier, buttonBackground?: ColorIdentifier, buttonHoverBackground?: ColorIdentifier }): IDisposable { +export interface IButtonStyleOverrides extends IStyleOverrides { + buttonForeground?: ColorIdentifier; + buttonBackground?: ColorIdentifier; + buttonHoverBackground?: ColorIdentifier; +} + +export function attachButtonStyler(widget: IThemable, themeService: IThemeService, style?: IButtonStyleOverrides): IDisposable { return attachStyler(themeService, { buttonForeground: (style && style.buttonForeground) || buttonForeground, buttonBackground: (style && style.buttonBackground) || buttonBackground, buttonHoverBackground: (style && style.buttonHoverBackground) || buttonHoverBackground, buttonBorder: contrastBorder - }, widget); + } as IButtonStyleOverrides, widget); } -export function attachProgressBarStyler(widget: IThemable, themeService: IThemeService, style?: { progressBarBackground?: ColorIdentifier }): IDisposable { +export interface IProgressBarStyleOverrides extends IStyleOverrides { + progressBarBackground?: ColorIdentifier; +} + +export function attachProgressBarStyler(widget: IThemable, themeService: IThemeService, style?: IProgressBarStyleOverrides): IDisposable { return attachStyler(themeService, { progressBarBackground: (style && style.progressBarBackground) || progressBarBackground - }, widget); + } as IProgressBarStyleOverrides, widget); } export function attachStylerCallback(themeService: IThemeService, colors: { [name: string]: ColorIdentifier }, callback: styleFn): IDisposable { diff --git a/src/vs/platform/update/common/update.ts b/src/vs/platform/update/common/update.ts index 2c680aabced..13928e33f17 100644 --- a/src/vs/platform/update/common/update.ts +++ b/src/vs/platform/update/common/update.ts @@ -5,7 +5,7 @@ 'use strict'; -import Event from 'vs/base/common/event'; +import Event, { NodeEventEmitter } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -35,7 +35,7 @@ export interface IUpdate { url?: string; } -export interface IAutoUpdater extends NodeJS.EventEmitter { +export interface IAutoUpdater extends NodeEventEmitter { setFeedURL(url: string): void; checkForUpdates(): void; quitAndInstall(): void; diff --git a/src/vs/platform/update/common/updateIpc.ts b/src/vs/platform/update/common/updateIpc.ts index 0dd76ca51f6..bd42c38e018 100644 --- a/src/vs/platform/update/common/updateIpc.ts +++ b/src/vs/platform/update/common/updateIpc.ts @@ -63,7 +63,7 @@ export class UpdateChannelClient implements IUpdateService { get onStateChange(): Event { return this._onStateChange.event; } private _state: State = State.Uninitialized; - get state(): State { return this._state; }; + get state(): State { return this._state; } constructor(private channel: IUpdateChannel) { // always set this._state as the state changes diff --git a/src/vs/platform/update/electron-main/updateService.ts b/src/vs/platform/update/electron-main/updateService.ts index 8c387a90710..bb4b2da6262 100644 --- a/src/vs/platform/update/electron-main/updateService.ts +++ b/src/vs/platform/update/electron-main/updateService.ts @@ -9,10 +9,9 @@ import * as fs from 'original-fs'; import * as path from 'path'; import * as electron from 'electron'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import Event, { Emitter, once, filterEvent } from 'vs/base/common/event'; +import Event, { Emitter, once, filterEvent, fromNodeEventEmitter } from 'vs/base/common/event'; import { always, Throttler } from 'vs/base/common/async'; import { memoize } from 'vs/base/common/decorators'; -import { fromEventEmitter } from 'vs/base/node/event'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Win32AutoUpdaterImpl } from './auto-updater.win32'; import { LinuxAutoUpdaterImpl } from './auto-updater.linux'; @@ -22,6 +21,7 @@ import product from 'vs/platform/node/product'; import { TPromise } from 'vs/base/common/winjs.base'; import { IUpdateService, State, IAutoUpdater, IUpdate, IRawUpdate } from 'vs/platform/update/common/update'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; export class UpdateService implements IUpdateService { @@ -52,22 +52,22 @@ export class UpdateService implements IUpdateService { @memoize private get onRawError(): Event { - return fromEventEmitter(this.raw, 'error', (_, message) => message); + return fromNodeEventEmitter(this.raw, 'error', (_, message) => message); } @memoize private get onRawUpdateNotAvailable(): Event { - return fromEventEmitter(this.raw, 'update-not-available'); + return fromNodeEventEmitter(this.raw, 'update-not-available'); } @memoize private get onRawUpdateAvailable(): Event<{ url: string; version: string; }> { - return filterEvent(fromEventEmitter(this.raw, 'update-available', (_, url, version) => ({ url, version })), ({ url }) => !!url); + return filterEvent(fromNodeEventEmitter(this.raw, 'update-available', (_, url, version) => ({ url, version })), ({ url }) => !!url); } @memoize private get onRawUpdateDownloaded(): Event { - return fromEventEmitter(this.raw, 'update-downloaded', (_, releaseNotes, version, date, url) => ({ releaseNotes, version, date })); + return fromNodeEventEmitter(this.raw, 'update-downloaded', (_, releaseNotes, version, date, url) => ({ releaseNotes, version, date })); } get state(): State { @@ -87,7 +87,8 @@ export class UpdateService implements IUpdateService { @IRequestService requestService: IRequestService, @ILifecycleService private lifecycleService: ILifecycleService, @IConfigurationService private configurationService: IConfigurationService, - @ITelemetryService private telemetryService: ITelemetryService + @ITelemetryService private telemetryService: ITelemetryService, + @IEnvironmentService private environmentService: IEnvironmentService ) { if (process.platform === 'win32') { this.raw = new Win32AutoUpdaterImpl(requestService); @@ -99,6 +100,10 @@ export class UpdateService implements IUpdateService { return; } + if (this.environmentService.disableUpdates) { + return; + } + const channel = this.getUpdateChannel(); const feedUrl = this.getUpdateFeedUrl(channel); @@ -164,6 +169,11 @@ export class UpdateService implements IUpdateService { if (!update) { this._onUpdateNotAvailable.fire(explicit); this.state = State.Idle; + /* __GDPR__ + "update:notAvailable" : { + "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('update:notAvailable', { explicit }); } else if (update.url) { @@ -177,6 +187,13 @@ export class UpdateService implements IUpdateService { this._availableUpdate = data; this._onUpdateAvailable.fire({ url: update.url, version: update.version }); this.state = State.UpdateAvailable; + /* __GDPR__ + "update:available" : { + "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "version": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "currentVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('update:available', { explicit, version: update.version, currentVersion: product.commit }); } else { @@ -189,6 +206,11 @@ export class UpdateService implements IUpdateService { this._availableUpdate = data; this._onUpdateReady.fire(data); this.state = State.UpdateDownloaded; + /* __GDPR__ + "update:downloaded" : { + "version" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('update:downloaded', { version: update.version }); } diff --git a/src/vs/platform/url/electron-main/urlService.ts b/src/vs/platform/url/electron-main/urlService.ts index 01e4a8895a2..5469274fb20 100644 --- a/src/vs/platform/url/electron-main/urlService.ts +++ b/src/vs/platform/url/electron-main/urlService.ts @@ -5,8 +5,7 @@ 'use strict'; -import Event, { mapEvent, chain, echo, Emitter, any } from 'vs/base/common/event'; -import { fromEventEmitter } from 'vs/base/node/event'; +import Event, { mapEvent, chain, echo, Emitter, anyEvent, fromNodeEventEmitter } from 'vs/base/common/event'; import { IURLService } from 'vs/platform/url/common/url'; import product from 'vs/platform/node/product'; import { app } from 'electron'; @@ -28,7 +27,7 @@ export class URLService implements IURLService { app.setAsDefaultProtocolClient(product.urlProtocol, process.execPath, ['--open-url']); - const rawOnOpenUrl = fromEventEmitter(app, 'open-url', (event: Electron.Event, url: string) => ({ event, url })); + const rawOnOpenUrl = fromNodeEventEmitter(app, 'open-url', (event: Electron.Event, url: string) => ({ event, url })); // always prevent default and return the url as string const preventedOnOpenUrl = mapEvent(rawOnOpenUrl, ({ event, url }) => { @@ -39,7 +38,7 @@ export class URLService implements IURLService { // echo all `onOpenUrl` events to each listener const bufferedOnOpenUrl = echo(preventedOnOpenUrl, true, initialBuffer); - this.onOpenURL = chain(any(bufferedOnOpenUrl, this.openUrlEmitter.event)) + this.onOpenURL = chain(anyEvent(bufferedOnOpenUrl, this.openUrlEmitter.event)) .map(url => { try { return URI.parse(url); @@ -54,4 +53,4 @@ export class URLService implements IURLService { open(url: string): void { this.openUrlEmitter.fire(url); } -} \ No newline at end of file +} diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index f52cec56bb1..8b1a745eb63 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -11,8 +11,10 @@ import Event from 'vs/base/common/event'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; -import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IRecentlyOpened } from 'vs/platform/history/common/history'; +import { ICommandAction } from 'vs/platform/actions/common/actions'; +import { PerformanceEntry } from 'vs/base/common/performance'; export const IWindowsService = createDecorator('windowsService'); @@ -20,12 +22,74 @@ export interface INativeOpenDialogOptions { windowId?: number; forceNewWindow?: boolean; - dialogOptions?: Electron.OpenDialogOptions; + dialogOptions?: OpenDialogOptions; telemetryEventName?: string; telemetryExtraData?: ITelemetryData; } +export interface IEnterWorkspaceResult { + workspace: IWorkspaceIdentifier; + backupPath: string; +} + +export interface CrashReporterStartOptions { + companyName?: string; + submitURL: string; + productName?: string; + uploadToServer?: boolean; + ignoreSystemCrashHandler?: boolean; + extra?: any; + crashesDirectory?: string; +} + +export interface OpenDialogOptions { + title?: string; + defaultPath?: string; + buttonLabel?: string; + filters?: FileFilter[]; + properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'>; + message?: string; +} + +export interface FileFilter { + extensions: string[]; + name: string; +} + +export interface MessageBoxOptions { + type?: string; + buttons?: string[]; + defaultId?: number; + title?: string; + message: string; + detail?: string; + checkboxLabel?: string; + checkboxChecked?: boolean; + cancelId?: number; + noLink?: boolean; + normalizeAccessKeys?: boolean; +} + +export interface SaveDialogOptions { + title?: string; + defaultPath?: string; + buttonLabel?: string; + filters?: FileFilter[]; + message?: string; + nameFieldLabel?: string; + showsTagField?: boolean; +} + +export interface OpenDialogOptions { + title?: string; + defaultPath?: string; + buttonLabel?: string; + filters?: FileFilter[]; + properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'>; + message?: string; +} + export interface IWindowsService { _serviceBrand: any; @@ -37,13 +101,13 @@ export interface IWindowsService { pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise; pickFileAndOpen(options: INativeOpenDialogOptions): TPromise; pickFolderAndOpen(options: INativeOpenDialogOptions): TPromise; + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise; reloadWindow(windowId: number): TPromise; openDevTools(windowId: number): TPromise; toggleDevTools(windowId: number): TPromise; closeWorkspace(windowId: number): TPromise; - openWorkspace(windowId: number): TPromise; - createAndOpenWorkspace(windowId: number, folders?: string[], path?: string): TPromise; - saveAndOpenWorkspace(windowId: number, path: string): TPromise; + createAndEnterWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], path?: string): TPromise; + saveAndEnterWorkspace(windowId: number, path: string): TPromise; toggleFullScreen(windowId: number): TPromise; setRepresentedFilename(windowId: number, fileName: string): TPromise; addRecentlyOpened(files: string[]): TPromise; @@ -61,6 +125,16 @@ export interface IWindowsService { quit(): TPromise; relaunch(options: { addArgs?: string[], removeArgs?: string[] }): TPromise; + // macOS Native Tabs + showPreviousWindowTab(): TPromise; + showNextWindowTab(): TPromise; + moveWindowTabToNewWindow(): TPromise; + mergeAllWindowTabs(): TPromise; + toggleWindowTabsBar(): TPromise; + + // macOS TouchBar + updateTouchBar(windowId: number, items: ICommandAction[][]): TPromise; + // Shared process whenSharedProcessReady(): TPromise; toggleSharedProcess(): TPromise; @@ -79,11 +153,16 @@ export interface IWindowsService { openExternal(url: string): TPromise; // TODO: this is a bit backwards - startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise; + startCrashReporter(config: CrashReporterStartOptions): TPromise; } export const IWindowService = createDecorator('windowService'); +export interface IMessageBoxResult { + button: number; + checkboxChecked?: boolean; +} + export interface IWindowService { _serviceBrand: any; @@ -94,13 +173,14 @@ export interface IWindowService { pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise; pickFileAndOpen(options: INativeOpenDialogOptions): TPromise; pickFolderAndOpen(options: INativeOpenDialogOptions): TPromise; + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise; reloadWindow(): TPromise; openDevTools(): TPromise; toggleDevTools(): TPromise; closeWorkspace(): TPromise; - openWorkspace(): TPromise; - createAndOpenWorkspace(folders?: string[], path?: string): TPromise; - saveAndOpenWorkspace(path: string): TPromise; + updateTouchBar(items: ICommandAction[][]): TPromise; + createAndEnterWorkspace(folders?: IWorkspaceFolderCreationData[], path?: string): TPromise; + saveAndEnterWorkspace(path: string): TPromise; toggleFullScreen(): TPromise; setRepresentedFilename(fileName: string): TPromise; getRecentlyOpened(): TPromise; @@ -113,9 +193,10 @@ export interface IWindowService { unmaximizeWindow(): TPromise; onWindowTitleDoubleClick(): TPromise; show(): TPromise; - showMessageBox(options: Electron.ShowMessageBoxOptions): number; - showSaveDialog(options: Electron.SaveDialogOptions, callback?: (fileName: string) => void): string; - showOpenDialog(options: Electron.OpenDialogOptions, callback?: (fileNames: string[]) => void): string[]; + showMessageBoxSync(options: MessageBoxOptions): number; + showMessageBox(options: MessageBoxOptions): TPromise; + showSaveDialog(options: SaveDialogOptions, callback?: (fileName: string) => void): string; + showOpenDialog(options: OpenDialogOptions, callback?: (fileNames: string[]) => void): string[]; } export type MenuBarVisibility = 'default' | 'visible' | 'toggle' | 'hidden'; @@ -196,10 +277,16 @@ export interface IPath { columnNumber?: number; } +export interface IPathsToWaitFor { + paths: IPath[]; + waitMarkerFilePath: string; +} + export interface IOpenFileRequest { filesToOpen?: IPath[]; filesToCreate?: IPath[]; filesToDiff?: IPath[]; + filesToWait?: IPathsToWaitFor; } export interface IAddFoldersRequest { @@ -219,7 +306,6 @@ export interface IWindowConfiguration extends ParsedArgs, IOpenFileRequest { workspace?: IWorkspaceIdentifier; folderPath?: string; - isISOKeyboard?: boolean; zoomLevel?: number; fullscreen?: boolean; highContrast?: boolean; @@ -227,7 +313,13 @@ export interface IWindowConfiguration extends ParsedArgs, IOpenFileRequest { backgroundColor?: string; accessibilitySupport?: boolean; + perfEntries: PerformanceEntry[]; perfStartTime?: number; perfAppReady?: number; perfWindowLoadTime?: number; -} \ No newline at end of file +} + +export interface IRunActionInWindowRequest { + id: string; + from: 'menu' | 'touchbar' | 'mouse'; +} diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index 378ebd62e45..2000965fadf 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -8,9 +8,11 @@ import { TPromise } from 'vs/base/common/winjs.base'; import Event, { buffer } from 'vs/base/common/event'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IWindowsService, INativeOpenDialogOptions } from './windows'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, CrashReporterStartOptions } from 'vs/platform/windows/common/windows'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IRecentlyOpened } from 'vs/platform/history/common/history'; +import { ICommandAction } from 'vs/platform/actions/common/actions'; +import URI from 'vs/base/common/uri'; export interface IWindowsChannel extends IChannel { call(command: 'event:onWindowOpen'): TPromise; @@ -19,18 +21,24 @@ export interface IWindowsChannel extends IChannel { call(command: 'pickFileFolderAndOpen', arg: INativeOpenDialogOptions): TPromise; call(command: 'pickFileAndOpen', arg: INativeOpenDialogOptions): TPromise; call(command: 'pickFolderAndOpen', arg: INativeOpenDialogOptions): TPromise; + call(command: 'pickWorkspaceAndOpen', arg: INativeOpenDialogOptions): TPromise; call(command: 'reloadWindow', arg: number): TPromise; call(command: 'toggleDevTools', arg: number): TPromise; call(command: 'closeWorkspace', arg: number): TPromise; - call(command: 'openWorkspace', arg: number): TPromise; - call(command: 'createAndOpenWorkspace', arg: [number, string[], string]): TPromise; - call(command: 'saveAndOpenWorkspace', arg: [number, string]): TPromise; + call(command: 'createAndEnterWorkspace', arg: [number, IWorkspaceFolderCreationData[], string]): TPromise; + call(command: 'saveAndEnterWorkspace', arg: [number, string]): TPromise; call(command: 'toggleFullScreen', arg: number): TPromise; call(command: 'setRepresentedFilename', arg: [number, string]): TPromise; call(command: 'addRecentlyOpened', arg: string[]): TPromise; call(command: 'removeFromRecentlyOpened', arg: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)[]): TPromise; call(command: 'clearRecentlyOpened'): TPromise; call(command: 'getRecentlyOpened', arg: number): TPromise; + call(command: 'showPreviousWindowTab', arg: number): TPromise; + call(command: 'showNextWindowTab', arg: number): TPromise; + call(command: 'moveWindowTabToNewWindow', arg: number): TPromise; + call(command: 'mergeAllWindowTabs', arg: number): TPromise; + call(command: 'toggleWindowTabsBar', arg: number): TPromise; + call(command: 'updateTouchBar', arg: [number, ICommandAction[][]]): TPromise; call(command: 'focusWindow', arg: number): TPromise; call(command: 'closeWindow', arg: number): TPromise; call(command: 'isFocused', arg: number): TPromise; @@ -51,7 +59,7 @@ export interface IWindowsChannel extends IChannel { call(command: 'log', arg: [string, string[]]): TPromise; call(command: 'showItemInFolder', arg: string): TPromise; call(command: 'openExternal', arg: string): TPromise; - call(command: 'startCrashReporter', arg: Electron.CrashReporterStartOptions): TPromise; + call(command: 'startCrashReporter', arg: CrashReporterStartOptions): TPromise; call(command: string, arg?: any): TPromise; } @@ -75,18 +83,37 @@ export class WindowsChannel implements IWindowsChannel { case 'pickFileFolderAndOpen': return this.service.pickFileFolderAndOpen(arg); case 'pickFileAndOpen': return this.service.pickFileAndOpen(arg); case 'pickFolderAndOpen': return this.service.pickFolderAndOpen(arg); + case 'pickWorkspaceAndOpen': return this.service.pickWorkspaceAndOpen(arg); case 'reloadWindow': return this.service.reloadWindow(arg); case 'openDevTools': return this.service.openDevTools(arg); case 'toggleDevTools': return this.service.toggleDevTools(arg); case 'closeWorkspace': return this.service.closeWorkspace(arg); - case 'openWorkspace': return this.service.openWorkspace(arg); - case 'createAndOpenWorkspace': return this.service.createAndOpenWorkspace(arg[0], arg[1], arg[2]); - case 'saveAndOpenWorkspace': return this.service.saveAndOpenWorkspace(arg[0], arg[1]); + case 'createAndEnterWorkspace': { + const rawFolders: IWorkspaceFolderCreationData[] = arg[1]; + let folders: IWorkspaceFolderCreationData[]; + if (Array.isArray(rawFolders)) { + folders = rawFolders.map(rawFolder => { + return { + uri: URI.revive(rawFolder.uri), // convert raw URI back to real URI + name: rawFolder.name + } as IWorkspaceFolderCreationData; + }); + } + + return this.service.createAndEnterWorkspace(arg[0], folders, arg[2]); + } + case 'saveAndEnterWorkspace': return this.service.saveAndEnterWorkspace(arg[0], arg[1]); case 'toggleFullScreen': return this.service.toggleFullScreen(arg); case 'setRepresentedFilename': return this.service.setRepresentedFilename(arg[0], arg[1]); case 'addRecentlyOpened': return this.service.addRecentlyOpened(arg); case 'removeFromRecentlyOpened': return this.service.removeFromRecentlyOpened(arg); case 'clearRecentlyOpened': return this.service.clearRecentlyOpened(); + case 'showPreviousWindowTab': return this.service.showPreviousWindowTab(); + case 'showNextWindowTab': return this.service.showNextWindowTab(); + case 'moveWindowTabToNewWindow': return this.service.moveWindowTabToNewWindow(); + case 'mergeAllWindowTabs': return this.service.mergeAllWindowTabs(); + case 'toggleWindowTabsBar': return this.service.toggleWindowTabsBar(); + case 'updateTouchBar': return this.service.updateTouchBar(arg[0], arg[1]); case 'getRecentlyOpened': return this.service.getRecentlyOpened(arg); case 'focusWindow': return this.service.focusWindow(arg); case 'closeWindow': return this.service.closeWindow(arg); @@ -141,6 +168,10 @@ export class WindowsChannelClient implements IWindowsService { return this.channel.call('pickFolderAndOpen', options); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + return this.channel.call('pickWorkspaceAndOpen', options); + } + reloadWindow(windowId: number): TPromise { return this.channel.call('reloadWindow', windowId); } @@ -157,16 +188,12 @@ export class WindowsChannelClient implements IWindowsService { return this.channel.call('closeWorkspace', windowId); } - openWorkspace(windowId: number): TPromise { - return this.channel.call('openWorkspace', windowId); + createAndEnterWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { + return this.channel.call('createAndEnterWorkspace', [windowId, folders, path]); } - createAndOpenWorkspace(windowId: number, folders?: string[], path?: string): TPromise { - return this.channel.call('createAndOpenWorkspace', [windowId, folders, path]); - } - - saveAndOpenWorkspace(windowId: number, path: string): TPromise { - return this.channel.call('saveAndOpenWorkspace', [windowId, path]); + saveAndEnterWorkspace(windowId: number, path: string): TPromise { + return this.channel.call('saveAndEnterWorkspace', [windowId, path]); } toggleFullScreen(windowId: number): TPromise { @@ -193,6 +220,26 @@ export class WindowsChannelClient implements IWindowsService { return this.channel.call('getRecentlyOpened', windowId); } + showPreviousWindowTab(): TPromise { + return this.channel.call('showPreviousWindowTab'); + } + + showNextWindowTab(): TPromise { + return this.channel.call('showNextWindowTab'); + } + + moveWindowTabToNewWindow(): TPromise { + return this.channel.call('moveWindowTabToNewWindow'); + } + + mergeAllWindowTabs(): TPromise { + return this.channel.call('mergeAllWindowTabs'); + } + + toggleWindowTabsBar(): TPromise { + return this.channel.call('toggleWindowTabsBar'); + } + focusWindow(windowId: number): TPromise { return this.channel.call('focusWindow', windowId); } @@ -273,7 +320,11 @@ export class WindowsChannelClient implements IWindowsService { return this.channel.call('openExternal', url); } - startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise { + startCrashReporter(config: CrashReporterStartOptions): TPromise { return this.channel.call('startCrashReporter', config); } + + updateTouchBar(windowId: number, items: ICommandAction[][]): TPromise { + return this.channel.call('updateTouchBar', [windowId, items]); + } } diff --git a/src/vs/platform/windows/electron-browser/windowService.ts b/src/vs/platform/windows/electron-browser/windowService.ts index 0dbdaab92c6..32f28c1fde9 100644 --- a/src/vs/platform/windows/electron-browser/windowService.ts +++ b/src/vs/platform/windows/electron-browser/windowService.ts @@ -5,11 +5,15 @@ 'use strict'; -import Event, { filterEvent, mapEvent, any } from 'vs/base/common/event'; +import Event, { filterEvent, mapEvent, anyEvent } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IWindowService, IWindowsService, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows'; +import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult } from 'vs/platform/windows/common/windows'; import { remote } from 'electron'; import { IRecentlyOpened } from 'vs/platform/history/common/history'; +import { ICommandAction } from 'vs/platform/actions/common/actions'; +import { isMacintosh } from 'vs/base/common/platform'; +import { normalizeNFC } from 'vs/base/common/strings'; +import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; export class WindowService implements IWindowService { @@ -23,7 +27,7 @@ export class WindowService implements IWindowService { ) { const onThisWindowFocus = mapEvent(filterEvent(windowsService.onWindowFocus, id => id === windowId), _ => true); const onThisWindowBlur = mapEvent(filterEvent(windowsService.onWindowBlur, id => id === windowId), _ => false); - this.onDidChangeFocus = any(onThisWindowFocus, onThisWindowBlur); + this.onDidChangeFocus = anyEvent(onThisWindowFocus, onThisWindowBlur); } getCurrentWindowId(): number { @@ -48,6 +52,12 @@ export class WindowService implements IWindowService { return this.windowsService.pickFolderAndOpen(options); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + options.windowId = this.windowId; + + return this.windowsService.pickWorkspaceAndOpen(options); + } + reloadWindow(): TPromise { return this.windowsService.reloadWindow(this.windowId); } @@ -64,16 +74,12 @@ export class WindowService implements IWindowService { return this.windowsService.closeWorkspace(this.windowId); } - openWorkspace(): TPromise { - return this.windowsService.openWorkspace(this.windowId); + createAndEnterWorkspace(folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { + return this.windowsService.createAndEnterWorkspace(this.windowId, folders, path); } - createAndOpenWorkspace(folders?: string[], path?: string): TPromise { - return this.windowsService.createAndOpenWorkspace(this.windowId, folders, path); - } - - saveAndOpenWorkspace(path: string): TPromise { - return this.windowsService.saveAndOpenWorkspace(this.windowId, path); + saveAndEnterWorkspace(path: string): TPromise { + return this.windowsService.saveAndEnterWorkspace(this.windowId, path); } closeWindow(): TPromise { @@ -124,23 +130,53 @@ export class WindowService implements IWindowService { return this.windowsService.showWindow(this.windowId); } - showMessageBox(options: Electron.ShowMessageBoxOptions): number { + showMessageBoxSync(options: Electron.MessageBoxOptions): number { return remote.dialog.showMessageBox(remote.getCurrentWindow(), options); } + showMessageBox(options: Electron.MessageBoxOptions): TPromise { + return new TPromise((c, e) => { + return remote.dialog.showMessageBox(remote.getCurrentWindow(), options, (response: number, checkboxChecked: boolean) => { + c({ button: response, checkboxChecked }); + }); + }); + } + showSaveDialog(options: Electron.SaveDialogOptions, callback?: (fileName: string) => void): string { - if (callback) { - return remote.dialog.showSaveDialog(remote.getCurrentWindow(), options, callback); + + function normalizePath(path: string): string { + if (path && isMacintosh) { + path = normalizeNFC(path); // normalize paths returned from the OS + } + + return path; } - return remote.dialog.showSaveDialog(remote.getCurrentWindow(), options); // https://github.com/electron/electron/issues/4936 + if (callback) { + return remote.dialog.showSaveDialog(remote.getCurrentWindow(), options, path => callback(normalizePath(path))); + } + + return normalizePath(remote.dialog.showSaveDialog(remote.getCurrentWindow(), options)); // https://github.com/electron/electron/issues/4936 } showOpenDialog(options: Electron.OpenDialogOptions, callback?: (fileNames: string[]) => void): string[] { - if (callback) { - return remote.dialog.showOpenDialog(remote.getCurrentWindow(), options, callback); + + function normalizePaths(paths: string[]): string[] { + if (paths && paths.length > 0 && isMacintosh) { + paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS + } + + return paths; } - return remote.dialog.showOpenDialog(remote.getCurrentWindow(), options); // https://github.com/electron/electron/issues/4936 + if (callback) { + return remote.dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => callback(normalizePaths(paths))); + } + + return normalizePaths(remote.dialog.showOpenDialog(remote.getCurrentWindow(), options)); // https://github.com/electron/electron/issues/4936 + } + + updateTouchBar(items: ICommandAction[][]): TPromise { + return this.windowsService.updateTouchBar(this.windowId, items); } } diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 2e5d618c2a7..f6c8b4d712b 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -6,12 +6,13 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { OpenContext, IWindowConfiguration, ReadyState, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows'; +import { OpenContext, IWindowConfiguration, ReadyState, INativeOpenDialogOptions, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import Event from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment } from 'vs/base/common/platform'; -import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import { ICommandAction } from 'vs/platform/actions/common/actions'; export interface ICodeWindow { id: number; @@ -35,6 +36,8 @@ export interface ICodeWindow { setRepresentedFilename(name: string): void; getRepresentedFilename(): string; onWindowTitleDoubleClick(): void; + + updateTouchBar(items: ICommandAction[][]): void; } export const IWindowsMainService = createDecorator('windowsMainService'); @@ -57,18 +60,18 @@ export interface IWindowsMainService { // methods ready(initialUserEnv: IProcessEnvironment): void; reload(win: ICodeWindow, cli?: ParsedArgs): void; - openWorkspace(win?: ICodeWindow): void; - createAndOpenWorkspace(win: ICodeWindow, folders?: string[], path?: string): void; - saveAndOpenWorkspace(win: ICodeWindow, path: string): void; + createAndEnterWorkspace(win: ICodeWindow, folders?: IWorkspaceFolderCreationData[], path?: string): TPromise; + saveAndEnterWorkspace(win: ICodeWindow, path: string): TPromise; closeWorkspace(win: ICodeWindow): void; open(openConfig: IOpenConfiguration): ICodeWindow[]; openExtensionDevelopmentHostWindow(openConfig: IOpenConfiguration): void; pickFileFolderAndOpen(options: INativeOpenDialogOptions): void; pickFolderAndOpen(options: INativeOpenDialogOptions): void; pickFileAndOpen(options: INativeOpenDialogOptions): void; + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): void; focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow; getLastActiveWindow(): ICodeWindow; - waitForWindowClose(windowId: number): TPromise; + waitForWindowCloseOrLoad(windowId: number): TPromise; openNewWindow(context: OpenContext): void; sendToFocused(channel: string, ...args: any[]): void; sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void; diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 0a14db499fa..56fe2279713 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -9,16 +9,16 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; -import { IWindowsService, OpenContext, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows'; +import { IWindowsService, OpenContext, INativeOpenDialogOptions, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { shell, crashReporter, app } from 'electron'; -import Event, { chain } from 'vs/base/common/event'; -import { fromEventEmitter } from 'vs/base/node/event'; +import { shell, crashReporter, app, Menu } from 'electron'; +import Event, { chain, fromNodeEventEmitter } from 'vs/base/common/event'; import { IURLService } from 'vs/platform/url/common/url'; import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { IWindowsMainService, ISharedProcess } from 'vs/platform/windows/electron-main/windows'; import { IHistoryMainService, IRecentlyOpened } from 'vs/platform/history/common/history'; -import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import { ICommandAction } from 'vs/platform/actions/common/actions'; export class WindowsService implements IWindowsService, IDisposable { @@ -26,9 +26,9 @@ export class WindowsService implements IWindowsService, IDisposable { private disposables: IDisposable[] = []; - readonly onWindowOpen: Event = fromEventEmitter(app, 'browser-window-created', (_, w: Electron.BrowserWindow) => w.id); - readonly onWindowFocus: Event = fromEventEmitter(app, 'browser-window-focus', (_, w: Electron.BrowserWindow) => w.id); - readonly onWindowBlur: Event = fromEventEmitter(app, 'browser-window-blur', (_, w: Electron.BrowserWindow) => w.id); + readonly onWindowOpen: Event = fromNodeEventEmitter(app, 'browser-window-created', (_, w: Electron.BrowserWindow) => w.id); + readonly onWindowFocus: Event = fromNodeEventEmitter(app, 'browser-window-focus', (_, w: Electron.BrowserWindow) => w.id); + readonly onWindowBlur: Event = fromNodeEventEmitter(app, 'browser-window-blur', (_, w: Electron.BrowserWindow) => w.id); constructor( private sharedProcess: ISharedProcess, @@ -69,6 +69,12 @@ export class WindowsService implements IWindowsService, IDisposable { return TPromise.as(null); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + this.windowsMainService.pickWorkspaceAndOpen(options); + + return TPromise.as(null); + } + reloadWindow(windowId: number): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); @@ -104,6 +110,16 @@ export class WindowsService implements IWindowsService, IDisposable { return TPromise.as(null); } + updateTouchBar(windowId: number, items: ICommandAction[][]): TPromise { + const codeWindow = this.windowsMainService.getWindowById(windowId); + + if (codeWindow) { + codeWindow.updateTouchBar(items); + } + + return TPromise.as(null); + } + closeWorkspace(windowId: number): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); @@ -114,31 +130,21 @@ export class WindowsService implements IWindowsService, IDisposable { return TPromise.as(null); } - openWorkspace(windowId: number): TPromise { + createAndEnterWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); if (codeWindow) { - this.windowsMainService.openWorkspace(codeWindow); + return this.windowsMainService.createAndEnterWorkspace(codeWindow, folders, path); } return TPromise.as(null); } - createAndOpenWorkspace(windowId: number, folders?: string[], path?: string): TPromise { + saveAndEnterWorkspace(windowId: number, path: string): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); if (codeWindow) { - this.windowsMainService.createAndOpenWorkspace(codeWindow, folders, path); - } - - return TPromise.as(null); - } - - saveAndOpenWorkspace(windowId: number, path: string): TPromise { - const codeWindow = this.windowsMainService.getWindowById(windowId); - - if (codeWindow) { - this.windowsMainService.saveAndOpenWorkspace(codeWindow, path); + return this.windowsMainService.saveAndEnterWorkspace(codeWindow, path); } return TPromise.as(null); @@ -192,6 +198,36 @@ export class WindowsService implements IWindowsService, IDisposable { return TPromise.as(this.historyService.getRecentlyOpened()); } + showPreviousWindowTab(): TPromise { + Menu.sendActionToFirstResponder('selectPreviousTab:'); + + return TPromise.as(void 0); + } + + showNextWindowTab(): TPromise { + Menu.sendActionToFirstResponder('selectNextTab:'); + + return TPromise.as(void 0); + } + + moveWindowTabToNewWindow(): TPromise { + Menu.sendActionToFirstResponder('moveTabToNewWindow:'); + + return TPromise.as(void 0); + } + + mergeAllWindowTabs(): TPromise { + Menu.sendActionToFirstResponder('mergeAllWindows:'); + + return TPromise.as(void 0); + } + + toggleWindowTabsBar(): TPromise { + Menu.sendActionToFirstResponder('toggleTabBar:'); + + return TPromise.as(void 0); + } + focusWindow(windowId: number): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 4eeb0b8fb83..af594644bae 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -5,44 +5,36 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import * as paths from 'vs/base/common/paths'; -import { TrieMap } from 'vs/base/common/map'; +import * as resources from 'vs/base/common/resources'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { TernarySearchTree } from 'vs/base/common/map'; import Event from 'vs/base/common/event'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { coalesce, distinct } from 'vs/base/common/arrays'; import { isLinux } from 'vs/base/common/platform'; -import { distinct } from 'vs/base/common/arrays'; export const IWorkspaceContextService = createDecorator('contextService'); +export enum WorkbenchState { + EMPTY = 1, + FOLDER, + WORKSPACE +} + +export interface IWorkspaceFoldersChangeEvent { + added: IWorkspaceFolder[]; + removed: IWorkspaceFolder[]; + changed: IWorkspaceFolder[]; +} + export interface IWorkspaceContextService { _serviceBrand: any; /** - * Returns if the application was opened with a workspace or not. + * An event which fires on workbench state changes. */ - hasWorkspace(): boolean; - - /** - * Returns if the application was opened with a folder. - */ - hasFolderWorkspace(): boolean; - - /** - * Returns if the application was opened with a workspace that can have one or more folders. - */ - hasMultiFolderWorkspace(): boolean; - - /** - * Provides access to the workspace object the platform is running with. This may be null if the workbench was opened - * without workspace (empty); - */ - getLegacyWorkspace(): ILegacyWorkspace; - - /** - * Provides access to the workspace object the platform is running with. This may be null if the workbench was opened - * without workspace (empty); - */ - getWorkspace(): IWorkspace; + onDidChangeWorkbenchState: Event; /** * An event which fires on workspace name changes. @@ -50,39 +42,39 @@ export interface IWorkspaceContextService { onDidChangeWorkspaceName: Event; /** - * An event which fires on workspace roots change. + * An event which fires on workspace folders change. */ - onDidChangeWorkspaceRoots: Event; + onDidChangeWorkspaceFolders: Event; /** - * Returns the root for the given resource from the workspace. + * Provides access to the workspace object the platform is running with. + */ + getWorkspace(): IWorkspace; + + /** + * Return the state of the workbench. + * + * WorkbenchState.EMPTY - if the workbench was opened with empty window or file + * WorkbenchState.FOLDER - if the workbench was opened with a folder + * WorkbenchState.WORKSPACE - if the workbench was opened with a workspace + */ + getWorkbenchState(): WorkbenchState; + + /** + * Returns the folder for the given resource from the workspace. * Can be null if there is no workspace or the resource is not inside the workspace. */ - getRoot(resource: URI): URI; + getWorkspaceFolder(resource: URI): IWorkspaceFolder; + + /** + * Return `true` if the current workspace has the given identifier otherwise `false`. + */ + isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean; /** * Returns if the provided resource is inside the workspace or not. */ isInsideWorkspace(resource: URI): boolean; - - /** - * Given a workspace relative path, returns the resource with the absolute path. - */ - toResource: (workspaceRelativePath: string) => URI; -} - -export interface ILegacyWorkspace { - - /** - * the full uri of the workspace. this is a file:// URL to the location - * of the workspace on disk. - */ - resource: URI; - - /** - * creation time of the workspace folder if known - */ - ctime?: number; } export interface IWorkspace { @@ -98,9 +90,9 @@ export interface IWorkspace { readonly name: string; /** - * Roots in the workspace. + * Folders in the workspace. */ - readonly roots: URI[]; + readonly folders: IWorkspaceFolder[]; /** * the location of the workspace configuration @@ -108,59 +100,70 @@ export interface IWorkspace { readonly configuration?: URI; } -export class LegacyWorkspace implements ILegacyWorkspace { - private _name: string; +export interface IWorkspaceFolderData { + /** + * The associated URI for this workspace folder. + */ + readonly uri: URI; - constructor(private _resource: URI, private _ctime?: number) { - this._name = paths.basename(this._resource.fsPath) || this._resource.fsPath; - } + /** + * The name of this workspace folder. Defaults to + * the basename its [uri-path](#Uri.path) + */ + readonly name: string; - public get resource(): URI { - return this._resource; - } + /** + * The ordinal number of this workspace folder. + */ + readonly index: number; +} - public get name(): string { - return this._name; - } +export interface IWorkspaceFolder extends IWorkspaceFolderData { - public get ctime(): number { - return this._ctime; - } - - public toResource(workspaceRelativePath: string, root?: URI): URI { - if (typeof workspaceRelativePath === 'string') { - return URI.file(paths.join(root ? root.fsPath : this._resource.fsPath, workspaceRelativePath)); - } - - return null; - } + /** + * Given workspace folder relative path, returns the resource with the absolute path. + */ + toResource: (relativePath: string) => URI; } export class Workspace implements IWorkspace { - private _rootsMap: TrieMap = new TrieMap(); - private _roots: URI[]; + private _foldersMap: TernarySearchTree = TernarySearchTree.forPaths(); + private _folders: WorkspaceFolder[]; constructor( - public readonly id: string, - private _name: string, - roots: URI[], - private _configuration: URI = null + private _id: string, + private _name: string = '', + folders: WorkspaceFolder[] = [], + private _configuration: URI = null, + private _ctime?: number ) { - this.roots = roots; + this.folders = folders; } - private ensureUnique(roots: URI[]): URI[] { - return distinct(roots, root => isLinux ? root.fsPath : root.fsPath.toLowerCase()); + public update(workspace: Workspace) { + this._id = workspace.id; + this._name = workspace.name; + this._configuration = workspace.configuration; + this._ctime = workspace.ctime; + this.folders = workspace.folders; } - public get roots(): URI[] { - return this._roots; + public get folders(): WorkspaceFolder[] { + return this._folders; } - public set roots(roots: URI[]) { - this._roots = this.ensureUnique(roots); - this.updateRootsMap(); + public set folders(folders: WorkspaceFolder[]) { + this._folders = folders; + this.updateFoldersMap(); + } + + public get id(): string { + return this._id; + } + + public get ctime(): number { + return this._ctime; } public get name(): string { @@ -179,22 +182,86 @@ export class Workspace implements IWorkspace { this._configuration = configuration; } - public getRoot(resource: URI): URI { + public getFolder(resource: URI): IWorkspaceFolder { if (!resource) { return null; } - return this._rootsMap.findSubstr(resource.fsPath); + return this._foldersMap.findSubstr(resource.toString()); } - private updateRootsMap(): void { - this._rootsMap = new TrieMap(); - for (const root of this.roots) { - this._rootsMap.insert(root.fsPath, root); + private updateFoldersMap(): void { + this._foldersMap = TernarySearchTree.forPaths(); + for (const folder of this.folders) { + this._foldersMap.set(folder.uri.toString(), folder); } } public toJSON(): IWorkspace { - return { id: this.id, roots: this.roots, name: this.name }; + return { id: this.id, folders: this.folders, name: this.name }; } } + +export class WorkspaceFolder implements IWorkspaceFolder { + + readonly uri: URI; + readonly name: string; + readonly index: number; + + constructor(data: IWorkspaceFolderData, + readonly raw?: IStoredWorkspaceFolder) { + this.uri = data.uri; + this.index = data.index; + this.name = data.name; + } + + toResource(relativePath: string): URI { + return this.uri.with({ path: paths.join(this.uri.path, relativePath) }); + } + + toJSON(): IWorkspaceFolderData { + return { uri: this.uri, name: this.name, index: this.index }; + } +} + +export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): WorkspaceFolder[] { + let workspaceFolders = parseWorkspaceFolders(configuredFolders, relativeTo); + return ensureUnique(coalesce(workspaceFolders)) + .map(({ uri, raw, name }, index) => new WorkspaceFolder({ uri, name: name || resources.basenameOrAuthority(uri), index }, raw)); +} + +function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] { + return configuredFolders.map((configuredFolder, index) => { + let uri: URI; + if (isRawFileWorkspaceFolder(configuredFolder)) { + uri = toUri(configuredFolder.path, relativeTo); + } else if (isRawUriWorkspaceFolder(configuredFolder)) { + try { + uri = URI.parse(configuredFolder.uri); + } catch (e) { + console.warn(e); + // ignore + } + } + if (!uri) { + return void 0; + } + return new WorkspaceFolder({ uri, name: configuredFolder.name, index }, configuredFolder); + }); +} + +function toUri(path: string, relativeTo: URI): URI { + if (path) { + if (paths.isAbsolute(path)) { + return URI.file(path); + } + if (relativeTo) { + return relativeTo.with({ path: paths.join(relativeTo.path, path) }); + } + } + return null; +} + +function ensureUnique(folders: WorkspaceFolder[]): WorkspaceFolder[] { + return distinct(folders, folder => isLinux ? folder.uri.toString() : folder.uri.toString().toLowerCase()); +} diff --git a/src/vs/platform/workspace/test/common/testWorkspace.ts b/src/vs/platform/workspace/test/common/testWorkspace.ts index 97c90a65d03..6a204873e0c 100644 --- a/src/vs/platform/workspace/test/common/testWorkspace.ts +++ b/src/vs/platform/workspace/test/common/testWorkspace.ts @@ -4,15 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import URI from 'vs/base/common/uri'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; +import { isWindows } from 'vs/base/common/platform'; -const wsUri = URI.file('C:\\testWorkspace'); +const wsUri = URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace'); export const TestWorkspace = testWorkspace(wsUri); export function testWorkspace(resource: URI): Workspace { return new Workspace( resource.toString(), resource.fsPath, - [resource] + toWorkspaceFolders([{ path: resource.fsPath }]) ); } \ No newline at end of file diff --git a/src/vs/platform/workspace/test/common/workspace.test.ts b/src/vs/platform/workspace/test/common/workspace.test.ts index 1f296428317..ac6f0caf17f 100644 --- a/src/vs/platform/workspace/test/common/workspace.test.ts +++ b/src/vs/platform/workspace/test/common/workspace.test.ts @@ -6,17 +6,190 @@ 'use strict'; import * as assert from 'assert'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { Workspace, toWorkspaceFolders, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; +import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; suite('Workspace', () => { - test('Workspace ensures unique roots', () => { + test('getFolder returns the folder with given uri', () => { + const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 }); + let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), expected, new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]); - // Unique - let roots = [URI.file('/some/path'), URI.file('/some/path')]; - let ws = new Workspace('id', 'name', roots, URI.file('/config')); + const actual = testObject.getFolder(expected.uri); - assert.equal(ws.roots.length, 1); + assert.equal(actual, expected); }); -}); \ No newline at end of file + + test('getFolder returns the folder if the uri is sub', () => { + const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 }); + let testObject = new Workspace('', '', [expected, new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 1 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]); + + const actual = testObject.getFolder(URI.file('/src/test/a')); + + assert.equal(actual, expected); + }); + + test('getFolder returns the closest folder if the uri is sub', () => { + const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 }); + let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 }), expected]); + + const actual = testObject.getFolder(URI.file('/src/test/a')); + + assert.equal(actual, expected); + }); + + test('getFolder returns null if the uri is not sub', () => { + let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 })]); + + const actual = testObject.getFolder(URI.file('/src/main/a')); + + assert.equal(actual, undefined); + }); + + test('toWorkspaceFolders with single absolute folder', () => { + const actual = toWorkspaceFolders([{ path: '/src/test' }]); + + assert.equal(actual.length, 1); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); + assert.equal((actual[0].raw).path, '/src/test'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test'); + }); + + test('toWorkspaceFolders with single relative folder', () => { + const actual = toWorkspaceFolders([{ path: './test' }], URI.file('src')); + + assert.equal(actual.length, 1); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); + assert.equal((actual[0].raw).path, './test'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test'); + }); + + test('toWorkspaceFolders with single absolute folder with name', () => { + const actual = toWorkspaceFolders([{ path: '/src/test', name: 'hello' }]); + + assert.equal(actual.length, 1); + + assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); + assert.equal((actual[0].raw).path, '/src/test'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'hello'); + }); + + test('toWorkspaceFolders with multiple unique absolute folders', () => { + const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3' }, { path: '/src/test1' }]); + + assert.equal(actual.length, 3); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); + assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test2'); + + assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); + assert.equal((actual[1].raw).path, '/src/test3'); + assert.equal(actual[1].index, 1); + assert.equal(actual[1].name, 'test3'); + + assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); + assert.equal((actual[2].raw).path, '/src/test1'); + assert.equal(actual[2].index, 2); + assert.equal(actual[2].name, 'test1'); + }); + + test('toWorkspaceFolders with multiple unique absolute folders with names', () => { + const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: '/src/test1' }]); + + assert.equal(actual.length, 3); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); + assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test2'); + + assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); + assert.equal((actual[1].raw).path, '/src/test3'); + assert.equal(actual[1].index, 1); + assert.equal(actual[1].name, 'noName'); + + assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); + assert.equal((actual[2].raw).path, '/src/test1'); + assert.equal(actual[2].index, 2); + assert.equal(actual[2].name, 'test1'); + }); + + test('toWorkspaceFolders with multiple unique absolute and relative folders', () => { + const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/abc/test3', name: 'noName' }, { path: './test1' }], URI.file('src')); + + assert.equal(actual.length, 3); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); + assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test2'); + + assert.equal(actual[1].uri.fsPath, URI.file('/abc/test3').fsPath); + assert.equal((actual[1].raw).path, '/abc/test3'); + assert.equal(actual[1].index, 1); + assert.equal(actual[1].name, 'noName'); + + assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); + assert.equal((actual[2].raw).path, './test1'); + assert.equal(actual[2].index, 2); + assert.equal(actual[2].name, 'test1'); + }); + + test('toWorkspaceFolders with multiple absolute folders with duplicates', () => { + const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test2', name: 'noName' }, { path: '/src/test1' }]); + + assert.equal(actual.length, 2); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); + assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test2'); + + assert.equal(actual[1].uri.fsPath, URI.file('/src/test1').fsPath); + assert.equal((actual[1].raw).path, '/src/test1'); + assert.equal(actual[1].index, 1); + assert.equal(actual[1].name, 'test1'); + }); + + test('toWorkspaceFolders with multiple absolute and relative folders with duplicates', () => { + const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], URI.file('src')); + + assert.equal(actual.length, 3); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); + assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test2'); + + assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); + assert.equal((actual[1].raw).path, '/src/test3'); + assert.equal(actual[1].index, 1); + assert.equal(actual[1].name, 'noName'); + + assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); + assert.equal((actual[2].raw).path, '/abc/test1'); + assert.equal(actual[2].index, 2); + assert.equal(actual[2].name, 'test1'); + }); + + test('toWorkspaceFolders with multiple absolute and relative folders with invalid paths', () => { + const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], URI.file('src')); + + assert.equal(actual.length, 3); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); + assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].index, 0); + assert.equal(actual[0].name, 'test2'); + + assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); + assert.equal((actual[1].raw).path, './test3'); + assert.equal(actual[1].index, 1); + assert.equal(actual[1].name, 'test3'); + + assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); + assert.equal((actual[2].raw).path, '/abc/test1'); + assert.equal(actual[2].index, 2); + assert.equal(actual[2].name, 'test1'); + }); +}); diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 1702cd61757..8e4e14b1fb9 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -14,6 +14,8 @@ import { isLinux } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import Event from 'vs/base/common/event'; import { tildify, getPathLabel } from 'vs/base/common/labels'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import URI from 'vs/base/common/uri'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); export const IWorkspacesService = createDecorator('workspacesService'); @@ -32,21 +34,54 @@ export interface IWorkspaceIdentifier { configPath: string; } -export interface IStoredWorkspaceFolder { +export function isStoredWorkspaceFolder(thing: any): thing is IStoredWorkspaceFolder { + return isRawFileWorkspaceFolder(thing) || isRawUriWorkspaceFolder(thing); +} + +export function isRawFileWorkspaceFolder(thing: any): thing is IRawFileWorkspaceFolder { + return thing + && typeof thing === 'object' + && typeof thing.path === 'string' + && (!thing.name || typeof thing.name === 'string'); +} + +export function isRawUriWorkspaceFolder(thing: any): thing is IRawUriWorkspaceFolder { + return thing + && typeof thing === 'object' + && typeof thing.uri === 'string' + && (!thing.name || typeof thing.name === 'string'); +} + +export interface IRawFileWorkspaceFolder { path: string; + name?: string; +} + +export interface IRawUriWorkspaceFolder { + uri: string; + name?: string; +} + +export type IStoredWorkspaceFolder = IRawFileWorkspaceFolder | IRawUriWorkspaceFolder; + +export interface IResolvedWorkspace extends IWorkspaceIdentifier { + folders: IWorkspaceFolder[]; } export interface IStoredWorkspace { folders: IStoredWorkspaceFolder[]; } -export interface IResolvedWorkspace extends IWorkspaceIdentifier, IStoredWorkspace { } - export interface IWorkspaceSavedEvent { workspace: IWorkspaceIdentifier; oldConfigPath: string; } +export interface IWorkspaceFolderCreationData { + uri: URI; + name?: string; +} + export interface IWorkspacesMainService extends IWorkspacesService { _serviceBrand: any; @@ -54,7 +89,8 @@ export interface IWorkspacesMainService extends IWorkspacesService { onUntitledWorkspaceDeleted: Event; saveWorkspace(workspace: IWorkspaceIdentifier, target: string): TPromise; - createWorkspaceSync(folders?: string[]): IWorkspaceIdentifier; + + createWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier; resolveWorkspace(path: string): TPromise; resolveWorkspaceSync(path: string): IResolvedWorkspace; @@ -71,7 +107,7 @@ export interface IWorkspacesMainService extends IWorkspacesService { export interface IWorkspacesService { _serviceBrand: any; - createWorkspace(folders?: string[]): TPromise; + createWorkspace(folders?: IWorkspaceFolderCreationData[]): TPromise; } export function getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier), environmentService: IEnvironmentService, options?: { verbose: boolean }): string { @@ -104,4 +140,4 @@ export function isWorkspaceIdentifier(obj: any): obj is IWorkspaceIdentifier { const workspaceIdentifier = obj as IWorkspaceIdentifier; return workspaceIdentifier && typeof workspaceIdentifier.id === 'string' && typeof workspaceIdentifier.configPath === 'string'; -} \ No newline at end of file +} diff --git a/src/vs/platform/workspaces/common/workspacesIpc.ts b/src/vs/platform/workspaces/common/workspacesIpc.ts index 45c495b242f..981405a1190 100644 --- a/src/vs/platform/workspaces/common/workspacesIpc.ts +++ b/src/vs/platform/workspaces/common/workspacesIpc.ts @@ -7,10 +7,11 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IWorkspacesService, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesService, IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import URI from 'vs/base/common/uri'; export interface IWorkspacesChannel extends IChannel { - call(command: 'createWorkspace', arg: [string[]]): TPromise; + call(command: 'createWorkspace', arg: [IWorkspaceFolderCreationData[]]): TPromise; call(command: string, arg?: any): TPromise; } @@ -18,9 +19,22 @@ export class WorkspacesChannel implements IWorkspacesChannel { constructor(private service: IWorkspacesService) { } - call(command: string, arg?: any): TPromise { + public call(command: string, arg?: any): TPromise { switch (command) { - case 'createWorkspace': return this.service.createWorkspace(arg); + case 'createWorkspace': { + const rawFolders: IWorkspaceFolderCreationData[] = arg; + let folders: IWorkspaceFolderCreationData[]; + if (Array.isArray(rawFolders)) { + folders = rawFolders.map(rawFolder => { + return { + uri: URI.revive(rawFolder.uri), // convert raw URI back to real URI + name: rawFolder.name + } as IWorkspaceFolderCreationData; + }); + } + + return this.service.createWorkspace(folders); + } } return void 0; @@ -33,7 +47,7 @@ export class WorkspacesChannelClient implements IWorkspacesService { constructor(private channel: IWorkspacesChannel) { } - createWorkspace(folders?: string[]): TPromise { + public createWorkspace(folders?: IWorkspaceFolderCreationData[]): TPromise { return this.channel.call('createWorkspace', folders); } } \ No newline at end of file diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 94760a95bf4..d6941cfdbb9 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -5,27 +5,29 @@ 'use strict'; -import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { TPromise } from 'vs/base/common/winjs.base'; import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { extname, join, dirname, isAbsolute, resolve, relative } from 'path'; +import { extname, join, dirname, isAbsolute, resolve } from 'path'; import { mkdirp, writeFile, readFile } from 'vs/base/node/pfs'; import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; -import { isLinux } from 'vs/base/common/platform'; +import { isLinux, isMacintosh } from 'vs/base/common/platform'; import { delSync, readdirSync } from 'vs/base/node/extfs'; import Event, { Emitter } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; -import { isEqual, isEqualOrParent } from 'vs/base/common/paths'; +import { isEqual } from 'vs/base/common/paths'; import { coalesce } from 'vs/base/common/arrays'; import { createHash } from 'crypto'; -import URI from 'vs/base/common/uri'; import * as json from 'vs/base/common/json'; +import * as jsonEdit from 'vs/base/common/jsonEdit'; +import { applyEdit } from 'vs/base/common/jsonFormatter'; +import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; +import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; +import URI from 'vs/base/common/uri'; -// TODO@Ben migration -export interface ILegacyStoredWorkspace { - id: string; - folders: string[]; +export interface IStoredWorkspace { + folders: IStoredWorkspaceFolder[]; } export class WorkspacesMainService implements IWorkspacesMainService { @@ -68,7 +70,14 @@ export class WorkspacesMainService implements IWorkspacesMainService { return null; // does not look like a valid workspace config file } - return this.doResolveWorkspace(path, readFileSync(path, 'utf8')); + let contents: string; + try { + contents = readFileSync(path, 'utf8'); + } catch (error) { + return null; // invalid workspace + } + + return this.doResolveWorkspace(path, contents); } private isWorkspacePath(path: string): boolean { @@ -79,17 +88,10 @@ export class WorkspacesMainService implements IWorkspacesMainService { try { const workspace = this.doParseStoredWorkspace(path, contents); - // relative paths get resolved against the workspace location - workspace.folders.forEach(folder => { - if (!isAbsolute(folder.path)) { - folder.path = resolve(dirname(path), folder.path); - } - }); - return { id: this.getWorkspaceId(path), configPath: path, - folders: workspace.folders + folders: toWorkspaceFolders(workspace.folders, URI.file(dirname(path))) }; } catch (error) { this.logService.log(error.toString()); @@ -108,20 +110,13 @@ export class WorkspacesMainService implements IWorkspacesMainService { throw new Error(`${path} cannot be parsed as JSON file (${error}).`); } - // TODO@Ben migration - const legacyStoredWorkspace = (storedWorkspace) as ILegacyStoredWorkspace; - if (legacyStoredWorkspace.folders.some(folder => typeof folder === 'string')) { - storedWorkspace.folders = legacyStoredWorkspace.folders.map(folder => ({ path: URI.parse(folder).fsPath })); - writeFileSync(path, JSON.stringify(storedWorkspace, null, '\t')); - } - - // Filter out folders which do not have a path set + // Filter out folders which do not have a path or uri set if (Array.isArray(storedWorkspace.folders)) { - storedWorkspace.folders = storedWorkspace.folders.filter(folder => !!folder.path); + storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder)); } // Validate - if (!Array.isArray(storedWorkspace.folders) || storedWorkspace.folders.length === 0) { + if (!Array.isArray(storedWorkspace.folders)) { throw new Error(`${path} looks like an invalid workspace file.`); } @@ -132,7 +127,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */); } - public createWorkspace(folders: string[]): TPromise { + public createWorkspace(folders?: IWorkspaceFolderCreationData[]): TPromise { const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(folders); return mkdirp(configParent).then(() => { @@ -140,7 +135,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { }); } - public createWorkspaceSync(folders: string[]): IWorkspaceIdentifier { + public createWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier { const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(folders); if (!existsSync(this.workspacesHome)) { @@ -154,15 +149,32 @@ export class WorkspacesMainService implements IWorkspacesMainService { return workspace; } - private createUntitledWorkspace(folders: string[]): { workspace: IWorkspaceIdentifier, configParent: string, storedWorkspace: IStoredWorkspace } { + private createUntitledWorkspace(folders: IWorkspaceFolderCreationData[] = []): { workspace: IWorkspaceIdentifier, configParent: string, storedWorkspace: IStoredWorkspace } { const randomId = (Date.now() + Math.round(Math.random() * 1000)).toString(); const untitledWorkspaceConfigFolder = join(this.workspacesHome, randomId); const untitledWorkspaceConfigPath = join(untitledWorkspaceConfigFolder, UNTITLED_WORKSPACE_NAME); const storedWorkspace: IStoredWorkspace = { - folders: folders.map(folder => ({ - path: folder - })) + folders: folders.map(folder => { + const folderResource = folder.uri; + let storedWorkspace: IStoredWorkspaceFolder; + + // File URI + if (folderResource.scheme === 'file') { + storedWorkspace = { path: massageFolderPathForWorkspace(folderResource.fsPath, untitledWorkspaceConfigFolder, []) }; + } + + // Any URI + else { + storedWorkspace = { uri: folderResource.toString(true) }; + } + + if (folder.name) { + storedWorkspace.name = folder.name; + } + + return storedWorkspace; + }) }; return { @@ -195,10 +207,11 @@ export class WorkspacesMainService implements IWorkspacesMainService { } // Read the contents of the workspace file and resolve it - return readFile(workspace.configPath).then(rawWorkspaceContents => { + return readFile(workspace.configPath).then(raw => { + const rawWorkspaceContents = raw.toString(); let storedWorkspace: IStoredWorkspace; try { - storedWorkspace = this.doParseStoredWorkspace(workspace.configPath, rawWorkspaceContents.toString()); + storedWorkspace = this.doParseStoredWorkspace(workspace.configPath, rawWorkspaceContents); } catch (error) { return TPromise.wrapError(error); } @@ -210,16 +223,24 @@ export class WorkspacesMainService implements IWorkspacesMainService { // is a parent of the location of the workspace file itself. Otherwise keep // using absolute paths. storedWorkspace.folders.forEach(folder => { - if (!isAbsolute(folder.path)) { - folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location + if (isRawFileWorkspaceFolder(folder)) { + if (!isAbsolute(folder.path)) { + folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location + } + folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders); } - if (isEqualOrParent(folder.path, targetConfigFolder, !isLinux)) { - folder.path = relative(targetConfigFolder, folder.path) || '.'; // absolute paths get converted to relative ones to workspace location if possible - } }); - return writeFile(targetConfigPath, JSON.stringify(storedWorkspace, null, '\t')).then(() => { + // Preserve as much of the existing workspace as possible by using jsonEdit + // and only changing the folders portion. + let newRawWorkspaceContents = rawWorkspaceContents; + const edits = jsonEdit.setProperty(rawWorkspaceContents, ['folders'], storedWorkspace.folders, { insertSpaces: false, tabSize: 4, eol: (isLinux || isMacintosh) ? '\n' : '\r\n' }); + edits.forEach(edit => { + newRawWorkspaceContents = applyEdit(rawWorkspaceContents, edit); + }); + + return writeFile(targetConfigPath, newRawWorkspaceContents).then(() => { const savedWorkspaceIdentifier = { id: this.getWorkspaceId(targetConfigPath), configPath: targetConfigPath }; // Event diff --git a/src/vs/platform/workspaces/node/workspaces.ts b/src/vs/platform/workspaces/node/workspaces.ts new file mode 100644 index 00000000000..8b149ff2693 --- /dev/null +++ b/src/vs/platform/workspaces/node/workspaces.ts @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IStoredWorkspaceFolder, isRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { isWindows, isLinux } from 'vs/base/common/platform'; +import { isAbsolute, relative } from 'path'; +import { isEqualOrParent, normalize } from 'vs/base/common/paths'; +import { normalizeDriveLetter } from 'vs/base/common/labels'; + +const SLASH = '/'; + +/** + * Given the absolute path to a folder, massage it in a way that it fits + * into an existing set of workspace folders of a workspace. + * + * @param absoluteFolderPath the absolute path of a workspace folder + * @param targetConfigFolder the folder where the workspace is living in + * @param existingFolders a set of existing folders of the workspace + */ +export function massageFolderPathForWorkspace(absoluteFolderPath: string, targetConfigFolder: string, existingFolders: IStoredWorkspaceFolder[]): string { + const useSlashesForPath = shouldUseSlashForPath(existingFolders); + + // Convert path to relative path if the target config folder + // is a parent of the path. + if (isEqualOrParent(absoluteFolderPath, targetConfigFolder, !isLinux)) { + absoluteFolderPath = relative(targetConfigFolder, absoluteFolderPath) || '.'; + } + + // Windows gets special treatment: + // - normalize all paths to get nice casing of drive letters + // - convert to slashes if we want to use slashes for paths + if (isWindows) { + if (isAbsolute(absoluteFolderPath)) { + if (useSlashesForPath) { + absoluteFolderPath = normalize(absoluteFolderPath, false /* do not use OS path separator */); + } + + absoluteFolderPath = normalizeDriveLetter(absoluteFolderPath); + } else if (useSlashesForPath) { + absoluteFolderPath = absoluteFolderPath.replace(/[\\]/g, SLASH); + } + } + + return absoluteFolderPath; +} + +function shouldUseSlashForPath(storedFolders: IStoredWorkspaceFolder[]): boolean { + + // Determine which path separator to use: + // - macOS/Linux: slash + // - Windows: use slash if already used in that file + let useSlashesForPath = !isWindows; + if (isWindows) { + storedFolders.forEach(folder => { + if (isRawFileWorkspaceFolder(folder) && !useSlashesForPath && folder.path.indexOf(SLASH) >= 0) { + useSlashesForPath = true; + } + }); + } + + return useSlashesForPath; +} diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index ec0683890ca..33f0f4e86c5 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -13,13 +13,14 @@ import extfs = require('vs/base/node/extfs'); import pfs = require('vs/base/node/pfs'); import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; -import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/electron-main/workspacesMainService'; +import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder, IWorkspaceFolderCreationData, IRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { LogMainService } from 'vs/platform/log/common/log'; import URI from 'vs/base/common/uri'; +import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; suite('WorkspacesMainService', () => { - const parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); + const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesservice'); const workspacesHome = path.join(parentDir, 'Workspaces'); class TestEnvironmentService extends EnvironmentService { @@ -38,6 +39,14 @@ suite('WorkspacesMainService', () => { } } + function createWorkspace(folders: string[], names?: string[]) { + return service.createWorkspace(folders.map((folder, index) => ({ uri: URI.file(folder), name: names ? names[index] : void 0 } as IWorkspaceFolderCreationData))); + } + + function createWorkspaceSync(folders: string[], names?: string[]) { + return service.createWorkspaceSync(folders.map((folder, index) => ({ uri: URI.file(folder), name: names ? names[index] : void 0 } as IWorkspaceFolderCreationData))); + } + const environmentService = new TestEnvironmentService(parseArgs(process.argv), process.execPath); const logService = new LogMainService(environmentService); @@ -59,34 +68,104 @@ suite('WorkspacesMainService', () => { }); test('createWorkspace (folders)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { assert.ok(workspace); assert.ok(fs.existsSync(workspace.configPath)); assert.ok(service.isUntitledWorkspace(workspace)); const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 2); // - assert.equal(ws.folders[0].path, process.cwd()); - assert.equal(ws.folders[1].path, os.tmpdir()); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); + + assert.ok(!(ws.folders[0]).name); + assert.ok(!(ws.folders[1]).name); done(); }); }); + test('createWorkspace (folders with name)', done => { + return createWorkspace([process.cwd(), os.tmpdir()], ['currentworkingdirectory', 'tempdir']).then(workspace => { + assert.ok(workspace); + assert.ok(fs.existsSync(workspace.configPath)); + assert.ok(service.isUntitledWorkspace(workspace)); + + const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; + assert.equal(ws.folders.length, 2); // + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); + + assert.equal((ws.folders[0]).name, 'currentworkingdirectory'); + assert.equal((ws.folders[1]).name, 'tempdir'); + + done(); + }); + }); + + test('createWorkspace (folders as other resource URIs)', () => { + return service.createWorkspace([{ uri: URI.from({ scheme: 'myScheme', path: process.cwd() }) }, { uri: URI.from({ scheme: 'myScheme', path: os.tmpdir() }) }]).then(workspace => { + assert.ok(workspace); + assert.ok(fs.existsSync(workspace.configPath)); + assert.ok(service.isUntitledWorkspace(workspace)); + + const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; + assert.equal(ws.folders.length, 2); + assert.equal((ws.folders[0]).uri, URI.from({ scheme: 'myScheme', path: process.cwd() }).toString(true)); + assert.equal((ws.folders[1]).uri, URI.from({ scheme: 'myScheme', path: os.tmpdir() }).toString(true)); + + assert.ok(!(ws.folders[0]).name); + assert.ok(!(ws.folders[1]).name); + }); + }); + test('createWorkspaceSync (folders)', () => { - const workspace = service.createWorkspaceSync([process.cwd(), os.tmpdir()]); + const workspace = createWorkspaceSync([process.cwd(), os.tmpdir()]); assert.ok(workspace); assert.ok(fs.existsSync(workspace.configPath)); assert.ok(service.isUntitledWorkspace(workspace)); const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; - assert.equal(ws.folders.length, 2); // - assert.equal(ws.folders[0].path, process.cwd()); - assert.equal(ws.folders[1].path, os.tmpdir()); + assert.equal(ws.folders.length, 2); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); + + assert.ok(!(ws.folders[0]).name); + assert.ok(!(ws.folders[1]).name); + }); + + test('createWorkspaceSync (folders with names)', () => { + const workspace = createWorkspaceSync([process.cwd(), os.tmpdir()], ['currentworkingdirectory', 'tempdir']); + assert.ok(workspace); + assert.ok(fs.existsSync(workspace.configPath)); + assert.ok(service.isUntitledWorkspace(workspace)); + + const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; + assert.equal(ws.folders.length, 2); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); + + assert.equal((ws.folders[0]).name, 'currentworkingdirectory'); + assert.equal((ws.folders[1]).name, 'tempdir'); + }); + + test('createWorkspaceSync (folders as other resource URIs)', () => { + const workspace = service.createWorkspaceSync([{ uri: URI.from({ scheme: 'myScheme', path: process.cwd() }) }, { uri: URI.from({ scheme: 'myScheme', path: os.tmpdir() }) }]); + assert.ok(workspace); + assert.ok(fs.existsSync(workspace.configPath)); + assert.ok(service.isUntitledWorkspace(workspace)); + + const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; + assert.equal(ws.folders.length, 2); + assert.equal((ws.folders[0]).uri, URI.from({ scheme: 'myScheme', path: process.cwd() }).toString(true)); + assert.equal((ws.folders[1]).uri, URI.from({ scheme: 'myScheme', path: os.tmpdir() }).toString(true)); + + assert.ok(!(ws.folders[0]).name); + assert.ok(!(ws.folders[1]).name); }); test('resolveWorkspaceSync', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { assert.ok(service.resolveWorkspaceSync(workspace.configPath)); // make it a valid workspace path @@ -108,7 +187,7 @@ suite('WorkspacesMainService', () => { }); test('resolveWorkspace', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { return service.resolveWorkspace(workspace.configPath).then(ws => { assert.ok(ws); @@ -134,44 +213,44 @@ suite('WorkspacesMainService', () => { }); test('resolveWorkspaceSync (support relative paths)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); }); test('resolveWorkspaceSync (support relative paths #2)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib/../other' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); done(); }); }); test('resolveWorkspaceSync (support relative paths #3)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: 'ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); }); test('resolveWorkspaceSync (support invalid JSON via fault tolerant parsing)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath, '{ "folders": [ { "path": "./ticino-playground/lib" } , ] }'); // trailing comma const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -188,7 +267,7 @@ suite('WorkspacesMainService', () => { deletedEvent = e; }); - return service.createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => { const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => { @@ -200,9 +279,9 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(savedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal(ws.folders[0].path, process.cwd()); // absolute - assert.equal(ws.folders[1].path, '.'); // relative - assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal((ws.folders[0]).path, process.cwd()); // absolute + assert.equal((ws.folders[1]).path, '.'); // relative + assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative assert.equal(savedWorkspace, savedEvent.workspace); assert.equal(workspace.configPath, savedEvent.oldConfigPath); @@ -220,7 +299,7 @@ suite('WorkspacesMainService', () => { }); test('saveWorkspace (saved workspace)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => { const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); const newWorkspaceConfigPath = path.join(os.tmpdir(), `mySavedWorkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); @@ -232,9 +311,61 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal(ws.folders[0].path, process.cwd()); // absolute path because outside of tmpdir - assert.equal(ws.folders[1].path, '.'); // relative path because inside of tmpdir - assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal((ws.folders[0]).path, process.cwd()); // absolute path because outside of tmpdir + assert.equal((ws.folders[1]).path, '.'); // relative path because inside of tmpdir + assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + + extfs.delSync(workspaceConfigPath); + extfs.delSync(newWorkspaceConfigPath); + + done(); + }); + }); + }); + }); + + test('saveWorkspace (saved workspace, preserves comments)', done => { + return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => { + const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); + const newWorkspaceConfigPath = path.join(os.tmpdir(), `mySavedWorkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); + + return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => { + const contents = fs.readFileSync(savedWorkspace.configPath).toString(); + fs.writeFileSync(savedWorkspace.configPath, `// this is a comment\n${contents}`); + + return service.saveWorkspace(savedWorkspace, newWorkspaceConfigPath).then(newSavedWorkspace => { + assert.ok(newSavedWorkspace.id); + assert.notEqual(newSavedWorkspace.id, workspace.id); + assert.equal(newSavedWorkspace.configPath, newWorkspaceConfigPath); + + const savedContents = fs.readFileSync(newSavedWorkspace.configPath).toString(); + assert.equal(0, savedContents.indexOf('// this is a comment')); + + extfs.delSync(workspaceConfigPath); + extfs.delSync(newWorkspaceConfigPath); + + done(); + }); + }); + }); + }); + + test('saveWorkspace (saved workspace, preserves forward slashes)', done => { + return createWorkspace([process.cwd(), os.tmpdir(), path.join(os.tmpdir(), 'somefolder')]).then(workspace => { + const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); + const newWorkspaceConfigPath = path.join(os.tmpdir(), `mySavedWorkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); + + return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => { + const contents = fs.readFileSync(savedWorkspace.configPath).toString(); + fs.writeFileSync(savedWorkspace.configPath, contents.replace(/[\\]/g, '/')); // convert backslash to slash + + return service.saveWorkspace(savedWorkspace, newWorkspaceConfigPath).then(newSavedWorkspace => { + assert.ok(newSavedWorkspace.id); + assert.notEqual(newSavedWorkspace.id, workspace.id); + assert.equal(newSavedWorkspace.configPath, newWorkspaceConfigPath); + + const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; + assert.ok(ws.folders.every(f => (f).path.indexOf('\\') < 0)); extfs.delSync(workspaceConfigPath); extfs.delSync(newWorkspaceConfigPath); @@ -246,7 +377,7 @@ suite('WorkspacesMainService', () => { }); test('deleteUntitledWorkspaceSync (untitled)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { assert.ok(fs.existsSync(workspace.configPath)); service.deleteUntitledWorkspaceSync(workspace); @@ -258,7 +389,7 @@ suite('WorkspacesMainService', () => { }); test('deleteUntitledWorkspaceSync (saved)', done => { - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { const workspaceConfigPath = path.join(os.tmpdir(), `myworkspace.${Date.now()}.${WORKSPACE_EXTENSION}`); return service.saveWorkspace(workspace, workspaceConfigPath).then(savedWorkspace => { @@ -277,20 +408,22 @@ suite('WorkspacesMainService', () => { let untitled = service.getUntitledWorkspacesSync(); assert.equal(0, untitled.length); - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(untitledOne => { + return createWorkspace([process.cwd(), os.tmpdir()]).then(untitledOne => { untitled = service.getUntitledWorkspacesSync(); assert.equal(1, untitled.length); assert.equal(untitledOne.id, untitled[0].id); - return service.createWorkspace([process.cwd(), os.tmpdir()]).then(untitledTwo => { + return createWorkspace([os.tmpdir(), process.cwd()]).then(untitledTwo => { untitled = service.getUntitledWorkspacesSync(); assert.equal(2, untitled.length); service.deleteUntitledWorkspaceSync(untitledOne); - service.deleteUntitledWorkspaceSync(untitledTwo); + untitled = service.getUntitledWorkspacesSync(); + assert.equal(1, untitled.length); + service.deleteUntitledWorkspaceSync(untitledTwo); untitled = service.getUntitledWorkspacesSync(); assert.equal(0, untitled.length); @@ -298,4 +431,4 @@ suite('WorkspacesMainService', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index fbc0c95bb80..4fb32941228 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -733,7 +733,8 @@ declare module 'vscode' { /** * An optional view column in which the [editor](#TextEditor) should be shown. * The default is the [one](#ViewColumn.One), other values are adjusted to - * be __Min(column, columnCount + 1)__. + * be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is + * not adjusted. */ viewColumn?: ViewColumn; @@ -773,7 +774,7 @@ declare module 'vscode' { export interface ThemableDecorationRenderOptions { /** * Background color of the decoration. Use rgba() and define transparent background colors to play well with other decorations. - * Alternativly a color from the color registry an be [referenced](#ColorIdentifier). + * Alternatively a color from the color registry can be [referenced](#ThemeColor). */ backgroundColor?: string | ThemeColor; @@ -1179,6 +1180,11 @@ declare module 'vscode' { */ static parse(value: string): Uri; + /** + * Use the `file` and `parse` factory functions to create new `Uri` objects. + */ + private constructor(scheme: string, authority: string, path: string, query: string, fragment: string); + /** * Scheme is the `http` part of `http://www.msft.com/some/path?query#fragment`. * The part before the first colon. @@ -1498,6 +1504,96 @@ declare module 'vscode' { onDidSelectItem?(item: QuickPickItem | string): any; } + /** + * Options to configure the behaviour of the [workspace folder](#WorkspaceFolder) pick UI. + */ + export interface WorkspaceFolderPickOptions { + + /** + * An optional string to show as place holder in the input box to guide the user what to pick on. + */ + placeHolder?: string; + + /** + * Set to `true` to keep the picker open when focus moves to another part of the editor or to another window. + */ + ignoreFocusOut?: boolean; + } + + /** + * Options to configure the behaviour of a file open dialog. + * + * * Note 1: A dialog can select files, folders, or both. This is not true for Windows + * which enforces to open either files or folder, but *not both*. + * * Note 2: Explictly setting `canSelectFiles` and `canSelectFolders` to `false` is futile + * and the editor then silently adjusts the options to select files. + */ + export interface OpenDialogOptions { + /** + * The resource the dialog shows when opened. + */ + defaultUri?: Uri; + + /** + * A human-readable string for the open button. + */ + openLabel?: string; + + /** + * Allow to select files, defaults to `true`. + */ + canSelectFiles?: boolean; + + /** + * Allow to select folders, defaults to `false`. + */ + canSelectFolders?: boolean; + + /** + * Allow to select many files or folders. + */ + canSelectMany?: boolean; + + /** + * A set of file filters that are used by the dialog. Each entry is a human readable label, + * like "TypeScript", and an array of extensions, e.g. + * ```ts + * { + * 'Images': ['png', 'jpg'] + * 'TypeScript': ['ts', 'tsx'] + * } + * ``` + */ + filters?: { [name: string]: string[] }; + } + + /** + * Options to configure the behaviour of a file save dialog. + */ + export interface SaveDialogOptions { + /** + * The resource the dialog shows when opened. + */ + defaultUri?: Uri; + + /** + * A human-readable string for the save button. + */ + saveLabel?: string; + + /** + * A set of file filters that are used by the dialog. Each entry is a human readable label, + * like "TypeScript", and an array of extensions, e.g. + * ```ts + * { + * 'Images': ['png', 'jpg'] + * 'TypeScript': ['ts', 'tsx'] + * } + * ``` + */ + filters?: { [name: string]: string[] }; + } + /** * Represents an action that is shown with an information, warning, or * error message. @@ -1581,9 +1677,55 @@ declare module 'vscode' { * @return A human readable string which is presented as diagnostic message. * Return `undefined`, `null`, or the empty string when 'value' is valid. */ - validateInput?(value: string): string | undefined | null; + validateInput?(value: string): string | undefined | null | Thenable; } + /** + * A relative pattern is a helper to construct glob patterns that are matched + * relatively to a base path. The base path can either be an absolute file path + * or a [workspace folder](#WorkspaceFolder). + */ + export class RelativePattern { + + /** + * A base file path to which this pattern will be matched against relatively. + */ + base: string; + + /** + * A file glob pattern like `*.{ts,js}` that will be matched on file paths + * relative to the base path. + * + * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`, + * the file glob pattern will match on `index.js`. + */ + pattern: string; + + /** + * Creates a new relative pattern object with a base path and pattern to match. This pattern + * will be matched on file paths relative to the base path. + * + * @param base A base file path to which this pattern will be matched against relatively. + * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on file paths + * relative to the base path. + */ + constructor(base: WorkspaceFolder | string, pattern: string) + } + + /** + * A file glob pattern to match file paths against. This can either be a glob pattern string + * (like `**āˆ•*.{ts,js}` or `*.{ts,js}`) or a [relative pattern](#RelativePattern). + * + * Glob patterns can have the following syntax: + * * `*` to match one or more characters in a path segment + * * `?` to match on one character in a path segment + * * `**` to match any number of path segments, including none + * * `{}` to group conditions (e.g. `**āˆ•*.{ts,js}` matches all TypeScript and JavaScript files) + * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + */ + export type GlobPattern = string | RelativePattern; + /** * A document filter denotes a document by different properties like * the [language](#TextDocument.languageId), the [scheme](#Uri.scheme) of @@ -1605,9 +1747,10 @@ declare module 'vscode' { scheme?: string; /** - * A glob pattern, like `*.{ts,js}`. + * A [glob pattern](#GlobPattern) that is matched on the absolute path of the document. Use a [relative pattern](#RelativePattern) + * to filter documents to a [workspace folder](#WorkspaceFolder). */ - pattern?: string; + pattern?: GlobPattern; } /** @@ -1619,7 +1762,6 @@ declare module 'vscode' { */ export type DocumentSelector = string | DocumentFilter | (string | DocumentFilter)[]; - /** * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves @@ -1852,6 +1994,13 @@ declare module 'vscode' { * @param value Markdown string. */ appendMarkdown(value: string): MarkdownString; + + /** + * Appends the given string as codeblock using the provided language. + * @param value A code snippet. + * @param language An optional [language identifier](#languages.getLanguages). + */ + appendCodeblock(value: string, language?: string): MarkdownString; } /** @@ -2087,6 +2236,11 @@ declare module 'vscode' { * skip the [location](#SymbolInformation.location) of symbols and implement `resolveWorkspaceSymbol` to do that * later. * + * The `query`-parameter should be interpreted in a *relaxed way* as the editor will apply its own highlighting + * and scoring on the results. A good rule of thumb is to match case-insensitive and to simply check that the + * characters of *query* appear in their order in a candidate symbol. Don't use prefix, substring, or similar + * strict matching. + * * @param query A non-empty query string. * @param token A cancellation token. * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be @@ -2458,7 +2612,7 @@ declare module 'vscode' { * The human-readable doc-comment of this signature. Will be shown * in the UI but can be omitted. */ - documentation?: string; + documentation?: string | MarkdownString; /** * Creates a new parameter information object. @@ -2466,7 +2620,7 @@ declare module 'vscode' { * @param label A label string. * @param documentation A doc string. */ - constructor(label: string, documentation?: string); + constructor(label: string, documentation?: string | MarkdownString); } /** @@ -2486,7 +2640,7 @@ declare module 'vscode' { * The human-readable doc-comment of this signature. Will be shown * in the UI but can be omitted. */ - documentation?: string; + documentation?: string | MarkdownString; /** * The parameters of this signature. @@ -2499,7 +2653,7 @@ declare module 'vscode' { * @param label A label string. * @param documentation A doc string. */ - constructor(label: string, documentation?: string); + constructor(label: string, documentation?: string | MarkdownString); } /** @@ -2613,7 +2767,7 @@ declare module 'vscode' { /** * A human-readable string that represents a doc-comment. */ - documentation?: string; + documentation?: string | MarkdownString; /** * A string that should be used when comparing this item @@ -2718,6 +2872,40 @@ declare module 'vscode' { constructor(items?: CompletionItem[], isIncomplete?: boolean); } + /** + * How a [completion provider](#CompletionItemProvider) was triggered + */ + export enum CompletionTriggerKind { + /** + * Completion was triggered normally. + */ + Invoke = 0, + /** + * Completion was triggered by a trigger character. + */ + TriggerCharacter = 1 + } + + /** + * Contains additional information about the context in which + * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + */ + export interface CompletionContext { + /** + * How the completion was triggered. + */ + readonly triggerKind: CompletionTriggerKind; + + /** + * Character that triggered the completion item provider. + * + * `undefined` if provider was not triggered by a character. + * + * The trigger character is already in the document when the completion provider is triggered. + */ + readonly triggerCharacter?: string; + } + /** * The completion item provider interface defines the contract between extensions and * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -2740,10 +2928,12 @@ declare module 'vscode' { * @param document The document in which the command was invoked. * @param position The position at which the command was invoked. * @param token A cancellation token. + * @param context How the completion was triggered. + * * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. */ - provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken, context: CompletionContext): ProviderResult; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) @@ -2814,6 +3004,133 @@ declare module 'vscode' { resolveDocumentLink?(link: DocumentLink, token: CancellationToken): ProviderResult; } + /** + * Represents a color in RGBA space. + */ + export class Color { + + /** + * The red component of this color in the range [0-1]. + */ + readonly red: number; + + /** + * The green component of this color in the range [0-1]. + */ + readonly green: number; + + /** + * The blue component of this color in the range [0-1]. + */ + readonly blue: number; + + /** + * The alpha component of this color in the range [0-1]. + */ + readonly alpha: number; + + /** + * Creates a new color instance. + * + * @param red The red component. + * @param green The green component. + * @param blue The bluew component. + * @param alpha The alpha component. + */ + constructor(red: number, green: number, blue: number, alpha: number); + } + + /** + * Represents a color range from a document. + */ + export class ColorInformation { + + /** + * The range in the document where this color appers. + */ + range: Range; + + /** + * The actual color value for this color range. + */ + color: Color; + + /** + * Creates a new color range. + * + * @param range The range the color appears in. Must not be empty. + * @param color The value of the color. + * @param format The format in which this color is currently formatted. + */ + constructor(range: Range, color: Color); + } + + /** + * A color presentation object describes how a [`color`](#Color) should be represented as text and what + * edits are required to refer to it from source code. + * + * For some languages one color can have multiple presentations, e.g. css can represent the color red with + * the constant `Red`, the hex-value `#ff0000`, or in rgba and hsla forms. In csharp other representations + * apply, e.g `System.Drawing.Color.Red`. + */ + export class ColorPresentation { + + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + label: string; + + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + * is used. + */ + textEdit?: TextEdit; + + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + */ + additionalTextEdits?: TextEdit[]; + + /** + * Creates a new color presentation. + * + * @param label The label of this color presentation. + */ + constructor(label: string); + } + + /** + * The document color provider defines the contract between extensions and feature of + * picking and modifying colors in the editor. + */ + export interface DocumentColorProvider { + + /** + * Provide colors for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [color informations](#ColorInformation) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult; + + /** + * Provide [representations](#ColorPresentation) for a color. + * + * @param color The color to show and insert. + * @param context A context object with additional information + * @param token A cancellation token. + * @return An array of color presentations or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideColorPresentations(color: Color, context: { document: TextDocument, range: Range }, token: CancellationToken): ProviderResult; + } + /** * A tuple of two characters, like a pair of * opening and closing brackets. @@ -3311,8 +3628,24 @@ declare module 'vscode' { * used to show editors side by side. */ export enum ViewColumn { + /** + * A *symbolic* editor column representing the currently + * active column. This value can be used when opening editors, but the + * *resolved* [viewColumn](#TextEditor.viewColumn)-value of editors will always + * be `One`, `Two`, `Three`, or `undefined` but never `Active`. + */ + Active = -1, + /** + * The left most editor column. + */ One = 1, + /** + * The center editor column. + */ Two = 2, + /** + * The right most editor column. + */ Three = 3 } @@ -3869,13 +4202,30 @@ declare module 'vscode' { options?: ShellExecutionOptions; } + /** + * The scope of a task. + */ + export enum TaskScope { + /** + * The task is a global task + */ + Global = 1, + + /** + * The task is a workspace task + */ + Workspace = 2 + } + /** * A task to execute */ export class Task { /** - * Creates a new task. + * ~~Creates a new task.~~ + * + * @deprecated Use the new constructors that allow specifying a target for the task. * * @param definition The task definition as defined in the taskDefinitions extension point. * @param name The task's name. Is presented in the user interface. @@ -3887,11 +4237,30 @@ declare module 'vscode' { */ constructor(taskDefinition: TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + /** + * Creates a new task. + * + * @param definition The task definition as defined in the taskDefinitions extension point. + * @param target Specifies the task's target. It is either a global or a workspace task or a task for a specific workspace folder. + * @param name The task's name. Is presented in the user interface. + * @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface. + * @param execution The process or shell execution. + * @param problemMatchers the names of problem matchers to use, like '$tsc' + * or '$eslint'. Problem matchers can be contributed by an extension using + * the `problemMatchers` extension point. + */ + constructor(taskDefinition: TaskDefinition, target: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + /** * The task's definition. */ definition: TaskDefinition; + /** + * The task's scope. + */ + scope?: TaskScope.Global | TaskScope.Workspace | WorkspaceFolder; + /** * The task's name */ @@ -4175,8 +4544,9 @@ declare module 'vscode' { * to control where the editor is being shown. Might change the [active editor](#window.activeTextEditor). * * @param document A text document to be shown. - * @param column A view column in which the editor should be shown. The default is the [one](#ViewColumn.One), other values - * are adjusted to be __Min(column, columnCount + 1)__. + * @param column A view column in which the [editor](#TextEditor) should be shown. The default is the [one](#ViewColumn.One), other values + * are adjusted to be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is + * not adjusted. * @param preserveFocus When `true` the editor will not take focus. * @return A promise that resolves to an [editor](#TextEditor). */ @@ -4187,7 +4557,7 @@ declare module 'vscode' { * to control options of the editor is being shown. Might change the [active editor](#window.activeTextEditor). * * @param document A text document to be shown. - * @param options [Editor options](#ShowTextDocumentOptions) to configure the behavior of showing the [editor](#TextEditor). + * @param options [Editor options](#TextDocumentShowOptions) to configure the behavior of showing the [editor](#TextEditor). * @return A promise that resolves to an [editor](#TextEditor). */ export function showTextDocument(document: TextDocument, options?: TextDocumentShowOptions): Thenable; @@ -4198,7 +4568,7 @@ declare module 'vscode' { * @see [openTextDocument](#openTextDocument) * * @param uri A resource identifier. - * @param options [Editor options](#ShowTextDocumentOptions) to configure the behavior of showing the [editor](#TextEditor). + * @param options [Editor options](#TextDocumentShowOptions) to configure the behavior of showing the [editor](#TextEditor). * @return A promise that resolves to an [editor](#TextEditor). */ export function showTextDocument(uri: Uri, options?: TextDocumentShowOptions): Thenable; @@ -4367,6 +4737,33 @@ declare module 'vscode' { */ export function showQuickPick(items: T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; + /** + * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. + * Returns `undefined` if no folder is open. + * + * @param options Configures the behavior of the workspace folder list. + * @return A promise that resolves to the workspace folder or `undefined`. + */ + export function showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions): Thenable; + + /** + * Shows a file open dialog to the user which allows to select a file + * for opening-purposes. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resources or `undefined`. + */ + export function showOpenDialog(options: OpenDialogOptions): Thenable; + + /** + * Shows a file save dialog to the user which allows to select a file + * for saving-purposes. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resource or `undefined`. + */ + export function showSaveDialog(options: SaveDialogOptions): Thenable; + /** * Opens an input box to ask the user for input. * @@ -4590,6 +4987,10 @@ declare module 'vscode' { * Args for the custom shell executable, this does not work on Windows (see #8429) */ shellArgs?: string[]; + /** + * Object with environment variables that will be added to the VS Code process. + */ + env?: { [key: string]: string | null }; } /** @@ -4756,13 +5157,16 @@ declare module 'vscode' { export interface WorkspaceFolder { /** - * The associated URI for this workspace folder. + * The associated uri for this workspace folder. + * + * *Note:* The [Uri](#Uri)-type was intentionally chosen such that future releases of the editor can support + * workspace folders that are not stored on the local disk, e.g. `ftp://server/workspaces/foo`. */ readonly uri: Uri; /** * The name of this workspace folder. Defaults to - * the basename its [uri-path](#Uri.path) + * the basename of its [uri-path](#Uri.path) */ readonly name: string; @@ -4801,14 +5205,23 @@ declare module 'vscode' { */ export let workspaceFolders: WorkspaceFolder[] | undefined; + /** + * The name of the workspace. `undefined` when no folder + * has been opened. + * + * @readonly + */ + export let name: string | undefined; + /** * An event that is emitted when a workspace folder is added or removed. */ export const onDidChangeWorkspaceFolders: Event; /** - * Returns a [workspace folder](#WorkspaceFolder) for the provided resource. When the resource - * is a workspace folder itself, its parent workspace folder or `undefined` is returned. + * Returns the [workspace folder](#WorkspaceFolder) that contains a given uri. + * * returns `undefined` when the given uri doesn't match any workspace folder + * * returns the *input* when the given uri is a workspace folder itself * * @param uri An uri. * @return A workspace folder or `undefined` @@ -4832,30 +5245,35 @@ declare module 'vscode' { /** * Creates a file system watcher. * - * A glob pattern that filters the file events must be provided. Optionally, flags to ignore certain - * kinds of events can be provided. To stop listening to events the watcher must be disposed. + * A glob pattern that filters the file events on their absolute path must be provided. Optionally, + * flags to ignore certain kinds of events can be provided. To stop listening to events the watcher must be disposed. * * *Note* that only files within the current [workspace folders](#workspace.workspaceFolders) can be watched. * - * @param globPattern A glob pattern that is applied to the names of created, changed, and deleted files. + * @param globPattern A [glob pattern](#GlobPattern) that is applied to the absolute paths of created, changed, + * and deleted files. Use a [relative pattern](#RelativePattern) to limit events to a certain [workspace folder](#WorkspaceFolder). * @param ignoreCreateEvents Ignore when files have been created. * @param ignoreChangeEvents Ignore when files have been changed. * @param ignoreDeleteEvents Ignore when files have been deleted. * @return A new file system watcher instance. */ - export function createFileSystemWatcher(globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher; + export function createFileSystemWatcher(globPattern: GlobPattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher; /** - * Find files in the workspace. + * Find files across all [workspace folders](#workspace.workspaceFolders) in the workspace. * * @sample `findFiles('**āˆ•*.js', '**āˆ•node_modulesāˆ•**', 10)` - * @param include A glob pattern that defines the files to search for. - * @param exclude A glob pattern that defines files and folders to exclude. + * @param include A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. Use a [relative pattern](#RelativePattern) + * to restrict the search results to a [workspace folder](#WorkspaceFolder). + * @param exclude A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. * @param maxResults An upper-bound for the result. * @param token A token that can be used to signal cancellation to the underlying search engine. - * @return A thenable that resolves to an array of resource identifiers. + * @return A thenable that resolves to an array of resource identifiers. Will return no results if no + * [workspace folders](#workspace.workspaceFolders) are opened. */ - export function findFiles(include: string, exclude?: string, maxResults?: number, token?: CancellationToken): Thenable; + export function findFiles(include: GlobPattern, exclude?: GlobPattern, maxResults?: number, token?: CancellationToken): Thenable; /** * Save all dirty files. @@ -4947,7 +5365,7 @@ declare module 'vscode' { /** * An event that is emitted when a [text document](#TextDocument) is changed. This usually happens * when the [contents](#TextDocument.getText) changes but also when other things like the - * [dirty](TextDocument#isDirty)-state changes. + * [dirty](#TextDocument.isDirty)-state changes. */ export const onDidChangeTextDocument: Event; @@ -4989,7 +5407,7 @@ declare module 'vscode' { /** * An event that is emitted when the [configuration](#WorkspaceConfiguration) changed. */ - export const onDidChangeConfiguration: Event; + export const onDidChangeConfiguration: Event; /** * Register a task provider. @@ -5001,6 +5419,21 @@ declare module 'vscode' { export function registerTaskProvider(type: string, provider: TaskProvider): Disposable; } + /** + * An event describing the change in Configuration + */ + export interface ConfigurationChangeEvent { + + /** + * Returns `true` if the given section for the given resource (if provided) is affected. + * + * @param section Configuration name, supports _dotted_ names. + * @param resource A resource Uri. + * @return `true` if the given section for the given resource (if provided) is affected. + */ + affectsConfiguration(section: string, resource?: Uri): boolean; + } + /** * Namespace for participating in language-specific editor [features](https://code.visualstudio.com/docs/editor/editingevolved), * like IntelliSense, code actions, diagnostics etc. @@ -5314,6 +5747,19 @@ declare module 'vscode' { */ export function registerDocumentLinkProvider(selector: DocumentSelector, provider: DocumentLinkProvider): Disposable; + /** + * Register a color provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A color provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; + /** * Set a [language configuration](#LanguageConfiguration) for a language. * @@ -5333,6 +5779,11 @@ declare module 'vscode' { * Setter and getter for the contents of the input box. */ value: string; + + /** + * A string to show as place holder in the input box to guide the user. + */ + placeholder: string; } interface QuickDiffProvider { @@ -5469,6 +5920,11 @@ declare module 'vscode' { */ readonly label: string; + /** + * The (optional) Uri of the root of this source control. + */ + readonly rootUri: Uri | undefined; + /** * The [input box](#SourceControlInputBox) for this source control. */ @@ -5528,7 +5984,7 @@ declare module 'vscode' { * ~~The [input box](#SourceControlInputBox) for the last source control * created by the extension.~~ * - * @deprecated Use [SourceControl.inputBox](#SourceControl.inputBox) instead + * @deprecated Use SourceControl.inputBox instead */ export const inputBox: SourceControlInputBox; @@ -5537,9 +5993,10 @@ declare module 'vscode' { * * @param id An `id` for the source control. Something short, eg: `git`. * @param label A human-readable string for the source control. Eg: `Git`. + * @param rootUri An optional Uri of the root of the source control. Eg: `Uri.parse(workspaceRoot)`. * @return An instance of [source control](#SourceControl). */ - export function createSourceControl(id: string, label: string): SourceControl; + export function createSourceControl(id: string, label: string, rootUri?: Uri): SourceControl; } /** @@ -5615,8 +6072,8 @@ declare module 'vscode' { /** * A debug configuration provider allows to add the initial debug configurations to a newly created launch.json - * and allows to resolve a launch configuration before it is used to start a new debug session. - * A debug configuration provider is registered via #workspace.registerDebugConfigurationProvider. + * and to resolve a launch configuration before it is used to start a new debug session. + * A debug configuration provider is registered via #debug.registerDebugConfigurationProvider. */ export interface DebugConfigurationProvider { /** @@ -5633,11 +6090,12 @@ declare module 'vscode' { * Resolves a [debug configuration](#DebugConfiguration) by filling in missing values or by adding/changing/removing attributes. * If more than one debug configuration provider is registered for the same type, the resolveDebugConfiguration calls are chained * in arbitrary order and the initial debug configuration is piped through the chain. + * Returning the value 'undefined' prevents the debug session from starting. * * @param folder The workspace folder from which the configuration originates from or undefined for a folderless setup. * @param debugConfiguration The [debug configuration](#DebugConfiguration) to resolve. * @param token A cancellation token. - * @return The resolved debug configuration. + * @return The resolved debug configuration or undefined. */ resolveDebugConfiguration?(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult; } @@ -5652,7 +6110,7 @@ declare module 'vscode' { * or by directly passing a [DebugConfiguration](#DebugConfiguration). * The named configurations are looked up in '.vscode/launch.json' found in the given folder. * Before debugging starts, all unsaved files are saved and the launch configurations are brought up-to-date. - * Folder specific variables used in the configuration (e.g. '${workspaceRoot}') are resolved against the given folder. + * Folder specific variables used in the configuration (e.g. '${workspaceFolder}') are resolved against the given folder. * @param folder The [workspace folder](#WorkspaceFolder) for looking up named configurations and resolving variables or `undefined` for a non-folder setup. * @param nameOrConfiguration Either the name of a debug or compound configuration or a [DebugConfiguration](#DebugConfiguration) object. * @return A thenable that resolves when debugging could be successfully started. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index c09eb2627a0..028db0ba669 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -7,29 +7,128 @@ declare module 'vscode' { - export interface OpenDialogOptions { - uri?: Uri; - openFiles?: boolean; - openFolders?: boolean; - openMany?: boolean; + // export enum FileErrorCodes { + // /** + // * Not owner. + // */ + // EPERM = 1, + // /** + // * No such file or directory. + // */ + // ENOENT = 2, + // /** + // * I/O error. + // */ + // EIO = 5, + // /** + // * Permission denied. + // */ + // EACCES = 13, + // /** + // * File exists. + // */ + // EEXIST = 17, + // /** + // * Not a directory. + // */ + // ENOTDIR = 20, + // /** + // * Is a directory. + // */ + // EISDIR = 21, + // /** + // * File too large. + // */ + // EFBIG = 27, + // /** + // * No space left on device. + // */ + // ENOSPC = 28, + // /** + // * Directory is not empty. + // */ + // ENOTEMPTY = 66, + // /** + // * Invalid file handle. + // */ + // ESTALE = 70, + // /** + // * Illegal NFS file handle. + // */ + // EBADHANDLE = 10001, + // } + + export enum FileChangeType { + Updated = 0, + Added = 1, + Deleted = 2 } - export namespace window { + export interface FileChange { + type: FileChangeType; + resource: Uri; + } - export function showOpenDialog(options: OpenDialogOptions): Thenable; + export enum FileType { + File = 0, + Dir = 1, + Symlink = 2 + } + + export interface FileStat { + id: number | string; + mtime: number; + // atime: number; + size: number; + type: FileType; } // todo@joh discover files etc export interface FileSystemProvider { - // todo@joh -> added, deleted, renamed, changed - onDidChange: Event; - resolveContents(resource: Uri): string | Thenable; - writeContents(resource: Uri, contents: string): void | Thenable; + onDidChange?: Event; - // -- search - // todo@joh - extract into its own provider? - findFiles(query: string, progress: Progress, token?: CancellationToken): Thenable; + root: Uri; + + // more... + // + utimes(resource: Uri, mtime: number, atime: number): Thenable; + + stat(resource: Uri): Thenable; + + read(resource: Uri, offset: number, length: number, progress: Progress): Thenable; + + // todo@remote + // offset - byte offset to start + // count - number of bytes to write + // Thenable - number of bytes actually written + write(resource: Uri, content: Uint8Array): Thenable; + + // todo@remote + // Thenable + move(resource: Uri, target: Uri): Thenable; + + // todo@remote + // helps with performance bigly + // copy?(from: Uri, to: Uri): Thenable; + + // todo@remote + // Thenable + mkdir(resource: Uri): Thenable; + + readdir(resource: Uri): Thenable<[Uri, FileStat][]>; + + // todo@remote + // ? merge both + // ? recursive del + rmdir(resource: Uri): Thenable; + unlink(resource: Uri): Thenable; + + // todo@remote + // create(resource: Uri): Thenable; + + // find files by names + findFiles?(query: string, progress: Progress, token: CancellationToken): Thenable; } export namespace workspace { @@ -70,145 +169,59 @@ declare module 'vscode' { export function registerDiffInformationCommand(command: string, callback: (diff: LineChange[], ...args: any[]) => any, thisArg?: any): Disposable; } - /** - * Represents a color in RGBA space. - */ - export class Color { + //#region decorations - /** - * The red component of this color in the range [0-1]. - */ - readonly red: number; - - /** - * The green component of this color in the range [0-1]. - */ - readonly green: number; - - /** - * The blue component of this color in the range [0-1]. - */ - readonly blue: number; - - /** - * The alpha component of this color in the range [0-1]. - */ - readonly alpha: number; - - constructor(red: number, green: number, blue: number, alpha: number); - - /** - * Creates a color from the HSLA space. - * - * @param hue The hue component in the range [0-1]. - * @param saturation The saturation component in the range [0-1]. - * @param luminance The luminance component in the range [0-1]. - * @param alpha The alpha component in the range [0-1]. - */ - static fromHSLA(hue: number, saturation: number, luminance: number, alpha: number): Color; - - /** - * Creates a color by from a hex string. Supported formats are: #RRGGBB, #RRGGBBAA, #RGB, #RGBA. - * null is returned if the string does not match one of the supported formats. - * @param hex a string to parse - */ - static fromHex(hex: string): Color | null; + //todo@joh -> make class + export interface DecorationData { + priority?: number; + title?: string; + bubble?: boolean; + abbreviation?: string; + color?: ThemeColor; + source?: string; } - /** - * A color format is either a single format or a combination of two - * formats: an opaque one and a transparent one. The format itself - * is a string representation of how the color can be formatted. It - * supports the use of placeholders, similar to how snippets work. - * Each placeholder, surrounded by curly braces `{}`, requires a - * variable name and can optionally specify a number format and range - * for that variable's value. - * - * Supported variables: - * - `red` - * - `green` - * - `blue` - * - `hue` - * - `saturation` - * - `luminance` - * - `alpha` - * - * Supported number formats: - * - `f`, float with 2 decimal points. This is the default format. Default range is `[0-1]`. - * - `Xf`, float with `X` decimal points. Default range is `[0-1]`. - * - `d`, decimal. Default range is `[0-255]`. - * - `x`, `X`, hexadecimal. Default range is `[00-FF]`. - * - * The default number format is float. The default number range is `[0-1]`. - * - * As an example, take the color `Color(1, 0.5, 0, 1)`. Here's how - * different formats would format it: - * - * - CSS RGB - * - Format: `rgb({red:d[0-255]}, {green:d[0-255]}, {blue:d[0-255]})` - * - Output: `rgb(255, 127, 0)` - * - * - CSS RGBA - * - Format: `rgba({red:d[0-255]}, {green:d[0-255]}, {blue:d[0-255]}, {alpha})` - * - Output: `rgba(255, 127, 0, 1)` - * - * - CSS Hexadecimal - * - Format: `#{red:X}{green:X}{blue:X}` - * - Output: `#FF7F00` - * - * - CSS HSLA - * - Format: `hsla({hue:d[0-360]}, {saturation:d[0-100]}%, {luminance:d[0-100]}%, {alpha})` - * - Output: `hsla(30, 100%, 50%, 1)` - */ - export type ColorFormat = string | { opaque: string, transparent: string }; - - /** - * Represents a color range from a document. - */ - export class ColorRange { - - /** - * The range in the document where this color appers. - */ - range: Range; - - /** - * The actual color value for this color range. - */ - color: Color; - - /** - * The other formats this color range supports the color to be formatted in. - */ - availableFormats: ColorFormat[]; - - /** - * Creates a new color range. - * - * @param range The range the color appears in. Must not be empty. - * @param color The value of the color. - * @param format The format in which this color is currently formatted. - */ - constructor(range: Range, color: Color, availableFormats: ColorFormat[]); + export interface SourceControlResourceDecorations { + source?: string; + letter?: string; + color?: ThemeColor; } - /** - * The document color provider defines the contract between extensions and feature of - * picking and modifying colors in the editor. - */ - export interface DocumentColorProvider { - /** - * Provide colors for the given document. - * - * @param document The document in which the command was invoked. - * @param token A cancellation token. - * @return An array of [color ranges](#ColorRange) or a thenable that resolves to such. The lack of a result - * can be signaled by returning `undefined`, `null`, or an empty array. - */ - provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult; + export interface DecorationProvider { + onDidChangeDecorations: Event; + provideDecoration(uri: Uri, token: CancellationToken): ProviderResult; } - export namespace languages { - export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; + export namespace window { + export function registerDecorationProvider(provider: DecorationProvider): Disposable; + } + + //#endregion + + /** + * Represents the debug console. + */ + export interface DebugConsole { + /** + * Append the given value to the debug console. + * + * @param value A string, falsy values will not be printed. + */ + append(value: string): void; + + /** + * Append the given value and a line feed character + * to the debug console. + * + * @param value A string, falsy values will be printed. + */ + appendLine(value: string): void; + } + + export namespace debug { + /** + * The [debug console](#DebugConsole) singleton. + */ + export let console: DebugConsole; } } diff --git a/src/vs/workbench/parts/views/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts similarity index 65% rename from src/vs/workbench/parts/views/browser/viewsExtensionPoint.ts rename to src/vs/workbench/api/browser/viewsExtensionPoint.ts index 4e6d42a117e..0ebf0e9893d 100644 --- a/src/vs/workbench/parts/views/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -8,9 +8,10 @@ import { localize } from 'vs/nls'; import { forEach } from 'vs/base/common/collections'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; -import { ViewLocation, ViewsRegistry, IViewDescriptor } from 'vs/workbench/parts/views/browser/viewsRegistry'; -import { TreeView } from 'vs/workbench/parts/views/browser/treeView'; +import { ViewLocation, ViewsRegistry, IViewDescriptor } from 'vs/workbench/browser/parts/views/viewsRegistry'; +import { TreeView } from 'vs/workbench/browser/parts/views/treeView'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { coalesce, } from 'vs/base/common/arrays'; namespace schema { @@ -82,30 +83,49 @@ namespace schema { }; } -ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyViewDescriptor[] }>('views', [], schema.viewsContribution).setHandler(extensions => { - for (let extension of extensions) { - const { value, collector } = extension; +ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyViewDescriptor[] }>('views', [], schema.viewsContribution) + .setHandler((extensions) => { + for (let extension of extensions) { + const { value, collector } = extension; - forEach(value, entry => { - if (!schema.isValidViewDescriptors(entry.value, collector)) { - return; - } + forEach(value, entry => { + if (!schema.isValidViewDescriptors(entry.value, collector)) { + return; + } - const location = ViewLocation.getContributedViewLocation(entry.key); - if (!location) { - collector.warn(localize('locationId.invalid', "`{0}` is not a valid view location", entry.key)); - return; - } + const location = ViewLocation.getContributedViewLocation(entry.key); + if (!location) { + collector.warn(localize('locationId.invalid', "`{0}` is not a valid view location", entry.key)); + return; + } - const viewDescriptors = entry.value.map(item => ({ - id: item.id, - name: item.name, - ctor: TreeView, - location, - when: ContextKeyExpr.deserialize(item.when), - canToggleVisibility: true - })); - ViewsRegistry.registerViews(viewDescriptors); - }); - } -}); \ No newline at end of file + const registeredViews = ViewsRegistry.getViews(location); + const viewIds = []; + const viewDescriptors = coalesce(entry.value.map(item => { + const viewDescriptor = { + id: item.id, + name: item.name, + ctor: TreeView, + location, + when: ContextKeyExpr.deserialize(item.when), + canToggleVisibility: true, + collapsed: true + }; + + // validate + if (viewIds.indexOf(viewDescriptor.id) !== -1) { + collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}` in the location `{1}`", viewDescriptor.id, viewDescriptor.location.id)); + return null; + } + if (registeredViews.some(v => v.id === viewDescriptor.id)) { + collector.error(localize('duplicateView2', "A view with id `{0}` is already registered in the location `{1}`", viewDescriptor.id, viewDescriptor.location.id)); + return null; + } + + viewIds.push(viewDescriptor.id); + return viewDescriptor; + })); + ViewsRegistry.registerViews(viewDescriptors); + }); + } + }); diff --git a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts index 746d242419b..2940cda2e51 100644 --- a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts @@ -19,6 +19,7 @@ import './mainThreadCommands'; import './mainThreadConfiguration'; import './mainThreadCredentials'; import './mainThreadDebugService'; +import './mainThreadDecorations'; import './mainThreadDiagnostics'; import './mainThreadDialogs'; import './mainThreadDocumentContentProviders'; @@ -28,6 +29,7 @@ import './mainThreadEditor'; import './mainThreadEditors'; import './mainThreadErrors'; import './mainThreadExtensionService'; +import './mainThreadFileSystem'; import './mainThreadFileSystemEventService'; import './mainThreadHeapService'; import './mainThreadLanguageFeatures'; diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 36b5e975ef9..5133d7125a9 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -9,11 +9,11 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext } from '../node/extHost.protocol'; +import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext, IWorkspaceConfigurationChangeEventData } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { ConfigurationTarget, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; @extHostNamedCustomer(MainContext.MainThreadConfiguration) export class MainThreadConfiguration implements MainThreadConfigurationShape { @@ -22,14 +22,13 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { constructor( extHostContext: IExtHostContext, - @IConfigurationEditingService private readonly _configurationEditingService: IConfigurationEditingService, @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService + @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService ) { const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration); - this._configurationListener = configurationService.onDidUpdateConfiguration(() => { - proxy.$acceptConfigurationChanged(configurationService.getConfigurationData()); + this._configurationListener = configurationService.onDidChangeConfiguration(e => { + proxy.$acceptConfigurationChanged(configurationService.getConfigurationData(), this.toConfigurationChangeEventData(e)); }); } @@ -47,16 +46,26 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { private writeConfiguration(target: ConfigurationTarget, key: string, value: any, resource: URI): TPromise { target = target !== null && target !== undefined ? target : this.deriveConfigurationTarget(key, resource); - return this._configurationEditingService.writeConfiguration(target, { key, value }, { donotNotifyError: true, scopes: { resource } }); + return this.configurationService.updateValue(key, value, { resource }, target, true); } private deriveConfigurationTarget(key: string, resource: URI): ConfigurationTarget { - if (resource && this._workspaceContextService.hasMultiFolderWorkspace()) { + if (resource && this._workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); if (configurationProperties[key] && configurationProperties[key].scope === ConfigurationScope.RESOURCE) { - return ConfigurationTarget.FOLDER; + return ConfigurationTarget.WORKSPACE_FOLDER; } } return ConfigurationTarget.WORKSPACE; } + + private toConfigurationChangeEventData(event: IConfigurationChangeEvent): IWorkspaceConfigurationChangeEventData { + return { + changedConfiguration: event.changedConfiguration, + changedConfigurationByResource: event.changedConfigurationByResource.keys().reduce((result, resource) => { + result[resource.toString()] = event.changedConfigurationByResource.get(resource); + return result; + }, Object.create({})) + }; + } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadCredentials.ts b/src/vs/workbench/api/electron-browser/mainThreadCredentials.ts index bc0a15a0496..fc728e9f5df 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadCredentials.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadCredentials.ts @@ -11,6 +11,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC @extHostNamedCustomer(MainContext.MainThreadCredentials) export class MainThreadCredentials implements MainThreadCredentialsShape { + // @ts-ignore unused property private _proxy: ExtHostCredentialsShape; constructor( diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 1e67b9b28eb..3008bbebe2b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import URI from 'vs/base/common/uri'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import uri from 'vs/base/common/uri'; import { IDebugService, IConfig, IDebugConfigurationProvider } from 'vs/workbench/parts/debug/common/debug'; import { TPromise } from 'vs/base/common/winjs.base'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import severity from 'vs/base/common/severity'; @extHostNamedCustomer(MainContext.MainThreadDebugService) export class MainThreadDebugService implements MainThreadDebugServiceShape { @@ -19,7 +21,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { constructor( extHostContext: IExtHostContext, - @IDebugService private debugService: IDebugService + @IDebugService private debugService: IDebugService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostDebugService); this._toDispose = []; @@ -34,8 +37,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { })); this._toDispose.push(debugService.onDidCustomEvent(event => { if (event && event.sessionId) { - const process = this.debugService.findProcessByUUID(event.sessionId); - this._proxy.$acceptDebugSessionCustomEvent(event.sessionId, process.configuration.type, process.configuration.name, event); + const process = this.debugService.getModel().getProcesses().filter(p => p.getId() === event.sessionId).pop(); + if (process) { + this._proxy.$acceptDebugSessionCustomEvent(event.sessionId, process.configuration.type, process.configuration.name, event); + } } })); } @@ -50,12 +55,12 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { type: debugType }; if (hasProvide) { - provider.provideDebugConfigurations = (folder: URI | undefined) => { + provider.provideDebugConfigurations = folder => { return this._proxy.$provideDebugConfigurations(handle, folder); }; } if (hasResolve) { - provider.resolveDebugConfiguration = (folder: URI | undefined, debugConfiguration: any) => { + provider.resolveDebugConfiguration = (folder, debugConfiguration) => { return this._proxy.$resolveDebugConfiguration(handle, folder, debugConfiguration); }; } @@ -69,30 +74,17 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { return TPromise.as(undefined); } - public $startDebugging(folderUri: URI | undefined, nameOrConfiguration: string | IConfig): TPromise { - return this.debugService.startDebugging(folderUri, nameOrConfiguration).then(x => { + public $startDebugging(folderUri: uri | undefined, nameOrConfiguration: string | IConfig): TPromise { + const folder = folderUri ? this.contextService.getWorkspace().folders.filter(wf => wf.uri.toString() === folderUri.toString()).pop() : undefined; + return this.debugService.startDebugging(folder, nameOrConfiguration).then(x => { return true; }, err => { return TPromise.wrapError(err && err.message ? err.message : 'cannot start debugging'); }); } - public $startDebugSession(folderUri: URI | undefined, configuration: IConfig): TPromise { - if (configuration.request !== 'launch' && configuration.request !== 'attach') { - return TPromise.wrapError(new Error(`only 'launch' or 'attach' allowed for 'request' attribute`)); - } - return this.debugService.createProcess(folderUri, configuration).then(process => { - if (process) { - return process.getId(); - } - return TPromise.wrapError(new Error('cannot create debug session')); - }, err => { - return TPromise.wrapError(err && err.message ? err.message : 'cannot start debug session'); - }); - } - public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): TPromise { - const process = this.debugService.findProcessByUUID(sessionId); + const process = this.debugService.getModel().getProcesses().filter(p => p.getId() === sessionId).pop(); if (process) { return process.session.custom(request, args).then(response => { if (response.success) { @@ -104,4 +96,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { } return TPromise.wrapError(new Error('debug session not found')); } + + public $appendDebugConsole(value: string): TPromise { + // Use warning as severity to get the orange color for messages coming from the debug extension + this.debugService.logToRepl(value, severity.Warning); + return TPromise.as(undefined); + } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts new file mode 100644 index 00000000000..b7eb0fc9ea9 --- /dev/null +++ b/src/vs/workbench/api/electron-browser/mainThreadDecorations.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. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import URI from 'vs/base/common/uri'; +import { Emitter } from 'vs/base/common/event'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape } from '../node/extHost.protocol'; +import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; + +@extHostNamedCustomer(MainContext.MainThreadDecorations) +export class MainThreadDecorations implements MainThreadDecorationsShape { + + private readonly _provider = new Map, IDisposable]>(); + private readonly _proxy: ExtHostDecorationsShape; + + constructor( + context: IExtHostContext, + @IDecorationsService private readonly _decorationsService: IDecorationsService + ) { + this._proxy = context.get(ExtHostContext.ExtHostDecorations); + } + + dispose() { + this._provider.forEach(value => dispose(value)); + this._provider.clear(); + } + + $registerDecorationProvider(handle: number, label: string): void { + let emitter = new Emitter(); + let registration = this._decorationsService.registerDecorationsProvider({ + label, + onDidChange: emitter.event, + provideDecorations: (uri) => { + return this._proxy.$providerDecorations(handle, uri).then(data => { + if (!data) { + return undefined; + } + const [weight, bubble, tooltip, letter, themeColor, source] = data; + return { + weight: weight || 0, + bubble: bubble || false, + color: themeColor && themeColor.id, + tooltip, + letter, + source, + }; + }); + } + }); + this._provider.set(handle, [emitter, registration]); + } + + $onDidChange(handle: number, resources: URI[]): void { + const [emitter] = this._provider.get(handle); + emitter.fire(resources); + } + + $unregisterDecorationProvider(handle: number): void { + if (this._provider.has(handle)) { + dispose(this._provider.get(handle)); + this._provider.delete(handle); + } + } +} diff --git a/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts b/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts index e7ecfff9141..2e6768b97ed 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts @@ -6,9 +6,10 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; -import { MainThreadDiaglogsShape, MainContext, IExtHostContext, MainThreadDialogOptions } from '../node/extHost.protocol'; +import { MainThreadDiaglogsShape, MainContext, IExtHostContext, MainThreadDialogOpenOptions, MainThreadDialogSaveOptions } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IWindowService } from 'vs/platform/windows/common/windows'; +import { forEach } from 'vs/base/common/collections'; @extHostNamedCustomer(MainContext.MainThreadDialogs) export class MainThreadDialogs implements MainThreadDiaglogsShape { @@ -24,40 +25,75 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { // } - $showOpenDialog(options: MainThreadDialogOptions): TPromise { + $showOpenDialog(options: MainThreadDialogOpenOptions): TPromise { // TODO@joh what about remote dev setup? - if (options.uri && options.uri.scheme !== 'file') { - return TPromise.wrapError(new Error('bad path')); + if (options.defaultUri && options.defaultUri.scheme !== 'file') { + return TPromise.wrapError(new Error('Not supported - Open-dialogs can only be opened on `file`-uris.')); } return new TPromise(resolve => { - this._windowService.showOpenDialog(MainThreadDialogs._convertOptions(options), filenames => { - resolve(isFalsyOrEmpty(filenames) ? undefined : filenames); - }); + this._windowService.showOpenDialog( + MainThreadDialogs._convertOpenOptions(options), + filenames => resolve(isFalsyOrEmpty(filenames) ? undefined : filenames) + ); }); } - private static _convertOptions(options: MainThreadDialogOptions): Electron.OpenDialogOptions { + $showSaveDialog(options: MainThreadDialogSaveOptions): TPromise { + // TODO@joh what about remote dev setup? + if (options.defaultUri && options.defaultUri.scheme !== 'file') { + return TPromise.wrapError(new Error('Not supported - Save-dialogs can only be opened on `file`-uris.')); + } + return new TPromise(resolve => { + this._windowService.showSaveDialog( + MainThreadDialogs._convertSaveOptions(options), + filename => resolve(!filename ? undefined : filename) + ); + }); + } + + private static _convertOpenOptions(options: MainThreadDialogOpenOptions): Electron.OpenDialogOptions { const result: Electron.OpenDialogOptions = { properties: ['createDirectory'] }; if (options.openLabel) { result.buttonLabel = options.openLabel; } - if (options.uri) { - result.defaultPath = options.uri.fsPath; + if (options.defaultUri) { + result.defaultPath = options.defaultUri.fsPath; } - if (!options.openFiles && !options.openFolders) { - options.openFiles = true; + if (!options.canSelectFiles && !options.canSelectFolders) { + options.canSelectFiles = true; } - if (options.openFiles) { + if (options.canSelectFiles) { result.properties.push('openFile'); } - if (options.openFolders) { + if (options.canSelectFolders) { result.properties.push('openDirectory'); } - if (options.openMany) { + if (options.canSelectMany) { result.properties.push('multiSelections'); } + if (options.filters) { + result.filters = []; + forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value })); + } + return result; + } + + private static _convertSaveOptions(options: MainThreadDialogSaveOptions): Electron.SaveDialogOptions { + const result: Electron.SaveDialogOptions = { + + }; + if (options.defaultUri) { + result.defaultPath = options.defaultUri.fsPath; + } + if (options.saveLabel) { + result.buttonLabel = options.saveLabel; + } + if (options.filters) { + result.filters = []; + forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value })); + } return result; } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts b/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts index d0fcfb8b158..9293b819709 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts @@ -66,7 +66,6 @@ export class BoundModelReferenceCollection { export class MainThreadDocuments implements MainThreadDocumentsShape { private _modelService: IModelService; - private _modeService: IModeService; private _textModelResolverService: ITextModelService; private _textFileService: ITextFileService; private _fileService: IFileService; @@ -89,7 +88,6 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { @IUntitledEditorService untitledEditorService: IUntitledEditorService, ) { this._modelService = modelService; - this._modeService = modeService; this._textModelResolverService = textModelResolverService; this._textFileService = textFileService; this._fileService = fileService; diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts index bf9247c8c81..be7ea0e06c6 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts @@ -6,8 +6,6 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IModel, ICommonCodeEditor, isCommonCodeEditor, isCommonDiffEditor } from 'vs/editor/common/editorCommon'; -import { compare } from 'vs/base/common/strings'; -import { delta } from 'vs/base/common/arrays'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import Event, { Emitter } from 'vs/base/common/event'; @@ -26,28 +24,73 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -namespace cmp { - export function compareModels(a: IModel, b: IModel): number { - return compare(a.uri.toString(), b.uri.toString()); +namespace mapset { + + export function newSet(from: Set): Set { + return new (Set)(from); + // let ret = new Set(); + // from.forEach(ret.add, ret); + // return ret; } - export function compareEditors(a: EditorAndModel, b: EditorAndModel): number { - let ret = compare(a.editor.getId(), b.editor.getId()); - if (ret === 0) { - ret = compare(a.document.uri.toString(), b.document.uri.toString()); - } + + export function setValues(set: Set): T[] { + // return Array.from(set); + let ret: T[] = []; + set.forEach(v => ret.push(v)); + return ret; + } + + export function mapValues(map: Map): T[] { + // return Array.from(map.values()); + let ret: T[] = []; + map.forEach(v => ret.push(v)); return ret; } } -class EditorAndModel { +namespace delta { + + export function ofSets(before: Set, after: Set): { removed: T[], added: T[] } { + const removed: T[] = []; + const added: T[] = []; + before.forEach(element => { + if (!after.has(element)) { + removed.push(element); + } + }); + after.forEach(element => { + if (!before.has(element)) { + added.push(element); + } + }); + return { removed, added }; + } + + export function ofMaps(before: Map, after: Map): { removed: V[], added: V[] } { + const removed: V[] = []; + const added: V[] = []; + before.forEach((value, index) => { + if (!after.has(index)) { + removed.push(value); + } + }); + after.forEach((value, index) => { + if (!before.has(index)) { + added.push(value); + } + }); + return { removed, added }; + } +} + +class EditorSnapshot { readonly id: string; constructor( readonly editor: ICommonCodeEditor, - readonly document: IModel, ) { - this.id = `${editor.getId()},${document.uri.toString()}`; + this.id = `${editor.getId()},${editor.getModel().id}`; } } @@ -58,8 +101,8 @@ class DocumentAndEditorStateDelta { constructor( readonly removedDocuments: IModel[], readonly addedDocuments: IModel[], - readonly removedEditors: EditorAndModel[], - readonly addedEditors: EditorAndModel[], + readonly removedEditors: EditorSnapshot[], + readonly addedEditors: EditorSnapshot[], readonly oldActiveEditor: string, readonly newActiveEditor: string, ) { @@ -85,10 +128,14 @@ class DocumentAndEditorState { static compute(before: DocumentAndEditorState, after: DocumentAndEditorState): DocumentAndEditorStateDelta { if (!before) { - return new DocumentAndEditorStateDelta([], after.documents, [], after.editors, undefined, after.activeEditor); + return new DocumentAndEditorStateDelta( + [], mapset.setValues(after.documents), + [], mapset.mapValues(after.editors), + undefined, after.activeEditor + ); } - const documentDelta = delta(before.documents, after.documents, cmp.compareModels); - const editorDelta = delta(before.editors, after.editors, cmp.compareEditors); + const documentDelta = delta.ofSets(before.documents, after.documents); + const editorDelta = delta.ofMaps(before.editors, after.editors); const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined; const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined; @@ -100,12 +147,11 @@ class DocumentAndEditorState { } constructor( - readonly documents: IModel[], - readonly editors: EditorAndModel[], + readonly documents: Set, + readonly editors: Map, readonly activeEditor: string, ) { - this.documents = documents.sort(cmp.compareModels); - this.editors = editors.sort(cmp.compareEditors); + // } } @@ -121,7 +167,7 @@ class MainThreadDocumentAndEditorStateComputer { @ICodeEditorService private _codeEditorService: ICodeEditorService, @IWorkbenchEditorService private _workbenchEditorService: IWorkbenchEditorService ) { - this._modelService.onModelAdded(this._updateState, this, this._toDispose); + this._modelService.onModelAdded(this._updateStateOnModelAdd, this, this._toDispose); this._modelService.onModelRemoved(this._updateState, this, this._toDispose); this._codeEditorService.onCodeEditorAdd(this._onDidAddEditor, this, this._toDispose); @@ -151,19 +197,45 @@ class MainThreadDocumentAndEditorStateComputer { } } + private _updateStateOnModelAdd(model: IModel): void { + if (model.isTooLargeForHavingARichMode()) { + // ignore + return; + } + + if (!this._currentState) { + // too early + this._updateState(); + return; + } + + // small (fast) delta + this._currentState = new DocumentAndEditorState( + this._currentState.documents.add(model), + this._currentState.editors, + this._currentState.activeEditor + ); + + this._onDidChangeState(new DocumentAndEditorStateDelta( + [], [model], + [], [], + this._currentState.activeEditor, this._currentState.activeEditor + )); + } + private _updateState(): void { // models: ignore too large models - const models = this._modelService.getModels(); - for (let i = 0; i < models.length; i++) { - if (models[i].isTooLargeForHavingARichMode()) { - models.splice(i, 1); - i--; + const models = new Set(); + for (const model of this._modelService.getModels()) { + if (!model.isTooLargeForHavingARichMode()) { + models.add(model); } } + // editor: only take those that have a not too large model - const editors: EditorAndModel[] = []; + const editors = new Map(); let activeEditor: string = null; for (const editor of this._codeEditorService.listCodeEditors()) { @@ -172,8 +244,8 @@ class MainThreadDocumentAndEditorStateComputer { && !model.isDisposed() // model disposed && Boolean(this._modelService.getModel(model.uri)) // model disposing, the flag didn't flip yet but the model service already removed it ) { - const apiEditor = new EditorAndModel(editor, model); - editors.push(apiEditor); + const apiEditor = new EditorSnapshot(editor); + editors.set(apiEditor.id, apiEditor); if (editor.isFocused()) { activeEditor = apiEditor.id; } @@ -194,12 +266,11 @@ class MainThreadDocumentAndEditorStateComputer { candidate = workbenchEditorControl.getModifiedEditor(); } if (candidate) { - for (const { editor, id } of editors) { - if (candidate === editor) { - activeEditor = id; - break; + editors.forEach(snapshot => { + if (candidate === snapshot.editor) { + activeEditor = snapshot.id; } - } + }); } } } @@ -250,7 +321,7 @@ export class MainThreadDocumentsAndEditors { const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService); extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments); - const mainThreadEditors = new MainThreadEditors(this, extHostContext, codeEditorService, this._workbenchEditorService, editorGroupService, telemetryService); + const mainThreadEditors = new MainThreadEditors(this, extHostContext, codeEditorService, this._workbenchEditorService, editorGroupService, telemetryService, textModelResolverService, fileService, this._modelService); extHostContext.set(MainContext.MainThreadEditors, mainThreadEditors); // It is expected that the ctor of the state computer calls our `_onDelta`. @@ -282,7 +353,7 @@ export class MainThreadDocumentsAndEditors { // added editors for (const apiEditor of delta.addedEditors) { - const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.document, + const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.editor.getModel(), apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService); this._editors[apiEditor.id] = mainThreadEditor; diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts index 0da01725b17..bc23649dbe8 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts @@ -244,6 +244,17 @@ export class MainThreadTextEditor { this._codeEditor.setDecorations(key, ranges); } + public setDecorationsFast(key: string, _ranges: number[]): void { + if (!this._codeEditor) { + return; + } + let ranges: Range[] = []; + for (let i = 0, len = Math.floor(_ranges.length / 4); i < len; i++) { + ranges[i] = new Range(_ranges[4 * i], _ranges[4 * i + 1], _ranges[4 * i + 2], _ranges[4 * i + 3]); + } + this._codeEditor.setDecorationsFast(key, ranges); + } + public revealRange(range: IRange, revealType: TextEditorRevealType): void { if (!this._codeEditor) { return; diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts index 8dc711aa435..eb1b487da37 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts @@ -8,7 +8,7 @@ import URI from 'vs/base/common/uri'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { disposed } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; -import { ISingleEditOperation, IDecorationRenderOptions, IDecorationOptions, ILineChange } from 'vs/editor/common/editorCommon'; +import { ISingleEditOperation, IDecorationRenderOptions, IDecorationOptions, ILineChange, ICommonCodeEditor, isCommonCodeEditor } from 'vs/editor/common/editorCommon'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; @@ -18,9 +18,13 @@ import { ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOption import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { equals as objectEquals } from 'vs/base/common/objects'; -import { ExtHostContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IExtHostContext } from '../node/extHost.protocol'; +import { ExtHostContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IExtHostContext, IWorkspaceResourceEdit } from '../node/extHost.protocol'; import { IRange } from 'vs/editor/common/core/range'; import { ISelection } from 'vs/editor/common/core/selection'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { bulkEdit, IResourceEdit } from 'vs/editor/common/services/bulkEdit'; +import { IModelService } from 'vs/editor/common/services/modelService'; export class MainThreadEditors implements MainThreadEditorsShape { @@ -31,6 +35,7 @@ export class MainThreadEditors implements MainThreadEditorsShape { private _toDispose: IDisposable[]; private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; }; private _editorPositionData: ITextEditorPositionData; + private _registeredDecorationTypes: { [decorationType: string]: boolean; }; constructor( documentsAndEditors: MainThreadDocumentsAndEditors, @@ -38,7 +43,10 @@ export class MainThreadEditors implements MainThreadEditorsShape { @ICodeEditorService private _codeEditorService: ICodeEditorService, @IWorkbenchEditorService workbenchEditorService: IWorkbenchEditorService, @IEditorGroupService editorGroupService: IEditorGroupService, - @ITelemetryService telemetryService: ITelemetryService + @ITelemetryService telemetryService: ITelemetryService, + @ITextModelService private readonly _textModelResolverService: ITextModelService, + @IFileService private readonly _fileService: IFileService, + @IModelService private readonly _modelService: IModelService, ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostEditors); this._documentsAndEditors = documentsAndEditors; @@ -52,7 +60,9 @@ export class MainThreadEditors implements MainThreadEditorsShape { this._toDispose.push(documentsAndEditors.onTextEditorRemove(editors => editors.forEach(this._onTextEditorRemove, this))); this._toDispose.push(editorGroupService.onEditorsChanged(() => this._updateActiveAndVisibleTextEditors())); - this._toDispose.push(editorGroupService.onEditorsMoved(() => this._updateActiveAndVisibleTextEditors())); + this._toDispose.push(editorGroupService.onEditorGroupMoved(() => this._updateActiveAndVisibleTextEditors())); + + this._registeredDecorationTypes = Object.create(null); } public dispose(): void { @@ -61,6 +71,10 @@ export class MainThreadEditors implements MainThreadEditorsShape { }); this._textEditorsListenersMap = Object.create(null); this._toDispose = dispose(this._toDispose); + for (let decorationType in this._registeredDecorationTypes) { + this._codeEditorService.removeDecorationType(decorationType); + } + this._registeredDecorationTypes = Object.create(null); } private _onTextEditorAdd(textEditor: MainThreadTextEditor): void { @@ -126,6 +140,11 @@ export class MainThreadEditors implements MainThreadEditorsShape { $tryShowEditor(id: string, position: EditorPosition): TPromise { // check how often this is used + /* __GDPR__ + "api.deprecated" : { + "function" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.show' }); let mainThreadEditor = this._documentsAndEditors.getEditor(id); @@ -141,6 +160,11 @@ export class MainThreadEditors implements MainThreadEditorsShape { $tryHideEditor(id: string): TPromise { // check how often this is used + /* __GDPR__ + "api.deprecated" : { + "function" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.hide' }); let mainThreadEditor = this._documentsAndEditors.getEditor(id); @@ -171,6 +195,14 @@ export class MainThreadEditors implements MainThreadEditorsShape { return TPromise.as(null); } + $trySetDecorationsFast(id: string, key: string, ranges: string): TPromise { + if (!this._documentsAndEditors.getEditor(id)) { + return TPromise.wrapError(disposed(`TextEditor(${id})`)); + } + this._documentsAndEditors.getEditor(id).setDecorationsFast(key, /*TODO: marshaller is too slow*/JSON.parse(ranges)); + return TPromise.as(null); + } + $tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise { if (!this._documentsAndEditors.getEditor(id)) { return TPromise.wrapError(disposed(`TextEditor(${id})`)); @@ -194,6 +226,52 @@ export class MainThreadEditors implements MainThreadEditorsShape { return TPromise.as(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts)); } + $tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise { + + // First check if loaded models were not changed in the meantime + for (let i = 0, len = workspaceResourceEdits.length; i < len; i++) { + const workspaceResourceEdit = workspaceResourceEdits[i]; + if (workspaceResourceEdit.modelVersionId) { + let model = this._modelService.getModel(workspaceResourceEdit.resource); + if (model && model.getVersionId() !== workspaceResourceEdit.modelVersionId) { + // model changed in the meantime + return TPromise.as(false); + } + } + } + + // Convert to shape expected by bulkEdit below + let resourceEdits: IResourceEdit[] = []; + for (let i = 0, len = workspaceResourceEdits.length; i < len; i++) { + const workspaceResourceEdit = workspaceResourceEdits[i]; + const uri = workspaceResourceEdit.resource; + const edits = workspaceResourceEdit.edits; + + for (let j = 0, lenJ = edits.length; j < lenJ; j++) { + const edit = edits[j]; + + resourceEdits.push({ + resource: uri, + newText: edit.newText, + newEol: edit.newEol, + range: edit.range + }); + } + } + + let codeEditor: ICommonCodeEditor; + let editor = this._workbenchEditorService.getActiveEditor(); + if (editor) { + let candidate = editor.getControl(); + if (isCommonCodeEditor(candidate)) { + codeEditor = candidate; + } + } + + return bulkEdit(this._textModelResolverService, codeEditor, resourceEdits, this._fileService) + .then(() => true); + } + $tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise { if (!this._documentsAndEditors.getEditor(id)) { return TPromise.wrapError(disposed(`TextEditor(${id})`)); @@ -202,10 +280,12 @@ export class MainThreadEditors implements MainThreadEditorsShape { } $registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void { + this._registeredDecorationTypes[key] = true; this._codeEditorService.registerDecorationType(key, options); } $removeTextEditorDecorationType(key: string): void { + delete this._registeredDecorationTypes[key]; this._codeEditorService.removeDecorationType(key); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts new file mode 100644 index 00000000000..a874c9121fe --- /dev/null +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -0,0 +1,163 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; +import { TPromise, PPromise } from 'vs/base/common/winjs.base'; +import { ExtHostContext, MainContext, IExtHostContext, MainThreadFileSystemShape, ExtHostFileSystemShape } from '../node/extHost.protocol'; +import { IFileService, IFileSystemProvider, IStat, IFileChange } from 'vs/platform/files/common/files'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import Event, { Emitter } from 'vs/base/common/event'; +import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { IProgress } from 'vs/platform/progress/common/progress'; +import { ISearchResultProvider, ISearchQuery, ISearchComplete, ISearchProgressItem, QueryType, IFileMatch, ISearchService } from 'vs/platform/search/common/search'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { onUnexpectedError } from 'vs/base/common/errors'; + +@extHostNamedCustomer(MainContext.MainThreadFileSystem) +export class MainThreadFileSystem implements MainThreadFileSystemShape { + + private readonly _toDispose: IDisposable[] = []; + private readonly _proxy: ExtHostFileSystemShape; + private readonly _provider = new Map(); + + constructor( + extHostContext: IExtHostContext, + @IFileService private readonly _fileService: IFileService, + @ISearchService private readonly _searchService: ISearchService, + @IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService + ) { + this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem); + } + + dispose(): void { + dispose(this._toDispose); + } + + $registerFileSystemProvider(handle: number, scheme: string): void { + this._provider.set(handle, new RemoteFileSystemProvider(this._fileService, this._searchService, scheme, handle, this._proxy)); + } + + $unregisterFileSystemProvider(handle: number): void { + dispose(this._provider.get(handle)); + this._provider.delete(handle); + } + + $onDidAddFileSystemRoot(uri: URI): void { + this._workspaceEditingService.addFolders([{ uri }], true).done(null, onUnexpectedError); + } + + $onFileSystemChange(handle: number, changes: IFileChange[]): void { + this._provider.get(handle).$onFileSystemChange(changes); + } + + $reportFileChunk(handle: number, resource: URI, chunk: number[]): void { + this._provider.get(handle).reportFileChunk(resource, chunk); + } + + // --- search + + $handleSearchProgress(handle: number, session: number, resource: URI): void { + this._provider.get(handle).handleSearchProgress(session, resource); + } +} + +class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProvider { + + private readonly _onDidChange = new Emitter(); + private readonly _reads = new Map>(); + private readonly _registrations: IDisposable[]; + + readonly onDidChange: Event = this._onDidChange.event; + + + constructor( + fileService: IFileService, + searchService: ISearchService, + scheme: string, + private readonly _handle: number, + private readonly _proxy: ExtHostFileSystemShape + ) { + this._registrations = [ + fileService.registerProvider(scheme, this), + searchService.registerSearchResultProvider(this), + ]; + } + + dispose(): void { + dispose(this._registrations); + this._onDidChange.dispose(); + } + + $onFileSystemChange(changes: IFileChange[]): void { + this._onDidChange.fire(changes); + } + + // --- forwarding calls + + utimes(resource: URI, mtime: number, atime: number): TPromise { + return this._proxy.$utimes(this._handle, resource, mtime, atime); + } + stat(resource: URI): TPromise { + return this._proxy.$stat(this._handle, resource); + } + read(resource: URI, offset: number, count: number, progress: IProgress): TPromise { + this._reads.set(resource.toString(), progress); + return this._proxy.$read(this._handle, offset, count, resource); + } + reportFileChunk(resource: URI, chunk: number[]): void { + this._reads.get(resource.toString()).report(Buffer.from(chunk)); + } + write(resource: URI, content: Uint8Array): TPromise { + return this._proxy.$write(this._handle, resource, [].slice.call(content)); + } + unlink(resource: URI): TPromise { + return this._proxy.$unlink(this._handle, resource); + } + move(resource: URI, target: URI): TPromise { + return this._proxy.$move(this._handle, resource, target); + } + mkdir(resource: URI): TPromise { + return this._proxy.$mkdir(this._handle, resource); + } + readdir(resource: URI): TPromise<[URI, IStat][], any> { + return this._proxy.$readdir(this._handle, resource); + } + rmdir(resource: URI): TPromise { + return this._proxy.$rmdir(this._handle, resource); + } + + // --- search + + private _searches = new Map void>(); + private _searchesIdPool = 0; + + search(query: ISearchQuery): PPromise { + if (query.type === QueryType.Text) { + return PPromise.as({ results: [], stats: undefined }); + } + const id = ++this._searchesIdPool; + const matches: IFileMatch[] = []; + return new PPromise((resolve, reject, report) => { + this._proxy.$fileFiles(this._handle, id, query.filePattern).then(() => { + this._searches.delete(id); + resolve({ + results: matches, + stats: undefined + }); + }, reject); + + this._searches.set(id, resource => { + const match: IFileMatch = { resource }; + matches.push(match); + report(match); + }); + }); + } + + handleSearchProgress(session: number, resource: URI): void { + this._searches.get(session)(resource); + } +} diff --git a/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts b/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts index d538ccaefae..e962c85b7ac 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts @@ -69,7 +69,7 @@ export class HeapService implements IHeapService { trackRecursive(p: TPromise): TPromise; trackRecursive(obj: T): T; - trackRecursive(obj: any): any { + trackRecursive(obj: any): any { if (TPromise.is(obj)) { return obj.then(result => this.trackRecursive(result)); } else { diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 258bd4449e8..9578af3db6e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -15,12 +15,11 @@ import { wireCancellationToken } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange } from 'vs/editor/common/core/range'; -import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, IRawColorFormatMap, MainContext, IExtHostContext } from '../node/extHost.protocol'; +import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration'; import { IHeapService } from './mainThreadHeapService'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { ColorFormatter, CombinedColorFormatter } from 'vs/editor/contrib/colorPicker/common/colorFormatter'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) @@ -30,7 +29,6 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha private _heapService: IHeapService; private _modeService: IModeService; private _registrations: { [handle: number]: IDisposable; } = Object.create(null); - private _formatters: Map; constructor( extHostContext: IExtHostContext, @@ -40,7 +38,6 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha this._proxy = extHostContext.get(ExtHostContext.ExtHostLanguageFeatures); this._heapService = heapService; this._modeService = modeService; - this._formatters = new Map(); } dispose(): void { @@ -208,9 +205,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- navigate type $registerNavigateTypeSupport(handle: number): TPromise { + let lastResultId: number; this._registrations[handle] = WorkspaceSymbolProviderRegistry.register({ provideWorkspaceSymbols: (search: string): TPromise => { - return this._heapService.trackRecursive(this._proxy.$provideWorkspaceSymbols(handle, search)); + + return this._proxy.$provideWorkspaceSymbols(handle, search).then(result => { + if (lastResultId !== undefined) { + this._proxy.$releaseWorkspaceSymbols(handle, lastResultId); + } + lastResultId = result._id; + return result.symbols; + }); }, resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise => { return this._proxy.$resolveWorkspaceSymbol(handle, item); @@ -232,15 +237,25 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- suggest - $registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[]): TPromise { + $registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[], supportsResolveDetails: boolean): TPromise { + this._registrations[handle] = modes.SuggestRegistry.register(selector, { triggerCharacters, - provideCompletionItems: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable => { - return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position))); + provideCompletionItems: (model: IReadOnlyModel, position: EditorPosition, context: modes.SuggestContext, token: CancellationToken): Thenable => { + return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position, context)).then(result => { + if (!result) { + return result; + } + return { + suggestions: result.suggestions, + incomplete: result.incomplete, + dispose: () => this._proxy.$releaseCompletionItems(handle, result._id) + }; + }); }, - resolveCompletionItem: (model: IReadOnlyModel, position: EditorPosition, suggestion: modes.ISuggestion, token: CancellationToken): Thenable => { - return wireCancellationToken(token, this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion)); - } + resolveCompletionItem: supportsResolveDetails + ? (model, position, suggestion, token) => wireCancellationToken(token, this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion)) + : undefined }); return undefined; } @@ -279,44 +294,37 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): TPromise { const proxy = this._proxy; this._registrations[handle] = modes.ColorProviderRegistry.register(selector, { - provideColorRanges: (model, token) => { + provideDocumentColors: (model, token) => { return wireCancellationToken(token, proxy.$provideDocumentColors(handle, model.uri)) .then(documentColors => { return documentColors.map(documentColor => { - const formatters = documentColor.availableFormats.map(f => { - if (typeof f === 'number') { - return this._formatters.get(f); - } else { - return new CombinedColorFormatter(this._formatters.get(f[0]), this._formatters.get(f[1])); - } - }); - const [red, green, blue, alpha] = documentColor.color; const color = { - red: red / 255.0, - green: green / 255.0, - blue: blue / 255.0, + red: red, + green: green, + blue: blue, alpha }; return { color, - formatters, range: documentColor.range }; }); }); + }, + + provideColorPresentations: (model, colorInfo, token) => { + return wireCancellationToken(token, proxy.$provideColorPresentations(handle, model.uri, { + color: [colorInfo.color.red, colorInfo.color.green, colorInfo.color.blue, colorInfo.color.alpha], + range: colorInfo.range + })); } }); return TPromise.as(null); } - $registerColorFormats(formats: IRawColorFormatMap): TPromise { - formats.forEach(f => this._formatters.set(f[0], new ColorFormatter(f[1]))); - return TPromise.as(null); - } - // --- configuration $setLanguageConfiguration(handle: number, languageId: string, _configuration: vscode.LanguageConfiguration): TPromise { diff --git a/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts b/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts index 9bf93689c11..090834e9b6a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts @@ -11,14 +11,13 @@ import { Action } from 'vs/base/common/actions'; import { TPromise as Promise } from 'vs/base/common/winjs.base'; import { MainThreadMessageServiceShape, MainContext, IExtHostContext, MainThreadMessageOptions } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; -import { IExtensionService, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; @extHostNamedCustomer(MainContext.MainThreadMessageService) export class MainThreadMessageService implements MainThreadMessageServiceShape { constructor( extHostContext: IExtHostContext, - @IExtensionService private readonly _extensionService: IExtensionService, @IMessageService private readonly _messageService: IMessageService, @IChoiceService private readonly _choiceService: IChoiceService ) { diff --git a/src/vs/workbench/api/electron-browser/mainThreadProgress.ts b/src/vs/workbench/api/electron-browser/mainThreadProgress.ts index 10d607c2bd1..5ddce6f738b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadProgress.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadProgress.ts @@ -33,12 +33,16 @@ export class MainThreadProgress implements MainThreadProgressShape { } $progressReport(handle: number, message: IProgressStep): void { - this._progress.get(handle).progress.report(message); + if (this._progress.has(handle)) { + this._progress.get(handle).progress.report(message); + } } $progressEnd(handle: number): void { - this._progress.get(handle).resolve(); - this._progress.delete(handle); + if (this._progress.has(handle)) { + this._progress.get(handle).resolve(); + this._progress.delete(handle); + } } private _createTask(handle: number) { diff --git a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts index 46b56f0e896..02d1be98665 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts @@ -10,23 +10,36 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { assign } from 'vs/base/common/objects'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResource, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol'; +import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, ISCMResourceCollection, ISCMResourceSplice } from 'vs/workbench/services/scm/common/scm'; +import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { Command } from 'vs/editor/common/modes'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +class MainThreadSCMResourceCollection implements ISCMResourceCollection { + + readonly resources: ISCMResource[] = []; + + private _onDidSplice = new Emitter(); + readonly onDidSplice = this._onDidSplice.event; + + splice(start: number, deleteCount: number, resources: ISCMResource[]) { + this.resources.splice(start, deleteCount, ...resources); + this._onDidSplice.fire({ start, deleteCount, resources }); + } +} + class MainThreadSCMResourceGroup implements ISCMResourceGroup { + readonly resourceCollection = new MainThreadSCMResourceCollection(); + get hideWhenEmpty(): boolean { return this.features.hideWhenEmpty; } + constructor( private sourceControlHandle: number, private handle: number, public provider: ISCMProvider, public features: SCMGroupFeatures, public label: string, - public id: string, - public resources: ISCMResource[] + public id: string ) { } toJSON(): any { @@ -41,15 +54,19 @@ class MainThreadSCMResourceGroup implements ISCMResourceGroup { class MainThreadSCMResource implements ISCMResource { constructor( + private proxy: ExtHostSCMShape, private sourceControlHandle: number, private groupHandle: number, private handle: number, public sourceUri: URI, - public command: Command | undefined, public resourceGroup: ISCMResourceGroup, public decorations: ISCMResourceDecorations ) { } + open(): TPromise { + return this.proxy.$executeResourceCommand(this.sourceControlHandle, this.groupHandle, this.handle); + } + toJSON(): any { return { $mid: 3, @@ -71,42 +88,40 @@ class MainThreadSCMProvider implements ISCMProvider { get resources(): ISCMResourceGroup[] { return this._groups - .filter(g => g.resources.length > 0 || !g.features.hideWhenEmpty); + .filter(g => g.resourceCollection.resources.length > 0 || !g.features.hideWhenEmpty); } - private _onDidChange = new Emitter(); - get onDidChange(): Event { return this._onDidChange.event; } + private _onDidChangeResources = new Emitter(); + get onDidChangeResources(): Event { return this._onDidChangeResources.event; } private features: SCMProviderFeatures = {}; get handle(): number { return this._handle; } get label(): string { return this._label; } + get rootUri(): URI | undefined { return this._rootUri; } get contextValue(): string { return this._contextValue; } get commitTemplate(): string | undefined { return this.features.commitTemplate; } get acceptInputCommand(): Command | undefined { return this.features.acceptInputCommand; } get statusBarCommands(): Command[] | undefined { return this.features.statusBarCommands; } + get count(): number | undefined { return this.features.count; } private _onDidChangeCommitTemplate = new Emitter(); get onDidChangeCommitTemplate(): Event { return this._onDidChangeCommitTemplate.event; } - private _count: number | undefined = undefined; - get count(): number | undefined { return this._count; } + private _onDidChange = new Emitter(); + get onDidChange(): Event { return this._onDidChange.event; } constructor( private proxy: ExtHostSCMShape, private _handle: number, private _contextValue: string, private _label: string, - @ISCMService scmService: ISCMService, - @ICommandService private commandService: ICommandService + private _rootUri: URI | undefined, + @ISCMService scmService: ISCMService ) { } $updateSourceControl(features: SCMProviderFeatures): void { - if ('count' in features) { - this._count = features.count; - } - this.features = assign(this.features, features); this._onDidChange.fire(); @@ -122,8 +137,7 @@ class MainThreadSCMProvider implements ISCMProvider { this, {}, label, - id, - [] + id ); this._groups.push(group); @@ -152,37 +166,50 @@ class MainThreadSCMProvider implements ISCMProvider { this._onDidChange.fire(); } - $updateGroupResourceStates(groupHandle: number, resources: SCMRawResource[]): void { - const group = this._groupsByHandle[groupHandle]; + $spliceGroupResourceStates(splices: SCMRawResourceSplices[]): void { + for (const [groupHandle, groupSlices] of splices) { + const group = this._groupsByHandle[groupHandle]; - if (!group) { - return; + if (!group) { + console.warn(`SCM group ${groupHandle} not found in provider ${this.label}`); + continue; + } + + // reverse the splices sequence in order to apply them correctly + groupSlices.reverse(); + + for (const [start, deleteCount, rawResources] of groupSlices) { + const resources = rawResources.map(rawResource => { + const [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] = rawResource; + const icon = icons[0]; + const iconDark = icons[1] || icon; + const decorations = { + icon: icon && URI.parse(icon), + iconDark: iconDark && URI.parse(iconDark), + tooltip, + strikeThrough, + faded, + source, + letter, + color: color && color.id + }; + + return new MainThreadSCMResource( + this.proxy, + this.handle, + groupHandle, + handle, + URI.parse(sourceUri), + group, + decorations + ); + }); + + group.resourceCollection.splice(start, deleteCount, resources); + } } - group.resources = resources.map(rawResource => { - const [handle, sourceUri, command, icons, tooltip, strikeThrough, faded] = rawResource; - const icon = icons[0]; - const iconDark = icons[1] || icon; - const decorations = { - icon: icon && URI.parse(icon), - iconDark: iconDark && URI.parse(iconDark), - tooltip, - strikeThrough, - faded - }; - - return new MainThreadSCMResource( - this.handle, - groupHandle, - handle, - URI.parse(sourceUri), - command, - group, - decorations - ); - }); - - this._onDidChange.fire(); + this._onDidChangeResources.fire(); } $unregisterGroup(handle: number): void { @@ -226,9 +253,7 @@ export class MainThreadSCM implements MainThreadSCMShape { constructor( extHostContext: IExtHostContext, - @IInstantiationService private instantiationService: IInstantiationService, - @ISCMService private scmService: ISCMService, - @ICommandService private commandService: ICommandService + @ISCMService private scmService: ISCMService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostSCM); } @@ -245,8 +270,8 @@ export class MainThreadSCM implements MainThreadSCMShape { this._disposables = dispose(this._disposables); } - $registerSourceControl(handle: number, id: string, label: string): void { - const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, this.scmService, this.commandService); + $registerSourceControl(handle: number, id: string, label: string, rootUri: string | undefined): void { + const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri && URI.parse(rootUri), this.scmService); const repository = this.scmService.registerSCMProvider(provider); this._repositories[handle] = repository; @@ -312,7 +337,7 @@ export class MainThreadSCM implements MainThreadSCMShape { provider.$updateGroupLabel(groupHandle, label); } - $updateGroupResourceStates(sourceControlHandle: number, groupHandle: number, resources: SCMRawResource[]): void { + $spliceResourceStates(sourceControlHandle: number, splices: SCMRawResourceSplices[]): void { const repository = this._repositories[sourceControlHandle]; if (!repository) { @@ -320,7 +345,7 @@ export class MainThreadSCM implements MainThreadSCMShape { } const provider = repository.provider as MainThreadSCMProvider; - provider.$updateGroupResourceStates(groupHandle, resources); + provider.$spliceGroupResourceStates(splices); } $unregisterGroup(sourceControlHandle: number, handle: number): void { @@ -343,4 +368,14 @@ export class MainThreadSCM implements MainThreadSCMShape { repository.input.value = value; } + + $setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void { + const repository = this._repositories[sourceControlHandle]; + + if (!repository) { + return; + } + + repository.input.placeholder = placeholder; + } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts index 3e4127cd39b..d81c18b6085 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts @@ -24,6 +24,7 @@ import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textF import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../node/extHost.protocol'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; export interface INamedSaveParticpant extends ISaveParticipant { readonly name: string; @@ -41,7 +42,7 @@ class TrimWhitespaceParticipant implements INamedSaveParticpant { } public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void { - if (this.configurationService.lookup('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() }).value) { + if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO); } } @@ -99,7 +100,7 @@ export class FinalNewLineParticipant implements INamedSaveParticpant { } public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void { - if (this.configurationService.lookup('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() }).value) { + if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doInsertFinalNewLine(model.textEditorModel); } } @@ -127,12 +128,60 @@ export class FinalNewLineParticipant implements INamedSaveParticpant { } } +export class TrimFinalNewLinesParticipant implements INamedSaveParticpant { + + readonly name = 'TrimFinalNewLinesParticipant'; + + constructor( + @IConfigurationService private configurationService: IConfigurationService, + @ICodeEditorService private codeEditorService: ICodeEditorService + ) { + // Nothing + } + + public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void { + if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { + this.doTrimFinalNewLines(model.textEditorModel); + } + } + + private doTrimFinalNewLines(model: IModel): void { + const lineCount = model.getLineCount(); + + // Do not insert new line if file does not end with new line + if (!lineCount) { + return; + } + + let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)]; + const editor = findEditor(model, this.codeEditorService); + if (editor) { + prevSelection = editor.getSelections(); + } + + let currentLineNumber = model.getLineCount(); + let currentLine = model.getLineContent(currentLineNumber); + let currentLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(currentLine) === -1; + while (currentLineIsEmptyOrWhitespace) { + currentLineNumber--; + currentLine = model.getLineContent(currentLineNumber); + currentLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(currentLine) === -1; + } + model.pushEditOperations(prevSelection, [EditOperation.delete(new Range(currentLineNumber + 1, 1, lineCount + 1, 1))], edits => prevSelection); + + if (editor) { + editor.setSelections(prevSelection); + } + } +} + class FormatOnSaveParticipant implements INamedSaveParticpant { readonly name = 'FormatOnSaveParticipant'; constructor( @ICodeEditorService private _editorService: ICodeEditorService, + @IEditorWorkerService private _editorWorkerService: IEditorWorkerService, @IConfigurationService private _configurationService: IConfigurationService ) { // Nothing @@ -142,7 +191,7 @@ class FormatOnSaveParticipant implements INamedSaveParticpant { const model = editorModel.textEditorModel; if (env.reason === SaveReason.AUTO - || !this._configurationService.lookup('editor.formatOnSave', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() }).value) { + || !this._configurationService.getValue('editor.formatOnSave', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() })) { return undefined; } @@ -151,7 +200,9 @@ class FormatOnSaveParticipant implements INamedSaveParticpant { return new TPromise((resolve, reject) => { setTimeout(reject, 750); - getDocumentFormattingEdits(model, { tabSize, insertSpaces }).then(resolve, reject); + getDocumentFormattingEdits(model, { tabSize, insertSpaces }) + .then(edits => this._editorWorkerService.computeMoreMinimalEdits(model.uri, edits)) + .then(resolve, reject); }).then(edits => { if (edits && versionNow === model.getVersionId()) { @@ -230,13 +281,15 @@ export class SaveParticipant implements ISaveParticipant { @ITelemetryService private _telemetryService: ITelemetryService, @IInstantiationService instantiationService: IInstantiationService, @IConfigurationService configurationService: IConfigurationService, - @ICodeEditorService codeEditorService: ICodeEditorService + @ICodeEditorService codeEditorService: ICodeEditorService, + @IEditorWorkerService editorWorkerService: IEditorWorkerService ) { this._saveParticipants = [ new TrimWhitespaceParticipant(configurationService, codeEditorService), - new FormatOnSaveParticipant(codeEditorService, configurationService), + new FormatOnSaveParticipant(codeEditorService, editorWorkerService, configurationService), new FinalNewLineParticipant(configurationService, codeEditorService), + new TrimFinalNewLinesParticipant(configurationService, codeEditorService), new ExtHostSaveParticipant(extHostContext) ]; @@ -266,6 +319,20 @@ export class SaveParticipant implements ISaveParticipant { }); return sequence(promiseFactory).then(() => { + /* __GDPR__ + "saveParticipantStats" : { + "${wildcard}": [ + { + "${prefix}": "Success-", + "${classification}": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + }, + { + "${prefix}": "Failure-", + "${classification}": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + ] + } + */ this._telemetryService.publicLog('saveParticipantStats', stats); }); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadTask.ts b/src/vs/workbench/api/electron-browser/mainThreadTask.ts index 467b59df491..be7d48776f7 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTask.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTask.ts @@ -6,6 +6,9 @@ import { TPromise } from 'vs/base/common/winjs.base'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; + +import { ContributedTask, ExtensionTaskSourceTransfer } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from '../node/extHost.protocol'; @@ -19,7 +22,8 @@ export class MainThreadTask implements MainThreadTaskShape { constructor( extHostContext: IExtHostContext, - @ITaskService private _taskService: ITaskService + @ITaskService private _taskService: ITaskService, + @IWorkspaceContextService private _workspaceContextServer: IWorkspaceContextService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostTask); this._activeHandles = Object.create(null); @@ -35,7 +39,18 @@ export class MainThreadTask implements MainThreadTaskShape { public $registerTaskProvider(handle: number): TPromise { this._taskService.registerTaskProvider(handle, { provideTasks: () => { - return this._proxy.$provideTasks(handle); + return this._proxy.$provideTasks(handle).then((value) => { + for (let task of value.tasks) { + if (ContributedTask.is(task)) { + let uri = (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder; + if (uri) { + delete (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder; + (task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(uri); + } + } + } + return value; + }); } }); this._activeHandles[handle] = true; diff --git a/src/vs/workbench/api/electron-browser/mainThreadTelemetry.ts b/src/vs/workbench/api/electron-browser/mainThreadTelemetry.ts index 31727b37625..215f3b95b86 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTelemetry.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTelemetry.ts @@ -25,6 +25,11 @@ export class MainThreadTelemetry implements MainThreadTelemetryShape { } $publicLog(eventName: string, data: any = Object.create(null)): void { + /* __GDPR__FRAGMENT__ + "MainThreadData" : { + "pluginHostTelemetry" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ data[MainThreadTelemetry._name] = true; this._telemetryService.publicLog(eventName, data); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts b/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts index a0c4d0db90f..aade4a664e3 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts @@ -33,13 +33,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape // when the extension host process goes down ? } - public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], waitOnExit?: boolean): TPromise { + public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], env?: { [key: string]: string }, waitOnExit?: boolean): TPromise { const shellLaunchConfig: IShellLaunchConfig = { name, executable: shellPath, args: shellArgs, waitOnExit, - ignoreConfigurationCwd: true + ignoreConfigurationCwd: true, + env }; return TPromise.as(this.terminalService.createInstance(shellLaunchConfig).id); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts index 75c077967d2..553016983c3 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts @@ -9,8 +9,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/base/common/lifecycle'; import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; -import { ViewsRegistry } from 'vs/workbench/parts/views/browser/viewsRegistry'; -import { ITreeViewDataProvider, ITreeItem, TreeItemCollapsibleState } from 'vs/workbench/parts/views/common/views'; +import { ViewsRegistry } from 'vs/workbench/browser/parts/views/viewsRegistry'; +import { ITreeViewDataProvider, ITreeItem, TreeItemCollapsibleState } from 'vs/workbench/common/views'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; @extHostNamedCustomer(MainContext.MainThreadTreeViews) @@ -103,6 +103,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider { this._onDispose.fire(); } + // @ts-ignore unused property private clearChildren(treeItemHandle: TreeItemHandle): void { const children = this.childrenMap.get(treeItemHandle); if (children) { @@ -132,6 +133,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider { } } + // @ts-ignore unused property private populateElementsToExpand(elements: ITreeItem[], toExpand: ITreeItem[]) { for (const element of elements) { if (element.collapsibleState === TreeItemCollapsibleState.Expanded) { diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index ad58576214d..18e06d646ee 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -6,20 +6,15 @@ import { isPromiseCanceledError } from 'vs/base/common/errors'; import URI from 'vs/base/common/uri'; -import { ISearchService, QueryType, ISearchQuery, ISearchProgressItem, ISearchComplete } from 'vs/platform/search/common/search'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ISearchService, QueryType, ISearchQuery, IFolderQuery, ISearchConfiguration } from 'vs/platform/search/common/search'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { ICommonCodeEditor, isCommonCodeEditor } from 'vs/editor/common/editorCommon'; -import { bulkEdit, IResourceEdit } from 'vs/editor/common/services/bulkEdit'; -import { TPromise, PPromise } from 'vs/base/common/winjs.base'; +import { TPromise } from 'vs/base/common/winjs.base'; import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext, MainContext, IExtHostContext } from '../node/extHost.protocol'; -import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; -import { Emitter } from 'vs/base/common/event'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IRelativePattern } from 'vs/base/common/glob'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { @@ -33,12 +28,11 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @ISearchService private readonly _searchService: ISearchService, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @ITextFileService private readonly _textFileService: ITextFileService, - @IWorkbenchEditorService private readonly _editorService: IWorkbenchEditorService, - @ITextModelService private readonly _textModelResolverService: ITextModelService, - @IFileService private readonly _fileService: IFileService + @IConfigurationService private _configurationService: IConfigurationService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostWorkspace); - this._contextService.onDidChangeWorkspaceRoots(this._onDidChangeWorkspace, this, this._toDispose); + this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose); + this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspace, this, this._toDispose); } dispose(): void { @@ -53,23 +47,42 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- workspace --- private _onDidChangeWorkspace(): void { - this._proxy.$acceptWorkspaceData(this._contextService.getWorkspace()); + this._proxy.$acceptWorkspaceData(this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace()); } // --- search --- - $startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable { + $startSearch(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults: number, requestId: number): Thenable { const workspace = this._contextService.getWorkspace(); - if (!workspace) { + if (!workspace.folders.length) { return undefined; } + let folderQueries: IFolderQuery[]; + if (typeof include === 'string' || !include) { + folderQueries = workspace.folders.map(folder => ({ folder: folder.uri })); // absolute pattern: search across all folders + } else { + folderQueries = [{ folder: URI.file(include.base) }]; // relative pattern: search only in base folder + } + + const useRipgrep = folderQueries.every(folderQuery => { + const folderConfig = this._configurationService.getConfiguration({ resource: folderQuery.folder }); + return folderConfig.search.useRipgrep; + }); + + const ignoreSymlinks = folderQueries.every(folderQuery => { + const folderConfig = this._configurationService.getConfiguration({ resource: folderQuery.folder }); + return !folderConfig.search.followSymlinks; + }); + const query: ISearchQuery = { - folderQueries: workspace.roots.map(root => ({ folder: root })), + folderQueries, type: QueryType.File, maxResults, - includePattern: { [include]: true }, - excludePattern: { [exclude]: true }, + includePattern: { [typeof include === 'string' ? include : !!include ? include.pattern : undefined]: true }, + excludePattern: { [typeof exclude === 'string' ? exclude : !!exclude ? exclude.pattern : undefined]: true }, + useRipgrep, + ignoreSymlinks }; this._searchService.extendQuery(query); @@ -106,96 +119,5 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return result.results.every(each => each.success === true); }); } - - $applyWorkspaceEdit(edits: IResourceEdit[]): TPromise { - - let codeEditor: ICommonCodeEditor; - let editor = this._editorService.getActiveEditor(); - if (editor) { - let candidate = editor.getControl(); - if (isCommonCodeEditor(candidate)) { - codeEditor = candidate; - } - } - - return bulkEdit(this._textModelResolverService, codeEditor, edits, this._fileService) - .then(() => true); - } - - // --- EXPERIMENT: workspace provider - - private _idPool: number = 0; - private readonly _provider = new Map]>(); - private readonly _searchSessions = new Map void, reject: Function, progress: (item: ISearchProgressItem) => void, matches: URI[] }>(); - - $registerFileSystemProvider(handle: number, authority: string): void { - if (!(this._fileService instanceof RemoteFileService)) { - throw new Error(); - } - const emitter = new Emitter(); - const provider = { - onDidChange: emitter.event, - resolve: (resource: URI) => { - return this._proxy.$resolveFile(handle, resource); - }, - update: (resource: URI, value: string) => { - return this._proxy.$storeFile(handle, resource, value); - } - }; - const searchProvider = { - search: (query: ISearchQuery) => { - if (query.type !== QueryType.File) { - return undefined; - } - const session = ++this._idPool; - return new PPromise((resolve, reject, progress) => { - this._searchSessions.set(session, { resolve, reject, progress, matches: [] }); - this._proxy.$startSearch(handle, session, query.filePattern); - }, () => { - this._proxy.$cancelSearch(handle, session); - }); - } - }; - const registrations = combinedDisposable([ - this._fileService.registerProvider(authority, provider), - this._searchService.registerSearchResultProvider(searchProvider), - ]); - this._provider.set(handle, [registrations, emitter]); - } - - $unregisterFileSystemProvider(handle: number): void { - if (this._provider.has(handle)) { - dispose(this._provider.get(handle)[0]); - this._provider.delete(handle); - } - } - - $onFileSystemChange(handle: number, resource: URI) { - const [, emitter] = this._provider.get(handle); - emitter.fire(resource); - }; - - $updateSearchSession(session: number, data: URI): void { - if (this._searchSessions.has(session)) { - this._searchSessions.get(session).progress({ resource: data }); - this._searchSessions.get(session).matches.push(data); - } - } - - $finishSearchSession(session: number, err?: any): void { - if (this._searchSessions.has(session)) { - const { matches, resolve, reject } = this._searchSessions.get(session); - this._searchSessions.delete(session); - if (err) { - reject(err); - } else { - resolve({ - limitHit: false, - stats: undefined, - results: matches.map(resource => ({ resource })) - }); - } - } - } } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index e52fefeddc1..275da883ed8 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -5,7 +5,7 @@ 'use strict'; import { Emitter } from 'vs/base/common/event'; -import { TrieMap } from 'vs/base/common/map'; +import { TernarySearchTree } from 'vs/base/common/map'; import { score } from 'vs/editor/common/modes/languageSelector'; import * as Platform from 'vs/base/common/platform'; import * as errors from 'vs/base/common/errors'; @@ -53,7 +53,9 @@ import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService'; import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs'; -import { MarkdownString } from 'vs/base/common/htmlContent'; +import { ExtHostFileSystem } from 'vs/workbench/api/node/extHostFileSystem'; +import { FileChangeType, FileType } from 'vs/platform/files/common/files'; +import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations'; export interface IExtensionApiFactory { (extension: IExtensionDescription): typeof vscode; @@ -75,30 +77,32 @@ function proposedApiFunction(extension: IExtensionDescription, fn: T): T { export function createApiFactory( initData: IInitData, threadService: ExtHostThreadService, + extHostWorkspace: ExtHostWorkspace, + extHostConfiguration: ExtHostConfiguration, extensionService: ExtHostExtensionService ): IExtensionApiFactory { - const mainThreadTelemetry = threadService.get(MainContext.MainThreadTelemetry); - // Addressable instances const extHostHeapService = threadService.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService()); - const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService, extensionService)); + const extHostDecorations = threadService.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(threadService)); + const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService)); const extHostDocuments = threadService.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(threadService, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = threadService.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(threadService, extHostDocumentsAndEditors)); - const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace))); + const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadEditors))); const extHostEditors = threadService.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(threadService, extHostDocumentsAndEditors)); const extHostCommands = threadService.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(threadService, extHostHeapService)); const extHostTreeViews = threadService.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(threadService.get(MainContext.MainThreadTreeViews), extHostCommands)); - const extHostWorkspace = threadService.set(ExtHostContext.ExtHostWorkspace, new ExtHostWorkspace(threadService, initData.workspace)); + threadService.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace); const extHostDebugService = threadService.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(threadService, extHostWorkspace)); - const extHostConfiguration = threadService.set(ExtHostContext.ExtHostConfiguration, new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration)); + threadService.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration); const extHostDiagnostics = threadService.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(threadService)); const languageFeatures = threadService.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics)); + const extHostFileSystem = threadService.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(threadService)); const extHostFileSystemEvent = threadService.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService()); - const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService)); + const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService, extHostWorkspace, extHostCommands)); const extHostTerminalService = threadService.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(threadService)); const extHostSCM = threadService.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(threadService, extHostCommands)); - const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService)); + const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService, extHostWorkspace)); const extHostCredentials = threadService.set(ExtHostContext.ExtHostCredentials, new ExtHostCredentials(threadService)); const extHostWindow = threadService.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(threadService)); threadService.set(ExtHostContext.ExtHostExtensionService, extensionService); @@ -136,23 +140,9 @@ export function createApiFactory( } } - const apiUsage = new class { - private _seen = new Set(); - publicLog(apiName: string) { - if (this._seen.has(apiName)) { - return undefined; - } - this._seen.add(apiName); - return mainThreadTelemetry.$publicLog('apiUsage', { - name: apiName, - extension: extension.id - }); - } - }; - // namespace: commands const commands: typeof vscode.commands = { - registerCommand(id: string, command: (...args: any[]) => T | Thenable, thisArgs?: any): vscode.Disposable { + registerCommand(id: string, command: (...args: any[]) => T | Thenable, thisArgs?: any): vscode.Disposable { return extHostCommands.registerCommand(id, command, thisArgs); }, registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => void, thisArg?: any): vscode.Disposable { @@ -281,13 +271,12 @@ export function createApiFactory( registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable { return languageFeatures.registerDocumentLinkProvider(selector, provider); }, + registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable { + return languageFeatures.registerColorProvider(selector, provider); + }, setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => { return languageFeatures.setLanguageConfiguration(language, configuration); - }, - // proposed API - registerColorProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider) => { - return languageFeatures.registerColorProvider(selector, provider); - }) + } }; // namespace: window @@ -333,9 +322,9 @@ export function createApiFactory( get state() { return extHostWindow.state; }, - onDidChangeWindowState: proposedApiFunction(extension, (listener, thisArg?, disposables?) => { + onDidChangeWindowState(listener, thisArg?, disposables?) { return extHostWindow.onDidChangeWindowState(listener, thisArg, disposables); - }), + }, showInformationMessage(message, first, ...rest) { return extHostMessageService.showMessage(extension, Severity.Info, message, first, rest); }, @@ -348,9 +337,18 @@ export function createApiFactory( showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showQuickPick(items, options, token); }, + showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) { + return extHostQuickOpen.showWorkspaceFolderPick(options); + }, showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showInput(options, token); }, + showOpenDialog(options) { + return extHostDialogs.showOpenDialog(options); + }, + showSaveDialog(options) { + return extHostDialogs.showSaveDialog(options); + }, createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem { return extHostStatusBar.createStatusBarEntry(extension.id, position, priority); }, @@ -380,15 +378,14 @@ export function createApiFactory( sampleFunction: proposedApiFunction(extension, () => { return extHostMessageService.showMessage(extension, Severity.Info, 'Hello Proposed Api!', {}, []); }), - showOpenDialog: proposedApiFunction(extension, options => { - return extHostDialogs.showOpenDialog(options); + registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => { + return extHostDecorations.registerDecorationProvider(provider, extension.id); }) }; // namespace: workspace const workspace: typeof vscode.workspace = { get rootPath() { - apiUsage.publicLog('workspace#rootPath'); return extHostWorkspace.getPath(); }, set rootPath(value) { @@ -398,11 +395,15 @@ export function createApiFactory( return extHostWorkspace.getWorkspaceFolder(resource); }, get workspaceFolders() { - apiUsage.publicLog('workspace#workspaceFolders'); return extHostWorkspace.getWorkspaceFolders(); }, + get name() { + return extHostWorkspace.workspace ? extHostWorkspace.workspace.name : undefined; + }, + set name(value) { + throw errors.readonly(); + }, onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) { - apiUsage.publicLog('workspace#onDidChangeWorkspaceFolders'); return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables); }, asRelativePath: (pathOrUri, includeWorkspace) => { @@ -415,7 +416,7 @@ export function createApiFactory( return extHostWorkspace.saveAll(includeUntitled); }, applyEdit(edit: vscode.WorkspaceEdit): TPromise { - return extHostWorkspace.appyEdit(edit); + return extHostEditors.applyWorkspaceEdit(edit); }, createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): vscode.FileSystemWatcher => { return extHostFileSystemEvent.createFileSystemWatcher(pattern, ignoreCreate, ignoreChange, ignoreDelete); @@ -430,12 +431,12 @@ export function createApiFactory( let uriPromise: TPromise; let options = uriOrFileNameOrOptions as { language?: string; content?: string; }; - if (!options || typeof options.language === 'string') { - uriPromise = extHostDocuments.createDocumentData(options); - } else if (typeof uriOrFileNameOrOptions === 'string') { + if (typeof uriOrFileNameOrOptions === 'string') { uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions)); } else if (uriOrFileNameOrOptions instanceof URI) { - uriPromise = TPromise.as(uriOrFileNameOrOptions); + uriPromise = TPromise.as(uriOrFileNameOrOptions); + } else if (!options || typeof options === 'object') { + uriPromise = extHostDocuments.createDocumentData(options); } else { throw new Error('illegal argument - uriOrFileNameOrOptions'); } @@ -465,8 +466,9 @@ export function createApiFactory( onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables); }, - getConfiguration: (section?: string, resource?: vscode.Uri): vscode.WorkspaceConfiguration => { - return extHostConfiguration.getConfiguration(section, resource); + getConfiguration(section?: string, resource?: vscode.Uri): vscode.WorkspaceConfiguration { + resource = arguments.length === 1 ? void 0 : resource; + return extHostConfiguration.getConfiguration(section, resource, extension.id); }, registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) { return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider); @@ -475,7 +477,7 @@ export function createApiFactory( return extHostTask.registerTaskProvider(extension, provider); }, registerFileSystemProvider: proposedApiFunction(extension, (authority, provider) => { - return extHostWorkspace.registerFileSystemProvider(authority, provider); + return extHostFileSystem.registerFileSystemProvider(authority, provider); }) }; @@ -484,14 +486,8 @@ export function createApiFactory( get inputBox() { return extHostSCM.getLastInputBox(extension); }, - createSourceControl(id: string, label: string) { - mainThreadTelemetry.$publicLog('registerSCMProvider', { - extensionId: extension.id, - providerId: id, - providerLabel: label - }); - - return extHostSCM.createSourceControl(extension, id, label); + createSourceControl(id: string, label: string, rootUri?: vscode.Uri) { + return extHostSCM.createSourceControl(extension, id, label, rootUri); } }; @@ -500,6 +496,9 @@ export function createApiFactory( get activeDebugSession() { return extHostDebugService.activeDebugSession; }, + get console() { + return extHostDebugService.debugConsole; + }, startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration) { return extHostDebugService.startDebugging(folder, nameOrConfig); }, @@ -517,7 +516,7 @@ export function createApiFactory( }, registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider) { return extHostDebugService.registerDebugConfigurationProvider(debugType, provider); - }, + } }; // namespace: credentials @@ -549,11 +548,13 @@ export function createApiFactory( CancellationTokenSource: CancellationTokenSource, CodeLens: extHostTypes.CodeLens, Color: extHostTypes.Color, - ColorRange: extHostTypes.ColorRange, + ColorPresentation: extHostTypes.ColorPresentation, + ColorInformation: extHostTypes.ColorInformation, EndOfLine: extHostTypes.EndOfLine, CompletionItem: extHostTypes.CompletionItem, CompletionItemKind: extHostTypes.CompletionItemKind, CompletionList: extHostTypes.CompletionList, + CompletionTriggerKind: extHostTypes.CompletionTriggerKind, Diagnostic: extHostTypes.Diagnostic, DiagnosticSeverity: extHostTypes.DiagnosticSeverity, Disposable: extHostTypes.Disposable, @@ -564,7 +565,7 @@ export function createApiFactory( Hover: extHostTypes.Hover, IndentAction: languageConfiguration.IndentAction, Location: extHostTypes.Location, - MarkdownString: MarkdownString, + MarkdownString: extHostTypes.MarkdownString, OverviewRulerLane: EditorCommon.OverviewRulerLane, ParameterInformation: extHostTypes.ParameterInformation, Position: extHostTypes.Position, @@ -583,7 +584,7 @@ export function createApiFactory( TextEditorRevealType: extHostTypes.TextEditorRevealType, TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind, DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior, - Uri: URI, + Uri: URI, ViewColumn: extHostTypes.ViewColumn, WorkspaceEdit: extHostTypes.WorkspaceEdit, ProgressLocation: extHostTypes.ProgressLocation, @@ -596,8 +597,14 @@ export function createApiFactory( TaskGroup: extHostTypes.TaskGroup, ProcessExecution: extHostTypes.ProcessExecution, ShellExecution: extHostTypes.ShellExecution, + TaskScope: extHostTypes.TaskScope, Task: extHostTypes.Task, - ConfigurationTarget: extHostTypes.ConfigurationTarget + ConfigurationTarget: extHostTypes.ConfigurationTarget, + RelativePattern: extHostTypes.RelativePattern, + + // TODO@JOH,remote + FileChangeType: FileChangeType, + FileType: FileType }; if (extension.enableProposedApi && extension.isBuiltin) { api['credentials'] = credentials; @@ -638,7 +645,7 @@ export function initializeExtensionApi(extensionService: ExtHostExtensionService return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie)); } -function defineAPI(factory: IExtensionApiFactory, extensionPaths: TrieMap): void { +function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree): void { // each extension is meant to get its own api implementation const extApiImpl = new Map(); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 84398b38cf5..54227f1d4f2 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -26,11 +26,9 @@ import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/pro import * as editorCommon from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; -import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { ITextSource } from 'vs/editor/common/model/textSource'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationData } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -44,10 +42,14 @@ import { IPosition } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; -import { ITreeItem } from 'vs/workbench/parts/views/common/views'; +import { ITreeItem } from 'vs/workbench/common/views'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { SerializedError } from 'vs/base/common/errors'; +import { IRelativePattern } from 'vs/base/common/glob'; +import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; +import { IStat, IFileChange } from 'vs/platform/files/common/files'; +import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; export interface IEnvironment { isExtensionDevelopmentDebug: boolean; @@ -64,7 +66,7 @@ export interface IEnvironment { export interface IWorkspaceData { id: string; name: string; - roots: URI[]; + folders: IWorkspaceFolderData[]; } export interface IInitData { @@ -72,10 +74,19 @@ export interface IInitData { environment: IEnvironment; workspace: IWorkspaceData; extensions: IExtensionDescription[]; - configuration: IConfigurationData; + configuration: IConfigurationInitData; telemetryInfo: ITelemetryInfo; } +export interface IConfigurationInitData extends IConfigurationData { + configurationScopes: ConfigurationScope[]; +} + +export interface IWorkspaceConfigurationChangeEventData { + changedConfiguration: IConfigurationModel; + changedConfigurationByResource: { [folder: string]: IConfigurationModel }; +} + export interface IExtHostContext { /** * Returns a proxy to an object addressable/named in the extension host process. @@ -114,16 +125,30 @@ export interface MainThreadDiagnosticsShape extends IDisposable { $clear(owner: string): TPromise; } -export interface MainThreadDialogOptions { - uri?: URI; +export interface MainThreadDialogOpenOptions { + defaultUri?: URI; openLabel?: string; - openFiles?: boolean; - openFolders?: boolean; - openMany?: boolean; + canSelectFiles?: boolean; + canSelectFolders?: boolean; + canSelectMany?: boolean; + filters?: { [name: string]: string[] }; +} + +export interface MainThreadDialogSaveOptions { + defaultUri?: URI; + saveLabel?: string; + filters?: { [name: string]: string[] }; } export interface MainThreadDiaglogsShape extends IDisposable { - $showOpenDialog(options: MainThreadDialogOptions): TPromise; + $showOpenDialog(options: MainThreadDialogOpenOptions): TPromise; + $showSaveDialog(options: MainThreadDialogSaveOptions): TPromise; +} + +export interface MainThreadDecorationsShape extends IDisposable { + $registerDecorationProvider(handle: number, label: string): void; + $unregisterDecorationProvider(handle: number): void; + $onDidChange(handle: number, resources: URI[]): void; } export interface MainThreadDocumentContentProvidersShape extends IDisposable { @@ -182,6 +207,16 @@ export interface ITextDocumentShowOptions { selection?: IRange; } +export interface IWorkspaceResourceEdit { + resource: URI; + modelVersionId?: number; + edits: { + range?: IRange; + newText: string; + newEol?: editorCommon.EndOfLineSequence; + }[]; +} + export interface MainThreadEditorsShape extends IDisposable { $tryShowTextDocument(resource: URI, options: ITextDocumentShowOptions): TPromise; $registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void; @@ -190,9 +225,11 @@ export interface MainThreadEditorsShape extends IDisposable { $tryHideEditor(id: string): TPromise; $trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise; $trySetDecorations(id: string, key: string, ranges: editorCommon.IDecorationOptions[]): TPromise; + $trySetDecorationsFast(id: string, key: string, ranges: string): TPromise; $tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise; $trySetSelections(id: string, selections: ISelection[]): TPromise; $tryApplyEdits(id: string, modelVersionId: number, edits: editorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): TPromise; + $tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise; $tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): TPromise; $getDiffInformation(id: string): TPromise; } @@ -223,10 +260,9 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): TPromise; $registerNavigateTypeSupport(handle: number): TPromise; $registerRenameSupport(handle: number, selector: vscode.DocumentSelector): TPromise; - $registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[]): TPromise; + $registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[], supportsResolveDetails: boolean): TPromise; $registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): TPromise; $registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): TPromise; - $registerColorFormats(formats: IRawColorFormatMap): TPromise; $registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): TPromise; $setLanguageConfiguration(handle: number, languageId: string, configuration: vscode.LanguageConfiguration): TPromise; } @@ -260,7 +296,7 @@ export interface MainThreadProgressShape extends IDisposable { } export interface MainThreadTerminalServiceShape extends IDisposable { - $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], waitOnExit?: boolean): TPromise; + $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], env?: { [key: string]: string }, waitOnExit?: boolean): TPromise; $dispose(terminalId: number): void; $hide(terminalId: number): void; $sendText(terminalId: number, text: string, addNewLine: boolean): void; @@ -292,16 +328,20 @@ export interface MainThreadTelemetryShape extends IDisposable { } export interface MainThreadWorkspaceShape extends IDisposable { - $startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable; + $startSearch(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults: number, requestId: number): Thenable; $cancelSearch(requestId: number): Thenable; $saveAll(includeUntitled?: boolean): Thenable; - $applyWorkspaceEdit(edits: IResourceEdit[]): TPromise; +} - $registerFileSystemProvider(handle: number, authority: string): void; +export interface MainThreadFileSystemShape extends IDisposable { + $registerFileSystemProvider(handle: number, scheme: string): void; $unregisterFileSystemProvider(handle: number): void; - $onFileSystemChange(handle: number, resource: URI): void; - $updateSearchSession(session: number, data): void; - $finishSearchSession(session: number, err?: any): void; + + $onDidAddFileSystemRoot(root: URI): void; + $onFileSystemChange(handle: number, resource: IFileChange[]): void; + $reportFileChunk(handle: number, resource: URI, chunk: number[] | null): void; + + $handleSearchProgress(handle: number, session: number, resource: URI): void; } export interface MainThreadTaskShape extends IDisposable { @@ -330,25 +370,41 @@ export interface SCMGroupFeatures { export type SCMRawResource = [ number /*handle*/, string /*resourceUri*/, - modes.Command /*command*/, string[] /*icons: light, dark*/, string /*tooltip*/, boolean /*strike through*/, - boolean /*faded*/ + boolean /*faded*/, + + string | undefined /*source*/, + string | undefined /*letter*/, + ThemeColor | null /*color*/ +]; + +export type SCMRawResourceSplice = [ + number /* start */, + number /* delete count */, + SCMRawResource[] +]; + +export type SCMRawResourceSplices = [ + number, /*handle*/ + SCMRawResourceSplice[] ]; export interface MainThreadSCMShape extends IDisposable { - $registerSourceControl(handle: number, id: string, label: string): void; + $registerSourceControl(handle: number, id: string, label: string, rootUri: string | undefined): void; $updateSourceControl(handle: number, features: SCMProviderFeatures): void; $unregisterSourceControl(handle: number): void; $registerGroup(sourceControlHandle: number, handle: number, id: string, label: string): void; $updateGroup(sourceControlHandle: number, handle: number, features: SCMGroupFeatures): void; $updateGroupLabel(sourceControlHandle: number, handle: number, label: string): void; - $updateGroupResourceStates(sourceControlHandle: number, groupHandle: number, resources: SCMRawResource[]): void; $unregisterGroup(sourceControlHandle: number, handle: number): void; + $spliceResourceStates(sourceControlHandle: number, splices: SCMRawResourceSplices[]): void; + $setInputBoxValue(sourceControlHandle: number, value: string): void; + $setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void; } export type DebugSessionUUID = string; @@ -356,9 +412,9 @@ export type DebugSessionUUID = string; export interface MainThreadDebugServiceShape extends IDisposable { $registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, handle: number): TPromise; $unregisterDebugConfigurationProvider(handle: number): TPromise; - $startDebugging(folderUri: URI | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise; - $startDebugSession(folderUri: URI | undefined, config: vscode.DebugConfiguration): TPromise; + $startDebugging(folder: URI | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise; $customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise; + $appendDebugConsole(value: string): TPromise; } export interface MainThreadCredentialsShape extends IDisposable { @@ -379,7 +435,7 @@ export interface ExtHostCommandsShape { } export interface ExtHostConfigurationShape { - $acceptConfigurationChanged(data: IConfigurationData): void; + $acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData): void; } export interface ExtHostDiagnosticsShape { @@ -444,11 +500,19 @@ export interface ExtHostTreeViewsShape { export interface ExtHostWorkspaceShape { $acceptWorkspaceData(workspace: IWorkspaceData): void; +} - $resolveFile(handle: number, resource: URI): TPromise; - $storeFile(handle: number, resource: URI, content: string): TPromise; - $startSearch(handle: number, session: number, query: string): void; - $cancelSearch(handle: number, session: number): void; +export interface ExtHostFileSystemShape { + $utimes(handle: number, resource: URI, mtime: number, atime: number): TPromise; + $stat(handle: number, resource: URI): TPromise; + $read(handle: number, offset: number, count: number, resource: URI): TPromise; + $write(handle: number, resource: URI, content: number[]): TPromise; + $unlink(handle: number, resource: URI): TPromise; + $move(handle: number, resource: URI, target: URI): TPromise; + $mkdir(handle: number, resource: URI): TPromise; + $readdir(handle: number, resource: URI): TPromise<[URI, IStat][]>; + $rmdir(handle: number, resource: URI): TPromise; + $fileFiles(handle: number, session: number, query: string): TPromise; } export interface ExtHostExtensionServiceShape { @@ -484,11 +548,34 @@ export interface ExtHostHeapServiceShape { } export interface IRawColorInfo { color: [number, number, number, number]; - availableFormats: (number | [number, number])[]; range: IRange; } -export type IRawColorFormatMap = [number, string][]; +export interface IExtHostSuggestion extends modes.ISuggestion { + _id: number; + _parentId: number; +} + +export interface IExtHostSuggestResult { + _id: number; + suggestions: IExtHostSuggestion[]; + incomplete?: boolean; +} + +export interface IdObject { + _id: number; +} + +export namespace IdObject { + let n = 0; + export function mixin(object: T): T & IdObject { + (object)._id = n++; + return object; + } +} + +export type IWorkspaceSymbol = IdObject & modes.SymbolInformation; +export interface IWorkspaceSymbols extends IdObject { symbols: IWorkspaceSymbol[]; } export interface ExtHostLanguageFeaturesShape { $provideDocumentSymbols(handle: number, resource: URI): TPromise; @@ -504,15 +591,18 @@ export interface ExtHostLanguageFeaturesShape { $provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise; $provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: IRange, options: modes.FormattingOptions): TPromise; $provideOnTypeFormattingEdits(handle: number, resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise; - $provideWorkspaceSymbols(handle: number, search: string): TPromise; - $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise; + $provideWorkspaceSymbols(handle: number, search: string): TPromise; + $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise; + $releaseWorkspaceSymbols(handle: number, id: number): void; $provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise; - $provideCompletionItems(handle: number, resource: URI, position: IPosition): TPromise; + $provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise; $resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise; + $releaseCompletionItems(handle: number, id: number): void; $provideSignatureHelp(handle: number, resource: URI, position: IPosition): TPromise; $provideDocumentLinks(handle: number, resource: URI): TPromise; - $provideDocumentColors(handle: number, resource: URI): TPromise; $resolveDocumentLink(handle: number, link: modes.ILink): TPromise; + $provideDocumentColors(handle: number, resource: URI): TPromise; + $provideColorPresentations(handle: number, resource: URI, colorInfo: IRawColorInfo): TPromise; } export interface ExtHostQuickOpenShape { @@ -528,6 +618,7 @@ export interface ExtHostTerminalServiceShape { export interface ExtHostSCMShape { $provideOriginalResource(sourceControlHandle: number, uri: URI): TPromise; $onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise; + $executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise; } export interface ExtHostTaskShape { @@ -543,6 +634,13 @@ export interface ExtHostDebugServiceShape { $acceptDebugSessionCustomEvent(id: DebugSessionUUID, type: string, name: string, event: any): void; } + +export type DecorationData = [number, boolean, string, string, ThemeColor, string]; + +export interface ExtHostDecorationsShape { + $providerDecorations(handle: number, uri: URI): TPromise; +} + export interface ExtHostCredentialsShape { } @@ -556,6 +654,7 @@ export const MainContext = { MainThreadCommands: createMainId('MainThreadCommands'), MainThreadConfiguration: createMainId('MainThreadConfiguration'), MainThreadDebugService: createMainId('MainThreadDebugService'), + MainThreadDecorations: createMainId('MainThreadDecorations'), MainThreadDiagnostics: createMainId('MainThreadDiagnostics'), MainThreadDialogs: createMainId('MainThreadDiaglogs'), MainThreadDocuments: createMainId('MainThreadDocuments'), @@ -574,6 +673,7 @@ export const MainContext = { MainThreadTelemetry: createMainId('MainThreadTelemetry'), MainThreadTerminalService: createMainId('MainThreadTerminalService'), MainThreadWorkspace: createMainId('MainThreadWorkspace'), + MainThreadFileSystem: createMainId('MainThreadFileSystem'), MainThreadExtensionService: createMainId('MainThreadExtensionService'), MainThreadSCM: createMainId('MainThreadSCM'), MainThreadTask: createMainId('MainThreadTask'), @@ -586,12 +686,14 @@ export const ExtHostContext = { ExtHostConfiguration: createExtId('ExtHostConfiguration'), ExtHostDiagnostics: createExtId('ExtHostDiagnostics'), ExtHostDebugService: createExtId('ExtHostDebugService'), + ExtHostDecorations: createExtId('ExtHostDecorations'), ExtHostDocumentsAndEditors: createExtId('ExtHostDocumentsAndEditors'), ExtHostDocuments: createExtId('ExtHostDocuments'), ExtHostDocumentContentProviders: createExtId('ExtHostDocumentContentProviders'), ExtHostDocumentSaveParticipant: createExtId('ExtHostDocumentSaveParticipant'), ExtHostEditors: createExtId('ExtHostEditors'), ExtHostTreeViews: createExtId('ExtHostTreeViews'), + ExtHostFileSystem: createExtId('ExtHostFileSystem'), ExtHostFileSystemEventService: createExtId('ExtHostFileSystemEventService'), ExtHostHeapService: createExtId('ExtHostHeapMonitor'), ExtHostLanguageFeatures: createExtId('ExtHostLanguageFeatures'), diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index f877c4062ae..6a4c1e415dc 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -195,15 +195,6 @@ export class ExtHostApiCommands { ] }); - this._register('vscode.startDebug', (configuration?: any, folderUri?: URI) => { - return this._commands.executeCommand('_workbench.startDebug', configuration, folderUri); - }, { - description: 'Start a debugging session.', - args: [ - { name: 'configuration', description: '(optional) Name of the debug configuration from \'launch.json\' to use. Or a configuration json object to use.' } - ] - }); - this._register('vscode.diff', (left: URI, right: URI, label: string, options?: vscode.TextDocumentShowOptions) => { return this._commands.executeCommand('_workbench.diff', [ left, right, diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 931b01fc875..e7fa2a2066c 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -7,12 +7,15 @@ import { mixin } from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; -import { WorkspaceConfiguration } from 'vscode'; +import * as vscode from 'vscode'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; -import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; +import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from './extHost.protocol'; import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes'; -import { IConfigurationData, Configuration } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { Configuration, ConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; +import { StrictResourceMap } from 'vs/base/common/map'; +import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; function lookUp(tree: any, key: string) { if (key) { @@ -35,30 +38,36 @@ type ConfigurationInspect = { export class ExtHostConfiguration implements ExtHostConfigurationShape { - private readonly _onDidChangeConfiguration = new Emitter(); + private readonly _onDidChangeConfiguration = new Emitter(); private readonly _proxy: MainThreadConfigurationShape; private readonly _extHostWorkspace: ExtHostWorkspace; - private _configuration: Configuration; + private _configurationScopes: Map; + private _configuration: Configuration; - constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationData) { + constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) { this._proxy = proxy; this._extHostWorkspace = extHostWorkspace; - this._configuration = Configuration.parse(data, extHostWorkspace.workspace); + this._configuration = Configuration.parse(data); + this._readConfigurationScopes(data.configurationScopes); } - get onDidChangeConfiguration(): Event { + get onDidChangeConfiguration(): Event { return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event; } - $acceptConfigurationChanged(data: IConfigurationData) { - this._configuration = Configuration.parse(data, this._extHostWorkspace.workspace); - this._onDidChangeConfiguration.fire(undefined); + $acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData) { + this._configuration = Configuration.parse(data); + this._onDidChangeConfiguration.fire(this._toConfigurationChangeEvent(eventData)); } - getConfiguration(section?: string, resource?: URI): WorkspaceConfiguration { + getConfiguration(section?: string, resource?: URI, extensionId?: string): vscode.WorkspaceConfiguration { const config = section - ? lookUp(this._configuration.getValue(null, { resource }), section) - : this._configuration.getValue(null, { resource }); + ? lookUp(this._configuration.getSection(null, { resource }, this._extHostWorkspace.workspace), section) + : this._configuration.getSection(null, { resource }, this._extHostWorkspace.workspace); + + if (section) { + this._validateConfigurationAccess(section, resource, extensionId); + } function parseConfigurationTarget(arg: boolean | ExtHostConfigurationTarget): ConfigurationTarget { if (arg === void 0 || arg === null) { @@ -71,15 +80,16 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { switch (arg) { case ExtHostConfigurationTarget.Global: return ConfigurationTarget.USER; case ExtHostConfigurationTarget.Workspace: return ConfigurationTarget.WORKSPACE; - case ExtHostConfigurationTarget.WorkspaceFolder: return ConfigurationTarget.FOLDER; + case ExtHostConfigurationTarget.WorkspaceFolder: return ConfigurationTarget.WORKSPACE_FOLDER; } } - const result: WorkspaceConfiguration = { + const result: vscode.WorkspaceConfiguration = { has(key: string): boolean { return typeof lookUp(config, key) !== 'undefined'; }, - get(key: string, defaultValue?: T): T { + get: (key: string, defaultValue?: T) => { + this._validateConfigurationAccess(section ? `${section}.${key}` : key, resource, extensionId); let result = lookUp(config, key); if (typeof result === 'undefined') { result = defaultValue; @@ -97,14 +107,14 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { }, inspect: (key: string): ConfigurationInspect => { key = section ? `${section}.${key}` : key; - const config = this._configuration.lookup(key, { resource }); + const config = this._configuration.lookup(key, { resource }, this._extHostWorkspace.workspace); if (config) { return { key, defaultValue: config.default, globalValue: config.user, workspaceValue: config.workspace, - workspaceFolderValue: config.folder + workspaceFolderValue: config.workspaceFolder }; } return undefined; @@ -115,6 +125,49 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { mixin(result, config, false); } - return Object.freeze(result); + return Object.freeze(result); + } + + private _validateConfigurationAccess(key: string, resource: URI, extensionId: string): void { + const scope = this._configurationScopes.get(key); + const extensionIdText = extensionId ? `[${extensionId}] ` : ''; + if (ConfigurationScope.RESOURCE === scope) { + if (resource === void 0) { + console.warn(`${extensionIdText}Accessing a resource scoped configuration without providing a resource is not expected. To get the effective value for '${key}', provide the URI of a resource or 'null' for any resource.`); + } + return; + } + if (ConfigurationScope.WINDOW === scope) { + if (resource) { + console.warn(`${extensionIdText}Accessing a window scoped configuration for a resource is not expected. To associate '${key}' to a resource, define its scope to 'resource' in configuration contributions in 'package.json'.`); + } + return; + } + } + + private _readConfigurationScopes(scopes: ConfigurationScope[]): void { + this._configurationScopes = new Map(); + if (scopes.length) { + const defaultKeys = this._configuration.keys(this._extHostWorkspace.workspace).default; + if (defaultKeys.length === scopes.length) { + for (let i = 0; i < defaultKeys.length; i++) { + this._configurationScopes.set(defaultKeys[i], scopes[i]); + } + } + } + } + + private _toConfigurationChangeEvent(data: IWorkspaceConfigurationChangeEventData): vscode.ConfigurationChangeEvent { + const changedConfiguration = new ConfigurationModel(data.changedConfiguration.contents, data.changedConfiguration.keys, data.changedConfiguration.overrides); + const changedConfigurationByResource: StrictResourceMap = new StrictResourceMap(); + for (const key of Object.keys(data.changedConfigurationByResource)) { + const resource = URI.parse(key); + const model = data.changedConfigurationByResource[key]; + changedConfigurationByResource.set(resource, new ConfigurationModel(model.contents, model.keys, model.overrides)); + } + const event = new WorkspaceConfigurationChangeEvent(new ConfigurationChangeEvent(changedConfiguration, changedConfigurationByResource), this._extHostWorkspace.workspace); + return Object.freeze({ + affectsConfiguration: (section: string, resource?: URI) => event.affectsConfiguration(section, resource) + }); } } diff --git a/src/vs/workbench/api/node/extHostCredentials.ts b/src/vs/workbench/api/node/extHostCredentials.ts index de7a8ef0181..26f31d13803 100644 --- a/src/vs/workbench/api/node/extHostCredentials.ts +++ b/src/vs/workbench/api/node/extHostCredentials.ts @@ -13,7 +13,7 @@ export class ExtHostCredentials implements ExtHostCredentialsShape { constructor(mainContext: IMainContext) { this._proxy = mainContext.get(MainContext.MainThreadCredentials); - }; + } readSecret(service: string, account: string): Thenable { return this._proxy.$readSecret(service, account); diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 277fce79171..23c7a043199 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -40,6 +40,9 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { private _onDidReceiveDebugSessionCustomEvent: Emitter; get onDidReceiveDebugSessionCustomEvent(): Event { return this._onDidReceiveDebugSessionCustomEvent.event; } + private _debugConsole: ExtHostDebugConsole; + get debugConsole(): ExtHostDebugConsole { return this._debugConsole; } + constructor(mainContext: IMainContext, workspace: ExtHostWorkspace) { @@ -54,6 +57,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { this._onDidReceiveDebugSessionCustomEvent = new Emitter(); this._debugServiceProxy = mainContext.get(MainContext.MainThreadDebugService); + + this._debugConsole = new ExtHostDebugConsole(this._debugServiceProxy); } public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable { @@ -95,17 +100,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise { - - return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig); - } - - public startDebugSession(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration): TPromise { - - return this._debugServiceProxy.$startDebugSession(folder ? folder.uri : undefined, config).then((id: DebugSessionUUID) => { - const debugSession = new ExtHostDebugSession(this._debugServiceProxy, id, config.type, config.name); - this._debugSessions.set(id, debugSession); - return debugSession; - }); + return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig); } public $acceptDebugSessionStarted(id: DebugSessionUUID, type: string, name: string): void { @@ -188,7 +183,7 @@ export class ExtHostDebugSession implements vscode.DebugSession { this._id = id; this._type = type; this._name = name; - }; + } public get id(): string { return this._id; @@ -206,3 +201,20 @@ export class ExtHostDebugSession implements vscode.DebugSession { return this._debugServiceProxy.$customDebugAdapterRequest(this._id, command, args); } } + +export class ExtHostDebugConsole implements vscode.DebugConsole { + + private _debugServiceProxy: MainThreadDebugServiceShape; + + constructor(proxy: MainThreadDebugServiceShape) { + this._debugServiceProxy = proxy; + } + + append(value: string): void { + this._debugServiceProxy.$appendDebugConsole(value); + } + + appendLine(value: string): void { + this.append(value + '\n'); + } +} diff --git a/src/vs/workbench/api/node/extHostDecorations.ts b/src/vs/workbench/api/node/extHostDecorations.ts new file mode 100644 index 00000000000..b2f746e6dc4 --- /dev/null +++ b/src/vs/workbench/api/node/extHostDecorations.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * 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 vscode from 'vscode'; +import URI from 'vs/base/common/uri'; +import { MainContext, IMainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData } from 'vs/workbench/api/node/extHost.protocol'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { Disposable } from 'vs/workbench/api/node/extHostTypes'; +import { asWinJsPromise } from 'vs/base/common/async'; + +export class ExtHostDecorations implements ExtHostDecorationsShape { + + private static _handlePool = 0; + + private readonly _provider = new Map(); + private readonly _proxy: MainThreadDecorationsShape; + + constructor(mainContext: IMainContext) { + this._proxy = mainContext.get(MainContext.MainThreadDecorations); + } + + registerDecorationProvider(provider: vscode.DecorationProvider, label: string): vscode.Disposable { + const handle = ExtHostDecorations._handlePool++; + this._provider.set(handle, provider); + this._proxy.$registerDecorationProvider(handle, label); + + const listener = provider.onDidChangeDecorations(e => { + this._proxy.$onDidChange(handle, !e ? null : Array.isArray(e) ? e : [e]); + }); + + return new Disposable(() => { + listener.dispose(); + this._proxy.$unregisterDecorationProvider(handle); + this._provider.delete(handle); + }); + } + + $providerDecorations(handle: number, uri: URI): TPromise { + const provider = this._provider.get(handle); + return asWinJsPromise(token => provider.provideDecoration(uri, token)).then(data => { + return data && [data.priority, data.bubble, data.title, data.abbreviation, data.color, data.source]; + }); + } +} diff --git a/src/vs/workbench/api/node/extHostDiagnostics.ts b/src/vs/workbench/api/node/extHostDiagnostics.ts index 1a200433765..8b44277e384 100644 --- a/src/vs/workbench/api/node/extHostDiagnostics.ts +++ b/src/vs/workbench/api/node/extHostDiagnostics.ts @@ -133,7 +133,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { } } - entries.push([uri, marker]); + entries.push([uri, marker]); } this._proxy.$changeMany(this.name, entries); @@ -142,7 +142,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { delete(uri: vscode.Uri): void { this._checkDisposed(); this._data.delete(uri.toString()); - this._proxy.$changeMany(this.name, [[uri, undefined]]); + this._proxy.$changeMany(this.name, [[uri, undefined]]); } clear(): void { diff --git a/src/vs/workbench/api/node/extHostDialogs.ts b/src/vs/workbench/api/node/extHostDialogs.ts index 5543e949a88..fc0bc2b807c 100644 --- a/src/vs/workbench/api/node/extHostDialogs.ts +++ b/src/vs/workbench/api/node/extHostDialogs.ts @@ -17,8 +17,14 @@ export class ExtHostDialogs { } showOpenDialog(options: vscode.OpenDialogOptions): Thenable { - return this._proxy.$showOpenDialog(options).then(filepaths => { + return this._proxy.$showOpenDialog(options).then(filepaths => { return filepaths && filepaths.map(URI.file); }); } + + showSaveDialog(options: vscode.SaveDialogOptions): Thenable { + return this._proxy.$showSaveDialog(options).then(filepath => { + return filepath && URI.file(filepath); + }); + } } diff --git a/src/vs/workbench/api/node/extHostDocumentContentProviders.ts b/src/vs/workbench/api/node/extHostDocumentContentProviders.ts index c3d6e39536e..dc53c36fcc8 100644 --- a/src/vs/workbench/api/node/extHostDocumentContentProviders.ts +++ b/src/vs/workbench/api/node/extHostDocumentContentProviders.ts @@ -47,7 +47,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro if (typeof provider.onDidChange === 'function') { subscription = provider.onDidChange(uri => { if (this._documentsAndEditors.getDocument(uri.toString())) { - this.$provideTextDocumentContent(handle, uri).then(value => { + this.$provideTextDocumentContent(handle, uri).then(value => { const document = this._documentsAndEditors.getDocument(uri.toString()); if (!document) { @@ -60,7 +60,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro // broadcast event when content changed if (!document.equalLines(textSource)) { - return this._proxy.$onVirtualDocumentChange(uri, textSource); + return this._proxy.$onVirtualDocumentChange(uri, textSource); } }, onUnexpectedError); diff --git a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts index 90e5e6e0d81..16d2ed87ccd 100644 --- a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts @@ -10,10 +10,9 @@ import URI from 'vs/base/common/uri'; import { sequence, always } from 'vs/base/common/async'; import { illegalState } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; -import { MainThreadWorkspaceShape, ExtHostDocumentSaveParticipantShape } from 'vs/workbench/api/node/extHost.protocol'; +import { ExtHostDocumentSaveParticipantShape, MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol'; import { TextEdit } from 'vs/workbench/api/node/extHostTypes'; import { fromRange, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters'; -import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import * as vscode from 'vscode'; @@ -21,14 +20,14 @@ import * as vscode from 'vscode'; export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSaveParticipantShape { private _documents: ExtHostDocuments; - private _workspace: MainThreadWorkspaceShape; + private _mainThreadEditors: MainThreadEditorsShape; private _callbacks = new CallbackList(); private _badListeners = new WeakMap(); private _thresholds: { timeout: number; errors: number; }; - constructor(documents: ExtHostDocuments, workspace: MainThreadWorkspaceShape, thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }) { + constructor(documents: ExtHostDocuments, mainThreadEditors: MainThreadEditorsShape, thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }) { this._documents = documents; - this._workspace = workspace; + this._mainThreadEditors = mainThreadEditors; this._thresholds = thresholds; } @@ -38,12 +37,8 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic get onWillSaveTextDocumentEvent(): Event { return (listener, thisArg, disposables) => { - this._callbacks.add(listener, thisArg); - const result = { - dispose: () => { - this._callbacks.remove(listener, thisArg); - } - }; + const remove = this._callbacks.add(listener, thisArg); + const result = { dispose: remove }; if (Array.isArray(disposables)) { disposables.push(result); } @@ -133,13 +128,15 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic }).then(values => { - let edits: IResourceEdit[] = []; + let workspaceResourceEdit: IWorkspaceResourceEdit = { + resource: document.uri, + edits: [] + }; for (const value of values) { if (Array.isArray(value) && (value).every(e => e instanceof TextEdit)) { for (const { newText, newEol, range } of value) { - edits.push({ - resource: document.uri, + workspaceResourceEdit.edits.push({ range: range && fromRange(range), newText, newEol: EndOfLine.from(newEol) @@ -150,12 +147,12 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic // apply edits if any and if document // didn't change somehow in the meantime - if (edits.length === 0) { + if (workspaceResourceEdit.edits.length === 0) { return undefined; } if (version === document.version) { - return this._workspace.$applyWorkspaceEdit(edits); + return this._mainThreadEditors.$tryApplyWorkspaceEdit([workspaceResourceEdit]); } // TODO@joh bubble this to listener? diff --git a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts index 8129a12b69a..da9cc09702c 100644 --- a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts +++ b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts @@ -8,10 +8,9 @@ import Event, { Emitter } from 'vs/base/common/event'; import { dispose } from 'vs/base/common/lifecycle'; import { MainContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IMainContext } from './extHost.protocol'; import { ExtHostDocumentData } from './extHostDocumentData'; -import { ExtHostTextEditor, ExtHostTextEditor2 } from './extHostTextEditor'; +import { ExtHostTextEditor } from './extHostTextEditor'; import * as assert from 'assert'; import * as typeConverters from './extHostTypeConverters'; -import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape { @@ -30,8 +29,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha readonly onDidChangeActiveTextEditor: Event = this._onDidChangeActiveTextEditor.event; constructor( - private readonly _mainContext: IMainContext, - private readonly _extHostExtensions?: ExtHostExtensionService + private readonly _mainContext: IMainContext ) { } @@ -81,9 +79,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha assert.ok(!this._editors.has(data.id), `editor '${data.id}' already exists!`); const documentData = this._documents.get(data.document.toString()); - const editor = new ExtHostTextEditor2( - this._extHostExtensions, - this._mainContext.get(MainContext.MainThreadTelemetry), + const editor = new ExtHostTextEditor( this._mainContext.get(MainContext.MainThreadEditors), data.id, documentData, diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index f13519818d8..809a99ec59b 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -17,8 +17,10 @@ import { MainContext, MainThreadExtensionServiceShape, IWorkspaceData, IEnvironm import { IExtensionMemento, ExtensionsActivator, ActivatedExtension, IExtensionAPI, IExtensionContext, EmptyExtension, IExtensionModule, ExtensionActivationTimesBuilder, ExtensionActivationTimes } from 'vs/workbench/api/node/extHostExtensionActivator'; import { Barrier } from 'vs/workbench/services/extensions/node/barrier'; import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService'; +import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { realpath } from 'fs'; -import { TrieMap } from 'vs/base/common/map'; +import { TernarySearchTree } from 'vs/base/common/map'; class ExtensionMemento implements IExtensionMemento { @@ -116,11 +118,15 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private readonly _storagePath: ExtensionStoragePath; private readonly _proxy: MainThreadExtensionServiceShape; private _activator: ExtensionsActivator; - private _extensionPathIndex: TPromise>; + private _extensionPathIndex: TPromise>; /** * This class is constructed manually because it is a service, so it doesn't use any ctor injection */ - constructor(initData: IInitData, threadService: ExtHostThreadService) { + constructor(initData: IInitData, + threadService: ExtHostThreadService, + extHostWorkspace: ExtHostWorkspace, + extHostConfiguration: ExtHostConfiguration + ) { this._barrier = new Barrier(); this._registry = new ExtensionDescriptionRegistry(initData.extensions); this._threadService = threadService; @@ -131,7 +137,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { this._activator = null; // initialize API first (i.e. do not release barrier until the API is initialized) - const apiFactory = createApiFactory(initData, threadService, this); + const apiFactory = createApiFactory(initData, threadService, extHostWorkspace, extHostConfiguration, this); initializeExtensionApi(this, apiFactory).then(() => { @@ -204,9 +210,9 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { } // create trie to enable fast 'filename -> extension id' look up - public getExtensionPathIndex(): TPromise> { + public getExtensionPathIndex(): TPromise> { if (!this._extensionPathIndex) { - const trie = new TrieMap(); + const tree = TernarySearchTree.forPaths(); const extensions = this.getAllExtensionDescriptions().map(ext => { if (!ext.main) { return undefined; @@ -216,13 +222,13 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { if (err) { reject(err); } else { - trie.insert(path, ext); + tree.set(path, ext); resolve(void 0); } }); }); }); - this._extensionPathIndex = TPromise.join(extensions).then(() => trie); + this._extensionPathIndex = TPromise.join(extensions).then(() => tree); } return this._extensionPathIndex; } @@ -281,6 +287,13 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private _doActivateExtension(extensionDescription: IExtensionDescription, startup: boolean): TPromise { let event = getTelemetryActivationEvent(extensionDescription); + /* __GDPR__ + "activatePlugin" : { + "${include}": [ + "${TelemetryActivationEvent}" + ] + } + */ this._mainThreadTelemetry.$publicLog('activatePlugin', event); if (!extensionDescription.main) { // Treat the extension as being empty => NOT AN ERROR CASE @@ -380,6 +393,21 @@ function loadCommonJSModule(modulePath: string, activationTimesBuilder: Exten } function getTelemetryActivationEvent(extensionDescription: IExtensionDescription): any { + /* __GDPR__FRAGMENT__ + "TelemetryActivationEvent" : { + "id": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "name": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "publisherDisplayName": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "activationEvents": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "isBuiltin": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "${wildcard}": [ + { + "${prefix}": "contribution.", + "${classification}": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + ] + } + */ let event = { id: extensionDescription.id, name: extensionDescription.name, diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts new file mode 100644 index 00000000000..a7b8c787310 --- /dev/null +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape } from './extHost.protocol'; +import * as vscode from 'vscode'; +import { IStat } from 'vs/platform/files/common/files'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { asWinJsPromise } from 'vs/base/common/async'; + +export class ExtHostFileSystem implements ExtHostFileSystemShape { + + private readonly _proxy: MainThreadFileSystemShape; + private readonly _provider = new Map(); + private _handlePool: number = 0; + + constructor(mainContext: IMainContext) { + this._proxy = mainContext.get(MainContext.MainThreadFileSystem); + } + + registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider) { + const handle = this._handlePool++; + this._provider.set(handle, provider); + this._proxy.$registerFileSystemProvider(handle, scheme); + this._proxy.$onDidAddFileSystemRoot(provider.root); + let reg: IDisposable; + if (provider.onDidChange) { + reg = provider.onDidChange(event => this._proxy.$onFileSystemChange(handle, event)); + } + return { + dispose: () => { + if (reg) { + reg.dispose(); + } + this._provider.delete(handle); + this._proxy.$unregisterFileSystemProvider(handle); + } + }; + } + + $utimes(handle: number, resource: URI, mtime: number, atime: number): TPromise { + return asWinJsPromise(token => this._provider.get(handle).utimes(resource, mtime, atime)); + } + $stat(handle: number, resource: URI): TPromise { + return asWinJsPromise(token => this._provider.get(handle).stat(resource)); + } + $read(handle: number, offset: number, count: number, resource: URI): TPromise { + const progress = { + report: chunk => { + this._proxy.$reportFileChunk(handle, resource, [].slice.call(chunk)); + } + }; + return asWinJsPromise(token => this._provider.get(handle).read(resource, offset, count, progress)); + } + $write(handle: number, resource: URI, content: number[]): TPromise { + return asWinJsPromise(token => this._provider.get(handle).write(resource, Buffer.from(content))); + } + $unlink(handle: number, resource: URI): TPromise { + return asWinJsPromise(token => this._provider.get(handle).unlink(resource)); + } + $move(handle: number, resource: URI, target: URI): TPromise { + return asWinJsPromise(token => this._provider.get(handle).move(resource, target)); + } + $mkdir(handle: number, resource: URI): TPromise { + return asWinJsPromise(token => this._provider.get(handle).mkdir(resource)); + } + $readdir(handle: number, resource: URI): TPromise<[URI, IStat][], any> { + return asWinJsPromise(token => this._provider.get(handle).readdir(resource)); + } + $rmdir(handle: number, resource: URI): TPromise { + return asWinJsPromise(token => this._provider.get(handle).rmdir(resource)); + } + $fileFiles(handle: number, session: number, query: string): TPromise { + const provider = this._provider.get(handle); + if (!provider.findFiles) { + return TPromise.as(undefined); + } + const progress = { report: (uri) => this._proxy.$handleSearchProgress(handle, session, uri) }; + return asWinJsPromise(token => provider.findFiles(query, progress, token)); + } +} diff --git a/src/vs/workbench/api/node/extHostFileSystemEventService.ts b/src/vs/workbench/api/node/extHostFileSystemEventService.ts index 822298414c3..1c5aa2b1e28 100644 --- a/src/vs/workbench/api/node/extHostFileSystemEventService.ts +++ b/src/vs/workbench/api/node/extHostFileSystemEventService.ts @@ -6,7 +6,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { Disposable } from './extHostTypes'; -import { match } from 'vs/base/common/glob'; +import { parse, IRelativePattern } from 'vs/base/common/glob'; import { Uri, FileSystemWatcher as _FileSystemWatcher } from 'vscode'; import { FileSystemEvents, ExtHostFileSystemEventServiceShape } from './extHost.protocol'; @@ -30,7 +30,7 @@ class FileSystemWatcher implements _FileSystemWatcher { return Boolean(this._config & 0b100); } - constructor(dispatcher: Event, globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean) { + constructor(dispatcher: Event, globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean) { this._config = 0; if (ignoreCreateEvents) { @@ -43,24 +43,26 @@ class FileSystemWatcher implements _FileSystemWatcher { this._config += 0b100; } + const parsedPattern = parse(globPattern); + let subscription = dispatcher(events => { if (!ignoreCreateEvents) { for (let created of events.created) { - if (match(globPattern, created.fsPath)) { + if (parsedPattern(created.fsPath)) { this._onDidCreate.fire(created); } } } if (!ignoreChangeEvents) { for (let changed of events.changed) { - if (match(globPattern, changed.fsPath)) { + if (parsedPattern(changed.fsPath)) { this._onDidChange.fire(changed); } } } if (!ignoreDeleteEvents) { for (let deleted of events.deleted) { - if (match(globPattern, deleted.fsPath)) { + if (parsedPattern(deleted.fsPath)) { this._onDidDelete.fire(deleted); } } @@ -94,7 +96,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ constructor() { } - public createFileSystemWatcher(globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): _FileSystemWatcher { + public createFileSystemWatcher(globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): _FileSystemWatcher { return new FileSystemWatcher(this._emitter.event, globPattern, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents); } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 63184e86417..b2fd9b556e1 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -9,22 +9,19 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { mixin } from 'vs/base/common/objects'; import * as vscode from 'vscode'; import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters'; -import { Range, Disposable, CompletionList, CompletionItem, SnippetString } from 'vs/workbench/api/node/extHostTypes'; +import { Range, Disposable, CompletionList, SnippetString, Color } from 'vs/workbench/api/node/extHostTypes'; import { ISingleEditOperation } from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; -import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search'; import { asWinJsPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadTelemetryShape, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IRawColorFormatMap, IMainContext } from './extHost.protocol'; +import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion, IWorkspaceSymbols, IWorkspaceSymbol, IdObject } from './extHost.protocol'; import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; -import { containsCommandLink } from 'vs/base/common/htmlContent'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; -import { once } from 'vs/base/common/functional'; // --- adapter @@ -179,7 +176,6 @@ class HoverAdapter { constructor( private readonly _documents: ExtHostDocuments, private readonly _provider: vscode.HoverProvider, - private readonly _telemetryLog: (name: string, data: object) => void, ) { // } @@ -200,14 +196,7 @@ class HoverAdapter { value.range = new Range(pos, pos); } - const result = TypeConverters.fromHover(value); - - // we wanna know which extension uses command links - // because that is a potential trick-attack on users - if (result.contents.some(h => containsCommandLink(h.value))) { - this._telemetryLog('usesCommandLink', { from: 'hover' }); - } - return result; + return TypeConverters.fromHover(value); }); } } @@ -378,45 +367,56 @@ class OnTypeFormattingAdapter { } } +class NavigateTypeAdapter { -class NavigateTypeAdapter implements IWorkspaceSymbolProvider { + private readonly _symbolCache: { [id: number]: vscode.SymbolInformation } = Object.create(null); + private readonly _resultCache: { [id: number]: [number, number] } = Object.create(null); + private readonly _provider: vscode.WorkspaceSymbolProvider; - private _provider: vscode.WorkspaceSymbolProvider; - private _heapService: ExtHostHeapService; - - constructor(provider: vscode.WorkspaceSymbolProvider, heapService: ExtHostHeapService) { + constructor(provider: vscode.WorkspaceSymbolProvider) { this._provider = provider; - this._heapService = heapService; } - provideWorkspaceSymbols(search: string): TPromise { - + provideWorkspaceSymbols(search: string): TPromise { + const result: IWorkspaceSymbols = IdObject.mixin({ symbols: [] }); return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => { - if (Array.isArray(value)) { - return value.map(item => { - const id = this._heapService.keep(item); - const result = TypeConverters.fromSymbolInformation(item); - return ObjectIdentifier.mixin(result, id); - }); + if (!isFalsyOrEmpty(value)) { + for (const item of value) { + const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item)); + this._symbolCache[symbol._id] = item; + result.symbols.push(symbol); + } } - return undefined; + }).then(() => { + this._resultCache[result._id] = [result.symbols[0]._id, result.symbols[result.symbols.length - 1]._id]; + return result; }); } - resolveWorkspaceSymbol(item: modes.SymbolInformation): TPromise { + resolveWorkspaceSymbol(symbol: IWorkspaceSymbol): TPromise { if (typeof this._provider.resolveWorkspaceSymbol !== 'function') { - return TPromise.as(item); + return TPromise.as(symbol); } - const symbolInfo = this._heapService.get(ObjectIdentifier.of(item)); - if (symbolInfo) { - return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(symbolInfo, token)).then(value => { - return value && TypeConverters.fromSymbolInformation(value); + const item = this._symbolCache[symbol._id]; + if (item) { + return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(item, token)).then(value => { + return value && mixin(symbol, TypeConverters.fromSymbolInformation(value), true); }); } return undefined; } + + releaseWorkspaceSymbols(id: number): any { + const range = this._resultCache[id]; + if (range) { + for (let [from, to] = range; from <= to; from++) { + delete this._symbolCache[from]; + } + delete this._resultCache[id]; + } + } } class RenameAdapter { @@ -447,7 +447,7 @@ class RenameAdapter { let [uri, textEdits] = entry; for (let textEdit of textEdits) { result.edits.push({ - resource: uri, + resource: uri, newText: textEdit.newText, range: TypeConverters.fromRange(textEdit.range) }); @@ -460,8 +460,15 @@ class RenameAdapter { edits: undefined, rejectReason: err }; + } else if (err instanceof Error && typeof err.message === 'string') { + return { + edits: undefined, + rejectReason: err.message + }; + } else { + // generic error + return TPromise.wrapError(err); } - return TPromise.wrapError(err); }); } } @@ -469,26 +476,36 @@ class RenameAdapter { class SuggestAdapter { + static supportsResolving(provider: vscode.CompletionItemProvider): boolean { + return typeof provider.resolveCompletionItem === 'function'; + } + private _documents: ExtHostDocuments; private _commands: CommandsConverter; - private _heapService: ExtHostHeapService; private _provider: vscode.CompletionItemProvider; - constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CompletionItemProvider) { + private _cache = new Map(); + private _idPool = 0; + + constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) { this._documents = documents; this._commands = commands; - this._heapService = heapService; this._provider = provider; } - provideCompletionItems(resource: URI, position: IPosition): TPromise { + provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise { const doc = this._documents.getDocumentData(resource).document; const pos = TypeConverters.toPosition(position); - return asWinJsPromise(token => this._provider.provideCompletionItems(doc, pos, token)).then(value => { + return asWinJsPromise(token => { + return this._provider.provideCompletionItems(doc, pos, token, TypeConverters.CompletionContext.from(context)); + }).then(value => { - const result: modes.ISuggestResult = { + const _id = this._idPool++; + + const result: IExtHostSuggestResult = { + _id, suggestions: [], }; @@ -509,19 +526,15 @@ class SuggestAdapter { const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos)) .with({ end: pos }); - for (const item of list.items) { - - const suggestion = this._convertCompletionItem(item, pos, wordRangeBeforePos); - - // bad completion item - if (!suggestion) { - // converter did warn - continue; + for (let i = 0; i < list.items.length; i++) { + const suggestion = this._convertCompletionItem(list.items[i], pos, wordRangeBeforePos, i, _id); + // check for bad completion item + // for the converter did warn + if (suggestion) { + result.suggestions.push(suggestion); } - - ObjectIdentifier.mixin(suggestion, this._heapService.keep(item)); - result.suggestions.push(suggestion); } + this._cache.set(_id, list.items); return result; }); @@ -533,8 +546,8 @@ class SuggestAdapter { return TPromise.as(suggestion); } - const id = ObjectIdentifier.of(suggestion); - const item = this._heapService.get(id); + const { _parentId, _id } = (suggestion); + const item = this._cache.has(_parentId) && this._cache.get(_parentId)[_id]; if (!item) { return TPromise.as(suggestion); } @@ -548,7 +561,7 @@ class SuggestAdapter { const doc = this._documents.getDocumentData(resource).document; const pos = TypeConverters.toPosition(position); const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos)).with({ end: pos }); - const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos); + const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos, _id, _parentId); if (newSuggestion) { mixin(suggestion, newSuggestion, true); } @@ -557,13 +570,20 @@ class SuggestAdapter { }); } - private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range): modes.ISuggestion { + releaseCompletionItems(id: number): any { + this._cache.delete(id); + } + + private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range, _id: number, _parentId: number): IExtHostSuggestion { if (typeof item.label !== 'string' || item.label.length === 0) { console.warn('INVALID text edit -> must have at least a label'); return undefined; } - const result: modes.ISuggestion = { + const result: IExtHostSuggestion = { + // + _id, + _parentId, // label: item.label, type: TypeConverters.CompletionItemKind.from(item.kind), @@ -693,12 +713,8 @@ class LinkProviderAdapter { class ColorProviderAdapter { - private static _colorFormatHandlePool: number = 0; - constructor( - private _proxy: MainThreadLanguageFeaturesShape, private _documents: ExtHostDocuments, - private _colorFormatCache: Map, private _provider: vscode.DocumentColorProvider ) { } @@ -709,39 +725,25 @@ class ColorProviderAdapter { return []; } - const newRawColorFormats: IRawColorFormatMap = []; - const getFormatId = (format: string) => { - let id = this._colorFormatCache.get(format); - - if (typeof id !== 'number') { - id = ColorProviderAdapter._colorFormatHandlePool++; - this._colorFormatCache.set(format, id); - newRawColorFormats.push([id, format]); - } - - return id; - }; - const colorInfos: IRawColorInfo[] = colors.map(ci => { - const availableFormats = ci.availableFormats.map(format => { - if (typeof format === 'string') { - return getFormatId(format); - } else { - return [getFormatId(format.opaque), getFormatId(format.transparent)] as [number, number]; - } - }); - return { color: [ci.color.red, ci.color.green, ci.color.blue, ci.color.alpha] as [number, number, number, number], - availableFormats: availableFormats, range: TypeConverters.fromRange(ci.range) }; }); - this._proxy.$registerColorFormats(newRawColorFormats); return colorInfos; }); } + + provideColorPresentations(resource: URI, raw: IRawColorInfo): TPromise { + const document = this._documents.getDocumentData(resource).document; + const range = TypeConverters.toRange(raw.range); + const color = new Color(raw.color[0], raw.color[1], raw.color[2], raw.color[3]); + return asWinJsPromise(token => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => { + return value.map(TypeConverters.ColorPresentation.from); + }); + } } type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter @@ -754,13 +756,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { private static _handlePool: number = 0; private _proxy: MainThreadLanguageFeaturesShape; - private _telemetry: MainThreadTelemetryShape; private _documents: ExtHostDocuments; private _commands: ExtHostCommands; private _heapService: ExtHostHeapService; private _diagnostics: ExtHostDiagnostics; private _adapter = new Map(); - private _colorFormatCache = new Map(); constructor( mainContext: IMainContext, @@ -770,7 +770,6 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { diagnostics: ExtHostDiagnostics ) { this._proxy = mainContext.get(MainContext.MainThreadLanguageFeatures); - this._telemetry = mainContext.get(MainContext.MainThreadTelemetry); this._documents = documents; this._commands = commands; this._heapService = heapMonitor; @@ -874,10 +873,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: string): vscode.Disposable { const handle = this._nextHandle(); - this._adapter.set(handle, new HoverAdapter(this._documents, provider, once((name: string, data: any) => { - data['extension'] = extensionId; - this._telemetry.$publicLog(name, data); - }))); + this._adapter.set(handle, new HoverAdapter(this._documents, provider)); this._proxy.$registerHoverProvider(handle, selector); return this._createDisposable(handle); } @@ -964,19 +960,23 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { const handle = this._nextHandle(); - this._adapter.set(handle, new NavigateTypeAdapter(provider, this._heapService)); + this._adapter.set(handle, new NavigateTypeAdapter(provider)); this._proxy.$registerNavigateTypeSupport(handle); return this._createDisposable(handle); } - $provideWorkspaceSymbols(handle: number, search: string): TPromise { + $provideWorkspaceSymbols(handle: number, search: string): TPromise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search)); } - $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise { + $resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol)); } + $releaseWorkspaceSymbols(handle: number, id: number) { + this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.releaseWorkspaceSymbols(id)); + } + // --- rename registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable { @@ -994,19 +994,23 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable { const handle = this._nextHandle(); - this._adapter.set(handle, new SuggestAdapter(this._documents, this._commands.converter, this._heapService, provider)); - this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters); + this._adapter.set(handle, new SuggestAdapter(this._documents, this._commands.converter, provider)); + this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters, SuggestAdapter.supportsResolving(provider)); return this._createDisposable(handle); } - $provideCompletionItems(handle: number, resource: URI, position: IPosition): TPromise { - return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position)); + $provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise { + return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position, context)); } $resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise { return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(resource, position, suggestion)); } + $releaseCompletionItems(handle: number, id: number): void { + this._withAdapter(handle, SuggestAdapter, adapter => adapter.releaseCompletionItems(id)); + } + // --- parameter hints registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, triggerCharacters: string[]): vscode.Disposable { @@ -1039,7 +1043,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable { const handle = this._nextHandle(); - this._adapter.set(handle, new ColorProviderAdapter(this._proxy, this._documents, this._colorFormatCache, provider)); + this._adapter.set(handle, new ColorProviderAdapter(this._documents, provider)); this._proxy.$registerDocumentColorProvider(handle, selector); return this._createDisposable(handle); } @@ -1048,6 +1052,10 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(resource)); } + $provideColorPresentations(handle: number, resource: URI, colorInfo: IRawColorInfo): TPromise { + return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(resource, colorInfo)); + } + // --- configuration setLanguageConfiguration(languageId: string, configuration: vscode.LanguageConfiguration): vscode.Disposable { diff --git a/src/vs/workbench/api/node/extHostMessageService.ts b/src/vs/workbench/api/node/extHostMessageService.ts index 5a4e176f26d..d0698c554bc 100644 --- a/src/vs/workbench/api/node/extHostMessageService.ts +++ b/src/vs/workbench/api/node/extHostMessageService.ts @@ -9,8 +9,7 @@ import vscode = require('vscode'); import { MainContext, MainThreadMessageServiceShape, MainThreadMessageOptions, IMainContext } from './extHost.protocol'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; - -function isMessageItem(item: any): item is vscode.MessageItem { +function isMessageItem(item: any): item is vscode.MessageItem { return item && item.title; } diff --git a/src/vs/workbench/api/node/extHostQuickOpen.ts b/src/vs/workbench/api/node/extHostQuickOpen.ts index edaaf12385d..03672ebf187 100644 --- a/src/vs/workbench/api/node/extHostQuickOpen.ts +++ b/src/vs/workbench/api/node/extHostQuickOpen.ts @@ -5,21 +5,28 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { wireCancellationToken } from 'vs/base/common/async'; +import { wireCancellationToken, asWinJsPromise } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { QuickPickOptions, QuickPickItem, InputBoxOptions } from 'vscode'; +import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder } from 'vscode'; import { MainContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, IMainContext } from './extHost.protocol'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; export type Item = string | QuickPickItem; export class ExtHostQuickOpen implements ExtHostQuickOpenShape { private _proxy: MainThreadQuickOpenShape; - private _onDidSelectItem: (handle: number) => void; - private _validateInput: (input: string) => string; + private _workspace: ExtHostWorkspace; + private _commands: ExtHostCommands; - constructor(mainContext: IMainContext) { + private _onDidSelectItem: (handle: number) => void; + private _validateInput: (input: string) => string | Thenable; + + constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) { this._proxy = mainContext.get(MainContext.MainThreadQuickOpen); + this._workspace = workspace; + this._commands = commands; } showQuickPick(itemsOrItemsPromise: string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; @@ -113,8 +120,20 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { $validateInput(input: string): TPromise { if (this._validateInput) { - return TPromise.as(this._validateInput(input)); + return asWinJsPromise(_ => this._validateInput(input)); } return undefined; } + + // ---- workspace folder picker + + showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions, token = CancellationToken.None): Thenable { + return this._commands.executeCommand('_workbench.pickWorkspaceFolder', [options]).then((selectedFolder: WorkspaceFolder) => { + if (!selectedFolder) { + return undefined; + } + + return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0]; + }); + } } diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index 60b4aee43f9..7ffe2da7829 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -6,13 +6,21 @@ import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import Event, { Emitter } from 'vs/base/common/event'; +import Event, { Emitter, once } from 'vs/base/common/event'; +import { debounce } from 'vs/base/common/decorators'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { asWinJsPromise } from 'vs/base/common/async'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; -import { MainContext, MainThreadSCMShape, SCMRawResource, IMainContext } from './extHost.protocol'; +import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; +import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext } from './extHost.protocol'; +import { sortedDiff } from 'vs/base/common/arrays'; +import { comparePaths } from 'vs/base/common/comparers'; import * as vscode from 'vscode'; +type ProviderHandle = number; +type GroupHandle = number; +type ResourceStateHandle = number; + function getIconPath(decorations: vscode.SourceControlResourceThemableDecorations) { if (!decorations) { return undefined; @@ -24,6 +32,82 @@ function getIconPath(decorations: vscode.SourceControlResourceThemableDecoration return undefined; } +function compareResourceThemableDecorations(a: vscode.SourceControlResourceThemableDecorations, b: vscode.SourceControlResourceThemableDecorations): number { + if (!a.iconPath && !b.iconPath) { + return 0; + } else if (!a.iconPath) { + return -1; + } else if (!b.iconPath) { + return 1; + } + + const aPath = typeof a.iconPath === 'string' ? a.iconPath : a.iconPath.fsPath; + const bPath = typeof b.iconPath === 'string' ? b.iconPath : b.iconPath.fsPath; + return comparePaths(aPath, bPath); +} + +function compareResourceStatesDecorations(a: vscode.SourceControlResourceDecorations, b: vscode.SourceControlResourceDecorations): number { + let result = 0; + + if (a.strikeThrough !== b.strikeThrough) { + return a.strikeThrough ? 1 : -1; + } + + if (a.faded !== b.faded) { + return a.faded ? 1 : -1; + } + + if (a.tooltip !== b.tooltip) { + return (a.tooltip || '').localeCompare(b.tooltip); + } + + result = compareResourceThemableDecorations(a, b); + + if (result !== 0) { + return result; + } + + if (a.light && b.light) { + result = compareResourceThemableDecorations(a.light, b.light); + } else if (a.light) { + return 1; + } else if (b.light) { + return -1; + } + + if (result !== 0) { + return result; + } + + if (a.dark && b.dark) { + result = compareResourceThemableDecorations(a.dark, b.dark); + } else if (a.dark) { + return 1; + } else if (b.dark) { + return -1; + } + + return result; +} + +function compareResourceStates(a: vscode.SourceControlResourceState, b: vscode.SourceControlResourceState): number { + let result = comparePaths(a.resourceUri.fsPath, b.resourceUri.fsPath); + + if (result !== 0) { + return result; + } + + if (a.decorations && b.decorations) { + result = compareResourceStatesDecorations(a.decorations, b.decorations); + } else if (a.decorations) { + return 1; + } else if (b.decorations) { + return -1; + } + + return result; +} + export class ExtHostSCMInputBox { private _value: string = ''; @@ -43,6 +127,17 @@ export class ExtHostSCMInputBox { return this._onDidChange.event; } + private _placeholder: string = ''; + + get placeholder(): string { + return this._placeholder; + } + + set placeholder(placeholder: string) { + this._proxy.$setInputBoxPlaceholder(this._sourceControlHandle, placeholder); + this._placeholder = placeholder; + } + constructor(private _proxy: MainThreadSCMShape, private _sourceControlHandle: number) { // noop } @@ -62,99 +157,135 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG private static _handlePool: number = 0; private _resourceHandlePool: number = 0; private _resourceStates: vscode.SourceControlResourceState[] = []; + private _resourceStatesRollingDisposables: { (): void }[] = []; private _resourceStatesMap: Map = new Map(); + private _resourceStatesCommandsMap: Map = new Map(); - get id(): string { - return this._id; - } + private _onDidUpdateResourceStates = new Emitter(); + readonly onDidUpdateResourceStates = this._onDidUpdateResourceStates.event; + private _onDidDispose = new Emitter(); + readonly onDidDispose = this._onDidDispose.event; - get label(): string { - return this._label; - } + private _handlesSnapshot: number[] = []; + private _resourceSnapshot: vscode.SourceControlResourceState[] = []; + get id(): string { return this._id; } + + get label(): string { return this._label; } set label(label: string) { this._label = label; - this._proxy.$updateGroupLabel(this._sourceControlHandle, this._handle, label); + this._proxy.$updateGroupLabel(this._sourceControlHandle, this.handle, label); } private _hideWhenEmpty: boolean | undefined = undefined; - - get hideWhenEmpty(): boolean | undefined { - return this._hideWhenEmpty; - } - + get hideWhenEmpty(): boolean | undefined { return this._hideWhenEmpty; } set hideWhenEmpty(hideWhenEmpty: boolean | undefined) { this._hideWhenEmpty = hideWhenEmpty; - this._proxy.$updateGroup(this._sourceControlHandle, this._handle, { hideWhenEmpty }); - } - - get resourceStates(): vscode.SourceControlResourceState[] { - return [...this._resourceStates]; + this._proxy.$updateGroup(this._sourceControlHandle, this.handle, { hideWhenEmpty }); } + get resourceStates(): vscode.SourceControlResourceState[] { return [...this._resourceStates]; } set resourceStates(resources: vscode.SourceControlResourceState[]) { this._resourceStates = [...resources]; - - const handles: number[] = []; - const rawResources = resources.map(r => { - const handle = this._resourceHandlePool++; - this._resourceStatesMap.set(handle, r); - handles.push(handle); - - const sourceUri = r.resourceUri.toString(); - const command = this._commands.toInternal(r.command); - const iconPath = getIconPath(r.decorations); - const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath; - const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath; - const icons: string[] = []; - - if (lightIconPath || darkIconPath) { - icons.push(lightIconPath); - } - - if (darkIconPath !== lightIconPath) { - icons.push(darkIconPath); - } - - const tooltip = (r.decorations && r.decorations.tooltip) || ''; - const strikeThrough = r.decorations && !!r.decorations.strikeThrough; - const faded = r.decorations && !!r.decorations.faded; - - return [handle, sourceUri, command, icons, tooltip, strikeThrough, faded] as SCMRawResource; - }); - - const disposable = () => handles.forEach(handle => this._resourceStatesMap.delete(handle)); - this._resourceStatesRollingDisposables.push(disposable); - - while (this._resourceStatesRollingDisposables.length >= 10) { - this._resourceStatesRollingDisposables.shift()(); - } - - this._proxy.$updateGroupResourceStates(this._sourceControlHandle, this._handle, rawResources); + this._onDidUpdateResourceStates.fire(); } - private _handle: GroupHandle = ExtHostSourceControlResourceGroup._handlePool++; - get handle(): GroupHandle { - return this._handle; - } + readonly handle = ExtHostSourceControlResourceGroup._handlePool++; + private _disposables: IDisposable[] = []; constructor( private _proxy: MainThreadSCMShape, - private _commands: CommandsConverter, + private _commands: ExtHostCommands, private _sourceControlHandle: number, private _id: string, private _label: string, ) { - this._proxy.$registerGroup(_sourceControlHandle, this._handle, _id, _label); + this._proxy.$registerGroup(_sourceControlHandle, this.handle, _id, _label); } getResourceState(handle: number): vscode.SourceControlResourceState | undefined { return this._resourceStatesMap.get(handle); } + async $executeResourceCommand(handle: number): TPromise { + const command = this._resourceStatesCommandsMap.get(handle); + + if (!command) { + return; + } + + await this._commands.executeCommand(command.command, ...command.arguments); + } + + _takeResourceStateSnapshot(): SCMRawResourceSplice[] { + const snapshot = [...this._resourceStates].sort(compareResourceStates); + const diffs = sortedDiff(this._resourceSnapshot, snapshot, compareResourceStates); + const handlesToDelete: number[] = []; + + const splices = diffs.map(diff => { + const { start, deleteCount } = diff; + const handles: number[] = []; + + const rawResources = diff.inserted + .map(r => { + const handle = this._resourceHandlePool++; + this._resourceStatesMap.set(handle, r); + handles.push(handle); + + const sourceUri = r.resourceUri.toString(); + const iconPath = getIconPath(r.decorations); + const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath; + const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath; + const icons: string[] = []; + + if (r.command) { + this._resourceStatesCommandsMap.set(handle, r.command); + } + + if (lightIconPath || darkIconPath) { + icons.push(lightIconPath); + } + + if (darkIconPath !== lightIconPath) { + icons.push(darkIconPath); + } + + const tooltip = (r.decorations && r.decorations.tooltip) || ''; + const strikeThrough = r.decorations && !!r.decorations.strikeThrough; + const faded = r.decorations && !!r.decorations.faded; + + const source = r.decorations && r.decorations.source || undefined; + const letter = r.decorations && r.decorations.letter || undefined; + const color = r.decorations && r.decorations.color || undefined; + + return [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource; + }); + + handlesToDelete.push(...this._handlesSnapshot.splice(start, deleteCount, ...handles)); + + return [start, deleteCount, rawResources] as SCMRawResourceSplice; + }); + + const disposable = () => handlesToDelete.forEach(handle => { + this._resourceStatesMap.delete(handle); + this._resourceStatesCommandsMap.delete(handle); + }); + + this._resourceStatesRollingDisposables.push(disposable); + + while (this._resourceStatesRollingDisposables.length >= 10) { + this._resourceStatesRollingDisposables.shift()(); + } + + this._resourceSnapshot = snapshot; + return splices; + } + dispose(): void { - this._proxy.$unregisterGroup(this._sourceControlHandle, this._handle); + this._proxy.$unregisterGroup(this._sourceControlHandle, this.handle); + this._disposables = dispose(this._disposables); + this._onDidDispose.fire(); } } @@ -171,6 +302,10 @@ class ExtHostSourceControl implements vscode.SourceControl { return this._label; } + get rootUri(): vscode.Uri | undefined { + return this._rootUri; + } + private _inputBox: ExtHostSCMInputBox; get inputBox(): ExtHostSCMInputBox { return this._inputBox; } @@ -182,7 +317,7 @@ class ExtHostSourceControl implements vscode.SourceControl { set count(count: number | undefined) { this._count = count; - this._proxy.$updateSourceControl(this._handle, { count }); + this._proxy.$updateSourceControl(this.handle, { count }); } private _quickDiffProvider: vscode.QuickDiffProvider | undefined = undefined; @@ -193,7 +328,7 @@ class ExtHostSourceControl implements vscode.SourceControl { set quickDiffProvider(quickDiffProvider: vscode.QuickDiffProvider | undefined) { this._quickDiffProvider = quickDiffProvider; - this._proxy.$updateSourceControl(this._handle, { hasQuickDiffProvider: !!quickDiffProvider }); + this._proxy.$updateSourceControl(this.handle, { hasQuickDiffProvider: !!quickDiffProvider }); } private _commitTemplate: string | undefined = undefined; @@ -204,7 +339,7 @@ class ExtHostSourceControl implements vscode.SourceControl { set commitTemplate(commitTemplate: string | undefined) { this._commitTemplate = commitTemplate; - this._proxy.$updateSourceControl(this._handle, { commitTemplate }); + this._proxy.$updateSourceControl(this.handle, { commitTemplate }); } private _acceptInputCommand: vscode.Command | undefined = undefined; @@ -216,8 +351,8 @@ class ExtHostSourceControl implements vscode.SourceControl { set acceptInputCommand(acceptInputCommand: vscode.Command | undefined) { this._acceptInputCommand = acceptInputCommand; - const internal = this._commands.toInternal(acceptInputCommand); - this._proxy.$updateSourceControl(this._handle, { acceptInputCommand: internal }); + const internal = this._commands.converter.toInternal(acceptInputCommand); + this._proxy.$updateSourceControl(this.handle, { acceptInputCommand: internal }); } private _statusBarCommands: vscode.Command[] | undefined = undefined; @@ -229,41 +364,74 @@ class ExtHostSourceControl implements vscode.SourceControl { set statusBarCommands(statusBarCommands: vscode.Command[] | undefined) { this._statusBarCommands = statusBarCommands; - const internal = (statusBarCommands || []).map(c => this._commands.toInternal(c)); - this._proxy.$updateSourceControl(this._handle, { statusBarCommands: internal }); + const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal(c)); + this._proxy.$updateSourceControl(this.handle, { statusBarCommands: internal }); } - private _handle: number = ExtHostSourceControl._handlePool++; + private handle: number = ExtHostSourceControl._handlePool++; constructor( private _proxy: MainThreadSCMShape, - private _commands: CommandsConverter, + private _commands: ExtHostCommands, private _id: string, private _label: string, + private _rootUri?: vscode.Uri ) { - this._inputBox = new ExtHostSCMInputBox(this._proxy, this._handle); - this._proxy.$registerSourceControl(this._handle, _id, _label); + this._inputBox = new ExtHostSCMInputBox(this._proxy, this.handle); + this._proxy.$registerSourceControl(this.handle, _id, _label, _rootUri && _rootUri.toString()); } + private updatedResourceGroups = new Set(); + createResourceGroup(id: string, label: string): ExtHostSourceControlResourceGroup { - const group = new ExtHostSourceControlResourceGroup(this._proxy, this._commands, this._handle, id, label); + const group = new ExtHostSourceControlResourceGroup(this._proxy, this._commands, this.handle, id, label); + + const updateListener = group.onDidUpdateResourceStates(() => { + this.updatedResourceGroups.add(group); + this.eventuallyUpdateResourceStates(); + }); + + once(group.onDidDispose)(() => { + this.updatedResourceGroups.delete(group); + updateListener.dispose(); + this._groups.delete(group.handle); + }); + this._groups.set(group.handle, group); return group; } + @debounce(100) + eventuallyUpdateResourceStates(): void { + const splices: SCMRawResourceSplices[] = []; + + this.updatedResourceGroups.forEach(group => { + const snapshot = group._takeResourceStateSnapshot(); + + if (snapshot.length === 0) { + return; + } + + splices.push([group.handle, snapshot]); + }); + + if (splices.length > 0) { + this._proxy.$spliceResourceStates(this.handle, splices); + } + + this.updatedResourceGroups.clear(); + } + getResourceGroup(handle: GroupHandle): ExtHostSourceControlResourceGroup | undefined { return this._groups.get(handle); } dispose(): void { - this._proxy.$unregisterSourceControl(this._handle); + this._groups.forEach(group => group.dispose()); + this._proxy.$unregisterSourceControl(this.handle); } } -type ProviderHandle = number; -type GroupHandle = number; -type ResourceStateHandle = number; - export class ExtHostSCM { private static _handlePool: number = 0; @@ -320,9 +488,9 @@ export class ExtHostSCM { }); } - createSourceControl(extension: IExtensionDescription, id: string, label: string): vscode.SourceControl { + createSourceControl(extension: IExtensionDescription, id: string, label: string, rootUri: vscode.Uri | undefined): vscode.SourceControl { const handle = ExtHostSCM._handlePool++; - const sourceControl = new ExtHostSourceControl(this._proxy, this._commands.converter, id, label); + const sourceControl = new ExtHostSourceControl(this._proxy, this._commands, id, label, rootUri); this._sourceControls.set(handle, sourceControl); const sourceControls = this._sourceControlsByExtension.get(extension.id) || []; @@ -357,11 +525,27 @@ export class ExtHostSCM { $onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise { const sourceControl = this._sourceControls.get(sourceControlHandle); - if (!sourceControl || !sourceControl.quickDiffProvider) { + if (!sourceControl) { return TPromise.as(null); } sourceControl.inputBox.$onInputBoxValueChange(value); return TPromise.as(null); } + + async $executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise { + const sourceControl = this._sourceControls.get(sourceControlHandle); + + if (!sourceControl) { + return; + } + + const group = sourceControl.getResourceGroup(groupHandle); + + if (!group) { + return; + } + + await group.$executeResourceCommand(handle); + } } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index a174c82f1b7..09538e65693 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import URI from 'vs/base/common/uri'; import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import * as Objects from 'vs/base/common/objects'; @@ -15,11 +16,9 @@ import * as TaskSystem from 'vs/workbench/parts/tasks/common/tasks'; import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol'; import * as types from 'vs/workbench/api/node/extHostTypes'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import * as vscode from 'vscode'; -interface StringMap { - [key: string]: V; -} /* namespace ProblemPattern { @@ -116,7 +115,7 @@ namespace FileLocation { case types.FileLocationKind.Absolute: return { kind: Problems.FileLocationKind.Absolute }; case types.FileLocationKind.Relative: - return { kind: Problems.FileLocationKind.Relative, prefix: '${workspaceRoot}' }; + return { kind: Problems.FileLocationKind.Relative, prefix: '${workspaceFolder}' }; } return { kind: Problems.FileLocationKind.Auto }; } @@ -295,13 +294,13 @@ namespace ShellConfiguration { namespace Tasks { - export function from(tasks: vscode.Task[], extension: IExtensionDescription): TaskSystem.Task[] { + export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.Task[] { if (tasks === void 0 || tasks === null) { return []; } let result: TaskSystem.Task[] = []; for (let task of tasks) { - let converted = fromSingle(task, extension); + let converted = fromSingle(task, rootFolder, extension); if (converted) { result.push(converted); } @@ -309,7 +308,7 @@ namespace Tasks { return result; } - function fromSingle(task: vscode.Task, extension: IExtensionDescription): TaskSystem.ContributedTask { + function fromSingle(task: vscode.Task, rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.ContributedTask { if (typeof task.name !== 'string') { return undefined; } @@ -326,11 +325,33 @@ namespace Tasks { return undefined; } command.presentation = PresentationOptions.from(task.presentationOptions); - let source = { + + let taskScope: types.TaskScope.Global | types.TaskScope.Workspace | vscode.WorkspaceFolder | undefined = task.scope; + let workspaceFolder: vscode.WorkspaceFolder | undefined; + let scope: TaskSystem.TaskScope; + // For backwards compatibility + if (taskScope === void 0) { + scope = TaskSystem.TaskScope.Folder; + workspaceFolder = rootFolder; + } else if (taskScope === types.TaskScope.Global) { + scope = TaskSystem.TaskScope.Global; + } else if (taskScope === types.TaskScope.Workspace) { + scope = TaskSystem.TaskScope.Workspace; + } else { + scope = TaskSystem.TaskScope.Folder; + workspaceFolder = taskScope; + } + let source: TaskSystem.ExtensionTaskSource = { kind: TaskSystem.TaskSourceKind.Extension, label: typeof task.source === 'string' ? task.source : extension.name, - extension: extension.id + extension: extension.id, + scope: scope, + workspaceFolder: undefined }; + // We can't transfer a workspace folder object from the extension host to main since they differ + // in shape and we don't have backwards converting function. So transfer the URI and resolve the + // workspace folder on the main side. + (source as any).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined; let label = nls.localize('task.label', '{0}: {1}', source.label, task.name); let key = (task as types.Task).definitionKey; let kind = (task as types.Task).definition; @@ -398,14 +419,16 @@ interface HandlerData { export class ExtHostTask implements ExtHostTaskShape { private _proxy: MainThreadTaskShape; + private _extHostWorkspace: ExtHostWorkspace; private _handleCounter: number; private _handlers: Map; - constructor(mainContext: IMainContext) { + constructor(mainContext: IMainContext, extHostWorkspace: ExtHostWorkspace) { this._proxy = mainContext.get(MainContext.MainThreadTask); + this._extHostWorkspace = extHostWorkspace; this._handleCounter = 0; this._handlers = new Map(); - }; + } public registerTaskProvider(extension: IExtensionDescription, provider: vscode.TaskProvider): vscode.Disposable { if (!provider) { @@ -426,8 +449,9 @@ export class ExtHostTask implements ExtHostTaskShape { return TPromise.wrapError(new Error('no handler found')); } return asWinJsPromise(token => handler.provider.provideTasks(token)).then(value => { + let workspaceFolders = this._extHostWorkspace.getWorkspaceFolders(); return { - tasks: Tasks.from(value, handler.extension), + tasks: Tasks.from(value, workspaceFolders && workspaceFolders.length > 0 ? workspaceFolders[0] : undefined, handler.extension), extension: handler.extension }; }); @@ -436,4 +460,4 @@ export class ExtHostTask implements ExtHostTaskShape { private nextHandle(): number { return this._handleCounter++; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index e42fc83d1f6..dd7e1c10b60 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -24,6 +24,7 @@ export class ExtHostTerminal implements vscode.Terminal { name?: string, shellPath?: string, shellArgs?: string[], + env?: { [key: string]: string }, waitOnExit?: boolean ) { this._name = name; @@ -32,7 +33,7 @@ export class ExtHostTerminal implements vscode.Terminal { this._pidPromise = new TPromise(c => { this._pidPromiseComplete = c; }); - this._proxy.$createTerminal(name, shellPath, shellArgs, waitOnExit).then((id) => { + this._proxy.$createTerminal(name, shellPath, shellArgs, env, waitOnExit).then((id) => { this._id = id; this._queuedRequests.forEach((r) => { r.run(this._proxy, this._id); @@ -113,7 +114,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { } public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal { - let terminal = new ExtHostTerminal(this._proxy, options.name, options.shellPath, options.shellArgs/*, options.waitOnExit*/); + let terminal = new ExtHostTerminal(this._proxy, options.name, options.shellPath, options.shellArgs, options.env/*, options.waitOnExit*/); this._terminals.push(terminal); return terminal; } @@ -134,7 +135,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { public $acceptTerminalProcessId(id: number, processId: number): void { let terminal = this._getTerminalById(id); - terminal._setProcessId(processId); + if (terminal) { + terminal._setProcessId(processId); + } } private _getTerminalById(id: number): ExtHostTerminal { diff --git a/src/vs/workbench/api/node/extHostTextEditor.ts b/src/vs/workbench/api/node/extHostTextEditor.ts index a3e9c45edae..9872ac721fd 100644 --- a/src/vs/workbench/api/node/extHostTextEditor.ts +++ b/src/vs/workbench/api/node/extHostTextEditor.ts @@ -6,19 +6,17 @@ import { ok } from 'vs/base/common/assert'; -import { readonly, illegalArgument, V8CallSite } from 'vs/base/common/errors'; +import { readonly, illegalArgument } from 'vs/base/common/errors'; import { IdGenerator } from 'vs/base/common/idGenerator'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData'; import { Selection, Range, Position, EndOfLine, TextEditorRevealType, TextEditorLineNumbersStyle, SnippetString } from './extHostTypes'; import { ISingleEditOperation } from 'vs/editor/common/editorCommon'; import * as TypeConverters from './extHostTypeConverters'; -import { MainThreadEditorsShape, MainThreadTelemetryShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from './extHost.protocol'; +import { MainThreadEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from './extHost.protocol'; import * as vscode from 'vscode'; import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; import { IRange } from 'vs/editor/common/core/range'; -import { containsCommandLink } from 'vs/base/common/htmlContent'; -import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; export class TextEditorDecorationType implements vscode.TextEditorDecorationType { @@ -418,11 +416,29 @@ export class ExtHostTextEditor implements vscode.TextEditor { setDecorations(decorationType: vscode.TextEditorDecorationType, ranges: Range[] | vscode.DecorationOptions[]): void { this._runOnProxy( - () => this._proxy.$trySetDecorations( - this._id, - decorationType.key, - TypeConverters.fromRangeOrRangeWithMessage(ranges) - ) + () => { + if (TypeConverters.isDecorationOptionsArr(ranges)) { + return this._proxy.$trySetDecorations( + this._id, + decorationType.key, + TypeConverters.fromRangeOrRangeWithMessage(ranges) + ); + } else { + let _ranges: number[] = new Array(4 * ranges.length); + for (let i = 0, len = ranges.length; i < len; i++) { + const range = ranges[i]; + _ranges[4 * i] = range.start.line + 1; + _ranges[4 * i + 1] = range.start.character + 1; + _ranges[4 * i + 2] = range.end.line + 1; + _ranges[4 * i + 3] = range.end.character + 1; + } + return this._proxy.$trySetDecorationsFast( + this._id, + decorationType.key, + /*TODO: marshaller is too slow*/JSON.stringify(_ranges) + ); + } + } ); } @@ -552,70 +568,6 @@ export class ExtHostTextEditor implements vscode.TextEditor { } } -export class ExtHostTextEditor2 extends ExtHostTextEditor { - - constructor( - private readonly _extHostExtensions: ExtHostExtensionService, - private readonly _mainThreadTelemetry: MainThreadTelemetryShape, - proxy: MainThreadEditorsShape, - id: string, - document: ExtHostDocumentData, - selections: Selection[], - options: IResolvedTextEditorConfiguration, - viewColumn: vscode.ViewColumn - ) { - super(proxy, id, document, selections, options, viewColumn); - } - - setDecorations(decorationType: vscode.TextEditorDecorationType, rangesOrOptions: Range[] | vscode.DecorationOptions[]): void { - // (1) find out if this decoration is important for us - let usesCommandLink = false; - outer: for (const rangeOrOption of rangesOrOptions) { - if (Range.isRange(rangeOrOption)) { - break; - } - if (typeof rangeOrOption.hoverMessage === 'string' && containsCommandLink(rangeOrOption.hoverMessage)) { - usesCommandLink = true; - break; - } else if (Array.isArray(rangeOrOption.hoverMessage)) { - for (const message of rangeOrOption.hoverMessage) { - if (typeof message === 'string' && containsCommandLink(message)) { - usesCommandLink = true; - break outer; - } - } - } - } - // (2) send event for important decorations - if (usesCommandLink) { - let tag = new Error(); - this._extHostExtensions.getExtensionPathIndex().then(index => { - const oldHandler = (Error).prepareStackTrace; - (Error).prepareStackTrace = (error: Error, stackTrace: V8CallSite[]) => { - for (const call of stackTrace) { - const extension = index.findSubstr(call.getFileName()); - if (extension) { - this._mainThreadTelemetry.$publicLog('usesCommandLink', { - extension: extension.id, - from: 'decoration', - }); - return; - } - } - }; - // it all happens here... - // tslint:disable-next-line:no-unused-expression - tag.stack; - (Error).prepareStackTrace = oldHandler; - }); - } - - // (3) do it - super.setDecorations(decorationType, rangesOrOptions); - } -} - - function warnOnError(promise: TPromise): void { promise.then(null, (err) => { console.warn(err); diff --git a/src/vs/workbench/api/node/extHostTextEditors.ts b/src/vs/workbench/api/node/extHostTextEditors.ts index e820774046d..d3ca9b8edc8 100644 --- a/src/vs/workbench/api/node/extHostTextEditors.ts +++ b/src/vs/workbench/api/node/extHostTextEditors.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { toThenable } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -13,7 +12,7 @@ import * as TypeConverters from './extHostTypeConverters'; import { TextEditorDecorationType, ExtHostTextEditor } from './extHostTextEditor'; import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors'; import { Position as EditorPosition } from 'vs/platform/editor/common/editor'; -import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext } from './extHost.protocol'; +import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext, IWorkspaceResourceEdit } from './extHost.protocol'; import * as vscode from 'vscode'; export class ExtHostEditors implements ExtHostEditorsShape { @@ -77,7 +76,7 @@ export class ExtHostEditors implements ExtHostEditorsShape { }; } - return this._proxy.$tryShowTextDocument(document.uri, options).then(id => { + return this._proxy.$tryShowTextDocument(document.uri, options).then(id => { let editor = this._extHostDocumentsAndEditors.getEditor(id); if (editor) { return editor; @@ -91,6 +90,40 @@ export class ExtHostEditors implements ExtHostEditorsShape { return new TextEditorDecorationType(this._proxy, options); } + applyWorkspaceEdit(edit: vscode.WorkspaceEdit): TPromise { + + let workspaceResourceEdits: IWorkspaceResourceEdit[] = []; + + let entries = edit.entries(); + for (let entry of entries) { + let [uri, edits] = entry; + + let doc = this._extHostDocumentsAndEditors.getDocument(uri.toString()); + let docVersion: number = undefined; + if (doc) { + docVersion = doc.version; + } + + let workspaceResourceEdit: IWorkspaceResourceEdit = { + resource: uri, + modelVersionId: docVersion, + edits: [] + }; + + for (let edit of edits) { + workspaceResourceEdit.edits.push({ + newText: edit.newText, + newEol: TypeConverters.EndOfLine.from(edit.newEol), + range: edit.range && TypeConverters.fromRange(edit.range) + }); + } + + workspaceResourceEdits.push(workspaceResourceEdit); + } + + return this._proxy.$tryApplyWorkspaceEdit(workspaceResourceEdits); + } + // --- called from main thread $acceptOptionsChanged(id: string, opts: IResolvedTextEditorConfiguration): void { diff --git a/src/vs/workbench/api/node/extHostTreeViews.ts b/src/vs/workbench/api/node/extHostTreeViews.ts index 39cf34468be..71789d1563c 100644 --- a/src/vs/workbench/api/node/extHostTreeViews.ts +++ b/src/vs/workbench/api/node/extHostTreeViews.ts @@ -12,7 +12,7 @@ import { debounceEvent } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/base/common/lifecycle'; import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol'; -import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/parts/views/common/views'; +import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/common/views'; import { TreeItemCollapsibleState } from './extHostTypes'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { asWinJsPromise } from 'vs/base/common/async'; diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index b44a1355eae..ed56a19b30f 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -115,6 +115,8 @@ export function fromViewColumn(column?: vscode.ViewColumn): EditorPosition { editorColumn = EditorPosition.TWO; } else if (column === types.ViewColumn.Three) { editorColumn = EditorPosition.THREE; + } else if (column === types.ViewColumn.Active) { + editorColumn = undefined; } return editorColumn; } @@ -137,7 +139,7 @@ function isDecorationOptions(something: any): something is vscode.DecorationOpti return (typeof something.range !== 'undefined'); } -function isDecorationOptionsArr(something: vscode.Range[] | vscode.DecorationOptions[]): something is vscode.DecorationOptions[] { +export function isDecorationOptionsArr(something: vscode.Range[] | vscode.DecorationOptions[]): something is vscode.DecorationOptions[] { if (something.length === 0) { return true; } @@ -156,7 +158,7 @@ export namespace MarkdownString { } function isCodeblock(thing: any): thing is Codeblock { - return typeof thing === 'object' + return thing && typeof thing === 'object' && typeof (thing).language === 'string' && typeof (thing).value === 'string'; } @@ -168,7 +170,7 @@ export namespace MarkdownString { } else if (htmlContent.isMarkdownString(markup)) { return markup; } else if (typeof markup === 'string') { - return { value: markup, isTrusted: true }; + return { value: markup }; } else { return { value: '' }; } @@ -178,6 +180,13 @@ export namespace MarkdownString { ret.isTrusted = value.isTrusted; return ret; } + + export function fromStrict(value: string | types.MarkdownString): undefined | string | htmlContent.IMarkdownString { + if (!value) { + return undefined; + } + return typeof value === 'string' ? value : MarkdownString.from(value); + } } export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.DecorationOptions[]): IDecorationOptions[] { @@ -282,7 +291,7 @@ export const location = { from(value: vscode.Location): modes.Location { return { range: value.range && fromRange(value.range), - uri: value.uri + uri: value.uri }; }, to(value: modes.Location): types.Location { @@ -305,6 +314,28 @@ export function toDocumentHighlight(occurrence: modes.DocumentHighlight): types. return new types.DocumentHighlight(toRange(occurrence.range), occurrence.kind); } +export namespace CompletionTriggerKind { + export function from(kind: modes.SuggestTriggerKind) { + switch (kind) { + case modes.SuggestTriggerKind.TriggerCharacter: + return types.CompletionTriggerKind.TriggerCharacter; + + case modes.SuggestTriggerKind.Invoke: + default: + return types.CompletionTriggerKind.Invoke; + } + } +} + +export namespace CompletionContext { + export function from(context: modes.SuggestContext): types.CompletionContext { + return { + triggerKind: CompletionTriggerKind.from(context.triggerKind), + triggerCharacter: context.triggerCharacter + }; + } +} + export const CompletionItemKind = { from(kind: types.CompletionItemKind): modes.SuggestionType { @@ -354,7 +385,7 @@ export namespace Suggest { result.insertText = suggestion.insertText; result.kind = CompletionItemKind.to(suggestion.type); result.detail = suggestion.detail; - result.documentation = suggestion.documentation; + result.documentation = htmlContent.isMarkdownString(suggestion.documentation) ? MarkdownString.to(suggestion.documentation) : suggestion.documentation; result.sortText = suggestion.sortText; result.filterText = suggestion.filterText; @@ -379,16 +410,58 @@ export namespace Suggest { return result; } -}; +} + +export namespace ParameterInformation { + export function from(info: types.ParameterInformation): modes.ParameterInformation { + return { + label: info.label, + documentation: MarkdownString.fromStrict(info.documentation) + }; + } + export function to(info: modes.ParameterInformation): types.ParameterInformation { + return { + label: info.label, + documentation: htmlContent.isMarkdownString(info.documentation) ? MarkdownString.to(info.documentation) : info.documentation + }; + } +} + +export namespace SignatureInformation { + + export function from(info: types.SignatureInformation): modes.SignatureInformation { + return { + label: info.label, + documentation: MarkdownString.fromStrict(info.documentation), + parameters: info.parameters && info.parameters.map(ParameterInformation.from) + }; + } + + export function to(info: modes.SignatureInformation): types.SignatureInformation { + return { + label: info.label, + documentation: htmlContent.isMarkdownString(info.documentation) ? MarkdownString.to(info.documentation) : info.documentation, + parameters: info.parameters && info.parameters.map(ParameterInformation.to) + }; + } +} export namespace SignatureHelp { - export function from(signatureHelp: types.SignatureHelp): modes.SignatureHelp { - return signatureHelp; + export function from(help: types.SignatureHelp): modes.SignatureHelp { + return { + activeSignature: help.activeSignature, + activeParameter: help.activeParameter, + signatures: help.signatures && help.signatures.map(SignatureInformation.from) + }; } - export function to(hints: modes.SignatureHelp): types.SignatureHelp { - return hints; + export function to(help: modes.SignatureHelp): types.SignatureHelp { + return { + activeSignature: help.activeSignature, + activeParameter: help.activeParameter, + signatures: help.signatures && help.signatures.map(SignatureInformation.to) + }; } } @@ -406,6 +479,24 @@ export namespace DocumentLink { } } +export namespace ColorPresentation { + export function to(colorPresentation: modes.IColorPresentation): vscode.ColorPresentation { + return { + label: colorPresentation.label, + textEdit: colorPresentation.textEdit ? TextEdit.to(colorPresentation.textEdit) : undefined, + additionalTextEdits: colorPresentation.additionalTextEdits ? colorPresentation.additionalTextEdits.map(value => TextEdit.to(value)) : undefined + }; + } + + export function from(colorPresentation: vscode.ColorPresentation): modes.IColorPresentation { + return { + label: colorPresentation.label, + textEdit: colorPresentation.textEdit ? TextEdit.from(colorPresentation.textEdit) : undefined, + additionalTextEdits: colorPresentation.additionalTextEdits ? colorPresentation.additionalTextEdits.map(value => TextEdit.from(value)) : undefined + }; + } +} + export namespace TextDocumentSaveReason { export function to(reason: SaveReason): vscode.TextDocumentSaveReason { diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 980d89b0c0e..2ce4bbaa1db 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -7,10 +7,10 @@ import * as crypto from 'crypto'; import URI from 'vs/base/common/uri'; -import { Color as BaseColor, HSLA } from 'vs/base/common/color'; import { illegalArgument } from 'vs/base/common/errors'; import * as vscode from 'vscode'; import { isMarkdownString } from 'vs/base/common/htmlContent'; +import { IRelativePattern } from 'vs/base/common/glob'; export class Disposable { @@ -794,7 +794,7 @@ export class SymbolInformation { if (locationOrUri instanceof Location) { this.location = locationOrUri; } else if (rangeOrContainer instanceof Range) { - this.location = new Location(locationOrUri, rangeOrContainer); + this.location = new Location(locationOrUri, rangeOrContainer); } } @@ -824,12 +824,42 @@ export class CodeLens { } } +export class MarkdownString { + + value: string; + isTrusted?: boolean; + + constructor(value?: string) { + this.value = value || ''; + } + + appendText(value: string): MarkdownString { + // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash + this.value += value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&'); + return this; + } + + appendMarkdown(value: string): MarkdownString { + this.value += value; + return this; + } + + appendCodeblock(code: string, language: string = ''): MarkdownString { + this.value += '\n```'; + this.value += language; + this.value += '\n'; + this.value += code; + this.value += '\n```\n'; + return this; + } +} + export class ParameterInformation { label: string; - documentation?: string; + documentation?: string | MarkdownString; - constructor(label: string, documentation?: string) { + constructor(label: string, documentation?: string | MarkdownString) { this.label = label; this.documentation = documentation; } @@ -838,10 +868,10 @@ export class ParameterInformation { export class SignatureInformation { label: string; - documentation?: string; + documentation?: string | MarkdownString; parameters: ParameterInformation[]; - constructor(label: string, documentation?: string) { + constructor(label: string, documentation?: string | MarkdownString) { this.label = label; this.documentation = documentation; this.parameters = []; @@ -859,6 +889,16 @@ export class SignatureHelp { } } +export enum CompletionTriggerKind { + Invoke = 0, + TriggerCharacter = 1 +} + +export interface CompletionContext { + triggerKind: CompletionTriggerKind; + triggerCharacter: string; +} + export enum CompletionItemKind { Text = 0, Method = 1, @@ -892,7 +932,7 @@ export class CompletionItem { label: string; kind: CompletionItemKind; detail: string; - documentation: string; + documentation: string | MarkdownString; sortText: string; filterText: string; insertText: string | SnippetString; @@ -933,6 +973,7 @@ export class CompletionList { } export enum ViewColumn { + Active = -1, One = 1, Two = 2, Three = 3 @@ -1031,47 +1072,46 @@ export class Color { this.blue = blue; this.alpha = alpha; } - - static fromHSLA(hue: number, saturation: number, luminance: number, alpha: number): Color { - const color = new BaseColor(new HSLA(hue, saturation, luminance, alpha)).rgba; - return new Color(color.r, color.g, color.b, color.a); - } - - static fromHex(hex: string): Color | null { - let baseColor = BaseColor.Format.CSS.parseHex(hex); - if (baseColor) { - const rgba = baseColor.rgba; - return new Color(rgba.r, rgba.g, rgba.b, rgba.a); - } - return null; - } } export type IColorFormat = string | { opaque: string, transparent: string }; -export class ColorRange { +export class ColorInformation { range: Range; color: Color; - availableFormats: IColorFormat[]; - - constructor(range: Range, color: Color, availableFormats: IColorFormat[]) { + constructor(range: Range, color: Color) { if (color && !(color instanceof Color)) { throw illegalArgument('color'); } - if (availableFormats && !Array.isArray(availableFormats)) { - throw illegalArgument('availableFormats'); - } if (!Range.isRange(range) || range.isEmpty) { throw illegalArgument('range'); } this.range = range; this.color = color; - this.availableFormats = availableFormats; } } +export class ColorPresentation { + label: string; + textEdit?: TextEdit; + additionalTextEdits?: TextEdit[]; + + constructor(label: string) { + if (!label || typeof label !== 'string') { + throw illegalArgument('label'); + } + this.label = label; + } +} + +export enum ColorFormat { + RGB = 0, + HEX = 1, + HSL = 2 +} + export enum TaskRevealKind { Always = 1, @@ -1091,7 +1131,6 @@ export enum TaskPanelKind { export class TaskGroup implements vscode.TaskGroup { private _id: string; - private _label: string; public static Clean: TaskGroup = new TaskGroup('clean', 'Clean'); @@ -1101,15 +1140,14 @@ export class TaskGroup implements vscode.TaskGroup { public static Test: TaskGroup = new TaskGroup('test', 'Test'); - constructor(id: string, label: string) { + constructor(id: string, _label: string) { if (typeof id !== 'string') { throw illegalArgument('name'); } - if (typeof label !== 'string') { + if (typeof _label !== 'string') { throw illegalArgument('name'); } this._id = id; - this._label = label; } get id(): string { @@ -1208,10 +1246,16 @@ export class ShellExecution implements vscode.ShellExecution { } } +export enum TaskScope { + Global = 1, + Workspace = 2 +} + export class Task implements vscode.Task { private _definition: vscode.TaskDefinition; private _definitionKey: string; + private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder; private _name: string; private _execution: ProcessExecution | ShellExecution; private _problemMatchers: string[]; @@ -1221,11 +1265,29 @@ export class Task implements vscode.Task { private _group: TaskGroup; private _presentationOptions: vscode.TaskPresentationOptions; - constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]) { + constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + constructor(definition: vscode.TaskDefinition, arg2: string | (vscode.TaskScope.Global | vscode.TaskScope.Workspace) | vscode.WorkspaceFolder, arg3: any, arg4?: any, arg5?: any, arg6?: any) { this.definition = definition; - this.name = name; - this.source = source; - this.execution = execution; + let problemMatchers: string | string[]; + if (typeof arg2 === 'string') { + this.name = arg2; + this.source = arg3; + this.execution = arg4; + problemMatchers = arg5; + } else if (arg2 === TaskScope.Global || arg2 === TaskScope.Workspace) { + this.target = arg2; + this.name = arg3; + this.source = arg4; + this.execution = arg5; + problemMatchers = arg6; + } else { + this.target = arg2; + this.name = arg3; + this.source = arg4; + this.execution = arg5; + problemMatchers = arg6; + } if (typeof problemMatchers === 'string') { this._problemMatchers = [problemMatchers]; this._hasDefinedMatchers = true; @@ -1260,6 +1322,14 @@ export class Task implements vscode.Task { return this._definitionKey; } + get scope(): vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder { + return this._scope; + } + + set target(value: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder) { + this._scope = value; + } + get name(): string { return this._name; } @@ -1383,3 +1453,23 @@ export enum ConfigurationTarget { WorkspaceFolder = 3 } + +export class RelativePattern implements IRelativePattern { + base: string; + pattern: string; + + constructor(base: vscode.WorkspaceFolder | string, pattern: string) { + if (typeof base !== 'string') { + if (!base || !URI.isUri(base.uri)) { + throw illegalArgument('base'); + } + } + + if (typeof pattern !== 'string') { + throw illegalArgument('pattern'); + } + + this.base = typeof base === 'string' ? base : base.uri.fsPath; + this.pattern = pattern; + } +} diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index d19106c6995..654d088c5de 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -8,19 +8,13 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { normalize } from 'vs/base/common/paths'; import { delta } from 'vs/base/common/arrays'; -import { relative, basename } from 'path'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; -import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { fromRange, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters'; +import { relative, dirname } from 'path'; +import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol'; import * as vscode from 'vscode'; import { compare } from 'vs/base/common/strings'; -import { asWinJsPromise } from 'vs/base/common/async'; -import { Disposable } from 'vs/workbench/api/node/extHostTypes'; -import { TrieMap } from 'vs/base/common/map'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { Progress } from 'vs/platform/progress/common/progress'; +import { TernarySearchTree } from 'vs/base/common/map'; +import { IRelativePattern } from 'vs/base/common/glob'; class Workspace2 extends Workspace { @@ -28,42 +22,30 @@ class Workspace2 extends Workspace { return data ? new Workspace2(data) : null; } - private readonly _folder: vscode.WorkspaceFolder[] = []; - private readonly _structure = new TrieMap(s => s.split('/')); + private readonly _workspaceFolders: vscode.WorkspaceFolder[] = []; + private readonly _structure = TernarySearchTree.forPaths(); private constructor(data: IWorkspaceData) { - super(data.id, data.name, data.roots); + super(data.id, data.name, data.folders.map(folder => new WorkspaceFolder(folder))); // setup the workspace folder data structure - this.roots.forEach((uri, index) => { - const folder = { - name: basename(uri.fsPath), - uri, - index - }; - this._folder.push(folder); - this._structure.insert(folder.uri.toString(), folder); + this.folders.forEach(({ name, uri, index }) => { + const workspaceFolder = { name, uri, index }; + this._workspaceFolders.push(workspaceFolder); + this._structure.set(workspaceFolder.uri.toString(), workspaceFolder); }); } - get folders(): vscode.WorkspaceFolder[] { - return this._folder.slice(0); + get workspaceFolders(): vscode.WorkspaceFolder[] { + return this._workspaceFolders.slice(0); } - getWorkspaceFolder(uri: URI): vscode.WorkspaceFolder { - let str = uri.toString(); - let folder = this._structure.lookUp(str); - if (folder) { - // `uri` is a workspace folder so we - let parts = str.split('/'); - while (parts.length) { - if (parts.pop()) { - break; - } - } - str = parts.join('/'); + getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder { + if (resolveParent && this._structure.get(uri.toString())) { + // `uri` is a workspace folder so we check for its parent + uri = uri.with({ path: dirname(uri.path) }); } - return this._structure.findSubstr(str); + return this._structure.findSubstr(uri.toString()); } } @@ -92,15 +74,15 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { if (!this._workspace) { return undefined; } else { - return this._workspace.folders.slice(0); + return this._workspace.workspaceFolders.slice(0); } } - getWorkspaceFolder(uri: vscode.Uri): vscode.WorkspaceFolder { + getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder { if (!this._workspace) { return undefined; } - return this._workspace.getWorkspaceFolder(uri); + return this._workspace.getWorkspaceFolder(uri, resolveParent); } getPath(): string { @@ -110,11 +92,11 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { if (!this._workspace) { return undefined; } - const { roots } = this._workspace; - if (roots.length === 0) { + const { folders } = this._workspace; + if (folders.length === 0) { return undefined; } - return roots[0].fsPath; + return folders[0].uri.fsPath; } getRelativePath(pathOrUri: string | vscode.Uri, includeWorkspace?: boolean): string { @@ -130,24 +112,24 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return path; } - const folder = this.getWorkspaceFolder(typeof pathOrUri === 'string' - ? URI.file(pathOrUri) - : pathOrUri + const folder = this.getWorkspaceFolder( + typeof pathOrUri === 'string' ? URI.file(pathOrUri) : pathOrUri, + true ); if (!folder) { - return normalize(path); + return path; } if (typeof includeWorkspace === 'undefined') { - includeWorkspace = this.workspace.roots.length > 1; + includeWorkspace = this.workspace.folders.length > 1; } let result = relative(folder.uri.fsPath, path); if (includeWorkspace) { result = `${folder.name}/${result}`; } - return normalize(result); + return normalize(result, true); } $acceptWorkspaceData(data: IWorkspaceData): void { @@ -155,10 +137,10 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { // keep old workspace folder, build new workspace, and // capture new workspace folders. Compute delta between // them send that as event - const oldRoots = this._workspace ? this._workspace.folders.sort(ExtHostWorkspace._compareWorkspaceFolder) : []; + const oldRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : []; this._workspace = Workspace2.fromData(data); - const newRoots = this._workspace ? this._workspace.folders.sort(ExtHostWorkspace._compareWorkspaceFolder) : []; + const newRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : []; const { added, removed } = delta(oldRoots, newRoots, ExtHostWorkspace._compareWorkspaceFolder); this._onDidChangeWorkspace.fire(Object.freeze({ @@ -173,7 +155,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { // --- search --- - findFiles(include: string, exclude: string, maxResults?: number, token?: vscode.CancellationToken): Thenable { + findFiles(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults?: number, token?: vscode.CancellationToken): Thenable { const requestId = ExtHostWorkspace._requestIdPool++; const result = this._proxy.$startSearch(include, exclude, maxResults, requestId); if (token) { @@ -185,73 +167,4 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { saveAll(includeUntitled?: boolean): Thenable { return this._proxy.$saveAll(includeUntitled); } - - appyEdit(edit: vscode.WorkspaceEdit): TPromise { - - let resourceEdits: IResourceEdit[] = []; - - let entries = edit.entries(); - for (let entry of entries) { - let [uri, edits] = entry; - - for (let edit of edits) { - resourceEdits.push({ - resource: uri, - newText: edit.newText, - newEol: EndOfLine.from(edit.newEol), - range: edit.range && fromRange(edit.range) - }); - } - } - - return this._proxy.$applyWorkspaceEdit(resourceEdits); - } - - // --- EXPERIMENT: workspace resolver - - - private _handlePool = 0; - private readonly _fsProvider = new Map(); - private readonly _searchSession = new Map(); - - registerFileSystemProvider(authority: string, provider: vscode.FileSystemProvider): vscode.Disposable { - const handle = ++this._handlePool; - this._fsProvider.set(handle, provider); - const reg = provider.onDidChange(e => this._proxy.$onFileSystemChange(handle, e)); - this._proxy.$registerFileSystemProvider(handle, authority); - return new Disposable(() => { - this._fsProvider.delete(handle); - reg.dispose(); - }); - } - - $resolveFile(handle: number, resource: URI): TPromise { - const provider = this._fsProvider.get(handle); - return asWinJsPromise(token => provider.resolveContents(resource)); - } - - $storeFile(handle: number, resource: URI, content: string): TPromise { - const provider = this._fsProvider.get(handle); - return asWinJsPromise(token => provider.writeContents(resource, content)); - } - - $startSearch(handle: number, session: number, query: string): void { - const provider = this._fsProvider.get(handle); - const source = new CancellationTokenSource(); - const progress = new Progress(chunk => this._proxy.$updateSearchSession(session, chunk)); - - this._searchSession.set(session, source); - TPromise.wrap(provider.findFiles(query, progress, source.token)).then(() => { - this._proxy.$finishSearchSession(session); - }, err => { - this._proxy.$finishSearchSession(session, err); - }); - } - - $cancelSearch(handle: number, session: number): void { - if (this._searchSession.has(session)) { - this._searchSession.get(session).cancel(); - this._searchSession.delete(session); - } - } } diff --git a/src/vs/workbench/browser/actions.ts b/src/vs/workbench/browser/actions.ts index 32bf1d5f56b..9659c82ceb5 100644 --- a/src/vs/workbench/browser/actions.ts +++ b/src/vs/workbench/browser/actions.ts @@ -58,11 +58,6 @@ export class ActionBarContributor { */ export const Scope = { - /** - * Actions inside the global activity bar (DEPRECATED) - */ - GLOBAL: 'global', - /** * Actions inside viewlets. */ diff --git a/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts b/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts index 203f7204587..9ae30a6d59b 100644 --- a/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts +++ b/src/vs/workbench/browser/actions/toggleActivityBarVisibility.ts @@ -9,8 +9,8 @@ import nls = require('vs/nls'); import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; export class ToggleActivityBarVisibilityAction extends Action { @@ -24,7 +24,7 @@ export class ToggleActivityBarVisibilityAction extends Action { id: string, label: string, @IPartService private partService: IPartService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); @@ -35,9 +35,7 @@ export class ToggleActivityBarVisibilityAction extends Action { const visibility = this.partService.isVisible(Parts.ACTIVITYBAR_PART); const newVisibilityValue = !visibility; - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleActivityBarVisibilityAction.activityBarVisibleKey, value: newVisibilityValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleActivityBarVisibilityAction.activityBarVisibleKey, newVisibilityValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/browser/actions/toggleEditorLayout.ts b/src/vs/workbench/browser/actions/toggleEditorLayout.ts index 762f2a2cfbb..ddfab0a1946 100644 --- a/src/vs/workbench/browser/actions/toggleEditorLayout.ts +++ b/src/vs/workbench/browser/actions/toggleEditorLayout.ts @@ -10,7 +10,7 @@ import nls = require('vs/nls'); import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IEditorGroupService, GroupOrientation } from 'vs/workbench/services/group/common/groupService'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts index b2dabccb989..fc94e997424 100644 --- a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts +++ b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts @@ -9,9 +9,9 @@ import nls = require('vs/nls'); import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { IPartService, Position } from 'vs/workbench/services/part/common/partService'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class ToggleSidebarPositionAction extends Action { @@ -24,20 +24,18 @@ export class ToggleSidebarPositionAction extends Action { id: string, label: string, @IPartService private partService: IPartService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); - this.enabled = !!this.partService && !!this.configurationEditingService; + this.enabled = !!this.partService && !!this.configurationService; } public run(): TPromise { const position = this.partService.getSideBarPosition(); const newPositionValue = (position === Position.LEFT) ? 'right' : 'left'; - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleSidebarPositionAction.sidebarPositionConfigurationKey, value: newPositionValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts b/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts index 43f156d934d..0e9f81cca7e 100644 --- a/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts +++ b/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts @@ -9,7 +9,7 @@ import nls = require('vs/nls'); import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; diff --git a/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts b/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts index cf91fbb71a5..5949ea28756 100644 --- a/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts +++ b/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts @@ -9,8 +9,8 @@ import nls = require('vs/nls'); import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; export class ToggleStatusbarVisibilityAction extends Action { @@ -24,7 +24,7 @@ export class ToggleStatusbarVisibilityAction extends Action { id: string, label: string, @IPartService private partService: IPartService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); @@ -35,9 +35,7 @@ export class ToggleStatusbarVisibilityAction extends Action { const visibility = this.partService.isVisible(Parts.STATUSBAR_PART); const newVisibilityValue = !visibility; - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleStatusbarVisibilityAction.statusbarVisibleKey, value: newVisibilityValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/browser/actions/toggleTabsVisibility.ts b/src/vs/workbench/browser/actions/toggleTabsVisibility.ts new file mode 100644 index 00000000000..029eb47b5f0 --- /dev/null +++ b/src/vs/workbench/browser/actions/toggleTabsVisibility.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; +import nls = require('vs/nls'); +import { Registry } from 'vs/platform/registry/common/platform'; +import { Action } from 'vs/base/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; + +export class ToggleTabsVisibilityAction extends Action { + + public static ID = 'workbench.action.toggleTabsVisibility'; + public static LABEL = nls.localize('toggleTabs', "Toggle Tab Visibility"); + + private static tabsVisibleKey = 'workbench.editor.showTabs'; + + constructor( + id: string, + label: string, + @IConfigurationService private configurationService: IConfigurationService + ) { + super(id, label); + } + + public run(): TPromise { + const visibility = this.configurationService.getValue(ToggleTabsVisibilityAction.tabsVisibleKey); + const newVisibilityValue = !visibility; + + return this.configurationService.updateValue(ToggleTabsVisibilityAction.tabsVisibleKey, newVisibilityValue); + } +} + +const registry = Registry.as(Extensions.WorkbenchActions); +registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTabsVisibilityAction, ToggleTabsVisibilityAction.ID, ToggleTabsVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W }), 'View: Toggle Tab Visibility', nls.localize('view', "View")); \ No newline at end of file diff --git a/src/vs/workbench/browser/actions/toggleZenMode.ts b/src/vs/workbench/browser/actions/toggleZenMode.ts index f6209430da1..98cc5a32557 100644 --- a/src/vs/workbench/browser/actions/toggleZenMode.ts +++ b/src/vs/workbench/browser/actions/toggleZenMode.ts @@ -9,7 +9,7 @@ import { Action } from 'vs/base/common/actions'; import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { IPartService } from 'vs/workbench/services/part/common/partService'; class ToggleZenMode extends Action { diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index d67da02d0a5..07f7c530ddc 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -8,22 +8,45 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; import nls = require('vs/nls'); -import { distinct } from 'vs/base/common/arrays'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import URI from 'vs/base/common/uri'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkspacesService, WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces'; -import { IMessageService, Severity } from 'vs/platform/message/common/message'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { WORKSPACE_FILTER, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isLinux } from 'vs/base/common/platform'; import { dirname } from 'vs/base/common/paths'; -import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { isParent } from 'vs/platform/files/common/files'; +import * as resources from 'vs/base/common/resources'; +import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels'; +import { isParent, FileKind } from 'vs/platform/files/common/files'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IQuickOpenService, IFilePickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; + +export class OpenFileAction extends Action { + + static ID = 'workbench.action.files.openFile'; + static LABEL = nls.localize('openFile', "Open File..."); + + constructor( + id: string, + label: string, + @IWindowService private windowService: IWindowService, + @IHistoryService private historyService: IHistoryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService + ) { + super(id, label); + } + + run(event?: any, data?: ITelemetryData): TPromise { + return this.windowService.pickFileAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultFilePath(this.contextService, this.historyService) } }); + } +} export class OpenFolderAction extends Action { @@ -33,13 +56,15 @@ export class OpenFolderAction extends Action { constructor( id: string, label: string, - @IWindowService private windowService: IWindowService + @IWindowService private windowService: IWindowService, + @IHistoryService private historyService: IHistoryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(id, label); } run(event?: any, data?: ITelemetryData): TPromise { - return this.windowService.pickFolderAndOpen({ telemetryExtraData: data }); + return this.windowService.pickFolderAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultFolderPath(this.contextService, this.historyService) } }); } } @@ -51,16 +76,57 @@ export class OpenFileFolderAction extends Action { constructor( id: string, label: string, - @IWindowService private windowService: IWindowService + @IWindowService private windowService: IWindowService, + @IHistoryService private historyService: IHistoryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(id, label); } run(event?: any, data?: ITelemetryData): TPromise { - return this.windowService.pickFileFolderAndOpen({ telemetryExtraData: data }); + return this.windowService.pickFileFolderAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultFilePath(this.contextService, this.historyService) } }); } } +export const openFileFolderInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFileFolderAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultFilePath(contextService, historyService) } }); +}; + +export const openFolderCommand = (accessor: ServicesAccessor, forceNewWindow: boolean) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFolderAndOpen({ forceNewWindow, dialogOptions: { defaultPath: defaultFolderPath(contextService, historyService) } }); +}; + +export const openFolderInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFolderAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultFolderPath(contextService, historyService) } }); +}; + +export const openFileInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService } = services(accessor); + + windowService.pickFileAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultFilePath(contextService, historyService) } }); +}; + +export const openWorkspaceInNewWindowCommand = (accessor: ServicesAccessor) => { + const { windowService, historyService, contextService, environmentService } = services(accessor); + + windowService.pickWorkspaceAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: defaultWorkspacePath(contextService, historyService, environmentService) } }); +}; + +function services(accessor: ServicesAccessor): { windowService: IWindowService, historyService: IHistoryService, contextService: IWorkspaceContextService, environmentService: IEnvironmentService } { + return { + windowService: accessor.get(IWindowService), + historyService: accessor.get(IHistoryService), + contextService: accessor.get(IWorkspaceContextService), + environmentService: accessor.get(IEnvironmentService) + }; +} + export abstract class BaseWorkspacesAction extends Action { constructor( @@ -68,27 +134,65 @@ export abstract class BaseWorkspacesAction extends Action { label: string, protected windowService: IWindowService, protected environmentService: IEnvironmentService, - protected contextService: IWorkspaceContextService + protected contextService: IWorkspaceContextService, + protected historyService: IHistoryService ) { super(id, label); } protected pickFolders(buttonLabel: string, title: string): string[] { - const workspace = this.contextService.getWorkspace(); - let defaultPath: string; - if (workspace && workspace.roots.length > 0) { - defaultPath = dirname(workspace.roots[0].fsPath); // pick the parent of the first root by default - } - return this.windowService.showOpenDialog({ buttonLabel, title, properties: ['multiSelections', 'openDirectory', 'createDirectory'], - defaultPath + defaultPath: defaultFolderPath(this.contextService, this.historyService) }); } } +function defaultFilePath(contextService: IWorkspaceContextService, historyService: IHistoryService): string { + let candidate: URI; + + // Check for last active file first... + candidate = historyService.getLastActiveFile(); + + // ...then for last active file root + if (!candidate) { + candidate = historyService.getLastActiveWorkspaceRoot('file'); + } + + return candidate ? dirname(candidate.fsPath) : void 0; +} + +function defaultFolderPath(contextService: IWorkspaceContextService, historyService: IHistoryService): string { + let candidate: URI; + + // Check for last active file root first... + candidate = historyService.getLastActiveWorkspaceRoot('file'); + + // ...then for last active file + if (!candidate) { + candidate = historyService.getLastActiveFile(); + } + + return candidate ? dirname(candidate.fsPath) : void 0; +} + +function defaultWorkspacePath(contextService: IWorkspaceContextService, historyService: IHistoryService, environmentService: IEnvironmentService): string { + + // Check for current workspace config file first... + if (contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && !isUntitledWorkspace(contextService.getWorkspace().configuration.fsPath, environmentService)) { + return dirname(contextService.getWorkspace().configuration.fsPath); + } + + // ...then fallback to default folder path + return defaultFolderPath(contextService, historyService); +} + +function isUntitledWorkspace(path: string, environmentService: IEnvironmentService): boolean { + return isParent(path, environmentService.workspacesHome, !isLinux /* ignore case */); +} + export class AddRootFolderAction extends BaseWorkspacesAction { static ID = 'workbench.action.addRootFolder'; @@ -100,64 +204,57 @@ export class AddRootFolderAction extends BaseWorkspacesAction { @IWindowService windowService: IWindowService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IEnvironmentService environmentService: IEnvironmentService, - @IInstantiationService private instantiationService: IInstantiationService, @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, - @IViewletService private viewletService: IViewletService + @IViewletService private viewletService: IViewletService, + @IHistoryService historyService: IHistoryService ) { - super(id, label, windowService, environmentService, contextService); + super(id, label, windowService, environmentService, contextService, historyService); } public run(): TPromise { - if (!this.contextService.hasWorkspace()) { - return this.instantiationService.createInstance(NewWorkspaceAction, NewWorkspaceAction.ID, NewWorkspaceAction.LABEL, []).run(); - } - - if (this.contextService.hasFolderWorkspace()) { - return this.instantiationService.createInstance(NewWorkspaceAction, NewWorkspaceAction.ID, NewWorkspaceAction.LABEL, this.contextService.getWorkspace().roots).run(); - } - const folders = super.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")), nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace")); if (!folders || !folders.length) { return TPromise.as(null); } - return this.workspaceEditingService.addRoots(folders.map(folder => URI.file(folder))).then(() => { - return this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true); - }); + // Add and show Files Explorer viewlet + return this.workspaceEditingService.addFolders(folders.map(folder => ({ uri: URI.file(folder) }))).then(() => this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true)); } } -class NewWorkspaceAction extends BaseWorkspacesAction { +export class GlobalRemoveRootFolderAction extends BaseWorkspacesAction { - static ID = 'workbench.action.newWorkspace'; - static LABEL = nls.localize('newWorkspace', "New Workspace..."); + static ID = 'workbench.action.removeRootFolder'; + static LABEL = nls.localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace..."); constructor( id: string, label: string, - private presetRoots: URI[], @IWindowService windowService: IWindowService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IEnvironmentService environmentService: IEnvironmentService, - @IWorkspacesService protected workspacesService: IWorkspacesService, - @IWindowsService protected windowsService: IWindowsService, + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @ICommandService private commandService: ICommandService, + @IHistoryService historyService: IHistoryService ) { - super(id, label, windowService, environmentService, contextService); + super(id, label, windowService, environmentService, contextService, historyService); } public run(): TPromise { - const folders = super.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'select', comment: ['&& denotes a mnemonic'] }, "&&Select")), nls.localize('selectWorkspace', "Select Folders for Workspace")); - if (folders && folders.length) { - return this.createWorkspace([...this.presetRoots, ...folders.map(folder => URI.file(folder))]); + const state = this.contextService.getWorkbenchState(); + + // Workspace / Folder + if (state === WorkbenchState.WORKSPACE || state === WorkbenchState.FOLDER) { + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(folder => { + if (folder) { + return this.workspaceEditingService.removeFolders([folder.uri]).then(() => true); + } + + return true; + }); } - return TPromise.as(null); - } - - private createWorkspace(folders: URI[]): TPromise { - const workspaceFolders = distinct(folders.map(folder => folder.fsPath), folder => isLinux ? folder : folder.toLowerCase()); - - return this.windowService.createAndOpenWorkspace(workspaceFolders); + return TPromise.as(true); } } @@ -176,7 +273,29 @@ export class RemoveRootFolderAction extends Action { } public run(): TPromise { - return this.workspaceEditingService.removeRoots([this.rootUri]); + return this.workspaceEditingService.removeFolders([this.rootUri]); + } +} + +export class OpenFolderSettingsAction extends Action { + + static ID = 'workbench.action.openFolderSettings'; + static LABEL = nls.localize('openFolderSettings', "Open Folder Settings"); + + constructor( + private rootUri: URI, + id: string, + label: string, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @ICommandService private commandService: ICommandService + ) { + super(id, label); + } + + public run(): TPromise { + const workspaceFolder = this.contextService.getWorkspaceFolder(this.rootUri); + + return this.commandService.executeCommand('_workbench.action.openFolderSettings', workspaceFolder); } } @@ -191,63 +310,37 @@ export class SaveWorkspaceAsAction extends BaseWorkspacesAction { @IWindowService windowService: IWindowService, @IEnvironmentService environmentService: IEnvironmentService, @IWorkspaceContextService contextService: IWorkspaceContextService, - @IWorkspacesService protected workspacesService: IWorkspacesService, - @IWindowsService private windowsService: IWindowsService, - @IMessageService private messageService: IMessageService + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @IHistoryService historyService: IHistoryService ) { - super(id, label, windowService, environmentService, contextService); + super(id, label, windowService, environmentService, contextService, historyService); } public run(): TPromise { - if (!this.contextService.hasWorkspace()) { - this.messageService.show(Severity.Info, nls.localize('saveEmptyWorkspaceNotSupported', "Please open a workspace first to save.")); - return TPromise.as(null); - } - const configPath = this.getNewWorkspaceConfigPath(); if (configPath) { - if (this.contextService.hasFolderWorkspace()) { - return this.saveFolderWorkspace(configPath); - } + switch (this.contextService.getWorkbenchState()) { + case WorkbenchState.EMPTY: + case WorkbenchState.FOLDER: + const folders = this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri })); + return this.workspaceEditingService.createAndEnterWorkspace(folders, configPath); - if (this.contextService.hasMultiFolderWorkspace()) { - return this.saveWorkspace(configPath); + case WorkbenchState.WORKSPACE: + return this.workspaceEditingService.saveAndEnterWorkspace(configPath); } } return TPromise.as(null); } - private saveWorkspace(configPath: string): TPromise { - return this.windowService.saveAndOpenWorkspace(configPath); - } - - private saveFolderWorkspace(configPath: string): TPromise { - const workspaceFolders = this.contextService.getWorkspace().roots.map(root => root.fsPath); - - return this.windowService.createAndOpenWorkspace(workspaceFolders, configPath); - } - private getNewWorkspaceConfigPath(): string { - const workspace = this.contextService.getWorkspace(); - let defaultPath: string; - if (this.contextService.hasMultiFolderWorkspace() && !this.isUntitledWorkspace(workspace.configuration.fsPath)) { - defaultPath = workspace.configuration.fsPath; - } else if (workspace && workspace.roots.length > 0) { - defaultPath = dirname(workspace.roots[0].fsPath); // pick the parent of the first root by default - } - return this.windowService.showSaveDialog({ buttonLabel: mnemonicButtonLabel(nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), title: nls.localize('saveWorkspace', "Save Workspace"), filters: WORKSPACE_FILTER, - defaultPath + defaultPath: defaultWorkspacePath(this.contextService, this.historyService, this.environmentService) }); } - - private isUntitledWorkspace(path: string): boolean { - return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */); - } } export class OpenWorkspaceAction extends Action { @@ -259,12 +352,15 @@ export class OpenWorkspaceAction extends Action { id: string, label: string, @IWindowService private windowService: IWindowService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IHistoryService private historyService: IHistoryService, + @IEnvironmentService private environmentService: IEnvironmentService ) { super(id, label); } - public run(): TPromise { - return this.windowService.openWorkspace(); + public run(event?: any, data?: ITelemetryData): TPromise { + return this.windowService.pickWorkspaceAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: defaultWorkspacePath(this.contextService, this.historyService, this.environmentService) } }); } } @@ -281,10 +377,114 @@ export class OpenWorkspaceConfigFileAction extends Action { ) { super(id, label); - this.enabled = this.workspaceContextService.hasMultiFolderWorkspace(); + this.enabled = !!this.workspaceContextService.getWorkspace().configuration; } public run(): TPromise { return this.editorService.openEditor({ resource: this.workspaceContextService.getWorkspace().configuration }); } -} \ No newline at end of file +} + +export class OpenFolderAsWorkspaceInNewWindowAction extends Action { + + public static ID = 'workbench.action.openFolderAsWorkspaceInNewWindow'; + public static LABEL = nls.localize('openFolderAsWorkspaceInNewWindow', "Open Folder as Workspace in New Window"); + + constructor( + id: string, + label: string, + @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @IWindowsService private windowsService: IWindowsService, + @ICommandService private commandService: ICommandService, + @IWorkspacesService private workspacesService: IWorkspacesService + ) { + super(id, label); + } + + public run(): TPromise { + const folders = this.workspaceContextService.getWorkspace().folders; + + let folderPromise: TPromise; + if (folders.length === 0) { + folderPromise = TPromise.as(null); + } else if (folders.length === 1) { + folderPromise = TPromise.as(folders[0]); + } else { + folderPromise = this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND); + } + + return folderPromise.then(folder => { + if (!folder) { + return void 0; // need at least one folder + } + + return this.workspacesService.createWorkspace([{ uri: folder.uri }]).then(newWorkspace => { + return this.workspaceEditingService.copyWorkspaceSettings(newWorkspace).then(() => { + return this.windowsService.openWindow([newWorkspace.configPath], { forceNewWindow: true }); + }); + }); + }); + } +} + +export const PICK_WORKSPACE_FOLDER_COMMAND = '_workbench.pickWorkspaceFolder'; + +CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND, function (accessor: ServicesAccessor, args?: [IPickOptions, CancellationToken]) { + const contextService = accessor.get(IWorkspaceContextService); + const quickOpenService = accessor.get(IQuickOpenService); + const environmentService = accessor.get(IEnvironmentService); + + const folders = contextService.getWorkspace().folders; + if (!folders.length) { + return void 0; + } + + const folderPicks = folders.map(folder => { + return { + label: folder.name, + description: getPathLabel(resources.dirname(folder.uri), void 0, environmentService), + folder, + resource: folder.uri, + fileKind: FileKind.ROOT_FOLDER + } as IFilePickOpenEntry; + }); + + let options: IPickOptions; + if (args) { + options = args[0]; + } + + if (!options) { + options = Object.create(null); + } + + if (!options.autoFocus) { + options.autoFocus = { autoFocusFirstEntry: true }; + } + + if (!options.placeHolder) { + options.placeHolder = nls.localize('workspaceFolderPickerPlaceholder', "Select workspace folder"); + } + + if (typeof options.matchOnDescription !== 'boolean') { + options.matchOnDescription = true; + } + + let token: CancellationToken; + if (args) { + token = args[1]; + } + + if (!token) { + token = CancellationToken.None; + } + + return quickOpenService.pick(folderPicks, options, token).then(pick => { + if (!pick) { + return void 0; + } + + return folders[folderPicks.indexOf(pick)]; + }); +}); \ No newline at end of file diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index 0fba1254c67..9dbf2f35f25 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -9,11 +9,11 @@ import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions'; import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { Component } from 'vs/workbench/common/component'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { AsyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IComposite } from 'vs/workbench/common/composite'; import { IEditorControl } from 'vs/platform/editor/common/editor'; import Event, { Emitter } from 'vs/base/common/event'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; /** * Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite @@ -108,6 +108,11 @@ export abstract class Composite extends Component implements IComposite { // Only submit telemetry data when not running from an integration test if (this._telemetryService && this._telemetryService.publicLog) { const eventName: string = 'compositeOpen'; + /* __GDPR__ + "compositeOpen" : { + "composite" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this._telemetryService.publicLog(eventName, { composite: this.getId() }); } } @@ -121,6 +126,12 @@ export abstract class Composite extends Component implements IComposite { if (this._telemetryService && this._telemetryService.publicLog) { const eventName: string = 'compositeShown'; this._telemetryData.composite = this.getId(); + /* __GDPR__ + "compositeShown" : { + "timeSpent" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "composite": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this._telemetryService.publicLog(eventName, this._telemetryData); } } @@ -218,19 +229,26 @@ export abstract class Composite extends Component implements IComposite { /** * A composite descriptor is a leightweight descriptor of a composite in the workbench. */ -export abstract class CompositeDescriptor extends AsyncDescriptor { +export abstract class CompositeDescriptor { public id: string; public name: string; public cssClass: string; public order: number; + public keybindingId; - constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number) { - super(moduleId, ctorName); + private ctor: IConstructorSignature0; + constructor(ctor: IConstructorSignature0, id: string, name: string, cssClass?: string, order?: number, keybindingId?: string, ) { + this.ctor = ctor; this.id = id; this.name = name; this.cssClass = cssClass; this.order = order; + this.keybindingId = keybindingId; + } + + public instantiate(instantiationService: IInstantiationService): T { + return instantiationService.createInstance(this.ctor); } } diff --git a/src/vs/workbench/browser/editor.ts b/src/vs/workbench/browser/editor.ts new file mode 100644 index 00000000000..24c226052d9 --- /dev/null +++ b/src/vs/workbench/browser/editor.ts @@ -0,0 +1,239 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { EditorInput } from 'vs/workbench/common/editor'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { isArray } from 'vs/base/common/types'; +import URI from 'vs/base/common/uri'; + +export interface IEditorDescriptor { + instantiate(instantiationService: IInstantiationService): BaseEditor; + + getId(): string; + getName(): string; + + describes(obj: any): boolean; +} + +export interface IEditorRegistry { + + /** + * Registers an editor to the platform for the given input type. The second parameter also supports an + * array of input classes to be passed in. If the more than one editor is registered for the same editor + * input, the input itself will be asked which editor it prefers if this method is provided. Otherwise + * the first editor in the list will be returned. + * + * @param editorInputDescriptor a constructor function that returns an instance of EditorInput for which the + * registered editor should be used for. + */ + registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor): void; + registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor[]): void; + + /** + * Returns the editor descriptor for the given input or null if none. + */ + getEditor(input: EditorInput): IEditorDescriptor; + + /** + * Returns the editor descriptor for the given identifier or null if none. + */ + getEditorById(editorId: string): IEditorDescriptor; + + /** + * Returns an array of registered editors known to the platform. + */ + getEditors(): IEditorDescriptor[]; +} + +/** + * A lightweight descriptor of an editor. The descriptor is deferred so that heavy editors + * can load lazily in the workbench. + */ +export class EditorDescriptor implements IEditorDescriptor { + private ctor: IConstructorSignature0; + private id: string; + private name: string; + + constructor(ctor: IConstructorSignature0, id: string, name: string) { + this.ctor = ctor; + this.id = id; + this.name = name; + } + + public instantiate(instantiationService: IInstantiationService): BaseEditor { + return instantiationService.createInstance(this.ctor); + } + + public getId(): string { + return this.id; + } + + public getName(): string { + return this.name; + } + + public describes(obj: any): boolean { + return obj instanceof BaseEditor && (obj).getId() === this.id; + } +} + +const INPUT_DESCRIPTORS_PROPERTY = '__$inputDescriptors'; + +class EditorRegistry implements IEditorRegistry { + private editors: EditorDescriptor[]; + + constructor() { + this.editors = []; + } + + public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor): void; + public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor[]): void; + public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: any): void { + + // Support both non-array and array parameter + let inputDescriptors: SyncDescriptor[] = []; + if (!isArray(editorInputDescriptor)) { + inputDescriptors.push(editorInputDescriptor); + } else { + inputDescriptors = editorInputDescriptor; + } + + // Register (Support multiple Editors per Input) + descriptor[INPUT_DESCRIPTORS_PROPERTY] = inputDescriptors; + this.editors.push(descriptor); + } + + public getEditor(input: EditorInput): EditorDescriptor { + const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] => { + const matchingDescriptors: EditorDescriptor[] = []; + + for (let i = 0; i < this.editors.length; i++) { + const editor = this.editors[i]; + const inputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; + for (let j = 0; j < inputDescriptors.length; j++) { + const inputClass = inputDescriptors[j].ctor; + + // Direct check on constructor type (ignores prototype chain) + if (!byInstanceOf && input.constructor === inputClass) { + matchingDescriptors.push(editor); + break; + } + + // Normal instanceof check + else if (byInstanceOf && input instanceof inputClass) { + matchingDescriptors.push(editor); + break; + } + } + } + + // If no descriptors found, continue search using instanceof and prototype chain + if (!byInstanceOf && matchingDescriptors.length === 0) { + return findEditorDescriptors(input, true); + } + + if (byInstanceOf) { + return matchingDescriptors; + } + + return matchingDescriptors; + }; + + const descriptors = findEditorDescriptors(input); + if (descriptors && descriptors.length > 0) { + + // Ask the input for its preferred Editor + const preferredEditorId = input.getPreferredEditorId(descriptors.map(d => d.getId())); + if (preferredEditorId) { + return this.getEditorById(preferredEditorId); + } + + // Otherwise, first come first serve + return descriptors[0]; + } + + return null; + } + + public getEditorById(editorId: string): EditorDescriptor { + for (let i = 0; i < this.editors.length; i++) { + const editor = this.editors[i]; + if (editor.getId() === editorId) { + return editor; + } + } + + return null; + } + + public getEditors(): EditorDescriptor[] { + return this.editors.slice(0); + } + + public setEditors(editorsToSet: EditorDescriptor[]): void { + this.editors = editorsToSet; + } + + public getEditorInputs(): any[] { + const inputClasses: any[] = []; + for (let i = 0; i < this.editors.length; i++) { + const editor = this.editors[i]; + const editorInputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; + inputClasses.push(...editorInputDescriptors.map(descriptor => descriptor.ctor)); + } + + return inputClasses; + } +} + +export const Extensions = { + Editors: 'workbench.contributions.editors' +}; + +Registry.add(Extensions.Editors, new EditorRegistry()); + +export interface IDraggedResource { + resource: URI; + isExternal: boolean; +} + +export function extractResources(e: DragEvent, externalOnly?: boolean): IDraggedResource[] { + const resources: IDraggedResource[] = []; + if (e.dataTransfer.types.length > 0) { + + // Check for in-app DND + if (!externalOnly) { + const rawData = e.dataTransfer.getData('URL'); + if (rawData) { + try { + resources.push({ resource: URI.parse(rawData), isExternal: false }); + } catch (error) { + // Invalid URI + } + } + } + + // Check for native file transfer + if (e.dataTransfer && e.dataTransfer.files) { + for (let i = 0; i < e.dataTransfer.files.length; i++) { + const file = e.dataTransfer.files[i] as { path: string }; + if (file && file.path) { + try { + resources.push({ resource: URI.file(file.path), isExternal: true }); + } catch (error) { + // Invalid URI + } + } + } + } + } + + return resources; +} \ No newline at end of file diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index e31c98045c2..148b460e93c 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -6,13 +6,13 @@ 'use strict'; import uri from 'vs/base/common/uri'; -import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { IconLabel, IIconLabelOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IEditorInput } from 'vs/platform/editor/common/editor'; import { toResource } from 'vs/workbench/common/editor'; -import { getPathLabel, IRootProvider } from 'vs/base/common/labels'; +import { getPathLabel, IWorkspaceFolderProvider } from 'vs/base/common/labels'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -20,10 +20,13 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { IDecorationsService, IResourceDecorationChangeEvent, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { Schemas } from 'vs/base/common/network'; -import { FileKind } from 'vs/platform/files/common/files'; +import { FileKind, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; +import { IModel } from 'vs/editor/common/editorCommon'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; -export interface IEditorLabel { +export interface IResourceLabel { name: string; description?: string; resource?: uri; @@ -31,11 +34,12 @@ export interface IEditorLabel { export interface IResourceLabelOptions extends IIconLabelOptions { fileKind?: FileKind; + fileDecorations?: { colors: boolean, badges: boolean, data?: IDecorationData }; } export class ResourceLabel extends IconLabel { private toDispose: IDisposable[]; - private label: IEditorLabel; + private label: IResourceLabel; private options: IResourceLabelOptions; private computedIconClasses: string[]; private lastKnownConfiguredLangId: string; @@ -48,7 +52,9 @@ export class ResourceLabel extends IconLabel { @IConfigurationService private configurationService: IConfigurationService, @IModeService private modeService: IModeService, @IModelService private modelService: IModelService, - @IEnvironmentService protected environmentService: IEnvironmentService + @IEnvironmentService protected environmentService: IEnvironmentService, + @IDecorationsService protected decorationsService: IDecorationsService, + @IThemeService private themeService: IThemeService ) { super(container, options); @@ -58,11 +64,58 @@ export class ResourceLabel extends IconLabel { } private registerListeners(): void { - this.extensionService.onReady().then(() => this.render(true /* clear cache */)); // update when extensions are loaded with potentially new languages - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.render(true /* clear cache */))); // update when file.associations change + + // update when extensions are loaded with potentially new languages + this.extensionService.onReady().then(() => this.render(true /* clear cache */)); + + // react to model mode changes + this.toDispose.push(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e))); + + // react to file decoration changes + this.toDispose.push(this.decorationsService.onDidChangeDecorations(this.onFileDecorationsChanges, this)); + + // react to theme changes + this.toDispose.push(this.themeService.onThemeChange(() => this.render(false))); + + // react to files.associations changes + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(FILES_ASSOCIATIONS_CONFIG)) { + this.render(true /* clear cache */); + } + })); } - public setLabel(label: IEditorLabel, options?: IResourceLabelOptions): void { + private onModelModeChanged(e: { model: IModel; oldModeId: string; }): void { + if (!this.label || !this.label.resource) { + return; // only update if label exists + } + + if (!e.model.uri) { + return; // we need the resource to compare + } + + if (e.model.uri.scheme === Schemas.file && e.oldModeId === PLAINTEXT_MODE_ID) { + return; // ignore transitions in files from no mode to specific mode because this happens each time a model is created + } + + if (e.model.uri.toString() === this.label.resource.toString()) { + if (this.lastKnownConfiguredLangId !== e.model.getLanguageIdentifier().language) { + this.render(true); // update if the language id of the model has changed from our last known state + } + } + } + + private onFileDecorationsChanges(e: IResourceDecorationChangeEvent): void { + if (!this.options || !this.label || !this.label.resource) { + return; + } + + if (this.options.fileDecorations && e.affectsResource(this.label.resource)) { + this.render(false); + } + } + + public setLabel(label: IResourceLabel, options?: IResourceLabelOptions): void { const hasResourceChanged = this.hasResourceChanged(label, options); this.label = label; @@ -71,7 +124,7 @@ export class ResourceLabel extends IconLabel { this.render(hasResourceChanged); } - private hasResourceChanged(label: IEditorLabel, options: IResourceLabelOptions): boolean { + private hasResourceChanged(label: IResourceLabel, options: IResourceLabelOptions): boolean { const newResource = label ? label.resource : void 0; const oldResource = this.label ? this.label.resource : void 0; @@ -119,28 +172,51 @@ export class ResourceLabel extends IconLabel { return; } - const resource = this.label.resource; + const iconLabelOptions: IIconLabelOptions = { + title: '', + italic: this.options && this.options.italic, + matches: this.options && this.options.matches, + }; + + const resource = this.label.resource; + const label = this.label.name; - let title = ''; if (this.options && typeof this.options.title === 'string') { - title = this.options.title; + iconLabelOptions.title = this.options.title; } else if (resource) { - title = getPathLabel(resource.fsPath, void 0, this.environmentService); + iconLabelOptions.title = getPathLabel(resource, void 0, this.environmentService); } if (!this.computedIconClasses) { this.computedIconClasses = getIconClasses(this.modelService, this.modeService, resource, this.options && this.options.fileKind); } - let extraClasses = this.computedIconClasses.slice(0); + iconLabelOptions.extraClasses = this.computedIconClasses.slice(0); if (this.options && this.options.extraClasses) { - extraClasses.push(...this.options.extraClasses); + iconLabelOptions.extraClasses.push(...this.options.extraClasses); } - const italic = this.options && this.options.italic; - const matches = this.options && this.options.matches; + if (this.options && this.options.fileDecorations && resource) { + let deco = this.decorationsService.getDecoration( + resource, + this.options.fileKind !== FileKind.FILE, + this.options.fileDecorations.data + ); - this.setValue(this.label.name, this.label.description, { title, extraClasses, italic, matches }); + if (deco) { + if (deco.tooltip) { + iconLabelOptions.title = `${iconLabelOptions.title} • ${deco.tooltip}`; + } + if (this.options.fileDecorations.colors) { + iconLabelOptions.extraClasses.push(deco.labelClassName); + } + if (this.options.fileDecorations.badges) { + iconLabelOptions.extraClasses.push(deco.badgeClassName); + } + } + } + + this.setValue(label, this.label.description, iconLabelOptions); } public dispose(): void { @@ -182,22 +258,46 @@ export class FileLabel extends ResourceLabel { @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IEnvironmentService environmentService: IEnvironmentService, - @IUntitledEditorService private untitledEditorService: IUntitledEditorService + @IDecorationsService decorationsService: IDecorationsService, + @IThemeService themeService: IThemeService, + @IUntitledEditorService private untitledEditorService: IUntitledEditorService, ) { - super(container, options, extensionService, contextService, configurationService, modeService, modelService, environmentService); + super(container, options, extensionService, contextService, configurationService, modeService, modelService, environmentService, decorationsService, themeService); } - public setFile(resource: uri, options: IFileLabelOptions = Object.create(null)): void { - const hidePath = options.hidePath || (resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource)); - const rootProvider: IRootProvider = options.root ? { - getRoot(): uri { return options.root; }, - getWorkspace(): { roots: uri[]; } { return { roots: [options.root] }; }, - } : this.contextService; - this.setLabel({ - resource, - name: !options.hideLabel ? paths.basename(resource.fsPath) : void 0, - description: !hidePath ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : void 0 - }, options); + public setFile(resource: uri, options?: IFileLabelOptions): void { + const hideLabel = options && options.hideLabel; + let name: string; + if (!hideLabel) { + if (options && options.fileKind === FileKind.ROOT_FOLDER) { + const workspaceFolder = this.contextService.getWorkspaceFolder(resource); + if (workspaceFolder) { + name = workspaceFolder.name; + } + } + + if (!name) { + name = resources.basenameOrAuthority(resource); + } + } + + let description: string; + const hidePath = (options && options.hidePath) || (resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource)); + if (!hidePath) { + let rootProvider: IWorkspaceFolderProvider; + if (options && options.root) { + rootProvider = { + getWorkspaceFolder(): { uri } { return { uri: options.root }; }, + getWorkspace(): { folders: { uri: uri }[]; } { return { folders: [{ uri: options.root }] }; }, + }; + } else { + rootProvider = this.contextService; + } + + description = getPathLabel(resources.dirname(resource), rootProvider, this.environmentService); + } + + this.setLabel({ resource, name, description }, options); } } @@ -206,39 +306,36 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe // we always set these base classes even if we do not have a path const classes = fileKind === FileKind.ROOT_FOLDER ? ['rootfolder-icon'] : fileKind === FileKind.FOLDER ? ['folder-icon'] : ['file-icon']; - let path: string; if (resource) { - path = resource.fsPath; - } - - if (path) { - const basename = cssEscape(paths.basename(path).toLowerCase()); + const name = cssEscape(resources.basenameOrAuthority(resource).toLowerCase()); // Folders if (fileKind === FileKind.FOLDER) { - classes.push(`${basename}-name-folder-icon`); + classes.push(`${name}-name-folder-icon`); } // Files else { // Name - classes.push(`${basename}-name-file-icon`); + classes.push(`${name}-name-file-icon`); // Extension(s) - const dotSegments = basename.split('.'); + const dotSegments = name.split('.'); for (let i = 1; i < dotSegments.length; i++) { classes.push(`${dotSegments.slice(i).join('.')}-ext-file-icon`); // add each combination of all found extensions if more than one } + classes.push(`ext-file-icon`); // extra segment to increase file-ext score // Configured Language let configuredLangId = getConfiguredLangId(modelService, resource); - configuredLangId = configuredLangId || modeService.getModeIdByFilenameOrFirstLine(path); + configuredLangId = configuredLangId || modeService.getModeIdByFilenameOrFirstLine(name); if (configuredLangId) { classes.push(`${cssEscape(configuredLangId)}-lang-file-icon`); } } } + return classes; } @@ -259,4 +356,4 @@ function getConfiguredLangId(modelService: IModelService, resource: uri): string function cssEscape(val: string): string { return val.replace(/\s/g, '\\$&'); // make sure to not introduce CSS classes from files that contain whitespace -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 7b4676fee99..9a4245d5b17 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -19,14 +19,18 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { getZoomFactor } from 'vs/base/browser/browser'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { memoize } from 'vs/base/common/decorators'; const MIN_SIDEBAR_PART_WIDTH = 170; const MIN_EDITOR_PART_HEIGHT = 70; const MIN_EDITOR_PART_WIDTH = 220; const MIN_PANEL_PART_HEIGHT = 77; -const DEFAULT_PANEL_HEIGHT_COEFFICIENT = 0.4; +const MIN_PANEL_PART_WIDTH = 300; +const DEFAULT_PANEL_SIZE_COEFFICIENT = 0.4; +const PANEL_SIZE_BEFORE_MAXIMIZED_BOUNDARY = 0.7; const HIDE_SIDEBAR_WIDTH_THRESHOLD = 50; const HIDE_PANEL_HEIGHT_THRESHOLD = 50; +const HIDE_PANEL_WIDTH_THRESHOLD = 100; const TITLE_BAR_HEIGHT = 22; const STATUS_BAR_HEIGHT = 22; const ACTIVITY_BAR_WIDTH = 50; @@ -35,7 +39,7 @@ interface PartLayoutInfo { titlebar: { height: number; }; activitybar: { width: number; }; sidebar: { minWidth: number; }; - panel: { minHeight: number; }; + panel: { minHeight: number; minWidth: number; }; editor: { minWidth: number; minHeight: number; }; statusbar: { height: number; }; } @@ -45,7 +49,8 @@ interface PartLayoutInfo { */ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider { - private static sashXWidthSettingsKey = 'workbench.sidebar.width'; + private static sashXOneWidthSettingsKey = 'workbench.sidebar.width'; + private static sashXTwoWidthSettingsKey = 'workbench.panel.width'; private static sashYHeightSettingsKey = 'workbench.panel.height'; private parent: Builder; @@ -58,21 +63,18 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal private statusbar: Part; private quickopen: QuickOpenController; private toUnbind: IDisposable[]; - private partLayoutInfo: PartLayoutInfo; private workbenchSize: Dimension; - private sashX: Sash; + private sashXOne: Sash; + private sashXTwo: Sash; private sashY: Sash; - private startSidebarWidth: number; - private sidebarWidth: number; + private _sidebarWidth: number; private sidebarHeight: number; private titlebarHeight: number; - private activitybarWidth: number; private statusbarHeight: number; - private startPanelHeight: number; - private panelHeight: number; - private panelHeightBeforeMaximized: number; + private panelSizeBeforeMaximized: number; private panelMaximized: boolean; - private panelWidth: number; + private _panelHeight: number; + private _panelWidth: number; private layoutEditorGroupsVertically: boolean; // Take parts as an object bag since instatation service does not have typings for constructors with 9+ arguments @@ -106,11 +108,14 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.statusbar = parts.statusbar; this.quickopen = quickopen; this.toUnbind = []; - this.partLayoutInfo = this.getPartLayoutInfo(); - this.panelHeightBeforeMaximized = 0; + this.panelSizeBeforeMaximized = 0; this.panelMaximized = false; - this.sashX = new Sash(this.workbenchContainer.getHTMLElement(), this, { + this.sashXOne = new Sash(this.workbenchContainer.getHTMLElement(), this, { + baseSize: 5 + }); + + this.sashXTwo = new Sash(this.workbenchContainer.getHTMLElement(), this, { baseSize: 5 }); @@ -119,8 +124,9 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal orientation: Orientation.HORIZONTAL }); - this.sidebarWidth = this.storageService.getInteger(WorkbenchLayout.sashXWidthSettingsKey, StorageScope.GLOBAL, -1); - this.panelHeight = this.storageService.getInteger(WorkbenchLayout.sashYHeightSettingsKey, StorageScope.GLOBAL, 0); + this._sidebarWidth = this.storageService.getInteger(WorkbenchLayout.sashXOneWidthSettingsKey, StorageScope.GLOBAL, -1); + this._panelHeight = this.storageService.getInteger(WorkbenchLayout.sashYHeightSettingsKey, StorageScope.GLOBAL, 0); + this._panelWidth = this.storageService.getInteger(WorkbenchLayout.sashXTwoWidthSettingsKey, StorageScope.GLOBAL, 0); this.layoutEditorGroupsVertically = (this.editorGroupService.getGroupOrientation() !== 'horizontal'); @@ -131,7 +137,73 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.registerSashListeners(); } - private getPartLayoutInfo(): PartLayoutInfo { + private get editorCountForHeight(): number { + return Math.max(1, this.editorGroupService.getGroupOrientation() === 'horizontal' ? this.editorGroupService.getStacksModel().groups.length : 1); + } + + private get editorCountForWidth(): number { + return Math.max(1, this.editorGroupService.getGroupOrientation() === 'vertical' ? this.editorGroupService.getStacksModel().groups.length : 1); + } + + private get activitybarWidth(): number { + if (this.partService.isVisible(Parts.ACTIVITYBAR_PART)) { + return this.partLayoutInfo.activitybar.width; + } + + return 0; + } + + private get panelHeight(): number { + const panelPosition = this.partService.getPanelPosition(); + if (panelPosition === Position.RIGHT) { + return this.sidebarHeight; + } + + return this._panelHeight; + } + + private set panelHeight(value: number) { + this._panelHeight = Math.min(this.computeMaxPanelHeight(), Math.max(this.partLayoutInfo.panel.minHeight, value)); + } + + private get panelWidth(): number { + const panelPosition = this.partService.getPanelPosition(); + if (panelPosition === Position.BOTTOM) { + return this.workbenchSize.width - this.activitybarWidth - this.sidebarWidth; + } + + return this._panelWidth; + } + + private set panelWidth(value: number) { + this._panelWidth = Math.min(this.computeMaxPanelWidth(), Math.max(this.partLayoutInfo.panel.minWidth, value)); + } + + private computeMaxPanelWidth(): number { + const minSidebarSize = this.partService.isVisible(Parts.SIDEBAR_PART) ? (this.partService.getSideBarPosition() === Position.LEFT ? this.partLayoutInfo.sidebar.minWidth : this.sidebarWidth) : 0; + return Math.max(this.partLayoutInfo.panel.minWidth, this.workbenchSize.width - this.editorCountForWidth * this.partLayoutInfo.editor.minWidth - minSidebarSize - this.activitybarWidth); + } + + private computeMaxPanelHeight(): number { + return Math.max(this.partLayoutInfo.panel.minHeight, this.sidebarHeight - this.editorCountForHeight * this.partLayoutInfo.editor.minHeight); + } + + private get sidebarWidth(): number { + if (this.partService.isVisible(Parts.SIDEBAR_PART)) { + return this._sidebarWidth; + } + + return 0; + } + + private set sidebarWidth(value: number) { + const panelMinWidth = this.partService.getPanelPosition() === Position.RIGHT && this.partService.isVisible(Parts.PANEL_PART) ? this.partLayoutInfo.panel.minWidth : 0; + const maxSidebarWidth = this.workbenchSize.width - this.activitybarWidth - this.editorCountForWidth * this.partLayoutInfo.editor.minWidth - panelMinWidth; + this._sidebarWidth = Math.max(this.partLayoutInfo.sidebar.minWidth, Math.min(maxSidebarWidth, value)); + } + + @memoize + private get partLayoutInfo(): PartLayoutInfo { return { titlebar: { height: TITLE_BAR_HEIGHT @@ -143,7 +215,8 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal minWidth: MIN_SIDEBAR_PART_WIDTH }, panel: { - minHeight: MIN_PANEL_PART_HEIGHT + minHeight: MIN_PANEL_PART_HEIGHT, + minWidth: MIN_PANEL_PART_WIDTH }, editor: { minWidth: MIN_EDITOR_PART_WIDTH, @@ -158,22 +231,31 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal private registerSashListeners(): void { let startX: number = 0; let startY: number = 0; + let startXTwo: number = 0; + let startSidebarWidth: number; + let startPanelHeight: number; + let startPanelWidth: number; - this.sashX.addListener('start', (e: ISashEvent) => { - this.startSidebarWidth = this.sidebarWidth; + this.toUnbind.push(this.sashXOne.addListener('start', (e: ISashEvent) => { + startSidebarWidth = this.sidebarWidth; startX = e.startX; - }); + })); - this.sashY.addListener('start', (e: ISashEvent) => { - this.startPanelHeight = this.panelHeight; + this.toUnbind.push(this.sashY.addListener('start', (e: ISashEvent) => { + startPanelHeight = this.panelHeight; startY = e.startY; - }); + })); - this.sashX.addListener('change', (e: ISashEvent) => { + this.toUnbind.push(this.sashXTwo.addListener('start', (e: ISashEvent) => { + startPanelWidth = this.panelWidth; + startXTwo = e.startX; + })); + + this.toUnbind.push(this.sashXOne.addListener('change', (e: ISashEvent) => { let doLayout = false; let sidebarPosition = this.partService.getSideBarPosition(); let isSidebarVisible = this.partService.isVisible(Parts.SIDEBAR_PART); - let newSashWidth = (sidebarPosition === Position.LEFT) ? this.startSidebarWidth + e.currentX - startX : this.startSidebarWidth - e.currentX + startX; + let newSashWidth = (sidebarPosition === Position.LEFT) ? startSidebarWidth + e.currentX - startX : startSidebarWidth - e.currentX + startX; let promise = TPromise.as(null); // Sidebar visible @@ -181,10 +263,10 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Automatically hide side bar when a certain threshold is met if (newSashWidth + HIDE_SIDEBAR_WIDTH_THRESHOLD < this.partLayoutInfo.sidebar.minWidth) { - let dragCompensation = MIN_SIDEBAR_PART_WIDTH - HIDE_SIDEBAR_WIDTH_THRESHOLD; + let dragCompensation = this.partLayoutInfo.sidebar.minWidth - HIDE_SIDEBAR_WIDTH_THRESHOLD; promise = this.partService.setSideBarHidden(true); startX = (sidebarPosition === Position.LEFT) ? Math.max(this.activitybarWidth, e.currentX - dragCompensation) : Math.min(e.currentX + dragCompensation, this.workbenchSize.width - this.activitybarWidth); - this.sidebarWidth = this.startSidebarWidth; // when restoring sidebar, restore to the sidebar width we started from + this.sidebarWidth = startSidebarWidth; // when restoring sidebar, restore to the sidebar width we started from } // Otherwise size the sidebar accordingly @@ -198,21 +280,21 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal else { if ((sidebarPosition === Position.LEFT && e.currentX - startX >= this.partLayoutInfo.sidebar.minWidth) || (sidebarPosition === Position.RIGHT && startX - e.currentX >= this.partLayoutInfo.sidebar.minWidth)) { - this.startSidebarWidth = this.partLayoutInfo.sidebar.minWidth - (sidebarPosition === Position.LEFT ? e.currentX - startX : startX - e.currentX); + startSidebarWidth = this.partLayoutInfo.sidebar.minWidth - (sidebarPosition === Position.LEFT ? e.currentX - startX : startX - e.currentX); this.sidebarWidth = this.partLayoutInfo.sidebar.minWidth; promise = this.partService.setSideBarHidden(false); } } if (doLayout) { - promise.done(() => this.layout(), errors.onUnexpectedError); + promise.done(() => this.layout({ source: Parts.SIDEBAR_PART }), errors.onUnexpectedError); } - }); + })); - this.sashY.addListener('change', (e: ISashEvent) => { + this.toUnbind.push(this.sashY.addListener('change', (e: ISashEvent) => { let doLayout = false; let isPanelVisible = this.partService.isVisible(Parts.PANEL_PART); - let newSashHeight = this.startPanelHeight - (e.currentY - startY); + let newSashHeight = startPanelHeight - (e.currentY - startY); let promise = TPromise.as(null); // Panel visible @@ -220,10 +302,10 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Automatically hide panel when a certain threshold is met if (newSashHeight + HIDE_PANEL_HEIGHT_THRESHOLD < this.partLayoutInfo.panel.minHeight) { - let dragCompensation = MIN_PANEL_PART_HEIGHT - HIDE_PANEL_HEIGHT_THRESHOLD; + let dragCompensation = this.partLayoutInfo.panel.minHeight - HIDE_PANEL_HEIGHT_THRESHOLD; promise = this.partService.setPanelHidden(true); startY = Math.min(this.sidebarHeight - this.statusbarHeight - this.titlebarHeight, e.currentY + dragCompensation); - this.panelHeight = this.startPanelHeight; // when restoring panel, restore to the panel height we started from + this.panelHeight = startPanelHeight; // when restoring panel, restore to the panel height we started from } // Otherwise size the panel accordingly @@ -236,38 +318,86 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Panel hidden else { if (startY - e.currentY >= this.partLayoutInfo.panel.minHeight) { - this.startPanelHeight = 0; + startPanelHeight = 0; this.panelHeight = this.partLayoutInfo.panel.minHeight; promise = this.partService.setPanelHidden(false); } } if (doLayout) { - promise.done(() => this.layout(), errors.onUnexpectedError); + promise.done(() => this.layout({ source: Parts.PANEL_PART }), errors.onUnexpectedError); } - }); + })); - this.sashX.addListener('end', () => { - this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); - }); + this.toUnbind.push(this.sashXTwo.addListener('change', (e: ISashEvent) => { + let doLayout = false; + let isPanelVisible = this.partService.isVisible(Parts.PANEL_PART); + let newSashWidth = startPanelWidth - (e.currentX - startXTwo); + let promise = TPromise.as(null); - this.sashY.addListener('end', () => { + // Panel visible + if (isPanelVisible) { + + // Automatically hide panel when a certain threshold is met + if (newSashWidth + HIDE_PANEL_WIDTH_THRESHOLD < this.partLayoutInfo.panel.minWidth) { + let dragCompensation = this.partLayoutInfo.panel.minWidth - HIDE_PANEL_WIDTH_THRESHOLD; + promise = this.partService.setPanelHidden(true); + startXTwo = Math.min(this.workbenchSize.width - this.activitybarWidth, e.currentX + dragCompensation); + this.panelWidth = startPanelWidth; // when restoring panel, restore to the panel height we started from + } + + // Otherwise size the panel accordingly + else { + this.panelWidth = newSashWidth; + doLayout = newSashWidth >= this.partLayoutInfo.panel.minWidth; + } + } + + // Panel hidden + else { + if (startXTwo - e.currentX >= this.partLayoutInfo.panel.minWidth) { + startPanelWidth = 0; + this.panelWidth = this.partLayoutInfo.panel.minWidth; + promise = this.partService.setPanelHidden(false); + } + } + + if (doLayout) { + promise.done(() => this.layout({ source: Parts.PANEL_PART }), errors.onUnexpectedError); + } + })); + + this.toUnbind.push(this.sashXOne.addListener('end', () => { + this.storageService.store(WorkbenchLayout.sashXOneWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); + })); + + this.toUnbind.push(this.sashY.addListener('end', () => { this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); - }); + })); - this.sashY.addListener('reset', () => { - this.panelHeight = this.sidebarHeight * DEFAULT_PANEL_HEIGHT_COEFFICIENT; + this.toUnbind.push(this.sashXTwo.addListener('end', () => { + this.storageService.store(WorkbenchLayout.sashXTwoWidthSettingsKey, this.panelWidth, StorageScope.GLOBAL); + })); + + this.toUnbind.push(this.sashY.addListener('reset', () => { + this.panelHeight = this.sidebarHeight * DEFAULT_PANEL_SIZE_COEFFICIENT; this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); - this.partService.setPanelHidden(false).done(() => this.layout(), errors.onUnexpectedError); - }); + this.layout(); + })); - this.sashX.addListener('reset', () => { + this.toUnbind.push(this.sashXOne.addListener('reset', () => { let activeViewlet = this.viewletService.getActiveViewlet(); let optimalWidth = activeViewlet && activeViewlet.getOptimalWidth(); - this.sidebarWidth = Math.max(MIN_SIDEBAR_PART_WIDTH, optimalWidth || 0); - this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); + this.sidebarWidth = optimalWidth || 0; + this.storageService.store(WorkbenchLayout.sashXOneWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); this.partService.setSideBarHidden(false).done(() => this.layout(), errors.onUnexpectedError); - }); + })); + + this.toUnbind.push(this.sashXTwo.addListener('reset', () => { + this.panelWidth = (this.workbenchSize.width - this.sidebarWidth - this.activitybarWidth) * DEFAULT_PANEL_SIZE_COEFFICIENT; + this.storageService.store(WorkbenchLayout.sashXTwoWidthSettingsKey, this.panelWidth, StorageScope.GLOBAL); + this.layout(); + })); } private onEditorsChanged(): void { @@ -277,9 +407,11 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // input change that falls into this category. if (this.workbenchSize && (this.sidebarWidth || this.panelHeight)) { let visibleEditors = this.editorService.getVisibleEditors().length; + const panelVertical = this.partService.getPanelPosition() === Position.RIGHT; if (visibleEditors > 1) { - const sidebarOverflow = this.layoutEditorGroupsVertically && (this.workbenchSize.width - this.sidebarWidth < visibleEditors * MIN_EDITOR_PART_WIDTH); - const panelOverflow = !this.layoutEditorGroupsVertically && (this.workbenchSize.height - this.panelHeight < visibleEditors * MIN_EDITOR_PART_HEIGHT); + const sidebarOverflow = this.layoutEditorGroupsVertically && (this.workbenchSize.width - this.sidebarWidth < visibleEditors * this.partLayoutInfo.editor.minWidth); + const panelOverflow = !this.layoutEditorGroupsVertically && !panelVertical && (this.workbenchSize.height - this.panelHeight < visibleEditors * this.partLayoutInfo.editor.minHeight) || + panelVertical && this.layoutEditorGroupsVertically && (this.workbenchSize.width - this.panelWidth - this.sidebarWidth < visibleEditors * this.partLayoutInfo.editor.minWidth); if (sidebarOverflow || panelOverflow) { this.layout(); @@ -308,77 +440,77 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal const isStatusbarHidden = !this.partService.isVisible(Parts.STATUSBAR_PART); const isSidebarHidden = !this.partService.isVisible(Parts.SIDEBAR_PART); const sidebarPosition = this.partService.getSideBarPosition(); + const panelPosition = this.partService.getPanelPosition(); // Sidebar - let sidebarWidth: number; - if (isSidebarHidden) { - sidebarWidth = 0; - } else if (this.sidebarWidth !== -1) { - sidebarWidth = Math.max(this.partLayoutInfo.sidebar.minWidth, this.sidebarWidth); - } else { - sidebarWidth = this.workbenchSize.width / 5; - this.sidebarWidth = sidebarWidth; + if (this.sidebarWidth === -1) { + this.sidebarWidth = this.workbenchSize.width / 5; } this.statusbarHeight = isStatusbarHidden ? 0 : this.partLayoutInfo.statusbar.height; this.titlebarHeight = isTitlebarHidden ? 0 : this.partLayoutInfo.titlebar.height / getZoomFactor(); // adjust for zoom prevention - const previousMaxPanelHeight = this.sidebarHeight - MIN_EDITOR_PART_HEIGHT; + const previousMaxPanelHeight = this.sidebarHeight - this.partLayoutInfo.editor.minHeight; this.sidebarHeight = this.workbenchSize.height - this.statusbarHeight - this.titlebarHeight; - let sidebarSize = new Dimension(sidebarWidth, this.sidebarHeight); + let sidebarSize = new Dimension(this.sidebarWidth, this.sidebarHeight); // Activity Bar - this.activitybarWidth = isActivityBarHidden ? 0 : this.partLayoutInfo.activitybar.width; let activityBarSize = new Dimension(this.activitybarWidth, sidebarSize.height); // Panel part let panelHeight: number; - const editorCountForHeight = this.editorGroupService.getGroupOrientation() === 'horizontal' ? this.editorGroupService.getStacksModel().groups.length : 1; - const maxPanelHeight = sidebarSize.height - editorCountForHeight * MIN_EDITOR_PART_HEIGHT; + let panelWidth: number; + const maxPanelHeight = this.computeMaxPanelHeight(); + const maxPanelWidth = this.computeMaxPanelWidth(); + if (isPanelHidden) { panelHeight = 0; - } else if (this.panelHeight === previousMaxPanelHeight) { - panelHeight = maxPanelHeight; - } else if (this.panelHeight > 0) { - panelHeight = Math.min(maxPanelHeight, Math.max(this.partLayoutInfo.panel.minHeight, this.panelHeight)); + panelWidth = 0; + } else if (panelPosition === Position.BOTTOM) { + if (this.panelHeight === previousMaxPanelHeight) { + panelHeight = maxPanelHeight; + } else if (this.panelHeight > 0) { + panelHeight = Math.min(maxPanelHeight, Math.max(this.partLayoutInfo.panel.minHeight, this.panelHeight)); + } else { + panelHeight = sidebarSize.height * DEFAULT_PANEL_SIZE_COEFFICIENT; + } + panelWidth = this.workbenchSize.width - sidebarSize.width - activityBarSize.width; + + if (options && options.toggleMaximizedPanel) { + panelHeight = this.panelMaximized ? Math.max(this.partLayoutInfo.panel.minHeight, Math.min(this.panelSizeBeforeMaximized, maxPanelHeight)) : maxPanelHeight; + } + + this.panelMaximized = panelHeight === maxPanelHeight; + if (panelHeight / maxPanelHeight < PANEL_SIZE_BEFORE_MAXIMIZED_BOUNDARY) { + this.panelSizeBeforeMaximized = panelHeight; + } } else { - panelHeight = sidebarSize.height * DEFAULT_PANEL_HEIGHT_COEFFICIENT; + panelHeight = sidebarSize.height; + if (this.panelWidth > 0) { + panelWidth = Math.min(maxPanelWidth, Math.max(this.partLayoutInfo.panel.minWidth, this.panelWidth)); + } else { + panelWidth = (this.workbenchSize.width - activityBarSize.width - sidebarSize.width) * DEFAULT_PANEL_SIZE_COEFFICIENT; + } + + if (options && options.toggleMaximizedPanel) { + panelWidth = this.panelMaximized ? Math.max(this.partLayoutInfo.panel.minWidth, Math.min(this.panelSizeBeforeMaximized, maxPanelWidth)) : maxPanelWidth; + } + + this.panelMaximized = panelWidth === maxPanelWidth; + if (panelWidth / maxPanelWidth < PANEL_SIZE_BEFORE_MAXIMIZED_BOUNDARY) { + this.panelSizeBeforeMaximized = panelWidth; + } } - if (options && options.toggleMaximizedPanel) { - panelHeight = this.panelMaximized ? Math.max(this.partLayoutInfo.panel.minHeight, Math.min(this.panelHeightBeforeMaximized, maxPanelHeight)) : maxPanelHeight; - } - this.panelMaximized = panelHeight === maxPanelHeight; - if (panelHeight / maxPanelHeight < 0.7) { - // Remember the previous height only if the panel size is not too large. - // To get a nice minimize effect even if a user dragged the panel sash to maximum. - this.panelHeightBeforeMaximized = panelHeight; - } - const panelDimension = new Dimension(this.workbenchSize.width - sidebarSize.width - activityBarSize.width, panelHeight); - this.panelWidth = panelDimension.width; + const panelDimension = new Dimension(panelWidth, panelHeight); // Editor let editorSize = { width: 0, - height: 0, - remainderLeft: 0, - remainderRight: 0 + height: 0 }; - editorSize.width = panelDimension.width; - editorSize.height = sidebarSize.height - panelDimension.height; - - // Sidebar hidden - if (isSidebarHidden) { - editorSize.width = this.workbenchSize.width - activityBarSize.width; - - if (sidebarPosition === Position.LEFT) { - editorSize.remainderLeft = Math.round((this.workbenchSize.width - editorSize.width + activityBarSize.width) / 2); - editorSize.remainderRight = this.workbenchSize.width - editorSize.width - editorSize.remainderLeft; - } else { - editorSize.remainderRight = Math.round((this.workbenchSize.width - editorSize.width + activityBarSize.width) / 2); - editorSize.remainderLeft = this.workbenchSize.width - editorSize.width - editorSize.remainderRight; - } - } + editorSize.width = this.workbenchSize.width - sidebarSize.width - activityBarSize.width - (panelPosition === Position.RIGHT ? panelDimension.width : 0); + editorSize.height = sidebarSize.height - (panelPosition === Position.BOTTOM ? panelDimension.height : 0); // Assert Sidebar and Editor Size to not overflow let editorMinWidth = this.partLayoutInfo.editor.minWidth; @@ -395,26 +527,41 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal if (editorSize.width < editorMinWidth) { let diff = editorMinWidth - editorSize.width; editorSize.width = editorMinWidth; - panelDimension.width = editorMinWidth; - sidebarSize.width -= diff; - sidebarSize.width = Math.max(MIN_SIDEBAR_PART_WIDTH, sidebarSize.width); + if (panelPosition === Position.BOTTOM) { + panelDimension.width = editorMinWidth; + } else if (panelDimension.width >= diff && (!options || options.source !== Parts.PANEL_PART)) { + const oldWidth = panelDimension.width; + panelDimension.width = Math.max(this.partLayoutInfo.panel.minWidth, panelDimension.width - diff); + diff = diff - (oldWidth - panelDimension.width); + } + + if (sidebarSize.width >= diff) { + sidebarSize.width -= diff; + sidebarSize.width = Math.max(this.partLayoutInfo.sidebar.minWidth, sidebarSize.width); + } } - if (editorSize.height < editorMinHeight) { + if (editorSize.height < editorMinHeight && panelPosition === Position.BOTTOM) { let diff = editorMinHeight - editorSize.height; editorSize.height = editorMinHeight; + panelDimension.height -= diff; - panelDimension.height = Math.max(MIN_PANEL_PART_HEIGHT, panelDimension.height); + panelDimension.height = Math.max(this.partLayoutInfo.panel.minHeight, panelDimension.height); } if (!isSidebarHidden) { this.sidebarWidth = sidebarSize.width; - this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); + this.storageService.store(WorkbenchLayout.sashXOneWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL); } if (!isPanelHidden) { - this.panelHeight = panelDimension.height; - this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); + if (panelPosition === Position.BOTTOM) { + this.panelHeight = panelDimension.height; + this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL); + } else { + this.panelWidth = panelDimension.width; + this.storageService.store(WorkbenchLayout.sashXTwoWidthSettingsKey, this.panelWidth, StorageScope.GLOBAL); + } } // Workbench @@ -442,16 +589,22 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.editor.getContainer().size(editorSize.width, editorSize.height); this.panel.getContainer().size(panelDimension.width, panelDimension.height); - const editorBottom = this.statusbarHeight + panelDimension.height; - if (isSidebarHidden) { - this.editor.getContainer().position(this.titlebarHeight, editorSize.remainderRight, editorBottom, editorSize.remainderLeft); - this.panel.getContainer().position(editorSize.height + this.titlebarHeight, editorSize.remainderRight, this.statusbarHeight, editorSize.remainderLeft); - } else if (sidebarPosition === Position.LEFT) { - this.editor.getContainer().position(this.titlebarHeight, 0, editorBottom, sidebarSize.width + activityBarSize.width); - this.panel.getContainer().position(editorSize.height + this.titlebarHeight, 0, this.statusbarHeight, sidebarSize.width + activityBarSize.width); + if (panelPosition === Position.BOTTOM) { + if (sidebarPosition === Position.LEFT) { + this.editor.getContainer().position(this.titlebarHeight, 0, this.statusbarHeight + panelDimension.height, sidebarSize.width + activityBarSize.width); + this.panel.getContainer().position(editorSize.height + this.titlebarHeight, 0, this.statusbarHeight, sidebarSize.width + activityBarSize.width); + } else { + this.editor.getContainer().position(this.titlebarHeight, sidebarSize.width, this.statusbarHeight + panelDimension.height, 0); + this.panel.getContainer().position(editorSize.height + this.titlebarHeight, sidebarSize.width, this.statusbarHeight, 0); + } } else { - this.editor.getContainer().position(this.titlebarHeight, sidebarSize.width, editorBottom, 0); - this.panel.getContainer().position(editorSize.height + this.titlebarHeight, sidebarSize.width, this.statusbarHeight, 0); + if (sidebarPosition === Position.LEFT) { + this.editor.getContainer().position(this.titlebarHeight, panelDimension.width, this.statusbarHeight, sidebarSize.width + activityBarSize.width); + this.panel.getContainer().position(this.titlebarHeight, 0, this.statusbarHeight, sidebarSize.width + activityBarSize.width + editorSize.width); + } else { + this.editor.getContainer().position(this.titlebarHeight, sidebarSize.width + activityBarSize.width + panelWidth, this.statusbarHeight, 0); + this.panel.getContainer().position(this.titlebarHeight, sidebarSize.width + activityBarSize.width, this.statusbarHeight, editorSize.width); + } } // Activity Bar Part @@ -471,11 +624,11 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Sidebar Part this.sidebar.getContainer().size(sidebarSize.width, sidebarSize.height); - + const editorAndPanelWidth = editorSize.width + (panelPosition === Position.RIGHT ? panelWidth : 0); if (sidebarPosition === Position.LEFT) { - this.sidebar.getContainer().position(this.titlebarHeight, editorSize.width, 0, activityBarSize.width); + this.sidebar.getContainer().position(this.titlebarHeight, editorAndPanelWidth, this.statusbarHeight, activityBarSize.width); } else { - this.sidebar.getContainer().position(this.titlebarHeight, null, 0, editorSize.width); + this.sidebar.getContainer().position(this.titlebarHeight, activityBarSize.width, this.statusbarHeight, editorAndPanelWidth); } // Statusbar Part @@ -490,8 +643,16 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.quickopen.layout(this.workbenchSize); // Sashes - this.sashX.layout(); - this.sashY.layout(); + this.sashXOne.layout(); + if (panelPosition === Position.BOTTOM) { + this.sashXTwo.hide(); + this.sashY.layout(); + this.sashY.show(); + } else { + this.sashY.hide(); + this.sashXTwo.layout(); + this.sashXTwo.show(); + } // Propagate to Part Layouts this.titlebar.layout(new Dimension(this.workbenchSize.width, this.titlebarHeight)); @@ -509,14 +670,17 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } public getVerticalSashLeft(sash: Sash): number { - let isSidebarVisible = this.partService.isVisible(Parts.SIDEBAR_PART); let sidebarPosition = this.partService.getSideBarPosition(); + if (sash === this.sashXOne) { - if (sidebarPosition === Position.LEFT) { - return isSidebarVisible ? this.sidebarWidth + this.activitybarWidth : this.activitybarWidth; + if (sidebarPosition === Position.LEFT) { + return this.sidebarWidth + this.activitybarWidth; + } + + return this.workbenchSize.width - this.sidebarWidth - this.activitybarWidth; } - return isSidebarVisible ? this.workbenchSize.width - this.sidebarWidth - this.activitybarWidth : this.workbenchSize.width - this.activitybarWidth; + return this.workbenchSize.width - this.panelWidth - (sidebarPosition === Position.RIGHT ? this.sidebarWidth + this.activitybarWidth : 0); } public getVerticalSashHeight(sash: Sash): number { @@ -529,7 +693,11 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } public getHorizontalSashLeft(sash: Sash): number { - return this.partService.getSideBarPosition() === Position.LEFT ? this.getVerticalSashLeft(sash) : 0; + if (this.partService.getSideBarPosition() === Position.RIGHT) { + return 0; + } + + return this.sidebarWidth + this.activitybarWidth; } public getHorizontalSashWidth(sash: Sash): number { @@ -542,36 +710,47 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // change part size along the main axis public resizePart(part: Parts, sizeChange: number): void { - const visibleEditors = this.editorService.getVisibleEditors().length; + const panelPosition = this.partService.getPanelPosition(); const sizeChangePxWidth = this.workbenchSize.width * (sizeChange / 100); const sizeChangePxHeight = this.workbenchSize.height * (sizeChange / 100); let doLayout = false; - let newSashSize: number = 0; switch (part) { case Parts.SIDEBAR_PART: - newSashSize = this.sidebarWidth + sizeChangePxWidth; - this.sidebarWidth = Math.max(this.partLayoutInfo.sidebar.minWidth, newSashSize); // Sidebar can not become smaller than MIN_PART_WIDTH + this.sidebarWidth = this.sidebarWidth + sizeChangePxWidth; // Sidebar can not become smaller than MIN_PART_WIDTH - if (this.layoutEditorGroupsVertically && (this.workbenchSize.width - this.sidebarWidth < visibleEditors * MIN_EDITOR_PART_WIDTH)) { - this.sidebarWidth = (this.workbenchSize.width - visibleEditors * MIN_EDITOR_PART_WIDTH); + if (this.layoutEditorGroupsVertically && (this.workbenchSize.width - this.sidebarWidth < this.editorCountForWidth * MIN_EDITOR_PART_WIDTH)) { + this.sidebarWidth = (this.workbenchSize.width - this.editorCountForWidth * MIN_EDITOR_PART_WIDTH); } doLayout = true; break; case Parts.PANEL_PART: - newSashSize = this.panelHeight + sizeChangePxHeight; - this.panelHeight = Math.max(this.partLayoutInfo.panel.minHeight, newSashSize); + if (panelPosition === Position.BOTTOM) { + this.panelHeight = this.panelHeight + sizeChangePxHeight; + } else if (panelPosition === Position.RIGHT) { + this.panelWidth = this.panelWidth + sizeChangePxWidth; + } + doLayout = true; break; case Parts.EDITOR_PART: // If we have one editor we can cheat and resize sidebar with the negative delta - const visibleEditorCount = this.editorService.getVisibleEditors().length; + // If the sidebar is not visible and panel is, resize panel main axis with negative Delta + if (this.editorCountForWidth === 1) { + if (this.partService.isVisible(Parts.SIDEBAR_PART)) { + this.sidebarWidth = this.sidebarWidth - sizeChangePxWidth; + doLayout = true; + } else if (this.partService.isVisible(Parts.PANEL_PART)) { + if (panelPosition === Position.BOTTOM) { + this.panelHeight = this.panelHeight - sizeChangePxHeight; + } else if (panelPosition === Position.RIGHT) { + this.panelWidth = this.panelWidth - sizeChangePxWidth; + } + doLayout = true; + } - if (visibleEditorCount === 1) { - this.sidebarWidth = this.sidebarWidth - sizeChangePxWidth; - doLayout = true; } else { const stacks = this.editorGroupService.getStacksModel(); const activeGroup = stacks.positionOfGroup(stacks.activeGroup); diff --git a/src/vs/workbench/browser/panel.ts b/src/vs/workbench/browser/panel.ts index 418cb437d8c..d488911608c 100644 --- a/src/vs/workbench/browser/panel.ts +++ b/src/vs/workbench/browser/panel.ts @@ -11,6 +11,7 @@ import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/ import { Action } from 'vs/base/common/actions'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; export abstract class Panel extends Composite implements IPanel { } @@ -19,12 +20,8 @@ export abstract class Panel extends Composite implements IPanel { } */ export class PanelDescriptor extends CompositeDescriptor { - constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, private _commandId?: string) { - super(moduleId, ctorName, id, name, cssClass, order); - } - - public get commandId(): string { - return this._commandId; + constructor(ctor: IConstructorSignature0, id: string, name: string, cssClass?: string, order?: number, _commandId?: string) { + super(ctor, id, name, cssClass, order, _commandId); } } diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index 71e32226b2a..ad324177d50 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -111,7 +111,7 @@ const TITLE_HEIGHT = 35; export class PartLayout { - constructor(private container: Builder, private options: IPartOptions, private titleArea: Builder, private contentArea: Builder) { + constructor(container: Builder, private options: IPartOptions, titleArea: Builder, private contentArea: Builder) { } public layout(dimension: Dimension): Dimension[] { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 2655ebd9c0d..dcb5207ab72 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -6,75 +6,22 @@ 'use strict'; import 'vs/css!./media/activityaction'; -import nls = require('vs/nls'); import DOM = require('vs/base/browser/dom'); +import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; import { TPromise } from 'vs/base/common/winjs.base'; -import { Builder, $ } from 'vs/base/browser/builder'; -import { DelayedDragHandler } from 'vs/base/browser/dnd'; import { Action } from 'vs/base/common/actions'; -import { BaseActionItem, Separator, IBaseActionItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IActivityBarService, ProgressBadge, TextBadge, NumberBadge, IconBadge, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; -import Event, { Emitter } from 'vs/base/common/event'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { IActivity, IGlobalActivity } from 'vs/workbench/browser/activity'; +import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; import { dispose } from 'vs/base/common/lifecycle'; import { IViewletService, } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; -import { contrastBorder, activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; +import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; - -export interface IViewletActivity { - badge: IBadge; - clazz: string; -} - -export class ActivityAction extends Action { - private badge: IBadge; - private _onDidChangeBadge = new Emitter(); - - constructor(private _activity: IActivity) { - super(_activity.id, _activity.name, _activity.cssClass); - - this.badge = null; - } - - public get activity(): IActivity { - return this._activity; - } - - public get onDidChangeBadge(): Event { - return this._onDidChangeBadge.event; - } - - public activate(): void { - if (!this.checked) { - this._setChecked(true); - } - } - - public deactivate(): void { - if (this.checked) { - this._setChecked(false); - } - } - - public getBadge(): IBadge { - return this.badge; - } - - public setBadge(badge: IBadge): void { - this.badge = badge; - this._onDidChangeBadge.fire(this); - } -} +import { ActivityAction, ActivityActionItem, ICompositeBarColors } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; export class ViewletActivityAction extends ActivityAction { @@ -83,15 +30,11 @@ export class ViewletActivityAction extends ActivityAction { private lastRun: number = 0; constructor( - private _viewlet: ViewletDescriptor, + activity: IActivity, @IViewletService private viewletService: IViewletService, @IPartService private partService: IPartService ) { - super(_viewlet); - } - - public get descriptor(): ViewletDescriptor { - return this._viewlet; + super(activity); } public run(event: any): TPromise { @@ -110,492 +53,15 @@ export class ViewletActivityAction extends ActivityAction { const activeViewlet = this.viewletService.getActiveViewlet(); // Hide sidebar if selected viewlet already visible - if (sideBarVisible && activeViewlet && activeViewlet.getId() === this._viewlet.id) { + if (sideBarVisible && activeViewlet && activeViewlet.getId() === this.activity.id) { return this.partService.setSideBarHidden(true); } - return this.viewletService.openViewlet(this._viewlet.id, true) - .then(() => this.activate()); + return this.viewletService.openViewlet(this.activity.id, true).then(() => this.activate()); } } -export class ActivityActionItem extends BaseActionItem { - protected $container: Builder; - protected $label: Builder; - protected $badge: Builder; - - private $badgeContent: Builder; - private mouseUpTimeout: number; - - constructor( - action: ActivityAction, - options: IBaseActionItemOptions, - @IThemeService protected themeService: IThemeService - ) { - super(null, action, options); - - this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose); - action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose); - } - - protected get activity(): IActivity { - return (this._action as ActivityAction).activity; - } - - protected updateStyles(): void { - const theme = this.themeService.getTheme(); - - // Label - if (this.$label) { - const background = theme.getColor(ACTIVITY_BAR_FOREGROUND); - - this.$label.style('background-color', background ? background.toString() : null); - } - - // Badge - if (this.$badgeContent) { - const badgeForeground = theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND); - const badgeBackground = theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND); - const contrastBorderColor = theme.getColor(contrastBorder); - - this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null); - this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null); - - this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null); - this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null); - this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null); - } - } - - public render(container: HTMLElement): void { - super.render(container); - - // Make the container tab-able for keyboard navigation - this.$container = $(container).attr({ - tabIndex: '0', - role: 'button', - title: this.activity.name - }); - - // Try hard to prevent keyboard only focus feedback when using mouse - this.$container.on(DOM.EventType.MOUSE_DOWN, () => { - this.$container.addClass('clicked'); - }); - - this.$container.on(DOM.EventType.MOUSE_UP, () => { - if (this.mouseUpTimeout) { - clearTimeout(this.mouseUpTimeout); - } - - this.mouseUpTimeout = setTimeout(() => { - this.$container.removeClass('clicked'); - }, 800); // delayed to prevent focus feedback from showing on mouse up - }); - - // Label - this.$label = $('a.action-label').appendTo(this.builder); - if (this.activity.cssClass) { - this.$label.addClass(this.activity.cssClass); - } - - this.$badge = this.builder.clone().div({ 'class': 'badge' }, (badge: Builder) => { - this.$badgeContent = badge.div({ 'class': 'badge-content' }); - }); - - this.$badge.hide(); - - this.updateStyles(); - } - - private onThemeChange(theme: ITheme): void { - this.updateStyles(); - } - - public setBadge(badge: IBadge): void { - this.updateBadge(badge); - } - - protected updateBadge(badge: IBadge): void { - this.$badgeContent.empty(); - this.$badge.hide(); - - if (badge) { - - // Number - if (badge instanceof NumberBadge) { - if (badge.number) { - this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString()); - this.$badge.show(); - } - } - - // Text - else if (badge instanceof TextBadge) { - this.$badgeContent.text(badge.text); - this.$badge.show(); - } - - // Text - else if (badge instanceof IconBadge) { - this.$badge.show(); - } - - // Progress - else if (badge instanceof ProgressBadge) { - this.$badge.show(); - } - } - - // Title - let title: string; - if (badge && badge.getDescription()) { - title = `${this.activity.name} - ${badge.getDescription()}`; - } else { - title = this.activity.name; - } - - [this.$label, this.$badge, this.$container].forEach(b => { - if (b) { - b.attr('aria-label', title); - b.title(title); - } - }); - } - - private handleBadgeChangeEvenet(): void { - const action = this.getAction(); - if (action instanceof ActivityAction) { - this.updateBadge(action.getBadge()); - } - } - - public dispose(): void { - super.dispose(); - - if (this.mouseUpTimeout) { - clearTimeout(this.mouseUpTimeout); - } - - this.$badge.destroy(); - } -} - -export class ViewletActionItem extends ActivityActionItem { - - private static manageExtensionAction: ManageExtensionAction; - private static toggleViewletPinnedAction: ToggleViewletPinnedAction; - private static draggedViewlet: ViewletDescriptor; - - private viewletActivity: IActivity; - private cssClass: string; - - constructor( - private action: ViewletActivityAction, - @IContextMenuService private contextMenuService: IContextMenuService, - @IActivityBarService private activityBarService: IActivityBarService, - @IKeybindingService private keybindingService: IKeybindingService, - @IInstantiationService instantiationService: IInstantiationService, - @IThemeService themeService: IThemeService - ) { - super(action, { draggable: true }, themeService); - - this.cssClass = action.class; - - if (!ViewletActionItem.manageExtensionAction) { - ViewletActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction); - } - - if (!ViewletActionItem.toggleViewletPinnedAction) { - ViewletActionItem.toggleViewletPinnedAction = instantiationService.createInstance(ToggleViewletPinnedAction, void 0); - } - } - - protected get activity(): IActivity { - if (!this.viewletActivity) { - let activityName: string; - - const keybinding = this.getKeybindingLabel(this.viewlet.id); - if (keybinding) { - activityName = nls.localize('titleKeybinding', "{0} ({1})", this.viewlet.name, keybinding); - } else { - activityName = this.viewlet.name; - } - - this.viewletActivity = { - id: this.viewlet.id, - cssClass: this.cssClass, - name: activityName - }; - } - - return this.viewletActivity; - } - - private get viewlet(): ViewletDescriptor { - return this.action.descriptor; - } - - private getKeybindingLabel(id: string): string { - const kb = this.keybindingService.lookupKeybinding(id); - if (kb) { - return kb.getLabel(); - } - - return null; - } - - public render(container: HTMLElement): void { - super.render(container); - - this.$container.on('contextmenu', e => { - DOM.EventHelper.stop(e, true); - - this.showContextMenu(container); - }); - - // Allow to drag - this.$container.on(DOM.EventType.DRAG_START, (e: DragEvent) => { - e.dataTransfer.effectAllowed = 'move'; - this.setDraggedViewlet(this.viewlet); - - // Trigger the action even on drag start to prevent clicks from failing that started a drag - if (!this.getAction().checked) { - this.getAction().run(); - } - }); - - // Drag enter - let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470 - this.$container.on(DOM.EventType.DRAG_ENTER, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) { - counter++; - this.updateFromDragging(container, true); - } - }); - - // Drag leave - this.$container.on(DOM.EventType.DRAG_LEAVE, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet) { - counter--; - if (counter === 0) { - this.updateFromDragging(container, false); - } - } - }); - - // Drag end - this.$container.on(DOM.EventType.DRAG_END, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet) { - counter = 0; - this.updateFromDragging(container, false); - - ViewletActionItem.clearDraggedViewlet(); - } - }); - - // Drop - this.$container.on(DOM.EventType.DROP, (e: DragEvent) => { - DOM.EventHelper.stop(e, true); - - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet && draggedViewlet.id !== this.viewlet.id) { - this.updateFromDragging(container, false); - ViewletActionItem.clearDraggedViewlet(); - - this.activityBarService.move(draggedViewlet.id, this.viewlet.id); - } - }); - - // Activate on drag over to reveal targets - [this.$badge, this.$label].forEach(b => new DelayedDragHandler(b.getHTMLElement(), () => { - if (!ViewletActionItem.getDraggedViewlet() && !this.getAction().checked) { - this.getAction().run(); - } - })); - - this.updateStyles(); - } - - private updateFromDragging(element: HTMLElement, isDragging: boolean): void { - const theme = this.themeService.getTheme(); - const dragBackground = theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND); - - element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : null; - } - - public static getDraggedViewlet(): ViewletDescriptor { - return ViewletActionItem.draggedViewlet; - } - - private setDraggedViewlet(viewlet: ViewletDescriptor): void { - ViewletActionItem.draggedViewlet = viewlet; - } - - public static clearDraggedViewlet(): void { - ViewletActionItem.draggedViewlet = void 0; - } - - private showContextMenu(container: HTMLElement): void { - const actions: Action[] = [ViewletActionItem.toggleViewletPinnedAction]; - if (this.viewlet.extensionId) { - actions.push(new Separator()); - actions.push(ViewletActionItem.manageExtensionAction); - } - - const isPinned = this.activityBarService.isPinned(this.viewlet.id); - if (isPinned) { - ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('removeFromActivityBar', "Remove from Activity Bar"); - } else { - ViewletActionItem.toggleViewletPinnedAction.label = nls.localize('keepInActivityBar', "Keep in Activity Bar"); - } - - this.contextMenuService.showContextMenu({ - getAnchor: () => container, - getActionsContext: () => this.viewlet, - getActions: () => TPromise.as(actions) - }); - } - - public focus(): void { - this.$container.domFocus(); - } - - protected _updateClass(): void { - if (this.cssClass) { - this.$badge.removeClass(this.cssClass); - } - - this.cssClass = this.getAction().class; - this.$badge.addClass(this.cssClass); - } - - protected _updateChecked(): void { - if (this.getAction().checked) { - this.$container.addClass('checked'); - } else { - this.$container.removeClass('checked'); - } - } - - protected _updateEnabled(): void { - if (this.getAction().enabled) { - this.builder.removeClass('disabled'); - } else { - this.builder.addClass('disabled'); - } - } - - public dispose(): void { - super.dispose(); - - ViewletActionItem.clearDraggedViewlet(); - - this.$label.destroy(); - } -} - -export class ViewletOverflowActivityAction extends ActivityAction { - - constructor( - private showMenu: () => void - ) { - super({ - id: 'activitybar.additionalViewlets.action', - name: nls.localize('additionalViews', "Additional Views"), - cssClass: 'toggle-more' - }); - } - - public run(event: any): TPromise { - this.showMenu(); - - return TPromise.as(true); - } -} - -export class ViewletOverflowActivityActionItem extends ActivityActionItem { - private name: string; - private cssClass: string; - private actions: OpenViewletAction[]; - - constructor( - action: ActivityAction, - private getOverflowingViewlets: () => ViewletDescriptor[], - private getBadge: (viewlet: ViewletDescriptor) => IBadge, - @IInstantiationService private instantiationService: IInstantiationService, - @IViewletService private viewletService: IViewletService, - @IContextMenuService private contextMenuService: IContextMenuService, - @IThemeService themeService: IThemeService - ) { - super(action, null, themeService); - - this.cssClass = action.class; - this.name = action.label; - } - - public showMenu(): void { - if (this.actions) { - dispose(this.actions); - } - - this.actions = this.getActions(); - - this.contextMenuService.showContextMenu({ - getAnchor: () => this.builder.getHTMLElement(), - getActions: () => TPromise.as(this.actions), - onHide: () => dispose(this.actions) - }); - } - - private getActions(): OpenViewletAction[] { - const activeViewlet = this.viewletService.getActiveViewlet(); - - return this.getOverflowingViewlets().map(viewlet => { - const action = this.instantiationService.createInstance(OpenViewletAction, viewlet); - action.radio = activeViewlet && activeViewlet.getId() === action.id; - - const badge = this.getBadge(action.viewlet); - let suffix: string | number; - if (badge instanceof NumberBadge) { - suffix = badge.number; - } else if (badge instanceof TextBadge) { - suffix = badge.text; - } - - if (suffix) { - action.label = nls.localize('numberBadge', "{0} ({1})", action.viewlet.name, suffix); - } else { - action.label = action.viewlet.name; - } - - return action; - }); - } - - public dispose(): void { - super.dispose(); - - this.actions = dispose(this.actions); - } -} - -class ManageExtensionAction extends Action { - - constructor( - @ICommandService private commandService: ICommandService - ) { - super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension")); - } - - public run(viewlet: ViewletDescriptor): TPromise { - return this.commandService.executeCommand('_extensions.manage', viewlet.extensionId); - } -} - -class OpenViewletAction extends Action { +export class ToggleViewletAction extends Action { constructor( private _viewlet: ViewletDescriptor, @@ -605,44 +71,16 @@ class OpenViewletAction extends Action { super(_viewlet.id, _viewlet.name); } - public get viewlet(): ViewletDescriptor { - return this._viewlet; - } - public run(): TPromise { const sideBarVisible = this.partService.isVisible(Parts.SIDEBAR_PART); const activeViewlet = this.viewletService.getActiveViewlet(); // Hide sidebar if selected viewlet already visible - if (sideBarVisible && activeViewlet && activeViewlet.getId() === this.viewlet.id) { + if (sideBarVisible && activeViewlet && activeViewlet.getId() === this._viewlet.id) { return this.partService.setSideBarHidden(true); } - return this.viewletService.openViewlet(this.viewlet.id, true); - } -} - -export class ToggleViewletPinnedAction extends Action { - - constructor( - private viewlet: ViewletDescriptor, - @IActivityBarService private activityBarService: IActivityBarService - ) { - super('activitybar.show.toggleViewletPinned', viewlet ? viewlet.name : nls.localize('toggle', "Toggle View Pinned")); - - this.checked = this.viewlet && this.activityBarService.isPinned(this.viewlet.id); - } - - public run(context?: ViewletDescriptor): TPromise { - const viewlet = this.viewlet || context; - - if (this.activityBarService.isPinned(viewlet.id)) { - this.activityBarService.unpin(viewlet.id); - } else { - this.activityBarService.pin(viewlet.id); - } - - return TPromise.as(true); + return this.viewletService.openViewlet(this._viewlet.id, true); } } @@ -657,10 +95,11 @@ export class GlobalActivityActionItem extends ActivityActionItem { constructor( action: GlobalActivityAction, + colors: ICompositeBarColors, @IThemeService themeService: IThemeService, @IContextMenuService protected contextMenuService: IContextMenuService ) { - super(action, { draggable: false }, themeService); + super(action, { draggable: false, colors, icon: true }, themeService); } public render(container: HTMLElement): void { @@ -683,6 +122,13 @@ export class GlobalActivityActionItem extends ActivityActionItem { this.showContextMenu(this.$container.getHTMLElement()); } }); + + this.$container.on(TouchEventType.Tap, (e: GestureEvent) => { + DOM.EventHelper.stop(e, true); + + const event = new StandardMouseEvent(e); + this.showContextMenu({ x: event.posx, y: event.posy }); + }); } private showContextMenu(location: HTMLElement | { x: number, y: number }): void { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 6588c1512bd..299431306fe 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -8,37 +8,37 @@ import 'vs/css!./media/activitybarpart'; import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; -import DOM = require('vs/base/browser/dom'); -import * as arrays from 'vs/base/common/arrays'; import { illegalArgument } from 'vs/base/common/errors'; import { Builder, $, Dimension } from 'vs/base/browser/builder'; import { Action } from 'vs/base/common/actions'; -import { ActionsOrientation, ActionBar, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/browser/activity'; +import { ActionsOrientation, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity'; import { Registry } from 'vs/platform/registry/common/platform'; import { Part } from 'vs/workbench/browser/part'; -import { IViewlet } from 'vs/workbench/common/viewlet'; -import { ToggleViewletPinnedAction, ViewletActivityAction, ActivityAction, GlobalActivityActionItem, ViewletActionItem, ViewletOverflowActivityAction, ViewletOverflowActivityActionItem, GlobalActivityAction, IViewletActivity } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IActivityBarService, IBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IPartService, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { Scope as MementoScope } from 'vs/workbench/common/memento'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/toggleActivityBarVisibility'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar'; +import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; -export class ActivitybarPart extends Part implements IActivityBarService { +export class ActivitybarPart extends Part { - private static readonly ACTIVITY_ACTION_HEIGHT = 50; private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets'; + private static COLORS = { + backgroundColor: ACTIVITY_BAR_FOREGROUND, + badgeBackground: ACTIVITY_BAR_BADGE_BACKGROUND, + badgeForeground: ACTIVITY_BAR_BADGE_FOREGROUND, + dragAndDropBackground: ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND + }; public _serviceBrand: any; @@ -47,23 +47,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { private globalActionBar: ActionBar; private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; }; - private viewletSwitcherBar: ActionBar; - private viewletOverflowAction: ViewletOverflowActivityAction; - private viewletOverflowActionItem: ViewletOverflowActivityActionItem; - - private viewletIdToActions: { [viewletId: string]: ActivityAction; }; - private viewletIdToActionItems: { [viewletId: string]: IActionItem; }; - private viewletIdToActivityStack: { [viewletId: string]: IViewletActivity[]; }; - - private memento: object; - private pinnedViewlets: string[]; - private activeUnpinnedViewlet: ViewletDescriptor; + private compositeBar: CompositeBar; constructor( id: string, @IViewletService private viewletService: IViewletService, - @IExtensionService private extensionService: IExtensionService, - @IStorageService private storageService: IStorageService, @IContextMenuService private contextMenuService: IContextMenuService, @IInstantiationService private instantiationService: IInstantiationService, @IPartService private partService: IPartService, @@ -72,59 +60,42 @@ export class ActivitybarPart extends Part implements IActivityBarService { super(id, { hasTitle: false }, themeService); this.globalActivityIdToActions = Object.create(null); - - this.viewletIdToActionItems = Object.create(null); - this.viewletIdToActions = Object.create(null); - this.viewletIdToActivityStack = Object.create(null); - - this.memento = this.getMemento(this.storageService, MementoScope.GLOBAL); - - const pinnedViewlets = this.memento[ActivitybarPart.PINNED_VIEWLETS] as string[]; - - if (pinnedViewlets) { - this.pinnedViewlets = pinnedViewlets - // TODO@Ben: Migrate git => scm viewlet - .map(id => id === 'workbench.view.git' ? 'workbench.view.scm' : id) - .filter(arrays.uniqueFilter(str => str)); - } else { - this.pinnedViewlets = this.viewletService.getViewlets().map(v => v.id); - } - + this.compositeBar = this.instantiationService.createInstance(CompositeBar, { + icon: true, + storageId: ActivitybarPart.PINNED_VIEWLETS, + orientation: ActionsOrientation.VERTICAL, + composites: this.viewletService.getViewlets(), + openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), + getActivityAction: (compositeId: string) => this.instantiationService.createInstance(ViewletActivityAction, this.viewletService.getViewlet(compositeId)), + getCompositePinnedAction: (compositeId: string) => new ToggleCompositePinnedAction(this.viewletService.getViewlet(compositeId), this.compositeBar), + getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletAction, this.viewletService.getViewlet(compositeId)), + getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(), + hidePart: () => this.partService.setSideBarHidden(true), + colors: ActivitybarPart.COLORS, + overflowActionSize: 50 + }); this.registerListeners(); } private registerListeners(): void { // Activate viewlet action on opening of a viewlet - this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.onDidViewletOpen(viewlet))); + this.toUnbind.push(this.viewletService.onDidViewletOpen(viewlet => this.compositeBar.activateComposite(viewlet.getId()))); // Deactivate viewlet action on close - this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onDidViewletClose(viewlet))); + this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId()))); + this.toUnbind.push(this.compositeBar.onDidContextMenu(e => this.showContextMenu(e))); } - private onDidViewletOpen(viewlet: IViewlet): void { - const id = viewlet.getId(); - - if (this.viewletIdToActions[id]) { - this.viewletIdToActions[id].activate(); + public showActivity(viewletOrActionId: string, badge: IBadge, clazz?: string): IDisposable { + if (this.viewletService.getViewlet(viewletOrActionId)) { + return this.compositeBar.showActivity(viewletOrActionId, badge, clazz); } - const activeUnpinnedViewletShouldClose = this.activeUnpinnedViewlet && this.activeUnpinnedViewlet.id !== viewlet.getId(); - const activeUnpinnedViewletShouldShow = !this.getPinnedViewlets().some(v => v.id === viewlet.getId()); - if (activeUnpinnedViewletShouldShow || activeUnpinnedViewletShouldClose) { - this.updateViewletSwitcher(); - } + return this.showGlobalActivity(viewletOrActionId, badge); } - private onDidViewletClose(viewlet: IViewlet): void { - const id = viewlet.getId(); - - if (this.viewletIdToActions[id]) { - this.viewletIdToActions[id].deactivate(); - } - } - - public showGlobalActivity(globalActivityId: string, badge: IBadge): IDisposable { + private showGlobalActivity(globalActivityId: string, badge: IBadge): IDisposable { if (!badge) { throw illegalArgument('badge'); } @@ -139,93 +110,15 @@ export class ActivitybarPart extends Part implements IActivityBarService { return toDisposable(() => action.setBadge(undefined)); } - public showActivity(viewletId: string, badge: IBadge, clazz?: string): IDisposable { - if (!badge) { - throw illegalArgument('badge'); - } - - const activity = { badge, clazz }; - const stack = this.viewletIdToActivityStack[viewletId] || (this.viewletIdToActivityStack[viewletId] = []); - stack.unshift(activity); - - this.updateActivity(viewletId); - - return { - dispose: () => { - const stack = this.viewletIdToActivityStack[viewletId]; - if (!stack) { - return; - } - - const idx = stack.indexOf(activity); - if (idx < 0) { - return; - } - - stack.splice(idx, 1); - if (stack.length === 0) { - delete this.viewletIdToActivityStack[viewletId]; - } - - this.updateActivity(viewletId); - } - }; - } - - private updateActivity(viewletId: string) { - const action = this.viewletIdToActions[viewletId]; - if (!action) { - return; - } - - const stack = this.viewletIdToActivityStack[viewletId]; - - // reset - if (!stack || !stack.length) { - action.setBadge(undefined); - } - - // update - else { - const [{ badge, clazz }] = stack; - action.setBadge(badge); - if (clazz) { - action.class = clazz; - } - } - } - public createContentArea(parent: Builder): Builder { const $el = $(parent); const $result = $('.content').appendTo($el); // Top Actionbar with action items for each viewlet action - this.createViewletSwitcher($result.clone()); + this.compositeBar.create($result.getHTMLElement()); // Top Actionbar with action items for each viewlet action - this.createGlobalActivityActionBar($result.getHTMLElement()); - - // Contextmenu for viewlets - $(parent).on('contextmenu', (e: MouseEvent) => { - DOM.EventHelper.stop(e, true); - - this.showContextMenu(e); - }, this.toUnbind); - - // Allow to drop at the end to move viewlet to the end - $(parent).on(DOM.EventType.DROP, (e: DragEvent) => { - const draggedViewlet = ViewletActionItem.getDraggedViewlet(); - if (draggedViewlet) { - DOM.EventHelper.stop(e, true); - - ViewletActionItem.clearDraggedViewlet(); - - const targetId = this.pinnedViewlets[this.pinnedViewlets.length - 1]; - if (targetId !== draggedViewlet.id) { - this.move(draggedViewlet.id, this.pinnedViewlets[this.pinnedViewlets.length - 1]); - } - } - }); + this.createGlobalActivityActionBar($('.global-activity').appendTo($result).getHTMLElement()); return $result; } @@ -252,31 +145,17 @@ export class ActivitybarPart extends Part implements IActivityBarService { private showContextMenu(e: MouseEvent): void { const event = new StandardMouseEvent(e); - const actions: Action[] = this.viewletService.getViewlets().map(viewlet => this.instantiationService.createInstance(ToggleViewletPinnedAction, viewlet)); + const actions: Action[] = this.viewletService.getViewlets().map(viewlet => this.instantiationService.createInstance(ToggleCompositePinnedAction, viewlet, this.compositeBar)); actions.push(new Separator()); actions.push(this.instantiationService.createInstance(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, nls.localize('hideActivitBar', "Hide Activity Bar"))); this.contextMenuService.showContextMenu({ - getAnchor: () => { return { x: event.posx + 1, y: event.posy }; }, + getAnchor: () => { return { x: event.posx, y: event.posy }; }, getActions: () => TPromise.as(actions), onHide: () => dispose(actions) }); } - private createViewletSwitcher(div: Builder): void { - this.viewletSwitcherBar = new ActionBar(div, { - actionItemProvider: (action: Action) => action instanceof ViewletOverflowActivityAction ? this.viewletOverflowActionItem : this.viewletIdToActionItems[action.id], - orientation: ActionsOrientation.VERTICAL, - ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), - animated: false - }); - - this.updateViewletSwitcher(); - - // Update viewlet switcher when external viewlets become ready - this.extensionService.onReady().then(() => this.updateViewletSwitcher()); - } - private createGlobalActivityActionBar(container: HTMLElement): void { const activityRegistry = Registry.as(GlobalActivityExtensions); const descriptors = activityRegistry.getActivities(); @@ -285,7 +164,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { .map(a => new GlobalActivityAction(a)); this.globalActionBar = new ActionBar(container, { - actionItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionItem, a), + actionItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionItem, a, ActivitybarPart.COLORS), orientation: ActionsOrientation.VERTICAL, ariaLabel: nls.localize('globalActions', "Global Actions"), animated: false @@ -297,234 +176,8 @@ export class ActivitybarPart extends Part implements IActivityBarService { }); } - private updateViewletSwitcher() { - if (!this.viewletSwitcherBar) { - return; // We have not been rendered yet so there is nothing to update. - } - - let viewletsToShow = this.getPinnedViewlets(); - - // Always show the active viewlet even if it is marked to be hidden - const activeViewlet = this.viewletService.getActiveViewlet(); - if (activeViewlet && !viewletsToShow.some(viewlet => viewlet.id === activeViewlet.getId())) { - this.activeUnpinnedViewlet = this.viewletService.getViewlet(activeViewlet.getId()); - viewletsToShow.push(this.activeUnpinnedViewlet); - } else { - this.activeUnpinnedViewlet = void 0; - } - - // Ensure we are not showing more viewlets than we have height for - let overflows = false; - if (this.dimension) { - let availableHeight = this.dimension.height; - if (this.globalActionBar) { - availableHeight -= (this.globalActionBar.items.length * ActivitybarPart.ACTIVITY_ACTION_HEIGHT); // adjust for global actions showing - } - - const maxVisible = Math.floor(availableHeight / ActivitybarPart.ACTIVITY_ACTION_HEIGHT); - overflows = viewletsToShow.length > maxVisible; - - if (overflows) { - viewletsToShow = viewletsToShow.slice(0, maxVisible - 1 /* make room for overflow action */); - } - } - - const visibleViewlets = Object.keys(this.viewletIdToActions); - const visibleViewletsChange = !arrays.equals(viewletsToShow.map(viewlet => viewlet.id), visibleViewlets); - - // Pull out overflow action if there is a viewlet change so that we can add it to the end later - if (this.viewletOverflowAction && visibleViewletsChange) { - this.viewletSwitcherBar.pull(this.viewletSwitcherBar.length() - 1); - - this.viewletOverflowAction.dispose(); - this.viewletOverflowAction = null; - - this.viewletOverflowActionItem.dispose(); - this.viewletOverflowActionItem = null; - } - - // Pull out viewlets that overflow or got hidden - const viewletIdsToShow = viewletsToShow.map(v => v.id); - visibleViewlets.forEach(viewletId => { - if (viewletIdsToShow.indexOf(viewletId) === -1) { - this.pullViewlet(viewletId); - } - }); - - // Built actions for viewlets to show - const newViewletsToShow = viewletsToShow - .filter(viewlet => !this.viewletIdToActions[viewlet.id]) - .map(viewlet => this.toAction(viewlet)); - - // Update when we have new viewlets to show - if (newViewletsToShow.length) { - - // Add to viewlet switcher - this.viewletSwitcherBar.push(newViewletsToShow, { label: true, icon: true }); - - // Make sure to activate the active one - const activeViewlet = this.viewletService.getActiveViewlet(); - if (activeViewlet) { - const activeViewletEntry = this.viewletIdToActions[activeViewlet.getId()]; - if (activeViewletEntry) { - activeViewletEntry.activate(); - } - } - - // Make sure to restore activity - Object.keys(this.viewletIdToActions).forEach(viewletId => { - this.updateActivity(viewletId); - }); - } - - // Add overflow action as needed - if (visibleViewletsChange && overflows) { - this.viewletOverflowAction = this.instantiationService.createInstance(ViewletOverflowActivityAction, () => this.viewletOverflowActionItem.showMenu()); - this.viewletOverflowActionItem = this.instantiationService.createInstance(ViewletOverflowActivityActionItem, this.viewletOverflowAction, () => this.getOverflowingViewlets(), (viewlet: ViewletDescriptor) => this.viewletIdToActivityStack[viewlet.id] && this.viewletIdToActivityStack[viewlet.id][0].badge); - - this.viewletSwitcherBar.push(this.viewletOverflowAction, { label: true, icon: true }); - } - } - - private getOverflowingViewlets(): ViewletDescriptor[] { - const viewlets = this.getPinnedViewlets(); - if (this.activeUnpinnedViewlet) { - viewlets.push(this.activeUnpinnedViewlet); - } - const visibleViewlets = Object.keys(this.viewletIdToActions); - - return viewlets.filter(viewlet => visibleViewlets.indexOf(viewlet.id) === -1); - } - - private getVisibleViewlets(): ViewletDescriptor[] { - const viewlets = this.viewletService.getViewlets(); - const visibleViewlets = Object.keys(this.viewletIdToActions); - - return viewlets.filter(viewlet => visibleViewlets.indexOf(viewlet.id) >= 0); - } - - private getPinnedViewlets(): ViewletDescriptor[] { - return this.pinnedViewlets.map(viewletId => this.viewletService.getViewlet(viewletId)).filter(v => !!v); // ensure to remove those that might no longer exist - } - - private pullViewlet(viewletId: string): void { - const index = Object.keys(this.viewletIdToActions).indexOf(viewletId); - if (index >= 0) { - this.viewletSwitcherBar.pull(index); - - const action = this.viewletIdToActions[viewletId]; - action.dispose(); - delete this.viewletIdToActions[viewletId]; - - const actionItem = this.viewletIdToActionItems[action.id]; - actionItem.dispose(); - delete this.viewletIdToActionItems[action.id]; - } - } - - private toAction(viewlet: ViewletDescriptor): ActivityAction { - const action = this.instantiationService.createInstance(ViewletActivityAction, viewlet); - - this.viewletIdToActionItems[action.id] = this.instantiationService.createInstance(ViewletActionItem, action); - this.viewletIdToActions[viewlet.id] = action; - - return action; - } - public getPinned(): string[] { - return this.pinnedViewlets; - } - - public unpin(viewletId: string): void { - if (!this.isPinned(viewletId)) { - return; - } - - const activeViewlet = this.viewletService.getActiveViewlet(); - const defaultViewletId = this.viewletService.getDefaultViewletId(); - const visibleViewlets = this.getVisibleViewlets(); - - let unpinPromise: TPromise; - - // Case: viewlet is not the active one or the active one is a different one - // Solv: we do nothing - if (!activeViewlet || activeViewlet.getId() !== viewletId) { - unpinPromise = TPromise.as(null); - } - - // Case: viewlet is not the default viewlet and default viewlet is still showing - // Solv: we open the default viewlet - else if (defaultViewletId !== viewletId && this.isPinned(defaultViewletId)) { - unpinPromise = this.viewletService.openViewlet(defaultViewletId, true); - } - - // Case: we closed the last visible viewlet - // Solv: we hide the sidebar - else if (visibleViewlets.length === 1) { - unpinPromise = this.partService.setSideBarHidden(true); - } - - // Case: we closed the default viewlet - // Solv: we open the next visible viewlet from top - else { - unpinPromise = this.viewletService.openViewlet(visibleViewlets.filter(viewlet => viewlet.id !== viewletId)[0].id, true); - } - - unpinPromise.then(() => { - - // then remove from pinned and update switcher - const index = this.pinnedViewlets.indexOf(viewletId); - this.pinnedViewlets.splice(index, 1); - - this.updateViewletSwitcher(); - }); - } - - public isPinned(viewletId: string): boolean { - return this.pinnedViewlets.indexOf(viewletId) >= 0; - } - - public pin(viewletId: string, update = true): void { - if (this.isPinned(viewletId)) { - return; - } - - // first open that viewlet - this.viewletService.openViewlet(viewletId, true).then(() => { - - // then update - this.pinnedViewlets.push(viewletId); - this.pinnedViewlets = arrays.distinct(this.pinnedViewlets); - - if (update) { - this.updateViewletSwitcher(); - } - }); - } - - public move(viewletId: string, toViewletId: string): void { - - // Make sure a moved viewlet gets pinned - if (!this.isPinned(viewletId)) { - this.pin(viewletId, false /* defer update, we take care of it */); - } - - const fromIndex = this.pinnedViewlets.indexOf(viewletId); - const toIndex = this.pinnedViewlets.indexOf(toViewletId); - - this.pinnedViewlets.splice(fromIndex, 1); - this.pinnedViewlets.splice(toIndex, 0, viewletId); - - // Clear viewlets that are impacted by the move - const visibleViewlets = Object.keys(this.viewletIdToActions); - for (let i = Math.min(fromIndex, toIndex); i < visibleViewlets.length; i++) { - this.pullViewlet(visibleViewlets[i]); - } - - // timeout helps to prevent artifacts from showing up - setTimeout(() => { - this.updateViewletSwitcher(); - }, 0); + return this.viewletService.getViewlets().map(v => v.id).filter(id => this.compositeBar.isPinned(id)); } /** @@ -537,16 +190,20 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.dimension = sizes[1]; - // Update switcher to handle overflow issues - this.updateViewletSwitcher(); + let availableHeight = this.dimension.height; + if (this.globalActionBar) { + // adjust height for global actions showing + availableHeight -= (this.globalActionBar.items.length * this.globalActionBar.domNode.clientHeight); + } + this.compositeBar.layout(new Dimension(dimension.width, availableHeight)); return sizes; } public dispose(): void { - if (this.viewletSwitcherBar) { - this.viewletSwitcherBar.dispose(); - this.viewletSwitcherBar = null; + if (this.compositeBar) { + this.compositeBar.dispose(); + this.compositeBar = null; } if (this.globalActionBar) { @@ -558,11 +215,10 @@ export class ActivitybarPart extends Part implements IActivityBarService { } public shutdown(): void { - // Persist Hidden State - this.memento[ActivitybarPart.PINNED_VIEWLETS] = this.pinnedViewlets; + this.compositeBar.store(); // Pass to super super.shutdown(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index f9bb260bdbe..3f07bfcb0d0 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -41,10 +41,6 @@ right: 1px; } -.monaco-workbench > .activitybar > .content .monaco-action-bar .action-label.toggle-more { - -webkit-mask: url('ellipsis-global.svg') no-repeat 50% 50%; -} - .monaco-workbench > .activitybar > .content .monaco-action-bar .badge { position: absolute; top: 5px; diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css index 50061325e7e..2e8ceb738cc 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css @@ -21,4 +21,8 @@ .monaco-workbench > .activitybar [tabindex="0"]:focus { outline: 0 !important; /* activity bar indicates focus custom */ +} + +.monaco-workbench .activitybar > .content > .composite-bar > .monaco-action-bar .action-label.toggle-more { + -webkit-mask: url('ellipsis-global.svg') no-repeat 50% 50%; } \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 31d7e3c1ee8..7906d1d0da7 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -62,8 +62,7 @@ export abstract class CompositePart extends Part { private lastActiveCompositeId: string; private instantiatedComposites: Composite[]; private titleLabel: ICompositeTitleLabel; - private toolBar: ToolBar; - private compositeLoaderPromises: { [compositeId: string]: TPromise; }; + protected toolBar: ToolBar; private progressBar: ProgressBar; private contentAreaSize: Dimension; private telemetryActionsListener: IDisposable; @@ -75,7 +74,7 @@ export abstract class CompositePart extends Part { private messageService: IMessageService, private storageService: IStorageService, private telemetryService: ITelemetryService, - private contextMenuService: IContextMenuService, + protected contextMenuService: IContextMenuService, protected partService: IPartService, private keybindingService: IKeybindingService, protected instantiationService: IInstantiationService, @@ -98,7 +97,6 @@ export abstract class CompositePart extends Part { this.mapProgressServiceToComposite = {}; this.activeComposite = null; this.instantiatedComposites = []; - this.compositeLoaderPromises = {}; this.lastActiveCompositeId = storageService.get(activeCompositeSettingsKey, StorageScope.WORKSPACE, this.defaultCompositeId); } @@ -120,7 +118,7 @@ export abstract class CompositePart extends Part { private doOpenComposite(id: string, focus?: boolean): TPromise { // Use a generated token to avoid race conditions from long running promises - let currentCompositeOpenToken = defaultGenerator.nextId(); + const currentCompositeOpenToken = defaultGenerator.nextId(); this.currentCompositeOpenToken = currentCompositeOpenToken; // Hide current @@ -137,32 +135,31 @@ export abstract class CompositePart extends Part { this.updateTitle(id); // Create composite - return this.createComposite(id, true).then(composite => { + const composite = this.createComposite(id, true); - // Check if another composite opened meanwhile and return in that case - if ((this.currentCompositeOpenToken !== currentCompositeOpenToken) || (this.activeComposite && this.activeComposite.getId() !== composite.getId())) { - return TPromise.as(null); + // Check if another composite opened meanwhile and return in that case + if ((this.currentCompositeOpenToken !== currentCompositeOpenToken) || (this.activeComposite && this.activeComposite.getId() !== composite.getId())) { + return TPromise.as(null); + } + + // Check if composite already visible and just focus in that case + if (this.activeComposite && this.activeComposite.getId() === composite.getId()) { + if (focus) { + composite.focus(); } - // Check if composite already visible and just focus in that case - if (this.activeComposite && this.activeComposite.getId() === composite.getId()) { - if (focus) { - composite.focus(); - } + // Fullfill promise with composite that is being opened + return TPromise.as(composite); + } - // Fullfill promise with composite that is being opened - return TPromise.as(composite); + // Show Composite and Focus + return this.showComposite(composite).then(() => { + if (focus) { + composite.focus(); } - // Show Composite and Focus - return this.showComposite(composite).then(() => { - if (focus) { - composite.focus(); - } - - // Fullfill promise with composite that is being opened - return composite; - }); + // Fullfill promise with composite that is being opened + return composite; }); }).then(composite => { if (composite) { @@ -173,46 +170,31 @@ export abstract class CompositePart extends Part { }); } - protected createComposite(id: string, isActive?: boolean): TPromise { + protected createComposite(id: string, isActive?: boolean): Composite { // Check if composite is already created for (let i = 0; i < this.instantiatedComposites.length; i++) { if (this.instantiatedComposites[i].getId() === id) { - return TPromise.as(this.instantiatedComposites[i]); + return this.instantiatedComposites[i]; } } // Instantiate composite from registry otherwise - let compositeDescriptor = this.registry.getComposite(id); + const compositeDescriptor = this.registry.getComposite(id); if (compositeDescriptor) { - let loaderPromise = this.compositeLoaderPromises[id]; - if (!loaderPromise) { - let progressService = this.instantiationService.createInstance(WorkbenchProgressService, this.progressBar, compositeDescriptor.id, isActive); - let compositeInstantiationService = this.instantiationService.createChild(new ServiceCollection([IProgressService, progressService])); + const progressService = this.instantiationService.createInstance(WorkbenchProgressService, this.progressBar, compositeDescriptor.id, isActive); + const compositeInstantiationService = this.instantiationService.createChild(new ServiceCollection([IProgressService, progressService])); - loaderPromise = compositeInstantiationService.createInstance(compositeDescriptor).then((composite: Composite) => { - this.mapProgressServiceToComposite[composite.getId()] = progressService; + const composite = compositeDescriptor.instantiate(compositeInstantiationService); + this.mapProgressServiceToComposite[composite.getId()] = progressService; - // Remember as Instantiated - this.instantiatedComposites.push(composite); + // Remember as Instantiated + this.instantiatedComposites.push(composite); - // Register to title area update events from the composite - this.instantiatedCompositeListeners.push(composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId()))); + // Register to title area update events from the composite + this.instantiatedCompositeListeners.push(composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId()))); - // Remove from Promises Cache since Loaded - delete this.compositeLoaderPromises[id]; - - return composite; - }); - - // Report progress for slow loading composites - progressService.showWhile(loaderPromise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */); - - // Add to Promise Cache until Loaded - this.compositeLoaderPromises[id] = loaderPromise; - } - - return loaderPromise; + return composite; } throw new Error(strings.format('Unable to find composite with id {0}', id)); @@ -260,7 +242,7 @@ export abstract class CompositePart extends Part { } // Report progress for slow loading composites (but only if we did not create the composites before already) - let progressService = this.mapProgressServiceToComposite[composite.getId()]; + const progressService = this.mapProgressServiceToComposite[composite.getId()]; if (progressService && !compositeContainer) { this.mapProgressServiceToComposite[composite.getId()].showWhile(createCompositePromise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */); } @@ -281,7 +263,7 @@ export abstract class CompositePart extends Part { this.toolBar.actionRunner = composite.getActionRunner(); // Update title with composite title if it differs from descriptor - let descriptor = this.registry.getComposite(composite.getId()); + const descriptor = this.registry.getComposite(composite.getId()); if (descriptor && descriptor.name !== composite.getTitle()) { this.updateTitle(composite.getId(), composite.getTitle()); } @@ -309,6 +291,12 @@ export abstract class CompositePart extends Part { // Log in telemetry if (this.telemetryService) { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: this.nameForTelemetry }); } }); @@ -338,7 +326,7 @@ export abstract class CompositePart extends Part { this.updateTitle(this.activeComposite.getId(), this.activeComposite.getTitle()); // Actions - let actionsBinding = this.collectCompositeActions(this.activeComposite); + const actionsBinding = this.collectCompositeActions(this.activeComposite); this.mapActionsBindingToComposite[this.activeComposite.getId()] = actionsBinding; actionsBinding(); } @@ -350,8 +338,8 @@ export abstract class CompositePart extends Part { } private updateTitle(compositeId: string, compositeTitle?: string): void { - let compositeDescriptor = this.registry.getComposite(compositeId); - if (!compositeDescriptor) { + const compositeDescriptor = this.registry.getComposite(compositeId); + if (!compositeDescriptor || !this.titleLabel) { return; } @@ -369,15 +357,15 @@ export abstract class CompositePart extends Part { private collectCompositeActions(composite: Composite): () => void { // From Composite - let primaryActions: IAction[] = composite.getActions().slice(0); - let secondaryActions: IAction[] = composite.getSecondaryActions().slice(0); + const primaryActions: IAction[] = composite.getActions().slice(0); + const secondaryActions: IAction[] = composite.getSecondaryActions().slice(0); // From Part primaryActions.push(...this.getActions()); secondaryActions.push(...this.getSecondaryActions()); // From Contributions - let actionBarRegistry = Registry.as(Extensions.Actionbar); + const actionBarRegistry = Registry.as(Extensions.Actionbar); primaryActions.push(...actionBarRegistry.getActionBarActionsForContext(this.actionContributionScope, composite)); secondaryActions.push(...actionBarRegistry.getSecondaryActionBarActionsForContext(this.actionContributionScope, composite)); @@ -398,10 +386,10 @@ export abstract class CompositePart extends Part { return TPromise.as(null); // Nothing to do } - let composite = this.activeComposite; + const composite = this.activeComposite; this.activeComposite = null; - let compositeContainer = this.mapCompositeToCompositeContainer[composite.getId()]; + const compositeContainer = this.mapCompositeToCompositeContainer[composite.getId()]; // Indicate to Composite return composite.setVisible(false).then(() => { @@ -424,7 +412,7 @@ export abstract class CompositePart extends Part { public createTitleArea(parent: Builder): Builder { // Title Area Container - let titleArea = $(parent).div({ + const titleArea = $(parent).div({ 'class': ['composite', 'title'] }); @@ -480,7 +468,7 @@ export abstract class CompositePart extends Part { if (this.activeComposite) { const contextMenuActions = this.getTitleAreaContextMenuActions(); if (contextMenuActions.length) { - let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; + const anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, getActions: () => TPromise.as(contextMenuActions), @@ -506,7 +494,7 @@ export abstract class CompositePart extends Part { // Check Registry if (!actionItem) { - let actionBarRegistry = Registry.as(Extensions.Actionbar); + const actionBarRegistry = Registry.as(Extensions.Actionbar); actionItem = actionBarRegistry.getActionItemForContext(this.actionContributionScope, ToolBarContext, action); } @@ -542,7 +530,7 @@ export abstract class CompositePart extends Part { public layout(dimension: Dimension): Dimension[] { // Pass to super - let sizes = super.layout(dimension); + const sizes = super.layout(dimension); // Pass Contentsize to composite this.contentAreaSize = sizes[1]; diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBar.ts b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts new file mode 100644 index 00000000000..d2f8f3533ee --- /dev/null +++ b/src/vs/workbench/browser/parts/compositebar/compositeBar.ts @@ -0,0 +1,459 @@ +/*--------------------------------------------------------------------------------------------- + * 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 nls = require('vs/nls'); +import { Action } from 'vs/base/common/actions'; +import { illegalArgument } from 'vs/base/common/errors'; +import * as dom from 'vs/base/browser/dom'; +import * as arrays from 'vs/base/common/arrays'; +import { Dimension } from 'vs/base/browser/builder'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IBadge } from 'vs/workbench/services/activity/common/activity'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ActionBar, IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import Event, { Emitter } from 'vs/base/common/event'; +import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction, ICompositeBar, ICompositeBarColors } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; +import { TPromise } from 'vs/base/common/winjs.base'; + +export interface ICompositeBarOptions { + icon: boolean; + storageId: string; + orientation: ActionsOrientation; + composites: { id: string, name: string }[]; + colors: ICompositeBarColors; + overflowActionSize: number; + getActivityAction: (compositeId: string) => ActivityAction; + getCompositePinnedAction: (compositeId: string) => Action; + getOnCompositeClickAction: (compositeId: string) => Action; + openComposite: (compositeId: string) => TPromise; + getDefaultCompositeId: () => string; + hidePart: () => TPromise; +} + +export class CompositeBar implements ICompositeBar { + + private _onDidContextMenu: Emitter; + + private dimension: Dimension; + private toDispose: IDisposable[]; + + private compositeSwitcherBar: ActionBar; + private compositeOverflowAction: CompositeOverflowActivityAction; + private compositeOverflowActionItem: CompositeOverflowActivityActionItem; + + private compositeIdToActions: { [compositeId: string]: ActivityAction; }; + private compositeIdToActionItems: { [compositeId: string]: IActionItem; }; + private compositeIdToActivityStack: { [compositeId: string]: ICompositeActivity[]; }; + private compositeSizeInBar: Map; + + private pinnedComposites: string[]; + private activeCompositeId: string; + private activeUnpinnedCompositeId: string; + + constructor( + private options: ICompositeBarOptions, + @IInstantiationService private instantiationService: IInstantiationService, + @IStorageService private storageService: IStorageService, + ) { + this.toDispose = []; + this.compositeIdToActionItems = Object.create(null); + this.compositeIdToActions = Object.create(null); + this.compositeIdToActivityStack = Object.create(null); + this.compositeSizeInBar = new Map(); + + this._onDidContextMenu = new Emitter(); + + const pinnedComposites = JSON.parse(this.storageService.get(this.options.storageId, StorageScope.GLOBAL, null)) as string[]; + if (pinnedComposites) { + this.pinnedComposites = pinnedComposites; + } else { + this.pinnedComposites = this.options.composites.map(c => c.id); + } + } + + public get onDidContextMenu(): Event { + return this._onDidContextMenu.event; + } + + public activateComposite(id: string): void { + if (this.compositeIdToActions[id]) { + this.compositeIdToActions[id].activate(); + } + this.activeCompositeId = id; + + const activeUnpinnedCompositeShouldClose = this.activeUnpinnedCompositeId && this.activeUnpinnedCompositeId !== id; + const activeUnpinnedCompositeShouldShow = !this.pinnedComposites.some(pid => pid === id); + if (activeUnpinnedCompositeShouldShow || activeUnpinnedCompositeShouldClose) { + this.updateCompositeSwitcher(); + } + } + + public deactivateComposite(id: string): void { + if (this.compositeIdToActions[id]) { + this.compositeIdToActions[id].deactivate(); + } + } + + public showActivity(compositeId: string, badge: IBadge, clazz?: string): IDisposable { + if (!badge) { + throw illegalArgument('badge'); + } + + const activity = { badge, clazz }; + const stack = this.compositeIdToActivityStack[compositeId] || (this.compositeIdToActivityStack[compositeId] = []); + stack.unshift(activity); + + this.updateActivity(compositeId); + + return { + dispose: () => { + const stack = this.compositeIdToActivityStack[compositeId]; + if (!stack) { + return; + } + + const idx = stack.indexOf(activity); + if (idx < 0) { + return; + } + + stack.splice(idx, 1); + if (stack.length === 0) { + delete this.compositeIdToActivityStack[compositeId]; + } + + this.updateActivity(compositeId); + } + }; + } + + private updateActivity(compositeId: string) { + const action = this.compositeIdToActions[compositeId]; + if (!action) { + return; + } + + const stack = this.compositeIdToActivityStack[compositeId]; + + // reset + if (!stack || !stack.length) { + action.setBadge(undefined); + } + + // update + else { + const [{ badge, clazz }] = stack; + action.setBadge(badge); + if (clazz) { + action.class = clazz; + } + } + } + + public create(parent: HTMLElement): HTMLElement { + const actionBarDiv = parent.appendChild(dom.$('.composite-bar')); + this.compositeSwitcherBar = new ActionBar(actionBarDiv, { + actionItemProvider: (action: Action) => action instanceof CompositeOverflowActivityAction ? this.compositeOverflowActionItem : this.compositeIdToActionItems[action.id], + orientation: this.options.orientation, + ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), + animated: false, + }); + + // Contextmenu for composites + this.toDispose.push(dom.addDisposableListener(parent, dom.EventType.CONTEXT_MENU, (e: MouseEvent) => { + dom.EventHelper.stop(e, true); + this._onDidContextMenu.fire(e); + })); + + // Allow to drop at the end to move composites to the end + this.toDispose.push(dom.addDisposableListener(parent, dom.EventType.DROP, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId) { + dom.EventHelper.stop(e, true); + CompositeActionItem.clearDraggedComposite(); + + const targetId = this.pinnedComposites[this.pinnedComposites.length - 1]; + if (targetId !== draggedCompositeId) { + this.move(draggedCompositeId, this.pinnedComposites[this.pinnedComposites.length - 1]); + } + } + })); + + return actionBarDiv; + } + + public getAction(compositeId): ActivityAction { + return this.compositeIdToActions[compositeId]; + } + + private updateCompositeSwitcher(): void { + if (!this.compositeSwitcherBar || !this.dimension) { + return; // We have not been rendered yet so there is nothing to update. + } + + let compositesToShow = this.pinnedComposites; + + // Always show the active composite even if it is marked to be hidden + if (this.activeCompositeId && !compositesToShow.some(id => id === this.activeCompositeId)) { + this.activeUnpinnedCompositeId = this.activeCompositeId; + compositesToShow = compositesToShow.concat(this.activeUnpinnedCompositeId); + } else { + this.activeUnpinnedCompositeId = void 0; + } + + // Ensure we are not showing more composites than we have height for + let overflows = false; + let maxVisible = compositesToShow.length; + let size = 0; + const limit = this.options.orientation === ActionsOrientation.VERTICAL ? this.dimension.height : this.dimension.width; + for (let i = 0; i < compositesToShow.length && size <= limit; i++) { + size += this.compositeSizeInBar.get(compositesToShow[i]); + if (size > limit) { + maxVisible = i; + } + } + overflows = compositesToShow.length > maxVisible; + + if (overflows) { + size -= this.compositeSizeInBar.get(compositesToShow[maxVisible]); + compositesToShow = compositesToShow.slice(0, maxVisible); + } + // Check if we need to make extra room for the overflow action + if (overflows && (size + this.options.overflowActionSize > limit)) { + compositesToShow.pop(); + } + if (this.activeCompositeId && compositesToShow.length && compositesToShow.indexOf(this.activeCompositeId) === -1) { + compositesToShow.pop(); + compositesToShow.push(this.activeCompositeId); + } + + const visibleComposites = Object.keys(this.compositeIdToActions); + const visibleCompositesChange = !arrays.equals(compositesToShow, visibleComposites); + + // Pull out overflow action if there is a composite change so that we can add it to the end later + if (this.compositeOverflowAction && visibleCompositesChange) { + this.compositeSwitcherBar.pull(this.compositeSwitcherBar.length() - 1); + + this.compositeOverflowAction.dispose(); + this.compositeOverflowAction = null; + + this.compositeOverflowActionItem.dispose(); + this.compositeOverflowActionItem = null; + } + + // Pull out composites that overflow, got hidden or changed position + visibleComposites.forEach((compositeId, index) => { + if (compositesToShow.indexOf(compositeId) !== index) { + this.pullComposite(compositeId); + } + }); + + // Built actions for composites to show + const newCompositesToShow = compositesToShow + .filter(compositeId => !this.compositeIdToActions[compositeId]) + .map(compositeId => this.toAction(compositeId)); + + // Update when we have new composites to show + if (newCompositesToShow.length) { + + // Add to composite switcher + this.compositeSwitcherBar.push(newCompositesToShow, { label: true, icon: this.options.icon }); + + // Make sure to activate the active one + if (this.activeCompositeId) { + const activeCompositeEntry = this.compositeIdToActions[this.activeCompositeId]; + if (activeCompositeEntry) { + activeCompositeEntry.activate(); + } + } + + // Make sure to restore activity + Object.keys(this.compositeIdToActions).forEach(compositeId => { + this.updateActivity(compositeId); + }); + } + + // Add overflow action as needed + if ((visibleCompositesChange && overflows) || this.compositeSwitcherBar.length() === 0) { + this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => this.compositeOverflowActionItem.showMenu()); + this.compositeOverflowActionItem = this.instantiationService.createInstance( + CompositeOverflowActivityActionItem, + this.compositeOverflowAction, + () => this.getOverflowingComposites(), + () => this.activeCompositeId, + (compositeId: string) => this.compositeIdToActivityStack[compositeId] && this.compositeIdToActivityStack[compositeId][0].badge, + this.options.getOnCompositeClickAction, + this.options.colors + ); + + this.compositeSwitcherBar.push(this.compositeOverflowAction, { label: false, icon: true }); + } + } + + private getOverflowingComposites(): { id: string, name: string }[] { + let overflowingIds = this.pinnedComposites; + if (this.activeUnpinnedCompositeId) { + overflowingIds = overflowingIds.concat(this.activeUnpinnedCompositeId); + } + const visibleComposites = Object.keys(this.compositeIdToActions); + + overflowingIds = overflowingIds.filter(compositeId => visibleComposites.indexOf(compositeId) === -1); + return this.options.composites.filter(c => overflowingIds.indexOf(c.id) !== -1); + } + + private getVisibleComposites(): string[] { + return Object.keys(this.compositeIdToActions); + } + + private pullComposite(compositeId: string): void { + const index = Object.keys(this.compositeIdToActions).indexOf(compositeId); + if (index >= 0) { + this.compositeSwitcherBar.pull(index); + + const action = this.compositeIdToActions[compositeId]; + action.dispose(); + delete this.compositeIdToActions[compositeId]; + + const actionItem = this.compositeIdToActionItems[action.id]; + actionItem.dispose(); + delete this.compositeIdToActionItems[action.id]; + } + } + + private toAction(compositeId: string): ActivityAction { + if (this.compositeIdToActions[compositeId]) { + return this.compositeIdToActions[compositeId]; + } + + const compositeActivityAction = this.options.getActivityAction(compositeId); + const pinnedAction = this.options.getCompositePinnedAction(compositeId); + this.compositeIdToActionItems[compositeId] = this.instantiationService.createInstance(CompositeActionItem, compositeActivityAction, pinnedAction, this.options.colors, this.options.icon, this); + this.compositeIdToActions[compositeId] = compositeActivityAction; + + return compositeActivityAction; + } + + public unpin(compositeId: string): void { + if (!this.isPinned(compositeId)) { + return; + } + + const defaultCompositeId = this.options.getDefaultCompositeId(); + const visibleComposites = this.getVisibleComposites(); + + let unpinPromise: TPromise; + + // Case: composite is not the active one or the active one is a different one + // Solv: we do nothing + if (!this.activeCompositeId || this.activeCompositeId !== compositeId) { + unpinPromise = TPromise.as(null); + } + + // Case: composite is not the default composite and default composite is still showing + // Solv: we open the default composite + else if (defaultCompositeId !== compositeId && this.isPinned(defaultCompositeId)) { + unpinPromise = this.options.openComposite(defaultCompositeId); + } + + // Case: we closed the last visible composite + // Solv: we hide the part + else if (visibleComposites.length === 1) { + unpinPromise = this.options.hidePart(); + } + + // Case: we closed the default composite + // Solv: we open the next visible composite from top + else { + unpinPromise = this.options.openComposite(visibleComposites.filter(cid => cid !== compositeId)[0]); + } + + unpinPromise.then(() => { + // then remove from pinned and update switcher + const index = this.pinnedComposites.indexOf(compositeId); + this.pinnedComposites.splice(index, 1); + + this.updateCompositeSwitcher(); + }); + } + + public isPinned(compositeId: string): boolean { + return this.pinnedComposites.indexOf(compositeId) >= 0; + } + + public pin(compositeId: string, update = true): void { + if (this.isPinned(compositeId)) { + return; + } + + this.options.openComposite(compositeId).then(() => { + this.pinnedComposites.push(compositeId); + this.pinnedComposites = arrays.distinct(this.pinnedComposites); + + if (update) { + this.updateCompositeSwitcher(); + } + }); + } + + public move(compositeId: string, toCompositeId: string): void { + // Make sure both composites are known to this composite bar + if (this.options.composites.filter(c => c.id === compositeId || c.id === toCompositeId).length !== 2) { + return; + } + // Make sure a moved composite gets pinned + if (!this.isPinned(compositeId)) { + this.pin(compositeId, false /* defer update, we take care of it */); + } + + const fromIndex = this.pinnedComposites.indexOf(compositeId); + const toIndex = this.pinnedComposites.indexOf(toCompositeId); + + this.pinnedComposites.splice(fromIndex, 1); + this.pinnedComposites.splice(toIndex, 0, compositeId); + + // Clear composites that are impacted by the move + const visibleComposites = Object.keys(this.compositeIdToActions); + for (let i = Math.min(fromIndex, toIndex); i < visibleComposites.length; i++) { + this.pullComposite(visibleComposites[i]); + } + + // timeout helps to prevent artifacts from showing up + setTimeout(() => { + this.updateCompositeSwitcher(); + }, 0); + } + + public layout(dimension: Dimension): void { + this.dimension = dimension; + if (dimension.height === 0 || dimension.width === 0) { + // Do not layout if not visible. Otherwise the size measurment would be computed wrongly + return; + } + + if (this.compositeSizeInBar.size === 0) { + // Compute size of each composite by getting the size from the css renderer + // Size is later used for overflow computation + this.compositeSwitcherBar.clear(); + this.compositeSwitcherBar.push(this.options.composites.map(c => this.options.getActivityAction(c.id))); + this.options.composites.map((c, index) => this.compositeSizeInBar.set(c.id, this.options.orientation === ActionsOrientation.VERTICAL + ? this.compositeSwitcherBar.getHeight(index) + : this.compositeSwitcherBar.getWidth(index) + )); + this.compositeSwitcherBar.clear(); + } + this.updateCompositeSwitcher(); + } + + public store(): void { + this.storageService.store(this.options.storageId, JSON.stringify(this.pinnedComposites), StorageScope.GLOBAL); + } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + } +} diff --git a/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts new file mode 100644 index 00000000000..aa36133c7ba --- /dev/null +++ b/src/vs/workbench/browser/parts/compositebar/compositeBarActions.ts @@ -0,0 +1,608 @@ +/*--------------------------------------------------------------------------------------------- + * 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 nls = require('vs/nls'); +import { Action } from 'vs/base/common/actions'; +import { TPromise } from 'vs/base/common/winjs.base'; +import * as dom from 'vs/base/browser/dom'; +import { Builder, $ } from 'vs/base/browser/builder'; +import { BaseActionItem, IBaseActionItemOptions, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { dispose } from 'vs/base/common/lifecycle'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; +import { TextBadge, NumberBadge, IBadge, IconBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { DelayedDragHandler } from 'vs/base/browser/dnd'; +import { IActivity } from 'vs/workbench/common/activity'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import Event, { Emitter } from 'vs/base/common/event'; + +export interface ICompositeActivity { + badge: IBadge; + clazz: string; +} + +export interface ICompositeBar { + /** + * Unpins a composite from the composite bar. + */ + unpin(compositeId: string): void; + + /** + * Pin a composite inside the composite bar. + */ + pin(compositeId: string): void; + + /** + * Find out if a composite is pinned in the composite bar. + */ + isPinned(compositeId: string): boolean; + + /** + * Reorder composite ordering by moving a composite to the location of another composite. + */ + move(compositeId: string, tocompositeId: string): void; +} + +export class ActivityAction extends Action { + private badge: IBadge; + private _onDidChangeBadge = new Emitter(); + + constructor(private _activity: IActivity) { + super(_activity.id, _activity.name, _activity.cssClass); + + this.badge = null; + } + + public get activity(): IActivity { + return this._activity; + } + + public get onDidChangeBadge(): Event { + return this._onDidChangeBadge.event; + } + + public activate(): void { + if (!this.checked) { + this._setChecked(true); + } + } + + public deactivate(): void { + if (this.checked) { + this._setChecked(false); + } + } + + public getBadge(): IBadge { + return this.badge; + } + + public setBadge(badge: IBadge): void { + this.badge = badge; + this._onDidChangeBadge.fire(this); + } +} + +export interface ICompositeBarColors { + backgroundColor: string; + badgeBackground: string; + badgeForeground: string; + dragAndDropBackground: string; +} + +export interface IActivityActionItemOptions extends IBaseActionItemOptions { + icon?: boolean; + colors: ICompositeBarColors; +} + +export class ActivityActionItem extends BaseActionItem { + protected $container: Builder; + protected $label: Builder; + protected $badge: Builder; + protected options: IActivityActionItemOptions; + + private $badgeContent: Builder; + private mouseUpTimeout: number; + + constructor( + action: ActivityAction, + options: IActivityActionItemOptions, + @IThemeService protected themeService: IThemeService + ) { + super(null, action, options); + + this.themeService.onThemeChange(this.onThemeChange, this, this._callOnDispose); + action.onDidChangeBadge(this.handleBadgeChangeEvenet, this, this._callOnDispose); + } + + protected get activity(): IActivity { + return (this._action as ActivityAction).activity; + } + + protected updateStyles(): void { + const theme = this.themeService.getTheme(); + + // Label + if (this.$label && this.options.icon) { + const background = theme.getColor(this.options.colors.backgroundColor); + + this.$label.style('background-color', background ? background.toString() : null); + } + + // Badge + if (this.$badgeContent) { + const badgeForeground = theme.getColor(this.options.colors.badgeForeground); + const badgeBackground = theme.getColor(this.options.colors.badgeBackground); + const contrastBorderColor = theme.getColor(contrastBorder); + + this.$badgeContent.style('color', badgeForeground ? badgeForeground.toString() : null); + this.$badgeContent.style('background-color', badgeBackground ? badgeBackground.toString() : null); + + this.$badgeContent.style('border-style', contrastBorderColor ? 'solid' : null); + this.$badgeContent.style('border-width', contrastBorderColor ? '1px' : null); + this.$badgeContent.style('border-color', contrastBorderColor ? contrastBorderColor.toString() : null); + } + } + + public render(container: HTMLElement): void { + super.render(container); + + // Make the container tab-able for keyboard navigation + this.$container = $(container).attr({ + tabIndex: '0', + role: 'button', + title: this.activity.name + }); + + // Try hard to prevent keyboard only focus feedback when using mouse + this.$container.on(dom.EventType.MOUSE_DOWN, () => { + this.$container.addClass('clicked'); + }); + + this.$container.on(dom.EventType.MOUSE_UP, () => { + if (this.mouseUpTimeout) { + clearTimeout(this.mouseUpTimeout); + } + + this.mouseUpTimeout = setTimeout(() => { + this.$container.removeClass('clicked'); + }, 800); // delayed to prevent focus feedback from showing on mouse up + }); + + // Label + this.$label = $('a.action-label').appendTo(this.builder); + if (this.activity.cssClass) { + this.$label.addClass(this.activity.cssClass); + } + if (!this.options.icon) { + this.$label.text(this.getAction().label); + } + + this.$badge = this.builder.clone().div({ 'class': 'badge' }, (badge: Builder) => { + this.$badgeContent = badge.div({ 'class': 'badge-content' }); + }); + + this.$badge.hide(); + + this.updateStyles(); + } + + private onThemeChange(theme: ITheme): void { + this.updateStyles(); + } + + public setBadge(badge: IBadge): void { + this.updateBadge(badge); + } + + protected updateBadge(badge: IBadge): void { + this.$badgeContent.empty(); + this.$badge.hide(); + + if (badge) { + + // Number + if (badge instanceof NumberBadge) { + if (badge.number) { + this.$badgeContent.text(badge.number > 99 ? '99+' : badge.number.toString()); + this.$badge.show(); + } + } + + // Text + else if (badge instanceof TextBadge) { + this.$badgeContent.text(badge.text); + this.$badge.show(); + } + + // Text + else if (badge instanceof IconBadge) { + this.$badge.show(); + } + + // Progress + else if (badge instanceof ProgressBadge) { + this.$badge.show(); + } + } + + // Title + let title: string; + if (badge && badge.getDescription()) { + if (this.activity.name) { + title = nls.localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription()); + } else { + title = badge.getDescription(); + } + } else { + title = this.activity.name; + } + + [this.$label, this.$badge, this.$container].forEach(b => { + if (b) { + b.attr('aria-label', title); + b.title(title); + } + }); + } + + private handleBadgeChangeEvenet(): void { + const action = this.getAction(); + if (action instanceof ActivityAction) { + this.updateBadge(action.getBadge()); + } + } + + public dispose(): void { + super.dispose(); + + if (this.mouseUpTimeout) { + clearTimeout(this.mouseUpTimeout); + } + + this.$badge.destroy(); + } +} + +export class CompositeOverflowActivityAction extends ActivityAction { + + constructor( + private showMenu: () => void + ) { + super({ + id: 'additionalComposites.action', + name: nls.localize('additionalViews', "Additional Views"), + cssClass: 'toggle-more' + }); + } + + public run(event: any): TPromise { + this.showMenu(); + + return TPromise.as(true); + } +} + +export class CompositeOverflowActivityActionItem extends ActivityActionItem { + // @ts-ignore unused property + private name: string; + // @ts-ignore unused property + private cssClass: string; + private actions: Action[]; + + constructor( + action: ActivityAction, + private getOverflowingComposites: () => { id: string, name: string }[], + private getActiveCompositeId: () => string, + private getBadge: (compositeId: string) => IBadge, + private getCompositeOpenAction: (compositeId: string) => Action, + colors: ICompositeBarColors, + // @ts-ignore unused injected service + @IInstantiationService private instantiationService: IInstantiationService, + @IContextMenuService private contextMenuService: IContextMenuService, + @IThemeService themeService: IThemeService + ) { + super(action, { icon: true, colors }, themeService); + + this.cssClass = action.class; + this.name = action.label; + } + + public showMenu(): void { + if (this.actions) { + dispose(this.actions); + } + + this.actions = this.getActions(); + + this.contextMenuService.showContextMenu({ + getAnchor: () => this.builder.getHTMLElement(), + getActions: () => TPromise.as(this.actions), + onHide: () => dispose(this.actions) + }); + } + + private getActions(): Action[] { + return this.getOverflowingComposites().map(composite => { + const action = this.getCompositeOpenAction(composite.id); + action.radio = this.getActiveCompositeId() === action.id; + + const badge = this.getBadge(composite.id); + let suffix: string | number; + if (badge instanceof NumberBadge) { + suffix = badge.number; + } else if (badge instanceof TextBadge) { + suffix = badge.text; + } + + if (suffix) { + action.label = nls.localize('numberBadge', "{0} ({1})", composite.name, suffix); + } else { + action.label = composite.name; + } + + return action; + }); + } + + public dispose(): void { + super.dispose(); + + this.actions = dispose(this.actions); + } +} + +class ManageExtensionAction extends Action { + + constructor( + @ICommandService private commandService: ICommandService + ) { + super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension")); + } + + public run(id: string): TPromise { + return this.commandService.executeCommand('_extensions.manage', id); + } +} + +export class CompositeActionItem extends ActivityActionItem { + + private static manageExtensionAction: ManageExtensionAction; + private static draggedCompositeId: string; + + private compositeActivity: IActivity; + private cssClass: string; + + constructor( + private compositeActivityAction: ActivityAction, + private toggleCompositePinnedAction: Action, + colors: ICompositeBarColors, + icon: boolean, + private compositeBar: ICompositeBar, + @IContextMenuService private contextMenuService: IContextMenuService, + @IKeybindingService private keybindingService: IKeybindingService, + @IInstantiationService instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService + ) { + super(compositeActivityAction, { draggable: true, colors, icon }, themeService); + + this.cssClass = compositeActivityAction.class; + + if (!CompositeActionItem.manageExtensionAction) { + CompositeActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction); + } + } + + protected get activity(): IActivity { + if (!this.compositeActivity) { + let activityName: string; + const keybinding = this.getKeybindingLabel(this.compositeActivityAction.activity.keybindingId); + if (keybinding) { + activityName = nls.localize('titleKeybinding', "{0} ({1})", this.compositeActivityAction.activity.name, keybinding); + } else { + activityName = this.compositeActivityAction.activity.name; + } + + this.compositeActivity = { + id: this.compositeActivityAction.activity.id, + cssClass: this.cssClass, + name: activityName + }; + } + + return this.compositeActivity; + } + + private getKeybindingLabel(id: string): string { + const kb = this.keybindingService.lookupKeybinding(id); + if (kb) { + return kb.getLabel(); + } + + return null; + } + + public render(container: HTMLElement): void { + super.render(container); + + this.$container.on('contextmenu', e => { + dom.EventHelper.stop(e, true); + + this.showContextMenu(container); + }); + + // Allow to drag + this.$container.on(dom.EventType.DRAG_START, (e: DragEvent) => { + e.dataTransfer.effectAllowed = 'move'; + this.setDraggedComposite(this.activity.id); + + // Trigger the action even on drag start to prevent clicks from failing that started a drag + if (!this.getAction().checked) { + this.getAction().run(); + } + }); + + // Drag enter + let counter = 0; // see https://github.com/Microsoft/vscode/issues/14470 + this.$container.on(dom.EventType.DRAG_ENTER, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId && draggedCompositeId !== this.activity.id) { + counter++; + this.updateFromDragging(container, true); + } + }); + + // Drag leave + this.$container.on(dom.EventType.DRAG_LEAVE, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId) { + counter--; + if (counter === 0) { + this.updateFromDragging(container, false); + } + } + }); + + // Drag end + this.$container.on(dom.EventType.DRAG_END, (e: DragEvent) => { + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId) { + counter = 0; + this.updateFromDragging(container, false); + + CompositeActionItem.clearDraggedComposite(); + } + }); + + // Drop + this.$container.on(dom.EventType.DROP, (e: DragEvent) => { + dom.EventHelper.stop(e, true); + + const draggedCompositeId = CompositeActionItem.getDraggedCompositeId(); + if (draggedCompositeId && draggedCompositeId !== this.activity.id) { + this.updateFromDragging(container, false); + CompositeActionItem.clearDraggedComposite(); + + this.compositeBar.move(draggedCompositeId, this.activity.id); + } + }); + + // Activate on drag over to reveal targets + [this.$badge, this.$label].forEach(b => new DelayedDragHandler(b.getHTMLElement(), () => { + if (!CompositeActionItem.getDraggedCompositeId() && !this.getAction().checked) { + this.getAction().run(); + } + })); + + this.updateStyles(); + } + + private updateFromDragging(element: HTMLElement, isDragging: boolean): void { + const theme = this.themeService.getTheme(); + const dragBackground = theme.getColor(this.options.colors.dragAndDropBackground); + + element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : null; + } + + public static getDraggedCompositeId(): string { + return CompositeActionItem.draggedCompositeId; + } + + private setDraggedComposite(compositeId: string): void { + CompositeActionItem.draggedCompositeId = compositeId; + } + + public static clearDraggedComposite(): void { + CompositeActionItem.draggedCompositeId = void 0; + } + + private showContextMenu(container: HTMLElement): void { + const actions: Action[] = [this.toggleCompositePinnedAction]; + if ((this.compositeActivityAction.activity).extensionId) { + actions.push(new Separator()); + actions.push(CompositeActionItem.manageExtensionAction); + } + + const isPinned = this.compositeBar.isPinned(this.activity.id); + if (isPinned) { + this.toggleCompositePinnedAction.label = nls.localize('hide', "Hide"); + this.toggleCompositePinnedAction.checked = false; + } else { + this.toggleCompositePinnedAction.label = nls.localize('keep', "Keep"); + } + + this.contextMenuService.showContextMenu({ + getAnchor: () => container, + getActionsContext: () => this.activity.id, + getActions: () => TPromise.as(actions) + }); + } + + public focus(): void { + this.$container.domFocus(); + } + + protected _updateClass(): void { + if (this.cssClass) { + this.$badge.removeClass(this.cssClass); + } + + this.cssClass = this.getAction().class; + this.$badge.addClass(this.cssClass); + } + + protected _updateChecked(): void { + if (this.getAction().checked) { + this.$container.addClass('checked'); + } else { + this.$container.removeClass('checked'); + } + } + + protected _updateEnabled(): void { + if (this.getAction().enabled) { + this.builder.removeClass('disabled'); + } else { + this.builder.addClass('disabled'); + } + } + + public dispose(): void { + super.dispose(); + + CompositeActionItem.clearDraggedComposite(); + + this.$label.destroy(); + } +} + +export class ToggleCompositePinnedAction extends Action { + + constructor( + private activity: IActivity, + private compositeBar: ICompositeBar + ) { + super('show.toggleCompositePinned', activity ? activity.name : nls.localize('toggle', "Toggle View Pinned")); + + this.checked = this.activity && this.compositeBar.isPinned(this.activity.id); + } + + public run(context: string): TPromise { + const id = this.activity ? this.activity.id : context; + + if (this.compositeBar.isPinned(id)) { + this.compositeBar.unpin(id); + } else { + this.compositeBar.pin(id); + } + + return TPromise.as(true); + } +} diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index ba76dca67e9..b581b9743c0 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -5,14 +5,10 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import types = require('vs/base/common/types'); import { Builder } from 'vs/base/browser/builder'; -import { Registry } from 'vs/platform/registry/common/platform'; import { Panel } from 'vs/workbench/browser/panel'; -import { EditorInput, EditorOptions, IEditorDescriptor, IEditorInputFactory, IEditorRegistry, Extensions, IFileInputFactory } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { IEditor, Position } from 'vs/platform/editor/common/editor'; -import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; -import { SyncDescriptor, AsyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -123,183 +119,4 @@ export abstract class BaseEditor extends Panel implements IEditor { // Super Dispose super.dispose(); } -} - -/** - * A lightweight descriptor of an editor. The descriptor is deferred so that heavy editors - * can load lazily in the workbench. - */ -export class EditorDescriptor extends AsyncDescriptor implements IEditorDescriptor { - private id: string; - private name: string; - - constructor(id: string, name: string, moduleId: string, ctorName: string) { - super(moduleId, ctorName); - - this.id = id; - this.name = name; - } - - public getId(): string { - return this.id; - } - - public getName(): string { - return this.name; - } - - public describes(obj: any): boolean { - return obj instanceof BaseEditor && (obj).getId() === this.id; - } -} - -const INPUT_DESCRIPTORS_PROPERTY = '__$inputDescriptors'; - -class EditorRegistry implements IEditorRegistry { - private editors: EditorDescriptor[]; - private instantiationService: IInstantiationService; - private fileInputFactory: IFileInputFactory; - private editorInputFactoryConstructors: { [editorInputId: string]: IConstructorSignature0 } = Object.create(null); - private editorInputFactoryInstances: { [editorInputId: string]: IEditorInputFactory } = Object.create(null); - - constructor() { - this.editors = []; - } - - public setInstantiationService(service: IInstantiationService): void { - this.instantiationService = service; - - for (let key in this.editorInputFactoryConstructors) { - const element = this.editorInputFactoryConstructors[key]; - this.createEditorInputFactory(key, element); - } - - this.editorInputFactoryConstructors = {}; - } - - private createEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { - const instance = this.instantiationService.createInstance(ctor); - this.editorInputFactoryInstances[editorInputId] = instance; - } - - public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor): void; - public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor[]): void; - public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: any): void { - - // Support both non-array and array parameter - let inputDescriptors: SyncDescriptor[] = []; - if (!types.isArray(editorInputDescriptor)) { - inputDescriptors.push(editorInputDescriptor); - } else { - inputDescriptors = editorInputDescriptor; - } - - // Register (Support multiple Editors per Input) - descriptor[INPUT_DESCRIPTORS_PROPERTY] = inputDescriptors; - this.editors.push(descriptor); - } - - public getEditor(input: EditorInput): EditorDescriptor { - const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] => { - const matchingDescriptors: EditorDescriptor[] = []; - - for (let i = 0; i < this.editors.length; i++) { - const editor = this.editors[i]; - const inputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; - for (let j = 0; j < inputDescriptors.length; j++) { - const inputClass = inputDescriptors[j].ctor; - - // Direct check on constructor type (ignores prototype chain) - if (!byInstanceOf && input.constructor === inputClass) { - matchingDescriptors.push(editor); - break; - } - - // Normal instanceof check - else if (byInstanceOf && input instanceof inputClass) { - matchingDescriptors.push(editor); - break; - } - } - } - - // If no descriptors found, continue search using instanceof and prototype chain - if (!byInstanceOf && matchingDescriptors.length === 0) { - return findEditorDescriptors(input, true); - } - - if (byInstanceOf) { - return matchingDescriptors; - } - - return matchingDescriptors; - }; - - const descriptors = findEditorDescriptors(input); - if (descriptors && descriptors.length > 0) { - - // Ask the input for its preferred Editor - const preferredEditorId = input.getPreferredEditorId(descriptors.map(d => d.getId())); - if (preferredEditorId) { - return this.getEditorById(preferredEditorId); - } - - // Otherwise, first come first serve - return descriptors[0]; - } - - return null; - } - - public getEditorById(editorId: string): EditorDescriptor { - for (let i = 0; i < this.editors.length; i++) { - const editor = this.editors[i]; - if (editor.getId() === editorId) { - return editor; - } - } - - return null; - } - - public getEditors(): EditorDescriptor[] { - return this.editors.slice(0); - } - - public setEditors(editorsToSet: EditorDescriptor[]): void { - this.editors = editorsToSet; - } - - public getEditorInputs(): any[] { - const inputClasses: any[] = []; - for (let i = 0; i < this.editors.length; i++) { - const editor = this.editors[i]; - const editorInputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; - inputClasses.push(...editorInputDescriptors.map(descriptor => descriptor.ctor)); - } - - return inputClasses; - } - - public registerFileInputFactory(factory: IFileInputFactory): void { - this.fileInputFactory = factory; - } - - public getFileInputFactory(): IFileInputFactory { - return this.fileInputFactory; - } - - public registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { - if (!this.instantiationService) { - this.editorInputFactoryConstructors[editorInputId] = ctor; - } else { - this.createEditorInputFactory(editorInputId, ctor); - } - } - - public getEditorInputFactory(editorInputId: string): IEditorInputFactory { - return this.editorInputFactoryInstances[editorInputId]; - } -} - -Registry.add(Extensions.Editors, new EditorRegistry()); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 3cde1b68478..f5678672e9b 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -10,8 +10,8 @@ import URI from 'vs/base/common/uri'; import { Action, IAction } from 'vs/base/common/actions'; import { IEditorQuickOpenEntry, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { StatusbarItemDescriptor, StatusbarAlignment, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar'; -import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorInput, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; +import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor'; import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor'; import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; @@ -22,15 +22,15 @@ import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor'; import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { CloseEditorsInGroupAction, CloseEditorsInOtherGroupsAction, CloseAllEditorsAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, JoinTwoGroupsAction, KeepEditorAction, CloseOtherEditorsInGroupAction, OpenToSideAction, RevertAndCloseEditorAction, NavigateBetweenGroupsAction, FocusActiveGroupAction, FocusFirstGroupAction, FocusSecondGroupAction, FocusThirdGroupAction, EvenGroupWidthsAction, MaximizeGroupAction, MinimizeOtherGroupsAction, FocusPreviousGroup, FocusNextGroup, ShowEditorsInGroupOneAction, - toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, CloseRightEditorsInGroupAction, CloseUnmodifiedEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, ReopenClosedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, NAVIGATE_IN_GROUP_ONE_PREFIX, + toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, CloseRightEditorsInGroupAction, CloseUnmodifiedEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, NavigateLastAction, ReopenClosedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, NAVIGATE_IN_GROUP_ONE_PREFIX, OpenPreviousEditorFromHistoryAction, ShowAllEditorsAction, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, ClearEditorHistoryAction, ShowEditorsInGroupTwoAction, MoveEditorRightInGroupAction, OpenNextEditorInGroup, OpenPreviousEditorInGroup, OpenNextRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorAction, NAVIGATE_IN_GROUP_TWO_PREFIX, ShowEditorsInGroupThreeAction, NAVIGATE_IN_GROUP_THREE_PREFIX, FocusLastEditorInStackAction, OpenNextRecentlyUsedEditorInGroupAction, MoveEditorToPreviousGroupAction, MoveEditorToNextGroupAction, MoveEditorLeftInGroupAction, ClearRecentFilesAction } from 'vs/workbench/browser/parts/editor/editorActions'; @@ -39,14 +39,15 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { getQuickNavigateHandler, inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { isMacintosh } from 'vs/base/common/platform'; +import { GroupOnePicker, GroupTwoPicker, GroupThreePicker, AllEditorsPicker } from 'vs/workbench/browser/parts/editor/editorPicker'; // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( + TextResourceEditor, TextResourceEditor.ID, nls.localize('textEditor', "Text Editor"), - 'vs/workbench/browser/parts/editor/textResourceEditor', - 'TextResourceEditor' ), [ new SyncDescriptor(UntitledEditorInput), @@ -57,10 +58,9 @@ Registry.as(EditorExtensions.Editors).registerEditor( // Register Text Diff Editor Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( + TextDiffEditor, TextDiffEditor.ID, - nls.localize('textDiffEditor', "Text Diff Editor"), - 'vs/workbench/browser/parts/editor/textDiffEditor', - 'TextDiffEditor' + nls.localize('textDiffEditor', "Text Diff Editor") ), [ new SyncDescriptor(DiffEditorInput) @@ -70,10 +70,9 @@ Registry.as(EditorExtensions.Editors).registerEditor( // Register Binary Resource Diff Editor Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( + BinaryResourceDiffEditor, BinaryResourceDiffEditor.ID, - nls.localize('binaryDiffEditor', "Binary Diff Editor"), - 'vs/workbench/browser/parts/editor/binaryDiffEditor', - 'BinaryResourceDiffEditor' + nls.localize('binaryDiffEditor', "Binary Diff Editor") ), [ new SyncDescriptor(DiffEditorInput) @@ -82,10 +81,9 @@ Registry.as(EditorExtensions.Editors).registerEditor( Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( + SideBySideEditor, SideBySideEditor.ID, - nls.localize('sideBySideEditor', "Side by Side Editor"), - 'vs/workbench/browser/parts/editor/sideBySideEditor', - 'SideBySideEditor' + nls.localize('sideBySideEditor', "Side by Side Editor") ), [ new SyncDescriptor(SideBySideEditorInput) @@ -142,7 +140,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory { } } -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(UntitledEditorInput.ID, UntitledEditorInputFactory); +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(UntitledEditorInput.ID, UntitledEditorInputFactory); interface ISerializedSideBySideEditorInput { name: string; @@ -162,7 +160,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory { const input = editorInput; if (input.details && input.master) { - const registry = Registry.as(EditorExtensions.Editors); + const registry = Registry.as(EditorInputExtensions.EditorInputFactories); const detailsInputFactory = registry.getEditorInputFactory(input.details.getTypeId()); const masterInputFactory = registry.getEditorInputFactory(input.master.getTypeId()); @@ -189,7 +187,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory { public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput { const deserialized: ISerializedSideBySideEditorInput = JSON.parse(serializedEditorInput); - const registry = Registry.as(EditorExtensions.Editors); + const registry = Registry.as(EditorInputExtensions.EditorInputFactories); const detailsInputFactory = registry.getEditorInputFactory(deserialized.detailsTypeId); const masterInputFactory = registry.getEditorInputFactory(deserialized.masterTypeId); @@ -206,7 +204,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory { } } -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(SideBySideEditorInput.ID, SideBySideEditorInputFactory); +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(SideBySideEditorInput.ID, SideBySideEditorInputFactory); // Register Editor Status const statusBar = Registry.as(StatusExtensions.Statusbar); @@ -265,8 +263,8 @@ const editorPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExp Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/browser/parts/editor/editorPicker', - 'GroupOnePicker', + GroupOnePicker, + GroupOnePicker.ID, NAVIGATE_IN_GROUP_ONE_PREFIX, editorPickerContextKey, [ @@ -291,8 +289,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/browser/parts/editor/editorPicker', - 'GroupTwoPicker', + GroupTwoPicker, + GroupTwoPicker.ID, NAVIGATE_IN_GROUP_TWO_PREFIX, editorPickerContextKey, [] @@ -301,8 +299,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/browser/parts/editor/editorPicker', - 'GroupThreePicker', + GroupThreePicker, + GroupThreePicker.ID, NAVIGATE_IN_GROUP_THREE_PREFIX, editorPickerContextKey, [] @@ -311,8 +309,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/browser/parts/editor/editorPicker', - 'AllEditorsPicker', + AllEditorsPicker, + AllEditorsPicker.ID, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, editorPickerContextKey, [ @@ -338,7 +336,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ShowEditorsInGroupThre registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextEditor, OpenNextEditor.ID, OpenNextEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET] } }), 'View: Open Next Editor', category); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditor, OpenPreviousEditor.ID, OpenPreviousEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET] } }), 'View: Open Previous Editor', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ReopenClosedEditorAction, ReopenClosedEditorAction.ID, ReopenClosedEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_T }), 'View: Reopen Closed Editor', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'View: Clear Recently Opened', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'File: Clear Recently Opened', nls.localize('file', "File")); registry.registerWorkbenchAction(new SyncActionDescriptor(KeepEditorAction, KeepEditorAction.ID, KeepEditorAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.Enter) }), 'View: Keep Editor', category); registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllEditorsAction, CloseAllEditorsAction.ID, CloseAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', category); registry.registerWorkbenchAction(new SyncActionDescriptor(CloseLeftEditorsInGroupAction, CloseLeftEditorsInGroupAction.ID, CloseLeftEditorsInGroupAction.LABEL), 'View: Close Editors to the Left', category); @@ -368,6 +366,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousGroup, Fo registry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextGroup, FocusNextGroup.ID, FocusNextGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.RightArrow) }), 'View: Focus Next Group', category); registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateForwardAction, NavigateForwardAction.ID, NavigateForwardAction.LABEL, { primary: null, win: { primary: KeyMod.Alt | KeyCode.RightArrow }, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS } }), 'Go Forward'); registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateBackwardsAction, NavigateBackwardsAction.ID, NavigateBackwardsAction.LABEL, { primary: null, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS } }), 'Go Back'); +registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLastAction, NavigateLastAction.ID, NavigateLastAction.LABEL), 'Go Last'); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditorFromHistoryAction, OpenPreviousEditorFromHistoryAction.ID, OpenPreviousEditorFromHistoryAction.LABEL), 'Open Previous Editor from History'); registry.registerWorkbenchAction(new SyncActionDescriptor(ClearEditorHistoryAction, ClearEditorHistoryAction.ID, ClearEditorHistoryAction.LABEL), 'Clear Editor History'); registry.registerWorkbenchAction(new SyncActionDescriptor(RevertAndCloseEditorAction, RevertAndCloseEditorAction.ID, RevertAndCloseEditorAction.LABEL), 'View: Revert and Close Editor', category); @@ -375,8 +374,8 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(RevertAndCloseEditorAc // Register Editor Picker Actions including quick navigate support const openNextEditorKeybinding = { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }; const openPreviousEditorKeybinding = { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }; -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction.ID, OpenNextRecentlyUsedEditorInGroupAction.LABEL, openNextEditorKeybinding), 'Open Next Recently Used Editor in Group'); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction.ID, OpenPreviousRecentlyUsedEditorInGroupAction.LABEL, openPreviousEditorKeybinding), 'Open Previous Recently Used Editor in Group'); +registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction.ID, OpenNextRecentlyUsedEditorInGroupAction.LABEL, openNextEditorKeybinding), 'View: Open Next Recently Used Editor in Group', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction.ID, OpenPreviousRecentlyUsedEditorInGroupAction.LABEL, openPreviousEditorKeybinding), 'View: Open Previous Recently Used Editor in Group', category); const quickOpenNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker'; KeybindingsRegistry.registerCommandAndKeybindingRule({ @@ -400,4 +399,17 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ // Editor Commands -editorCommands.setup(); \ No newline at end of file +editorCommands.setup(); + +// Touch Bar +if (isMacintosh) { + MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { + command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/back-tb.png')).fsPath }, + group: 'navigation' + }); + + MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { + command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/forward-tb.png')).fsPath }, + group: 'navigation' + }); +} \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 694c02bdde0..7dce52b6198 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -9,7 +9,7 @@ import nls = require('vs/nls'); import { Action } from 'vs/base/common/actions'; import { mixin } from 'vs/base/common/objects'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; -import { EditorInput, hasResource, TextEditorOptions, EditorOptions, IEditorIdentifier, IEditorContext, ActiveEditorMoveArguments, ActiveEditorMovePositioning, EditorCommands, ConfirmResult } from 'vs/workbench/common/editor'; +import { EditorInput, TextEditorOptions, EditorOptions, IEditorIdentifier, IEditorContext, ActiveEditorMoveArguments, ActiveEditorMovePositioning, EditorCommands, ConfirmResult } from 'vs/workbench/common/editor'; import { QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry, QuickOpenAction } from 'vs/workbench/browser/quickopen'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -113,7 +113,6 @@ export class JoinTwoGroupsAction extends Action { constructor( id: string, label: string, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService ) { super(id, label); @@ -255,16 +254,13 @@ export class FocusFirstGroupAction extends Action { // Since no editor is currently opened, try to open last history entry to the target side const history = this.historyService.getHistory(); - for (let input of history) { - - // For now only support to open files from history to the side + if (history.length > 0) { + const input = history[0]; if (input instanceof EditorInput) { - if (hasResource(input, { filter: ['file', 'untitled'] })) { - return this.editorService.openEditor(input, null, Position.ONE); - } - } else { - return this.editorService.openEditor(input as IResourceInput, Position.ONE); + return this.editorService.openEditor(input, null, Position.ONE); } + + return this.editorService.openEditor(input as IResourceInput, Position.ONE); } return TPromise.as(true); @@ -327,15 +323,11 @@ export abstract class BaseFocusSideGroupAction extends Action { else if (referenceEditor) { const history = this.historyService.getHistory(); for (let input of history) { - - // For now only support to open files from history to the side - if (input instanceof EditorInput) { - if (hasResource(input, { filter: ['file', 'untitled'] })) { - return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide()); - } - } else { - return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: true } }, this.getTargetEditorSide()); + if (input instanceof EditorInput && input.supportsSplitEditor()) { + return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide()); } + + return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: true } }, this.getTargetEditorSide()); } } @@ -1116,6 +1108,22 @@ export class NavigateBackwardsAction extends Action { } } +export class NavigateLastAction extends Action { + + public static ID = 'workbench.action.navigateLast'; + public static LABEL = nls.localize('navigateLast', "Go Last"); + + constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) { + super(id, label); + } + + public run(): TPromise { + this.historyService.last(); + + return TPromise.as(null); + } +} + export class ReopenClosedEditorAction extends Action { public static ID = 'workbench.action.reopenClosedEditor'; diff --git a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts index 91769ce5d76..7dd9f702394 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts @@ -20,7 +20,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { isMacintosh } from 'vs/base/common/platform'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Position, POSITIONS } from 'vs/platform/editor/common/editor'; -import { IEditorGroupService, ITabOptions, GroupArrangement, GroupOrientation } from 'vs/workbench/services/group/common/groupService'; +import { IEditorGroupService, IEditorTabOptions, GroupArrangement, GroupOrientation } from 'vs/workbench/services/group/common/groupService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -30,7 +30,7 @@ import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleCon import { TitleControl, ITitleAreaControl, handleWorkspaceExternalDrop } from 'vs/workbench/browser/parts/editor/titleControl'; import { NoTabsTitleControl } from 'vs/workbench/browser/parts/editor/noTabsTitleControl'; import { IEditorStacksModel, IStacksModelChangeEvent, IEditorGroup, EditorOptions, TextEditorOptions, IEditorIdentifier } from 'vs/workbench/common/editor'; -import { extractResources } from 'vs/base/browser/dnd'; +import { extractResources } from 'vs/workbench/browser/editor'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -73,6 +73,7 @@ export interface IEditorGroupsControl { getInstantiationService(position: Position): IInstantiationService; getProgressBar(position: Position): ProgressBar; updateProgress(position: Position, state: ProgressState): void; + updateTitleAreas(refreshActive?: boolean): void; layout(dimension: Dimension): void; layout(position: Position): void; @@ -115,7 +116,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro private layoutVertically: boolean; - private tabOptions: ITabOptions; + private tabOptions: IEditorTabOptions; private silos: Builder[]; private silosSize: number[]; @@ -225,7 +226,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro this.extensionService.onReady().then(() => this.onExtensionsReady()); } - private updateTabOptions(tabOptions: ITabOptions, refresh?: boolean): void { + private updateTabOptions(tabOptions: IEditorTabOptions, refresh?: boolean): void { const tabCloseButton = this.tabOptions ? this.tabOptions.tabCloseButton : 'right'; this.tabOptions = tabOptions; @@ -443,6 +444,9 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro // Log this fact in telemetry if (this.telemetryService) { + /* __GDPR__ + "workbenchEditorMaximized" : {} + */ this.telemetryService.publicLog('workbenchEditorMaximized'); } @@ -2077,6 +2081,32 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro return silo ? silo.child().getProperty(key) : void 0; } + public updateTitleAreas(refreshActive?: boolean): void { + POSITIONS.forEach(position => { + const group = this.stacks.groupAt(position); + if (!group) { + return; + } + + const titleControl = this.getTitleAreaControl(position); + if (!titleControl) { + return; + } + + // Make sure the active group is shown in the title + // and refresh it if we are instructed to refresh it + if (refreshActive && group.isActive) { + titleControl.setContext(group); + titleControl.refresh(true); + } + + // Otherwise, just refresh the toolbar + else { + titleControl.updateEditorActionsToolbar(); + } + }); + } + public updateProgress(position: Position, state: ProgressState): void { const progressbar = this.getProgressBar(position); if (!progressbar) { diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index dadca40e0fe..24347e31208 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -20,17 +20,17 @@ import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Scope as MementoScope } from 'vs/workbench/common/memento'; import { Part } from 'vs/workbench/browser/part'; -import { BaseEditor, EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IEditorRegistry, Extensions as EditorExtensions, EditorInput, EditorOptions, ConfirmResult, IWorkbenchEditorConfiguration, IEditorDescriptor, TextEditorOptions, SideBySideEditorInput, TextCompareEditorVisible, TEXT_DIFF_EDITOR_ID } from 'vs/workbench/common/editor'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { EditorInput, EditorOptions, ConfirmResult, IWorkbenchEditorConfiguration, TextEditorOptions, SideBySideEditorInput, TextCompareEditorVisible, TEXT_DIFF_EDITOR_ID, EditorOpeningEvent, IEditorOpeningEvent } from 'vs/workbench/common/editor'; import { EditorGroupsControl, Rochade, IEditorGroupsControl, ProgressState } from 'vs/workbench/browser/parts/editor/editorGroupsControl'; import { WorkbenchProgressService } from 'vs/workbench/services/progress/browser/progressService'; -import { IEditorGroupService, GroupOrientation, GroupArrangement, ITabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IEditorPart } from 'vs/workbench/services/editor/browser/editorService'; +import { IEditorGroupService, GroupOrientation, GroupArrangement, IEditorTabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { IEditorPart } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { Position, POSITIONS, Direction } from 'vs/platform/editor/common/editor'; +import { Position, POSITIONS, Direction, IEditor } from 'vs/platform/editor/common/editor'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IMessageService, IMessageWithAction, Severity } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -44,6 +44,9 @@ import { EDITOR_GROUP_BACKGROUND } from 'vs/workbench/common/theme'; import { createCSSRule } from 'vs/base/browser/dom'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { join } from 'vs/base/common/paths'; +import { isCommonCodeEditor } from 'vs/editor/common/editorCommon'; +import { IEditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; +import { ThrottledEmitter } from 'vs/base/common/async'; class ProgressMonitor { @@ -91,23 +94,23 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService private editorGroupsControl: IEditorGroupsControl; private memento: object; private stacks: EditorStacksModel; - private tabOptions: ITabOptions; + private tabOptions: IEditorTabOptions; private forceHideTabs: boolean; private doNotFireTabOptionsChanged: boolean; private revealIfOpen: boolean; - private _onEditorsChanged: Emitter; - private _onEditorsMoved: Emitter; + private _onEditorsChanged: ThrottledEmitter; + private _onEditorOpening: Emitter; + private _onEditorGroupMoved: Emitter; private _onEditorOpenFail: Emitter; private _onGroupOrientationChanged: Emitter; - private _onTabOptionsChanged: Emitter; + private _onTabOptionsChanged: Emitter; private textCompareEditorVisible: IContextKey; // The following data structures are partitioned into array of Position as provided by Services.POSITION array private visibleEditors: BaseEditor[]; private instantiatedEditors: BaseEditor[][]; - private mapEditorInstantiationPromiseToEditor: { [editorId: string]: TPromise; }[]; private editorOpenToken: number[]; private pendingEditorInputsToClose: EditorIdentifier[]; private pendingEditorInputCloseTimeout: number; @@ -130,11 +133,12 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService ) { super(id, { hasTitle: false }, themeService); - this._onEditorsChanged = new Emitter(); - this._onEditorsMoved = new Emitter(); + this._onEditorsChanged = new ThrottledEmitter(); + this._onEditorOpening = new Emitter(); + this._onEditorGroupMoved = new Emitter(); this._onEditorOpenFail = new Emitter(); this._onGroupOrientationChanged = new Emitter(); - this._onTabOptionsChanged = new Emitter(); + this._onTabOptionsChanged = new Emitter(); this.visibleEditors = []; @@ -142,8 +146,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.instantiatedEditors = arrays.fill(POSITIONS.length, () => []); - this.mapEditorInstantiationPromiseToEditor = arrays.fill(POSITIONS.length, () => Object.create(null)); - this.pendingEditorInputsToClose = []; this.pendingEditorInputCloseTimeout = null; @@ -159,18 +161,27 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService previewEditors: editorConfig.enablePreview, showIcons: editorConfig.showIcons, showTabs: editorConfig.showTabs, - tabCloseButton: editorConfig.tabCloseButton + tabCloseButton: editorConfig.tabCloseButton, + labelFormat: editorConfig.labelFormat, }; this.revealIfOpen = editorConfig.revealIfOpen; + /* __GDPR__ + "workbenchEditorConfiguration" : { + "${include}": [ + "${IWorkbenchEditorConfiguration}" + ] + } + */ this.telemetryService.publicLog('workbenchEditorConfiguration', editorConfig); } else { this.tabOptions = { previewEditors: true, showIcons: false, showTabs: true, - tabCloseButton: 'right' + tabCloseButton: 'right', + labelFormat: 'default', }; this.revealIfOpen = false; @@ -195,40 +206,44 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.toUnbind.push(this.stacks.onEditorClosed(event => this.onEditorClosed(event))); this.toUnbind.push(this.stacks.onGroupOpened(event => this.onEditorGroupOpenedOrClosed())); this.toUnbind.push(this.stacks.onGroupClosed(event => this.onEditorGroupOpenedOrClosed())); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); } private onEditorGroupOpenedOrClosed(): void { this.updateStyles(); } - private onConfigurationUpdated(configuration: IWorkbenchEditorConfiguration): void { - if (configuration && configuration.workbench && configuration.workbench.editor) { - const editorConfig = configuration.workbench.editor; + private onConfigurationUpdated(event: IConfigurationChangeEvent): void { + if (event.affectsConfiguration('workbench.editor')) { + const configuration = this.configurationService.getConfiguration(); + if (configuration && configuration.workbench && configuration.workbench.editor) { + const editorConfig = configuration.workbench.editor; - // Pin all preview editors of the user chose to disable preview - const newPreviewEditors = editorConfig.enablePreview; - if (this.tabOptions.previewEditors !== newPreviewEditors && !newPreviewEditors) { - this.stacks.groups.forEach(group => { - if (group.previewEditor) { - this.pinEditor(group, group.previewEditor); - } - }); + // Pin all preview editors of the user chose to disable preview + const newPreviewEditors = editorConfig.enablePreview; + if (this.tabOptions.previewEditors !== newPreviewEditors && !newPreviewEditors) { + this.stacks.groups.forEach(group => { + if (group.previewEditor) { + this.pinEditor(group, group.previewEditor); + } + }); + } + + const oldTabOptions = objects.clone(this.tabOptions); + this.tabOptions = { + previewEditors: newPreviewEditors, + showIcons: editorConfig.showIcons, + tabCloseButton: editorConfig.tabCloseButton, + showTabs: this.forceHideTabs ? false : editorConfig.showTabs, + labelFormat: editorConfig.labelFormat, + }; + + if (!this.doNotFireTabOptionsChanged && !objects.equals(oldTabOptions, this.tabOptions)) { + this._onTabOptionsChanged.fire(this.tabOptions); + } + + this.revealIfOpen = editorConfig.revealIfOpen; } - - const oldTabOptions = objects.clone(this.tabOptions); - this.tabOptions = { - previewEditors: newPreviewEditors, - showIcons: editorConfig.showIcons, - tabCloseButton: editorConfig.tabCloseButton, - showTabs: this.forceHideTabs ? false : editorConfig.showTabs - }; - - if (!this.doNotFireTabOptionsChanged && !objects.equals(oldTabOptions, this.tabOptions)) { - this._onTabOptionsChanged.fire(this.tabOptions); - } - - this.revealIfOpen = editorConfig.revealIfOpen; } } @@ -244,10 +259,24 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } private onEditorOpened(identifier: EditorIdentifier): void { + /* __GDPR__ + "editorOpened" : { + "${include}": [ + "${EditorTelemetryDescriptor}" + ] + } + */ this.telemetryService.publicLog('editorOpened', identifier.editor.getTelemetryDescriptor()); } private onEditorClosed(event: EditorCloseEvent): void { + /* __GDPR__ + "editorClosed" : { + "${include}": [ + "${EditorTelemetryDescriptor}" + ] + } + */ this.telemetryService.publicLog('editorClosed', event.editor.getTelemetryDescriptor()); } @@ -266,8 +295,12 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this._onEditorsChanged.event; } - public get onEditorsMoved(): Event { - return this._onEditorsMoved.event; + public get onEditorOpening(): Event { + return this._onEditorOpening.event; + } + + public get onEditorGroupMoved(): Event { + return this._onEditorGroupMoved.event; } public get onEditorOpenFail(): Event { @@ -278,35 +311,48 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this._onGroupOrientationChanged.event; } - public get onTabOptionsChanged(): Event { + public get onTabOptionsChanged(): Event { return this._onTabOptionsChanged.event; } - public getTabOptions(): ITabOptions { + public getTabOptions(): IEditorTabOptions { return this.tabOptions; } - public openEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - public openEditor(input: EditorInput, options?: EditorOptions, position?: Position, ratio?: number[]): TPromise; - public openEditor(input: EditorInput, options?: EditorOptions, arg3?: any, ratio?: number[]): TPromise { - - // Normalize some values - if (!options) { options = null; } + public openEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + public openEditor(input: EditorInput, options?: EditorOptions, position?: Position, ratio?: number[]): TPromise; + public openEditor(input: EditorInput, options?: EditorOptions, arg3?: any, ratio?: number[]): TPromise { + if (!options) { + options = null; + } // Determine position to open editor in (one, two, three) const position = this.findPosition(input, options, arg3, ratio); // Some conditions under which we prevent the request if ( - !input || // no input - position === null || // invalid position - Object.keys(this.mapEditorInstantiationPromiseToEditor[position]).length > 0 || // pending editor load - !this.editorGroupsControl || // too early - this.editorGroupsControl.isDragging() // pending editor DND + !input || // no input + position === null || // invalid position + !this.editorGroupsControl || // too early + this.editorGroupsControl.isDragging() // pending editor DND ) { return TPromise.as(null); } + // Editor opening event (can be prevented and overridden) + const event = new EditorOpeningEvent(input, options, position); + this._onEditorOpening.fire(event); + const prevented = event.isPrevented(); + if (prevented) { + return prevented(); + } + + // Open through UI + return this.doOpenEditor(position, input, options, ratio); + } + + private doOpenEditor(position: Position, input: EditorInput, options: EditorOptions, ratio: number[]): TPromise { + // We need an editor descriptor for the input const descriptor = Registry.as(EditorExtensions.Editors).getEditor(input); if (!descriptor) { @@ -315,15 +361,14 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Opened to the side if (position !== Position.ONE) { + /* __GDPR__ + "workbenchSideEditorOpened" : { + "position" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchSideEditorOpened', { position: position }); } - // Open through UI - return this.doOpenEditor(position, descriptor, input, options, ratio); - } - - private doOpenEditor(position: Position, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[]): TPromise { - // Update stacks: We do this early on before the UI is there because we want our stacks model to have // a consistent view of the editor world and updating it later async after the UI is there will cause // issues (e.g. when a closeEditor call is made that expects the openEditor call to have updated the @@ -331,7 +376,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // This can however cause a race condition where the stacks model indicates the opened editor is there // while the UI is not yet ready. Clients have to deal with this fact and we have to make sure that the // stacks model gets updated if any of the UI updating fails with an error. - const group = this.ensureGroup(position, !options || !options.preserveFocus); + const [group, newGroupOpened] = this.ensureGroup(position, !options || !options.preserveFocus); const pinned = !this.tabOptions.previewEditors || (options && (options.pinned || typeof options.index === 'number')) || input.isDirty(); const active = (group.count === 0) || !options || !options.inactive; @@ -354,23 +399,34 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService })); // Show editor - return this.doShowEditor(group, descriptor, input, options, ratio, monitor).then(editor => { - if (!editor) { - return TPromise.as(null); // canceled or other error - } + const editor = this.doShowEditor(group, descriptor, input, options, ratio, monitor); + if (!editor) { + return TPromise.as(null); // canceled or other error + } - // Set input to editor - return this.doSetInput(group, editor, input, options, monitor); - }); + // Set input to editor + const inputPromise = this.doSetInput(group, editor, input, options, monitor); + + // A new active group got opened. Since this involves updating the title area controls to show + // the new editor and actions we trigger a direct update of title controls from here to avoid + // some UI flickering if we rely on the event handlers that all use schedulers. + // The reason we can trigger this now is that after the input is set to the editor group, the + // resource context is updated and the correct number of actions will be resolved from the title + // area. + if (newGroupOpened && this.stacks.isActive(group)) { + this.editorGroupsControl.updateTitleAreas(true /* refresh new active group */); + } + + return inputPromise; } - private doShowEditor(group: EditorGroup, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[], monitor: ProgressMonitor): TPromise { - const position = this.stacks.positionOfGroup(group); + private doShowEditor(group: EditorGroup, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[], monitor: ProgressMonitor): BaseEditor { + let position = this.stacks.positionOfGroup(group); const editorAtPosition = this.visibleEditors[position]; // Return early if the currently visible editor can handle the input if (editorAtPosition && descriptor.describes(editorAtPosition)) { - return TPromise.as(editorAtPosition); + return editorAtPosition; } // Hide active one first @@ -379,107 +435,77 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } // Create Editor - return this.doCreateEditor(group, descriptor, monitor).then(editor => { - const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile + const editor = this.doCreateEditor(group, descriptor, monitor); + position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile - // Make sure that the user meanwhile did not open another editor or something went wrong - if (!editor || !this.visibleEditors[position] || editor.getId() !== this.visibleEditors[position].getId()) { - monitor.cancel(); + // Make sure that the user meanwhile did not open another editor or something went wrong + if (!editor || !this.visibleEditors[position] || editor.getId() !== this.visibleEditors[position].getId()) { + monitor.cancel(); - return null; - } - - // Show in side by side control - this.editorGroupsControl.show(editor, position, options && options.preserveFocus, ratio); - - // Indicate to editor that it is now visible - editor.setVisible(true, position); - - // Update text compare editor visible context - this.updateTextCompareEditorVisible(); - - // Make sure the editor is layed out - this.editorGroupsControl.layout(position); - - return editor; - - }, e => { - this.messageService.show(Severity.Error, types.isString(e) ? new Error(e) : e); return null; - }); + } + + // Show in side by side control + this.editorGroupsControl.show(editor, position, options && options.preserveFocus, ratio); + + // Indicate to editor that it is now visible + editor.setVisible(true, position); + + // Update text compare editor visible context + this.updateTextCompareEditorVisible(); + + // Make sure the editor is layed out + this.editorGroupsControl.layout(position); + + return editor; } - private doCreateEditor(group: EditorGroup, descriptor: IEditorDescriptor, monitor: ProgressMonitor): TPromise { + private doCreateEditor(group: EditorGroup, descriptor: IEditorDescriptor, monitor: ProgressMonitor): BaseEditor { // Instantiate editor - return this.doInstantiateEditor(group, descriptor).then(editor => { - const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile + const editor = this.doInstantiateEditor(group, descriptor); + const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile - // Make sure that the user meanwhile did not open another editor - if (monitor.token !== this.editorOpenToken[position]) { - monitor.cancel(); + // Make sure that the user meanwhile did not open another editor + if (monitor.token !== this.editorOpenToken[position]) { + monitor.cancel(); - return null; - } + return null; + } - // Remember Editor at position - this.visibleEditors[position] = editor; + // Remember Editor at position + this.visibleEditors[position] = editor; - // Create editor as needed - if (!editor.getContainer()) { - editor.create($().div({ - 'class': 'editor-container', - 'role': 'tabpanel', - id: descriptor.getId() - })); - } + // Create editor as needed + if (!editor.getContainer()) { + editor.create($().div({ + 'class': 'editor-container', + 'role': 'tabpanel', + id: descriptor.getId() + })); + } - return editor; - }); + return editor; } - private doInstantiateEditor(group: EditorGroup, descriptor: IEditorDescriptor): TPromise { + private doInstantiateEditor(group: EditorGroup, descriptor: IEditorDescriptor): BaseEditor { const position = this.stacks.positionOfGroup(group); // Return early if already instantiated const instantiatedEditor = this.instantiatedEditors[position].filter(e => descriptor.describes(e))[0]; if (instantiatedEditor) { - return TPromise.as(instantiatedEditor); - } - - // Return early if editor is being instantiated at the same time from a previous call - const pendingEditorInstantiate = this.mapEditorInstantiationPromiseToEditor[position][descriptor.getId()]; - if (pendingEditorInstantiate) { - return pendingEditorInstantiate; + return instantiatedEditor; } // Otherwise instantiate const progressService = this.instantiationService.createInstance(WorkbenchProgressService, this.editorGroupsControl.getProgressBar(position), descriptor.getId(), true); const editorInstantiationService = this.editorGroupsControl.getInstantiationService(position).createChild(new ServiceCollection([IProgressService, progressService])); - let loaded = false; - const onInstantiate = (arg: BaseEditor): TPromise => { - const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile + const editor = descriptor.instantiate(editorInstantiationService); - loaded = true; - delete this.mapEditorInstantiationPromiseToEditor[position][descriptor.getId()]; + this.instantiatedEditors[position].push(editor); - this.instantiatedEditors[position].push(arg); - - return TPromise.as(arg); - }; - - const instantiateEditorPromise = editorInstantiationService.createInstance(descriptor).then(onInstantiate); - - if (!loaded) { - this.mapEditorInstantiationPromiseToEditor[position][descriptor.getId()] = instantiateEditorPromise; - } - - return instantiateEditorPromise.then(result => { - progressService.dispose(); - - return result; - }); + return editor; } private doSetInput(group: EditorGroup, editor: BaseEditor, input: EditorInput, options: EditorOptions, monitor: ProgressMonitor): TPromise { @@ -633,6 +659,9 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Explicitly trigger the focus changed handler because the side by side control will not trigger it unless // the user is actively changing focus with the mouse from left/top to right/bottom. this.onGroupFocusChanged(); + + // Update title area sync to avoid some flickering with actions + this.editorGroupsControl.updateTitleAreas(); } } @@ -659,7 +688,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Emit Editor move event if (rochade !== Rochade.NONE) { - this._onEditorsMoved.fire(); + this._onEditorGroupMoved.fire(); } } @@ -867,14 +896,13 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Move data structures arrays.move(this.visibleEditors, fromPosition, toPosition); arrays.move(this.editorOpenToken, fromPosition, toPosition); - arrays.move(this.mapEditorInstantiationPromiseToEditor, fromPosition, toPosition); arrays.move(this.instantiatedEditors, fromPosition, toPosition); // Restore focus this.focusGroup(fromGroup); // Events - this._onEditorsMoved.fire(); + this._onEditorGroupMoved.fire(); } public moveEditor(input: EditorInput, from: EditorGroup, to: EditorGroup, moveOptions?: IMoveOptions): void; @@ -1012,7 +1040,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } } - public replaceEditors(editors: { toReplace: EditorInput, replaceWith: EditorInput, options?: EditorOptions }[], position?: Position): TPromise { + public replaceEditors(editors: { toReplace: EditorInput, replaceWith: EditorInput, options?: EditorOptions }[], position?: Position): TPromise { const activeReplacements: IEditorReplacement[] = []; const hiddenReplacements: IEditorReplacement[] = []; @@ -1071,9 +1099,9 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return res; } - public openEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[]): TPromise { + public openEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[]): TPromise { if (!editors.length) { - return TPromise.as([]); + return TPromise.as([]); } let activePosition: Position; @@ -1090,7 +1118,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService return this.stacks.groups.some(g => g.count > 0); } - public restoreEditors(): TPromise { + public restoreEditors(): TPromise { const editors = this.stacks.groups.map((group, index) => { return { input: group.activeEditor, @@ -1100,7 +1128,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService }); if (!editors.length) { - return TPromise.as([]); + return TPromise.as([]); } let activePosition: Position; @@ -1110,10 +1138,11 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService const editorState: IEditorPartUIState = this.memento[EditorPart.EDITOR_PART_UI_STATE_STORAGE_KEY]; - return this.doOpenEditors(editors, activePosition, editorState && editorState.ratio); + // Open editors (throttle editor change events) + return this._onEditorsChanged.throttle(this.doOpenEditors(editors, activePosition, editorState && editorState.ratio)); } - private doOpenEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[], activePosition?: number, ratio?: number[]): TPromise { + private doOpenEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[], activePosition?: number, ratio?: number[]): TPromise { const positionOneEditors = editors.filter(e => e.position === Position.ONE); const positionTwoEditors = editors.filter(e => e.position === Position.TWO); const positionThreeEditors = editors.filter(e => e.position === Position.THREE); @@ -1160,7 +1189,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Open each input respecting the options. Since there can only be one active editor in each // position, we have to pick the first input from each position and add the others as inactive - const promises: TPromise[] = []; + const promises: TPromise[] = []; [positionOneEditors.shift(), positionTwoEditors.shift(), positionThreeEditors.shift()].forEach((editor, position) => { if (!editor) { return; // unused position @@ -1169,7 +1198,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService const input = editor.input; // Resolve editor options - const preserveFocus = (activePosition !== position); + const preserveFocus = (activePosition !== position && ratio && ratio.length > 0); // during restore, preserve focus to reduce flicker let options: EditorOptions; if (editor.options) { options = editor.options; @@ -1295,6 +1324,20 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } } + public invokeWithinEditorContext(fn: (accessor: ServicesAccessor) => T): T { + const activeEditor = this.getActiveEditor(); + if (activeEditor) { + const activeEditorControl = activeEditor.getControl(); + if (isCommonCodeEditor(activeEditorControl)) { + return activeEditorControl.invokeWithinContext(fn); + } + + return this.editorGroupsControl.getInstantiationService(activeEditor.position).invokeFunction(fn); + } + + return this.instantiationService.invokeFunction(fn); + } + public layout(dimension: Dimension): Dimension[] { // Pass to super @@ -1334,7 +1377,8 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Emitters this._onEditorsChanged.dispose(); - this._onEditorsMoved.dispose(); + this._onEditorOpening.dispose(); + this._onEditorGroupMoved.dispose(); this._onEditorOpenFail.dispose(); // Reset Tokens @@ -1490,7 +1534,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.doRochade(this.visibleEditors, from, to, null); this.doRochade(this.editorOpenToken, from, to, null); - this.doRochade(this.mapEditorInstantiationPromiseToEditor, from, to, Object.create(null)); this.doRochade(this.instantiatedEditors, from, to, []); } } @@ -1500,9 +1543,11 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService array[from] = empty; } - private ensureGroup(position: Position, activate = true): EditorGroup { + private ensureGroup(position: Position, activate = true): [EditorGroup, boolean /* new group opened */] { + let newGroupOpened = false; let group = this.stacks.groupAt(position); if (!group) { + newGroupOpened = true; // Race condition: it could be that someone quickly opens editors one after // the other and we are asked to open an editor in position 2 before position @@ -1525,7 +1570,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService this.stacks.setActive(group); } - return group; + return [group, newGroupOpened]; } private modifyGroups(modification: () => void) { diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index 4e73f77bb15..979df653a59 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -7,14 +7,11 @@ import 'vs/css!./media/editorpicker'; import { TPromise } from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); -import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); -import strings = require('vs/base/common/strings'); import { IIconLabelOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IAutoFocus, Mode, IEntryRunContext, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen'; -import { QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; -import scorer = require('vs/base/common/scorer'); +import { QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup, QuickOpenItemAccessor } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { IModeService } from 'vs/editor/common/services/modeService'; import { getIconClasses } from 'vs/workbench/browser/labels'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -23,8 +20,8 @@ import { Position } from 'vs/platform/editor/common/editor'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { EditorInput, toResource, IEditorGroup, IEditorStacksModel } from 'vs/workbench/common/editor'; +import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export class EditorPickerEntry extends QuickOpenEntryGroup { private stacks: IEditorStacksModel; @@ -89,11 +86,10 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { } export abstract class BaseEditorPicker extends QuickOpenHandler { - private scorerCache: { [key: string]: number }; + private scorerCache: ScorerCache; constructor( @IInstantiationService protected instantiationService: IInstantiationService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @IWorkbenchEditorService protected editorService: IWorkbenchEditorService, @IEditorGroupService protected editorGroupService: IEditorGroupService ) { @@ -103,41 +99,38 @@ export abstract class BaseEditorPicker extends QuickOpenHandler { } public getResults(searchValue: string): TPromise { - searchValue = searchValue.trim(); - const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase(); - const editorEntries = this.getEditorEntries(); if (!editorEntries.length) { return TPromise.as(null); } - const stacks = this.editorGroupService.getStacksModel(); + // Prepare search for scoring + const query = prepareQuery(searchValue); const entries = editorEntries.filter(e => { - if (!searchValue) { + if (!query.value) { return true; } - const resource = e.getResource(); - const targetToMatch = resource ? labels.getPathLabel(e.getResource(), this.contextService) : e.getLabel(); - if (!scorer.matches(targetToMatch, normalizedSearchValueLowercase)) { + const itemScore = scoreItem(e, query, true, QuickOpenItemAccessor, this.scorerCache); + if (!itemScore.score) { return false; } - const { labelHighlights, descriptionHighlights } = QuickOpenEntry.highlight(e, searchValue, true /* fuzzy highlight */); - e.setHighlights(labelHighlights, descriptionHighlights); + e.setHighlights(itemScore.labelMatch, itemScore.descriptionMatch); return true; }); // Sorting - if (searchValue) { + const stacks = this.editorGroupService.getStacksModel(); + if (query.value) { entries.sort((e1, e2) => { if (e1.group !== e2.group) { return stacks.positionOfGroup(e1.group) - stacks.positionOfGroup(e2.group); } - return QuickOpenEntry.compareByScore(e1, e2, searchValue, normalizedSearchValueLowercase, this.scorerCache); + return compareItemsByScore(e1, e2, query, true, QuickOpenItemAccessor, this.scorerCache); }); } @@ -220,6 +213,8 @@ export abstract class EditorGroupPicker extends BaseEditorPicker { export class GroupOnePicker extends EditorGroupPicker { + public static readonly ID = 'workbench.picker.editors.one'; + protected getPosition(): Position { return Position.ONE; } @@ -227,6 +222,8 @@ export class GroupOnePicker extends EditorGroupPicker { export class GroupTwoPicker extends EditorGroupPicker { + public static readonly ID = 'workbench.picker.editors.two'; + protected getPosition(): Position { return Position.TWO; } @@ -234,6 +231,8 @@ export class GroupTwoPicker extends EditorGroupPicker { export class GroupThreePicker extends EditorGroupPicker { + public static readonly ID = 'workbench.picker.editors.three'; + protected getPosition(): Position { return Position.THREE; } @@ -241,6 +240,8 @@ export class GroupThreePicker extends EditorGroupPicker { export class AllEditorsPicker extends BaseEditorPicker { + public static readonly ID = 'workbench.picker.editors'; + protected getEditorEntries(): EditorPickerEntry[] { const entries: EditorPickerEntry[] = []; diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index b9b2d496a8f..28dcafe4a0f 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -8,7 +8,7 @@ import 'vs/css!./media/editorstatus'; import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; -import { $, append, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; +import { $, append, runAtThisOrScheduleAtNextAnimationFrame, addDisposableListener } from 'vs/base/browser/dom'; import strings = require('vs/base/common/strings'); import paths = require('vs/base/common/paths'); import types = require('vs/base/common/types'); @@ -17,12 +17,12 @@ import errors = require('vs/base/common/errors'); import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { Action } from 'vs/base/common/actions'; import { language, LANGUAGE_DEFAULT, AccessibilitySupport } from 'vs/base/common/platform'; +import * as browser from 'vs/base/browser/browser'; import { IMode } from 'vs/editor/common/modes'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput } from 'vs/workbench/common/editor'; import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IEditorAction, ICommonCodeEditor, EndOfLineSequence, IModel } from 'vs/editor/common/editorCommon'; import { IModelLanguageChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { TrimTrailingWhitespaceAction } from 'vs/editor/contrib/linesOperations/common/linesOperations'; @@ -33,7 +33,7 @@ import { IEditor as IBaseEditor, IEditorInput } from 'vs/platform/editor/common/ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { SUPPORTED_ENCODINGS, IFileService } from 'vs/platform/files/common/files'; +import { SUPPORTED_ENCODINGS, IFileService, IFilesConfiguration, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -43,13 +43,19 @@ import { TabFocus } from 'vs/editor/common/config/commonEditorConfig'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { getCodeEditor as getEditorWidget } from 'vs/editor/common/services/codeEditorService'; +import { getCodeEditor as getEditorWidget, getCodeOrDiffEditor } from 'vs/editor/common/services/codeEditorService'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { widgetShadow, editorWidgetBackground } from 'vs/platform/theme/common/colorRegistry'; // TODO@Sandeep layer breaker // tslint:disable-next-line:import-patterns import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; function toEditorWithEncodingSupport(input: IEditorInput): IEncodingSupport { if (input instanceof SideBySideEditorInput) { @@ -229,7 +235,7 @@ const nlsMultiSelection = nls.localize('multiSelection', "{0} selections"); const nlsEOLLF = nls.localize('endOfLineLineFeed', "LF"); const nlsEOLCRLF = nls.localize('endOfLineCarriageReturnLineFeed', "CRLF"); const nlsTabFocusMode = nls.localize('tabFocusModeEnabled', "Tab Moves Focus"); -const nlsScreenReaderDetected = nls.localize('screenReaderDetected', "Screen Reader Detected"); +const nlsScreenReaderDetected = nls.localize('screenReaderDetected', "Screen Reader Optimized"); const nlsScreenReaderDetectedTitle = nls.localize('screenReaderDetectedExtra', "If you are not using a Screen Reader, please change the setting `editor.accessibilitySupport` to \"off\"."); function _setDisplay(el: HTMLElement, desiredValue: string): void { @@ -260,6 +266,7 @@ export class EditorStatus implements IStatusbarItem { private activeEditorListeners: IDisposable[]; private delayedRender: IDisposable; private toRender: StateChange; + private lastScreenReaderExplanation: ScreenReaderDetectedExplanation; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -268,11 +275,13 @@ export class EditorStatus implements IStatusbarItem { @IInstantiationService private instantiationService: IInstantiationService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, @IModeService private modeService: IModeService, - @ITextFileService private textFileService: ITextFileService + @ITextFileService private textFileService: ITextFileService, + @IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService, ) { this.toDispose = []; this.activeEditorListeners = []; this.state = new State(); + this.lastScreenReaderExplanation = null; } public render(container: HTMLElement): IDisposable { @@ -287,6 +296,7 @@ export class EditorStatus implements IStatusbarItem { this.screenRedearModeElement = append(this.element, $('a.editor-status-screenreadermode.status-bar-info')); this.screenRedearModeElement.textContent = nlsScreenReaderDetected; this.screenRedearModeElement.title = nlsScreenReaderDetectedTitle; + this.screenRedearModeElement.onclick = () => this.onScreenReaderModeClick(); hide(this.screenRedearModeElement); this.selectionElement = append(this.element, $('a.editor-status-selection')); @@ -468,6 +478,10 @@ export class EditorStatus implements IStatusbarItem { action.dispose(); } + private onScreenReaderModeClick(): void { + this.lastScreenReaderExplanation = this.instantiationService.createInstance(ScreenReaderDetectedExplanation, this.screenRedearModeElement); + } + private onSelectionClick(): void { this.quickOpenService.show(':'); // "Go to line" } @@ -606,15 +620,35 @@ export class EditorStatus implements IStatusbarItem { this.updateState(update); } + private _promptedScreenReader: boolean = false; + private onScreenReaderModeChange(editorWidget: ICommonCodeEditor): void { let screenReaderMode = false; // We only support text based editors if (editorWidget) { + const screenReaderDetected = (browser.getAccessibilitySupport() === AccessibilitySupport.Enabled); + if (screenReaderDetected) { + const screenReaderConfiguration = this.configurationService.getConfiguration('editor').accessibilitySupport; + if (screenReaderConfiguration === 'auto') { + // show explanation + if (!this._promptedScreenReader) { + this._promptedScreenReader = true; + setTimeout(() => { + this.onScreenReaderModeClick(); + }, 100); + } + } + } screenReaderMode = (editorWidget.getConfiguration().accessibilitySupport === AccessibilitySupport.Enabled); } + if (screenReaderMode === false && this.lastScreenReaderExplanation) { + this.lastScreenReaderExplanation.hide(); + this.lastScreenReaderExplanation = null; + } + this.updateState({ screenReaderMode: screenReaderMode }); } @@ -695,7 +729,7 @@ export class EditorStatus implements IStatusbarItem { private onResourceEncodingChange(resource: uri): void { const activeEditor = this.editorService.getActiveEditor(); if (activeEditor) { - const activeResource = toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] }); + const activeResource = toResource(activeEditor.input, { supportSideBySide: true }); if (activeResource && activeResource.toString() === resource.toString()) { return this.onEncodingChange(activeEditor); // only update if the encoding changed for the active resource } @@ -751,21 +785,17 @@ export class ChangeModeAction extends Action { public static ID = 'workbench.action.editor.changeLanguageMode'; public static LABEL = nls.localize('changeMode', "Change Language Mode"); - private static FILE_ASSOCIATION_KEY = 'files.associations'; - constructor( actionId: string, actionLabel: string, @IModeService private modeService: IModeService, @IModelService private modelService: IModelService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, @IQuickOpenService private quickOpenService: IQuickOpenService, @IPreferencesService private preferencesService: IPreferencesService, @IInstantiationService private instantiationService: IInstantiationService, - @ICommandService private commandService: ICommandService, - @IConfigurationEditingService private configurationEditService: IConfigurationEditingService + @IUntitledEditorService private untitledEditorService: IUntitledEditorService ) { super(actionId, actionLabel); } @@ -778,7 +808,12 @@ export class ChangeModeAction extends Action { } const textModel = editorWidget.getModel(); - const fileResource = toResource(activeEditor.input, { supportSideBySide: true, filter: 'file' }); + const resource = toResource(activeEditor.input, { supportSideBySide: true }); + + let hasLanguageSupport = !!resource; + if (resource.scheme === 'untitled' && !this.untitledEditorService.hasAssociatedFilePath(resource)) { + hasLanguageSupport = false; // no configuration for untitled resources (e.g. "Untitled-1") + } // Compute mode let currentModeId: string; @@ -817,7 +852,7 @@ export class ChangeModeAction extends Action { }; }); - if (fileResource) { + if (hasLanguageSupport) { picks[0].separator = { border: true, label: nls.localize('languagesPicks', "languages (identifier)") }; } @@ -825,15 +860,14 @@ export class ChangeModeAction extends Action { let configureModeAssociations: IPickOpenEntry; let configureModeSettings: IPickOpenEntry; let galleryAction: Action; - if (fileResource) { - const ext = paths.extname(fileResource.fsPath) || paths.basename(fileResource.fsPath); + if (hasLanguageSupport) { + const ext = paths.extname(resource.fsPath) || paths.basename(resource.fsPath); galleryAction = this.instantiationService.createInstance(ShowLanguageExtensionsAction, ext); if (galleryAction.enabled) { picks.unshift(galleryAction); } - configureModeSettings = { label: nls.localize('configureModeSettings', "Configure '{0}' language based settings...", currentModeId) }; picks.unshift(configureModeSettings); configureModeAssociations = { label: nls.localize('configureAssociationsExt', "Configure File Association for '{0}'...", ext) }; @@ -844,7 +878,8 @@ export class ChangeModeAction extends Action { const autoDetectMode: IPickOpenEntry = { label: nls.localize('autoDetect', "Auto Detect") }; - if (fileResource) { + + if (hasLanguageSupport) { picks.unshift(autoDetectMode); } @@ -860,7 +895,7 @@ export class ChangeModeAction extends Action { // User decided to permanently configure associations, return right after if (pick === configureModeAssociations) { - this.configureFileAssociation(fileResource); + this.configureFileAssociation(resource); return; } @@ -872,28 +907,38 @@ export class ChangeModeAction extends Action { // Change mode for active editor activeEditor = this.editorService.getActiveEditor(); - const editorWidget = getEditorWidget(activeEditor); - if (editorWidget) { - const models: IModel[] = []; - - const textModel = editorWidget.getModel(); - if (textModel) { - models.push(textModel); + const codeOrDiffEditor = getCodeOrDiffEditor(activeEditor); + const models: IModel[] = []; + if (codeOrDiffEditor.codeEditor) { + const codeEditorModel = codeOrDiffEditor.codeEditor.getModel(); + if (codeEditorModel) { + models.push(codeEditorModel); } - - // Find mode - let mode: TPromise; - if (pick === autoDetectMode) { - mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] }).fsPath, textModel.getLineContent(1)); - } else { - mode = this.modeService.getOrCreateModeByLanguageName(pick.label); - } - - // Change mode - models.forEach(textModel => { - this.modelService.setMode(textModel, mode); - }); } + if (codeOrDiffEditor.diffEditor) { + const diffEditorModel = codeOrDiffEditor.diffEditor.getModel(); + if (diffEditorModel) { + if (diffEditorModel.original) { + models.push(diffEditorModel.original); + } + if (diffEditorModel.modified) { + models.push(diffEditorModel.modified); + } + } + } + + // Find mode + let mode: TPromise; + if (pick === autoDetectMode) { + mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(toResource(activeEditor.input, { supportSideBySide: true }).fsPath, textModel.getLineContent(1)); + } else { + mode = this.modeService.getOrCreateModeByLanguageName(pick.label); + } + + // Change mode + models.forEach(textModel => { + this.modelService.setMode(textModel, mode); + }); }); } @@ -916,7 +961,7 @@ export class ChangeModeAction extends Action { TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).done(() => { this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || basename) }).done(language => { if (language) { - const fileAssociationsConfig = this.configurationService.lookup(ChangeModeAction.FILE_ASSOCIATION_KEY); + const fileAssociationsConfig = this.configurationService.inspect(FILES_ASSOCIATIONS_CONFIG); let associationKey: string; if (extension && basename[0] !== '.') { @@ -939,8 +984,7 @@ export class ChangeModeAction extends Action { currentAssociations[associationKey] = language.id; - // Write config - this.configurationEditingService.writeConfiguration(target, { key: ChangeModeAction.FILE_ASSOCIATION_KEY, value: currentAssociations }); + this.configurationService.updateValue(FILES_ASSOCIATIONS_CONFIG, currentAssociations, target); } }); }); @@ -1058,7 +1102,7 @@ export class ChangeEncodingAction extends Action { actionLabel: string, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IQuickOpenService private quickOpenService: IQuickOpenService, - @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, + @ITextResourceConfigurationService private textResourceConfigurationService: ITextResourceConfigurationService, @IFileService private fileService: IFileService ) { super(actionId, actionLabel); @@ -1100,19 +1144,22 @@ export class ChangeEncodingAction extends Action { return void 0; } - const resource = toResource(activeEditor.input, { filter: ['file', 'untitled'], supportSideBySide: true }); + const resource = toResource(activeEditor.input, { supportSideBySide: true }); return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */) .then(() => { - if (!resource || resource.scheme !== 'file') { - return TPromise.as(null); // encoding detection only possible for file resources + if (!resource || !this.fileService.canHandleResource(resource)) { + return TPromise.as(null); // encoding detection only possible for resources the file service can handle } return this.fileService.resolveContent(resource, { autoGuessEncoding: true, acceptTextOnly: true }).then(content => content.encoding, err => null); }) .then((guessedEncoding: string) => { const isReopenWithEncoding = (action === reopenWithEncodingPick); - const configuredEncoding = this.configurationService.lookup('files.encoding', { resource }).value; + + const config = this.textResourceConfigurationService.getConfiguration(resource) as IFilesConfiguration; + const configuredEncoding = config && config.files && config.files.encoding; + let directMatchIndex: number; let aliasMatchIndex: number; @@ -1141,7 +1188,7 @@ export class ChangeEncodingAction extends Action { aliasMatchIndex = index; } - return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong }; + return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong, description: key }; }); // If we have a guessed encoding, show it first unless it matches the configured encoding @@ -1166,3 +1213,107 @@ export class ChangeEncodingAction extends Action { }); } } + +class ScreenReaderDetectedExplanation { + + private _isDisposed: boolean; + private _toDispose: IDisposable[]; + + constructor( + anchorElement: HTMLElement, + @IThemeService private readonly themeService: IThemeService, + @IContextViewService private readonly contextViewService: IContextViewService, + @IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService, + ) { + this._isDisposed = false; + this._toDispose = []; + + this.contextViewService.showContextView({ + getAnchor: () => anchorElement, + + render: (container) => { + return this.renderContents(container); + }, + + onDOMEvent: (e, activeElement) => { + }, + + onHide: () => { + this.dispose(); + } + }); + } + + public dispose(): void { + this._isDisposed = true; + this._toDispose = dispose(this._toDispose); + } + + public hide(): void { + if (this._isDisposed) { + return; + } + this.contextViewService.hideContextView(); + } + + protected renderContents(container: HTMLElement): IDisposable { + const domNode = $('div.screen-reader-detected-explanation', { + 'aria-hidden': 'true' + }); + + const title = $('h2.title', {}, nls.localize('screenReaderDetectedExplanation.title', "Screen Reader Optimized")); + domNode.appendChild(title); + + const closeBtn = $('div.cancel'); + this._toDispose.push(addDisposableListener(closeBtn, 'click', () => { + this.contextViewService.hideContextView(); + })); + domNode.appendChild(closeBtn); + + const question = $('p.question', {}, nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate VS Code?")); + domNode.appendChild(question); + + const yesBtn = $('div.button', {}, nls.localize('screenReaderDetectedExplanation.answerYes', "Yes")); + this._toDispose.push(addDisposableListener(yesBtn, 'click', () => { + this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER); + this.contextViewService.hideContextView(); + })); + domNode.appendChild(yesBtn); + + const noBtn = $('div.button', {}, nls.localize('screenReaderDetectedExplanation.answerNo', "No")); + this._toDispose.push(addDisposableListener(noBtn, 'click', () => { + this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER); + this.contextViewService.hideContextView(); + })); + domNode.appendChild(noBtn); + + const clear = $('div'); + clear.style.clear = 'both'; + domNode.appendChild(clear); + + const br = $('br'); + domNode.appendChild(br); + + const hr = $('hr'); + domNode.appendChild(hr); + + const explanation1 = $('p.body1', {}, nls.localize('screenReaderDetectedExplanation.body1', "VS Code is now optimized for usage with a screen reader.")); + domNode.appendChild(explanation1); + + const explanation2 = $('p.body2', {}, nls.localize('screenReaderDetectedExplanation.body2', "Some editor features will have different behaviour: e.g. word wrapping, folding, etc.")); + domNode.appendChild(explanation2); + + container.appendChild(domNode); + + this._toDispose.push(attachStylerCallback(this.themeService, { widgetShadow, editorWidgetBackground }, colors => { + domNode.style.backgroundColor = colors.editorWidgetBackground; + if (colors.widgetShadow) { + domNode.style.boxShadow = `0 2px 8px ${colors.widgetShadow}`; + } + })); + + return { + dispose: () => { this.dispose(); } + }; + } +} diff --git a/src/vs/workbench/browser/parts/editor/media/back-tb.png b/src/vs/workbench/browser/parts/editor/media/back-tb.png new file mode 100644 index 00000000000..1f075e67e98 Binary files /dev/null and b/src/vs/workbench/browser/parts/editor/media/back-tb.png differ diff --git a/src/vs/workbench/browser/parts/editor/media/close-big-dark.svg b/src/vs/workbench/browser/parts/editor/media/close-big-dark.svg new file mode 100644 index 00000000000..ce0e5896405 --- /dev/null +++ b/src/vs/workbench/browser/parts/editor/media/close-big-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/media/close-big.svg b/src/vs/workbench/browser/parts/editor/media/close-big.svg new file mode 100644 index 00000000000..fde34404d4e --- /dev/null +++ b/src/vs/workbench/browser/parts/editor/media/close-big.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/media/editorstatus.css b/src/vs/workbench/browser/parts/editor/media/editorstatus.css index b4fd4bdd7d2..9029f71eac7 100644 --- a/src/vs/workbench/browser/parts/editor/media/editorstatus.css +++ b/src/vs/workbench/browser/parts/editor/media/editorstatus.css @@ -18,7 +18,78 @@ padding: 0 5px 0 5px; } -.monaco-workbench .editor-statusbar-item > .editor-status-metadata, -.monaco-workbench > .part.statusbar > .statusbar-item > .editor-statusbar-item > a.editor-status-screenreadermode { +.monaco-workbench .editor-statusbar-item > .editor-status-metadata { cursor: default !important; } + + +.monaco-shell .screen-reader-detected-explanation { + width: 420px; + top: 30px; + right: 6px; + padding: 1em; + cursor: default; +} + +.monaco-shell .screen-reader-detected-explanation .cancel { + position: absolute; + top: 0; + right: 0; + margin: .5em 0 0; + padding: .5em; + width: 22px; + height: 22px; + border: none; + cursor: pointer; +} + +.monaco-shell .screen-reader-detected-explanation h2 { + margin: 0; + padding: 0; + font-weight: 400; + font-size: 1.8em; +} + +.monaco-shell .screen-reader-detected-explanation p { + font-size: 1.2em; +} + +.monaco-shell .screen-reader-detected-explanation p.question { + font-size: 1.4em; + font-weight: bold; +} + +.monaco-shell .screen-reader-detected-explanation .button { + color: white; + border: none; + cursor: pointer; + background-color: #007ACC; + padding-left: 12px; + padding-right: 12px; + border: 4px solid #007ACC; + border-radius: 4px; + float: left; + margin-right: 5px; +} + +.monaco-shell.vs .screen-reader-detected-explanation .cancel { + background: url('close-big.svg') center center no-repeat; +} +.monaco-shell.vs .screen-reader-detected-explanation .cancel:hover { + background-color: #eaeaea; +} + +.monaco-shell.vs-dark .screen-reader-detected-explanation .cancel, +.monaco-shell.hc-black .screen-reader-detected-explanation .cancel { + background: url('close-big-dark.svg') center center no-repeat; +} +.monaco-shell.vs-dark .screen-reader-detected-explanation .cancel:hover { + background-color: rgba(30,30,30,0.8); +} + +.monaco-shell.hc-black .screen-reader-detected-explanation .cancel { + opacity: 0.6; +} +.monaco-shell.hc-black .screen-reader-detected-explanation .cancel:hover { + opacity: 1; +} diff --git a/src/vs/workbench/browser/parts/editor/media/forward-tb.png b/src/vs/workbench/browser/parts/editor/media/forward-tb.png new file mode 100644 index 00000000000..8949fe7f249 Binary files /dev/null and b/src/vs/workbench/browser/parts/editor/media/forward-tb.png differ diff --git a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 6814ef611b8..7b5575cf751 100644 --- a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -10,13 +10,15 @@ import errors = require('vs/base/common/errors'); import { IEditorGroup, toResource } from 'vs/workbench/common/editor'; import DOM = require('vs/base/browser/dom'); import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl'; -import { EditorLabel } from 'vs/workbench/browser/labels'; +import { ResourceLabel } from 'vs/workbench/browser/labels'; import { Verbosity } from 'vs/platform/editor/common/editor'; import { TAB_ACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND } from 'vs/workbench/common/theme'; +import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch'; export class NoTabsTitleControl extends TitleControl { private titleContainer: HTMLElement; - private editorLabel: EditorLabel; + private editorLabel: ResourceLabel; + private titleTouchSupport: Gesture; public setContext(group: IEditorGroup): void { super.setContext(group); @@ -29,17 +31,22 @@ export class NoTabsTitleControl extends TitleControl { this.titleContainer = parent; + // Gesture Support + this.titleTouchSupport = new Gesture(this.titleContainer); + // Pin on double click this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.DBLCLICK, (e: MouseEvent) => this.onTitleDoubleClick(e))); // Detect mouse click this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.CLICK, (e: MouseEvent) => this.onTitleClick(e))); + // Detect touch + this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, TouchEventType.Tap, (e: GestureEvent) => this.onTitleClick(e))); + // Editor Label - this.editorLabel = this.instantiationService.createInstance(EditorLabel, this.titleContainer, void 0); + this.editorLabel = this.instantiationService.createInstance(ResourceLabel, this.titleContainer, void 0); this.toUnbind.push(this.editorLabel); - this.toUnbind.push(DOM.addDisposableListener(this.editorLabel.labelElement, DOM.EventType.CLICK, (e: MouseEvent) => this.onTitleLabelClick(e))); - this.toUnbind.push(DOM.addDisposableListener(this.editorLabel.descriptionElement, DOM.EventType.CLICK, (e: MouseEvent) => this.onTitleLabelClick(e))); + this.toUnbind.push(this.editorLabel.onClick(e => this.onTitleLabelClick(e))); // Right Actions Container const actionsContainer = document.createElement('div'); @@ -51,6 +58,7 @@ export class NoTabsTitleControl extends TitleControl { // Context Menu this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.CONTEXT_MENU, (e: Event) => this.onContextMenu({ group: this.context, editor: this.context.activeEditor }, e, this.titleContainer))); + this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, TouchEventType.Contextmenu, (e: Event) => this.onContextMenu({ group: this.context, editor: this.context.activeEditor }, e, this.titleContainer))); } private onTitleLabelClick(e: MouseEvent): void { @@ -71,7 +79,7 @@ export class NoTabsTitleControl extends TitleControl { this.editorGroupService.pinEditor(group, group.activeEditor); } - private onTitleClick(e: MouseEvent): void { + private onTitleClick(e: MouseEvent | GestureEvent): void { if (!this.context) { return; } @@ -79,12 +87,15 @@ export class NoTabsTitleControl extends TitleControl { const group = this.context; // Close editor on middle mouse click - if (e.button === 1 /* Middle Button */) { + if (e instanceof MouseEvent && e.button === 1 /* Middle Button */) { this.closeEditorAction.run({ group, editor: group.activeEditor }).done(null, errors.onUnexpectedError); } - // Focus editor group unless click on toolbar - else if (this.stacks.groups.length === 1 && !DOM.isAncestor((e.target || e.srcElement) as HTMLElement, this.editorActionsToolbar.getContainer().getHTMLElement())) { + // Focus editor group unless: + // - click on toolbar: should trigger actions within + // - mouse click: do not focus group if there are more than one as it otherwise makes group DND funky + // - touch: always focus + else if ((this.stacks.groups.length === 1 || !(e instanceof MouseEvent)) && !DOM.isAncestor((e.target || e.srcElement) as HTMLElement, this.editorActionsToolbar.getContainer().getHTMLElement())) { this.editorGroupService.focusGroup(group); } } @@ -119,7 +130,15 @@ export class NoTabsTitleControl extends TitleControl { // Editor Label const resource = toResource(editor, { supportSideBySide: true }); const name = editor.getName() || ''; - const description = isActive ? (editor.getDescription() || '') : ''; + + const labelFormat = this.editorGroupService.getTabOptions().labelFormat; + let description: string; + if (labelFormat === 'default' && !isActive) { + description = ''; // hide description when group is not active and style is 'default' + } else { + description = editor.getDescription(this.getVerbosity(labelFormat)) || ''; + } + let title = editor.getTitle(Verbosity.LONG); if (description === title) { title = ''; // dont repeat what is already shown @@ -135,4 +154,18 @@ export class NoTabsTitleControl extends TitleControl { // Update Editor Actions Toolbar this.updateEditorActionsToolbar(); } + + private getVerbosity(style: string): Verbosity { + switch (style) { + case 'short': return Verbosity.SHORT; + case 'long': return Verbosity.LONG; + default: return Verbosity.MEDIUM; + } + } + + public dispose(): void { + super.dispose(); + + this.titleTouchSupport.dispose(); + } } \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index bcd21c6255f..c0099581a82 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -4,13 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import * as strings from 'vs/base/common/strings'; import * as DOM from 'vs/base/browser/dom'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IEditorRegistry, Extensions as EditorExtensions, EditorInput, EditorOptions, SideBySideEditorInput } from 'vs/workbench/common/editor'; -import { BaseEditor, EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { EditorInput, EditorOptions, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IEditorControl, Position, IEditor } from 'vs/platform/editor/common/editor'; import { VSash } from 'vs/base/browser/ui/sash/sash'; @@ -18,6 +17,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry'; +import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; export class SideBySideEditor extends BaseEditor { @@ -110,7 +110,7 @@ export class SideBySideEditor extends BaseEditor { return this.detailsEditor; } - private updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options?: EditorOptions): TPromise { + private updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options?: EditorOptions): void { if (!newInput.matches(oldInput)) { if (oldInput) { this.disposeEditors(); @@ -126,24 +126,21 @@ export class SideBySideEditor extends BaseEditor { } } - private setNewInput(newInput: SideBySideEditorInput, options?: EditorOptions): TPromise { - return TPromise.join([ - this._createEditor(newInput.details, this.detailsEditorContainer), - this._createEditor(newInput.master, this.masterEditorContainer) - ]).then(result => this.onEditorsCreated(result[0], result[1], newInput.details, newInput.master, options)); + private setNewInput(newInput: SideBySideEditorInput, options?: EditorOptions): void { + const detailsEditor = this._createEditor(newInput.details, this.detailsEditorContainer); + const masterEditor = this._createEditor(newInput.master, this.masterEditorContainer); + + this.onEditorsCreated(detailsEditor, masterEditor, newInput.details, newInput.master, options); } - private _createEditor(editorInput: EditorInput, container: HTMLElement): TPromise { + private _createEditor(editorInput: EditorInput, container: HTMLElement): BaseEditor { const descriptor = Registry.as(EditorExtensions.Editors).getEditor(editorInput); - if (!descriptor) { - return TPromise.wrapError(new Error(strings.format('Can not find a registered editor for the input {0}', editorInput))); - } - return this.instantiationService.createInstance(descriptor) - .then((editor: BaseEditor) => { - editor.create(new Builder(container)); - editor.setVisible(this.isVisible(), this.position); - return editor; - }); + + const editor = descriptor.instantiate(this.instantiationService); + editor.create(new Builder(container)); + editor.setVisible(this.isVisible(), this.position); + + return editor; } private onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions): TPromise { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 4c698cf41b5..ed52a7f4440 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -17,10 +17,11 @@ import { ActionRunner, IAction } from 'vs/base/common/actions'; import { Position, IEditorInput, Verbosity, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; import { IEditorGroup, toResource } from 'vs/workbench/common/editor'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { EditorLabel } from 'vs/workbench/browser/labels'; +import { ResourceLabel } from 'vs/workbench/browser/labels'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -35,9 +36,8 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; -import { extractResources } from 'vs/base/browser/dnd'; +import { extractResources } from 'vs/workbench/browser/editor'; import { getOrSet } from 'vs/base/common/map'; -import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TAB_INACTIVE_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, TAB_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND, TAB_UNFOCUSED_INACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_BORDER, TAB_ACTIVE_BORDER } from 'vs/workbench/common/theme'; @@ -47,16 +47,17 @@ import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; interface IEditorInputLabel { name: string; - hasAmbiguousName?: boolean; description?: string; title?: string; } +type AugmentedLabel = IEditorInputLabel & { editor: IEditorInput }; + export class TabsTitleControl extends TitleControl { private titleContainer: HTMLElement; private tabsContainer: HTMLElement; private activeTab: HTMLElement; - private editorLabels: EditorLabel[]; + private editorLabels: ResourceLabel[]; private scrollbar: ScrollableElement; private tabDisposeables: IDisposable[]; private blockRevealActiveTab: boolean; @@ -167,10 +168,11 @@ export class TabsTitleControl extends TitleControl { // Drag over this.toUnbind.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.DRAG_OVER, (e: DragEvent) => { + const draggedEditor = TabsTitleControl.getDraggedEditor(); // update the dropEffect, otherwise it would look like a "move" operation. but only if we are // not dragging a tab actually because there we support both moving as well as copying - if (!TabsTitleControl.getDraggedEditor()) { + if (!draggedEditor) { e.dataTransfer.dropEffect = 'copy'; } @@ -178,7 +180,17 @@ export class TabsTitleControl extends TitleControl { const target = e.target; if (target instanceof HTMLElement && target.className.indexOf('tabs-container') === 0) { - this.updateDropFeedback(this.tabsContainer, true); + + // Find out if the currently dragged editor is the last tab of this group and in that + // case we do not want to show any drop feedback because the drop would be a no-op + let draggedEditorIsLastTab = false; + if (draggedEditor && this.context === draggedEditor.group && this.context.indexOf(draggedEditor.editor) === this.context.count - 1) { + draggedEditorIsLastTab = true; + } + + if (!draggedEditorIsLastTab) { + this.updateDropFeedback(this.tabsContainer, true); + } } })); @@ -264,7 +276,7 @@ export class TabsTitleControl extends TitleControl { // Compute labels and protect against duplicates const editorsOfGroup = this.context.getEditors(); - const labels = this.getUniqueTabLabels(editorsOfGroup); + const labels = this.getTabLabels(editorsOfGroup); // Tab label and styles editorsOfGroup.forEach((editor, index) => { @@ -276,7 +288,7 @@ export class TabsTitleControl extends TitleControl { const label = labels[index]; const name = label.name; - const description = label.hasAmbiguousName && label.description ? label.description : ''; + const description = label.description || ''; const title = label.title || ''; // Container @@ -338,56 +350,108 @@ export class TabsTitleControl extends TitleControl { this.layout(); } - private getUniqueTabLabels(editors: IEditorInput[]): IEditorInputLabel[] { - const labels: IEditorInputLabel[] = []; - - const mapLabelToDuplicates = new Map(); - const mapLabelAndDescriptionToDuplicates = new Map(); + private getTabLabels(editors: IEditorInput[]): IEditorInputLabel[] { + const labelFormat = this.editorGroupService.getTabOptions().labelFormat; + const { verbosity, shortenDuplicates } = this.getLabelConfigFlags(labelFormat); // Build labels and descriptions for each editor - editors.forEach(editor => { - const name = editor.getName(); - let description = editor.getDescription(); - if (mapLabelAndDescriptionToDuplicates.has(`${name}${description}`)) { - description = editor.getDescription(true); // try verbose description if name+description already exists - } + const labels = editors.map(editor => ({ + editor, + name: editor.getName(), + description: editor.getDescription(verbosity), + title: editor.getTitle(Verbosity.LONG) + })); - const item: IEditorInputLabel = { - name, - description, - title: editor.getTitle(Verbosity.LONG) - }; - labels.push(item); - - getOrSet(mapLabelToDuplicates, item.name, []).push(item); - - if (typeof description === 'string') { - getOrSet(mapLabelAndDescriptionToDuplicates, `${item.name}${item.description}`, []).push(item); - } - }); - - // Mark duplicates and shorten their descriptions - mapLabelToDuplicates.forEach(duplicates => { - if (duplicates.length > 1) { - duplicates = duplicates.filter(d => { - // we could have items with equal label and description. in that case it does not make much - // sense to produce a shortened version of the label, so we ignore those kind of items - return typeof d.description === 'string' && mapLabelAndDescriptionToDuplicates.get(`${d.name}${d.description}`).length === 1; - }); - - if (duplicates.length > 1) { - const shortenedDescriptions = shorten(duplicates.map(duplicate => duplicate.description)); - duplicates.forEach((duplicate, i) => { - duplicate.description = shortenedDescriptions[i]; - duplicate.hasAmbiguousName = true; - }); - } - } - }); + // Shorten labels as needed + if (shortenDuplicates) { + this.shortenTabLabels(labels); + } return labels; } + private shortenTabLabels(labels: AugmentedLabel[]): void { + + // Gather duplicate titles, while filtering out invalid descriptions + const mapTitleToDuplicates = new Map(); + for (const label of labels) { + if (typeof label.description === 'string') { + getOrSet(mapTitleToDuplicates, label.name, []).push(label); + } else { + label.description = ''; + } + } + + // Identify duplicate titles and shorten descriptions + mapTitleToDuplicates.forEach(duplicateTitles => { + + // Remove description if the title isn't duplicated + if (duplicateTitles.length === 1) { + duplicateTitles[0].description = ''; + + return; + } + + // Identify duplicate descriptions + const mapDescriptionToDuplicates = new Map(); + for (const label of duplicateTitles) { + getOrSet(mapDescriptionToDuplicates, label.description, []).push(label); + } + + // For editors with duplicate descriptions, check whether any long descriptions differ + let useLongDescriptions = false; + mapDescriptionToDuplicates.forEach((duplicateDescriptions, name) => { + if (!useLongDescriptions && duplicateDescriptions.length > 1) { + const [first, ...rest] = duplicateDescriptions.map(({ editor }) => editor.getDescription(Verbosity.LONG)); + useLongDescriptions = rest.some(description => description !== first); + } + }); + + // If so, replace all descriptions with long descriptions + if (useLongDescriptions) { + mapDescriptionToDuplicates.clear(); + duplicateTitles.forEach(label => { + label.description = label.editor.getDescription(Verbosity.LONG); + getOrSet(mapDescriptionToDuplicates, label.description, []).push(label); + }); + } + + // Obtain final set of descriptions + const descriptions: string[] = []; + mapDescriptionToDuplicates.forEach((_, description) => descriptions.push(description)); + + // Remove description if all descriptions are identical + if (descriptions.length === 1) { + for (const label of mapDescriptionToDuplicates.get(descriptions[0])) { + label.description = ''; + } + + return; + } + + // Shorten descriptions + const shortenedDescriptions = shorten(descriptions); + descriptions.forEach((description, i) => { + for (const label of mapDescriptionToDuplicates.get(description)) { + label.description = shortenedDescriptions[i]; + } + }); + }); + } + + private getLabelConfigFlags(value: string) { + switch (value) { + case 'short': + return { verbosity: Verbosity.SHORT, shortenDuplicates: false }; + case 'medium': + return { verbosity: Verbosity.MEDIUM, shortenDuplicates: false }; + case 'long': + return { verbosity: Verbosity.LONG, shortenDuplicates: false }; + default: + return { verbosity: Verbosity.MEDIUM, shortenDuplicates: true }; + } + } + protected doRefresh(): void { const group = this.context; const editor = group && group.activeEditor; @@ -451,8 +515,11 @@ export class TabsTitleControl extends TitleControl { tabContainer.setAttribute('role', 'presentation'); // cannot use role "tab" here due to https://github.com/Microsoft/vscode/issues/8659 DOM.addClass(tabContainer, 'tab'); + // Gesture Support + const gestureSupport = new Gesture(tabContainer); + // Tab Editor Label - const editorLabel = this.instantiationService.createInstance(EditorLabel, tabContainer, void 0); + const editorLabel = this.instantiationService.createInstance(ResourceLabel, tabContainer, void 0); this.editorLabels.push(editorLabel); // Tab Close @@ -466,7 +533,7 @@ export class TabsTitleControl extends TitleControl { // Eventing const disposable = this.hookTabListeners(tabContainer, index); - this.tabDisposeables.push(combinedDisposable([disposable, bar, editorLabel])); + this.tabDisposeables.push(combinedDisposable([disposable, bar, editorLabel, gestureSupport])); return tabContainer; } @@ -516,14 +583,42 @@ export class TabsTitleControl extends TitleControl { private hookTabListeners(tab: HTMLElement, index: number): IDisposable { const disposables: IDisposable[] = []; - // Open on Click - disposables.push(DOM.addDisposableListener(tab, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { + const handleClickOrTouch = (e: MouseEvent | GestureEvent) => { tab.blur(); + if (e instanceof MouseEvent && e.button !== 0) { + if (e.button === 1) { + return false; // required due to https://github.com/Microsoft/vscode/issues/16690 + } + + return void 0; // only for left mouse click + } + const { editor, position } = this.toTabContext(index); - if (e.button === 0 /* Left Button */ && !this.isTabActionBar((e.target || e.srcElement) as HTMLElement)) { + if (!this.isTabActionBar((e.target || e.srcElement) as HTMLElement)) { setTimeout(() => this.editorService.openEditor(editor, null, position).done(null, errors.onUnexpectedError)); // timeout to keep focus in editor after mouse up } + + return void 0; + }; + + const showContextMenu = (e: Event) => { + DOM.EventHelper.stop(e); + + const { group, editor } = this.toTabContext(index); + + this.onContextMenu({ group, editor }, e, tab); + }; + + // Open on Click + disposables.push(DOM.addDisposableListener(tab, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => handleClickOrTouch(e))); + + // Open on Touch + disposables.push(DOM.addDisposableListener(tab, TouchEventType.Tap, (e: GestureEvent) => handleClickOrTouch(e))); + + // Touch Scroll Support + disposables.push(DOM.addDisposableListener(tab, TouchEventType.Change, (e: GestureEvent) => { + this.tabsContainer.scrollLeft -= e.translationX; })); // Close on mouse middle click @@ -540,14 +635,15 @@ export class TabsTitleControl extends TitleControl { disposables.push(DOM.addDisposableListener(tab, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); if (event.shiftKey && event.keyCode === KeyCode.F10) { - DOM.EventHelper.stop(e); - - const { group, editor } = this.toTabContext(index); - - this.onContextMenu({ group, editor }, e, tab); + showContextMenu(e); } })); + // Context menu on touch context menu gesture + disposables.push(DOM.addDisposableListener(tab, TouchEventType.Contextmenu, (e: GestureEvent) => { + showContextMenu(e); + })); + // Keyboard accessibility disposables.push(DOM.addDisposableListener(tab, DOM.EventType.KEY_UP, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); @@ -617,12 +713,15 @@ export class TabsTitleControl extends TitleControl { e.dataTransfer.effectAllowed = 'copyMove'; // Insert transfer accordingly - const fileResource = toResource(editor, { supportSideBySide: true, filter: 'file' }); - if (fileResource) { - const resource = fileResource.toString(); - e.dataTransfer.setData('URL', resource); // enables cross window DND of tabs - e.dataTransfer.setData('DownloadURL', [MIME_BINARY, editor.getName(), resource].join(':')); // enables support to drag a tab as file to desktop + const resource = toResource(editor, { supportSideBySide: true }); + if (resource) { + const resourceStr = resource.toString(); + e.dataTransfer.setData('URL', resourceStr); // enables cross window DND of tabs e.dataTransfer.setData('text/plain', getPathLabel(resource)); // enables dropping tab resource path into text controls + + if (resource.scheme === 'file') { + e.dataTransfer.setData('DownloadURL', [MIME_BINARY, editor.getName(), resourceStr].join(':')); // enables support to drag a tab as file to desktop + } } })); diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 7143b5a9fa2..bfc099a30fb 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -22,17 +22,15 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel'; -import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IEditorInput } from 'vs/platform/editor/common/editor'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -56,10 +54,9 @@ export class TextDiffEditor extends BaseTextEditor { @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IThemeService themeService: IThemeService, @IEditorGroupService editorGroupService: IEditorGroupService, - @IModeService modeService: IModeService, @ITextFileService textFileService: ITextFileService ) { - super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService, textFileService, editorGroupService); + super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorGroupService); } public getTitle(): string { diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index fb907cfd550..dc250322285 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -14,7 +14,7 @@ import types = require('vs/base/common/types'); import errors = require('vs/base/common/errors'); import DOM = require('vs/base/browser/dom'); import { CodeEditor } from 'vs/editor/browser/codeEditor'; -import { EditorInput, EditorOptions, toResource } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IEditorViewState, IEditor, isCommonCodeEditor, isCommonDiffEditor } from 'vs/editor/common/editorCommon'; import { Position } from 'vs/platform/editor/common/editor'; @@ -24,7 +24,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Scope } from 'vs/workbench/common/memento'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { ITextFileService, SaveReason, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; @@ -32,12 +31,6 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; const TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'textEditorViewState'; -interface ITextEditorViewState { - 0?: IEditorViewState; - 1?: IEditorViewState; - 2?: IEditorViewState; -} - export interface IEditorConfiguration { editor: object; diffEditor: object; @@ -60,13 +53,12 @@ export abstract class BaseTextEditor extends BaseEditor { @IStorageService private storageService: IStorageService, @ITextResourceConfigurationService private _configurationService: ITextResourceConfigurationService, @IThemeService protected themeService: IThemeService, - @IModeService private modeService: IModeService, @ITextFileService private _textFileService: ITextFileService, @IEditorGroupService protected editorGroupService: IEditorGroupService ) { super(id, telemetryService, themeService); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getConfiguration(this.getResource())))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getConfiguration(this.getResource())))); } protected get instantiationService(): IInstantiationService { @@ -318,7 +310,7 @@ export abstract class BaseTextEditor extends BaseEditor { } if (this.input) { - return toResource(this.input); + return this.input.getResource(); } return null; diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 7d723508d2a..cfabfc41b0e 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -20,7 +20,6 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { once } from 'vs/base/common/event'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -40,10 +39,9 @@ export class TextResourceEditor extends BaseTextEditor { @ITextResourceConfigurationService configurationService: ITextResourceConfigurationService, @IThemeService themeService: IThemeService, @IEditorGroupService editorGroupService: IEditorGroupService, - @IModeService modeService: IModeService, @ITextFileService textFileService: ITextFileService ) { - super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService, textFileService, editorGroupService); + super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorGroupService); } public getTitle(): string { diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 24f2303b131..08f07ce1bb4 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -39,7 +39,7 @@ import { IMenuService, MenuId, IMenu, ExecuteCommandAction } from 'vs/platform/a import { ResourceContextKey } from 'vs/workbench/common/resources'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Themable } from 'vs/workbench/common/theme'; -import { IDraggedResource } from 'vs/base/browser/dnd'; +import { IDraggedResource } from 'vs/workbench/browser/editor'; import { WORKSPACE_EXTENSION, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { extname } from 'vs/base/common/paths'; import { IFileService } from 'vs/platform/files/common/files'; @@ -60,6 +60,7 @@ export interface ITitleAreaControl { getContainer(): HTMLElement; refresh(instant?: boolean): void; update(instant?: boolean): void; + updateEditorActionsToolbar(): void; layout(): void; dispose(): void; } @@ -259,6 +260,12 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl // Log in telemetry if (this.telemetryService) { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'editorPart' }); } })); @@ -334,7 +341,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl return { primary, secondary }; } - protected updateEditorActionsToolbar(): void { + public updateEditorActionsToolbar(): void { const group = this.context; if (!group) { return; @@ -543,7 +550,7 @@ export function handleWorkspaceExternalDrop( // Multiple folders: Create new workspace with folders and open else if (folders.length > 1) { - workspacesToOpen = workspacesService.createWorkspace([...folders].map(folder => folder.fsPath)).then(workspace => [workspace.configPath]); + workspacesToOpen = workspacesService.createWorkspace(folders.map(folder => ({ uri: folder }))).then(workspace => [workspace.configPath]); } // Open diff --git a/src/vs/workbench/browser/parts/editor/webviewEditor.ts b/src/vs/workbench/browser/parts/editor/webviewEditor.ts index d31c6b57bd3..a1809c369d2 100644 --- a/src/vs/workbench/browser/parts/editor/webviewEditor.ts +++ b/src/vs/workbench/browser/parts/editor/webviewEditor.ts @@ -14,11 +14,6 @@ export interface HtmlPreviewEditorViewState { scrollYPercentage: number; } -interface HtmlPreviewEditorViewStates { - 0?: HtmlPreviewEditorViewState; - 1?: HtmlPreviewEditorViewState; - 2?: HtmlPreviewEditorViewState; -} /** * This class is only intended to be subclassed and not instantiated. diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis-inverse.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis-inverse.svg new file mode 100644 index 00000000000..1140c11ecc8 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/ellipsis-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis.svg new file mode 100644 index 00000000000..b61e2d0c750 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/ellipsis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/left-inverse.svg b/src/vs/workbench/browser/parts/panel/media/left-inverse.svg new file mode 100644 index 00000000000..5fea87ff152 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/left-inverse.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/src/vs/workbench/browser/parts/panel/media/left.svg b/src/vs/workbench/browser/parts/panel/media/left.svg new file mode 100644 index 00000000000..db88c12c6b3 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/left.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/src/vs/workbench/browser/parts/panel/media/panel-bottom-inverse.svg b/src/vs/workbench/browser/parts/panel/media/panel-bottom-inverse.svg new file mode 100755 index 00000000000..f9aa418241a --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-bottom-inverse.svg @@ -0,0 +1 @@ +BottomRowOfTwoRows_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panel-bottom.svg b/src/vs/workbench/browser/parts/panel/media/panel-bottom.svg new file mode 100755 index 00000000000..780681f19e5 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-bottom.svg @@ -0,0 +1 @@ +BottomRowOfTwoRows_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panel-right-inverse.svg b/src/vs/workbench/browser/parts/panel/media/panel-right-inverse.svg new file mode 100755 index 00000000000..428206fb117 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-right-inverse.svg @@ -0,0 +1 @@ +RightColumnOfTwoColumns_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panel-right.svg b/src/vs/workbench/browser/parts/panel/media/panel-right.svg new file mode 100755 index 00000000000..3b7b808f9ab --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/panel-right.svg @@ -0,0 +1 @@ +RightColumnOfTwoColumns_16x \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 10ffa06b7eb..67a4a38738a 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -13,10 +13,25 @@ } .monaco-workbench > .part.panel .title { - border-top-width: 1px; - border-top-style: solid; padding-right: 0px; height: 35px; + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.monaco-workbench > .part.panel.bottom .title { + border-top-width: 1px; + border-top-style: solid; +} + +.monaco-workbench > .part.panel.right { + border-left-width: 1px; + border-left-style: solid; +} + +.monaco-workbench > .part.panel > .composite.title > .title-actions { + flex: 0; } .monaco-workbench > .part.panel > .title > .title-actions .monaco-action-bar .action-item .action-label { @@ -25,8 +40,17 @@ /** Panel Switcher */ +.monaco-workbench > .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { + background: url('ellipsis.svg') center center no-repeat; + display: block; + height: 31px; + min-width: 28px; + margin-left: 0px; + margin-right: 0px; +} + .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar { - line-height: 35px; + line-height: 32px; } .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:first-child .action-label { @@ -41,10 +65,22 @@ padding-bottom: 4px; /* puts the bottom border down */ } -.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label.checked { +.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item.checked .action-label { border-bottom: 1px solid; } +.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .badge .badge-content { + top: 8px; + right: 0px; + position: absolute; + font-size: 11px; + min-width: 6px; + line-height: 18px; + padding: 0 5px; + border-radius: 20px; + text-align: center; +} + /** Actions */ .monaco-workbench .panel .monaco-action-bar .action-item.select-container { @@ -53,6 +89,7 @@ .monaco-workbench .panel .monaco-action-bar .action-item .select-box { cursor: pointer; + min-width: 110px; } .monaco-workbench .hide-panel-action { @@ -60,24 +97,65 @@ } .monaco-workbench .maximize-panel-action { - background: url('up.svg') center center no-repeat; + background-image: url('up.svg'); +} + +.monaco-workbench .panel.right .maximize-panel-action { + background-image: url('left.svg'); } .vs-dark .monaco-workbench .maximize-panel-action, .hc-black .monaco-workbench .maximize-panel-action { - background: url('up-inverse.svg') center center no-repeat; + background-image: url('up-inverse.svg'); +} + +.vs-dark .monaco-workbench .panel.right .maximize-panel-action, +.hc-black .monaco-workbench .panel.right .maximize-panel-action { + background-image: url('left-inverse.svg'); } .monaco-workbench .minimize-panel-action { - background: url('down.svg') center center no-repeat; + background-image: url('down.svg'); +} + +.monaco-workbench .panel.right .minimize-panel-action { + background-image: url('right.svg'); } .vs-dark .monaco-workbench .minimize-panel-action, .hc-black .monaco-workbench .minimize-panel-action { - background: url('down-inverse.svg') center center no-repeat; + background-image: url('down-inverse.svg'); +} + +.vs-dark .monaco-workbench .panel.right .minimize-panel-action, +.hc-black .monaco-workbench .panel.right .minimize-panel-action { + background-image: url('right-inverse.svg'); +} + +.monaco-workbench .move-panel-to-right { + background: url('panel-right.svg') center center no-repeat; +} + +.vs-dark .monaco-workbench .move-panel-to-right, +.hc-black .monaco-workbench .move-panel-to-right { + background: url('panel-right-inverse.svg') center center no-repeat; +} + +.monaco-workbench .move-panel-to-bottom { + background: url('panel-bottom.svg') center center no-repeat; +} + +.vs-dark .monaco-workbench .move-panel-to-bottom, +.hc-black .monaco-workbench .move-panel-to-bottom { + background: url('panel-bottom-inverse.svg') center center no-repeat; } .vs-dark .monaco-workbench .hide-panel-action, .hc-black .monaco-workbench .hide-panel-action { background: url('close-inverse.svg') center center no-repeat; -} \ No newline at end of file +} + +.vs-dark .monaco-workbench > .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more, +.hc-black .monaco-workbench > .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { + background: url('ellipsis-inverse.svg') center center no-repeat; +} diff --git a/src/vs/workbench/browser/parts/panel/media/right-inverse.svg b/src/vs/workbench/browser/parts/panel/media/right-inverse.svg new file mode 100644 index 00000000000..1dd4a2c4dfc --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/right-inverse.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/src/vs/workbench/browser/parts/panel/media/right.svg b/src/vs/workbench/browser/parts/panel/media/right.svg new file mode 100644 index 00000000000..91ac528b802 --- /dev/null +++ b/src/vs/workbench/browser/parts/panel/media/right.svg @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 9e9831c5c0d..f8cba33625d 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -11,45 +11,12 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Action } from 'vs/base/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actionRegistry'; -import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; - -export class PanelAction extends Action { - - constructor( - private panel: IPanelIdentifier, - @IKeybindingService private keybindingService: IKeybindingService, - @IPanelService private panelService: IPanelService - ) { - super(panel.id, panel.name); - - this.tooltip = nls.localize('panelActionTooltip', "{0} ({1})", panel.name, this.getKeybindingLabel(panel.commandId)); - } - - public run(event: any): TPromise { - return this.panelService.openPanel(this.panel.id, true).then(() => this.activate()); - } - - public activate(): void { - if (!this.checked) { - this._setChecked(true); - } - } - - public deactivate(): void { - if (this.checked) { - this._setChecked(false); - } - } - - private getKeybindingLabel(id: string): string { - const keys = this.keybindingService.lookupKeybinding(id); - - return keys ? keys.getLabel() : ''; - } -} +import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService'; +import { ActivityAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; +import { IActivity } from 'vs/workbench/common/activity'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class ClosePanelAction extends Action { static ID = 'workbench.action.closePanel'; @@ -115,6 +82,46 @@ class FocusPanelAction extends Action { } } +export class TogglePanelPositionAction extends Action { + + public static ID = 'workbench.action.togglePanelPosition'; + public static LABEL = nls.localize('toggledPanelPosition', "Toggle Panel Position"); + private static MOVE_TO_RIGHT_LABEL = nls.localize('moveToRight', "Move to Right"); + private static MOVE_TO_BOTTOM_LABEL = nls.localize('moveToBottom', "Move to Bottom"); + private static panelPositionConfigurationKey = 'workbench.panel.location'; + private toDispose: IDisposable[]; + + constructor( + id: string, + label: string, + @IPartService private partService: IPartService, + @IConfigurationService private configurationService: IConfigurationService + + ) { + super(id, label, partService.getPanelPosition() === Position.RIGHT ? 'move-panel-to-bottom' : 'move-panel-to-right'); + this.toDispose = []; + const setClassAndLabel = () => { + const positionRight = this.partService.getPanelPosition() === Position.RIGHT; + this.class = positionRight ? 'move-panel-to-bottom' : 'move-panel-to-right'; + this.label = positionRight ? TogglePanelPositionAction.MOVE_TO_BOTTOM_LABEL : TogglePanelPositionAction.MOVE_TO_RIGHT_LABEL; + }; + this.toDispose.push(partService.onEditorLayout(() => setClassAndLabel())); + setClassAndLabel(); + } + + public run(): TPromise { + const position = this.partService.getPanelPosition(); + const newPositionValue = (position === Position.BOTTOM) ? 'right' : 'bottom'; + + return this.configurationService.updateValue(TogglePanelPositionAction.panelPositionConfigurationKey, newPositionValue, ConfigurationTarget.USER); + } + + public dispose(): void { + super.dispose(); + this.toDispose = dispose(this.toDispose); + } +} + export class ToggleMaximizedPanelAction extends Action { public static ID = 'workbench.action.toggleMaximizedPanel'; @@ -139,7 +146,7 @@ export class ToggleMaximizedPanelAction extends Action { public run(): TPromise { // Show panel - return this.partService.setPanelHidden(false) + return (!this.partService.isVisible(Parts.PANEL_PART) ? this.partService.setPanelHidden(false) : TPromise.as(null)) .then(() => this.partService.toggleMaximizedPanel()); } @@ -149,8 +156,24 @@ export class ToggleMaximizedPanelAction extends Action { } } +export class PanelActivityAction extends ActivityAction { + + constructor( + activity: IActivity, + @IPanelService private panelService: IPanelService + ) { + super(activity); + } + + public run(event: any): TPromise { + return this.panelService.openPanel(this.activity.id, true).then(() => this.activate()); + } +} + const actionRegistry = Registry.as(WorkbenchExtensions.WorkbenchActions); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelAction, TogglePanelAction.ID, TogglePanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_J }), 'View: Toggle Panel', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPanelAction, FocusPanelAction.ID, FocusPanelAction.LABEL), 'View: Focus into Panel', nls.localize('view', "View")); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), 'View: Toggle Maximized Panel', nls.localize('view', "View")); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); \ No newline at end of file +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL), 'View: Close Panel', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), 'View: Toggle Panel Position', nls.localize('view', "View")); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, undefined), 'View: Toggle Panel Position', nls.localize('view', "View")); diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 9e761d9263e..59db62eedd2 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -4,40 +4,45 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/panelpart'; -import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; -import { IAction } from 'vs/base/common/actions'; +import { IAction, Action } from 'vs/base/common/actions'; import Event from 'vs/base/common/event'; -import { Builder, $ } from 'vs/base/browser/builder'; +import { Builder, Dimension } from 'vs/base/browser/builder'; import { Registry } from 'vs/platform/registry/common/platform'; +import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { Scope } from 'vs/workbench/browser/actions'; import { IPanel } from 'vs/workbench/common/panel'; import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/compositePart'; import { Panel, PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; +import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IMessageService } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ClosePanelAction, PanelAction, ToggleMaximizedPanelAction } from 'vs/workbench/browser/parts/panel/panelActions'; +import { ClosePanelAction, TogglePanelPositionAction, PanelActivityAction, ToggleMaximizedPanelAction } from 'vs/workbench/browser/parts/panel/panelActions'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER } from 'vs/workbench/common/theme'; -import { activeContrastBorder, focusBorder, contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; +import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; +import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry'; +import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar'; +import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IBadge } from 'vs/workbench/services/activity/common/activity'; export class PanelPart extends CompositePart implements IPanelService { public static activePanelSettingsKey = 'workbench.panelpart.activepanelid'; + private static readonly PINNED_PANELS = 'workbench.panel.pinnedPanels'; + private static readonly MIN_COMPOSITE_BAR_WIDTH = 50; public _serviceBrand: any; private blockOpeningPanel: boolean; - private panelSwitcherBar: ActionBar; - - private panelIdToActions: { [panelId: string]: PanelAction; }; + private compositeBar: CompositeBar; + private dimension: Dimension; constructor( id: string, @@ -48,7 +53,7 @@ export class PanelPart extends CompositePart implements IPanelService { @IPartService partService: IPartService, @IKeybindingService keybindingService: IKeybindingService, @IInstantiationService instantiationService: IInstantiationService, - @IThemeService themeService: IThemeService + @IThemeService themeService: IThemeService, ) { super( messageService, @@ -70,7 +75,26 @@ export class PanelPart extends CompositePart implements IPanelService { { hasTitle: true } ); - this.panelIdToActions = Object.create(null); + this.compositeBar = this.instantiationService.createInstance(CompositeBar, { + icon: false, + storageId: PanelPart.PINNED_PANELS, + orientation: ActionsOrientation.HORIZONTAL, + composites: this.getPanels(), + openComposite: (compositeId: string) => this.openPanel(compositeId, true), + getActivityAction: (compositeId: string) => this.instantiationService.createInstance(PanelActivityAction, this.getPanel(compositeId)), + getCompositePinnedAction: (compositeId: string) => new ToggleCompositePinnedAction(this.getPanel(compositeId), this.compositeBar), + getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(PanelActivityAction, this.getPanel(compositeId)), + getDefaultCompositeId: () => Registry.as(PanelExtensions.Panels).getDefaultPanelId(), + hidePart: () => this.partService.setPanelHidden(true), + overflowActionSize: 28, + colors: { + backgroundColor: PANEL_BACKGROUND, + badgeBackground, + badgeForeground, + dragAndDropBackground: PANEL_DRAG_AND_DROP_BACKGROUND + } + }); + this.toUnbind.push(this.compositeBar); this.registerListeners(); } @@ -78,16 +102,15 @@ export class PanelPart extends CompositePart implements IPanelService { private registerListeners(): void { // Activate panel action on opening of a panel - this.toUnbind.push(this.onDidPanelOpen(panel => this.updatePanelActions(panel.getId(), true))); + this.toUnbind.push(this.onDidPanelOpen(panel => { + this.compositeBar.activateComposite(panel.getId()); + // Need to relayout composite bar since different panels have different action bar width + this.layoutCompositeBar(); + })); // Deactivate panel action on close - this.toUnbind.push(this.onDidPanelClose(panel => this.updatePanelActions(panel.getId(), false))); - } - - private updatePanelActions(id: string, didOpen: boolean): void { - if (this.panelIdToActions[id]) { - didOpen ? this.panelIdToActions[id].activate() : this.panelIdToActions[id].deactivate(); - } + this.toUnbind.push(this.onDidPanelClose(panel => this.compositeBar.deactivateComposite(panel.getId()))); + this.toUnbind.push(this.compositeBar.onDidContextMenu(e => this.showContextMenu(e))); } public get onDidPanelOpen(): Event { @@ -98,11 +121,12 @@ export class PanelPart extends CompositePart implements IPanelService { return this._onDidCompositeClose.event; } - protected updateStyles(): void { + public updateStyles(): void { super.updateStyles(); const container = this.getContainer(); container.style('background-color', this.getColor(PANEL_BACKGROUND)); + container.style('border-left-color', this.getColor(PANEL_BORDER) || this.getColor(contrastBorder)); const title = this.getTitleArea(); title.style('border-top-color', this.getColor(PANEL_BORDER) || this.getColor(contrastBorder)); @@ -127,6 +151,25 @@ export class PanelPart extends CompositePart implements IPanelService { return promise.then(() => this.openComposite(id, focus)); } + public showActivity(panelId: string, badge: IBadge, clazz?: string): IDisposable { + return this.compositeBar.showActivity(panelId, badge, clazz); + } + + private getPanel(panelId: string): IPanelIdentifier { + return Registry.as(PanelExtensions.Panels).getPanels().filter(p => p.id === panelId).pop(); + } + + private showContextMenu(e: MouseEvent): void { + const event = new StandardMouseEvent(e); + const actions: Action[] = this.getPanels().map(panel => this.instantiationService.createInstance(ToggleCompositePinnedAction, panel, this.compositeBar)); + + this.contextMenuService.showContextMenu({ + getAnchor: () => { return { x: event.posx, y: event.posy }; }, + getActions: () => TPromise.as(actions), + onHide: () => dispose(actions) + }); + } + public getPanels(): IPanelIdentifier[] { return Registry.as(PanelExtensions.Panels).getPanels() .sort((v1, v2) => v1.order - v2.order); @@ -135,6 +178,7 @@ export class PanelPart extends CompositePart implements IPanelService { protected getActions(): IAction[] { return [ this.instantiationService.createInstance(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), + this.instantiationService.createInstance(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), this.instantiationService.createInstance(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL) ]; } @@ -152,23 +196,12 @@ export class PanelPart extends CompositePart implements IPanelService { } protected createTitleLabel(parent: Builder): ICompositeTitleLabel { - let titleArea = $(parent).div({ - 'class': ['panel-switcher-container'] - }); - - // Show a panel switcher - this.panelSwitcherBar = new ActionBar(titleArea, { - orientation: ActionsOrientation.HORIZONTAL, - ariaLabel: nls.localize('panelSwitcherBarAriaLabel', "Active Panel Switcher"), - animated: false - }); - this.toUnbind.push(this.panelSwitcherBar); - - this.fillPanelSwitcher(); + const titleArea = this.compositeBar.create(parent.getHTMLElement()); + titleArea.classList.add('panel-switcher-container'); return { updateTitle: (id, title, keybinding) => { - const action = this.panelIdToActions[id]; + const action = this.compositeBar.getAction(id); if (action) { action.label = title; } @@ -179,17 +212,37 @@ export class PanelPart extends CompositePart implements IPanelService { }; } - private fillPanelSwitcher(): void { - const panels = this.getPanels(); + public layout(dimension: Dimension): Dimension[] { - this.panelSwitcherBar.push(panels.map(panel => { - const action = this.instantiationService.createInstance(PanelAction, panel); + if (this.partService.getPanelPosition() === Position.RIGHT) { + // Take into account the 1px border when layouting + this.dimension = new Dimension(dimension.width - 1, dimension.height); + } else { + this.dimension = dimension; + } + const sizes = super.layout(this.dimension); + this.layoutCompositeBar(); - this.panelIdToActions[panel.id] = action; - this.toUnbind.push(action); + return sizes; + } - return action; - })); + private layoutCompositeBar(): void { + if (this.dimension) { + let availableWidth = this.dimension.width - 8; // take padding into account + if (this.toolBar) { + // adjust height for global actions showing + availableWidth = Math.max(PanelPart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.toolBar.getContainer().getHTMLElement().offsetWidth); + } + this.compositeBar.layout(new Dimension(availableWidth, this.dimension.height)); + } + } + + public shutdown(): void { + // Persist Hidden State + this.compositeBar.store(); + + // Pass to super + super.shutdown(); } } @@ -215,7 +268,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { if (titleActive || titleActiveBorder) { collector.addRule(` .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:hover .action-label, - .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label.checked { + .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item.checked .action-label { color: ${titleActive}; border-bottom-color: ${titleActiveBorder}; } @@ -236,13 +289,17 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const focusBorderColor = theme.getColor(focusBorder); if (focusBorderColor) { collector.addRule(` - .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:focus { + .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:focus .action-label { color: ${titleActive}; border-bottom-color: ${focusBorderColor} !important; border-bottom: 1px solid; + } + `); + collector.addRule(` + .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:focus { outline: none; } - `); + `); } // Styling with Outline color (e.g. high contrast theme) @@ -251,7 +308,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const outline = theme.getColor(activeContrastBorder); collector.addRule(` - .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label.checked, + .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item.checked .action-label, .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:hover { outline-color: ${outline}; outline-width: 1px; @@ -261,7 +318,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { outline-offset: 3px; } - .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:hover:not(.checked) { + .monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:not(.checked) .action-label:hover { outline-style: dashed; } `); diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 48394dca936..d40e65a496d 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -14,13 +14,14 @@ import strings = require('vs/base/common/strings'); import filters = require('vs/base/common/filters'); import DOM = require('vs/base/browser/dom'); import URI from 'vs/base/common/uri'; +import * as resources from 'vs/base/common/resources'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import types = require('vs/base/common/types'); import { Action, IAction } from 'vs/base/common/actions'; import { IIconLabelOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen'; -import { QuickOpenEntry, QuickOpenModel, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; +import { QuickOpenEntry, QuickOpenModel, QuickOpenEntryGroup, compareEntries, QuickOpenItemAccessorClass } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenWidget, HideReason } from 'vs/base/parts/quickopen/browser/quickOpenWidget'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; import labels = require('vs/base/common/labels'); @@ -31,12 +32,12 @@ import { IResourceInput, IEditorInput } from 'vs/platform/editor/common/editor'; import { IModeService } from 'vs/editor/common/services/modeService'; import { getIconClasses } from 'vs/workbench/browser/labels'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { EditorInput, toResource, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; +import { EditorInput, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; import { Component } from 'vs/workbench/common/component'; import Event, { Emitter } from 'vs/base/common/event'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { KeyMod } from 'vs/base/common/keyCodes'; -import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, EditorQuickOpenEntry, IWorkbenchQuickOpenConfiguration } from 'vs/workbench/browser/quickopen'; +import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, EditorQuickOpenEntry, CLOSE_ON_FOCUS_LOST_CONFIG } from 'vs/workbench/browser/quickopen'; import errors = require('vs/base/common/errors'); import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPickOpenEntry, IFilePickOpenEntry, IInputOptions, IQuickOpenService, IPickOptions, IShowOptions, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen'; @@ -54,7 +55,8 @@ import { attachQuickOpenStyler } from 'vs/platform/theme/common/styler'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { FileKind } from 'vs/platform/files/common/files'; +import { FileKind, IFileService } from 'vs/platform/files/common/files'; +import { scoreItem, ScorerCache, compareItemsByScore, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; const HELP_PREFIX = '?'; @@ -96,21 +98,20 @@ export class QuickOpenController extends Component implements IQuickOpenService private promisesToCompleteOnHide: ValueCallback[]; private previousActiveHandlerDescriptor: QuickOpenHandlerDescriptor; private actionProvider = new ContributableActionProvider(); - private previousValue = ''; private visibilityChangeTimeoutHandle: number; private closeOnFocusLost: boolean; + private editorHistoryHandler: EditorHistoryHandler; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @IContextKeyService private contextKeyService: IContextKeyService, @IConfigurationService private configurationService: IConfigurationService, - @IHistoryService private historyService: IHistoryService, @IInstantiationService private instantiationService: IInstantiationService, @IPartService private partService: IPartService, @IListService private listService: IListService, + @IEnvironmentService private environmentService: IEnvironmentService, @IThemeService themeService: IThemeService ) { super(QuickOpenController.ID, themeService); @@ -121,24 +122,30 @@ export class QuickOpenController extends Component implements IQuickOpenService this.promisesToCompleteOnHide = []; + this.editorHistoryHandler = this.instantiationService.createInstance(EditorHistoryHandler); + this.inQuickOpenMode = new RawContextKey('inQuickOpen', false).bindTo(contextKeyService); this._onShow = new Emitter(); this._onHide = new Emitter(); - this.updateConfiguration(this.configurationService.getConfiguration()); + this.updateConfiguration(); this.registerListeners(); } private registerListeners(): void { - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.updateConfiguration(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration())); this.toUnbind.push(this.partService.onTitleBarVisibilityChange(() => this.positionQuickOpenWidget())); this.toUnbind.push(browser.onDidChangeZoomLevel(() => this.positionQuickOpenWidget())); } - private updateConfiguration(settings: IWorkbenchQuickOpenConfiguration): void { - this.closeOnFocusLost = settings.workbench && settings.workbench.quickOpen && settings.workbench.quickOpen.closeOnFocusLost; + private updateConfiguration(): void { + if (this.environmentService.args['sticky-quickopen']) { + this.closeOnFocusLost = false; + } else { + this.closeOnFocusLost = this.configurationService.getValue(CLOSE_ON_FOCUS_LOST_CONFIG); + } } public get onShow(): Event { @@ -169,7 +176,7 @@ export class QuickOpenController extends Component implements IQuickOpenService : nls.localize('inputModeEntry', "Press 'Enter' to confirm your input or 'Escape' to cancel"); let currentPick = defaultMessage; - let currentValidation = TPromise.as(true); + let currentValidation: TPromise; let currentDecoration: Severity; let lastValue: string; @@ -186,35 +193,49 @@ export class QuickOpenController extends Component implements IQuickOpenService valueSelection: options.valueSelection, inputDecoration: currentDecoration, onDidType: (value) => { - lastValue = value; + if (lastValue !== value) { - if (options.validateInput) { - if (currentValidation) { - currentValidation.cancel(); - } + lastValue = value; - currentValidation = TPromise.timeout(100).then(() => { - return options.validateInput(value).then(message => { - currentDecoration = !!message ? Severity.Error : void 0; - const newPick = message || defaultMessage; - if (newPick !== currentPick) { - options.valueSelection = [lastValue.length, lastValue.length]; - currentPick = newPick; - resolve(new TPromise(init)); - } + if (options.validateInput) { + if (currentValidation) { + currentValidation.cancel(); + } - return !message; + currentValidation = TPromise.timeout(100).then(() => { + return options.validateInput(value).then(message => { + currentDecoration = !!message ? Severity.Error : void 0; + const newPick = message || defaultMessage; + if (newPick !== currentPick) { + options.valueSelection = [lastValue.length, lastValue.length]; + currentPick = newPick; + resolve(new TPromise(init)); + } + + return !message; + }); + }, err => { + // ignore + return null; }); - }, err => { - // ignore - return null; - }); + } } } }, token).then(resolve, reject); }; return new TPromise(init).then(item => { + + if (!currentValidation) { + if (options.validateInput) { + currentValidation = options + .validateInput(lastValue === void 0 ? options.value : lastValue) + .then(message => !message); + } else { + currentValidation = TPromise.as(true); + } + } + return currentValidation.then(valid => { if (valid && item) { return lastValue === void 0 ? (options.value || '') : lastValue; @@ -439,7 +460,7 @@ export class QuickOpenController extends Component implements IQuickOpenService return pickA.index - pickB.index; // restore natural order } - return QuickOpenEntry.compare(pickA, pickB, normalizedSearchValue); + return compareEntries(pickA, pickB, normalizedSearchValue); }); this.pickOpenWidget.refresh(model, value ? { autoFocusFirstEntry: true } : autoFocus); @@ -525,8 +546,7 @@ export class QuickOpenController extends Component implements IQuickOpenService public show(prefix?: string, options?: IShowOptions): TPromise { let quickNavigateConfiguration = options ? options.quickNavigateConfiguration : void 0; let inputSelection = options ? options.inputSelection : void 0; - - this.previousValue = prefix; + let autoFocus = options ? options.autoFocus : void 0; const promiseCompletedOnHide = new TPromise(c => { this.promisesToCompleteOnHide.push(c); @@ -536,11 +556,16 @@ export class QuickOpenController extends Component implements IQuickOpenService const registry = Registry.as(Extensions.Quickopen); const handlerDescriptor = registry.getQuickOpenHandler(prefix) || registry.getDefaultQuickOpenHandler(); + /* __GDPR__ + "quickOpenWidgetShown" : { + "mode" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "quickNavigate": { "${inline}": [ "${IQuickNavigateConfiguration}" ] } + } + */ this.telemetryService.publicLog('quickOpenWidgetShown', { mode: handlerDescriptor.getId(), quickNavigate: quickNavigateConfiguration }); // Trigger onOpen - this.resolveHandler(handlerDescriptor) - .done(null, errors.onUnexpectedError); + this.resolveHandler(handlerDescriptor).done(null, errors.onUnexpectedError); // Create upon first open if (!this.quickOpenWidget) { @@ -575,19 +600,21 @@ export class QuickOpenController extends Component implements IQuickOpenService // Show quick open with prefix or editor history if (!this.quickOpenWidget.isVisible() || quickNavigateConfiguration) { if (prefix) { - this.quickOpenWidget.show(prefix, { quickNavigateConfiguration, inputSelection }); + this.quickOpenWidget.show(prefix, { quickNavigateConfiguration, inputSelection, autoFocus }); } else { const editorHistory = this.getEditorHistoryWithGroupLabel(); if (editorHistory.getEntries().length < 2) { quickNavigateConfiguration = null; // If no entries can be shown, default to normal quick open mode } - let autoFocus: IAutoFocus; - if (!quickNavigateConfiguration) { - autoFocus = { autoFocusFirstEntry: true }; - } else { - const visibleEditorCount = this.editorService.getVisibleEditors().length; - autoFocus = { autoFocusFirstEntry: visibleEditorCount === 0, autoFocusSecondEntry: visibleEditorCount !== 0 }; + // Compute auto focus + if (!autoFocus) { + if (!quickNavigateConfiguration) { + autoFocus = { autoFocusFirstEntry: true }; + } else { + const visibleEditorCount = this.editorService.getVisibleEditors().length; + autoFocus = { autoFocusFirstEntry: visibleEditorCount === 0, autoFocusSecondEntry: visibleEditorCount !== 0 }; + } } // Update context @@ -695,7 +722,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } private getEditorHistoryWithGroupLabel(): QuickOpenModel { - const entries: QuickOpenEntry[] = this.getEditorHistoryEntries(); + const entries: QuickOpenEntry[] = this.editorHistoryHandler.getResults(); // Apply label to first entry if (entries.length > 0) { @@ -715,7 +742,6 @@ export class QuickOpenController extends Component implements IQuickOpenService } private onType(value: string): void { - this.previousValue = value; // look for a handler const registry = Registry.as(Extensions.Quickopen); @@ -793,7 +819,7 @@ export class QuickOpenController extends Component implements IQuickOpenService private handleDefaultHandler(handler: QuickOpenHandlerDescriptor, value: string, currentResultToken: string): TPromise { // Fill in history results if matching - const matchingHistoryEntries = this.getEditorHistoryEntries(value); + const matchingHistoryEntries = this.editorHistoryHandler.getResults(value); if (matchingHistoryEntries.length > 0) { matchingHistoryEntries[0] = new EditorHistoryEntryGroup(matchingHistoryEntries[0], nls.localize('historyMatches', "recently opened"), false); } @@ -835,59 +861,6 @@ export class QuickOpenController extends Component implements IQuickOpenService }); } - private getEditorHistoryEntries(searchValue?: string): QuickOpenEntry[] { - if (searchValue) { - searchValue = searchValue.replace(/ /g, ''); // get rid of all whitespace - } - - // Just return all if we are not searching - const history = this.historyService.getHistory(); - if (!searchValue) { - return history.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input)); - } - - const searchInPath = searchValue.indexOf(paths.nativeSep) >= 0; - - const results: QuickOpenEntry[] = []; - history.forEach(input => { - let resource: URI; - if (input instanceof EditorInput) { - resource = toResource(input, { filter: ['file', 'untitled'] }); - } else { - resource = (input as IResourceInput).resource; - } - - if (!resource) { - return; //For now, only support to match on inputs that provide resource information - } - - let searchTargetToMatch: string; - if (searchInPath) { - searchTargetToMatch = labels.getPathLabel(resource, this.contextService); - } else if (input instanceof EditorInput) { - searchTargetToMatch = input.getName(); - } else { - searchTargetToMatch = paths.basename((input as IResourceInput).resource.fsPath); - } - - // Check if this entry is a match for the search value - if (!filters.matchesFuzzy(searchValue, searchTargetToMatch)) { - return; - } - - const entry = this.instantiationService.createInstance(EditorHistoryEntry, input); - - const { labelHighlights, descriptionHighlights } = QuickOpenEntry.highlight(entry, searchValue); - entry.setHighlights(labelHighlights, descriptionHighlights); - - results.push(entry); - }); - - // Sort - const normalizedSearchValue = strings.stripWildcards(searchValue.toLowerCase()); - return results.sort((elementA: EditorHistoryEntry, elementB: EditorHistoryEntry) => QuickOpenEntry.compare(elementA, elementB, normalizedSearchValue)); - } - private mergeResults(quickOpenModel: QuickOpenModel, handlerResults: QuickOpenEntry[], groupLabel: string): void { // Remove results already showing by checking for a "resource" property @@ -1007,7 +980,7 @@ export class QuickOpenController extends Component implements IQuickOpenService return result.then(null, (error) => { delete this.mapResolvedHandlersToPrefix[id]; - return TPromise.wrapError(new Error('Unable to instantiate quick open handler ' + handler.moduleName + ' - ' + handler.ctorName + ': ' + JSON.stringify(error))); + return TPromise.wrapError(new Error(`Unable to instantiate quick open handler ${handler.getId()}: ${JSON.stringify(error)}`)); }); } @@ -1020,7 +993,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } // Otherwise load and create - return this.mapResolvedHandlersToPrefix[id] = this.instantiationService.createInstance(handler); + return this.mapResolvedHandlersToPrefix[id] = TPromise.as(handler.instantiate(this.instantiationService)); } public layout(dimension: Dimension): void { @@ -1191,6 +1164,80 @@ class PickOpenActionProvider implements IActionProvider { } } +class EditorHistoryHandler { + private scorerCache: ScorerCache; + + constructor( + @IHistoryService private historyService: IHistoryService, + @IInstantiationService private instantiationService: IInstantiationService, + @IFileService private fileService: IFileService + ) { + this.scorerCache = Object.create(null); + } + + public getResults(searchValue?: string): QuickOpenEntry[] { + + // Massage search for scoring + const query = prepareQuery(searchValue); + + // Just return all if we are not searching + const history = this.historyService.getHistory(); + if (!query.value) { + return history.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input)); + } + + // Otherwise filter by search value and sort by score. Include matches on description + // in case the user is explicitly including path separators. + const accessor = query.containsPathSeparator ? MatchOnDescription : DoNotMatchOnDescription; + return history + + // For now, only support to match on inputs that provide resource information + .filter(input => { + let resource: URI; + if (input instanceof EditorInput) { + resource = resourceForEditorHistory(input, this.fileService); + } else { + resource = (input as IResourceInput).resource; + } + + return !!resource; + }) + + // Conver to quick open entries + .map(input => this.instantiationService.createInstance(EditorHistoryEntry, input)) + + // Make sure the search value is matching + .filter(e => { + const itemScore = scoreItem(e, query, false, accessor, this.scorerCache); + if (!itemScore.score) { + return false; + } + + e.setHighlights(itemScore.labelMatch, itemScore.descriptionMatch); + + return true; + }) + + // Sort by score and provide a fallback sorter that keeps the + // recency of items in case the score for items is the same + .sort((e1, e2) => compareItemsByScore(e1, e2, query, false, accessor, this.scorerCache, (e1, e2, query, accessor) => -1)); + } +} + +class EditorHistoryItemAccessorClass extends QuickOpenItemAccessorClass { + + constructor(private allowMatchOnDescription: boolean) { + super(); + } + + public getItemDescription(entry: QuickOpenEntry): string { + return this.allowMatchOnDescription ? entry.getDescription() : void 0; + } +} + +const MatchOnDescription = new EditorHistoryItemAccessorClass(true); +const DoNotMatchOnDescription = new EditorHistoryItemAccessorClass(false); + export class EditorHistoryEntryGroup extends QuickOpenEntryGroup { // Marker class } @@ -1210,14 +1257,15 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { @ITextFileService private textFileService: ITextFileService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService, - @IEnvironmentService environmentService: IEnvironmentService + @IEnvironmentService environmentService: IEnvironmentService, + @IFileService fileService: IFileService ) { super(editorService); this.input = input; if (input instanceof EditorInput) { - this.resource = toResource(input, { filter: ['file', 'untitled'] }); + this.resource = resourceForEditorHistory(input, fileService); this.label = input.getName(); this.description = input.getDescription(); this.dirty = input.isDirty(); @@ -1225,7 +1273,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { const resourceInput = input as IResourceInput; this.resource = resourceInput.resource; this.label = paths.basename(resourceInput.resource.fsPath); - this.description = labels.getPathLabel(paths.dirname(this.resource.fsPath), contextService, environmentService); + this.description = labels.getPathLabel(resources.dirname(this.resource), contextService, environmentService); this.dirty = this.resource && this.textFileService.isDirty(this.resource); if (this.dirty && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { @@ -1282,6 +1330,18 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { } } +function resourceForEditorHistory(input: EditorInput, fileService: IFileService): URI { + const resource = input ? input.getResource() : void 0; + + // For the editor history we only prefer resources that are either untitled or + // can be handled by the file service which indicates they are editable resources. + if (resource && (fileService.canHandleResource(resource) || resource.scheme === 'untitled')) { + return resource; + } + + return void 0; +} + export class RemoveFromEditorHistoryAction extends Action { public static ID = 'workbench.action.removeFromEditorHistory'; diff --git a/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts b/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts index b541f56e11b..824a8017bae 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts @@ -8,7 +8,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { RemoveFromEditorHistoryAction } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; import { QuickOpenSelectNextAction, QuickOpenSelectPreviousAction, inQuickOpenContext, getQuickNavigateHandler, QuickOpenNavigateNextAction, QuickOpenNavigatePreviousAction, defaultQuickOpenContext, QUICKOPEN_ACTION_ID, QUICKOPEN_ACION_LABEL } from 'vs/workbench/browser/parts/quickopen/quickopen'; diff --git a/src/vs/workbench/browser/parts/quickopen/quickopen.ts b/src/vs/workbench/browser/parts/quickopen/quickopen.ts index 4b0331d645c..9138bb4c03c 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickopen.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickopen.ts @@ -29,6 +29,15 @@ CommandsRegistry.registerCommand(QUICKOPEN_ACTION_ID, function (accessor: Servic }); }); +export const QUICKOPEN_FOCUS_SECONDARY_ACTION_ID = 'workbench.action.quickOpenPreviousEditor'; +CommandsRegistry.registerCommand(QUICKOPEN_FOCUS_SECONDARY_ACTION_ID, function (accessor: ServicesAccessor, prefix: string = null) { + const quickOpenService = accessor.get(IQuickOpenService); + + return quickOpenService.show(null, { autoFocus: { autoFocusSecondEntry: true } }).then(() => { + return void 0; + }); +}); + export class BaseQuickOpenNavigateAction extends Action { constructor( diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index ed8f7c784a3..395f82e65cd 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -10,7 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Action, IAction } from 'vs/base/common/actions'; import { CompositePart } from 'vs/workbench/browser/parts/compositePart'; import { Viewlet, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index c27405a5766..011fb2a1548 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -17,7 +17,6 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Part } from 'vs/workbench/browser/part'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { StatusbarAlignment, IStatusbarRegistry, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -28,7 +27,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { Action } from 'vs/base/common/actions'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND, STATUS_BAR_BORDER, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER } from 'vs/workbench/common/theme'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { isThemeColor } from 'vs/editor/common/editorCommon'; import { Color } from 'vs/base/common/color'; @@ -55,7 +54,7 @@ export class StatusbarPart extends Part implements IStatusbarService { } private registerListeners(): void { - this.toUnbind.push(this.contextService.onDidChangeWorkspaceRoots(() => this.updateStyles())); + this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); } public addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable { @@ -141,10 +140,10 @@ export class StatusbarPart extends Part implements IStatusbarService { const container = this.getContainer(); - container.style('color', this.getColor(this.contextService.hasWorkspace() ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND)); - container.style('background-color', this.getColor(this.contextService.hasWorkspace() ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND)); + container.style('color', this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND)); + container.style('background-color', this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND)); - const borderColor = this.getColor(this.contextService.hasWorkspace() ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER) || this.getColor(contrastBorder); + const borderColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER) || this.getColor(contrastBorder); container.style('border-top-width', borderColor ? '1px' : null); container.style('border-top-style', borderColor ? 'solid' : null); container.style('border-top-color', borderColor); @@ -287,23 +286,6 @@ class StatusBarEntryItem implements IStatusbarItem { private executeCommand(id: string, args?: any[]) { args = args || []; - // Lookup built in commands - const builtInActionDescriptor = Registry.as(ActionExtensions.WorkbenchActions).getWorkbenchAction(id); - if (builtInActionDescriptor) { - const action = this.instantiationService.createInstance(builtInActionDescriptor.syncDescriptor); - - if (action.enabled) { - this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'status bar' }); - (action.run() || TPromise.as(null)).done(() => { - action.dispose(); - }, (err) => this.messageService.show(Severity.Error, toErrorMessage(err))); - } else { - this.messageService.show(Severity.Warning, nls.localize('canNotRun', "Command '{0}' is currently not enabled and can not be run.", action.label || id)); - } - - return; - } - // Maintain old behaviour of always focusing the editor here const activeEditor = this.editorService.getActiveEditor(); const codeEditor = getCodeEditor(activeEditor); @@ -311,7 +293,13 @@ class StatusBarEntryItem implements IStatusbarItem { codeEditor.focus(); } - // Fallback to the command service for any other case + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('workbenchActionExecuted', { id, from: 'status bar' }); this.commandService.executeCommand(id, ...args).done(undefined, err => this.messageService.show(Severity.Error, toErrorMessage(err))); } } @@ -349,4 +337,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { if (statusBarProminentItemHoverBackground) { collector.addRule(`.monaco-workbench > .part.statusbar > .statusbar-item a.status-bar-info:hover:not([disabled]):not(.disabled) { background-color: ${statusBarProminentItemHoverBackground}; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index cdc687484c1..14162ffd5ee 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -18,7 +18,7 @@ import * as errors from 'vs/base/common/errors'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IAction, Action } from 'vs/base/common/actions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; @@ -27,12 +27,13 @@ import nls = require('vs/nls'); import * as labels from 'vs/base/common/labels'; import { EditorInput, toResource } from 'vs/workbench/common/editor'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { Verbosity } from 'vs/platform/editor/common/editor'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER } from 'vs/workbench/common/theme'; +import { isMacintosh } from 'vs/base/common/platform'; import URI from 'vs/base/common/uri'; -import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; export class TitlebarPart extends Part implements ITitleService { @@ -41,7 +42,7 @@ export class TitlebarPart extends Part implements ITitleService { private static NLS_UNSUPPORTED = nls.localize('patchedWindowTitle', "[Unsupported]"); private static NLS_EXTENSION_HOST = nls.localize('devExtensionWindowTitlePrefix', "[Extension Development Host]"); private static TITLE_DIRTY = '\u25cf '; - private static TITLE_SEPARATOR = ' — '; + private static TITLE_SEPARATOR = isMacintosh ? ' — ' : ' - '; // macOS uses special - separator private titleContainer: Builder; private title: Builder; @@ -51,7 +52,6 @@ export class TitlebarPart extends Part implements ITitleService { private isInactive: boolean; - private titleTemplate: string; private isPure: boolean; private activeEditorListeners: IDisposable[]; @@ -67,7 +67,7 @@ export class TitlebarPart extends Part implements ITitleService { @IEnvironmentService private environmentService: IEnvironmentService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IThemeService themeService: IThemeService, - @IPartService private partService: IPartService + @ILifecycleService private lifecycleService: ILifecycleService ) { super(id, { hasTitle: false }, themeService); @@ -81,11 +81,8 @@ export class TitlebarPart extends Part implements ITitleService { private init(): void { - // Read initial config - this.onConfigurationChanged(); - // Initial window title when loading is done - this.partService.joinCreation().done(() => this.setTitle(this.getWindowTitle())); + this.lifecycleService.when(LifecyclePhase.Running).then(() => this.setTitle(this.getWindowTitle())); // Integrity for window title this.integrityService.isPure().then(r => { @@ -99,10 +96,11 @@ export class TitlebarPart extends Part implements ITitleService { private registerListeners(): void { this.toUnbind.push(DOM.addDisposableListener(window, DOM.EventType.BLUR, () => this.onBlur())); this.toUnbind.push(DOM.addDisposableListener(window, DOM.EventType.FOCUS, () => this.onFocus())); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(() => this.onConfigurationChanged(true))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChanged(e))); this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); - this.toUnbind.push(this.contextService.onDidChangeWorkspaceRoots(() => this.onDidChangeWorkspaceRoots())); - this.toUnbind.push(this.contextService.onDidChangeWorkspaceName(() => this.onDidChangeWorkspaceName())); + this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.setTitle(this.getWindowTitle()))); + this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.setTitle(this.getWindowTitle()))); + this.toUnbind.push(this.contextService.onDidChangeWorkspaceName(() => this.setTitle(this.getWindowTitle()))); } private onBlur(): void { @@ -115,19 +113,8 @@ export class TitlebarPart extends Part implements ITitleService { this.updateStyles(); } - private onDidChangeWorkspaceRoots(): void { - this.setTitle(this.getWindowTitle()); - } - - private onDidChangeWorkspaceName(): void { - this.setTitle(this.getWindowTitle()); - } - - private onConfigurationChanged(update?: boolean): void { - const currentTitleTemplate = this.titleTemplate; - this.titleTemplate = this.configurationService.lookup('window.title').value; - - if (update && currentTitleTemplate !== this.titleTemplate) { + private onConfigurationChanged(event: IConfigurationChangeEvent): void { + if (event.affectsConfiguration('window.title')) { this.setTitle(this.getWindowTitle()); } } @@ -192,41 +179,32 @@ export class TitlebarPart extends Part implements ITitleService { const input = this.editorService.getActiveEditorInput(); const workspace = this.contextService.getWorkspace(); - // Compute root resource - // Single Root Workspace: always the single root workspace in this case - // Multi Root Workspace: workspace configuration file let root: URI; - if (this.contextService.hasMultiFolderWorkspace()) { + if (workspace.configuration) { root = workspace.configuration; - } else if (this.contextService.hasFolderWorkspace()) { - root = workspace.roots[0]; + } else if (workspace.folders.length) { + root = workspace.folders[0].uri; } // Compute folder resource // Single Root Workspace: always the root single workspace in this case - // Multi Root Workspace: root folder of the currently active file if any - let folder: URI; - if (workspace) { - if (workspace.roots.length === 1) { - folder = workspace.roots[0]; - } else { - folder = this.contextService.getRoot(toResource(input, { supportSideBySide: true, filter: 'file' })); - } - } + // Otherwise: root folder of the currently active file if any + let folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(input, { supportSideBySide: true })); // Variables const activeEditorShort = input ? input.getTitle(Verbosity.SHORT) : ''; const activeEditorMedium = input ? input.getTitle(Verbosity.MEDIUM) : activeEditorShort; const activeEditorLong = input ? input.getTitle(Verbosity.LONG) : activeEditorMedium; - const rootName = workspace ? workspace.name : ''; - const rootPath = workspace ? labels.getPathLabel(root, void 0, this.environmentService) : ''; - const folderName = folder ? (paths.basename(folder.fsPath) || folder.fsPath) : ''; - const folderPath = folder ? labels.getPathLabel(folder, void 0, this.environmentService) : ''; + const rootName = workspace.name; + const rootPath = root ? labels.getPathLabel(root, void 0, this.environmentService) : ''; + const folderName = folder ? folder.name : ''; + const folderPath = folder ? labels.getPathLabel(folder.uri, void 0, this.environmentService) : ''; const dirty = input && input.isDirty() ? TitlebarPart.TITLE_DIRTY : ''; const appName = this.environmentService.appNameLong; const separator = TitlebarPart.TITLE_SEPARATOR; + const titleTemplate = this.configurationService.getValue('window.title'); - return labels.template(this.titleTemplate, { + return labels.template(titleTemplate, { activeEditorShort, activeEditorLong, activeEditorMedium, @@ -265,6 +243,17 @@ export class TitlebarPart extends Part implements ITitleService { } }); + // Since the title area is used to drag the window, we do not want to steal focus from the + // currently active element. So we restore focus after a timeout back to where it was. + this.titleContainer.on([DOM.EventType.MOUSE_DOWN], () => { + const active = document.activeElement; + setTimeout(() => { + if (active instanceof HTMLElement) { + active.focus(); + } + }, 0 /* need a timeout because we are in capture phase */); + }, void 0, true /* use capture to know the currently active element properly */); + return this.titleContainer; } diff --git a/test/smoke/src/areas/window.ts b/src/vs/workbench/browser/parts/views/media/panelviewlet.css similarity index 60% rename from test/smoke/src/areas/window.ts rename to src/vs/workbench/browser/parts/views/media/panelviewlet.css index 69182b4e537..adddb24399d 100644 --- a/test/smoke/src/areas/window.ts +++ b/src/vs/workbench/browser/parts/views/media/panelviewlet.css @@ -3,16 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SpectronApplication } from '../spectron/application'; - -export class Window { - - constructor(private spectron: SpectronApplication) { - - } - - public async getTitle(): Promise { - return this.spectron.client.getTitle(); - } - +.monaco-panel-view .panel > .panel-header > .title { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; } diff --git a/src/vs/workbench/parts/views/browser/media/views.css b/src/vs/workbench/browser/parts/views/media/views.css similarity index 100% rename from src/vs/workbench/parts/views/browser/media/views.css rename to src/vs/workbench/browser/parts/views/media/views.css diff --git a/src/vs/workbench/browser/parts/views/panelViewlet.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts new file mode 100644 index 00000000000..79e33335a08 --- /dev/null +++ b/src/vs/workbench/browser/parts/views/panelViewlet.ts @@ -0,0 +1,290 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/panelviewlet'; +import * as nls from 'vs/nls'; +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; +import { ColorIdentifier, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { attachStyler, IColorMapping, IThemable } from 'vs/platform/theme/common/styler'; +import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND } from 'vs/workbench/common/theme'; +import { Dimension, Builder } from 'vs/base/browser/builder'; +import { append, $, trackFocus } from 'vs/base/browser/dom'; +import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { firstIndex } from 'vs/base/common/arrays'; +import { IAction, IActionRunner } from 'vs/base/common/actions'; +import { IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { prepareActions } from 'vs/workbench/browser/actions'; +import { Viewlet, ViewletRegistry, Extensions } from 'vs/workbench/browser/viewlet'; +import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { PanelView, IPanelViewOptions, IPanelOptions, Panel } from 'vs/base/browser/ui/splitview/panelview'; + +export interface IPanelColors extends IColorMapping { + dropBackground?: ColorIdentifier; + headerForeground?: ColorIdentifier; + headerBackground?: ColorIdentifier; + headerHighContrastBorder?: ColorIdentifier; +} + +export function attachPanelStyler(widget: IThemable, themeService: IThemeService) { + return attachStyler(themeService, { + headerForeground: SIDE_BAR_SECTION_HEADER_FOREGROUND, + headerBackground: SIDE_BAR_SECTION_HEADER_BACKGROUND, + headerHighContrastBorder: contrastBorder, + dropBackground: SIDE_BAR_DRAG_AND_DROP_BACKGROUND + }, widget); +} + +export interface IViewletPanelOptions extends IPanelOptions { + actionRunner?: IActionRunner; +} + +export abstract class ViewletPanel extends Panel { + + private _onDidFocus = new Emitter(); + readonly onDidFocus: Event = this._onDidFocus.event; + + protected actionRunner: IActionRunner; + protected toolbar: ToolBar; + + constructor( + readonly title: string, + options: IViewletPanelOptions, + @IKeybindingService protected keybindingService: IKeybindingService, + @IContextMenuService protected contextMenuService: IContextMenuService + ) { + super(options); + + this.actionRunner = options.actionRunner; + } + + render(container: HTMLElement): void { + super.render(container); + + const focusTracker = trackFocus(container); + this.disposables.push(focusTracker); + this.disposables.push(focusTracker.addFocusListener(() => this._onDidFocus.fire())); + } + + protected renderHeader(container: HTMLElement): void { + this.renderHeaderTitle(container); + + const actions = append(container, $('.actions')); + this.toolbar = new ToolBar(actions, this.contextMenuService, { + orientation: ActionsOrientation.HORIZONTAL, + actionItemProvider: action => this.getActionItem(action), + ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.title), + getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), + actionRunner: this.actionRunner + }); + + this.disposables.push(this.toolbar); + this.updateActions(); + } + + protected renderHeaderTitle(container: HTMLElement): void { + append(container, $('.title', null, this.title)); + } + + focus(): void { + this._onDidFocus.fire(); + } + + protected updateActions(): void { + this.toolbar.setActions(prepareActions(this.getActions()), prepareActions(this.getSecondaryActions()))(); + this.toolbar.context = this.getActionsContext(); + } + + getActions(): IAction[] { + return []; + } + + getSecondaryActions(): IAction[] { + return []; + } + + getActionItem(action: IAction): IActionItem { + return null; + } + + getActionsContext(): any { + return undefined; + } + + getOptimalWidth(): number { + return 0; + } +} + +export interface IViewsViewletOptions extends IPanelViewOptions { + showHeaderInTitleWhenSingleView: boolean; +} + +interface IViewletPanelItem { + panel: ViewletPanel; + disposable: IDisposable; +} + +export class PanelViewlet extends Viewlet { + + protected lastFocusedPanel: ViewletPanel | undefined; + private panelItems: IViewletPanelItem[] = []; + private panelview: PanelView; + + get onDidSashChange(): Event { + return this.panelview.onDidSashChange; + } + + protected get length(): number { + return this.panelItems.length; + } + + constructor( + id: string, + private options: IViewsViewletOptions, + @ITelemetryService telemetryService: ITelemetryService, + @IThemeService themeService: IThemeService + ) { + super(id, telemetryService, themeService); + } + + async create(parent: Builder): TPromise { + super.create(parent); + + const container = parent.getHTMLElement(); + this.panelview = this._register(new PanelView(container, this.options)); + this.panelview.onDidDrop(({ from, to }) => this.movePanel(from as ViewletPanel, to as ViewletPanel)); + } + + getTitle(): string { + let title = Registry.as(Extensions.Viewlets).getViewlet(this.getId()).name; + + if (this.isSingleView()) { + title += ': ' + this.panelItems[0].panel.title; + } + + return title; + } + + getActions(): IAction[] { + if (this.isSingleView()) { + return this.panelItems[0].panel.getActions(); + } + + return []; + } + + getSecondaryActions(): IAction[] { + if (this.isSingleView()) { + return this.panelItems[0].panel.getSecondaryActions(); + } + + return []; + } + + focus(): void { + super.focus(); + + if (this.lastFocusedPanel) { + this.lastFocusedPanel.focus(); + } else if (this.panelItems.length > 0) { + this.panelItems[0].panel.focus(); + } + } + + layout(dimension: Dimension): void { + this.panelview.layout(dimension.height); + } + + getOptimalWidth(): number { + const sizes = this.panelItems + .map(panelItem => panelItem.panel.getOptimalWidth() || 0); + + return Math.max(...sizes); + } + + addPanel(panel: ViewletPanel, size: number, index = this.panelItems.length - 1): void { + const disposables: IDisposable[] = []; + const onDidFocus = panel.onDidFocus(() => this.lastFocusedPanel = panel, null, disposables); + const styler = attachPanelStyler(panel, this.themeService); + const disposable = combinedDisposable([onDidFocus, styler]); + const panelItem: IViewletPanelItem = { panel, disposable }; + + this.panelItems.splice(index, 0, panelItem); + this.panelview.addPanel(panel, size, index); + + this.updateViewHeaders(); + this.updateTitleArea(); + } + + removePanel(panel: ViewletPanel): void { + const index = firstIndex(this.panelItems, i => i.panel === panel); + + if (index === -1) { + return; + } + + if (this.lastFocusedPanel === panel) { + this.lastFocusedPanel = undefined; + } + + this.panelview.removePanel(panel); + const [panelItem] = this.panelItems.splice(index, 1); + panelItem.disposable.dispose(); + + this.updateViewHeaders(); + this.updateTitleArea(); + } + + movePanel(from: ViewletPanel, to: ViewletPanel): void { + const fromIndex = firstIndex(this.panelItems, item => item.panel === from); + const toIndex = firstIndex(this.panelItems, item => item.panel === to); + + if (fromIndex < 0 || fromIndex >= this.panelItems.length) { + return; + } + + if (toIndex < 0 || toIndex >= this.panelItems.length) { + return; + } + + const [panelItem] = this.panelItems.splice(fromIndex, 1); + this.panelItems.splice(toIndex, 0, panelItem); + + this.panelview.movePanel(from, to); + } + + resizePanel(panel: ViewletPanel, size: number): void { + this.panelview.resizePanel(panel, size); + } + + getPanelSize(panel: ViewletPanel): number { + return this.panelview.getPanelSize(panel); + } + + protected updateViewHeaders(): void { + if (this.isSingleView()) { + this.panelItems[0].panel.setExpanded(true); + this.panelItems[0].panel.headerVisible = false; + } else { + this.panelItems.forEach(i => i.panel.headerVisible = true); + } + } + + protected isSingleView(): boolean { + return this.options.showHeaderInTitleWhenSingleView && this.panelItems.length === 1; + } + + dispose(): void { + super.dispose(); + this.panelItems.forEach(i => i.disposable.dispose()); + this.panelview.dispose(); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/views/browser/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts similarity index 91% rename from src/vs/workbench/parts/views/browser/treeView.ts rename to src/vs/workbench/browser/parts/views/treeView.ts index 2ae8d3e7a21..ba88ed44156 100644 --- a/src/vs/workbench/parts/views/browser/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -25,14 +25,13 @@ import { IProgressService } from 'vs/platform/progress/common/progress'; import { ITree, IDataSource, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ViewsRegistry } from 'vs/workbench/parts/views/browser/viewsRegistry'; -import { ITreeViewDataProvider, ITreeItem, TreeItemCollapsibleState, TreeViewItemHandleArg } from 'vs/workbench/parts/views/common/views'; +import { ViewsRegistry } from 'vs/workbench/browser/parts/views/viewsRegistry'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { CollapsibleState, ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; -import { CollapsibleView, IViewletViewOptions, IViewOptions } from 'vs/workbench/parts/views/browser/views'; +import { ViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { ICommandService } from 'vs/platform/commands/common/commands'; +import { TreeItemCollapsibleState, ITreeItem, ITreeViewDataProvider, TreeViewItemHandleArg } from 'vs/workbench/common/views'; -export class TreeView extends CollapsibleView { +export class TreeView extends ViewsViewletPanel { private menus: Menus; private viewFocusContext: IContextKey; @@ -40,11 +39,9 @@ export class TreeView extends CollapsibleView { private treeInputPromise: TPromise; private dataProviderElementChangeListener: IDisposable; - private disposables: IDisposable[] = []; constructor( - initialSize: number, - private options: IViewletViewOptions, + options: IViewletViewOptions, @IMessageService private messageService: IMessageService, @IKeybindingService keybindingService: IKeybindingService, @IContextMenuService contextMenuService: IContextMenuService, @@ -55,22 +52,16 @@ export class TreeView extends CollapsibleView { @IExtensionService private extensionService: IExtensionService, @ICommandService private commandService: ICommandService ) { - super(initialSize, { ...(options as IViewOptions), ariaHeaderLabel: options.name, sizing: ViewSizing.Flexible, collapsed: options.collapsed === void 0 ? true : options.collapsed }, keybindingService, contextMenuService); + super({ ...(options as IViewOptions), ariaHeaderLabel: options.name }, keybindingService, contextMenuService); this.menus = this.instantiationService.createInstance(Menus, this.id); this.viewFocusContext = this.contextKeyService.createKey(this.id, void 0); this.menus.onDidChangeTitle(() => this.updateActions(), this, this.disposables); this.themeService.onThemeChange(() => this.tree.refresh() /* soft refresh */, this, this.disposables); - if (!options.collapsed) { + if (options.expanded) { this.activate(); } } - public renderHeader(container: HTMLElement): void { - const titleDiv = $('div.title').appendTo(container); - $('span').text(this.options.name).appendTo(titleDiv); - super.renderHeader(container); - } - public renderBody(container: HTMLElement): void { this.treeContainer = super.renderViewTree(container); DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); @@ -79,9 +70,10 @@ export class TreeView extends CollapsibleView { this.setInput(); } - protected changeState(state: CollapsibleState): void { - super.changeState(state); - if (state === CollapsibleState.EXPANDED) { + setExpanded(expanded: boolean): void { + super.setExpanded(expanded); + + if (expanded) { this.activate(); } } @@ -106,8 +98,8 @@ export class TreeView extends CollapsibleView { keyboardSupport: false }); - this.toDispose.push(attachListStyler(tree, this.themeService)); - this.toDispose.push(this.listService.register(tree, [this.viewFocusContext])); + this.disposables.push(attachListStyler(tree, this.themeService)); + this.disposables.push(this.listService.register(tree, [this.viewFocusContext])); tree.addListener('selection', (event: any) => this.onSelection()); return tree; } @@ -328,7 +320,7 @@ class TreeController extends DefaultController { if (!actions.length) { return true; } - const anchor = { x: event.posx + 1, y: event.posy }; + const anchor = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, diff --git a/src/vs/workbench/parts/views/browser/viewsRegistry.ts b/src/vs/workbench/browser/parts/views/viewsRegistry.ts similarity index 87% rename from src/vs/workbench/parts/views/browser/viewsRegistry.ts rename to src/vs/workbench/browser/parts/views/viewsRegistry.ts index 5dbfc762d5e..b5c6f618b02 100644 --- a/src/vs/workbench/parts/views/browser/viewsRegistry.ts +++ b/src/vs/workbench/browser/parts/views/viewsRegistry.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import Event, { Emitter } from 'vs/base/common/event'; -import { IViewConstructorSignature } from 'vs/workbench/parts/views/browser/views'; -import { ITreeViewDataProvider } from 'vs/workbench/parts/views/common/views'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ITreeViewDataProvider } from 'vs/workbench/common/views'; +import { localize } from 'vs/nls'; export class ViewLocation { @@ -39,7 +39,8 @@ export interface IViewDescriptor { readonly location: ViewLocation; - readonly ctor: IViewConstructorSignature; + // TODO do we really need this?! + readonly ctor: any; readonly when?: ContextKeyExpr; @@ -47,6 +48,8 @@ export interface IViewDescriptor { readonly size?: number; + readonly collapsed?: boolean; + readonly canToggleVisibility?: boolean; } @@ -94,6 +97,9 @@ export const ViewsRegistry: IViewsRegistry = new class { views = []; this._views.set(viewDescriptor.location, views); } + if (views.some(v => v.id === viewDescriptor.id)) { + throw new Error(localize('duplicateId', "A view with id `{0}` is already registered in the location `{1}`", viewDescriptor.id, viewDescriptor.location.id)); + } views.push(viewDescriptor); } this._onViewsRegistered.fire(viewDescriptors); @@ -116,8 +122,8 @@ export const ViewsRegistry: IViewsRegistry = new class { this._onViewsDeregistered.fire(viewsToDeregister); } - registerTreeViewDataProvider(id: string, factory: ITreeViewDataProvider) { - if (!this.isViewRegistered(id)) { + registerTreeViewDataProvider(id: string, factory: ITreeViewDataProvider) { + if (!this.isDataProviderRegistered(id)) { // TODO: throw error } this._treeViewDataPoviders.set(id, factory); @@ -136,9 +142,9 @@ export const ViewsRegistry: IViewsRegistry = new class { return this._treeViewDataPoviders.get(id); } - private isViewRegistered(id: string): boolean { + private isDataProviderRegistered(id: string): boolean { let registered = false; this._views.forEach(views => registered = registered || views.some(view => view.id === id)); return registered; } -}; \ No newline at end of file +}; diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts new file mode 100644 index 00000000000..3319af932d4 --- /dev/null +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -0,0 +1,653 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { TPromise } from 'vs/base/common/winjs.base'; +import * as errors from 'vs/base/common/errors'; +import * as DOM from 'vs/base/browser/dom'; +import { $, Dimension, Builder } from 'vs/base/browser/builder'; +import { Scope } from 'vs/workbench/common/memento'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IAction, IActionRunner } from 'vs/base/common/actions'; +import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ITree } from 'vs/base/parts/tree/browser/tree'; +import { firstIndex } from 'vs/base/common/arrays'; +import { DelayedDragHandler } from 'vs/base/browser/dnd'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/browser/parts/views/viewsRegistry'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { PanelViewlet, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; +import { IPanelOptions } from 'vs/base/browser/ui/splitview/panelview'; + +export interface IViewOptions extends IPanelOptions { + id: string; + name: string; + actionRunner: IActionRunner; +} + +export interface IViewConstructorSignature { + new(options: IViewOptions, ...services: { _serviceBrand: any; }[]): T; +} + +export abstract class ViewsViewletPanel extends ViewletPanel { + + readonly id: string; + readonly name: string; + protected treeContainer: HTMLElement; + + // TODO@sandeep why is tree here? isn't this coming only from TreeView + protected tree: ITree; + protected isDisposed: boolean; + private _isVisible: boolean; + private dragHandler: DelayedDragHandler; + + constructor( + options: IViewOptions, + protected keybindingService: IKeybindingService, + protected contextMenuService: IContextMenuService + ) { + super(options.name, options, keybindingService, contextMenuService); + + this.id = options.id; + this.name = options.name; + this._expanded = options.expanded; + } + + setExpanded(expanded: boolean): void { + this.updateTreeVisibility(this.tree, expanded); + super.setExpanded(expanded); + } + + protected renderHeader(container: HTMLElement): void { + super.renderHeader(container); + + // Expand on drag over + this.dragHandler = new DelayedDragHandler(container, () => this.setExpanded(true)); + } + + protected renderViewTree(container: HTMLElement): HTMLElement { + const treeContainer = document.createElement('div'); + container.appendChild(treeContainer); + return treeContainer; + } + + getViewer(): ITree { + return this.tree; + } + + isVisible(): boolean { + return this._isVisible; + } + + setVisible(visible: boolean): TPromise { + if (this._isVisible !== visible) { + this._isVisible = visible; + this.updateTreeVisibility(this.tree, visible && this.isExpanded()); + } + + return TPromise.as(null); + } + + focus(): void { + super.focus(); + this.focusTree(); + } + + protected reveal(element: any, relativeTop?: number): TPromise { + if (!this.tree) { + return TPromise.as(null); // return early if viewlet has not yet been created + } + + return this.tree.reveal(element, relativeTop); + } + + layoutBody(size: number): void { + if (this.tree) { + this.treeContainer.style.height = size + 'px'; + this.tree.layout(size); + } + } + + getActions(): IAction[] { + return []; + } + + getSecondaryActions(): IAction[] { + return []; + } + + getActionItem(action: IAction): IActionItem { + return null; + } + + getActionsContext(): any { + return undefined; + } + + getOptimalWidth(): number { + return 0; + } + + create(): TPromise { + return TPromise.as(null); + } + + shutdown(): void { + // Subclass to implement + } + + dispose(): void { + this.isDisposed = true; + this.treeContainer = null; + + if (this.tree) { + this.tree.dispose(); + } + + if (this.dragHandler) { + this.dragHandler.dispose(); + } + + super.dispose(); + } + + private updateTreeVisibility(tree: ITree, isVisible: boolean): void { + if (!tree) { + return; + } + + if (isVisible) { + $(tree.getHTMLElement()).show(); + } else { + $(tree.getHTMLElement()).hide(); // make sure the tree goes out of the tabindex world by hiding it + } + + if (isVisible) { + tree.onVisible(); + } else { + tree.onHidden(); + } + } + + private focusTree(): void { + if (!this.tree) { + return; // return early if viewlet has not yet been created + } + + // Make sure the current selected element is revealed + const selection = this.tree.getSelection(); + if (selection.length > 0) { + this.reveal(selection[0], 0.5).done(null, errors.onUnexpectedError); + } + + // Pass Focus to Viewer + this.tree.DOMFocus(); + } +} + +export interface IViewletViewOptions extends IViewOptions { + viewletSettings: object; +} + +export interface IViewState { + collapsed: boolean; + size: number | undefined; + isHidden: boolean; + order: number; +} + +export class ViewsViewlet extends PanelViewlet { + + private viewHeaderContextMenuListeners: IDisposable[] = []; + private viewletSettings: object; + private readonly viewsContextKeys: Set = new Set(); + private viewsViewletPanels: ViewsViewletPanel[] = []; + private didLayout = false; + protected viewsStates: Map = new Map(); + private areExtensionsReady: boolean = false; + + constructor( + id: string, + private location: ViewLocation, + private showHeaderInTitleWhenSingleView: boolean, + @ITelemetryService telemetryService: ITelemetryService, + @IStorageService protected storageService: IStorageService, + @IInstantiationService protected instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService, + @IContextKeyService protected contextKeyService: IContextKeyService, + @IContextMenuService protected contextMenuService: IContextMenuService, + @IExtensionService protected extensionService: IExtensionService + ) { + super(id, { showHeaderInTitleWhenSingleView, dnd: true }, telemetryService, themeService); + + this.viewletSettings = this.getMemento(storageService, Scope.WORKSPACE); + } + + async create(parent: Builder): TPromise { + await super.create(parent); + + this._register(this.onDidSashChange(() => this.updateAllViewsSizes())); + this._register(ViewsRegistry.onViewsRegistered(this.onViewsRegistered, this)); + this._register(ViewsRegistry.onViewsDeregistered(this.onViewsDeregistered, this)); + this._register(this.contextKeyService.onDidChangeContext(keys => this.onContextChanged(keys))); + + // Update headers after and title contributed views after available, since we read from cache in the beginning to know if the viewlet has single view or not. Ref #29609 + this.extensionService.onReady().then(() => { + this.areExtensionsReady = true; + this.updateHeaders(); + }); + + this.onViewsRegistered(ViewsRegistry.getViews(this.location)); + this.focus(); + } + + getContextMenuActions(): IAction[] { + return this.getViewDescriptorsFromRegistry(true) + .filter(viewDescriptor => viewDescriptor.canToggleVisibility && this.contextKeyService.contextMatchesRules(viewDescriptor.when)) + .map(viewDescriptor => ({ + id: `${viewDescriptor.id}.toggleVisibility`, + label: viewDescriptor.name, + checked: this.isCurrentlyVisible(viewDescriptor), + enabled: true, + run: () => this.toggleViewVisibility(viewDescriptor.id) + })); + } + + setVisible(visible: boolean): TPromise { + return super.setVisible(visible) + .then(() => TPromise.join(this.viewsViewletPanels.filter(view => view.isVisible() !== visible) + .map((view) => view.setVisible(visible)))) + .then(() => void 0); + } + + layout(dimension: Dimension): void { + super.layout(dimension); + + if (!this.didLayout) { + this.didLayout = true; + this._resizePanels(); + } + + this.updateAllViewsSizes(); + } + + getOptimalWidth(): number { + const additionalMargin = 16; + const optimalWidth = Math.max(...this.viewsViewletPanels.map(view => view.getOptimalWidth() || 0)); + return optimalWidth + additionalMargin; + } + + shutdown(): void { + this.viewsViewletPanels.forEach((view) => view.shutdown()); + super.shutdown(); + } + + toggleViewVisibility(id: string, visible?: boolean): void { + const view = this.getView(id); + let viewState = this.viewsStates.get(id); + + if ((visible === true && view) || (visible === false && !view)) { + return; + } + + if (view) { + viewState = viewState || this.createViewState(view); + viewState.isHidden = true; + } else { + viewState = viewState || { collapsed: true, size: void 0, isHidden: false, order: void 0 }; + viewState.isHidden = false; + } + this.viewsStates.set(id, viewState); + this.updateViews(); + } + + private onViewsRegistered(views: IViewDescriptor[]): TPromise { + this.viewsContextKeys.clear(); + for (const viewDescriptor of this.getViewDescriptorsFromRegistry()) { + if (viewDescriptor.when) { + for (const key of viewDescriptor.when.keys()) { + this.viewsContextKeys.add(key); + } + } + } + + return this.updateViews(); + } + + private onViewsDeregistered(views: IViewDescriptor[]): TPromise { + return this.updateViews(views); + } + + private onContextChanged(keys: string[]): void { + if (!keys) { + return; + } + + let hasToUpdate: boolean = false; + for (const key of keys) { + if (this.viewsContextKeys.has(key)) { + hasToUpdate = true; + break; + } + } + + if (hasToUpdate) { + this.updateViews(); + } + } + + protected updateViews(unregisteredViews: IViewDescriptor[] = []): TPromise { + const registeredViews = this.getViewDescriptorsFromRegistry(); + const [visible, toAdd, toRemove] = registeredViews.reduce<[IViewDescriptor[], IViewDescriptor[], IViewDescriptor[]]>((result, viewDescriptor) => { + const isCurrentlyVisible = this.isCurrentlyVisible(viewDescriptor); + const canBeVisible = this.canBeVisible(viewDescriptor); + + if (canBeVisible) { + result[0].push(viewDescriptor); + } + + if (!isCurrentlyVisible && canBeVisible) { + result[1].push(viewDescriptor); + } + + if (isCurrentlyVisible && !canBeVisible) { + result[2].push(viewDescriptor); + } + + return result; + + }, [[], [], []]); + + toRemove.push(...unregisteredViews.filter(viewDescriptor => this.isCurrentlyVisible(viewDescriptor))); + + const toCreate: ViewsViewletPanel[] = []; + + if (toAdd.length || toRemove.length) { + const panels = [...this.viewsViewletPanels]; + + for (const view of panels) { + let viewState = this.viewsStates.get(view.id); + if (!viewState || typeof viewState.size === 'undefined' || !view.isExpanded() !== viewState.collapsed) { + viewState = this.updateViewStateSize(view); + this.viewsStates.set(view.id, viewState); + } + } + + if (toRemove.length) { + for (const viewDescriptor of toRemove) { + let view = this.getView(viewDescriptor.id); + const viewState = this.updateViewStateSize(view); + this.viewsStates.set(view.id, viewState); + this.removePanel(view); + this.viewsViewletPanels.splice(this.viewsViewletPanels.indexOf(view), 1); + } + } + + for (const viewDescriptor of toAdd) { + let viewState = this.viewsStates.get(viewDescriptor.id); + let index = visible.indexOf(viewDescriptor); + const view = this.createView(viewDescriptor, + { + id: viewDescriptor.id, + name: viewDescriptor.name, + actionRunner: this.getActionRunner(), + expanded: !(viewState ? viewState.collapsed : viewDescriptor.collapsed), + viewletSettings: this.viewletSettings + }); + toCreate.push(view); + + const size = (viewState && viewState.size) || viewDescriptor.size || 200; + this.addPanel(view, size, index); + this.viewsViewletPanels.splice(index, 0, view); + + this.viewsStates.set(view.id, this.updateViewStateSize(view)); + } + + return TPromise.join(toCreate.map(view => view.create())) + .then(() => this.onViewsUpdated()) + .then(() => this._resizePanels()) + .then(() => toCreate); + } + + return TPromise.as([]); + } + + private updateAllViewsSizes(): void { + for (const view of this.viewsViewletPanels) { + let viewState = this.updateViewStateSize(view); + this.viewsStates.set(view.id, viewState); + } + } + + private _resizePanels(): void { + if (!this.didLayout) { + return; + } + + for (const panel of this.viewsViewletPanels) { + const viewState = this.viewsStates.get(panel.id); + const size = (viewState && viewState.size) || 200; + this.resizePanel(panel, size); + } + } + + movePanel(from: ViewletPanel, to: ViewletPanel): void { + const fromIndex = firstIndex(this.viewsViewletPanels, panel => panel === from); + const toIndex = firstIndex(this.viewsViewletPanels, panel => panel === to); + + if (fromIndex < 0 || fromIndex >= this.viewsViewletPanels.length) { + return; + } + + if (toIndex < 0 || toIndex >= this.viewsViewletPanels.length) { + return; + } + + super.movePanel(from, to); + + const [panel] = this.viewsViewletPanels.splice(fromIndex, 1); + this.viewsViewletPanels.splice(toIndex, 0, panel); + + for (let order = 0; order < this.viewsViewletPanels.length; order++) { + const view = this.viewsStates.get(this.viewsViewletPanels[order].id); + + if (!view) { + continue; + } + + view.order = order; + } + } + + protected getDefaultViewSize(): number | undefined { + return undefined; + } + + private isCurrentlyVisible(viewDescriptor: IViewDescriptor): boolean { + return !!this.getView(viewDescriptor.id); + } + + private canBeVisible(viewDescriptor: IViewDescriptor): boolean { + const viewstate = this.viewsStates.get(viewDescriptor.id); + if (viewDescriptor.canToggleVisibility && viewstate && viewstate.isHidden) { + return false; + } + return this.contextKeyService.contextMatchesRules(viewDescriptor.when); + } + + private onViewsUpdated(): TPromise { + this.viewHeaderContextMenuListeners = dispose(this.viewHeaderContextMenuListeners); + + for (const viewDescriptor of this.getViewDescriptorsFromRegistry()) { + const view = this.getView(viewDescriptor.id); + + if (view) { + this.viewHeaderContextMenuListeners.push(DOM.addDisposableListener(view.draggableElement, DOM.EventType.CONTEXT_MENU, e => { + e.stopPropagation(); + e.preventDefault(); + if (viewDescriptor.canToggleVisibility) { + this.onContextMenu(new StandardMouseEvent(e), view); + } + })); + } + } + + return this.setVisible(this.isVisible()); + } + + private updateHeaders(): void { + if (this.viewsViewletPanels.length) { + this.updateTitleArea(); + this.updateViewHeaders(); + } + } + + private onContextMenu(event: StandardMouseEvent, view: ViewsViewletPanel): void { + event.stopPropagation(); + event.preventDefault(); + + let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; + this.contextMenuService.showContextMenu({ + getAnchor: () => anchor, + getActions: () => TPromise.as([{ + id: `${view.id}.removeView`, + label: nls.localize('hideView', "Hide from Side Bar"), + enabled: true, + run: () => this.toggleViewVisibility(view.id) + }]), + }); + } + + protected isSingleView(): boolean { + if (!this.showHeaderInTitleWhenSingleView) { + return false; + } + if (this.getViewDescriptorsFromRegistry().length === 0) { + return false; + } + if (this.length > 1) { + return false; + } + // Check in cache so that view do not jump. See #29609 + if (ViewLocation.getContributedViewLocation(this.location.id) && !this.areExtensionsReady) { + let visibleViewsCount = 0; + this.viewsStates.forEach((viewState, id) => { + if (!viewState.isHidden) { + visibleViewsCount++; + } + }); + return visibleViewsCount === 1; + } + return super.isSingleView(); + } + + protected getViewDescriptorsFromRegistry(defaultOrder: boolean = false): IViewDescriptor[] { + return ViewsRegistry.getViews(this.location) + .sort((a, b) => { + const viewStateA = this.viewsStates.get(a.id); + const viewStateB = this.viewsStates.get(b.id); + const orderA = !defaultOrder && viewStateA ? viewStateA.order : a.order; + const orderB = !defaultOrder && viewStateB ? viewStateB.order : b.order; + + if (orderB === void 0 || orderB === null) { + return -1; + } + if (orderA === void 0 || orderA === null) { + return 1; + } + + return orderA - orderB; + }); + } + + protected createView(viewDescriptor: IViewDescriptor, options: IViewletViewOptions): ViewsViewletPanel { + return this.instantiationService.createInstance(viewDescriptor.ctor, options); + } + + protected get views(): ViewsViewletPanel[] { + return this.viewsViewletPanels; + } + + protected getView(id: string): ViewsViewletPanel { + return this.viewsViewletPanels.filter(view => view.id === id)[0]; + } + + private updateViewStateSize(view: ViewsViewletPanel): IViewState { + const currentState = this.viewsStates.get(view.id); + const newViewState = this.createViewState(view); + return currentState ? { ...currentState, collapsed: newViewState.collapsed, size: newViewState.size } : newViewState; + } + + protected createViewState(view: ViewsViewletPanel): IViewState { + return { + collapsed: !view.isExpanded(), + size: this.getPanelSize(view), + isHidden: false, + order: this.viewsViewletPanels.indexOf(view) + }; + } +} + +export class PersistentViewsViewlet extends ViewsViewlet { + + constructor( + id: string, + location: ViewLocation, + private viewletStateStorageId: string, + showHeaderInTitleWhenSingleView: boolean, + @ITelemetryService telemetryService: ITelemetryService, + @IStorageService storageService: IStorageService, + @IInstantiationService instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService, + @IWorkspaceContextService protected contextService: IWorkspaceContextService, + @IContextKeyService contextKeyService: IContextKeyService, + @IContextMenuService contextMenuService: IContextMenuService, + @IExtensionService extensionService: IExtensionService + ) { + super(id, location, showHeaderInTitleWhenSingleView, telemetryService, storageService, instantiationService, themeService, contextKeyService, contextMenuService, extensionService); + } + + create(parent: Builder): TPromise { + this.loadViewsStates(); + return super.create(parent); + } + + shutdown(): void { + this.saveViewsStates(); + super.shutdown(); + } + + protected saveViewsStates(): void { + const viewsStates = {}; + const registeredViewDescriptors = this.getViewDescriptorsFromRegistry(); + this.viewsStates.forEach((viewState, id) => { + const view = this.getView(id); + + if (view) { + viewsStates[id] = this.createViewState(view); + } else { + const viewDescriptor = registeredViewDescriptors.filter(v => v.id === id)[0]; + if (viewDescriptor) { + viewsStates[id] = viewState; + } + } + }); + + this.storageService.store(this.viewletStateStorageId, JSON.stringify(viewsStates), this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL); + } + + protected loadViewsStates(): void { + const viewsStates = JSON.parse(this.storageService.get(this.viewletStateStorageId, this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL, '{}')); + Object.keys(viewsStates).forEach(id => this.viewsStates.set(id, viewsStates[id])); + } +} \ No newline at end of file diff --git a/src/vs/workbench/browser/quickopen.ts b/src/vs/workbench/browser/quickopen.ts index f64144d4acc..7921f37fff7 100644 --- a/src/vs/workbench/browser/quickopen.ts +++ b/src/vs/workbench/browser/quickopen.ts @@ -15,18 +15,17 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { KeyMod } from 'vs/base/common/keyCodes'; import { Mode, IEntryRunContext, IAutoFocus, IModel, IQuickNavigateConfiguration } from 'vs/base/parts/quickopen/common/quickOpen'; -import { QuickOpenEntry, IHighlight, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; +import { QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { EditorOptions, EditorInput } from 'vs/workbench/common/editor'; import { IResourceInput, IEditorInput, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; -import { AsyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; + +export const CLOSE_ON_FOCUS_LOST_CONFIG = 'workbench.quickOpen.closeOnFocusLost'; export interface IWorkbenchQuickOpenConfiguration { workbench: { - quickOpen: { - closeOnFocusLost: boolean; - }, commandPalette: { history: number; preserveInput: boolean; @@ -128,7 +127,7 @@ export interface QuickOpenHandlerHelpEntry { /** * A lightweight descriptor of a quick open handler. */ -export class QuickOpenHandlerDescriptor extends AsyncDescriptor { +export class QuickOpenHandlerDescriptor { public prefix: string; public description: string; public contextKey: string; @@ -137,13 +136,13 @@ export class QuickOpenHandlerDescriptor extends AsyncDescriptor; - constructor(moduleId: string, ctorName: string, prefix: string, contextKey: string, description: string, instantProgress?: boolean); - constructor(moduleId: string, ctorName: string, prefix: string, contextKey: string, helpEntries: QuickOpenHandlerHelpEntry[], instantProgress?: boolean); - constructor(moduleId: string, ctorName: string, prefix: string, contextKey: string, param: any, instantProgress: boolean = false) { - super(moduleId, ctorName); - - this.id = moduleId + ctorName; + constructor(ctor: IConstructorSignature0, id: string, prefix: string, contextKey: string, description: string, instantProgress?: boolean); + constructor(ctor: IConstructorSignature0, id: string, prefix: string, contextKey: string, helpEntries: QuickOpenHandlerHelpEntry[], instantProgress?: boolean); + constructor(ctor: IConstructorSignature0, id: string, prefix: string, contextKey: string, param: any, instantProgress: boolean = false) { + this.ctor = ctor; + this.id = id; this.prefix = prefix; this.contextKey = contextKey; this.instantProgress = instantProgress; @@ -158,6 +157,10 @@ export class QuickOpenHandlerDescriptor extends AsyncDescriptor { constructor( - moduleId: string, - ctorName: string, + ctor: IConstructorSignature0, id: string, name: string, cssClass?: string, order?: number, private _extensionId?: string ) { - super(moduleId, ctorName, id, name, cssClass, order); - - if (_extensionId) { - this.appendStaticArguments([id]); // Pass viewletId to external viewlet, which doesn't know its id until runtime. - } + super(ctor, id, name, cssClass, order, id); } public get extensionId(): string { diff --git a/src/vs/workbench/common/actionRegistry.ts b/src/vs/workbench/common/actionRegistry.ts deleted file mode 100644 index a0bf5f60f84..00000000000 --- a/src/vs/workbench/common/actionRegistry.ts +++ /dev/null @@ -1,191 +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 { TPromise } from 'vs/base/common/winjs.base'; -import collections = require('vs/base/common/collections'); -import { Registry } from 'vs/platform/registry/common/platform'; -import { IAction } from 'vs/base/common/actions'; -import { KeybindingsRegistry, ICommandAndKeybindingRule } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { ICommandHandler } from 'vs/platform/commands/common/commands'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import Severity from 'vs/base/common/severity'; - -export const Extensions = { - WorkbenchActions: 'workbench.contributions.actions' -}; - -export interface IActionProvider { - getActions(): IAction[]; -} - -export interface IWorkbenchActionRegistry { - - /** - * Registers a workbench action to the platform. Workbench actions are not - * visible by default and can only be invoked through a keybinding if provided. - */ - registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): void; - - /** - * Unregisters a workbench action from the platform. - */ - unregisterWorkbenchAction(id: string): boolean; - - /** - * Returns the workbench action descriptor for the given id or null if none. - */ - getWorkbenchAction(id: string): SyncActionDescriptor; - - /** - * Returns an array of registered workbench actions known to the platform. - */ - getWorkbenchActions(): SyncActionDescriptor[]; - - /** - * Returns the alias associated with the given action or null if none. - */ - getAlias(actionId: string): string; - - /** - * Returns the category for the given action or null if none. - */ - getCategory(actionId: string): string; -} - -interface IActionMeta { - alias: string; - category?: string; -} - -class WorkbenchActionRegistry implements IWorkbenchActionRegistry { - private workbenchActions: collections.IStringDictionary; - private mapActionIdToMeta: { [id: string]: IActionMeta; }; - - constructor() { - this.workbenchActions = Object.create(null); - this.mapActionIdToMeta = Object.create(null); - } - - public registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): void { - if (!this.workbenchActions[descriptor.id]) { - this.workbenchActions[descriptor.id] = descriptor; - registerWorkbenchCommandFromAction(descriptor); - - let meta: IActionMeta = { alias }; - if (typeof category === 'string') { - meta.category = category; - } - - this.mapActionIdToMeta[descriptor.id] = meta; - } - } - - public unregisterWorkbenchAction(id: string): boolean { - if (!this.workbenchActions[id]) { - return false; - } - - delete this.workbenchActions[id]; - delete this.mapActionIdToMeta[id]; - - return true; - } - - public getWorkbenchAction(id: string): SyncActionDescriptor { - return this.workbenchActions[id] || null; - } - - public getCategory(id: string): string { - return (this.mapActionIdToMeta[id] && this.mapActionIdToMeta[id].category) || null; - } - - public getAlias(id: string): string { - return (this.mapActionIdToMeta[id] && this.mapActionIdToMeta[id].alias) || null; - } - - public getWorkbenchActions(): SyncActionDescriptor[] { - return collections.values(this.workbenchActions); - } - - public setWorkbenchActions(actions: SyncActionDescriptor[]): void { - this.workbenchActions = Object.create(null); - this.mapActionIdToMeta = Object.create(null); - - actions.forEach(action => this.registerWorkbenchAction(action, ''), this); - } -} - -Registry.add(Extensions.WorkbenchActions, new WorkbenchActionRegistry()); - -function registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor): void { - let when = descriptor.keybindingContext; - let weight = (typeof descriptor.keybindingWeight === 'undefined' ? KeybindingsRegistry.WEIGHT.workbenchContrib() : descriptor.keybindingWeight); - let keybindings = descriptor.keybindings; - - let desc: ICommandAndKeybindingRule = { - id: descriptor.id, - handler: createCommandHandler(descriptor), - weight: weight, - when: when, - primary: keybindings && keybindings.primary, - secondary: keybindings && keybindings.secondary, - win: keybindings && keybindings.win, - mac: keybindings && keybindings.mac, - linux: keybindings && keybindings.linux - }; - - KeybindingsRegistry.registerCommandAndKeybindingRule(desc); -} - -export function createCommandHandler(descriptor: SyncActionDescriptor): ICommandHandler { - return (accessor, args) => { - - let messageService = accessor.get(IMessageService); - let instantiationService = accessor.get(IInstantiationService); - let telemetryService = accessor.get(ITelemetryService); - let partService = accessor.get(IPartService); - - TPromise.as(triggerAndDisposeAction(instantiationService, telemetryService, partService, descriptor, args)).done(null, (err) => { - messageService.show(Severity.Error, err); - }); - }; -} - -export function triggerAndDisposeAction(instantitationService: IInstantiationService, telemetryService: ITelemetryService, partService: IPartService, descriptor: SyncActionDescriptor, args: any): TPromise { - let actionInstance = instantitationService.createInstance(descriptor.syncDescriptor); - actionInstance.label = descriptor.label || actionInstance.label; - - // don't run the action when not enabled - if (!actionInstance.enabled) { - actionInstance.dispose(); - - return void 0; - } - - const from = args && args.from || 'keybinding'; - if (telemetryService) { - telemetryService.publicLog('workbenchActionExecuted', { id: actionInstance.id, from }); - } - - // run action when workbench is created - return partService.joinCreation().then(() => { - try { - return TPromise.as(actionInstance.run(undefined, { from })).then(() => { - actionInstance.dispose(); - }, (err) => { - actionInstance.dispose(); - return TPromise.wrapError(err); - }); - } catch (err) { - actionInstance.dispose(); - return TPromise.wrapError(err); - } - }); -} diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts new file mode 100644 index 00000000000..100e65db4ec --- /dev/null +++ b/src/vs/workbench/common/actions.ts @@ -0,0 +1,126 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IAction } from 'vs/base/common/actions'; +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { IMessageService } from 'vs/platform/message/common/message'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import Severity from 'vs/base/common/severity'; +import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; + +export const Extensions = { + WorkbenchActions: 'workbench.contributions.actions' +}; + +export interface IActionProvider { + getActions(): IAction[]; +} + +export interface IWorkbenchActionRegistry { + + /** + * Registers a workbench action to the platform. Workbench actions are not + * visible by default and can only be invoked through a keybinding if provided. + */ + registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable; +} + +Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionRegistry { + + registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable { + return this._registerWorkbenchCommandFromAction(descriptor, alias, category); + } + + private _registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable { + let registrations: IDisposable[] = []; + + // command + registrations.push(CommandsRegistry.registerCommand(descriptor.id, this._createCommandHandler(descriptor))); + + // keybinding + const when = descriptor.keybindingContext; + const weight = (typeof descriptor.keybindingWeight === 'undefined' ? KeybindingsRegistry.WEIGHT.workbenchContrib() : descriptor.keybindingWeight); + const keybindings = descriptor.keybindings; + KeybindingsRegistry.registerKeybindingRule({ + id: descriptor.id, + weight: weight, + when: when, + primary: keybindings && keybindings.primary, + secondary: keybindings && keybindings.secondary, + win: keybindings && keybindings.win, + mac: keybindings && keybindings.mac, + linux: keybindings && keybindings.linux + }); + + // menu item + // TODO@Rob slightly weird if-check required because of + // https://github.com/Microsoft/vscode/blob/master/src/vs/workbench/parts/search/browser/search.contribution.ts#L266 + if (descriptor.label) { + + const command = { + id: descriptor.id, + title: { value: descriptor.label, original: alias }, + category + }; + + MenuRegistry.addCommand(command); + + registrations.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command })); + } + + // TODO@alex,joh + // support removal of keybinding rule + // support removal of command-ui + return combinedDisposable(registrations); + } + + private _createCommandHandler(descriptor: SyncActionDescriptor): ICommandHandler { + return (accessor, args) => { + const messageService = accessor.get(IMessageService); + const instantiationService = accessor.get(IInstantiationService); + const lifecycleService = accessor.get(ILifecycleService); + + TPromise.as(this._triggerAndDisposeAction(instantiationService, lifecycleService, descriptor, args)).then(null, (err) => { + messageService.show(Severity.Error, err); + }); + }; + } + + private _triggerAndDisposeAction(instantitationService: IInstantiationService, lifecycleService: ILifecycleService, descriptor: SyncActionDescriptor, args: any): Thenable { + const actionInstance = instantitationService.createInstance(descriptor.syncDescriptor); + actionInstance.label = descriptor.label || actionInstance.label; + + // don't run the action when not enabled + if (!actionInstance.enabled) { + actionInstance.dispose(); + + return void 0; + } + + const from = args && args.from || 'keybinding'; + + // run action when workbench is created + return lifecycleService.when(LifecyclePhase.Running).then(() => { + try { + return TPromise.as(actionInstance.run(undefined, { from })).then(() => { + actionInstance.dispose(); + }, (err) => { + actionInstance.dispose(); + return TPromise.wrapError(err); + }); + } catch (err) { + actionInstance.dispose(); + return TPromise.wrapError(err); + } + }); + } +}); + diff --git a/src/vs/workbench/browser/activity.ts b/src/vs/workbench/common/activity.ts similarity index 98% rename from src/vs/workbench/browser/activity.ts rename to src/vs/workbench/common/activity.ts index aff7d7553ab..9c5e0283b52 100644 --- a/src/vs/workbench/browser/activity.ts +++ b/src/vs/workbench/common/activity.ts @@ -10,6 +10,7 @@ import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instant export interface IActivity { id: string; name: string; + keybindingId?: string; cssClass: string; } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 0978319f3de..6ec676c9306 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -11,10 +11,10 @@ import types = require('vs/base/common/types'); import URI from 'vs/base/common/uri'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { IEditor, IEditorViewState, IModel, ScrollType } from 'vs/editor/common/editorCommon'; -import { IEditorInput, IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, Position, Verbosity } from 'vs/platform/editor/common/editor'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { IEditorInput, IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, Position, Verbosity, IEditor as IBaseEditor } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { Registry } from 'vs/platform/registry/common/platform'; export const TextCompareEditorVisible = new RawContextKey('textCompareEditorVisible', false); @@ -24,19 +24,6 @@ export enum ConfirmResult { CANCEL } -export interface IEditorDescriptor { - - getId(): string; - - getName(): string; - - describes(obj: any): boolean; -} - -export const Extensions = { - Editors: 'workbench.contributions.editors' -}; - /** * Text diff editor id. */ @@ -51,34 +38,7 @@ export interface IFileInputFactory { createFileInput(resource: URI, encoding: string, instantiationService: IInstantiationService): IFileEditorInput; } -export interface IEditorRegistry { - - /** - * Registers an editor to the platform for the given input type. The second parameter also supports an - * array of input classes to be passed in. If the more than one editor is registered for the same editor - * input, the input itself will be asked which editor it prefers if this method is provided. Otherwise - * the first editor in the list will be returned. - * - * @param editorInputDescriptor a constructor function that returns an instance of EditorInput for which the - * registered editor should be used for. - */ - registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor): void; - registerEditor(descriptor: IEditorDescriptor, editorInputDescriptor: SyncDescriptor[]): void; - - /** - * Returns the editor descriptor for the given input or null if none. - */ - getEditor(input: EditorInput): IEditorDescriptor; - - /** - * Returns the editor descriptor for the given identifier or null if none. - */ - getEditorById(editorId: string): IEditorDescriptor; - - /** - * Returns an array of registered editors known to the platform. - */ - getEditors(): IEditorDescriptor[]; +export interface IEditorInputFactoryRegistry { /** * Registers the file input factory to use for file inputs. @@ -164,6 +124,13 @@ export abstract class EditorInput implements IEditorInput { return this._onDispose.event; } + /** + * Returns the associated resource of this input if any. + */ + public getResource(): URI { + return null; + } + /** * Returns the name of this input that can be shown to the user. Examples include showing the name of the input * above the editor area when the input is shown. @@ -176,7 +143,7 @@ export abstract class EditorInput implements IEditorInput { * Returns the description of this input that can be shown to the user. Examples include showing the description of * the input above the editor area to the side of the name of the input. */ - public getDescription(): string { + public getDescription(verbosity?: Verbosity): string { return null; } @@ -207,6 +174,11 @@ export abstract class EditorInput implements IEditorInput { * Subclasses should extend if they can contribute. */ public getTelemetryDescriptor(): object { + /* __GDPR__FRAGMENT__ + "EditorTelemetryDescriptor" : { + "typeId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ return { typeId: this.getTypeId() }; } @@ -288,6 +260,48 @@ export abstract class EditorInput implements IEditorInput { } } +export interface IEditorOpeningEvent { + input: IEditorInput; + options?: IEditorOptions; + position: Position; + + /** + * Allows to prevent the opening of an editor by providing a callback + * that will be executed instead. By returning another editor promise + * it is possible to override the opening with another editor. It is ok + * to return a promise that resolves to NULL to prevent the opening + * altogether. + */ + prevent(callback: () => TPromise): void; +} + +export class EditorOpeningEvent { + private override: () => TPromise; + + constructor(private _input: IEditorInput, private _options: IEditorOptions, private _position: Position) { + } + + public get input(): IEditorInput { + return this._input; + } + + public get options(): IEditorOptions { + return this._options; + } + + public get position(): Position { + return this._position; + } + + public prevent(callback: () => TPromise): void { + this.override = callback; + } + + public isPrevented(): () => TPromise { + return this.override; + } +} + export enum EncodingMode { /** @@ -320,11 +334,6 @@ export interface IEncodingSupport { */ export interface IFileEditorInput extends IEditorInput, IEncodingSupport { - /** - * Gets the absolute file resource URI this input is about. - */ - getResource(): URI; - /** * Sets the preferred encodingt to use for this input. */ @@ -795,7 +804,22 @@ export const EditorOpenPositioning = { LAST: 'last' }; +export const OPEN_POSITIONING_CONFIG = 'workbench.editor.openPositioning'; + export interface IWorkbenchEditorConfiguration { + /* __GDPR__FRAGMENT__ + "IWorkbenchEditorConfiguration" : { + "showTabs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "tabCloseButton": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "showIcons": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "enablePreview": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "enablePreviewFromQuickOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "closeOnFileDelete": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "openPositioning": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "revealIfOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "swipeToNavigate": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ workbench: { editor: { showTabs: boolean; @@ -806,7 +830,8 @@ export interface IWorkbenchEditorConfiguration { closeOnFileDelete: boolean; openPositioning: 'left' | 'right' | 'first' | 'last'; revealIfOpen: boolean; - swipeToNavigate: boolean + swipeToNavigate: boolean, + labelFormat: 'default' | 'short' | 'medium' | 'long'; } }; } @@ -840,10 +865,6 @@ export interface IResourceOptions { filter?: 'file' | 'untitled' | ['file', 'untitled'] | ['untitled', 'file']; } -export function hasResource(editor: IEditorInput, options?: IResourceOptions): boolean { - return !!toResource(editor, options); -} - export function toResource(editor: IEditorInput, options?: IResourceOptions): URI { if (!editor) { return null; @@ -854,7 +875,7 @@ export function toResource(editor: IEditorInput, options?: IResourceOptions): UR editor = editor.master; } - const resource = doGetEditorResource(editor); + const resource = editor.getResource(); if (!options || !options.filter) { return resource; // return early if no filter is specified } @@ -884,14 +905,54 @@ export function toResource(editor: IEditorInput, options?: IResourceOptions): UR return null; } -// TODO@Ben every editor should have an associated resource -function doGetEditorResource(editor: IEditorInput): URI { - if (editor instanceof EditorInput && typeof (editor).getResource === 'function') { - const candidate = (editor).getResource(); - if (candidate instanceof URI) { - return candidate; +class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { + private instantiationService: IInstantiationService; + private fileInputFactory: IFileInputFactory; + private editorInputFactoryConstructors: { [editorInputId: string]: IConstructorSignature0 } = Object.create(null); + private editorInputFactoryInstances: { [editorInputId: string]: IEditorInputFactory } = Object.create(null); + + constructor() { + } + + public setInstantiationService(service: IInstantiationService): void { + this.instantiationService = service; + + for (let key in this.editorInputFactoryConstructors) { + const element = this.editorInputFactoryConstructors[key]; + this.createEditorInputFactory(key, element); + } + + this.editorInputFactoryConstructors = {}; + } + + private createEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { + const instance = this.instantiationService.createInstance(ctor); + this.editorInputFactoryInstances[editorInputId] = instance; + } + + public registerFileInputFactory(factory: IFileInputFactory): void { + this.fileInputFactory = factory; + } + + public getFileInputFactory(): IFileInputFactory { + return this.fileInputFactory; + } + + public registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { + if (!this.instantiationService) { + this.editorInputFactoryConstructors[editorInputId] = ctor; + } else { + this.createEditorInputFactory(editorInputId, ctor); } } - return null; -} \ No newline at end of file + public getEditorInputFactory(editorInputId: string): IEditorInputFactory { + return this.editorInputFactoryInstances[editorInputId]; + } +} + +export const Extensions = { + EditorInputFactories: 'workbench.contributions.editor.inputFactories' +}; + +Registry.add(Extensions.EditorInputFactories, new EditorInputFactoryRegistry()); \ No newline at end of file diff --git a/src/vs/workbench/common/editor/editorStacksModel.ts b/src/vs/workbench/common/editor/editorStacksModel.ts index 2191d20535c..20f09e32702 100644 --- a/src/vs/workbench/common/editor/editorStacksModel.ts +++ b/src/vs/workbench/common/editor/editorStacksModel.ts @@ -6,11 +6,11 @@ 'use strict'; import Event, { Emitter, once } from 'vs/base/common/event'; -import { IEditorRegistry, Extensions, EditorInput, toResource, IEditorStacksModel, IEditorGroup, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, IStacksModelChangeEvent, IWorkbenchEditorConfiguration, EditorOpenPositioning, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorStacksModel, IEditorGroup, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, IStacksModelChangeEvent, EditorOpenPositioning, SideBySideEditorInput, OPEN_POSITIONING_CONFIG } from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -84,7 +84,7 @@ export class EditorGroup implements IEditorGroup { this.mru = []; this.toDispose = []; this.mapResourceToEditorCount = new ResourceMap(); - this.onConfigurationUpdated(configurationService.getConfiguration()); + this.onConfigurationUpdated(); this._onEditorActivated = new Emitter(); this._onEditorOpened = new Emitter(); @@ -110,13 +110,11 @@ export class EditorGroup implements IEditorGroup { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); } - private onConfigurationUpdated(config: IWorkbenchEditorConfiguration): void { - if (config && config.workbench && config.workbench.editor) { - this.editorOpenPositioning = config.workbench.editor.openPositioning; - } + private onConfigurationUpdated(event?: IConfigurationChangeEvent): void { + this.editorOpenPositioning = this.configurationService.getValue(OPEN_POSITIONING_CONFIG); } public get id(): GroupIdentifier { @@ -637,7 +635,7 @@ export class EditorGroup implements IEditorGroup { } public serialize(): ISerializedEditorGroup { - const registry = Registry.as(Extensions.Editors); + const registry = Registry.as(Extensions.EditorInputFactories); // Serialize all editor inputs so that we can store them. // Editors that cannot be serialized need to be ignored @@ -671,7 +669,7 @@ export class EditorGroup implements IEditorGroup { } private deserialize(data: ISerializedEditorGroup): void { - const registry = Registry.as(Extensions.Editors); + const registry = Registry.as(Extensions.EditorInputFactories); this._label = data.label; this.editors = data.editors.map(e => { @@ -755,7 +753,7 @@ export class EditorStacksModel implements IEditorStacksModel { this._onWillCloseEditor = new Emitter(); this._onEditorClosed = new Emitter(); - this.toDispose.push(this._onGroupOpened, this._onGroupClosed, this._onGroupActivated, this._onGroupDeactivated, this._onGroupMoved, this._onGroupRenamed, this._onModelChanged, this._onEditorDisposed, this._onEditorDirty, this._onEditorLabelChange, this._onEditorClosed, this._onWillCloseEditor); + this.toDispose.push(this._onGroupOpened, this._onGroupClosed, this._onGroupActivated, this._onGroupDeactivated, this._onGroupMoved, this._onGroupRenamed, this._onModelChanged, this._onEditorDisposed, this._onEditorDirty, this._onEditorLabelChange, this._onEditorOpened, this._onEditorClosed, this._onWillCloseEditor); this.registerListeners(); } @@ -1215,7 +1213,7 @@ export class EditorStacksModel implements IEditorStacksModel { // Close the editor when it is no longer open in any group including diff editors editorsToClose.forEach(editorToClose => { - const resource = toResource(editorToClose); // prefer resource to not close right-hand side editors of a diff editor + const resource = editorToClose ? editorToClose.getResource() : void 0; // prefer resource to not close right-hand side editors of a diff editor if (!this.isOpen(resource || editorToClose)) { editorToClose.close(); } diff --git a/src/vs/workbench/common/editor/rangeDecorations.ts b/src/vs/workbench/common/editor/rangeDecorations.ts index 730062404f4..e8e821b044f 100644 --- a/src/vs/workbench/common/editor/rangeDecorations.ts +++ b/src/vs/workbench/common/editor/rangeDecorations.ts @@ -8,8 +8,6 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { toResource } from 'vs/workbench/common/editor'; -import { isEqual } from 'vs/base/common/paths'; import { IRange } from 'vs/editor/common/core/range'; import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; @@ -56,9 +54,10 @@ export class RangeHighlightDecorations implements IDisposable { } private getEditor(resourceRange: IRangeHighlightDecoration): editorCommon.ICommonCodeEditor { - const fileResource = toResource(this.editorService.getActiveEditorInput(), { filter: 'file' }); - if (fileResource) { - if (isEqual(fileResource.fsPath, resourceRange.resource.fsPath)) { + const activeInput = this.editorService.getActiveEditorInput(); + const resource = activeInput && activeInput.getResource(); + if (resource) { + if (resource.toString() === resourceRange.resource.toString()) { return this.editorService.getActiveEditor().getControl(); } } diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 3c33a6d16ec..4f9a57314ec 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -11,6 +11,7 @@ import { IReference } from 'vs/base/common/lifecycle'; import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUtils'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * A read-only text editor input whos contents are made of the provided resource that points to an existing @@ -29,7 +30,8 @@ export class ResourceEditorInput extends EditorInput { name: string, description: string, resource: URI, - @ITextModelService private textModelResolverService: ITextModelService + @ITextModelService private textModelResolverService: ITextModelService, + @IHashService private hashService: IHashService ) { super(); @@ -70,8 +72,13 @@ export class ResourceEditorInput extends EditorInput { public getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); - descriptor['resource'] = telemetryURIDescriptor(this.resource); + descriptor['resource'] = telemetryURIDescriptor(this.resource, path => this.hashService.createSHA1(path)); + /* __GDPR__FRAGMENT__ + "EditorTelemetryDescriptor" : { + "resource": { "${inline}": [ "${URIDescriptor}" ] } + } + */ return descriptor; } diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index 37c60e19f44..3a600630689 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -70,11 +70,7 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd protected createTextEditorModel(value: string | IRawTextSource, resource?: URI, modeId?: string): TPromise { const firstLineText = this.getFirstLineText(value); const mode = this.getOrCreateMode(this.modeService, modeId, firstLineText); - - // To avoid flickering, give the mode at most 50ms to load. If the mode doesn't load in 50ms, proceed creating the model with a mode promise - return TPromise.any([TPromise.timeout(50), mode]).then(() => { - return this.doCreateTextEditorModel(value, mode, resource); - }); + return TPromise.as(this.doCreateTextEditorModel(value, mode, resource)); } private doCreateTextEditorModel(value: string | IRawTextSource, mode: TPromise, resource: URI): EditorModel { @@ -166,4 +162,4 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd super.dispose(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 081b9bd7df4..45092f33e98 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -7,9 +7,11 @@ import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { suggestFilename } from 'vs/base/common/mime'; +import { memoize } from 'vs/base/common/decorators'; import labels = require('vs/base/common/labels'); import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult } from 'vs/workbench/common/editor'; import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -19,6 +21,8 @@ import Event, { Emitter } from 'vs/base/common/event'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUtils'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { Verbosity } from 'vs/platform/editor/common/editor'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * An editor input to be used for untitled text buffers. @@ -45,7 +49,8 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport @IInstantiationService private instantiationService: IInstantiationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextFileService private textFileService: ITextFileService, - @IEnvironmentService private environmentService: IEnvironmentService + @IEnvironmentService private environmentService: IEnvironmentService, + @IHashService private hashService: IHashService ) { super(); @@ -85,11 +90,80 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport } public getName(): string { - return this.hasAssociatedFilePath ? paths.basename(this.resource.fsPath) : this.resource.fsPath; + return this.hasAssociatedFilePath ? resources.basenameOrAuthority(this.resource) : this.resource.path; } - public getDescription(): string { - return this.hasAssociatedFilePath ? labels.getPathLabel(paths.dirname(this.resource.fsPath), this.contextService, this.environmentService) : null; + @memoize + private get shortDescription(): string { + return paths.basename(labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService)); + } + + @memoize + private get mediumDescription(): string { + return labels.getPathLabel(resources.dirname(this.resource), this.contextService, this.environmentService); + } + + @memoize + private get longDescription(): string { + return labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService); + } + + public getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string { + if (!this.hasAssociatedFilePath) { + return null; + } + + let description: string; + switch (verbosity) { + case Verbosity.SHORT: + description = this.shortDescription; + break; + case Verbosity.LONG: + description = this.longDescription; + break; + case Verbosity.MEDIUM: + default: + description = this.mediumDescription; + break; + } + + return description; + } + + @memoize + private get shortTitle(): string { + return this.getName(); + } + + @memoize + private get mediumTitle(): string { + return labels.getPathLabel(this.resource, this.contextService, this.environmentService); + } + + @memoize + private get longTitle(): string { + return labels.getPathLabel(this.resource, void 0, this.environmentService); + } + + public getTitle(verbosity: Verbosity): string { + if (!this.hasAssociatedFilePath) { + return this.getName(); + } + + let title: string; + switch (verbosity) { + case Verbosity.SHORT: + title = this.shortTitle; + break; + case Verbosity.MEDIUM: + title = this.mediumTitle; + break; + case Verbosity.LONG: + title = this.longTitle; + break; + } + + return title; } public isDirty(): boolean { @@ -180,8 +254,13 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport public getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); - descriptor['resource'] = telemetryURIDescriptor(this.getResource()); + descriptor['resource'] = telemetryURIDescriptor(this.getResource(), path => this.hashService.createSHA1(path)); + /* __GDPR__FRAGMENT__ + "EditorTelemetryDescriptor" : { + "resource": { "${inline}": [ "${URIDescriptor}" ] } + } + */ return descriptor; } diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index 17d7ff337a0..278e1bdcad8 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { IEncodingSupport } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; @@ -12,7 +12,6 @@ import URI from 'vs/base/common/uri'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { EndOfLinePreference } from 'vs/editor/common/editorCommon'; import { IFilesConfiguration, CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IMode } from 'vs/editor/common/modes'; @@ -20,13 +19,13 @@ import Event, { Emitter } from 'vs/base/common/event'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IBackupFileService, BACKUP_FILE_RESOLVE_OPTIONS } from 'vs/workbench/services/backup/common/backup'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; export class UntitledEditorModel extends BaseTextEditorModel implements IEncodingSupport { public static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY; - private textModelChangeListener: IDisposable; - private configurationChangeListener: IDisposable; + private toDispose: IDisposable[]; private dirty: boolean; private _onDidChangeContent: Emitter; @@ -49,18 +48,25 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin @IModelService modelService: IModelService, @IBackupFileService private backupFileService: IBackupFileService, @ITextFileService private textFileService: ITextFileService, - @IConfigurationService private configurationService: IConfigurationService + @ITextResourceConfigurationService private configurationService: ITextResourceConfigurationService ) { super(modelService, modeService); this.dirty = false; this.versionId = 0; + this.toDispose = []; this._onDidChangeContent = new Emitter(); + this.toDispose.push(this._onDidChangeContent); + this._onDidChangeDirty = new Emitter(); + this.toDispose.push(this._onDidChangeDirty); + this._onDidChangeEncoding = new Emitter(); + this.toDispose.push(this._onDidChangeEncoding); this.contentChangeEventScheduler = new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY); + this.toDispose.push(this.contentChangeEventScheduler); this.registerListeners(); } @@ -88,11 +94,20 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin private registerListeners(): void { // Config Changes - this.configurationChangeListener = this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange())); } - private onConfigurationChange(configuration: IFilesConfiguration): void { - this.configuredEncoding = configuration && configuration.files && configuration.files.encoding; + private onConfigurationChange(): void { + const configuration = this.configurationService.getConfiguration(this.resource); + const configuredEncoding = configuration && configuration.files && configuration.files.encoding; + + if (this.configuredEncoding !== configuredEncoding) { + this.configuredEncoding = configuredEncoding; + + if (!this.preferredEncoding) { + this._onDidChangeEncoding.fire(); // do not fire event if we have a preferred encoding set + } + } } public getVersionId(): number { @@ -170,13 +185,16 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin this.setDirty(this.hasAssociatedFilePath || !!backupContent); return this.doLoad(backupContent || this.initialValue || '').then(model => { - const configuration = this.configurationService.getConfiguration(); + const configuration = this.configurationService.getConfiguration(this.resource); // Encoding this.configuredEncoding = configuration && configuration.files && configuration.files.encoding; // Listen to content changes - this.textModelChangeListener = this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged()); + this.toDispose.push(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); + + // Listen to mode changes + this.toDispose.push(this.textEditorModel.onDidChangeLanguage(() => this.onConfigurationChange())); // mode change can have impact on config return model; }); @@ -219,20 +237,6 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin public dispose(): void { super.dispose(); - if (this.textModelChangeListener) { - this.textModelChangeListener.dispose(); - this.textModelChangeListener = null; - } - - if (this.configurationChangeListener) { - this.configurationChangeListener.dispose(); - this.configurationChangeListener = null; - } - - this.contentChangeEventScheduler.dispose(); - - this._onDidChangeContent.dispose(); - this._onDidChangeDirty.dispose(); - this._onDidChangeEncoding.dispose(); + this.toDispose = dispose(this.toDispose); } } \ No newline at end of file diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 830f77fd26f..e958dcf60f1 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -11,8 +11,8 @@ import paths = require('vs/base/common/paths'); import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ParsedExpression, IExpression } from 'vs/base/common/glob'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; import { basename } from 'vs/base/common/paths'; import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -23,11 +23,13 @@ export class ResourceContextKey implements IContextKey { static Filename = new RawContextKey('resourceFilename', undefined); static LangId = new RawContextKey('resourceLangId', undefined); static Resource = new RawContextKey('resource', undefined); + static Extension = new RawContextKey('resourceExtname', undefined); private _resourceKey: IContextKey; private _schemeKey: IContextKey; private _filenameKey: IContextKey; private _langIdKey: IContextKey; + private _extensionKey: IContextKey; constructor( @IContextKeyService contextKeyService: IContextKeyService, @@ -37,6 +39,7 @@ export class ResourceContextKey implements IContextKey { this._filenameKey = ResourceContextKey.Filename.bindTo(contextKeyService); this._langIdKey = ResourceContextKey.LangId.bindTo(contextKeyService); this._resourceKey = ResourceContextKey.Resource.bindTo(contextKeyService); + this._extensionKey = ResourceContextKey.Extension.bindTo(contextKeyService); } set(value: URI) { @@ -44,12 +47,15 @@ export class ResourceContextKey implements IContextKey { this._schemeKey.set(value && value.scheme); this._filenameKey.set(value && basename(value.fsPath)); this._langIdKey.set(value && this._modeService.getModeIdByFilenameOrFirstLine(value.fsPath)); + this._extensionKey.set(value && paths.extname(value.fsPath)); } reset(): void { this._schemeKey.reset(); this._langIdKey.reset(); this._resourceKey.reset(); + this._langIdKey.reset(); + this._extensionKey.reset(); } public get(): URI { @@ -68,7 +74,7 @@ export class ResourceGlobMatcher { constructor( private globFn: (root?: URI) => IExpression, - private parseFn: (expression: IExpression) => ParsedExpression, + private shouldUpdate: (event: IConfigurationChangeEvent) => boolean, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService ) { @@ -90,33 +96,27 @@ export class ResourceGlobMatcher { } private registerListeners(): void { - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(() => this.onConfigurationChanged())); - this.toUnbind.push(this.contextService.onDidChangeWorkspaceRoots(() => this.onDidChangeWorkspaceRoots())); - } - - private onConfigurationChanged(): void { - this.updateExcludes(true); - } - - private onDidChangeWorkspaceRoots(): void { - this.updateExcludes(true); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => { + if (this.shouldUpdate(e)) { + this.updateExcludes(true); + } + })); + this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.updateExcludes(true))); } private updateExcludes(fromEvent: boolean): void { let changed = false; // Add excludes per workspaces that got added - if (this.contextService.hasWorkspace()) { - this.contextService.getWorkspace().roots.forEach(root => { - const rootExcludes = this.globFn(root); - if (!this.mapRootToExpressionConfig.has(root.toString()) || !objects.equals(this.mapRootToExpressionConfig.get(root.toString()), rootExcludes)) { - changed = true; + this.contextService.getWorkspace().folders.forEach(folder => { + const rootExcludes = this.globFn(folder.uri); + if (!this.mapRootToExpressionConfig.has(folder.uri.toString()) || !objects.equals(this.mapRootToExpressionConfig.get(folder.uri.toString()), rootExcludes)) { + changed = true; - this.mapRootToParsedExpression.set(root.toString(), this.parseFn(rootExcludes)); - this.mapRootToExpressionConfig.set(root.toString(), objects.clone(rootExcludes)); - } - }); - } + this.mapRootToParsedExpression.set(folder.uri.toString(), parse(rootExcludes)); + this.mapRootToExpressionConfig.set(folder.uri.toString(), objects.clone(rootExcludes)); + } + }); // Remove excludes per workspace no longer present this.mapRootToExpressionConfig.forEach((value, root) => { @@ -124,7 +124,7 @@ export class ResourceGlobMatcher { return; // always keep this one } - if (!this.contextService.getRoot(URI.parse(root))) { + if (!this.contextService.getWorkspaceFolder(URI.parse(root))) { this.mapRootToParsedExpression.delete(root); this.mapRootToExpressionConfig.delete(root); @@ -137,7 +137,7 @@ export class ResourceGlobMatcher { if (!this.mapRootToExpressionConfig.has(ResourceGlobMatcher.NO_ROOT) || !objects.equals(this.mapRootToExpressionConfig.get(ResourceGlobMatcher.NO_ROOT), globalExcludes)) { changed = true; - this.mapRootToParsedExpression.set(ResourceGlobMatcher.NO_ROOT, this.parseFn(globalExcludes)); + this.mapRootToParsedExpression.set(ResourceGlobMatcher.NO_ROOT, parse(globalExcludes)); this.mapRootToExpressionConfig.set(ResourceGlobMatcher.NO_ROOT, objects.clone(globalExcludes)); } @@ -147,11 +147,11 @@ export class ResourceGlobMatcher { } public matches(resource: URI): boolean { - const root = this.contextService.getRoot(resource); + const folder = this.contextService.getWorkspaceFolder(resource); let expressionForRoot: ParsedExpression; - if (root && this.mapRootToParsedExpression.has(root.toString())) { - expressionForRoot = this.mapRootToParsedExpression.get(root.toString()); + if (folder && this.mapRootToParsedExpression.has(folder.uri.toString())) { + expressionForRoot = this.mapRootToParsedExpression.get(folder.uri.toString()); } else { expressionForRoot = this.mapRootToParsedExpression.get(ResourceGlobMatcher.NO_ROOT); } @@ -161,8 +161,8 @@ export class ResourceGlobMatcher { // a glob pattern of "src/**" will not match on an absolute path "/folder/src/file.txt" // but can match on "src/file.txt" let resourcePathToMatch: string; - if (root) { - resourcePathToMatch = paths.normalize(paths.relative(root.fsPath, resource.fsPath)); + if (folder) { + resourcePathToMatch = paths.normalize(paths.relative(folder.uri.fsPath, resource.fsPath)); } else { resourcePathToMatch = resource.fsPath; } @@ -173,4 +173,4 @@ export class ResourceGlobMatcher { public dispose(): void { this.toUnbind = dispose(this.toUnbind); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 5097ff16f1c..77887fd950d 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -118,7 +118,7 @@ export const PANEL_BORDER = registerColor('panel.border', { dark: Color.fromHex('#808080').transparent(0.35), light: Color.fromHex('#808080').transparent(0.35), hc: contrastBorder -}, nls.localize('panelBorder', "Panel border color on the top separating to the editor. Panels are shown below the editor area and contain views like output and integrated terminal.")); +}, nls.localize('panelBorder', "Panel border color to separate the panel from the editor. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_ACTIVE_TITLE_FOREGROUND = registerColor('panelTitle.activeForeground', { dark: '#E7E7E7', @@ -138,6 +138,11 @@ export const PANEL_ACTIVE_TITLE_BORDER = registerColor('panelTitle.activeBorder' hc: contrastBorder }, nls.localize('panelActiveTitleBorder', "Border color for the active panel title. Panels are shown below the editor area and contain views like output and integrated terminal.")); +export const PANEL_DRAG_AND_DROP_BACKGROUND = registerColor('panel.dropBackground', { + dark: Color.white.transparent(0.12), + light: Color.fromHex('#3399FF').transparent(0.18), + hc: Color.white.transparent(0.12) +}, nls.localize('panelDragAndDropBackground', "Drag and drop feedback color for the panel title items. The color should have transparency so that the panel entries can still shine through. Panels are shown below the editor area and contain views like output and integrated terminal.")); // < --- Status --- > @@ -224,6 +229,7 @@ export const ACTIVITY_BAR_BORDER = registerColor('activityBar.border', { hc: contrastBorder }, nls.localize('activityBarBorder', "Activity bar border color separating to the side bar. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); + export const ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND = registerColor('activityBar.dropBackground', { dark: Color.white.transparent(0.12), light: Color.white.transparent(0.12), @@ -243,7 +249,6 @@ export const ACTIVITY_BAR_BADGE_FOREGROUND = registerColor('activityBarBadge.for }, nls.localize('activityBarBadgeForeground', "Activity notification badge foreground color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); - // < --- Side Bar --- > export const SIDE_BAR_BACKGROUND = registerColor('sideBar.background', { diff --git a/src/vs/workbench/parts/views/common/views.ts b/src/vs/workbench/common/views.ts similarity index 99% rename from src/vs/workbench/parts/views/common/views.ts rename to src/vs/workbench/common/views.ts index 730931ed339..599a1cfdde4 100644 --- a/src/vs/workbench/parts/views/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -46,5 +46,4 @@ export interface ITreeViewDataProvider { getElements(): TPromise; getChildren(element: ITreeItem): TPromise; - } \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 5352574fb60..1cca1e27f11 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -18,11 +18,10 @@ import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; import errors = require('vs/base/common/errors'); import { IMessageService, Severity } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExtensionManagementService, LocalExtensionType, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IExtensionManagementService, LocalExtensionType, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import paths = require('vs/base/common/paths'); import { isMacintosh, isLinux } from 'vs/base/common/platform'; @@ -46,6 +45,7 @@ import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifi import { FileKind } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { getEntries } from 'vs/base/common/performance'; // --- actions @@ -104,7 +104,7 @@ export class CloseWorkspaceAction extends Action { } run(): TPromise { - if (!this.contextService.hasWorkspace()) { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(Severity.Info, nls.localize('noWorkspaceOpened', "There is currently no workspace opened in this instance to close.")); return TPromise.as(null); @@ -156,15 +156,13 @@ export class ToggleMenuBarAction extends Action { constructor( id: string, label: string, - @IMessageService private messageService: IMessageService, - @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); } public run(): TPromise { - let currentVisibilityValue = this.configurationService.lookup(ToggleMenuBarAction.menuBarVisibilityKey).value; + let currentVisibilityValue = this.configurationService.getValue(ToggleMenuBarAction.menuBarVisibilityKey); if (typeof currentVisibilityValue !== 'string') { currentVisibilityValue = 'default'; } @@ -176,7 +174,7 @@ export class ToggleMenuBarAction extends Action { newVisibilityValue = 'default'; } - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMenuBarAction.menuBarVisibilityKey, value: newVisibilityValue }); + this.configurationService.updateValue(ToggleMenuBarAction.menuBarVisibilityKey, newVisibilityValue, ConfigurationTarget.USER); return TPromise.as(null); } @@ -202,18 +200,12 @@ export abstract class BaseZoomAction extends Action { constructor( id: string, label: string, - @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService ) { super(id, label); } protected setConfiguredZoomLevel(level: number): void { - let target = ConfigurationTarget.USER; - if (typeof this.configurationService.lookup(BaseZoomAction.SETTING_KEY).workspace === 'number') { - target = ConfigurationTarget.WORKSPACE; - } - level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels const applyZoom = () => { @@ -225,7 +217,7 @@ export abstract class BaseZoomAction extends Action { browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false); }; - this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }, { donotNotifyError: true }).done(() => applyZoom(), error => applyZoom()); + this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level).done(() => applyZoom()); } } @@ -237,10 +229,9 @@ export class ZoomInAction extends BaseZoomAction { constructor( id: string, label: string, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService ) { - super(id, label, configurationService, configurationEditingService); + super(id, label, configurationService); } public run(): TPromise { @@ -258,10 +249,9 @@ export class ZoomOutAction extends BaseZoomAction { constructor( id: string, label: string, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService ) { - super(id, label, configurationService, configurationEditingService); + super(id, label, configurationService); } public run(): TPromise { @@ -279,10 +269,9 @@ export class ZoomResetAction extends BaseZoomAction { constructor( id: string, label: string, - @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService ) { - super(id, label, configurationService, configurationEditingService); + super(id, label, configurationService); } public run(): TPromise { @@ -351,11 +340,9 @@ export class ShowStartupPerformance extends Action { console.log(`Empty Workspace: ${metrics.emptyWorkbench}`); let nodeModuleLoadTime: number; - let nodeModuleLoadDetails: any[]; if (this.environmentService.performance) { const nodeModuleTimes = this.analyzeNodeModulesLoadTimes(); nodeModuleLoadTime = nodeModuleTimes.duration; - nodeModuleLoadDetails = nodeModuleTimes.table; } (console).table(this.getStartupMetricsTable(nodeModuleLoadTime)); @@ -374,6 +361,16 @@ export class ShowStartupPerformance extends Action { (console).group('Extension Activation Stats'); (console).table(this.extensionService.getExtensionsActivationTimes()); (console).groupEnd(); + + (console).group('Raw Startup Timers (CSV)'); + let value = `Name\tStart\tDuration\n`; + const entries = getEntries('measure'); + let offset = entries[0].startTime; + for (const entry of entries) { + value += `${entry.name}\t${entry.startTime - offset}\t${entry.duration}\n`; + } + console.log(value); + (console).groupEnd(); }, 1000); return TPromise.as(true); @@ -759,23 +756,12 @@ export abstract class BaseOpenRecentAction extends Action { const workspacePicks: IFilePickOpenEntry[] = recentWorkspaces.map((workspace, index) => toPick(workspace, index === 0 ? { label: nls.localize('workspaces', "workspaces") } : void 0, isSingleFolderWorkspaceIdentifier(workspace) ? FileKind.FOLDER : FileKind.ROOT_FOLDER, this.environmentService, !this.isQuickNavigate() ? this.removeAction : void 0)); const filePicks: IFilePickOpenEntry[] = recentFiles.map((p, index) => toPick(p, index === 0 ? { label: nls.localize('files', "files"), border: true } : void 0, FileKind.FILE, this.environmentService, !this.isQuickNavigate() ? this.removeAction : void 0)); - let isCurrentWorkspaceInList: boolean; - if (!this.contextService.hasWorkspace()) { - isCurrentWorkspaceInList = false; // we never show empty workspaces - } else if (this.contextService.hasFolderWorkspace()) { - isCurrentWorkspaceInList = true; // we always show folder workspaces - } else { - const firstWorkspace = recentWorkspaces[0]; - if (firstWorkspace && !isSingleFolderWorkspaceIdentifier(firstWorkspace)) { - isCurrentWorkspaceInList = firstWorkspace.id === this.contextService.getWorkspace().id; - } else { - isCurrentWorkspaceInList = false; // this is an untitled workspace thereby - } - } + // focus second entry if the first recent workspace is the current workspace + let autoFocusSecondEntry: boolean = recentWorkspaces[0] && this.contextService.isCurrentWorkspace(recentWorkspaces[0]); this.quickOpenService.pick([...workspacePicks, ...filePicks], { contextKey: inRecentFilesPickerContextKey, - autoFocus: { autoFocusFirstEntry: !isCurrentWorkspaceInList, autoFocusSecondEntry: isCurrentWorkspaceInList }, + autoFocus: { autoFocusFirstEntry: !autoFocusSecondEntry, autoFocusSecondEntry: autoFocusSecondEntry }, placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select to open (hold Cmd-key to open in new window)") : nls.localize('openRecentPlaceHolder', "Select to open (hold Ctrl-key to open in new window)"), matchOnDescription: true, quickNavigateConfiguration: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : void 0 @@ -898,6 +884,7 @@ export class ReportIssueAction extends Action { label: string, @IIntegrityService private integrityService: IIntegrityService, @IExtensionManagementService private extensionManagementService: IExtensionManagementService, + @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, @IEnvironmentService private environmentService: IEnvironmentService ) { super(id, label); @@ -917,6 +904,7 @@ export class ReportIssueAction extends Action { public run(): TPromise { return this._optimisticIsPure().then(isPure => { return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => { + extensions = extensions.filter(extension => this.extensionEnablementService.isEnabled(extension.identifier)); const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, isPure, extensions, this.environmentService.disableExtensions); window.open(issueUrl); @@ -1554,4 +1542,94 @@ export class DecreaseViewSizeAction extends BaseResizeViewAction { this.resizePart(-BaseResizeViewAction.RESIZE_INCREMENT); return TPromise.as(true); } -} \ No newline at end of file +} + +export class ShowPreviousWindowTab extends Action { + + public static ID = 'workbench.action.showPreviousWindowTab'; + public static LABEL = nls.localize('showPreviousTab', "Show Previous Window Tab"); + + constructor( + id: string, + label: string, + @IWindowsService private windowsService: IWindowsService + ) { + super(ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL); + } + + public run(): TPromise { + return this.windowsService.showPreviousWindowTab().then(() => true); + } +} + +export class ShowNextWindowTab extends Action { + + public static ID = 'workbench.action.showNextWindowTab'; + public static LABEL = nls.localize('showNextWindowTab', "Show Next Window Tab"); + + constructor( + id: string, + label: string, + @IWindowsService private windowsService: IWindowsService + ) { + super(ShowNextWindowTab.ID, ShowNextWindowTab.LABEL); + } + + public run(): TPromise { + return this.windowsService.showNextWindowTab().then(() => true); + } +} + +export class MoveWindowTabToNewWindow extends Action { + + public static ID = 'workbench.action.moveWindowTabToNewWindow'; + public static LABEL = nls.localize('moveWindowTabToNewWindow', "Move Window Tab to New Window"); + + constructor( + id: string, + label: string, + @IWindowsService private windowsService: IWindowsService + ) { + super(MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL); + } + + public run(): TPromise { + return this.windowsService.moveWindowTabToNewWindow().then(() => true); + } +} + +export class MergeAllWindowTabs extends Action { + + public static ID = 'workbench.action.mergeAllWindowTabs'; + public static LABEL = nls.localize('mergeAllWindowTabs', "Merge All Windows"); + + constructor( + id: string, + label: string, + @IWindowsService private windowsService: IWindowsService + ) { + super(MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL); + } + + public run(): TPromise { + return this.windowsService.mergeAllWindowTabs().then(() => true); + } +} + +export class ToggleWindowTabsBar extends Action { + + public static ID = 'workbench.action.toggleWindowTabsBar'; + public static LABEL = nls.localize('toggleWindowTabsBar', "Toggle Window Tabs Bar"); + + constructor( + id: string, + label: string, + @IWindowsService private windowsService: IWindowsService + ) { + super(ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL); + } + + public run(): TPromise { + return this.windowsService.toggleWindowTabsBar().then(() => true); + } +} diff --git a/src/vs/workbench/electron-browser/bootstrap/index.js b/src/vs/workbench/electron-browser/bootstrap/index.js index 8961feef2a7..81bc8dd1fbb 100644 --- a/src/vs/workbench/electron-browser/bootstrap/index.js +++ b/src/vs/workbench/electron-browser/bootstrap/index.js @@ -14,7 +14,9 @@ if (window.location.search.indexOf('prof-startup') >= 0) { /*global window,document,define,Monaco_Loader_Init*/ -const startTimer = require('../../../base/node/startupTimers').startTimer; +const perf = require('../../../base/common/performance'); +perf.mark('renderer/started'); + const path = require('path'); const electron = require('electron'); const remote = electron.remote; @@ -124,6 +126,7 @@ function main() { // Correctly inherit the parent's environment assign(process.env, configuration.userEnv); + perf.importEntries(configuration.perfEntries); // Get the nls configuration into the process.env as early as possible. var nlsConfig = { availableLanguages: {} }; @@ -161,7 +164,6 @@ function main() { window.nodeRequire = require.__$__nodeRequire; define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code - loaderTimer.stop(); window.MonacoEnvironment = {}; @@ -191,16 +193,17 @@ function main() { beforeLoadWorkbenchMain: Date.now() }; - const workbenchMainTimer = startTimer('load:workbench.main'); + const workbenchMainClock = perf.time('loadWorkbenchMain'); require([ 'vs/workbench/workbench.main', 'vs/nls!vs/workbench/workbench.main', 'vs/css!vs/workbench/workbench.main' ], function () { - workbenchMainTimer.stop(); + workbenchMainClock.stop(); timers.afterLoadWorkbenchMain = Date.now(); process.lazyEnv.then(function () { + perf.mark('main/startup'); require('vs/workbench/electron-browser/main') .startup(configuration) .done(function () { @@ -213,8 +216,6 @@ function main() { } // 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 - const loaderTimer = startTimer('load:loader'); if (typeof Monaco_Loader_Init === 'function') { const loader = Monaco_Loader_Init(); //eslint-disable-next-line no-global-assign diff --git a/src/vs/workbench/electron-browser/commands.ts b/src/vs/workbench/electron-browser/commands.ts index 67b9773b90d..89b3f5181f1 100644 --- a/src/vs/workbench/electron-browser/commands.ts +++ b/src/vs/workbench/electron-browser/commands.ts @@ -20,6 +20,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import URI from 'vs/base/common/uri'; import { IEditorOptions, Position as EditorPosition } from 'vs/platform/editor/common/editor'; +import { openFolderCommand, openFileInNewWindowCommand, openFileFolderInNewWindowCommand, openFolderInNewWindowCommand, openWorkspaceInNewWindowCommand } from 'vs/workbench/browser/actions/workspaceActions'; // --- List Commands @@ -420,4 +421,11 @@ export function registerCommands(): void { return void 0; }); }); + + CommandsRegistry.registerCommand('_files.pickFolderAndOpen', openFolderCommand); + + CommandsRegistry.registerCommand('workbench.action.files.openFileInNewWindow', openFileInNewWindowCommand); + CommandsRegistry.registerCommand('workbench.action.files.openFolderInNewWindow', openFolderInNewWindowCommand); + CommandsRegistry.registerCommand('workbench.action.files.openFileFolderInNewWindow', openFileFolderInNewWindowCommand); + CommandsRegistry.registerCommand('workbench.action.openWorkspaceInNewWindow', openWorkspaceInNewWindowCommand); } diff --git a/src/vs/workbench/browser/actions/configureLocale.ts b/src/vs/workbench/electron-browser/configureLocale.ts similarity index 93% rename from src/vs/workbench/browser/actions/configureLocale.ts rename to src/vs/workbench/electron-browser/configureLocale.ts index 08a405c4141..d360f840752 100644 --- a/src/vs/workbench/browser/actions/configureLocale.ts +++ b/src/vs/workbench/electron-browser/configureLocale.ts @@ -13,7 +13,7 @@ import * as Platform from 'vs/base/common/platform'; import { Action } from 'vs/base/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -69,6 +69,12 @@ class ConfigureLocaleAction extends Action { const registry = Registry.as(Extensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLocaleAction, ConfigureLocaleAction.ID, ConfigureLocaleAction.LABEL), 'Configure Language'); +let enumValues: string[] = ['de', 'en', 'en-US', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-CN', 'zh-TW']; +import product from 'vs/platform/node/product'; +if (product.quality !== 'stable') { + enumValues.push('hu'); +} + const schemaId = 'vscode://schemas/locale'; // Keep en-US since we generated files with that content. const schema: IJSONSchema = @@ -83,7 +89,7 @@ const schema: IJSONSchema = properties: { locale: { type: 'string', - enum: ['de', 'en', 'en-US', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-CN', 'zh-TW'], + enum: enumValues, description: nls.localize('JsonSchema.locale', 'The UI Language to use.') } } diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index c446905e5c7..91a80298351 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -11,14 +11,17 @@ import product from 'vs/platform/node/product'; import * as os from 'os'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; -import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction } from 'vs/workbench/electron-browser/actions'; +import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey } from 'vs/workbench/electron-browser/actions'; import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { registerCommands } from 'vs/workbench/electron-browser/commands'; -import { AddRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, OpenFolderAsWorkspaceInNewWindowAction, OpenFileFolderAction, OpenFileAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; // Contribute Commands registerCommands(); @@ -32,7 +35,16 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NewWin workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: null, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...'); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); + +if (isMacintosh) { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); +} else { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); +} + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory); if (!!product.reportIssueUrl) { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportIssueAction, ReportIssueAction.ID, ReportIssueAction.LABEL), 'Help: Report Issues', helpCategory); @@ -73,28 +85,49 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(Toggle if (isWindows || isLinux) { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMenuBarAction, ToggleMenuBarAction.ID, ToggleMenuBarAction.LABEL), 'View: Toggle Menu Bar', viewCategory); } -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, null), 'View: Move to the View Above', viewCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, null), 'View: Move to the View Below', viewCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, null), 'View: Move to the View on the Left', viewCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, null), 'View: Move to the View on the Right', viewCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, null), 'View: Navigate to the View Above', viewCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, null), 'View: Navigate to the View Below', viewCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, null), 'View: Navigate to the View on the Left', viewCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, null), 'View: Navigate to the View on the Right', viewCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(IncreaseViewSizeAction, IncreaseViewSizeAction.ID, IncreaseViewSizeAction.LABEL, null), 'View: Increase Current View Size', viewCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(DecreaseViewSizeAction, DecreaseViewSizeAction.ID, DecreaseViewSizeAction.LABEL, null), 'View: Decrease Current View Size', viewCategory); -// TODO@Ben multi root -if (product.quality !== 'stable') { - const workspacesCategory = nls.localize('workspaces', "Workspaces"); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace...', workspacesCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL), 'Workspaces: Open Workspace Configuration File', workspacesCategory); -} +const workspacesCategory = nls.localize('workspaces', "Workspaces"); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL), 'Workspaces: Open Workspace Configuration File', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAsWorkspaceInNewWindowAction, OpenFolderAsWorkspaceInNewWindowAction.ID, OpenFolderAsWorkspaceInNewWindowAction.LABEL), 'Workspaces: Open Folder as Workspace in New Window', workspacesCategory); // Developer related actions const developerCategory = nls.localize('developer', "Developer"); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowStartupPerformance, ShowStartupPerformance.ID, ShowStartupPerformance.LABEL), 'Developer: Startup Performance', developerCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); +const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey)); + +const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker'; +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: quickOpenNavigateNextInRecentFilesPickerId, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50), + handler: getQuickNavigateHandler(quickOpenNavigateNextInRecentFilesPickerId, true), + when: recentFilesPickerContext, + primary: KeyMod.CtrlCmd | KeyCode.KEY_R, + mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } +}); + +const quickOpenNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker'; +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: quickOpenNavigatePreviousInRecentFilesPicker, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50), + handler: getQuickNavigateHandler(quickOpenNavigatePreviousInRecentFilesPicker, false), + when: recentFilesPickerContext, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R, + mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R } +}); + // Configuration: Workbench const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -104,6 +137,23 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { 'description': nls.localize('showEditorTabs', "Controls if opened editors should show in tabs or not."), 'default': true }, + 'workbench.editor.labelFormat': { + 'type': 'string', + 'enum': ['default', 'short', 'medium', 'long'], + 'enumDescriptions': [ + nls.localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguinshing sections of each file's path are added. When tabs are disabled, the path relative to the workspace folder is shown if the editor is active."), + nls.localize('workbench.editor.labelFormat.short', "Show the name of the file followed by it's directory name."), + nls.localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by it's path relative to the workspace folder."), + nls.localize('workbench.editor.labelFormat.long', "Show the name of the file followed by it's absolute path.") + ], + 'default': 'default', + 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], key: 'tabDescription' }, + `Controls the format of the label for an editor. Changing this setting can for example make it easier to understand the location of a file: +- short: 'parent' +- medium: 'workspace/src/parent' +- long: '/home/user/workspace/src/parent' +- default: '.../parent', when another tab shares the same title, or the relative workspace path if tabs are disabled`), + }, 'workbench.editor.tabCloseButton': { 'type': 'string', 'enum': ['left', 'right', 'off'], @@ -117,7 +167,7 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { }, 'workbench.editor.enablePreview': { 'type': 'boolean', - 'description': nls.localize('enablePreview', "Controls if opened editors show as preview. Preview editors are reused until they are kept (e.g. via double click or editing)."), + 'description': nls.localize('enablePreview', "Controls if opened editors show as preview. Preview editors are reused until they are kept (e.g. via double click or editing) and show up with an italic font style."), 'default': true }, 'workbench.editor.enablePreviewFromQuickOpen': { @@ -129,7 +179,7 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { 'type': 'string', 'enum': ['left', 'right', 'first', 'last'], 'default': 'right', - 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select 'left' or 'right' to open editors to the left or right of the current active one. Select 'first' or 'last' to open editors independently from the currently active one.") + 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select 'left' or 'right' to open editors to the left or right of the currently active one. Select 'first' or 'last' to open editors independently from the currently active one.") }, 'workbench.editor.revealIfOpen': { 'type': 'boolean', @@ -138,7 +188,7 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { }, 'workbench.commandPalette.history': { 'type': 'number', - 'description': nls.localize('commandHistory', "Controls if the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."), + 'description': nls.localize('commandHistory', "Controls the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."), 'default': 50 }, 'workbench.commandPalette.preserveInput': { @@ -162,6 +212,12 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { 'default': 'left', 'description': nls.localize('sideBarLocation', "Controls the location of the sidebar. It can either show on the left or right of the workbench.") }, + 'workbench.panel.location': { + 'type': 'string', + 'enum': ['bottom', 'right'], + 'default': 'bottom', + 'description': nls.localize('panelLocation', "Controls the location of the panel. It can either show on the bottom or right of the workbench.") + }, 'workbench.statusBar.visible': { 'type': 'boolean', 'default': true, @@ -179,14 +235,40 @@ let workbenchProperties: { [path: string]: IJSONSchema; } = { } }; +if (product.quality !== 'stable') { + workbenchProperties['workbench.settings.experimentalFuzzySearchEndpoint'] = { + 'type': 'string', + 'description': nls.localize('experimentalFuzzySearchEndpoint', "Indicates the endpoint to use for the experimental settings search."), + 'default': '' + }; + + workbenchProperties['workbench.settings.experimentalFuzzySearchKey'] = { + 'type': 'string', + 'description': nls.localize('experimentalFuzzySearchKey', "Indicates the key to use for the experimental settings search."), + 'default': '' + }; + + workbenchProperties['workbench.settings.experimentalFuzzySearchBoost'] = { + 'type': 'number', + 'description': 'Indicates the amount to boost the "literal" component of the query. Temporary.', + 'default': 10 + }; + + workbenchProperties['workbench.settings.experimentalFuzzySearchAutoIngestFeedback'] = { + 'type': 'boolean', + 'description': 'Indicates whether feedback from this client should be automatically ingested.', + 'default': false + }; +} + if (isMacintosh) { workbenchProperties['workbench.fontAliasing'] = { 'type': 'string', 'enum': ['default', 'antialiased', 'none'], 'default': 'default', 'description': - nls.localize('fontAliasing', - `Controls font aliasing method in the workbench. + nls.localize('fontAliasing', + `Controls font aliasing method in the workbench. - default: Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text - antialiased: Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall - none: Disables font smoothing. Text will show with jagged sharp edges`), @@ -226,13 +308,13 @@ let properties: { [path: string]: IJSONSchema; } = { ], 'default': 'off', 'description': - nls.localize('openFilesInNewWindow', - `Controls if files should open in a new window. + nls.localize('openFilesInNewWindow', + `Controls if files should open in a new window. - default: files will open in the window with the files' folder open or the last active window unless opened via the dock or from finder (macOS only) - on: files will open in a new window - off: files will open in the window with the files' folder open or the last active window Note that there can still be cases where this setting is ignored (e.g. when using the -new-window or -reuse-window command line option).` - ) + ) }, 'window.openFoldersInNewWindow': { 'type': 'string', @@ -278,13 +360,13 @@ Note that there can still be cases where this setting is ignored (e.g. when usin 'default': isMacintosh ? '${activeEditorShort}${separator}${rootName}' : '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}', 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'], key: 'title' }, `Controls the window title based on the active editor. Variables are substituted based on the context: -\${activeEditorShort}: e.g. myFile.txt -\${activeEditorMedium}: e.g. myFolder/myFile.txt -\${activeEditorLong}: e.g. /Users/Development/myProject/myFolder/myFile.txt -\${folderName}: e.g. myFolder -\${folderPath}: e.g. /Users/Development/myFolder -\${rootName}: e.g. myFolder1, myFolder2, myFolder3 -\${rootPath}: e.g. /Users/Development/myWorkspace +\${activeEditorShort}: the file name (e.g. myFile.txt) +\${activeEditorMedium}: the path of the file relative to the workspace folder (e.g. myFolder/myFile.txt) +\${activeEditorLong}: the full path of the file (e.g. /Users/Development/myProject/myFolder/myFile.txt) +\${folderName}: name of the workspace folder the file is contained in (e.g. myFolder) +\${folderPath}: file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder) +\${rootName}: name of the workspace (e.g. myFolder or myWorkspace) +\${rootPath}: file path of the workspace (e.g. /Users/Development/myWorkspace) \${appName}: e.g. VS Code \${dirty}: a dirty indicator if the active editor is dirty \${separator}: a conditional separator (" - ") that only shows when surrounded by variables with values`) @@ -344,8 +426,8 @@ if (isMacintosh) { 'description': nls.localize('titleBarStyle', "Adjust the appearance of the window title bar. Changes require a full restart to apply.") }; - // macOS Sierra (10.12.x = darwin 16.x) and electron > 1.4.6 only - if (os.release().indexOf('16.') === 0 && process.versions.electron !== '1.4.6') { + // Minimum: macOS Sierra (10.12.x = darwin 16.x) + if (parseFloat(os.release()) >= 16) { properties['window.nativeTabs'] = { 'type': 'boolean', 'default': false, @@ -395,4 +477,4 @@ configurationRegistry.registerConfiguration({ 'description': nls.localize('zenMode.restore', "Controls if a window should restore to zen mode if it was exited in zen mode.") } } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 5fb7912d541..648c9992a64 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -16,13 +16,12 @@ import platform = require('vs/base/common/platform'); import paths = require('vs/base/common/paths'); import uri from 'vs/base/common/uri'; import strings = require('vs/base/common/strings'); -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { EmptyWorkspaceServiceImpl, WorkspaceServiceImpl, WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; +import { IWorkspaceContextService, Workspace, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { realpath, readFile, writeFile } from 'vs/base/node/pfs'; +import { realpath } from 'vs/base/node/pfs'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import path = require('path'); import gracefulFs = require('graceful-fs'); import { IInitData } from 'vs/workbench/services/timer/common/timerService'; import { TimerService } from 'vs/workbench/services/timer/node/timerService'; @@ -42,7 +41,6 @@ import { WorkspacesChannelClient } from 'vs/platform/workspaces/common/workspace import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { CredentialsChannelClient } from 'vs/platform/credentials/node/credentialsIpc'; -import { migrateStorageToMultiRootWorkspace } from 'vs/platform/storage/common/migration'; import fs = require('fs'); gracefulFs.gracefulify(fs); // enable gracefulFs @@ -60,7 +58,7 @@ export function startup(configuration: IWindowConfiguration): TPromise { browser.setFullscreen(!!configuration.fullscreen); - KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(configuration.isISOKeyboard); + KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(); browser.setAccessibilitySupport(configuration.accessibilitySupport ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled); @@ -80,8 +78,8 @@ function openWorkbench(configuration: IWindowConfiguration): TPromise { // Since the configuration service is one of the core services that is used in so many places, we initialize it // right before startup of the workbench shell to have its data ready for consumers return createAndInitializeWorkspaceService(configuration, environmentService, mainServices.get(IWorkspacesService)).then(workspaceService => { - const timerService = new TimerService((window).MonacoEnvironment.timers as IInitData, !workspaceService.hasWorkspace()); - const storageService = createStorageService(configuration, workspaceService, environmentService); + const timerService = new TimerService((window).MonacoEnvironment.timers as IInitData, workspaceService.getWorkbenchState() === WorkbenchState.EMPTY); + const storageService = createStorageService(workspaceService, environmentService); timerService.beforeDOMContentLoaded = Date.now(); @@ -112,51 +110,24 @@ function openWorkbench(configuration: IWindowConfiguration): TPromise { } function createAndInitializeWorkspaceService(configuration: IWindowConfiguration, environmentService: EnvironmentService, workspacesService: IWorkspacesService): TPromise { - return migrateWorkspaceId(configuration).then(() => { - return validateWorkspacePath(configuration).then(() => { - let workspaceService: WorkspaceServiceImpl | EmptyWorkspaceServiceImpl; - if (configuration.workspace || configuration.folderPath) { - workspaceService = new WorkspaceServiceImpl(configuration.workspace || configuration.folderPath, environmentService, workspacesService); - } else { - workspaceService = new EmptyWorkspaceServiceImpl(environmentService); - } + return validateSingleFolderPath(configuration).then(() => { + const workspaceService = new WorkspaceService(environmentService, workspacesService); - return workspaceService.initialize().then(() => workspaceService, error => new EmptyWorkspaceServiceImpl(environmentService)); - }); + return workspaceService.initialize(configuration.workspace || configuration.folderPath || configuration).then(() => workspaceService, error => workspaceService); }); } -// TODO@Ben migration -function migrateWorkspaceId(configuration: IWindowConfiguration): TPromise { - if (!configuration.workspace || !configuration.workspace.configPath) { - return TPromise.as(null); - } +function validateSingleFolderPath(configuration: IWindowConfiguration): TPromise { - return readFile(configuration.workspace.configPath).then(data => { - try { - const raw = JSON.parse(data.toString()); - if (raw.id) { - const previousWorkspaceId = raw.id; - delete raw.id; - - migrateStorageToMultiRootWorkspace(uri.from({ path: previousWorkspaceId, scheme: 'root' }).toString(), configuration.workspace, window.localStorage); - - return writeFile(configuration.workspace.configPath, JSON.stringify(raw, null, '\t')); - } - } catch (error) { }; - - return void 0; - }).then(() => void 0, () => void 0); -} - -function validateWorkspacePath(configuration: IWindowConfiguration): TPromise { + // Return early if we do not have a single folder path if (!configuration.folderPath) { - return TPromise.as(null); + return TPromise.as(void 0); } + // Otherwise: use realpath to resolve symbolic links to the truth return realpath(configuration.folderPath).then(realFolderPath => { - // for some weird reason, node adds a trailing slash to UNC paths + // For some weird reason, node adds a trailing slash to UNC paths // we never ever want trailing slashes as our workspace path unless // someone opens root ("/"). // See also https://github.com/nodejs/io.js/issues/1765 @@ -164,42 +135,50 @@ function validateWorkspacePath(configuration: IWindowConfiguration): TPromise { - errors.onUnexpectedError(error); + if (configuration.verbose) { + errors.onUnexpectedError(error); + } - return null; // treat invalid paths as empty workspace + // Treat any error case as empty workbench case (no folder path) + return null; + + }).then(realFolderPathOrNull => { + + // Update config with real path if we have one + configuration.folderPath = realFolderPathOrNull; }); } -function createStorageService(configuration: IWindowConfiguration, workspaceService: IWorkspaceContextService, environmentService: IEnvironmentService): IStorageService { - const workspace = workspaceService.getWorkspace(); - +function createStorageService(workspaceService: IWorkspaceContextService, environmentService: IEnvironmentService): IStorageService { let workspaceId: string; let secondaryWorkspaceId: number; - // in multi root workspace mode we use the provided ID as key for workspace storage - if (workspaceService.hasMultiFolderWorkspace()) { - workspaceId = uri.from({ path: workspace.id, scheme: 'root' }).toString(); - } + switch (workspaceService.getWorkbenchState()) { - // in single folder mode we use the path of the opened folder as key for workspace storage - // the ctime is used as secondary workspace id to clean up stale UI state if necessary - else if (workspaceService.hasFolderWorkspace()) { - const legacyWorkspace = workspaceService.getLegacyWorkspace(); - workspaceId = legacyWorkspace.resource.toString(); - secondaryWorkspaceId = legacyWorkspace.ctime; - } + // in multi root workspace mode we use the provided ID as key for workspace storage + case WorkbenchState.WORKSPACE: + workspaceId = uri.from({ path: workspaceService.getWorkspace().id, scheme: 'root' }).toString(); + break; - // finaly, if we do not have a workspace open, we need to find another identifier for the window to store - // workspace UI state. if we have a backup path in the configuration we can use that because this - // will be a unique identifier per window that is stable between restarts as long as there are - // dirty files in the workspace. - // We use basename() to produce a short identifier, we do not need the full path. We use a custom - // scheme so that we can later distinguish these identifiers from the workspace one. - else if (configuration.backupPath) { - workspaceId = uri.from({ path: path.basename(configuration.backupPath), scheme: 'empty' }).toString(); + // in single folder mode we use the path of the opened folder as key for workspace storage + // the ctime is used as secondary workspace id to clean up stale UI state if necessary + case WorkbenchState.FOLDER: + const workspace: Workspace = workspaceService.getWorkspace(); + workspaceId = workspace.folders[0].uri.toString(); + secondaryWorkspaceId = workspace.ctime; + break; + + // finaly, if we do not have a workspace open, we need to find another identifier for the window to store + // workspace UI state. if we have a backup path in the configuration we can use that because this + // will be a unique identifier per window that is stable between restarts as long as there are + // dirty files in the workspace. + // We use basename() to produce a short identifier, we do not need the full path. We use a custom + // scheme so that we can later distinguish these identifiers from the workspace one. + case WorkbenchState.EMPTY: + workspaceId = workspaceService.getWorkspace().id; + break; } const disableStorage = !!environmentService.extensionTestsPath; // never keep any state when running extension tests! diff --git a/src/vs/workbench/electron-browser/nodeCachedDataManager.ts b/src/vs/workbench/electron-browser/nodeCachedDataManager.ts index 52d57348df6..5f5ac8e12d7 100644 --- a/src/vs/workbench/electron-browser/nodeCachedDataManager.ts +++ b/src/vs/workbench/electron-browser/nodeCachedDataManager.ts @@ -4,41 +4,21 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { join, basename } from 'path'; -import { readdir, rimraf, stat } from 'vs/base/node/pfs'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { basename } from 'path'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import product from 'vs/platform/node/product'; declare type OnNodeCachedDataArgs = [{ errorCode: string, path: string, detail?: string }, { path: string, length: number }]; declare const MonacoEnvironment: { onNodeCachedData: OnNodeCachedDataArgs[] }; export class NodeCachedDataManager { - private static _DataMaxAge = product.nameLong.indexOf('Insiders') >= 0 - ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week - : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months - - private _telemetryService: ITelemetryService; - private _environmentService: IEnvironmentService; - private _disposables: IDisposable[] = []; + private readonly _telemetryService: ITelemetryService; constructor( @ITelemetryService telemetryService: ITelemetryService, - @IEnvironmentService environmentService: IEnvironmentService ) { this._telemetryService = telemetryService; - this._environmentService = environmentService; - this._handleCachedDataInfo(); - this._manageCachedDataSoon(); - } - - dispose(): void { - this._disposables = dispose(this._disposables); } private _handleCachedDataInfo(): void { @@ -52,6 +32,12 @@ export class NodeCachedDataManager { // log each failure separately if (err) { + /* __GDPR__ + "cachedDataError" : { + "errorCode" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "path": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" } + } + */ this._telemetryService.publicLog('cachedDataError', { errorCode: err.errorCode, path: basename(err.path) @@ -60,6 +46,13 @@ export class NodeCachedDataManager { } // log summary + /* __GDPR__ + "cachedDataInfo" : { + "didRequestCachedData" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "didRejectCachedData": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "didProduceCachedData": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ this._telemetryService.publicLog('cachedDataInfo', { didRequestCachedData: Boolean(global.require.getConfig().nodeCachedDataDir), didRejectCachedData, @@ -69,42 +62,4 @@ export class NodeCachedDataManager { global.require.config({ onNodeCachedData: undefined }); delete MonacoEnvironment.onNodeCachedData; } - - private _manageCachedDataSoon(): void { - // Cached data is stored as user data and we run a cleanup task everytime - // the editor starts. The strategy is to delete all files that are older than - // 3 months - - const { nodeCachedDataDir } = this._environmentService; - if (!nodeCachedDataDir) { - return; - } - - let handle = setTimeout(() => { - handle = undefined; - - readdir(nodeCachedDataDir).then(entries => { - - const now = Date.now(); - const deletes = entries.map(entry => { - const path = join(nodeCachedDataDir, entry); - return stat(path).then(stats => { - const diff = now - stats.mtime.getTime(); - if (diff > NodeCachedDataManager._DataMaxAge) { - return rimraf(path); - } - return undefined; - }); - }); - - return TPromise.join(deletes); - - }).done(undefined, onUnexpectedError); - - }, 30 * 1000); - - this._disposables.push({ - dispose() { clearTimeout(handle); } - }); - } } diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index f6bec8be10f..6e281cbc3b5 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -8,7 +8,6 @@ import 'vs/css!./media/shell'; import * as nls from 'vs/nls'; -import { TPromise } from 'vs/base/common/winjs.base'; import * as platform from 'vs/base/common/platform'; import { Dimension, Builder, $ } from 'vs/base/browser/builder'; import dom = require('vs/base/browser/dom'); @@ -31,7 +30,7 @@ import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; import { ElectronWindow } from 'vs/workbench/electron-browser/window'; import { resolveWorkbenchCommonProperties, getOrCreateMachineId } from 'vs/platform/telemetry/node/workbenchCommonProperties'; import { machineIdIpcChannel } from 'vs/platform/telemetry/node/commonProperties'; -import { WorkspaceStats } from 'vs/workbench/services/telemetry/common/workspaceStats'; +import { WorkspaceStats } from 'vs/workbench/services/telemetry/node/workspaceStats'; import { IWindowsService, IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { WindowService } from 'vs/platform/windows/electron-browser/windowService'; import { MessageService } from 'vs/workbench/services/message/electron-browser/messageService'; @@ -63,13 +62,12 @@ import { ChoiceChannel } from 'vs/platform/message/common/messageIpc'; import { ISearchService } from 'vs/platform/search/common/search'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { CommandService } from 'vs/platform/commands/common/commandService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { ICrashReporterService, NullCrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService'; -import { CrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService'; +import { ICrashReporterService, NullCrashReporterService, CrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService'; import { NodeCachedDataManager } from 'vs/workbench/electron-browser/nodeCachedDataManager'; import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; @@ -91,6 +89,8 @@ import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollba import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax'; import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService'; import { IBroadcastService, BroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { HashService } from 'vs/workbench/services/hash/node/hashService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * Services that we require for the Shell @@ -164,21 +164,19 @@ export class WorkbenchShell { const [instantiationService, serviceCollection] = this.initServiceCollection(parent.getHTMLElement()); // Workbench - this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.configuration, serviceCollection); - this.workbench.startup({ - onWorkbenchStarted: (info: IWorkbenchStartedInfo) => { + this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.configuration, serviceCollection, this.lifecycleService); + try { + this.workbench.startup({ + onWorkbenchStarted: (info: IWorkbenchStartedInfo) => this.onWorkbenchStarted(info, instantiationService) + }); + } catch (error) { - // run workbench started logic - this.onWorkbenchStarted(info); + // Print out error + console.error(toErrorMessage(error, true)); - // start cached data manager - instantiationService.createInstance(NodeCachedDataManager); - - // Set lifecycle phase to `Runnning` so that other contributions - // can now do something - this.lifecycleService.phase = LifecyclePhase.Running; - } - }); + // Rethrow + throw error; + } // Window this.workbench.getInstantiationService().createInstance(ElectronWindow, this.container); @@ -188,24 +186,46 @@ export class WorkbenchShell { console.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.'); }, 10000); - this.workbench.joinCreation().then(() => { + this.lifecycleService.when(LifecyclePhase.Running).then(() => { clearTimeout(timeoutHandle); }); return workbenchContainer; } - private onWorkbenchStarted(info: IWorkbenchStartedInfo): void { + private onWorkbenchStarted(info: IWorkbenchStartedInfo, instantiationService: IInstantiationService): void { // Telemetry: workspace info const { filesToOpen, filesToCreate, filesToDiff } = this.configuration; + /* __GDPR__ + "workspaceLoad" : { + "userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" }, + "experiments": { "${inline}": [ "${IExperiments}" ] }, + "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workspaceLoad', { userAgent: navigator.userAgent, windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, - emptyWorkbench: !this.contextService.hasWorkspace(), - 'workbench.filesToOpen': filesToOpen && filesToOpen.length || void 0, - 'workbench.filesToCreate': filesToCreate && filesToCreate.length || void 0, - 'workbench.filesToDiff': filesToDiff && filesToDiff.length || void 0, + emptyWorkbench: this.contextService.getWorkbenchState() === WorkbenchState.EMPTY, + 'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0, + 'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0, + 'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0, customKeybindingsCount: info.customKeybindingsCount, theme: this.themeService.getColorTheme().id, language: platform.language, @@ -221,6 +241,13 @@ export class WorkbenchShell { this.timerService.restoreEditorsDuration = info.restoreEditorsDuration; this.timerService.restoreViewletDuration = info.restoreViewletDuration; this.extensionService.onReady().done(() => { + /* __GDPR__ + "startupTime" : { + "${include}": [ + "${IStartupMetrics}" + ] + } + */ this.telemetryService.publicLog('startupTime', this.timerService.startupMetrics); }); @@ -229,9 +256,17 @@ export class WorkbenchShell { workspaceStats.reportWorkspaceTags(this.configuration); workspaceStats.reportCloudStats(); + // Root Warning if ((platform.isLinux || platform.isMacintosh) && process.getuid() === 0) { this.messageService.show(Severity.Warning, nls.localize('runningAsRoot', "It is recommended not to run Code as 'root'.")); } + + // Start cached data manager + instantiationService.createInstance(NodeCachedDataManager); + + // Set lifecycle phase to `Runnning` so that other contributions + // can now do something + this.lifecycleService.phase = LifecyclePhase.Running; } private initServiceCollection(container: HTMLElement): [IInstantiationService, ServiceCollection] { @@ -264,20 +299,23 @@ export class WorkbenchShell { restoreFontInfo(this.storageService); readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getConfiguration('editor'), browser.getZoomLevel())); + // Hash + serviceCollection.set(IHashService, new SyncDescriptor(HashService)); + // Experiments this.experimentService = instantiationService.createInstance(ExperimentService); serviceCollection.set(IExperimentService, this.experimentService); // Telemetry this.sendMachineIdToMain(this.storageService); - if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !!product.enableTelemetry) { + if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender'))); const commit = product.commit; const version = pkg.version; const config: ITelemetryServiceConfig = { appender: new TelemetryAppenderClient(channel), - commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version), + commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version, this.environmentService.installSource), piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath] }; @@ -288,6 +326,12 @@ export class WorkbenchShell { const idleMonitor = new IdleMonitor(2 * 60 * 1000); // 2 minutes const listener = idleMonitor.onStatusChange(status => + /* __GDPR__ + "UserIdleStart" : {} + */ + /* __GDPR__ + "UserIdleStop" : {} + */ this.telemetryService.publicLog(status === UserStatus.Active ? TelemetryService.IDLE_STOP_EVENT_NAME : TelemetryService.IDLE_START_EVENT_NAME @@ -302,7 +346,7 @@ export class WorkbenchShell { disposables.push(configurationTelemetry(this.telemetryService, this.configurationService)); let crashReporterService = NullCrashReporterService; - if (product.crashReporter && product.hockeyApp) { + if (!this.environmentService.disableCrashReporter && product.crashReporter && product.hockeyApp) { crashReporterService = instantiationService.createInstance(CrashReporterService); } serviceCollection.set(ICrashReporterService, crashReporterService); @@ -434,10 +478,6 @@ export class WorkbenchShell { this.workbench.layout(); } - public joinCreation(): TPromise { - return this.workbench.joinCreation(); - } - public dispose(): void { // Workbench diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 0bef05ddb8e..ce9f81ed794 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -12,23 +12,21 @@ import errors = require('vs/base/common/errors'); import types = require('vs/base/common/types'); import { TPromise } from 'vs/base/common/winjs.base'; import arrays = require('vs/base/common/arrays'); +import objects = require('vs/base/common/objects'); import DOM = require('vs/base/browser/dom'); import Severity from 'vs/base/common/severity'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IAction, Action } from 'vs/base/common/actions'; -import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { AutoSaveConfiguration, IFileService } from 'vs/platform/files/common/files'; import { toResource } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IMessageService } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { IWindowsService, IWindowService, IWindowSettings, IPath, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest } from 'vs/platform/windows/common/windows'; +import { IWindowsService, IWindowService, IWindowSettings, IPath, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { IWorkbenchThemeService, VS_HC_THEME, VS_DARK_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; import * as browser from 'vs/base/browser/browser'; @@ -39,8 +37,14 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { Themable } from 'vs/workbench/common/theme'; import { ipcRenderer as ipc, webFrame } from 'electron'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ConfigurationTarget, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; +import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), null, true, () => document.execCommand('undo') && TPromise.as(true)), @@ -57,42 +61,57 @@ export class ElectronWindow extends Themable { private static AUTO_SAVE_SETTING = 'files.autoSave'; + private touchBarUpdater: RunOnceScheduler; + private touchBarMenu: IMenu; + private touchBarDisposables: IDisposable[]; + private lastInstalledTouchedBar: ICommandAction[][]; + + private previousConfiguredZoomLevel: number; + constructor( shellContainer: HTMLElement, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService, - @IPartService private partService: IPartService, @IWindowsService private windowsService: IWindowsService, @IWindowService private windowService: IWindowService, @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, @ITitleService private titleService: ITitleService, @IWorkbenchThemeService protected themeService: IWorkbenchThemeService, @IMessageService private messageService: IMessageService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @ICommandService private commandService: ICommandService, @IExtensionService private extensionService: IExtensionService, @IViewletService private viewletService: IViewletService, @IContextMenuService private contextMenuService: IContextMenuService, @IKeybindingService private keybindingService: IKeybindingService, - @IEnvironmentService private environmentService: IEnvironmentService, @ITelemetryService private telemetryService: ITelemetryService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @IFileService private fileService: IFileService, + @IMenuService private menuService: IMenuService, + @ILifecycleService private lifecycleService: ILifecycleService ) { super(themeService); + this.touchBarDisposables = []; + + this.touchBarUpdater = new RunOnceScheduler(() => this.doSetupTouchbar(), 300); + this.toUnbind.push(this.touchBarUpdater); + this.registerListeners(); - this.setup(); + this.create(); } private registerListeners(): void { // React to editor input changes - this.editorGroupService.onEditorsChanged(() => { - const file = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' }); + this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => { + // Represented File Name + const file = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' }); this.titleService.setRepresentedFilename(file ? file.fsPath : ''); - }); + + // Touch Bar + this.updateTouchbarMenu(); + })); // prevent opening a real URL inside the shell [DOM.EventType.DRAG_OVER, DOM.EventType.DROP].forEach(event => { @@ -101,28 +120,39 @@ export class ElectronWindow extends Themable { }); }); - // Handle window.open() calls - const $this = this; - (window).open = function (url: string, target: string, features: string, replace: boolean): any { - $this.windowsService.openExternal(url); - - return null; - }; - } - - private setup(): void { - // Support runAction event - ipc.on('vscode:runAction', (event, actionId: string) => { - this.commandService.executeCommand(actionId, { from: 'menu' }).done(_ => { - this.telemetryService.publicLog('commandExecuted', { id: actionId, from: 'menu' }); + ipc.on('vscode:runAction', (_event: any, request: IRunActionInWindowRequest) => { + const args: any[] = []; + + // If we run an action from the touchbar, we fill in the currently active resource + // as payload because the touch bar items are context aware depending on the editor + if (request.from === 'touchbar') { + const activeEditor = this.editorService.getActiveEditor(); + if (activeEditor) { + const resource = toResource(activeEditor.input, { supportSideBySide: true }); + if (resource) { + args.push(resource); + } + } + } else { + args.push({ from: request.from }); // TODO@telemetry this is a bit weird to send this to every action? + } + + this.commandService.executeCommand(request.id, ...args).done(_ => { + /* __GDPR__ + "commandExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('commandExecuted', { id: request.id, from: request.from }); }, err => { this.messageService.show(Severity.Error, err); }); }); // Support resolve keybindings event - ipc.on('vscode:resolveKeybindings', (event, rawActionIds: string) => { + ipc.on('vscode:resolveKeybindings', (_event: any, rawActionIds: string) => { let actionIds: string[] = []; try { actionIds = JSON.parse(rawActionIds); @@ -138,12 +168,7 @@ export class ElectronWindow extends Themable { }, () => errors.onUnexpectedError); }); - // Send over all extension viewlets when extensions are ready - this.extensionService.onReady().then(() => { - ipc.send('vscode:extensionViewlets', JSON.stringify(this.viewletService.getViewlets().filter(v => !!v.extensionId).map(v => { return { id: v.id, label: v.name }; }))); - }); - - ipc.on('vscode:reportError', (event, error) => { + ipc.on('vscode:reportError', (_event: any, error: string) => { if (error) { const errorParsed = JSON.parse(error); errorParsed.mainProcess = true; @@ -152,114 +177,200 @@ export class ElectronWindow extends Themable { }); // Support openFiles event for existing and new files - ipc.on('vscode:openFiles', (event, request: IOpenFileRequest) => this.onOpenFiles(request)); + ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => this.onOpenFiles(request)); // Support addFolders event if we have a workspace opened - ipc.on('vscode:addFolders', (event, request: IAddFoldersRequest) => this.onAddFolders(request)); - - // Emit event when vscode has loaded - this.partService.joinCreation().then(() => { - ipc.send('vscode:workbenchLoaded', this.windowService.getCurrentWindowId()); - }); + ipc.on('vscode:addFolders', (_event: any, request: IAddFoldersRequest) => this.onAddFolders(request)); // Message support - ipc.on('vscode:showInfoMessage', (event, message: string) => { + ipc.on('vscode:showInfoMessage', (_event: any, message: string) => { this.messageService.show(Severity.Info, message); }); // Support toggling auto save - ipc.on('vscode.toggleAutoSave', event => { + ipc.on('vscode.toggleAutoSave', () => { this.toggleAutoSave(); }); // Fullscreen Events - ipc.on('vscode:enterFullScreen', event => { - this.partService.joinCreation().then(() => { + ipc.on('vscode:enterFullScreen', () => { + this.lifecycleService.when(LifecyclePhase.Running).then(() => { browser.setFullscreen(true); }); }); - ipc.on('vscode:leaveFullScreen', event => { - this.partService.joinCreation().then(() => { + ipc.on('vscode:leaveFullScreen', () => { + this.lifecycleService.when(LifecyclePhase.Running).then(() => { browser.setFullscreen(false); }); }); // High Contrast Events - ipc.on('vscode:enterHighContrast', event => { + ipc.on('vscode:enterHighContrast', () => { const windowConfig = this.configurationService.getConfiguration('window'); if (windowConfig && windowConfig.autoDetectHighContrast) { - this.partService.joinCreation().then(() => { + this.lifecycleService.when(LifecyclePhase.Running).then(() => { this.themeService.setColorTheme(VS_HC_THEME, null); }); } }); - ipc.on('vscode:leaveHighContrast', event => { + ipc.on('vscode:leaveHighContrast', () => { const windowConfig = this.configurationService.getConfiguration('window'); if (windowConfig && windowConfig.autoDetectHighContrast) { - this.partService.joinCreation().then(() => { + this.lifecycleService.when(LifecyclePhase.Running).then(() => { this.themeService.setColorTheme(VS_DARK_THEME, null); }); } }); // keyboard layout changed event - ipc.on('vscode:keyboardLayoutChanged', (event, isISOKeyboard: boolean) => { - KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(isISOKeyboard); + ipc.on('vscode:keyboardLayoutChanged', () => { + KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(); }); // keyboard layout changed event - ipc.on('vscode:accessibilitySupportChanged', (event, accessibilitySupportEnabled: boolean) => { + ipc.on('vscode:accessibilitySupportChanged', (_event: any, accessibilitySupportEnabled: boolean) => { browser.setAccessibilitySupport(accessibilitySupportEnabled ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled); }); // Configuration changes - let previousConfiguredZoomLevel: number; - this.configurationService.onDidUpdateConfiguration(e => { - const windowConfig: IWindowsConfiguration = this.configurationService.getConfiguration(); - - let newZoomLevel = 0; - if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') { - newZoomLevel = windowConfig.window.zoomLevel; - - // Leave early if the configured zoom level did not change (https://github.com/Microsoft/vscode/issues/1536) - if (previousConfiguredZoomLevel === newZoomLevel) { - return; - } - - previousConfiguredZoomLevel = newZoomLevel; - } - - if (webFrame.getZoomLevel() !== newZoomLevel) { - webFrame.setZoomLevel(newZoomLevel); - browser.setZoomFactor(webFrame.getZoomFactor()); - // See https://github.com/Microsoft/vscode/issues/26151 - // Cannot be trusted because the webFrame might take some time - // until it really applies the new zoom level - browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false); - } - }); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onDidUpdateConfiguration(e))); // Context menu support in input/textarea - window.document.addEventListener('contextmenu', e => { - if (e.target instanceof HTMLElement) { - const target = e.target; - if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) { - e.preventDefault(); - e.stopPropagation(); + window.document.addEventListener('contextmenu', e => this.onContextMenu(e)); + } - this.contextMenuService.showContextMenu({ - getAnchor: () => e, - getActions: () => TPromise.as(TextInputActions) - }); - } + private onContextMenu(e: PointerEvent): void { + if (e.target instanceof HTMLElement) { + const target = e.target; + if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) { + e.preventDefault(); + e.stopPropagation(); + + this.contextMenuService.showContextMenu({ + getAnchor: () => e, + getActions: () => TPromise.as(TextInputActions) + }); } + } + } + + private onDidUpdateConfiguration(event: IConfigurationChangeEvent): void { + if (!event.affectsConfiguration('window.zoomLevel')) { + return; + } + + const windowConfig: IWindowsConfiguration = this.configurationService.getConfiguration(); + + let newZoomLevel = 0; + if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') { + newZoomLevel = windowConfig.window.zoomLevel; + + // Leave early if the configured zoom level did not change (https://github.com/Microsoft/vscode/issues/1536) + if (this.previousConfiguredZoomLevel === newZoomLevel) { + return; + } + + this.previousConfiguredZoomLevel = newZoomLevel; + } + + if (webFrame.getZoomLevel() !== newZoomLevel) { + webFrame.setZoomLevel(newZoomLevel); + browser.setZoomFactor(webFrame.getZoomFactor()); + // See https://github.com/Microsoft/vscode/issues/26151 + // Cannot be trusted because the webFrame might take some time + // until it really applies the new zoom level + browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false); + } + } + + private create(): void { + + // Handle window.open() calls + const $this = this; + (window).open = function (url: string, target: string, features: string, replace: boolean): any { + $this.windowsService.openExternal(url); + + return null; + }; + + // Send over all extension viewlets when extensions are ready + this.extensionService.onReady().then(() => { + ipc.send('vscode:extensionViewlets', JSON.stringify(this.viewletService.getViewlets().filter(v => !!v.extensionId).map(v => { return { id: v.id, label: v.name }; }))); }); + + // Emit event when vscode has loaded + this.lifecycleService.when(LifecyclePhase.Running).then(() => { + ipc.send('vscode:workbenchLoaded', this.windowService.getCurrentWindowId()); + }); + + // Touchbar Support + this.updateTouchbarMenu(); + } + + private updateTouchbarMenu(): void { + if (!platform.isMacintosh) { + return; // macOS only + } + + // Dispose old + this.touchBarDisposables = dispose(this.touchBarDisposables); + + // Create new + this.touchBarMenu = this.editorGroupService.invokeWithinEditorContext(accessor => this.menuService.createMenu(MenuId.TouchBarContext, accessor.get(IContextKeyService))); + this.touchBarDisposables.push(this.touchBarMenu); + this.touchBarDisposables.push(this.touchBarMenu.onDidChange(() => { + this.scheduleSetupTouchbar(); + })); + + this.scheduleSetupTouchbar(); + } + + private scheduleSetupTouchbar(): void { + this.touchBarUpdater.schedule(); + } + + private doSetupTouchbar(): void { + const actions: (MenuItemAction | Separator)[] = []; + + // Fill actions into groups respecting order + fillInActions(this.touchBarMenu, void 0, actions); + + // Convert into command action multi array + const items: ICommandAction[][] = []; + let group: ICommandAction[] = []; + for (let i = 0; i < actions.length; i++) { + const action = actions[i]; + + // Command + if (action instanceof MenuItemAction) { + group.push(action.item); + } + + // Separator + else if (action instanceof Separator) { + if (group.length) { + items.push(group); + } + + group = []; + } + } + + if (group.length) { + items.push(group); + } + + // Only update if the actions have changed + if (!objects.equals(this.lastInstalledTouchedBar, items)) { + this.lastInstalledTouchedBar = items; + this.windowService.updateTouchBar(items); + } } private resolveKeybindings(actionIds: string[]): TPromise<{ id: string; label: string, isNative: boolean; }[]> { - return TPromise.join([this.partService.joinCreation(), this.extensionService.onReady()]).then(() => { + return TPromise.join([this.lifecycleService.when(LifecyclePhase.Running), this.extensionService.onReady()]).then(() => { return arrays.coalesce(actionIds.map(id => { const binding = this.keybindingService.lookupKeybinding(id); if (!binding) { @@ -284,33 +395,14 @@ export class ElectronWindow extends Themable { } private onAddFolders(request: IAddFoldersRequest): void { - const foldersToAdd = request.foldersToAdd.map(folderToAdd => URI.file(folderToAdd.filePath)); + const foldersToAdd = request.foldersToAdd.map(folderToAdd => ({ uri: URI.file(folderToAdd.filePath) })); - // Workspace: just add to workspace config - if (this.contextService.hasMultiFolderWorkspace()) { - this.workspaceEditingService.addRoots(foldersToAdd).done(null, errors.onUnexpectedError); - } - - // Single folder or no workspace: create workspace and open - else { - let workspaceFolders: URI[] = []; - - // Folder of workspace is the first of multi root workspace, so add it - if (this.contextService.hasFolderWorkspace()) { - workspaceFolders.push(...this.contextService.getWorkspace().roots); - } - - // Fill in remaining ones from request - workspaceFolders.push(...request.foldersToAdd.map(folderToAdd => URI.file(folderToAdd.filePath))); - - // Create workspace and open (ensure no duplicates) - this.windowService.createAndOpenWorkspace(arrays.distinct(workspaceFolders.map(folder => folder.fsPath), folder => platform.isLinux ? folder : folder.toLowerCase())); - } + this.workspaceEditingService.addFolders(foldersToAdd).done(null, errors.onUnexpectedError); } private onOpenFiles(request: IOpenFileRequest): void { - let inputs: IResourceInputType[] = []; - let diffMode = (request.filesToDiff.length === 2); + const inputs: IResourceInputType[] = []; + const diffMode = (request.filesToDiff.length === 2); if (!diffMode && request.filesToOpen) { inputs.push(...this.toInputs(request.filesToOpen, false)); @@ -325,13 +417,27 @@ export class ElectronWindow extends Themable { } if (inputs.length) { - this.openResources(inputs, diffMode).done(null, errors.onUnexpectedError); + this.openResources(inputs, diffMode).then(null, errors.onUnexpectedError); + } + + if (request.filesToWait && inputs.length) { + // In wait mode, listen to changes to the editors and wait until the files + // are closed that the user wants to wait for. When this happens we delete + // the wait marker file to signal to the outside that editing is done. + const resourcesToWaitFor = request.filesToWait.paths.map(p => URI.file(p.filePath)); + const waitMarkerFile = URI.file(request.filesToWait.waitMarkerFilePath); + const stacks = this.editorGroupService.getStacksModel(); + const unbind = stacks.onEditorClosed(() => { + if (resourcesToWaitFor.every(r => !stacks.isOpen(r))) { + unbind.dispose(); + this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError); + } + }); } } - private openResources(resources: (IResourceInput | IUntitledResourceInput)[], diffMode: boolean): TPromise { - return this.partService.joinCreation().then((): TPromise => { - + private openResources(resources: (IResourceInput | IUntitledResourceInput)[], diffMode: boolean): Thenable { + return this.lifecycleService.when(LifecyclePhase.Running).then((): TPromise => { // In diffMode we open 2 resources as diff if (diffMode && resources.length === 2) { @@ -376,7 +482,7 @@ export class ElectronWindow extends Themable { } private toggleAutoSave(): void { - const setting = this.configurationService.lookup(ElectronWindow.AUTO_SAVE_SETTING); + const setting = this.configurationService.inspect(ElectronWindow.AUTO_SAVE_SETTING); let userAutoSaveConfig = setting.user; if (types.isUndefinedOrNull(userAutoSaveConfig)) { userAutoSaveConfig = setting.default; // use default if setting not defined @@ -389,6 +495,12 @@ export class ElectronWindow extends Themable { newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; } - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ElectronWindow.AUTO_SAVE_SETTING, value: newAutoSaveValue }); + this.configurationService.updateValue(ElectronWindow.AUTO_SAVE_SETTING, newAutoSaveValue, ConfigurationTarget.USER); + } + + public dispose(): void { + this.touchBarDisposables = dispose(this.touchBarDisposables); + + super.dispose(); } } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 36578b66d2e..bc7cac8d8da 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -8,25 +8,23 @@ import 'vs/css!./media/workbench'; import { localize } from 'vs/nls'; -import { TPromise, ValueCallback } from 'vs/base/common/winjs.base'; +import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Event, { Emitter, chain } from 'vs/base/common/event'; import DOM = require('vs/base/browser/dom'); import { Builder, $ } from 'vs/base/browser/builder'; import { Delayer, RunOnceScheduler } from 'vs/base/common/async'; import * as browser from 'vs/base/browser/browser'; -import assert = require('vs/base/common/assert'); import { StopWatch } from 'vs/base/common/stopwatch'; -import { startTimer } from 'vs/base/node/startupTimers'; +import { time } from 'vs/base/common/performance'; import errors = require('vs/base/common/errors'); import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Registry } from 'vs/platform/registry/common/platform'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { Position as EditorPosition, IResourceDiffInput, IUntitledResourceInput, IEditor, IResourceInput } from 'vs/platform/editor/common/editor'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; +import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { HistoryService } from 'vs/workbench/services/history/browser/history'; import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart'; import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; @@ -39,26 +37,22 @@ import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbe import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; import { getServices } from 'vs/platform/instantiation/common/extensions'; -import { WorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; -import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; +import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IActivityBarService } from 'vs/workbench/services/activity/common/activityBarService'; +import { IActivityService } from 'vs/workbench/services/activity/common/activity'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService'; -// import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; import { IFileService } from 'vs/platform/files/common/files'; import { IListService, ListService } from 'vs/platform/list/browser/listService'; @@ -67,7 +61,7 @@ import { ConfigurationResolverService } from 'vs/workbench/services/configuratio import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService'; -import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, IResourceInputType, WorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; @@ -84,7 +78,8 @@ import { ProgressService2 } from 'vs/workbench/services/progress/browser/progres import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILifecycleService, ShutdownReason, ShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; +import { ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { LifecycleService } from 'vs/workbench/services/lifecycle/electron-browser/lifecycleService'; import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration, IPath } from 'vs/platform/windows/common/windows'; import { IMessageService } from 'vs/platform/message/common/message'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; @@ -92,21 +87,20 @@ import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/a import { MenuService } from 'vs/platform/actions/common/menuService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; -import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, inRecentFilesPickerContextKey } from 'vs/workbench/electron-browser/actions'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar } from 'vs/workbench/electron-browser/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { getQuickNavigateHandler, inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickopen'; -import { IWorkspaceEditingService, IWorkspaceMigrationService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService'; +import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; +import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; +import { ActivityService } from 'vs/workbench/services/activity/browser/activityService'; import URI from 'vs/base/common/uri'; -import { isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { WorkspaceMigrationService } from 'vs/workbench/services/workspace/node/workspaceMigrationService'; export const MessagesVisibleContext = new RawContextKey('globalMessageVisible', false); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); export const InZenModeContext = new RawContextKey('inZenMode', false); +export const SidebarVisibleContext = new RawContextKey('sidebarVisible', false); export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated(); interface WorkbenchParams { @@ -157,6 +151,7 @@ export class Workbench implements IPartService { private static zenModeActiveSettingKey = 'workbench.zenmode.active'; private static sidebarPositionConfigurationKey = 'workbench.sideBar.location'; + private static panelPositionConfigurationKey = 'workbench.panel.location'; private static statusbarVisibleConfigurationKey = 'workbench.statusBar.visible'; private static activityBarVisibleConfigurationKey = 'workbench.activityBar.visible'; @@ -181,8 +176,7 @@ export class Workbench implements IPartService { private contextKeyService: IContextKeyService; private keybindingService: IKeybindingService; private backupFileService: IBackupFileService; - private configurationEditingService: IConfigurationEditingService; - private workspaceMigrationService: WorkspaceMigrationService; + private fileService: IFileService; private titlebarPart: TitlebarPart; private activitybarPart: ActivitybarPart; private sidebarPart: SidebarPart; @@ -194,18 +188,18 @@ export class Workbench implements IPartService { private toDispose: IDisposable[]; private toShutdown: { shutdown: () => void; }[]; private callbacks: IWorkbenchCallbacks; - private creationPromise: TPromise; - private creationPromiseComplete: ValueCallback; private sideBarHidden: boolean; private statusBarHidden: boolean; private activityBarHidden: boolean; private sideBarPosition: Position; + private panelPosition: Position; private panelHidden: boolean; private editorBackgroundDelayer: Delayer; private closeEmptyWindowScheduler: RunOnceScheduler; private messagesVisibleContext: IContextKey; private editorsVisibleContext: IContextKey; private inZenMode: IContextKey; + private sideBarVisibleContext: IContextKey; private hasFilesToCreateOpenOrDiff: boolean; private fontAliasing: string; private zenMode: { @@ -220,13 +214,12 @@ export class Workbench implements IPartService { container: HTMLElement, configuration: IWindowConfiguration, serviceCollection: ServiceCollection, + private lifecycleService: LifecycleService, @IInstantiationService private instantiationService: IInstantiationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IStorageService private storageService: IStorageService, - @ILifecycleService private lifecycleService: ILifecycleService, @IMessageService private messageService: IMessageService, @IConfigurationService private configurationService: WorkspaceService, - @ITelemetryService private telemetryService: ITelemetryService, @IEnvironmentService private environmentService: IEnvironmentService, @IWindowService private windowService: IWindowService ) { @@ -250,10 +243,6 @@ export class Workbench implements IPartService { this.closeEmptyWindowScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50); this._onTitleBarVisibilityChange = new Emitter(); - - this.creationPromise = new TPromise(c => { - this.creationPromiseComplete = c; - }); } public get onTitleBarVisibilityChange(): Event { @@ -271,135 +260,134 @@ export class Workbench implements IPartService { * once. Use the shutdown function to free up resources created by the workbench on startup. */ public startup(callbacks?: IWorkbenchCallbacks): void { - assert.ok(!this.workbenchStarted, 'Can not start a workbench that was already started'); - assert.ok(!this.workbenchShutdown, 'Can not start a workbench that was shutdown'); + this.workbenchStarted = true; + this.callbacks = callbacks; - try { - this.workbenchStarted = true; - this.callbacks = callbacks; + // Create Workbench + this.createWorkbench(); - // Create Workbench - this.createWorkbench(); + // Install some global actions + this.createGlobalActions(); - // Install some global actions - this.createGlobalActions(); + // Services + this.initServices(); + if (this.callbacks && this.callbacks.onServicesCreated) { + this.callbacks.onServicesCreated(); + } - // Services - this.initServices(); - if (this.callbacks && this.callbacks.onServicesCreated) { - this.callbacks.onServicesCreated(); + // Contexts + this.messagesVisibleContext = MessagesVisibleContext.bindTo(this.contextKeyService); + this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService); + this.inZenMode = InZenModeContext.bindTo(this.contextKeyService); + this.sideBarVisibleContext = SidebarVisibleContext.bindTo(this.contextKeyService); + + // Register Listeners + this.registerListeners(); + + // Settings + this.initSettings(); + + // Create Workbench and Parts + this.renderWorkbench(); + + // Workbench Layout + this.createWorkbenchLayout(); + + // Restore Parts + this.restoreParts().done(startedInfo => { + this.workbenchCreated = true; + + if (this.callbacks && this.callbacks.onWorkbenchStarted) { + this.callbacks.onWorkbenchStarted(startedInfo); + } + }); + } + + private restoreParts(): TPromise { + const restorePromises: TPromise[] = []; + + // Restore Editors + const editorRestoreStopWatch = StopWatch.create(); + const editorRestoreClock = time('restore:editors'); + const restoredEditors: string[] = []; + restorePromises.push(this.resolveEditorsToOpen().then(inputs => { + this.lifecycleService.phase = LifecyclePhase.Restoring; + + let editorOpenPromise: TPromise; + if (inputs.length) { + editorOpenPromise = this.editorService.openEditors(inputs.map(input => { return { input, position: EditorPosition.ONE }; })); + } else { + editorOpenPromise = this.editorPart.restoreEditors(); } - // Contexts - this.messagesVisibleContext = MessagesVisibleContext.bindTo(this.contextKeyService); - this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService); - this.inZenMode = InZenModeContext.bindTo(this.contextKeyService); + return editorOpenPromise.then(editors => { + this.handleEditorBackground(); // make sure we show the proper background in the editor area - // Register Listeners - this.registerListeners(); + editorRestoreClock.stop(); + editorRestoreStopWatch.stop(); - // Settings - this.initSettings(); - - // Create Workbench and Parts - this.renderWorkbench(); - - // Workbench Layout - this.createWorkbenchLayout(); - - // Load composites and editors in parallel - const compositeAndEditorPromises: TPromise[] = []; - - // Restore last opened viewlet - let viewletRestoreStopWatch: StopWatch; - let viewletIdToRestore: string; - if (!this.sideBarHidden) { - - if (this.shouldRestoreLastOpenedViewlet()) { - viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); - } - - if (!viewletIdToRestore) { - viewletIdToRestore = this.viewletService.getDefaultViewletId(); - } - - viewletRestoreStopWatch = StopWatch.create(); - const viewletTimer = startTimer('restore:viewlet'); - compositeAndEditorPromises.push(viewletTimer.while(this.viewletService.openViewlet(viewletIdToRestore)).then(() => { - viewletRestoreStopWatch.stop(); - })); - } - - // Load Panel - const panelRegistry = Registry.as(PanelExtensions.Panels); - const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId()); - if (!this.panelHidden && !!panelId) { - compositeAndEditorPromises.push(this.panelPart.openPanel(panelId, false)); - } - - // Load Editors - const editorRestoreStopWatch = StopWatch.create(); - const restoredEditors: string[] = []; - const editorsTimer = startTimer('restore:editors'); - compositeAndEditorPromises.push(editorsTimer.while(this.resolveEditorsToOpen().then(inputs => { - let editorOpenPromise: TPromise; - if (inputs.length) { - editorOpenPromise = this.editorService.openEditors(inputs.map(input => { return { input, position: EditorPosition.ONE }; })); - } else { - editorOpenPromise = this.editorPart.restoreEditors(); - } - - return editorOpenPromise.then(editors => { - this.handleEditorBackground(); // make sure we show the proper background in the editor area - editorRestoreStopWatch.stop(); - - for (const editor of editors) { - if (editor) { - if (editor.input) { - restoredEditors.push(editor.input.getName()); - } else { - restoredEditors.push(`other:${editor.getId()}`); - } + for (const editor of editors) { + if (editor) { + if (editor.input) { + restoredEditors.push(editor.input.getName()); + } else { + restoredEditors.push(`other:${editor.getId()}`); } } - }); - }))); + } + }); + })); - if (this.storageService.getBoolean(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE, false)) { - this.toggleZenMode(true); + // Restore Sidebar + let viewletRestoreStopWatch: StopWatch; + let viewletIdToRestore: string; + if (!this.sideBarHidden) { + this.sideBarVisibleContext.set(true); + + if (this.shouldRestoreLastOpenedViewlet()) { + viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); } - // Flag workbench as created once done - const workbenchDone = (error?: Error) => { - this.workbenchCreated = true; - this.creationPromiseComplete(true); + if (!viewletIdToRestore) { + viewletIdToRestore = this.viewletService.getDefaultViewletId(); + } - if (this.callbacks && this.callbacks.onWorkbenchStarted) { - this.callbacks.onWorkbenchStarted({ - customKeybindingsCount: this.keybindingService.customKeybindingsCount(), - restoreViewletDuration: viewletRestoreStopWatch ? Math.round(viewletRestoreStopWatch.elapsed()) : 0, - restoreEditorsDuration: Math.round(editorRestoreStopWatch.elapsed()), - pinnedViewlets: this.activitybarPart.getPinned(), - restoredViewlet: viewletIdToRestore, - restoredEditors - }); - } - - if (error) { - errors.onUnexpectedError(error); - } - }; - - // Join viewlet, panel and editor promises - TPromise.join(compositeAndEditorPromises).then(() => workbenchDone(), error => workbenchDone(error)); - } catch (error) { - - // Print out error - console.error(toErrorMessage(error, true)); - - // Rethrow - throw error; + viewletRestoreStopWatch = StopWatch.create(); + const viewletRestoreClock = time('restore:viewlet'); + restorePromises.push(this.viewletService.openViewlet(viewletIdToRestore).then(() => { + viewletRestoreStopWatch.stop(); + viewletRestoreClock.stop(); + })); } + + // Restore Panel + const panelRegistry = Registry.as(PanelExtensions.Panels); + const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId()); + if (!this.panelHidden && !!panelId) { + restorePromises.push(this.panelPart.openPanel(panelId, false)); + } + + // Restore Zen Mode if active + if (this.storageService.getBoolean(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE, false)) { + this.toggleZenMode(true); + } + + const onRestored = (error?: Error): IWorkbenchStartedInfo => { + if (error) { + errors.onUnexpectedError(error); + } + + return { + customKeybindingsCount: this.keybindingService.customKeybindingsCount(), + restoreViewletDuration: viewletRestoreStopWatch ? Math.round(viewletRestoreStopWatch.elapsed()) : 0, + restoreEditorsDuration: Math.round(editorRestoreStopWatch.elapsed()), + pinnedViewlets: this.activitybarPart.getPinned(), + restoredViewlet: viewletIdToRestore, + restoredEditors + }; + }; + + return TPromise.join(restorePromises).then(() => onRestored(), error => onRestored(error)); } private createGlobalActions(): void { @@ -411,38 +399,25 @@ export class Workbench implements IPartService { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } } : void 0), 'Developer: Toggle Developer Tools', localize('developer', "Developer")); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: isDeveloping ? null : KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', localize('file', "File")); - const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey)); - - const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker'; - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: quickOpenNavigateNextInRecentFilesPickerId, - weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50), - handler: getQuickNavigateHandler(quickOpenNavigateNextInRecentFilesPickerId, true), - when: recentFilesPickerContext, - primary: KeyMod.CtrlCmd | KeyCode.KEY_R, - mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } - }); - - const quickOpenNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker'; - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: quickOpenNavigatePreviousInRecentFilesPicker, - weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50), - handler: getQuickNavigateHandler(quickOpenNavigatePreviousInRecentFilesPicker, false), - when: recentFilesPickerContext, - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R, - mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R } - }); + // Actions for macOS native tabs management (only when enabled) + const windowConfig = this.configurationService.getConfiguration(); + if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab'); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab'); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveWindowTabToNewWindow, MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL), 'Move Window Tab to New Window'); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(MergeAllWindowTabs, MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL), 'Merge All Windows'); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWindowTabsBar, ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL), 'Toggle Window Tabs Bar'); + } } private resolveEditorsToOpen(): TPromise { + const config = this.workbenchParams.configuration; // Files to open, diff or create if (this.hasFilesToCreateOpenOrDiff) { - const filesToCreate = this.toInputs(this.workbenchParams.configuration.filesToCreate); - const filesToOpen = this.toInputs(this.workbenchParams.configuration.filesToOpen); - const filesToDiff = this.toInputs(this.workbenchParams.configuration.filesToDiff); // Files to diff is exclusive + const filesToDiff = this.toInputs(config.filesToDiff, false); if (filesToDiff && filesToDiff.length === 2) { return TPromise.as([{ leftResource: filesToDiff[0].resource, @@ -451,21 +426,15 @@ export class Workbench implements IPartService { }]); } - // Otherwise: Open/Create files - else { - const filesToCreateInputs: IUntitledResourceInput[] = filesToCreate.map(resourceInput => { - return { - filePath: resourceInput.resource.fsPath, - options: { pinned: true } - }; - }); + const filesToCreate = this.toInputs(config.filesToCreate, true); + const filesToOpen = this.toInputs(config.filesToOpen, false); - return TPromise.as([].concat(filesToOpen).concat(filesToCreateInputs)); - } + // Otherwise: Open/Create files + return TPromise.as([...filesToOpen, ...filesToCreate]); } // Empty workbench - else if (!this.contextService.hasWorkspace() && this.openUntitledFile()) { + else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) { if (this.editorPart.hasEditorsToRestore()) { return TPromise.as([]); // do not open any empty untitled file if we have editors to restore } @@ -482,20 +451,21 @@ export class Workbench implements IPartService { return TPromise.as([]); } - private toInputs(paths?: IPath[]): IResourceInput[] { + private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] { if (!paths || !paths.length) { return []; } return paths.map(p => { - const input = {}; - input.resource = URI.file(p.filePath); + const resource = URI.file(p.filePath); + let input: IResourceInput | IUntitledResourceInput; + if (isNew) { + input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput; + } else { + input = { resource, options: { pinned: true } } as IResourceInput; + } - input.options = { - pinned: true // opening on startup is always pinned and not preview - }; - - if (p.lineNumber) { + if (!isNew && p.lineNumber) { input.options.selection = { startLineNumber: p.lineNumber, startColumn: p.columnNumber @@ -507,13 +477,13 @@ export class Workbench implements IPartService { } private openUntitledFile() { - const startupEditor = this.configurationService.lookup('workbench.startupEditor'); + const startupEditor = this.configurationService.inspect('workbench.startupEditor'); // Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined if (!startupEditor.user && !startupEditor.workspace) { - const welcomeEnabled = this.configurationService.lookup('workbench.welcome.enabled'); - if (typeof welcomeEnabled.value === 'boolean') { - return !welcomeEnabled.value; + const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled'); + if (typeof welcomeEnabledValue === 'boolean') { + return !welcomeEnabledValue; } } @@ -523,7 +493,6 @@ export class Workbench implements IPartService { private initServices(): void { const { serviceCollection } = this.workbenchParams; - this.toDispose.push(this.lifecycleService.onWillShutdown(event => this.onWillShutdown(event))); this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this)); // Services we contribute @@ -576,7 +545,13 @@ export class Workbench implements IPartService { this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART); this.toDispose.push(this.activitybarPart); this.toShutdown.push(this.activitybarPart); - serviceCollection.set(IActivityBarService, this.activitybarPart); + const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart); + serviceCollection.set(IActivityService, activityService); + + // File Service + this.fileService = this.instantiationService.createInstance(RemoteFileService); + serviceCollection.set(IFileService, this.fileService); + this.toDispose.push(this.fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e))); // Editor service (editor part) this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff); @@ -592,11 +567,6 @@ export class Workbench implements IPartService { this.toShutdown.push(this.titlebarPart); serviceCollection.set(ITitleService, this.titlebarPart); - // File Service - const fileService = this.instantiationService.createInstance(RemoteFileService); - serviceCollection.set(IFileService, fileService); - this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e))); - // History serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService)); @@ -607,6 +577,9 @@ export class Workbench implements IPartService { // Text File Service serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService)); + // File Decorations + serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService)); + // SCM Service serviceCollection.set(ISCMService, new SyncDescriptor(SCMService)); @@ -617,10 +590,6 @@ export class Workbench implements IPartService { const jsonEditingService = this.instantiationService.createInstance(JSONEditingService); serviceCollection.set(IJSONEditingService, jsonEditingService); - // Configuration Editing - this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService); - serviceCollection.set(IConfigurationEditingService, this.configurationEditingService); - // Workspace Editing serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService)); @@ -630,10 +599,6 @@ export class Workbench implements IPartService { // Configuration Resolver serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env)); - // Workspace Migrating - this.workspaceMigrationService = this.instantiationService.createInstance(WorkspaceMigrationService); - serviceCollection.set(IWorkspaceMigrationService, this.workspaceMigrationService); - // Quick open service (quick open controller) this.quickOpen = this.instantiationService.createInstance(QuickOpenController); this.toDispose.push(this.quickOpen); @@ -649,13 +614,17 @@ export class Workbench implements IPartService { // Set the some services to registries that have been created eagerly Registry.as(ActionBarExtensions.Actionbar).setInstantiationService(this.instantiationService); Registry.as(WorkbenchExtensions.Workbench).setInstantiationService(this.instantiationService); - Registry.as(EditorExtensions.Editors).setInstantiationService(this.instantiationService); + Registry.as(EditorExtensions.EditorInputFactories).setInstantiationService(this.instantiationService); + + this.instantiationService.createInstance(DefaultConfigurationExportHelper); + + this.configurationService.setInstantiationService(this.getInstantiationService()); } private initSettings(): void { // Sidebar visibility - this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE, !this.contextService.hasWorkspace()); + this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY); // Panel part visibility const panelRegistry = Registry.as(PanelExtensions.Panels); @@ -665,19 +634,23 @@ export class Workbench implements IPartService { } // Sidebar position - const sideBarPosition = this.configurationService.lookup(Workbench.sidebarPositionConfigurationKey).value; + const sideBarPosition = this.configurationService.getValue(Workbench.sidebarPositionConfigurationKey); this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT; + // Panel position + const panelPosition = this.configurationService.getValue(Workbench.panelPositionConfigurationKey); + this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM; + // Statusbar visibility - const statusBarVisible = this.configurationService.lookup(Workbench.statusbarVisibleConfigurationKey).value; + const statusBarVisible = this.configurationService.getValue(Workbench.statusbarVisibleConfigurationKey); this.statusBarHidden = !statusBarVisible; // Activity bar visibility - const activityBarVisible = this.configurationService.lookup(Workbench.activityBarVisibleConfigurationKey).value; + const activityBarVisible = this.configurationService.getValue(Workbench.activityBarVisibleConfigurationKey); this.activityBarHidden = !activityBarVisible; // Font aliasing - this.fontAliasing = this.configurationService.lookup(Workbench.fontAliasingConfigurationKey).value; + this.fontAliasing = this.configurationService.getValue(Workbench.fontAliasingConfigurationKey); // Zen mode this.zenMode = { @@ -702,10 +675,6 @@ export class Workbench implements IPartService { return this.workbenchCreated && this.workbenchStarted; } - public joinCreation(): TPromise { - return this.creationPromise; - } - public hasFocus(part: Parts): boolean { const activeElement = document.activeElement; if (!activeElement) { @@ -815,6 +784,7 @@ export class Workbench implements IPartService { public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise { this.sideBarHidden = hidden; + this.sideBarVisibleContext.set(!hidden); // Adjust CSS if (hidden) { @@ -850,7 +820,7 @@ export class Workbench implements IPartService { return promise.then(() => { // Remember in settings - const defaultHidden = !this.contextService.hasWorkspace(); + const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY; if (hidden !== defaultHidden) { this.storageService.store(Workbench.sidebarHiddenSettingKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE); } else { @@ -924,7 +894,7 @@ export class Workbench implements IPartService { private setSideBarPosition(position: Position): void { if (this.sideBarHidden) { - this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError); + this.setSideBarHidden(false, true /* Skip Layout */).done(void 0, errors.onUnexpectedError); } const newPositionValue = (position === Position.LEFT) ? 'left' : 'right'; @@ -945,6 +915,30 @@ export class Workbench implements IPartService { this.workbenchLayout.layout(); } + public getPanelPosition(): Position { + return this.panelPosition; + } + + private setPanelPosition(position: Position): void { + if (this.panelHidden) { + this.setPanelHidden(false, true /* Skip Layout */).done(void 0, errors.onUnexpectedError); + } + + const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right'; + const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right'; + this.panelPosition = position; + + // Adjust CSS + this.panelPart.getContainer().removeClass(oldPositionValue); + this.panelPart.getContainer().addClass(newPositionValue); + + // Update Styles + this.panelPart.updateStyles(); + + // Layout + this.workbenchLayout.layout(); + } + private setFontAliasing(aliasing: string) { this.fontAliasing = aliasing; @@ -970,19 +964,6 @@ export class Workbench implements IPartService { } } - private onWillShutdown(event: ShutdownEvent): void { - - if (event.reason === ShutdownReason.RELOAD) { - const workspace = event.payload; - - // We are transitioning into a workspace from an empty workspace or workspace, and - // as such we want to migrate UI state from the current workspace to the new one. - if (isWorkspaceIdentifier(workspace)) { - event.veto(this.instantiationService.createInstance(WorkspaceMigrationService).migrate(workspace).then(() => false, () => false)); - } - } - } - private shutdownComponents(reason = ShutdownReason.QUIT): void { // Restore sidebar if we are being shutdown as a matter of a reload @@ -1008,6 +989,16 @@ export class Workbench implements IPartService { // Listen to editor changes this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged())); + // Listen to editor closing (if we run with --wait) + const filesToWait = this.workbenchParams.configuration.filesToWait; + if (filesToWait) { + const resourcesToWaitFor = filesToWait.paths.map(p => URI.file(p.filePath)); + const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath); + const listenerDispose = this.editorPart.getStacksModel().onEditorClosed(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile)); + + this.toDispose.push(listenerDispose); + } + // Handle message service and quick open events this.toDispose.push((this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true))); this.toDispose.push((this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset())); @@ -1016,7 +1007,7 @@ export class Workbench implements IPartService { this.toDispose.push(this.quickOpen.onHide(() => (this.messageService).resume())); // resume messages once quick open is closed again // Configuration changes - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.onDidUpdateConfiguration())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration())); // Fullscreen changes this.toDispose.push(browser.onDidChangeFullscreen(() => this.onFullscreenChanged())); @@ -1046,14 +1037,26 @@ export class Workbench implements IPartService { } } + private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void { + + // In wait mode, listen to changes to the editors and wait until the files + // are closed that the user wants to wait for. When this happens we delete + // the wait marker file to signal to the outside that editing is done. + const stacks = this.editorPart.getStacksModel(); + if (resourcesToWaitFor.every(r => !stacks.isOpen(r))) { + listenerDispose.dispose(); + this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError); + } + } + private onEditorsChanged(): void { const visibleEditors = this.editorService.getVisibleEditors().length; // Close when empty: check if we should close the window based on the setting // Overruled by: window has a workspace opened or this window is for extension development // or setting is disabled. Also enabled when running with --wait from the command line. - if (visibleEditors === 0 && !this.contextService.hasWorkspace() && !this.environmentService.isExtensionDevelopment) { - const closeWhenEmpty = this.configurationService.lookup(Workbench.closeWhenEmptyConfigurationKey).value; + if (visibleEditors === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) { + const closeWhenEmpty = this.configurationService.getValue(Workbench.closeWhenEmptyConfigurationKey); if (closeWhenEmpty || this.environmentService.args.wait) { this.closeEmptyWindowScheduler.schedule(); } @@ -1085,24 +1088,30 @@ export class Workbench implements IPartService { } private onDidUpdateConfiguration(skipLayout?: boolean): void { - const newSidebarPositionValue = this.configurationService.lookup(Workbench.sidebarPositionConfigurationKey).value; + const newSidebarPositionValue = this.configurationService.getValue(Workbench.sidebarPositionConfigurationKey); const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT; if (newSidebarPosition !== this.getSideBarPosition()) { this.setSideBarPosition(newSidebarPosition); } - const fontAliasing = this.configurationService.lookup(Workbench.fontAliasingConfigurationKey).value; + const newPanelPositionValue = this.configurationService.getValue(Workbench.panelPositionConfigurationKey); + const newPanelPosition = (newPanelPositionValue === 'right') ? Position.RIGHT : Position.BOTTOM; + if (newPanelPosition !== this.getPanelPosition()) { + this.setPanelPosition(newPanelPosition); + } + + const fontAliasing = this.configurationService.getValue(Workbench.fontAliasingConfigurationKey); if (fontAliasing !== this.fontAliasing) { this.setFontAliasing(fontAliasing); } if (!this.zenMode.active) { - const newStatusbarHiddenValue = !this.configurationService.lookup(Workbench.statusbarVisibleConfigurationKey).value; + const newStatusbarHiddenValue = !this.configurationService.getValue(Workbench.statusbarVisibleConfigurationKey); if (newStatusbarHiddenValue !== this.statusBarHidden) { this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout); } - const newActivityBarHiddenValue = !this.configurationService.lookup(Workbench.activityBarVisibleConfigurationKey).value; + const newActivityBarHiddenValue = !this.configurationService.getValue(Workbench.activityBarVisibleConfigurationKey); if (newActivityBarHiddenValue !== this.activityBarHidden) { this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout); } @@ -1205,7 +1214,7 @@ export class Workbench implements IPartService { private createPanelPart(): void { const panelPartContainer = $(this.workbench) .div({ - 'class': ['part', 'panel'], + 'class': ['part', 'panel', this.panelPosition === Position.BOTTOM ? 'bottom' : 'right'], id: Identifiers.PANEL_PART, role: 'complementary' }); @@ -1235,26 +1244,18 @@ export class Workbench implements IPartService { } public getEditorPart(): EditorPart { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.editorPart; } public getSidebarPart(): SidebarPart { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.sidebarPart; } public getPanelPart(): PanelPart { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.panelPart; } public getInstantiationService(): IInstantiationService { - assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.'); - return this.instantiationService; } @@ -1276,6 +1277,7 @@ export class Workbench implements IPartService { public toggleZenMode(skipLayout?: boolean): void { this.zenMode.active = !this.zenMode.active; + // Check if zen mode transitioned to full screen and if now we are out of zen mode -> we need to go out of full screen let toggleFullScreen = false; if (this.zenMode.active) { @@ -1284,25 +1286,29 @@ export class Workbench implements IPartService { this.zenMode.transitionedToFullScreen = toggleFullScreen; this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART); this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART); - this.setPanelHidden(true, true).done(undefined, errors.onUnexpectedError); - this.setSideBarHidden(true, true).done(undefined, errors.onUnexpectedError); + this.setPanelHidden(true, true).done(void 0, errors.onUnexpectedError); + this.setSideBarHidden(true, true).done(void 0, errors.onUnexpectedError); if (config.hideActivityBar) { this.setActivityBarHidden(true, true); } + if (config.hideStatusBar) { this.setStatusBarHidden(true, true); } + if (config.hideTabs) { this.editorPart.hideTabs(true); } } else { if (this.zenMode.wasPanelVisible) { - this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError); + this.setPanelHidden(false, true).done(void 0, errors.onUnexpectedError); } + if (this.zenMode.wasSideBarVisible) { - this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError); + this.setSideBarHidden(false, true).done(void 0, errors.onUnexpectedError); } + // Status bar and activity bar visibility come from settings -> update their visibility. this.onDidUpdateConfiguration(true); this.editorPart.hideTabs(false); @@ -1310,15 +1316,18 @@ export class Workbench implements IPartService { if (activeEditor) { activeEditor.focus(); } + toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen(); } + this.inZenMode.set(this.zenMode.active); if (!skipLayout) { this.layout(); } + if (toggleFullScreen) { - this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError); + this.windowService.toggleFullScreen().done(void 0, errors.onUnexpectedError); } } diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index b798a89d457..4cf61b3e915 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -12,12 +12,15 @@ import { join } from 'path'; import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService'; +import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { QueryType, ISearchQuery } from 'vs/platform/search/common/search'; import { DiskSearch } from 'vs/workbench/services/search/node/searchService'; import { IInitData, IEnvironment, IWorkspaceData, MainContext } from 'vs/workbench/api/node/extHost.protocol'; import * as errors from 'vs/base/common/errors'; import * as watchdog from 'native-watchdog'; +import * as glob from 'vs/base/common/glob'; // const nativeExit = process.exit.bind(process); process.exit = function () { @@ -57,6 +60,7 @@ export class ExtensionHostMain { private _workspace: IWorkspaceData; private _environment: IEnvironment; private _extensionService: ExtHostExtensionService; + private _extHostConfiguration: ExtHostConfiguration; constructor(rpcProtocol: RPCProtocol, initData: IInitData) { this._environment = initData.environment; @@ -64,7 +68,9 @@ export class ExtensionHostMain { // services const threadService = new ExtHostThreadService(rpcProtocol); - this._extensionService = new ExtHostExtensionService(initData, threadService); + const extHostWorkspace = new ExtHostWorkspace(threadService, initData.workspace); + this._extHostConfiguration = new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration); + this._extensionService = new ExtHostExtensionService(initData, threadService, extHostWorkspace, this._extHostConfiguration); // error forwarding and stack trace scanning const extensionErrors = new WeakMap(); @@ -145,68 +151,102 @@ export class ExtensionHostMain { } private handleWorkspaceContainsEagerExtensions(): TPromise { - if (!this._workspace || this._workspace.roots.length === 0) { + if (!this._workspace || this._workspace.folders.length === 0) { return TPromise.as(null); } - const desiredFilesMap: { - [filename: string]: boolean; - } = {}; + return TPromise.join( + this._extensionService.getAllExtensionDescriptions().map((desc) => { + return this.handleWorkspaceContainsEagerExtension(desc); + }) + ).then(() => { }); + } - this._extensionService.getAllExtensionDescriptions().forEach((desc) => { - let activationEvents = desc.activationEvents; - if (!activationEvents) { - return; - } + private handleWorkspaceContainsEagerExtension(desc: IExtensionDescription): TPromise { + let activationEvents = desc.activationEvents; + if (!activationEvents) { + return TPromise.as(void 0); + } - for (let i = 0; i < activationEvents.length; i++) { - if (/^workspaceContains:/.test(activationEvents[i])) { - let fileName = activationEvents[i].substr('workspaceContains:'.length); - desiredFilesMap[fileName] = true; + const fileNames: string[] = []; + const globPatterns: string[] = []; + + for (let i = 0; i < activationEvents.length; i++) { + if (/^workspaceContains:/.test(activationEvents[i])) { + let fileNameOrGlob = activationEvents[i].substr('workspaceContains:'.length); + if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0) { + globPatterns.push(fileNameOrGlob); + } else { + fileNames.push(fileNameOrGlob); } } - }); + } - const matchingPatterns = Object.keys(desiredFilesMap).map(p => { - // TODO: This is a bit hacky -- maybe this should be implemented by using something like - // `workspaceGlob` or something along those lines? - if (p.indexOf('*') > -1 || p.indexOf('?') > -1) { - if (!this._diskSearch) { - // Shut down this search process after 1s - this._diskSearch = new DiskSearch(false, 1000); - } + if (fileNames.length === 0 && globPatterns.length === 0) { + return TPromise.as(void 0); + } - const query: ISearchQuery = { - folderQueries: this._workspace.roots.map(root => ({ folder: root })), - type: QueryType.File, - maxResults: 1, - includePattern: { [p]: true } - }; + let fileNamePromise = TPromise.join(fileNames.map((fileName) => this.activateIfFileName(desc.id, fileName))).then(() => { }); + let globPatternPromise = this.activateIfGlobPatterns(desc.id, globPatterns); - return this._diskSearch.search(query).then(result => result.results.length ? p : undefined); - } else { - // find exact path - return (async resolve => { - for (const { fsPath } of this._workspace.roots) { - if (await pfs.exists(join(fsPath, p))) { - return p; - } - } - return undefined; - })(); + return TPromise.join([fileNamePromise, globPatternPromise]).then(() => { }); + } + + private async activateIfFileName(extensionId: string, fileName: string): TPromise { + // find exact path + + for (const { uri } of this._workspace.folders) { + if (await pfs.exists(join(uri.fsPath, fileName))) { + // the file was found + return ( + this._extensionService.activateById(extensionId, true) + .done(null, err => console.error(err)) + ); } + } + + return undefined; + } + + private async activateIfGlobPatterns(extensionId: string, globPatterns: string[]): TPromise { + if (globPatterns.length === 0) { + return TPromise.as(void 0); + } + + if (!this._diskSearch) { + // Shut down this search process after 1s + this._diskSearch = new DiskSearch(false, 1000); + } + + let includes: glob.IExpression = {}; + globPatterns.forEach((globPattern) => { + includes[globPattern] = true; }); - return TPromise.join(matchingPatterns).then(patterns => { - patterns - .filter(p => p !== undefined) - .forEach(p => { - const activationEvent = `workspaceContains:${p}`; + const folderQueries = this._workspace.folders.map(folder => ({ folder: folder.uri })); + const config = this._extHostConfiguration.getConfiguration('search'); + const useRipgrep = config.get('useRipgrep', true); + const followSymlinks = config.get('followSymlinks', true); - this._extensionService.activateByEvent(activationEvent, true) - .done(null, err => console.error(err)); - }); - }); + const query: ISearchQuery = { + folderQueries, + type: QueryType.File, + exists: true, + includePattern: includes, + useRipgrep, + ignoreSymlinks: !followSymlinks + }; + + let result = await this._diskSearch.search(query); + if (result.limitHit) { + // a file was found matching one of the glob patterns + return ( + this._extensionService.activateById(extensionId, true) + .done(null, err => console.error(err)) + ); + } + + return TPromise.as(void 0); } private handleExtensionTests(): TPromise { diff --git a/src/vs/workbench/parts/backup/common/backupModelTracker.ts b/src/vs/workbench/parts/backup/common/backupModelTracker.ts index 787897cd389..4b1408847d2 100644 --- a/src/vs/workbench/parts/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/parts/backup/common/backupModelTracker.ts @@ -50,7 +50,7 @@ export class BackupModelTracker implements IWorkbenchContribution { this.toDispose.push(this.untitledEditorService.onDidDisposeModel((e) => this.discardBackup(e))); // Listen to config changes - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); } private onConfigurationChange(configuration: IFilesConfiguration): void { diff --git a/src/vs/workbench/parts/backup/common/backupRestorer.ts b/src/vs/workbench/parts/backup/common/backupRestorer.ts index f035909c3e9..4ff211eb4b7 100644 --- a/src/vs/workbench/parts/backup/common/backupRestorer.ts +++ b/src/vs/workbench/parts/backup/common/backupRestorer.ts @@ -9,7 +9,6 @@ import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { IUntitledEditorService, UNTITLED_SCHEMA } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IPartService } from 'vs/workbench/services/part/common/partService'; import errors = require('vs/base/common/errors'); import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; @@ -17,6 +16,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { Position, IResourceInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Schemas } from 'vs/base/common/network'; +import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; export class BackupRestorer implements IWorkbenchContribution { @@ -24,18 +24,18 @@ export class BackupRestorer implements IWorkbenchContribution { constructor( @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IPartService private partService: IPartService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IBackupFileService private backupFileService: IBackupFileService, @ITextFileService private textFileService: ITextFileService, - @IEditorGroupService private groupService: IEditorGroupService + @IEditorGroupService private groupService: IEditorGroupService, + @ILifecycleService private lifecycleService: ILifecycleService ) { this.restoreBackups(); } private restoreBackups(): void { if (this.backupFileService.backupEnabled) { - this.partService.joinCreation().then(() => { + this.lifecycleService.when(LifecyclePhase.Running).then(() => { this.doRestoreBackups().done(null, errors.onUnexpectedError); }); } diff --git a/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts b/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts index 3aa4c25c532..32a8c8227fc 100644 --- a/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts +++ b/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts @@ -11,18 +11,12 @@ import { nfcall } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; -import { IEditorService } from 'vs/platform/editor/common/editor'; import product from 'vs/platform/node/product'; -interface ILegacyUse { - file: string; - lineNumber: number; -} - function ignore(code: string, value: T = null): (err: any) => TPromise { return err => err.code === code ? TPromise.as(value) : TPromise.wrapError(err); } @@ -42,8 +36,7 @@ class InstallAction extends Action { constructor( id: string, label: string, - @IMessageService private messageService: IMessageService, - @IEditorService private editorService: IEditorService + @IMessageService private messageService: IMessageService ) { super(id, label); } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts b/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts index ddbc5ae45e6..6df4199bc2a 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/accessibility.ts @@ -25,10 +25,9 @@ import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/common/toggleTabFocusMode'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorWidgetBackground, widgetShadow, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import * as editorOptions from 'vs/editor/common/config/editorOptions'; import * as platform from 'vs/base/common/platform'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import URI from 'vs/base/common/uri'; @@ -87,7 +86,6 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { @IContextKeyService private _contextKeyService: IContextKeyService, @IKeybindingService private _keybindingService: IKeybindingService, @IConfigurationService private _configurationService: IConfigurationService, - @IConfigurationEditingService private _configurationEditingService: IConfigurationEditingService, @IOpenerService private _openerService: IOpenerService ) { super(); @@ -124,10 +122,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_E)) { alert(nls.localize('emergencyConfOn', "Now changing the setting `editor.accessibilitySupport` to 'on'.")); - this._configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { - key: 'editor.accessibilitySupport', - value: 'on' - }); + this._configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER); e.preventDefault(); e.stopPropagation(); @@ -283,6 +278,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { } @editorAction +// @ts-ignore @editorAction uses the class class ShowAccessibilityHelpAction extends EditorAction { constructor() { diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/inspectKeybindings.ts b/src/vs/workbench/parts/codeEditor/electron-browser/inspectKeybindings.ts index a37c93ea70f..983302f0396 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/inspectKeybindings.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/inspectKeybindings.ts @@ -13,6 +13,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IUntitledResourceInput } from 'vs/platform/editor/common/editor'; @editorAction +// @ts-ignore @editorAction uses the class class InspectKeyMap extends EditorAction { constructor() { diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts index c5ba3a10a1b..4b7695b68b9 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts @@ -5,9 +5,10 @@ 'use strict'; import * as nls from 'vs/nls'; +import * as types from 'vs/base/common/types'; import { parse, ParseError } from 'vs/base/common/json'; import { readFile } from 'vs/base/node/pfs'; -import { CharacterPair, LanguageConfiguration, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, CommentRule } from 'vs/editor/common/modes/languageConfiguration'; +import { CharacterPair, LanguageConfiguration, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, CommentRule, FoldingRules } from 'vs/editor/common/modes/languageConfiguration'; import { IModeService } from 'vs/editor/common/services/modeService'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; @@ -35,6 +36,27 @@ interface ILanguageConfiguration { surroundingPairs?: (CharacterPair | IAutoClosingPair)[]; wordPattern?: string | IRegExp; indentationRules?: IIndentationRules; + folding?: FoldingRules; +} + +function isStringArr(something: string[]): boolean { + if (!Array.isArray(something)) { + return false; + } + for (let i = 0, len = something.length; i < len; i++) { + if (typeof something[i] !== 'string') { + return false; + } + } + return true; + +} + +function isCharacterPair(something: CharacterPair): boolean { + return ( + isStringArr(something) + && something.length === 2 + ); } export class LanguageConfigurationFileHandler { @@ -79,24 +101,177 @@ export class LanguageConfigurationFileHandler { }); } + private _extractValidCommentRule(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): CommentRule { + const source = configuration.comments; + if (typeof source === 'undefined') { + return null; + } + if (!types.isObject(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`comments\` to be an object.`); + return null; + } + + let result: CommentRule = null; + if (typeof source.lineComment !== 'undefined') { + if (typeof source.lineComment !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`comments.lineComment\` to be a string.`); + } else { + result = result || {}; + result.lineComment = source.lineComment; + } + } + if (typeof source.blockComment !== 'undefined') { + if (!isCharacterPair(source.blockComment)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`comments.blockComment\` to be an array of two strings.`); + } else { + result = result || {}; + result.blockComment = source.blockComment; + } + } + return result; + } + + private _extractValidBrackets(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): CharacterPair[] { + const source = configuration.brackets; + if (typeof source === 'undefined') { + return null; + } + if (!Array.isArray(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`brackets\` to be an array.`); + return null; + } + + let result: CharacterPair[] = null; + for (let i = 0, len = source.length; i < len; i++) { + const pair = source[i]; + if (!isCharacterPair(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`brackets[${i}]\` to be an array of two strings.`); + continue; + } + + result = result || []; + result.push(pair); + } + return result; + } + + private _extractValidAutoClosingPairs(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): IAutoClosingPairConditional[] { + const source = configuration.autoClosingPairs; + if (typeof source === 'undefined') { + return null; + } + if (!Array.isArray(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs\` to be an array.`); + return null; + } + + let result: IAutoClosingPairConditional[] = null; + for (let i = 0, len = source.length; i < len; i++) { + const pair = source[i]; + if (Array.isArray(pair)) { + if (!isCharacterPair(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + result = result || []; + result.push({ open: pair[0], close: pair[1] }); + } else { + if (!types.isObject(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + if (typeof pair.open !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}].open\` to be a string.`); + continue; + } + if (typeof pair.close !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}].close\` to be a string.`); + continue; + } + if (typeof pair.notIn !== 'undefined') { + if (!isStringArr(pair.notIn)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`autoClosingPairs[${i}].notIn\` to be a string array.`); + continue; + } + } + result = result || []; + result.push({ open: pair.open, close: pair.close, notIn: pair.notIn }); + } + } + return result; + } + + private _extractValidSurroundingPairs(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): IAutoClosingPair[] { + const source = configuration.surroundingPairs; + if (typeof source === 'undefined') { + return null; + } + if (!Array.isArray(source)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs\` to be an array.`); + return null; + } + + let result: IAutoClosingPair[] = null; + for (let i = 0, len = source.length; i < len; i++) { + const pair = source[i]; + if (Array.isArray(pair)) { + if (!isCharacterPair(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + result = result || []; + result.push({ open: pair[0], close: pair[1] }); + } else { + if (!types.isObject(pair)) { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}]\` to be an array of two strings or an object.`); + continue; + } + if (typeof pair.open !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}].open\` to be a string.`); + continue; + } + if (typeof pair.close !== 'string') { + console.warn(`[${languageIdentifier.language}]: language configuration: expected \`surroundingPairs[${i}].close\` to be a string.`); + continue; + } + result = result || []; + result.push({ open: pair.open, close: pair.close }); + } + } + return result; + } + + // private _mapCharacterPairs(pairs: (CharacterPair | IAutoClosingPairConditional)[]): IAutoClosingPairConditional[] { + // return pairs.map(pair => { + // if (Array.isArray(pair)) { + // return { open: pair[0], close: pair[1] }; + // } + // return pair; + // }); + // } + private _handleConfig(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): void { let richEditConfig: LanguageConfiguration = {}; - if (configuration.comments) { - richEditConfig.comments = configuration.comments; + const comments = this._extractValidCommentRule(languageIdentifier, configuration); + if (comments) { + richEditConfig.comments = comments; } - if (configuration.brackets) { - richEditConfig.brackets = configuration.brackets; + const brackets = this._extractValidBrackets(languageIdentifier, configuration); + if (brackets) { + richEditConfig.brackets = brackets; } - if (configuration.autoClosingPairs) { - richEditConfig.autoClosingPairs = this._mapCharacterPairs(configuration.autoClosingPairs); + const autoClosingPairs = this._extractValidAutoClosingPairs(languageIdentifier, configuration); + if (autoClosingPairs) { + richEditConfig.autoClosingPairs = autoClosingPairs; } - if (configuration.surroundingPairs) { - richEditConfig.surroundingPairs = this._mapCharacterPairs(configuration.surroundingPairs); + const surroundingPairs = this._extractValidSurroundingPairs(languageIdentifier, configuration); + if (surroundingPairs) { + richEditConfig.surroundingPairs = surroundingPairs; } if (configuration.wordPattern) { @@ -117,6 +292,15 @@ export class LanguageConfigurationFileHandler { } } + if (configuration.folding) { + let markers = configuration.folding.markers; + + richEditConfig.folding = { + offSide: configuration.folding.offSide, + markers: markers ? { start: new RegExp(markers.start), end: new RegExp(markers.end) } : void 0 + }; + } + LanguageConfigurationRegistry.register(languageIdentifier, richEditConfig); } @@ -156,15 +340,6 @@ export class LanguageConfigurationFileHandler { return null; } - - private _mapCharacterPairs(pairs: (CharacterPair | IAutoClosingPairConditional)[]): IAutoClosingPairConditional[] { - return pairs.map(pair => { - if (Array.isArray(pair)) { - return { open: pair[0], close: pair[1] }; - } - return pair; - }); - } } const schemaId = 'vscode://schemas/language-configuration'; @@ -377,7 +552,32 @@ const schema: IJSONSchema = { } } } + }, + folding: { + type: 'object', + description: nls.localize('schema.folding', 'The language\'s folding settings.'), + properties: { + offSide: { + type: 'boolean', + description: nls.localize('schema.folding.offSide', 'A language adheres to the off-side rule if blocks in that language are expressed by their indentation. If set, empty lines belong to the subsequent block.'), + }, + markers: { + type: 'object', + description: nls.localize('schema.folding.markers', 'Language specific folding markers such as \'#region\' and \'#endregion\'. The start and end regexes will be tested against the contents of all lines and must be designed efficiently'), + properties: { + start: { + type: 'string', + description: nls.localize('schema.folding.markers.start', 'The RegExp pattern for the start marker. The regexp must start with \'^\'.') + }, + end: { + type: 'string', + description: nls.localize('schema.folding.markers.end', 'The RegExp pattern for the end marker. The regexp must start with \'^\'.') + }, + } + } + } } + } }; let schemaRegistry = Registry.as(Extensions.JSONContribution); diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/textMate/inspectTMScopes.ts b/src/vs/workbench/parts/codeEditor/electron-browser/textMate/inspectTMScopes.ts index e28e657d8d7..27065a87ebb 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/textMate/inspectTMScopes.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/textMate/inspectTMScopes.ts @@ -102,6 +102,7 @@ class InspectTMScopesController extends Disposable implements IEditorContributio } @editorAction +// @ts-ignore @editorAction uses the class class InspectTMScopes extends EditorAction { constructor() { diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts index 86cdf51939a..247b6b2e73b 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMinimap.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @editorAction export class ToggleMinimapAction extends EditorAction { @@ -22,10 +22,10 @@ export class ToggleMinimapAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { - const configurationEditingService = accessor.get(IConfigurationEditingService); + const configurationService = accessor.get(IConfigurationService); const newValue = !editor.getConfiguration().viewInfo.minimap.enabled; - configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.minimap.enabled', value: newValue }); + configurationService.updateValue('editor.minimap.enabled', newValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts index b39ffe5ea9f..a2022660076 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleMultiCursorModifier.ts @@ -9,9 +9,8 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class ToggleMultiCursorModifierAction extends Action { @@ -23,21 +22,16 @@ export class ToggleMultiCursorModifierAction extends Action { constructor( id: string, label: string, - @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); - - this.enabled = !!this.configurationService && !!this.configurationEditingService; } public run(): TPromise { const editorConf = this.configurationService.getConfiguration<{ multiCursorModifier: 'ctrlCmd' | 'alt' }>('editor'); const newValue: 'ctrlCmd' | 'alt' = (editorConf.multiCursorModifier === 'ctrlCmd' ? 'alt' : 'ctrlCmd'); - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMultiCursorModifierAction.multiCursorModifierConfigurationKey, value: newValue }); - - return TPromise.as(null); + return this.configurationService.updateValue(ToggleMultiCursorModifierAction.multiCursorModifierConfigurationKey, newValue, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts index dc51edcbf3d..5eff950044a 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderControlCharacter.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @editorAction export class ToggleRenderControlCharacterAction extends EditorAction { @@ -22,10 +22,10 @@ export class ToggleRenderControlCharacterAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { - const configurationEditingService = accessor.get(IConfigurationEditingService); + const configurationService = accessor.get(IConfigurationService); let newRenderControlCharacters = !editor.getConfiguration().viewInfo.renderControlCharacters; - configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.renderControlCharacters', value: newRenderControlCharacters }); + configurationService.updateValue('editor.renderControlCharacters', newRenderControlCharacters, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts index 1ce47241da5..c95eca4cc60 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleRenderWhitespace.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; @editorAction export class ToggleRenderWhitespaceAction extends EditorAction { @@ -22,7 +22,7 @@ export class ToggleRenderWhitespaceAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { - const configurationEditingService = accessor.get(IConfigurationEditingService); + const configurationService = accessor.get(IConfigurationService); let renderWhitespace = editor.getConfiguration().viewInfo.renderWhitespace; let newRenderWhitespace: string; @@ -32,6 +32,6 @@ export class ToggleRenderWhitespaceAction extends EditorAction { newRenderWhitespace = 'none'; } - configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.renderWhitespace', value: newRenderWhitespace }); + configurationService.updateValue('editor.renderWhitespace', newRenderWhitespace, ConfigurationTarget.USER); } } diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts index 1b8da02242b..7065e678a6d 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts @@ -131,6 +131,7 @@ function applyWordWrapState(editor: ICommonCodeEditor, state: IWordWrapState): v } @editorAction +// @ts-ignore @editorAction uses the class class ToggleWordWrapAction extends EditorAction { constructor() { @@ -175,6 +176,7 @@ class ToggleWordWrapAction extends EditorAction { } @commonEditorContribution +// @ts-ignore @editorAction uses the class class ToggleWordWrapController extends Disposable implements IEditorContribution { private static _ID = 'editor.contrib.toggleWordWrapController'; diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts b/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts index 83b7176dcbc..641f87730cc 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/wordWrapMigration.ts @@ -55,6 +55,7 @@ class WordWrapMigrationStorage { } @editorContribution +// @ts-ignore @editorAction uses the class class WordWrapMigrationController extends Disposable implements IEditorContribution { private static ID = 'editor.contrib.wordWrapMigrationController'; @@ -83,7 +84,7 @@ class WordWrapMigrationController extends Disposable implements IEditorContribut } WordWrapMigrationController._checked = true; - let result = this.configurationService.lookup('editor.wrappingColumn'); + let result = this.configurationService.inspect('editor.wrappingColumn'); if (typeof result.value === 'undefined') { // Setting is not used return; diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index be36a43df43..81af57279a2 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -15,7 +15,6 @@ import { SelectActionItem, IActionItem } from 'vs/base/browser/ui/actionbar/acti import { EventEmitter } from 'vs/base/common/eventEmitter'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IDebugService } from 'vs/workbench/parts/debug/common/debug'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; @@ -42,8 +41,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { @IDebugService private debugService: IDebugService, @IThemeService private themeService: IThemeService, @IConfigurationService private configurationService: IConfigurationService, - @ICommandService private commandService: ICommandService, - @IQuickOpenService private quickOpenService: IQuickOpenService + @ICommandService private commandService: ICommandService ) { super(); this.toDispose = []; @@ -56,8 +54,8 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => { - if (e.sourceConfig.launch) { + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('launch')) { this.updateOptions(); } })); @@ -160,7 +158,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { if (name === manager.selectedName && launch === manager.selectedLaunch) { this.selected = this.options.length; } - const label = launches.length > 1 ? `${name} (${launch.name})` : name; + const label = launches.length > 1 ? `${name} (${launch.workspace.name})` : name; this.options.push({ label, handler: () => { manager.selectConfiguration(launch, name); return true; } }); })); @@ -171,10 +169,10 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem { const disabledIdx = this.options.length - 1; launches.forEach(l => { - const label = launches.length > 1 ? nls.localize("addConfigTo", "Add Config ({0})...", l.name) : nls.localize('addConfiguration', "Add Configuration..."); + const label = launches.length > 1 ? nls.localize("addConfigTo", "Add Config ({0})...", l.workspace.name) : nls.localize('addConfiguration', "Add Configuration..."); this.options.push({ label, handler: () => { - this.commandService.executeCommand('debug.addConfiguration', l.workspaceUri.toString()).done(undefined, errors.onUnexpectedError); + this.commandService.executeCommand('debug.addConfiguration', l.workspace.uri.toString()).done(undefined, errors.onUnexpectedError); return false; } }); diff --git a/src/vs/workbench/parts/debug/browser/debugActions.ts b/src/vs/workbench/parts/debug/browser/debugActions.ts index b462d58e460..3bbac5cc4ea 100644 --- a/src/vs/workbench/parts/debug/browser/debugActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugActions.ts @@ -11,7 +11,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IFileService } from 'vs/platform/files/common/files'; import { IMessageService } from 'vs/platform/message/common/message'; import { IDebugService, State, IProcess, IThread, IEnablement, IBreakpoint, IStackFrame, IFunctionBreakpoint, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, IExpression, REPL_ID, ProcessState } @@ -77,7 +77,6 @@ export class ConfigureAction extends AbstractDebugAction { constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @IMessageService private messageService: IMessageService ) { super(id, label, 'debug-action configure', debugService, keybindingService); @@ -98,7 +97,7 @@ export class ConfigureAction extends AbstractDebugAction { } public run(event?: any): TPromise { - if (!this.contextService.hasWorkspace()) { + if (!this.debugService.getConfigurationManager().selectedLaunch) { this.messageService.show(severity.Info, nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration.")); return TPromise.as(null); } @@ -118,13 +117,15 @@ export class StartAction extends AbstractDebugAction { @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(id, label, 'debug-action start', debugService, keybindingService); - this.debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateEnablement()); - this.debugService.getModel().onDidChangeCallStack(() => this.updateEnablement()); + + this.toDispose.push(this.debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateEnablement())); + this.toDispose.push(this.debugService.getModel().onDidChangeCallStack(() => this.updateEnablement())); + this.toDispose.push(this.contextService.onDidChangeWorkbenchState(() => this.updateEnablement())); } public run(): TPromise { const launch = this.debugService.getConfigurationManager().selectedLaunch; - return this.debugService.startDebugging(launch ? launch.workspaceUri : undefined, undefined, this.isNoDebug()); + return this.debugService.startDebugging(launch ? launch.workspace : undefined, undefined, this.isNoDebug()); } protected isNoDebug(): boolean { @@ -140,10 +141,10 @@ export class StartAction extends AbstractDebugAction { if (state === State.Initializing) { return false; } - if (this.contextService && !this.contextService.hasWorkspace() && processes.length > 0) { + if (this.contextService && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && processes.length > 0) { return false; } - if (processes.some(p => p.getName(false) === selectedName && (!launch || p.session.root.toString() === launch.workspaceUri.toString()))) { + if (processes.some(p => p.getName(false) === selectedName && (!launch || p.session.root.uri.toString() === launch.workspace.uri.toString()))) { return false; } const compound = launch && launch.getCompound(selectedName); @@ -215,7 +216,7 @@ export class RestartAction extends AbstractDebugAction { } protected isEnabled(state: State): boolean { - return super.isEnabled(state) && state !== State.Inactive; + return super.isEnabled(state) && (state === State.Running || state === State.Stopped); } } @@ -299,7 +300,7 @@ export class StopAction extends AbstractDebugAction { } protected isEnabled(state: State): boolean { - return super.isEnabled(state) && state !== State.Inactive; + return super.isEnabled(state) && (state === State.Running || state === State.Stopped); } } @@ -317,7 +318,7 @@ export class DisconnectAction extends AbstractDebugAction { } protected isEnabled(state: State): boolean { - return super.isEnabled(state) && state !== State.Inactive; + return super.isEnabled(state) && (state === State.Running || state === State.Stopped); } } @@ -516,7 +517,7 @@ export class ReapplyBreakpointsAction extends AbstractDebugAction { protected isEnabled(state: State): boolean { const model = this.debugService.getModel(); - return super.isEnabled(state) && state !== State.Inactive && + return super.isEnabled(state) && (state === State.Running || state === State.Stopped) && (model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length > 0); } } diff --git a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts index 78aefdb3d52..3513a9f08ac 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts @@ -21,7 +21,7 @@ import { IDebugConfiguration, IDebugService, State } from 'vs/workbench/parts/de import { AbstractDebugAction, PauseAction, ContinueAction, StepBackAction, ReverseContinueAction, StopAction, DisconnectAction, StepOverAction, StepIntoAction, StepOutAction, RestartAction, FocusProcessAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { FocusProcessActionItem } from 'vs/workbench/parts/debug/browser/debugActionItems'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IMessageService } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -93,7 +93,7 @@ export class DebugActionsWidget extends Themable implements IWorkbenchContributi private registerListeners(): void { this.toUnbind.push(this.debugService.onDidChangeState(state => this.update(state))); - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(() => this.update(this.debugService.state))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onDidConfigurationChange(e))); this.toUnbind.push(this.actionBar.actionRunner.addListener(EventType.RUN, (e: any) => { // check for error if (e.error && !errors.isPromiseCanceledError(e.error)) { @@ -102,6 +102,12 @@ export class DebugActionsWidget extends Themable implements IWorkbenchContributi // log in telemetry if (this.telemetryService) { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'debugActionsWidget' }); } })); @@ -141,6 +147,11 @@ export class DebugActionsWidget extends Themable implements IWorkbenchContributi private storePosition(): void { const position = parseFloat(this.$el.getComputedStyle().left) / window.innerWidth; this.storageService.store(DEBUG_ACTIONS_WIDGET_POSITION_KEY, position, StorageScope.WORKSPACE); + /* __GDPR__ + "debug.actionswidgetposition" : { + "position" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(DEBUG_ACTIONS_WIDGET_POSITION_KEY, { position }); } @@ -184,8 +195,14 @@ export class DebugActionsWidget extends Themable implements IWorkbenchContributi return DebugActionsWidget.ID; } + private onDidConfigurationChange(event: IConfigurationChangeEvent): void { + if (event.affectsConfiguration('debug.hideActionBar')) { + this.update(this.debugService.state); + } + } + private update(state: State): void { - if (state === State.Inactive || this.configurationService.getConfiguration('debug').hideActionBar) { + if (state === State.Inactive || state === State.Initializing || this.configurationService.getConfiguration('debug').hideActionBar) { return this.hide(); } diff --git a/src/vs/workbench/parts/debug/browser/debugContentProvider.ts b/src/vs/workbench/parts/debug/browser/debugContentProvider.ts index ad96768d0d5..44c7fd9b680 100644 --- a/src/vs/workbench/parts/debug/browser/debugContentProvider.ts +++ b/src/vs/workbench/parts/debug/browser/debugContentProvider.ts @@ -13,7 +13,21 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { DEBUG_SCHEME, IDebugService, IProcess } from 'vs/workbench/parts/debug/common/debug'; +import { Source } from 'vs/workbench/parts/debug/common/debugSource'; +/** + * Debug URI format + * + * a debug URI represents a Source object and the debug session where the Source comes from. + * + * debug:arbitrary_path?session=123e4567-e89b-12d3-a456-426655440000&ref=1016 + * \___/ \____________/ \__________________________________________/ \______/ + * | | | | + * scheme source.path session id source.referencequery + * + * the arbitrary_path and the session id are encoded with 'encodeURIComponent' + * + */ export class DebugContentProvider implements IWorkbenchContribution, ITextModelContentProvider { constructor( @@ -32,15 +46,12 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC public provideTextContent(resource: uri): TPromise { let process: IProcess; + let sourceRef: number; + if (resource.query) { - const keyvalues = resource.query.split('&'); - for (let keyvalue of keyvalues) { - const pair = keyvalue.split('='); - if (pair.length === 2 && pair[0] === 'session') { - process = this.debugService.findProcessByUUID(decodeURIComponent(pair[1])); - break; - } - } + const data = Source.getEncodedDebugData(resource); + process = this.debugService.getModel().getProcesses().filter(p => p.getId() === data.processId).pop(); + sourceRef = data.sourceReference; } if (!process) { @@ -55,18 +66,26 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC let rawSource: DebugProtocol.Source; if (source) { rawSource = source.raw; + if (!sourceRef) { + sourceRef = source.reference; + } } else { - // Remove debug: scheme - rawSource = { path: resource.with({ scheme: '', query: '' }).toString(true) }; + // create a Source + rawSource = { + path: resource.with({ scheme: '', query: '' }).toString(true), // Remove debug: scheme + sourceReference: sourceRef + }; } - return process.session.source({ sourceReference: source ? source.reference : undefined, source: rawSource }).then(response => { - const mime = response.body.mimeType || guessMimeTypes(resource.toString())[0]; + return process.session.source({ sourceReference: sourceRef, source: rawSource }).then(response => { + + const mime = response.body.mimeType || guessMimeTypes(resource.path)[0]; const modePromise = this.modeService.getOrCreateMode(mime); const model = this.modelService.createModel(response.body.content, modePromise, resource); return model; }, (err: DebugProtocol.ErrorResponse) => { + this.debugService.sourceIsNotAvailable(resource); const modePromise = this.modeService.getOrCreateMode(MIME_TEXT); const model = this.modelService.createModel(err.message, modePromise, resource); diff --git a/src/vs/workbench/parts/debug/browser/debugEditorActions.ts b/src/vs/workbench/parts/debug/browser/debugEditorActions.ts index 44289a6b188..14c6c3ef0f3 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorActions.ts @@ -16,6 +16,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @editorAction +// @ts-ignore @editorAction uses the class class ToggleBreakpointAction extends EditorAction { constructor() { super({ @@ -68,6 +69,7 @@ function addColumnBreakpoint(accessor: ServicesAccessor, editor: ICommonCodeEdit } @editorAction +// @ts-ignore @editorAction uses the class class ToggleColumnBreakpointAction extends EditorAction { constructor() { super({ @@ -89,6 +91,7 @@ class ToggleColumnBreakpointAction extends EditorAction { // TODO@Isidor merge two column breakpoints actions together @editorAction +// @ts-ignore @editorAction uses the class class ToggleColumnBreakpointContextMenuAction extends EditorAction { constructor() { super({ @@ -109,6 +112,7 @@ class ToggleColumnBreakpointContextMenuAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class ConditionalBreakpointAction extends EditorAction { constructor() { @@ -132,6 +136,7 @@ class ConditionalBreakpointAction extends EditorAction { @editorAction +// @ts-ignore @editorAction uses the class class RunToCursorAction extends EditorAction { constructor() { @@ -175,6 +180,7 @@ class RunToCursorAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class SelectionToReplAction extends EditorAction { constructor() { @@ -202,6 +208,7 @@ class SelectionToReplAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class SelectionToWatchExpressionsAction extends EditorAction { constructor() { @@ -227,6 +234,7 @@ class SelectionToWatchExpressionsAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class ShowDebugHoverAction extends EditorAction { constructor() { diff --git a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts index e229724a162..6f7aa08d4ec 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts @@ -13,15 +13,14 @@ import { IModel, TrackedRangeStickiness, IModelDeltaDecoration, IModelDecoration import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IDebugService, IBreakpoint, IRawBreakpoint, State } from 'vs/workbench/parts/debug/common/debug'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { MarkdownString } from 'vs/base/common/htmlContent'; interface IDebugEditorModelData { model: IModel; toDispose: lifecycle.IDisposable[]; breakpointDecorationIds: string[]; - breakpointLines: number[]; - breakpointDecorationsAsMap: Map; + breakpointModelIds: string[]; + breakpointDecorationsAsMap: Map; currentStackDecorations: string[]; dirty: boolean; topStackFrameRange: Range; @@ -81,17 +80,18 @@ export class DebugEditorModelManager implements IWorkbenchContribution { const breakpoints = this.debugService.getModel().getBreakpoints().filter(bp => bp.uri.toString() === modelUrlStr); const currentStackDecorations = model.deltaDecorations([], this.createCallStackDecorations(modelUrlStr)); - const breakPointDecorations = model.deltaDecorations([], this.createBreakpointDecorations(breakpoints)); + const desiredDecorations = this.createBreakpointDecorations(model, breakpoints); + const breakPointDecorations = model.deltaDecorations([], desiredDecorations); - const toDispose: lifecycle.IDisposable[] = [model.onDidChangeDecorations((e) => this.onModelDecorationsChanged(modelUrlStr, e))]; - const breakpointDecorationsAsMap = new Map(); - breakPointDecorations.forEach(bpd => breakpointDecorationsAsMap.set(bpd, true)); + const toDispose: lifecycle.IDisposable[] = [model.onDidChangeDecorations((e) => this.onModelDecorationsChanged(modelUrlStr))]; + const breakpointDecorationsAsMap = new Map(); + breakPointDecorations.forEach((decorationId, index) => breakpointDecorationsAsMap.set(decorationId, desiredDecorations[index].range)); this.modelDataMap.set(modelUrlStr, { model: model, toDispose: toDispose, breakpointDecorationIds: breakPointDecorations, - breakpointLines: breakpoints.map(bp => bp.lineNumber), + breakpointModelIds: breakpoints.map(bp => bp.getId()), breakpointDecorationsAsMap, currentStackDecorations: currentStackDecorations, dirty: false, @@ -185,39 +185,46 @@ export class DebugEditorModelManager implements IWorkbenchContribution { } // breakpoints management. Represent data coming from the debug service and also send data back. - private onModelDecorationsChanged(modelUrlStr: string, e: IModelDecorationsChangedEvent): void { + private onModelDecorationsChanged(modelUrlStr: string): void { const modelData = this.modelDataMap.get(modelUrlStr); if (modelData.breakpointDecorationsAsMap.size === 0) { // I have no decorations return; } - if (!e.changedDecorations.some(decorationId => modelData.breakpointDecorationsAsMap.has(decorationId))) { + let somethingChanged = false; + modelData.breakpointDecorationsAsMap.forEach((breakpointRange, decorationId) => { + if (somethingChanged) { + return; + } + const newBreakpointRange = modelData.model.getDecorationRange(decorationId); + if (newBreakpointRange && !breakpointRange.equalsRange(newBreakpointRange)) { + somethingChanged = true; + } + }); + if (!somethingChanged) { // nothing to do, my decorations did not change. return; } const data: IRawBreakpoint[] = []; - const lineToBreakpointDataMap = new Map(); - this.debugService.getModel().getBreakpoints().filter(bp => bp.uri.toString() === modelUrlStr).forEach(bp => { - lineToBreakpointDataMap.set(bp.lineNumber, bp); - }); - + const breakpoints = this.debugService.getModel().getBreakpoints(); const modelUri = modelData.model.uri; for (let i = 0, len = modelData.breakpointDecorationIds.length; i < len; i++) { const decorationRange = modelData.model.getDecorationRange(modelData.breakpointDecorationIds[i]); - const lineNumber = modelData.breakpointLines[i]; // check if the line got deleted. - if (decorationRange.endColumn - decorationRange.startColumn > 0) { - const breakpoint = lineToBreakpointDataMap.get(lineNumber); + if (decorationRange && decorationRange.endColumn - decorationRange.startColumn > 0) { + const breakpoint = breakpoints.filter(bp => bp.getId() === modelData.breakpointModelIds[i]).pop(); // since we know it is collapsed, it cannot grow to multiple lines - data.push({ - lineNumber: decorationRange.startLineNumber, - enabled: breakpoint.enabled, - condition: breakpoint.condition, - hitCondition: breakpoint.hitCondition, - column: breakpoint.column ? decorationRange.startColumn : undefined - }); + if (breakpoint) { + data.push({ + lineNumber: decorationRange.startLineNumber, + enabled: breakpoint.enabled, + condition: breakpoint.condition, + hitCondition: breakpoint.hitCondition, + column: breakpoint.column ? decorationRange.startColumn : undefined + }); + } } } modelData.dirty = this.debugService.state !== State.Inactive; @@ -254,16 +261,19 @@ export class DebugEditorModelManager implements IWorkbenchContribution { } private updateBreakpoints(modelData: IDebugEditorModelData, newBreakpoints: IBreakpoint[]): void { - modelData.breakpointDecorationIds = modelData.model.deltaDecorations(modelData.breakpointDecorationIds, this.createBreakpointDecorations(newBreakpoints)); + const desiredDecorations = this.createBreakpointDecorations(modelData.model, newBreakpoints); + modelData.breakpointDecorationIds = modelData.model.deltaDecorations(modelData.breakpointDecorationIds, desiredDecorations); + modelData.breakpointModelIds = newBreakpoints.map(nbp => nbp.getId()); modelData.breakpointDecorationsAsMap.clear(); - modelData.breakpointDecorationIds.forEach(id => modelData.breakpointDecorationsAsMap.set(id, true)); - modelData.breakpointLines = newBreakpoints.map(bp => bp.lineNumber); + modelData.breakpointDecorationIds.forEach((decorationId, index) => modelData.breakpointDecorationsAsMap.set(decorationId, desiredDecorations[index].range)); } - private createBreakpointDecorations(breakpoints: IBreakpoint[]): IModelDeltaDecoration[] { + private createBreakpointDecorations(model: IModel, breakpoints: IBreakpoint[]): { range: Range; options: IModelDecorationOptions; }[] { return breakpoints.map((breakpoint) => { - const range = breakpoint.column ? new Range(breakpoint.lineNumber, breakpoint.column, breakpoint.lineNumber, breakpoint.column + 1) - : new Range(breakpoint.lineNumber, 1, breakpoint.lineNumber, Constants.MAX_SAFE_SMALL_INTEGER); // Decoration has to have a width #20688 + const range = model.validateRange( + breakpoint.column ? new Range(breakpoint.lineNumber, breakpoint.column, breakpoint.lineNumber, breakpoint.column + 1) + : new Range(breakpoint.lineNumber, 1, breakpoint.lineNumber, Constants.MAX_SAFE_SMALL_INTEGER) // Decoration has to have a width #20688 + ); return { options: this.getBreakpointDecorationOptions(breakpoint), range @@ -274,7 +284,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution { private getBreakpointDecorationOptions(breakpoint: IBreakpoint): IModelDecorationOptions { const activated = this.debugService.getModel().areBreakpointsActivated(); const state = this.debugService.state; - const debugActive = state === State.Running || state === State.Stopped || state === State.Initializing; + const debugActive = state === State.Running || state === State.Stopped; const modelData = this.modelDataMap.get(breakpoint.uri.toString()); let result = (!breakpoint.enabled || !activated) ? DebugEditorModelManager.BREAKPOINT_DISABLED_DECORATION : diff --git a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts index cd6fbefae6e..92b616fe4cf 100644 --- a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts +++ b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts @@ -9,18 +9,52 @@ import { TPromise } from 'vs/base/common/winjs.base'; import Quickopen = require('vs/workbench/browser/quickopen'); import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen'); import Model = require('vs/base/parts/quickopen/browser/quickOpenModel'); -import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IDebugService, ILaunch } from 'vs/workbench/parts/debug/common/debug'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import * as errors from 'vs/base/common/errors'; +import { QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; +import { ICommandService } from 'vs/platform/commands/common/commands'; -class DebugEntry extends Model.QuickOpenEntry { +class AddConfigEntry extends Model.QuickOpenEntry { - constructor(private debugService: IDebugService, private launch: ILaunch, private configurationName: string, highlights: Model.IHighlight[] = []) { + constructor(private label: string, private launch: ILaunch, private commandService: ICommandService, private contextService: IWorkspaceContextService, highlights: Model.IHighlight[] = []) { super(highlights); } public getLabel(): string { - return this.debugService.getConfigurationManager().getLaunches().length <= 1 ? this.configurationName : `${this.configurationName} (${this.launch.name})`; + return this.label; + } + + public getDescription(): string { + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? this.launch.workspace.name : ''; + } + + public getAriaLabel(): string { + return nls.localize('entryAriaLabel', "{0}, debug", this.getLabel()); + } + + public run(mode: QuickOpen.Mode, context: Model.IContext): boolean { + if (mode === QuickOpen.Mode.PREVIEW) { + return false; + } + this.commandService.executeCommand('debug.addConfiguration', this.launch.workspace.uri.toString()).done(undefined, errors.onUnexpectedError); + + return true; + } +} + +class StartDebugEntry extends Model.QuickOpenEntry { + + constructor(private debugService: IDebugService, private contextService: IWorkspaceContextService, private launch: ILaunch, private configurationName: string, highlights: Model.IHighlight[] = []) { + super(highlights); + } + + public getLabel(): string { + return this.configurationName; + } + + public getDescription(): string { + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? this.launch.workspace.name : ''; } public getAriaLabel(): string { @@ -33,7 +67,7 @@ class DebugEntry extends Model.QuickOpenEntry { } // Run selected debug configuration this.debugService.getConfigurationManager().selectConfiguration(this.launch, this.configurationName); - this.debugService.startDebugging(this.launch.workspaceUri).done(undefined, errors.onUnexpectedError); + this.debugService.startDebugging(this.launch.workspace).done(undefined, errors.onUnexpectedError); return true; } @@ -41,9 +75,13 @@ class DebugEntry extends Model.QuickOpenEntry { export class DebugQuickOpenHandler extends Quickopen.QuickOpenHandler { + public static readonly ID = 'workbench.picker.launch'; + private autoFocusIndex: number; + constructor( - @IQuickOpenService private quickOpenService: IQuickOpenService, - @IDebugService private debugService: IDebugService + @IDebugService private debugService: IDebugService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @ICommandService private commandService: ICommandService ) { super(); } @@ -53,20 +91,38 @@ export class DebugQuickOpenHandler extends Quickopen.QuickOpenHandler { } public getResults(input: string): TPromise { - const configurations: DebugEntry[] = []; + const configurations: QuickOpenEntry[] = []; - for (let launch of this.debugService.getConfigurationManager().getLaunches()) { + const configManager = this.debugService.getConfigurationManager(); + const launches = configManager.getLaunches(); + for (let launch of launches) { launch.getConfigurationNames().map(config => ({ config: config, highlights: Filters.matchesContiguousSubString(input, config) })) .filter(({ highlights }) => !!highlights) - .forEach(({ config, highlights }) => configurations.push(new DebugEntry(this.debugService, launch, config, highlights))); + .forEach(({ config, highlights }) => { + if (launch === configManager.selectedLaunch && config === configManager.selectedName) { + this.autoFocusIndex = configurations.length; + } + configurations.push(new StartDebugEntry(this.debugService, this.contextService, launch, config, highlights)); + }); } + launches.forEach((l, index) => { + const label = launches.length > 1 ? nls.localize("addConfigTo", "Add Config ({0})...", l.workspace.name) : nls.localize('addConfiguration', "Add Configuration..."); + const entry = new AddConfigEntry(label, l, this.commandService, this.contextService, Filters.matchesContiguousSubString(input, label)); + if (index === 0) { + configurations.push(new QuickOpenEntryGroup(entry, undefined, true)); + } else { + configurations.push(entry); + } + + }); return TPromise.as(new Model.QuickOpenModel(configurations)); } public getAutoFocus(input: string): QuickOpen.IAutoFocus { return { - autoFocusFirstEntry: !!input + autoFocusFirstEntry: !!input, + autoFocusIndex: this.autoFocusIndex }; } diff --git a/src/vs/workbench/parts/debug/browser/debugStatus.ts b/src/vs/workbench/parts/debug/browser/debugStatus.ts new file mode 100644 index 00000000000..4ed7c675b90 --- /dev/null +++ b/src/vs/workbench/parts/debug/browser/debugStatus.ts @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import * as dom from 'vs/base/browser/dom'; +import * as errors from 'vs/base/common/errors'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; +import { IDebugService, State } from 'vs/workbench/parts/debug/common/debug'; +import { Themable, STATUS_BAR_FOREGROUND } from 'vs/workbench/common/theme'; + +const $ = dom.$; + +export class DebugStatus extends Themable implements IStatusbarItem { + private toDispose: IDisposable[]; + private container: HTMLElement; + private label: HTMLElement; + private icon: HTMLElement; + private hidden = true; + + constructor( + @IQuickOpenService private quickOpenService: IQuickOpenService, + @IDebugService private debugService: IDebugService, + @IThemeService themeService: IThemeService + ) { + super(themeService); + this.toDispose = []; + this.toDispose.push(this.debugService.getConfigurationManager().onDidSelectConfiguration(e => { + this.setLabel(); + })); + this.toDispose.push(this.debugService.onDidChangeState(state => { + if (state !== State.Inactive && this.hidden) { + this.hidden = false; + this.render(this.container); + } + })); + } + + protected updateStyles(): void { + super.updateStyles(); + if (this.icon) { + this.icon.style.backgroundColor = this.getColor(STATUS_BAR_FOREGROUND); + } + } + + public render(container: HTMLElement): IDisposable { + this.container = container; + if (!this.hidden) { + const statusBarItem = dom.append(container, $('.debug-statusbar-item')); + this.toDispose.push(dom.addDisposableListener(statusBarItem, 'click', () => { + this.quickOpenService.show('debug ').done(undefined, errors.onUnexpectedError); + })); + statusBarItem.title = nls.localize('selectAndStartDebug', "Select and start debug configuration"); + const a = dom.append(statusBarItem, $('a')); + this.icon = dom.append(a, $('.icon')); + this.label = dom.append(a, $('span.label')); + this.setLabel(); + this.updateStyles(); + } + + return this; + } + + private setLabel(): void { + if (this.label && !this.hidden) { + const manager = this.debugService.getConfigurationManager(); + const name = manager.selectedName || ''; + this.label.textContent = manager.getLaunches().length > 1 ? `${name} (${manager.selectedLaunch.workspace.name})` : name; + } + } + + public dispose(): void { + super.dispose(); + this.toDispose = dispose(this.toDispose); + } +} diff --git a/src/vs/workbench/parts/debug/browser/debugViewlet.ts b/src/vs/workbench/parts/debug/browser/debugViewlet.ts index 43aa1630336..af6801d50c5 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewlet.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/debugViewlet'; +import * as nls from 'vs/nls'; import { Builder } from 'vs/base/browser/builder'; +import { Action, IAction } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IAction } from 'vs/base/common/actions'; import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { PersistentViewsViewlet } from 'vs/workbench/parts/views/browser/views'; -import { IDebugService, VIEWLET_ID, State } from 'vs/workbench/parts/debug/common/debug'; +import { PersistentViewsViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { IDebugService, VIEWLET_ID, State, VARIABLES_VIEW_ID, WATCH_VIEW_ID, CALLSTACK_VIEW_ID, BREAKPOINTS_VIEW_ID } from 'vs/workbench/parts/debug/common/debug'; import { StartAction, ToggleReplAction, ConfigureAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { StartDebugActionItem } from 'vs/workbench/parts/debug/browser/debugActionItems'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -20,13 +21,13 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ViewLocation } from 'vs/workbench/parts/views/browser/viewsRegistry'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { ViewLocation } from 'vs/workbench/browser/parts/views/viewsRegistry'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; export class DebugViewlet extends PersistentViewsViewlet { - private actions: IAction[]; private startDebugActionItem: StartDebugActionItem; private progressRunner: IProgressRunner; @@ -47,35 +48,30 @@ export class DebugViewlet extends PersistentViewsViewlet { this.progressRunner = null; this._register(this.debugService.onDidChangeState(state => this.onDebugServiceStateChange(state))); + this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateTitleArea())); } - public create(parent: Builder): TPromise { - return super.create(parent).then(() => DOM.addClass(this.viewletContainer, 'debug-viewlet')); + async create(parent: Builder): TPromise { + await super.create(parent); + + const el = parent.getHTMLElement(); + DOM.addClass(el, 'debug-viewlet'); } public focus(): void { super.focus(); - if (!this.contextService.hasWorkspace()) { - this.views[0].focusBody(); - } - if (this.startDebugActionItem) { this.startDebugActionItem.focus(); } } public getActions(): IAction[] { - if (!this.actions) { - this.actions = []; - this.actions.push(this.instantiationService.createInstance(StartAction, StartAction.ID, StartAction.LABEL)); - if (this.contextService.hasWorkspace()) { - this.actions.push(this.instantiationService.createInstance(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL)); - } - this.actions.push(this._register(this.instantiationService.createInstance(ToggleReplAction, ToggleReplAction.ID, ToggleReplAction.LABEL))); - } - - return this.actions; + const actions = []; + actions.push(this.instantiationService.createInstance(StartAction, StartAction.ID, StartAction.LABEL)); + actions.push(this.instantiationService.createInstance(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL)); + actions.push(this._register(this.instantiationService.createInstance(ToggleReplAction, ToggleReplAction.ID, ToggleReplAction.LABEL))); + return actions; } public getSecondaryActions(): IAction[] { @@ -83,7 +79,7 @@ export class DebugViewlet extends PersistentViewsViewlet { } public getActionItem(action: IAction): IActionItem { - if (action.id === StartAction.ID && this.contextService.hasWorkspace()) { + if (action.id === StartAction.ID && !!this.debugService.getConfigurationManager().selectedLaunch) { this.startDebugActionItem = this.instantiationService.createInstance(StartDebugActionItem, null, action); return this.startDebugActionItem; } @@ -91,6 +87,13 @@ export class DebugViewlet extends PersistentViewsViewlet { return null; } + public focusView(id: string): void { + const view = this.getView(id); + if (view) { + view.focus(); + } + } + private onDebugServiceStateChange(state: State): void { if (this.progressRunner) { this.progressRunner.done(); @@ -103,3 +106,75 @@ export class DebugViewlet extends PersistentViewsViewlet { } } } + +export class FocusVariablesViewAction extends Action { + + static ID = 'workbench.debug.action.focusVariablesView'; + static LABEL = nls.localize('debugFocusVariablesView', 'Focus Variables'); + + constructor(id: string, label: string, + @IViewletService private viewletService: IViewletService + ) { + super(id, label); + } + + public run(): TPromise { + return this.viewletService.openViewlet(VIEWLET_ID).then((viewlet: DebugViewlet) => { + viewlet.focusView(VARIABLES_VIEW_ID); + }); + } +} + +export class FocusWatchViewAction extends Action { + + static ID = 'workbench.debug.action.focusWatchView'; + static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusWatchView' }, 'Focus Watch'); + + constructor(id: string, label: string, + @IViewletService private viewletService: IViewletService + ) { + super(id, label); + } + + public run(): TPromise { + return this.viewletService.openViewlet(VIEWLET_ID).then((viewlet: DebugViewlet) => { + viewlet.focusView(WATCH_VIEW_ID); + }); + } +} + +export class FocusCallStackViewAction extends Action { + + static ID = 'workbench.debug.action.focusCallStackView'; + static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusCallStackView' }, 'Focus CallStack'); + + constructor(id: string, label: string, + @IViewletService private viewletService: IViewletService + ) { + super(id, label); + } + + public run(): TPromise { + return this.viewletService.openViewlet(VIEWLET_ID).then((viewlet: DebugViewlet) => { + viewlet.focusView(CALLSTACK_VIEW_ID); + }); + } +} + +export class FocusBreakpointsViewAction extends Action { + + static ID = 'workbench.debug.action.focusBreakpointsView'; + static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusBreakpointsView' }, 'Focus Breakpoints'); + + constructor(id: string, label: string, + @IViewletService private viewletService: IViewletService + ) { + super(id, label); + } + + public run(): TPromise { + return this.viewletService.openViewlet(VIEWLET_ID).then((viewlet: DebugViewlet) => { + viewlet.focusView(BREAKPOINTS_VIEW_ID); + }); + } +} diff --git a/src/vs/workbench/parts/debug/browser/exceptionWidget.ts b/src/vs/workbench/parts/debug/browser/exceptionWidget.ts index 3719a86393b..d5cf00cb85a 100644 --- a/src/vs/workbench/parts/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/parts/debug/browser/exceptionWidget.ts @@ -8,8 +8,7 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { IDebugService, IExceptionInfo } from 'vs/workbench/parts/debug/common/debug'; +import { IExceptionInfo } from 'vs/workbench/parts/debug/common/debug'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; @@ -21,15 +20,13 @@ const $ = dom.$; // theming export const debugExceptionWidgetBorder = registerColor('debugExceptionWidget.border', { dark: '#a31515', light: '#a31515', hc: '#a31515' }, nls.localize('debugExceptionWidgetBorder', 'Exception widget border color.')); -export const debugExceptionWidgetBackground = registerColor('debugExceptionWidget.background', { dark: '#a3151540', light: '#a315150d', hc: '#a3151573' }, nls.localize('debugExceptionWidgetBackground', 'Exception widget background color.')); +export const debugExceptionWidgetBackground = registerColor('debugExceptionWidget.background', { dark: '#420b0d', light: '#f1dfde', hc: '#420b0d' }, nls.localize('debugExceptionWidgetBackground', 'Exception widget background color.')); export class ExceptionWidget extends ZoneWidget { private _backgroundColor: Color; - constructor(editor: ICodeEditor, private exceptionInfo: IExceptionInfo, private lineNumber: number, - @IContextViewService private contextViewService: IContextViewService, - @IDebugService private debugService: IDebugService, + constructor(editor: ICodeEditor, private exceptionInfo: IExceptionInfo, @IThemeService themeService: IThemeService, @IInstantiationService private instantiationService: IInstantiationService ) { diff --git a/src/vs/workbench/parts/debug/browser/linkDetector.ts b/src/vs/workbench/parts/debug/browser/linkDetector.ts index a419b37aa4f..650b4fc5319 100644 --- a/src/vs/workbench/parts/debug/browser/linkDetector.ts +++ b/src/vs/workbench/parts/debug/browser/linkDetector.ts @@ -3,14 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import strings = require('vs/base/common/strings'); import uri from 'vs/base/common/uri'; import { isMacintosh } from 'vs/base/common/platform'; import * as errors from 'vs/base/common/errors'; import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import * as nls from 'vs/nls'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export class LinkDetector { private static FILE_LOCATION_PATTERNS: RegExp[] = [ @@ -24,8 +22,7 @@ export class LinkDetector { ]; constructor( - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IWorkspaceContextService private contextService: IWorkspaceContextService + @IWorkbenchEditorService private editorService: IWorkbenchEditorService ) { // noop } @@ -46,11 +43,6 @@ export class LinkDetector { let match = pattern.exec(text); while (match !== null) { let resource: uri = null; - try { - resource = (match && !strings.startsWith(match[0], 'http')) - && (match[2] || strings.startsWith(match[1], '/') ? uri.file(match[1]) : this.contextService.toResource(match[1])); // TODO@Michel TODO@Isidor (https://github.com/Microsoft/vscode/issues/29190) - } catch (e) { } - if (!resource) { match = pattern.exec(text); continue; diff --git a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css index 87918a9013a..05d23a6ffd0 100644 --- a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css @@ -102,6 +102,21 @@ box-sizing: border-box; } +/* Debug status */ +/* A very precise css rule to overwrite the display set in statusbar.css */ +.monaco-workbench > .part.statusbar > .statusbar-item > .debug-statusbar-item > a:not([disabled]):not(.disabled) { + display: flex; + padding: 0 5px 0 5px; +} + +.monaco-workbench .part.statusbar .debug-statusbar-item .icon { + -webkit-mask: url('continue.svg') no-repeat 50% 50%; + -webkit-mask-size: 18px; + display: inline-block; + padding-right: 2px; + width: 16px; +} + /* Expressions */ .monaco-workbench .monaco-tree-row .expression { diff --git a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css index 174bf9f39aa..208bf5a0716 100644 --- a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css @@ -200,6 +200,7 @@ overflow: hidden; text-overflow: ellipsis; padding-right: 0.8em; + display: flex; } .debug-viewlet .debug-call-stack .stack-frame.label { @@ -207,6 +208,12 @@ font-style: italic; } +.debug-viewlet .debug-call-stack .stack-frame .label { + flex: 1; + flex-shrink: 0; + min-width: fit-content; +} + .debug-viewlet .debug-call-stack .stack-frame.subtle { font-style: italic; } @@ -216,7 +223,10 @@ } .debug-viewlet .debug-call-stack .stack-frame > .file { - float: right; + display: flex; + overflow: hidden; + flex-wrap: wrap; + justify-content: flex-end; } .debug-viewlet .debug-call-stack .stack-frame > .file > .line-number.unavailable { @@ -227,6 +237,11 @@ color: rgba(108, 108, 108, 0.8); } +.debug-viewlet .debug-call-stack .stack-frame > .file > .file-name { + overflow: hidden; + text-overflow: ellipsis; +} + .vs-dark .debug-viewlet .debug-call-stack > .monaco-tree-row:not(.selected) .stack-frame > .file { color: rgba(204, 204, 204, 0.6); } diff --git a/src/vs/workbench/parts/debug/browser/media/repl.css b/src/vs/workbench/parts/debug/browser/media/repl.css index 01c8566b02b..045daba87c5 100644 --- a/src/vs/workbench/parts/debug/browser/media/repl.css +++ b/src/vs/workbench/parts/debug/browser/media/repl.css @@ -36,6 +36,22 @@ font-size: 12px; } +.monaco-workbench .repl .repl-tree .monaco-tree-row .output.expression.value-and-source { + display: flex; +} + + +.monaco-workbench .repl .repl-tree .monaco-tree-row .output.expression.value-and-source .value { + flex: 1; +} + +.monaco-workbench .repl .repl-tree .monaco-tree-row .output.expression.value-and-source .source { + margin-left: 4px; + margin-right: 8px; + cursor: pointer; + text-decoration: underline; +} + .monaco-workbench.windows .repl .repl-tree .monaco-tree-row .input.expression, .monaco-workbench.windows .repl .repl-tree .monaco-tree-row .output.expression, .monaco-workbench.linux .repl .repl-tree .monaco-tree-row .input.expression, diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index b211bcc96cb..f87ee2d6c80 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -17,9 +17,14 @@ import { ISuggestion } from 'vs/editor/common/modes'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { Range, IRange } from 'vs/editor/common/core/range'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; export const VIEWLET_ID = 'workbench.view.debug'; +export const VARIABLES_VIEW_ID = 'workbench.debug.variablesView'; +export const WATCH_VIEW_ID = 'workbench.debug.watchExpressionsView'; +export const CALLSTACK_VIEW_ID = 'workbench.debug.callStackView'; +export const BREAKPOINTS_VIEW_ID = 'workbench.debug.breakPointsView'; export const REPL_ID = 'workbench.panel.repl'; export const DEBUG_SERVICE_ID = 'debugService'; export const CONTEXT_DEBUG_TYPE = new RawContextKey('debugType', undefined); @@ -51,7 +56,6 @@ export interface IRawModelUpdate { thread?: DebugProtocol.Thread; callStack?: DebugProtocol.StackFrame[]; stoppedDetails?: IRawStoppedDetails; - allThreadsStopped?: boolean; } export interface IRawStoppedDetails { @@ -72,6 +76,13 @@ export interface ITreeElement { export interface IReplElement extends ITreeElement { toString(): string; + sourceData?: IReplElementSource; +} + +export interface IReplElementSource { + source: Source; + lineNumber: number; + column: number; } export interface IExpressionContainer extends ITreeElement { @@ -87,7 +98,7 @@ export interface IExpression extends IReplElement, IExpressionContainer { } export interface ISession { - root: uri; + root: IWorkspaceFolder; stackTrace(args: DebugProtocol.StackTraceArguments): TPromise; exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): TPromise; scopes(args: DebugProtocol.ScopesArguments): TPromise; @@ -99,6 +110,7 @@ export interface ISession { custom(request: string, args: any): TPromise; onDidEvent: Event; onDidInitialize: Event; + onDidExitAdapter: Event; restartFrame(args: DebugProtocol.RestartFrameArguments, threadId: number): TPromise; next(args: DebugProtocol.NextArguments): TPromise; @@ -128,6 +140,7 @@ export interface IProcess extends ITreeElement { state: ProcessState; getThread(threadId: number): IThread; getAllThreads(): IThread[]; + getSource(raw: DebugProtocol.Source): Source; completions(frameId: number, text: string, position: Position, overwriteBefore: number): TPromise; } @@ -291,7 +304,7 @@ export interface IModel extends ITreeElement { onDidChangeCallStack: Event; onDidChangeWatchExpressions: Event; onDidChangeReplElements: Event; -}; +} // Debug enums @@ -306,6 +319,7 @@ export enum State { export interface IDebugConfiguration { allowBreakpointsEverywhere: boolean; + openDebug: string; openExplorerOnEnd: boolean; inlineValues: boolean; hideActionBar: boolean; @@ -361,8 +375,7 @@ export interface IRawAdapter extends IRawEnvAdapter { enableBreakpointsFor?: { languageIds: string[] }; configurationAttributes?: any; configurationSnippets?: IJSONSchemaSnippet[]; - initialConfigurations?: any[] | string; - startSessionCommand?: string; + initialConfigurations?: any[]; languages?: string[]; variables?: { [key: string]: string }; aiKey?: string; @@ -375,8 +388,9 @@ export interface IRawAdapter extends IRawEnvAdapter { export interface IDebugConfigurationProvider { type: string; - resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: any): TPromise; - provideDebugConfigurations?(folderUri: uri | undefined): TPromise; + handle: number; + resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: IConfig): TPromise; + provideDebugConfigurations?(folderUri: uri | undefined): TPromise; } export interface IConfigurationManager { @@ -401,16 +415,9 @@ export interface IConfigurationManager { */ onDidSelectConfiguration: Event; - /** - * Returns a "startSessionCommand" contribution for an adapter with the passed type. - * If no type is specified will try to automatically pick an adapter by looking at - * the active editor language and matching it against the "languages" contribution of an adapter. - */ - getStartSessionCommand(type?: string): TPromise<{ command: string, type: string }>; - registerDebugConfigurationProvider(handle: number, debugConfigurationProvider: IDebugConfigurationProvider): void; unregisterDebugConfigurationProvider(handle: number): void; - resolveDebugConfiguration(folderUri: uri | undefined, debugConfiguration: any): TPromise; + resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): TPromise; } export interface ILaunch { @@ -420,9 +427,7 @@ export interface ILaunch { */ uri: uri; - workspaceUri: uri; - - name: string; + workspace: IWorkspaceFolder; /** * Returns a configuration with the specified name. @@ -583,19 +588,9 @@ export interface IDebugService { /** * Starts debugging. If the configOrName is not passed uses the selected configuration in the debug dropdown. * Also saves all files, manages if compounds are present in the configuration - * and calls the startSessionCommand if an adapter registered it. + * and resolveds configurations via DebugConfigurationProviders. */ - startDebugging(root: uri, configOrName?: IConfig | string, noDebug?: boolean): TPromise; - - /** - * Creates a new debug process. Depending on the configuration will either 'launch' or 'attach'. - */ - createProcess(root: uri, config: IConfig): TPromise; - - /** - * Find process by ID. - */ - findProcessByUUID(uuid: string): IProcess | null; + startDebugging(root: IWorkspaceFolder, configOrName?: IConfig | string, noDebug?: boolean): TPromise; /** * Restarts a process or creates a new one if there is no active session. diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 56561224d93..c8ef0226454 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import uri from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import { TPromise } from 'vs/base/common/winjs.base'; import * as lifecycle from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; @@ -19,7 +19,7 @@ import { Range, IRange } from 'vs/editor/common/core/range'; import { ISuggestion } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import { - ITreeElement, IExpression, IExpressionContainer, IProcess, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IModel, + ITreeElement, IExpression, IExpressionContainer, IProcess, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IModel, IReplElementSource, IConfig, ISession, IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IRawBreakpoint, IExceptionInfo, IReplElement, ProcessState } from 'vs/workbench/parts/debug/common/debug'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; @@ -27,28 +27,28 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi const MAX_REPL_LENGTH = 10000; -export abstract class AbstractOutputElement implements IReplElement { +export abstract class AbstractReplElement implements IReplElement { private static ID_COUNTER = 0; - constructor(private id = AbstractOutputElement.ID_COUNTER++) { + constructor(public sourceData: IReplElementSource, private id = AbstractReplElement.ID_COUNTER++) { // noop } public getId(): string { - return `outputelement:${this.id}`; + return `replelement:${this.id}`; } abstract toString(): string; } -export class OutputElement extends AbstractOutputElement { - +export class SimpleReplElement extends AbstractReplElement { constructor( public value: string, public severity: severity, + source: IReplElementSource, ) { - super(); + super(source); } public toString(): string { @@ -56,12 +56,12 @@ export class OutputElement extends AbstractOutputElement { } } -export class OutputNameValueElement extends AbstractOutputElement implements IExpression { +export class RawObjectReplElement extends AbstractReplElement implements IExpression { private static MAX_CHILDREN = 1000; // upper bound of children per value - constructor(public name: string, public valueObj: any, public annotation?: string) { - super(); + constructor(public name: string, public valueObj: any, source?: IReplElementSource, public annotation?: string) { + super(source); } public get value(): string { @@ -85,11 +85,11 @@ export class OutputNameValueElement extends AbstractOutputElement implements IEx public getChildren(): TPromise { let result: IExpression[] = []; if (Array.isArray(this.valueObj)) { - result = (this.valueObj).slice(0, OutputNameValueElement.MAX_CHILDREN) - .map((v, index) => new OutputNameValueElement(String(index), v)); + result = (this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) + .map((v, index) => new RawObjectReplElement(String(index), v)); } else if (isObject(this.valueObj)) { - result = Object.getOwnPropertyNames(this.valueObj).slice(0, OutputNameValueElement.MAX_CHILDREN) - .map(key => new OutputNameValueElement(key, this.valueObj[key])); + result = Object.getOwnPropertyNames(this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN) + .map(key => new RawObjectReplElement(key, this.valueObj[key])); } return TPromise.as(result); @@ -184,7 +184,7 @@ export class ExpressionContainer implements IExpressionContainer { } private fetchVariables(start: number, count: number, filter: 'indexed' | 'named'): TPromise { - return this.process.session.variables({ + return this.process.state !== ProcessState.INACTIVE ? this.process.session.variables({ variablesReference: this.reference, start, count, @@ -193,7 +193,7 @@ export class ExpressionContainer implements IExpressionContainer { return response && response.body && response.body.variables ? distinct(response.body.variables.filter(v => !!v && v.name), v => v.name).map( v => new Variable(this.process, this, v.variablesReference, v.name, v.evaluateName, v.value, v.namedVariables, v.indexedVariables, v.type) ) : []; - }, (e: Error) => [new Variable(this.process, this, 0, null, e.message, '', 0, 0, null, false)]); + }, (e: Error) => [new Variable(this.process, this, 0, null, e.message, '', 0, 0, null, false)]) : TPromise.as([]); } // The adapter explicitly sents the children count of an expression only if there are lots of children which should be chunked. @@ -282,7 +282,7 @@ export class Variable extends ExpressionContainer implements IExpression { public available = true, startOfVariables = 0 ) { - super(process, reference, `variable:${parent.getId()}:${name}:${reference}`, namedVariables, indexedVariables, startOfVariables); + super(process, reference, `variable:${parent.getId()}:${name}`, namedVariables, indexedVariables, startOfVariables); this.value = value; } @@ -313,6 +313,7 @@ export class Scope extends ExpressionContainer implements IScope { constructor( stackFrame: IStackFrame, + index: number, public name: string, reference: number, public expensive: boolean, @@ -320,7 +321,7 @@ export class Scope extends ExpressionContainer implements IScope { indexedVariables: number, public range?: IRange ) { - super(stackFrame.thread.process, reference, `scope:${stackFrame.getId()}:${name}:${reference}`, namedVariables, indexedVariables); + super(stackFrame.thread.process, reference, `scope:${stackFrame.getId()}:${name}:${index}`, namedVariables, indexedVariables); } } @@ -348,7 +349,7 @@ export class StackFrame implements IStackFrame { if (!this.scopes) { this.scopes = this.thread.process.session.scopes({ frameId: this.frameId }).then(response => { return response && response.body && response.body.scopes ? - response.body.scopes.map(rs => new Scope(this, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables, + response.body.scopes.map((rs, index) => new Scope(this, index, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables, rs.line && rs.column && rs.endLine && rs.endColumn ? new Range(rs.line, rs.column, rs.endLine, rs.endColumn) : null)) : []; }, err => []); } @@ -379,18 +380,8 @@ export class StackFrame implements IStackFrame { } public openInEditor(editorService: IWorkbenchEditorService, preserveFocus?: boolean, sideBySide?: boolean): TPromise { - - return !this.source.available ? TPromise.as(null) : editorService.openEditor({ - resource: this.source.uri, - description: this.source.origin, - options: { - preserveFocus, - selection: this.range, - revealIfVisible: true, - revealInCenterIfOutsideViewport: true, - pinned: !preserveFocus && !this.source.inMemory - } - }, sideBySide); + return !this.source.available ? TPromise.as(null) : + this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide); } } @@ -459,12 +450,7 @@ export class Thread implements IThread { } return response.body.stackFrames.map((rsf, index) => { - let source = new Source(rsf.source); - if (this.process.sources.has(source.uri.toString())) { - source = this.process.sources.get(source.uri.toString()); - } else { - this.process.sources.set(source.uri.toString(), source); - } + const source = this.process.getSource(rsf.source); return new StackFrame(this, rsf.id, source, rsf.name, rsf.presentationHint, new Range( rsf.line, @@ -545,7 +531,7 @@ export class Process implements IProcess { public sources: Map; private threads: Map; - private inactive = true; + public inactive = true; constructor(public configuration: IConfig, private _session: ISession & ITreeElement) { this.threads = new Map(); @@ -558,7 +544,7 @@ export class Process implements IProcess { } public getName(includeRoot: boolean): string { - return includeRoot ? `${this.configuration.name} (${paths.basename(this.session.root.fsPath)})` : this.configuration.name; + return includeRoot ? `${this.configuration.name} (${resources.basenameOrAuthority(this.session.root.uri)})` : this.configuration.name; } public get state(): ProcessState { @@ -569,6 +555,17 @@ export class Process implements IProcess { return this.configuration.type === 'attach' ? ProcessState.ATTACH : ProcessState.LAUNCH; } + public getSource(raw: DebugProtocol.Source): Source { + let source = new Source(raw, this.getId()); + if (this.sources.has(source.uri.toString())) { + source = this.sources.get(source.uri.toString()); + } else { + this.sources.set(source.uri.toString(), source); + } + + return source; + } + public getThread(threadId: number): Thread { return this.threads.get(threadId); } @@ -596,7 +593,7 @@ export class Process implements IProcess { if (data.stoppedDetails) { // Set the availability of the threads' callstacks depending on // whether the thread is stopped or not - if (data.allThreadsStopped) { + if (data.stoppedDetails.allThreadsStopped) { this.threads.forEach(thread => { thread.stoppedDetails = thread.threadId === data.threadId ? data.stoppedDetails : { reason: undefined }; thread.stopped = true; @@ -613,7 +610,7 @@ export class Process implements IProcess { } public clearThreads(removeThreads: boolean, reference: number = undefined): void { - if (reference) { + if (reference !== undefined && reference !== null) { if (this.threads.has(reference)) { const thread = this.threads.get(reference); thread.clearCallStack(); @@ -685,6 +682,7 @@ export class Breakpoint implements IBreakpoint { public enabled: boolean, public condition: string, public hitCondition: string, + public adapterData: any ) { if (enabled === undefined) { this.enabled = true; @@ -865,12 +863,16 @@ export class Model implements IModel { this._onDidChangeBreakpoints.fire(); } - public addBreakpoints(uri: uri, rawData: IRawBreakpoint[]): void { - this.breakpoints = this.breakpoints.concat(rawData.map(rawBp => - new Breakpoint(uri, rawBp.lineNumber, rawBp.column, rawBp.enabled, rawBp.condition, rawBp.hitCondition))); + public addBreakpoints(uri: uri, rawData: IRawBreakpoint[], fireEvent = true): Breakpoint[] { + const newBreakpoints = rawData.map(rawBp => new Breakpoint(uri, rawBp.lineNumber, rawBp.column, rawBp.enabled, rawBp.condition, rawBp.hitCondition, undefined)); + this.breakpoints = this.breakpoints.concat(newBreakpoints); this.breakpointsActivated = true; this.breakpoints = distinct(this.breakpoints, bp => `${bp.uri.toString()}:${bp.lineNumber}:${bp.column}`); - this._onDidChangeBreakpoints.fire(); + if (fireEvent) { + this._onDidChangeBreakpoints.fire(); + } + + return newBreakpoints; } public removeBreakpoints(toRemove: IBreakpoint[]): void { @@ -889,6 +891,7 @@ export class Model implements IModel { bp.verified = bpData.verified; bp.idFromAdapter = bpData.id; bp.message = bpData.message; + bp.adapterData = bpData.source ? bpData.source.adapterData : bp.adapterData; } }); this.breakpoints = distinct(this.breakpoints, bp => `${bp.uri.toString()}:${bp.lineNumber}:${bp.column}`); @@ -913,7 +916,6 @@ export class Model implements IModel { bp.verified = false; } }); - this.exceptionBreakpoints.forEach(ebp => ebp.enabled = enable); this.functionBreakpoints.forEach(fbp => fbp.enabled = enable); this._onDidChangeBreakpoints.fire(); @@ -954,23 +956,23 @@ export class Model implements IModel { .then(() => this._onDidChangeREPLElements.fire()); } - public appendToRepl(output: string | IExpression, severity: severity): void { - if (typeof output === 'string') { - const previousOutput = this.replElements.length && (this.replElements[this.replElements.length - 1] as OutputElement); + public appendToRepl(data: string | IExpression, severity: severity, source?: IReplElementSource): void { + if (typeof data === 'string') { + const previousElement = this.replElements.length && (this.replElements[this.replElements.length - 1] as SimpleReplElement); - const toAdd = output.split('\n').map(line => new OutputElement(line, severity)); - if (previousOutput instanceof OutputElement && severity === previousOutput.severity && toAdd.length) { - previousOutput.value += toAdd.shift().value; - } - if (previousOutput && previousOutput.value === '' && previousOutput.severity !== severity) { - // remove potential empty lines between different output types + const toAdd = data.split('\n').map((line, index) => new SimpleReplElement(line, severity, index === 0 ? source : undefined)); + if (previousElement && previousElement.value === '') { + // remove potential empty lines between different repl types this.replElements.pop(); + } else if (previousElement instanceof SimpleReplElement && severity === previousElement.severity && toAdd.length && toAdd[0].sourceData === previousElement.sourceData) { + previousElement.value += toAdd.shift().value; } this.addReplElements(toAdd); } else { // TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression - (output).severity = severity; - this.addReplElements([output]); + (data).severity = severity; + (data).sourceData = source; + this.addReplElements([data]); } this._onDidChangeREPLElements.fire(); diff --git a/src/vs/workbench/parts/debug/common/debugProtocol.d.ts b/src/vs/workbench/parts/debug/common/debugProtocol.d.ts index 0892be44843..b6c73dc89a8 100644 --- a/src/vs/workbench/parts/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/parts/debug/common/debugProtocol.d.ts @@ -178,7 +178,7 @@ declare module DebugProtocol { // event: 'breakpoint'; body: { /** The reason for the event. - Values: 'changed', 'new', etc. + Values: 'changed', 'new', 'removed', etc. */ reason: string; /** The breakpoint. */ @@ -283,6 +283,8 @@ declare module DebugProtocol { clientID?: string; /** The ID of the debug adapter. */ adapterID: string; + /** The ISO-639 locale of the (frontend) client using this adapter, e.g. en-US or de-CH. */ + locale?: string; /** If true all line numbers are 1-based (default). */ linesStartAt1?: boolean; /** If true all column numbers are 1-based (default). */ diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index 4ccf9f55e43..a154158dc82 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -4,23 +4,36 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; +import { TPromise } from 'vs/base/common/winjs.base'; import uri from 'vs/base/common/uri'; +import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import { DEBUG_SCHEME } from 'vs/workbench/parts/debug/common/debug'; +import { IRange } from 'vs/editor/common/core/range'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source"); export class Source { - public uri: uri; + public readonly uri: uri; public available: boolean; - constructor(public raw: DebugProtocol.Source) { + constructor(public readonly raw: DebugProtocol.Source, sessionId: string) { if (!raw) { this.raw = { name: UNKNOWN_SOURCE_LABEL }; } - const path = this.raw.path || this.raw.name; this.available = this.raw.name !== UNKNOWN_SOURCE_LABEL; - this.uri = this.raw.sourceReference > 0 ? uri.parse(`${DEBUG_SCHEME}:${path}`) : uri.file(path); + const path = this.raw.path || this.raw.name; + if (this.raw.sourceReference > 0) { + this.uri = uri.parse(`${DEBUG_SCHEME}:${encodeURIComponent(path)}?session=${encodeURIComponent(sessionId)}&ref=${this.raw.sourceReference}`); + } else { + if (paths.isAbsolute(path)) { + this.uri = uri.file(path); // path should better be absolute! + } else { + this.uri = uri.parse(path); + } + } } public get name() { @@ -40,6 +53,61 @@ export class Source { } public get inMemory() { - return this.uri.toString().indexOf(`${DEBUG_SCHEME}:`) === 0; + return this.uri.scheme === DEBUG_SCHEME; } -} + + public openInEditor(editorService: IWorkbenchEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean): TPromise { + return !this.available ? TPromise.as(null) : editorService.openEditor({ + resource: this.uri, + description: this.origin, + options: { + preserveFocus, + selection, + revealIfVisible: true, + revealInCenterIfOutsideViewport: true, + pinned: !preserveFocus && !this.inMemory + } + }, sideBySide); + } + + public static getEncodedDebugData(modelUri: uri): { name: string, path: string, processId: string, sourceReference: number } { + let path: string; + let sourceReference: number; + let processId: string; + + switch (modelUri.scheme) { + case 'file': + path = paths.normalize(modelUri.fsPath, true); + break; + case DEBUG_SCHEME: + path = modelUri.path; + if (modelUri.query) { + const keyvalues = modelUri.query.split('&'); + for (let keyvalue of keyvalues) { + const pair = keyvalue.split('='); + if (pair.length === 2) { + switch (pair[0]) { + case 'session': + processId = decodeURIComponent(pair[1]); + break; + case 'ref': + sourceReference = parseInt(pair[1]); + break; + } + } + } + } + break; + default: + path = modelUri.toString(); + break; + } + + return { + name: resources.basenameOrAuthority(modelUri), + path, + sourceReference, + processId + }; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/common/debugViewModel.ts b/src/vs/workbench/parts/debug/common/debugViewModel.ts index d394b47018d..2da97bc70b5 100644 --- a/src/vs/workbench/parts/debug/common/debugViewModel.ts +++ b/src/vs/workbench/parts/debug/common/debugViewModel.ts @@ -17,14 +17,12 @@ export class ViewModel implements debug.IViewModel { private _onDidSelectExpression: Emitter; private _onDidSelectFunctionBreakpoint: Emitter; private multiProcessView: boolean; - public changedWorkbenchViewState: boolean; constructor() { this._onDidFocusProcess = new Emitter(); this._onDidFocusStackFrame = new Emitter<{ stackFrame: debug.IStackFrame, explicit: boolean }>(); this._onDidSelectExpression = new Emitter(); this._onDidSelectFunctionBreakpoint = new Emitter(); - this.changedWorkbenchViewState = false; this.multiProcessView = false; } diff --git a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts index 1d7a39e00c0..5bc4348995b 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts @@ -7,17 +7,21 @@ import 'vs/css!../browser/media/debug.contribution'; import 'vs/css!../browser/media/debugHover'; import * as nls from 'vs/nls'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionRegistryExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionRegistryExtensions } from 'vs/workbench/common/actions'; import { ToggleViewletAction, Extensions as ViewletExtensions, ViewletRegistry, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { TogglePanelAction, Extensions as PanelExtensions, PanelRegistry, PanelDescriptor } from 'vs/workbench/browser/panel'; +import { StatusbarItemDescriptor, StatusbarAlignment, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { VariablesView, WatchExpressionsView, CallStackView, BreakpointsView } from 'vs/workbench/parts/debug/electron-browser/debugViews'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { IDebugService, VIEWLET_ID, REPL_ID, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/parts/debug/common/debug'; +import { + IDebugService, VIEWLET_ID, REPL_ID, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA, + CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID +} from 'vs/workbench/parts/debug/common/debug'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { DebugEditorModelManager } from 'vs/workbench/parts/debug/browser/debugEditorModelManager'; @@ -34,7 +38,14 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import * as debugCommands from 'vs/workbench/parts/debug/electron-browser/debugCommands'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { StatusBarColorProvider } from 'vs/workbench/parts/debug/electron-browser/statusbarColorProvider'; -import { ViewLocation, ViewsRegistry } from 'vs/workbench/parts/views/browser/viewsRegistry'; +import { ViewLocation, ViewsRegistry } from 'vs/workbench/browser/parts/views/viewsRegistry'; +import { isMacintosh } from 'vs/base/common/platform'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import URI from 'vs/base/common/uri'; +import { DebugViewlet, FocusVariablesViewAction, FocusBreakpointsViewAction, FocusCallStackViewAction, FocusWatchViewAction } from 'vs/workbench/parts/debug/browser/debugViewlet'; +import { Repl } from 'vs/workbench/parts/debug/electron-browser/repl'; +import { DebugQuickOpenHandler } from 'vs/workbench/parts/debug/browser/debugQuickOpen'; +import { DebugStatus } from 'vs/workbench/parts/debug/browser/debugStatus'; class OpenDebugViewletAction extends ToggleViewletAction { public static ID = VIEWLET_ID; @@ -66,8 +77,7 @@ class OpenDebugPanelAction extends TogglePanelAction { // register viewlet Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( - 'vs/workbench/parts/debug/browser/debugViewlet', - 'DebugViewlet', + DebugViewlet, VIEWLET_ID, nls.localize('debug', "Debug"), 'debug', @@ -83,8 +93,7 @@ const openPanelKb: IKeybindings = { // register repl panel Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( - 'vs/workbench/parts/debug/electron-browser/repl', - 'Repl', + Repl, REPL_ID, nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'), 'repl', @@ -94,10 +103,10 @@ Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescri Registry.as(PanelExtensions.Panels).setDefaultPanelId(REPL_ID); // Register default debug views -ViewsRegistry.registerViews([{ id: 'workbench.debug.variablesView', name: nls.localize('variables', "Variables"), ctor: VariablesView, order: 10, size: 40, location: ViewLocation.Debug, canToggleVisibility: true }]); -ViewsRegistry.registerViews([{ id: 'workbench.debug.watchExpressionsView', name: nls.localize('watch', "Watch"), ctor: WatchExpressionsView, order: 20, size: 10, location: ViewLocation.Debug, canToggleVisibility: true }]); -ViewsRegistry.registerViews([{ id: 'workbench.debug.callStackView', name: nls.localize('callStack', "Call Stack"), ctor: CallStackView, order: 30, size: 30, location: ViewLocation.Debug, canToggleVisibility: true }]); -ViewsRegistry.registerViews([{ id: 'workbench.debug.breakPointsView', name: nls.localize('breakpoints', "Breakpoints"), ctor: BreakpointsView, order: 40, size: 20, location: ViewLocation.Debug, canToggleVisibility: true }]); +ViewsRegistry.registerViews([{ id: VARIABLES_VIEW_ID, name: nls.localize('variables', "Variables"), ctor: VariablesView, order: 10, size: 40, location: ViewLocation.Debug, canToggleVisibility: true }]); +ViewsRegistry.registerViews([{ id: WATCH_VIEW_ID, name: nls.localize('watch', "Watch"), ctor: WatchExpressionsView, order: 20, size: 10, location: ViewLocation.Debug, canToggleVisibility: true }]); +ViewsRegistry.registerViews([{ id: CALLSTACK_VIEW_ID, name: nls.localize('callStack', "Call Stack"), ctor: CallStackView, order: 30, size: 30, location: ViewLocation.Debug, canToggleVisibility: true }]); +ViewsRegistry.registerViews([{ id: BREAKPOINTS_VIEW_ID, name: nls.localize('breakpoints', "Breakpoints"), ctor: BreakpointsView, order: 40, size: 20, location: ViewLocation.Debug, canToggleVisibility: true }]); // register action to open viewlet const registry = Registry.as(WorkbenchActionRegistryExtensions.WorkbenchActions); @@ -123,19 +132,24 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(PauseAction, PauseActi registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory); -registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5 }, CONTEXT_NOT_IN_DEBUG_MODE), 'Debug: Start Without Debugging', debugCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5, mac: { primary: KeyMod.WinCtrl | KeyCode.F5 } }, CONTEXT_NOT_IN_DEBUG_MODE), 'Debug: Start Without Debugging', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(FocusReplAction, FocusReplAction.ID, FocusReplAction.LABEL), 'Debug: Focus Debug Console', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusVariablesViewAction, FocusVariablesViewAction.ID, FocusVariablesViewAction.LABEL), 'Debug: Focus Variables', debugCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusWatchViewAction, FocusWatchViewAction.ID, FocusWatchViewAction.LABEL), 'Debug: Focus Watch', debugCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusCallStackViewAction, FocusCallStackViewAction.ID, FocusCallStackViewAction.LABEL), 'Debug: Focus CallStack', debugCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusBreakpointsViewAction, FocusBreakpointsViewAction.ID, FocusBreakpointsViewAction.LABEL), 'Debug: Focus Breakpoints', debugCategory); + // Register Quick Open (Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/debug/browser/debugQuickOpen', - 'DebugQuickOpenHandler', + DebugQuickOpenHandler, + DebugQuickOpenHandler.ID, 'debug ', 'inLaunchConfigurationsPicker', nls.localize('debugCommands', "Debug Configuration") @@ -174,6 +188,11 @@ configurationRegistry.registerConfiguration({ default: false }, 'debug.internalConsoleOptions': INTERNAL_CONSOLE_OPTIONS_SCHEMA, + 'debug.openDebug': { + enum: ['neverOpen', 'openOnSessionStart', 'openOnFirstSessionStart'], + default: 'openOnFirstSessionStart', + description: nls.localize('openDebug', "Controls whether debug viewlet should be open on debugging session start.") + }, 'launch': { type: 'object', description: nls.localize({ comment: ['This is the description for a setting'], key: 'launch' }, "Global debug launch configuration. Should be used as an alternative to 'launch.json' that is shared across workspaces"), @@ -183,3 +202,31 @@ configurationRegistry.registerConfiguration({ }); debugCommands.registerCommands(); + +// Register Debug Status +const statusBar = Registry.as(StatusExtensions.Statusbar); +statusBar.registerStatusbarItem(new StatusbarItemDescriptor(DebugStatus, StatusbarAlignment.LEFT, 30 /* Low Priority */)); + +// Touch Bar +if (isMacintosh) { + + const registerTouchBarEntry = (id: string, title: string, order, when: ContextKeyExpr, icon: string) => { + MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { + command: { + id, title, iconPath: URI.parse(require.toUrl(`vs/workbench/parts/debug/electron-browser/media/${icon}`)).fsPath + }, + when, + group: '9_debug', + order + }); + }; + + registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_NOT_IN_DEBUG_MODE, 'continue-tb.png'); + registerTouchBarEntry(ContinueAction.ID, ContinueAction.LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png'); + registerTouchBarEntry(PauseAction.ID, PauseAction.LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png'); + registerTouchBarEntry(StepOverAction.ID, StepOverAction.LABEL, 2, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepover-tb.png'); + registerTouchBarEntry(StepIntoAction.ID, StepIntoAction.LABEL, 3, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepinto-tb.png'); + registerTouchBarEntry(StepOutAction.ID, StepOutAction.LABEL, 4, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepout-tb.png'); + registerTouchBarEntry(RestartAction.ID, RestartAction.LABEL, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png'); + registerTouchBarEntry(StopAction.ID, StopAction.LABEL, 6, CONTEXT_IN_DEBUG_MODE, 'stop-tb.png'); +} \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts b/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts index c1824de5b62..91aa2006c29 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import uri from 'vs/base/common/uri'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { TPromise } from 'vs/base/common/winjs.base'; import severity from 'vs/base/common/severity'; @@ -15,53 +14,14 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IListService } from 'vs/platform/list/browser/listService'; import { IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IDebugService, IConfig, IEnablement, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution } from 'vs/workbench/parts/debug/common/debug'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution } from 'vs/workbench/parts/debug/common/debug'; import { Expression, Variable, Breakpoint, FunctionBreakpoint } from 'vs/workbench/parts/debug/common/debugModel'; import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; export function registerCommands(): void { - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: '_workbench.startDebug', - weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), - handler(accessor: ServicesAccessor, configurationOrName: IConfig | string, folderUri?: uri) { - const debugService = accessor.get(IDebugService); - if (!configurationOrName) { - configurationOrName = debugService.getConfigurationManager().selectedName; - } - - if (!folderUri) { - const selectedLaunch = debugService.getConfigurationManager().selectedLaunch; - folderUri = selectedLaunch ? selectedLaunch.workspaceUri : undefined; - } - - if (typeof configurationOrName === 'string') { - debugService.startDebugging(folderUri, configurationOrName); - } else { - debugService.createProcess(folderUri, configurationOrName); - } - }, - when: CONTEXT_NOT_IN_DEBUG_MODE, - primary: undefined - }); - - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'workbench.customDebugRequest', - weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), - handler(accessor: ServicesAccessor, request: string, requestArgs: any) { - const process = accessor.get(IDebugService).getViewModel().focusedProcess; - if (process) { - return process.session.custom(request, requestArgs); - } - - return undefined; - }, - when: CONTEXT_IN_DEBUG_MODE, - primary: undefined - }); - KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'debug.logToDebugConsole', weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), @@ -204,11 +164,11 @@ export function registerCommands(): void { primary: undefined, handler: (accessor, workspaceUri: string) => { const manager = accessor.get(IDebugService).getConfigurationManager(); - if (!accessor.get(IWorkspaceContextService).hasWorkspace()) { + if (accessor.get(IWorkspaceContextService).getWorkbenchState() === WorkbenchState.EMPTY) { accessor.get(IMessageService).show(severity.Info, nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration.")); return TPromise.as(null); } - const launch = manager.getLaunches().filter(l => l.workspaceUri.toString() === workspaceUri).pop() || manager.selectedLaunch; + const launch = manager.getLaunches().filter(l => l.workspace.uri.toString() === workspaceUri).pop() || manager.selectedLaunch; return launch.openConfigFile(false).done(editor => { if (editor) { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index f48ee8c0f95..0336e082173 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -12,7 +12,6 @@ import { first } from 'vs/base/common/arrays'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import * as objects from 'vs/base/common/objects'; import uri from 'vs/base/common/uri'; -import { Schemas } from 'vs/base/common/network'; import * as paths from 'vs/base/common/paths'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IModel, isCommonCodeEditor } from 'vs/editor/common/editorCommon'; @@ -25,11 +24,10 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, DEBUG_SCHEME, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch } from 'vs/workbench/parts/debug/common/debug'; import { Adapter } from 'vs/workbench/parts/debug/node/debugAdapter'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; @@ -84,10 +82,6 @@ export const debuggersExtPoint = extensionsRegistry.ExtensionsRegistry.registerE description: nls.localize('vscode.extension.contributes.debuggers.adapterExecutableCommand', "If specified VS Code will call this command to determine the executable path of the debug adapter and the arguments to pass."), type: 'string' }, - startSessionCommand: { - description: nls.localize('vscode.extension.contributes.debuggers.startSessionCommand', "If specified VS Code will call this command for the \"debug\" or \"run\" actions targeted for this extension."), - type: 'string' - }, configurationSnippets: { description: nls.localize('vscode.extension.contributes.debuggers.configurationSnippets', "Snippets for adding new configurations in \'launch.json\'."), type: 'array' @@ -218,37 +212,36 @@ export class ConfigurationManager implements IConfigurationManager { private _selectedLaunch: ILaunch; private toDispose: IDisposable[]; private _onDidSelectConfigurationName = new Emitter(); - private _providers: Map; + private providers: IDebugConfigurationProvider[]; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IFileService private fileService: IFileService, - @ITelemetryService private telemetryService: ITelemetryService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IConfigurationService private configurationService: IConfigurationService, @IQuickOpenService private quickOpenService: IQuickOpenService, - @IConfigurationResolverService private configurationResolverService: IConfigurationResolverService, @IInstantiationService private instantiationService: IInstantiationService, @ICommandService private commandService: ICommandService, @IStorageService private storageService: IStorageService, @ILifecycleService lifecycleService: ILifecycleService ) { - this._providers = new Map(); + this.providers = []; this.adapters = []; this.toDispose = []; this.registerListeners(lifecycleService); this.initLaunches(); const previousSelectedRoot = this.storageService.get(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE); - const filtered = this.launches.filter(l => l.workspaceUri.toString() === previousSelectedRoot); - const launchToSelect = filtered.length ? filtered[0] : this.launches.length ? this.launches[0] : undefined; - this.selectConfiguration(launchToSelect, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE)); + const filtered = this.launches.filter(l => l.workspace.uri.toString() === previousSelectedRoot); + this.selectConfiguration(filtered.length ? filtered[0] : undefined, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE)); } public registerDebugConfigurationProvider(handle: number, debugConfigurationProvider: IDebugConfigurationProvider): void { if (!debugConfigurationProvider) { return; } - this._providers.set(handle, debugConfigurationProvider); + + debugConfigurationProvider.handle = handle; + this.providers = this.providers.filter(p => p.handle !== handle); + this.providers.push(debugConfigurationProvider); const adapter = this.getAdapter(debugConfigurationProvider.type); // Check if the provider contributes provideDebugConfigurations method if (adapter && debugConfigurationProvider.provideDebugConfigurations) { @@ -256,42 +249,26 @@ export class ConfigurationManager implements IConfigurationManager { } } - public unregisterDebugConfigurationProvider(handle: number): boolean { - return this._providers.delete(handle); + public unregisterDebugConfigurationProvider(handle: number): void { + this.providers = this.providers.filter(p => p.handle !== handle); } - public resolveDebugConfiguration(folderUri: uri | undefined, debugConfiguration: IConfig): TPromise { - - // collect all candidates - const providers: IDebugConfigurationProvider[] = []; - this._providers.forEach(provider => { - if (provider.type === debugConfiguration.type && provider.resolveDebugConfiguration) { - providers.push(provider); - } - }); - + public resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: IConfig): TPromise { // pipe the config through the promises sequentially - return providers.reduce((promise, provider) => { + return this.providers.filter(p => p.type === type && p.resolveDebugConfiguration).reduce((promise, provider) => { return promise.then(config => { - return provider.resolveDebugConfiguration(folderUri, config); + if (config) { + return provider.resolveDebugConfiguration(folderUri, config); + } else { + return Promise.resolve(config); + } }); }, TPromise.as(debugConfiguration)); } public provideDebugConfigurations(folderUri: uri | undefined, type: string): TPromise { - - // collect all candidates - const configs: TPromise[] = []; - this._providers.forEach(provider => { - if (provider.type === type && provider.provideDebugConfigurations) { - configs.push(provider.provideDebugConfigurations(folderUri)); - } - }); - - // combine all configs into one array - return TPromise.join(configs).then(results => { - return [].concat.apply([], results); - }); + return TPromise.join(this.providers.filter(p => p.type === type && p.provideDebugConfigurations).map(p => p.provideDebugConfigurations(folderUri))) + .then(results => results.reduce((first, second) => first.concat(second), [])); } private registerListeners(lifecycleService: ILifecycleService): void { @@ -338,18 +315,21 @@ export class ConfigurationManager implements IConfigurationManager { }); }); - this.toDispose.push(this.contextService.onDidChangeWorkspaceRoots(() => { + this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => { this.initLaunches(); - const toSelect = this.selectedLaunch && this.selectedLaunch.getConfigurationNames().length ? this.selectedLaunch : first(this.launches, l => !!l.getConfigurationNames().length, this.launches.length ? this.launches[0] : undefined); - this.selectConfiguration(toSelect); + this.selectConfiguration(); + })); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('launch')) { + this.selectConfiguration(); + } })); this.toDispose.push(lifecycleService.onShutdown(this.store, this)); } private initLaunches(): void { - const workspace = this.contextService.getWorkspace(); - this.launches = workspace ? workspace.roots.map(root => this.instantiationService.createInstance(Launch, this, root)) : []; + this.launches = this.contextService.getWorkspace().folders.map(folder => this.instantiationService.createInstance(Launch, this, folder)); if (this.launches.indexOf(this._selectedLaunch) === -1) { this._selectedLaunch = undefined; } @@ -371,10 +351,14 @@ export class ConfigurationManager implements IConfigurationManager { return this._onDidSelectConfigurationName.event; } - public selectConfiguration(launch: ILaunch, name?: string, debugStarted?: boolean): void { + public selectConfiguration(launch?: ILaunch, name?: string, debugStarted?: boolean): void { const previousLaunch = this._selectedLaunch; const previousName = this._selectedName; + if (!launch) { + launch = this.selectedLaunch && this.selectedLaunch.getConfigurationNames().length ? this.selectedLaunch : first(this.launches, l => !!l.getConfigurationNames().length, this.launches.length ? this.launches[0] : undefined); + } + this._selectedLaunch = launch; const names = launch ? launch.getConfigurationNames() : []; if (name && names.indexOf(name) >= 0) { @@ -390,15 +374,15 @@ export class ConfigurationManager implements IConfigurationManager { } public canSetBreakpointsIn(model: IModel): boolean { - if (model.uri.scheme !== Schemas.file && model.uri.scheme !== DEBUG_SCHEME) { + const modeId = model ? model.getLanguageIdentifier().language : null; + if (!modeId || modeId === 'json') { + // do not allow breakpoints in our settings files return false; } if (this.configurationService.getConfiguration('debug').allowBreakpointsEverywhere) { return true; } - const modeId = model ? model.getLanguageIdentifier().language : null; - return this.breakpointModeIdsSet.has(modeId); } @@ -437,22 +421,10 @@ export class ConfigurationManager implements IConfigurationManager { }); } - public getStartSessionCommand(type?: string): TPromise<{ command: string, type: string }> { - return this.guessAdapter(type).then(adapter => { - if (adapter) { - return { - command: adapter.startSessionCommand, - type: adapter.type - }; - } - return undefined; - }); - } - private store(): void { this.storageService.store(DEBUG_SELECTED_CONFIG_NAME_KEY, this.selectedName, StorageScope.WORKSPACE); if (this._selectedLaunch) { - this.storageService.store(DEBUG_SELECTED_ROOT, this._selectedLaunch.workspaceUri.toString(), StorageScope.WORKSPACE); + this.storageService.store(DEBUG_SELECTED_ROOT, this._selectedLaunch.workspace.uri.toString(), StorageScope.WORKSPACE); } } @@ -463,22 +435,20 @@ export class ConfigurationManager implements IConfigurationManager { class Launch implements ILaunch { - public name: string; - constructor( private configurationManager: ConfigurationManager, - public workspaceUri: uri, + public workspace: IWorkspaceFolder, @IFileService private fileService: IFileService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IConfigurationService private configurationService: IConfigurationService, @IConfigurationResolverService private configurationResolverService: IConfigurationResolverService, @IExtensionService private extensionService: IExtensionService ) { - this.name = paths.basename(this.workspaceUri.fsPath); + // noop } public getCompound(name: string): ICompound { - const config = this.configurationService.getConfiguration('launch', { resource: this.workspaceUri }); + const config = this.configurationService.getConfiguration('launch', { resource: this.workspace.uri }); if (!config || !config.compounds) { return null; } @@ -487,8 +457,8 @@ class Launch implements ILaunch { } public getConfigurationNames(): string[] { - const config = this.configurationService.getConfiguration('launch', { resource: this.workspaceUri }); - if (!config || !config.configurations) { + const config = this.configurationService.getConfiguration('launch', { resource: this.workspace.uri }); + if (!config || !config.configurations || !Array.isArray(config.configurations)) { return []; } else { const names = config.configurations.filter(cfg => cfg && typeof cfg.name === 'string').map(cfg => cfg.name); @@ -504,7 +474,7 @@ class Launch implements ILaunch { } public getConfiguration(name: string): IConfig { - const config = this.configurationService.getConfiguration('launch', { resource: this.workspaceUri }); + const config = this.configurationService.getConfiguration('launch', { resource: this.workspace.uri }); if (!config || !config.configurations) { return null; } @@ -513,7 +483,7 @@ class Launch implements ILaunch { } public resolveConfiguration(config: IConfig): TPromise { - const result = objects.deepClone(config) as IConfig; + const result = objects.clone(config) as IConfig; // Set operating system specific properties #1873 const setOSProperties = (flag: boolean, osConfig: IEnvConfig) => { if (flag && osConfig) { @@ -528,7 +498,7 @@ class Launch implements ILaunch { // massage configuration attributes - append workspace path to relatvie paths, substitute variables in paths. Object.keys(result).forEach(key => { - result[key] = this.configurationResolverService.resolveAny(this.workspaceUri, result[key]); + result[key] = this.configurationResolverService.resolveAny(this.workspace, result[key]); }); const adapter = this.configurationManager.getAdapter(result.type); @@ -536,7 +506,7 @@ class Launch implements ILaunch { } public get uri(): uri { - return uri.file(paths.join(this.workspaceUri.fsPath, '/.vscode/launch.json')); + return this.workspace.uri.with({ path: paths.join(this.workspace.uri.path, '/.vscode/launch.json') }); } public openConfigFile(sideBySide: boolean, type?: string): TPromise { @@ -550,8 +520,8 @@ class Launch implements ILaunch { return this.configurationManager.guessAdapter(type).then(adapter => { if (adapter) { - return this.configurationManager.provideDebugConfigurations(this.workspaceUri, adapter.type).then(initialConfigs => { - return adapter.getInitialConfigurationContent(this.workspaceUri, initialConfigs); + return this.configurationManager.provideDebugConfigurations(this.workspace.uri, adapter.type).then(initialConfigs => { + return adapter.getInitialConfigurationContent(initialConfigs); }); } else { return undefined; diff --git a/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts b/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts index 6ec643f4e3d..9356d41764f 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts @@ -39,6 +39,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Position } from 'vs/editor/common/core/position'; import { CoreEditingCommands } from 'vs/editor/common/controller/coreCommands'; import { first } from 'vs/base/common/arrays'; +import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; const HOVER_DELAY = 300; const LAUNCH_JSON_REGEX = /launch\.json$/; @@ -146,7 +147,8 @@ export class DebugEditorContribution implements IDebugEditorContribution { private registerListeners(): void { this.toDispose.push(this.editor.onMouseDown((e: IEditorMouseEvent) => { - if (e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || /* after last line */ e.target.detail || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) { + const data = e.target.detail as IMarginData; + if (e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) { return; } const canSetBreakpoints = this.debugService.getConfigurationManager().canSetBreakpointsIn(this.editor.getModel()); @@ -158,7 +160,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { return; } - const anchor = { x: e.event.posx + 1, y: e.event.posy }; + const anchor = { x: e.event.posx, y: e.event.posy }; const breakpoints = this.debugService.getModel().getBreakpoints().filter(bp => bp.lineNumber === lineNumber && bp.uri.toString() === uri.toString()); this.contextMenuService.showContextMenu({ @@ -182,8 +184,8 @@ export class DebugEditorContribution implements IDebugEditorContribution { let showBreakpointHintAtLineNumber = -1; if (e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && this.debugService.getConfigurationManager().canSetBreakpointsIn(this.editor.getModel()) && this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) { - if (!e.target.detail) { - // is not after last line + const data = e.target.detail as IMarginData; + if (!data.isAfterLines) { showBreakpointHintAtLineNumber = e.target.position.lineNumber; } } @@ -365,7 +367,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { // First call stack frame that is available is the frame where exception has been thrown const exceptionSf = first(callStack, sf => sf.source && sf.source.available, undefined); - if (!exceptionSf) { + if (!exceptionSf || exceptionSf !== focusedSf) { this.closeExceptionWidget(); return; } @@ -387,7 +389,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.exceptionWidget.dispose(); } - this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, exceptionInfo, lineNumber); + this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, exceptionInfo); this.exceptionWidget.show({ lineNumber, column }, 0); } @@ -411,6 +413,9 @@ export class DebugEditorContribution implements IDebugEditorContribution { } public addLaunchConfiguration(): TPromise { + /* __GDPR__ + "debug/addLaunchConfiguration" : {} + */ this.telemetryService.publicLog('debug/addLaunchConfiguration'); let configurationsArrayPosition: Position; const model = this.editor.getModel(); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugHover.ts b/src/vs/workbench/parts/debug/electron-browser/debugHover.ts index 3af92756683..9dec498f49a 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugHover.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugHover.ts @@ -254,7 +254,8 @@ export class DebugHoverWidget implements IContentWidget { this.valueContainer.hidden = false; renderExpressionValue(expression, this.valueContainer, { showChanged: false, - preserveWhitespace: true + preserveWhitespace: true, + colorize: true }); this.valueContainer.title = ''; this.editor.layoutContentWidget(this); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 61d1e82c57a..22c4956393a 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -6,10 +6,11 @@ import * as nls from 'vs/nls'; import * as lifecycle from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; -import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import * as strings from 'vs/base/common/strings'; import { generateUuid } from 'vs/base/common/uuid'; import uri from 'vs/base/common/uri'; +import * as platform from 'vs/base/common/platform'; import { Action } from 'vs/base/common/actions'; import { first, distinct } from 'vs/base/common/arrays'; import { isObject, isUndefinedOrNull } from 'vs/base/common/types'; @@ -25,15 +26,14 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/files/common/files'; import { IMessageService, CloseAction } from 'vs/platform/message/common/message'; -import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc'; -import { ICommandService } from 'vs/platform/commands/common/commands'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import * as debug from 'vs/workbench/parts/debug/common/debug'; import { RawDebugSession } from 'vs/workbench/parts/debug/electron-browser/rawDebugSession'; -import { Model, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, Expression, OutputNameValueElement, ExpressionContainer, Process } from 'vs/workbench/parts/debug/common/debugModel'; +import { Model, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, Expression, RawObjectReplElement, ExpressionContainer, Process } from 'vs/workbench/parts/debug/common/debugModel'; import { ViewModel } from 'vs/workbench/parts/debug/common/debugViewModel'; import * as debugactions from 'vs/workbench/parts/debug/browser/debugActions'; import { ConfigurationManager } from 'vs/workbench/parts/debug/electron-browser/debugConfigurationManager'; @@ -46,10 +46,12 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ILogEntry, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; +import { EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; import { IBroadcastService, IBroadcast } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/node/console'; +import { Source } from 'vs/workbench/parts/debug/common/debugSource'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; @@ -57,11 +59,6 @@ const DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint'; const DEBUG_EXCEPTION_BREAKPOINTS_KEY = 'debug.exceptionbreakpoint'; const DEBUG_WATCH_EXPRESSIONS_KEY = 'debug.watchexpressions'; -interface StartSessionResult { - status: 'ok' | 'initialConfiguration' | 'saveConfiguration'; - content?: string; -}; - export class DebugService implements debug.IDebugService { public _serviceBrand: any; @@ -74,7 +71,6 @@ export class DebugService implements debug.IDebugService { private viewModel: ViewModel; private allProcesses: Map; private configurationManager: ConfigurationManager; - private customTelemetryService: ITelemetryService; private toDispose: lifecycle.IDisposable[]; private toDisposeOnSessionEnd: Map; private inDebugMode: IContextKey; @@ -82,6 +78,8 @@ export class DebugService implements debug.IDebugService { private debugState: IContextKey; private breakpointsToSendOnResourceSaved: Set; private launchJsonChanged: boolean; + private firstSessionStart: boolean; + private previousState: debug.State; constructor( @IStorageService private storageService: IStorageService, @@ -91,20 +89,18 @@ export class DebugService implements debug.IDebugService { @IPanelService private panelService: IPanelService, @IMessageService private messageService: IMessageService, @IPartService private partService: IPartService, - @IWindowsService private windowsService: IWindowsService, @IWindowService private windowService: IWindowService, @IBroadcastService private broadcastService: IBroadcastService, @ITelemetryService private telemetryService: ITelemetryService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IContextKeyService contextKeyService: IContextKeyService, - @ILifecycleService lifecycleService: ILifecycleService, + @ILifecycleService private lifecycleService: ILifecycleService, @IInstantiationService private instantiationService: IInstantiationService, @IExtensionService private extensionService: IExtensionService, @IMarkerService private markerService: IMarkerService, @ITaskService private taskService: ITaskService, @IFileService private fileService: IFileService, - @IConfigurationService private configurationService: IConfigurationService, - @ICommandService private commandService: ICommandService + @IConfigurationService private configurationService: IConfigurationService ) { this.toDispose = []; this.toDisposeOnSessionEnd = new Map(); @@ -126,14 +122,15 @@ export class DebugService implements debug.IDebugService { this.loadExceptionBreakpoints(), this.loadWatchExpressions()); this.toDispose.push(this.model); this.viewModel = new ViewModel(); + this.firstSessionStart = true; - this.registerListeners(lifecycleService); + this.registerListeners(); } - private registerListeners(lifecycleService: ILifecycleService): void { + private registerListeners(): void { this.toDispose.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); - lifecycleService.onShutdown(this.store, this); - lifecycleService.onShutdown(this.dispose, this); + this.lifecycleService.onShutdown(this.store, this); + this.lifecycleService.onShutdown(this.dispose, this); this.toDispose.push(this.broadcastService.onBroadcast(this.onBroadcast, this)); } @@ -163,15 +160,23 @@ export class DebugService implements debug.IDebugService { // an extension logged output, show it inside the REPL if (broadcast.channel === EXTENSION_LOG_BROADCAST_CHANNEL) { - let extensionOutput: ILogEntry = broadcast.payload.logEntry; + let extensionOutput: IRemoteConsoleLog = broadcast.payload.logEntry; let sev = extensionOutput.severity === 'warn' ? severity.Warning : extensionOutput.severity === 'error' ? severity.Error : severity.Info; - let args: any[] = []; - try { - let parsed = JSON.parse(extensionOutput.arguments); - args.push(...Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(extensionOutput.arguments); + const { args, stack } = parse(extensionOutput); + let source: debug.IReplElementSource; + if (stack) { + const frame = getFirstFrame(stack); + if (frame) { + source = { + column: frame.column, + lineNumber: frame.line, + source: process.getSource({ + name: resources.basenameOrAuthority(frame.uri), + path: frame.uri.fsPath + }) + }; + } } // add output for each argument logged @@ -194,12 +199,12 @@ export class DebugService implements debug.IDebugService { // flush any existing simple values logged if (simpleVals.length) { - this.logToRepl(simpleVals.join(' '), sev); + this.logToRepl(simpleVals.join(' '), sev, source); simpleVals = []; } // show object - this.logToRepl(new OutputNameValueElement((a).prototype, a, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev); + this.logToRepl(new RawObjectReplElement((a).prototype, a, undefined, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev, source); } // string: watch out for % replacement directive @@ -229,14 +234,14 @@ export class DebugService implements debug.IDebugService { // flush simple values // always append a new line for output coming from an extension such that separate logs go to separate lines #23695 if (simpleVals.length) { - this.logToRepl(simpleVals.join(' ') + '\n', sev); + this.logToRepl(simpleVals.join(' ') + '\n', sev, source); } } } private tryToAutoFocusStackFrame(thread: debug.IThread): TPromise { const callStack = thread.getCallStack(); - if (!callStack.length || this.viewModel.focusedStackFrame) { + if (!callStack.length || (this.viewModel.focusedStackFrame && this.viewModel.focusedStackFrame.thread.getId() === thread.getId())) { return TPromise.as(null); } @@ -252,7 +257,7 @@ export class DebugService implements debug.IDebugService { aria.alert(nls.localize('debuggingPaused', "Debugging paused, reason {0}, {1} {2}", thread.stoppedDetails.reason, stackFrameToFocus.source ? stackFrameToFocus.source.name : '', stackFrameToFocus.range.startLineNumber)); } - return stackFrameToFocus.openInEditor(this.editorService); + return stackFrameToFocus.openInEditor(this.editorService, true); } private registerSessionListeners(process: Process, session: RawDebugSession): void { @@ -319,6 +324,7 @@ export class DebugService implements debug.IDebugService { this.updateStateAndEmit(session.getId(), debug.State.Running); })); + let outputPromises: TPromise[] = []; this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidOutput(event => { if (!event.body) { return; @@ -328,33 +334,71 @@ export class DebugService implements debug.IDebugService { if (event.body.category === 'telemetry') { // only log telemetry events from debug adapter if the adapter provided the telemetry key // and the user opted in telemetry - if (this.customTelemetryService && this.telemetryService.isOptedIn) { - this.customTelemetryService.publicLog(event.body.output, event.body.data); + if (session.customTelemetryService && this.telemetryService.isOptedIn) { + // __GDPR__TODO__ We're sending events in the name of the debug adapter and we can not ensure that those are declared correctly. + session.customTelemetryService.publicLog(event.body.output, event.body.data); } - } else if (event.body.variablesReference) { + + return; + } + + // Make sure to append output in the correct order by properly waiting on preivous promises #33822 + const waitFor = outputPromises.slice(); + const source = event.body.source ? { + lineNumber: event.body.line, + column: event.body.column, + source: process.getSource(event.body.source) + } : undefined; + if (event.body.variablesReference) { const container = new ExpressionContainer(process, event.body.variablesReference, generateUuid()); - container.getChildren().then(children => { - children.forEach(child => { + outputPromises.push(container.getChildren().then(children => { + return TPromise.join(waitFor).then(() => children.forEach(child => { // Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names) child.name = null; - this.logToRepl(child, outputSeverity); - }); - }); + this.logToRepl(child, outputSeverity, source); + })); + })); } else if (typeof event.body.output === 'string') { - this.logToRepl(event.body.output, outputSeverity); + TPromise.join(waitFor).then(() => this.logToRepl(event.body.output, outputSeverity, source)); } + TPromise.join(outputPromises).then(() => outputPromises = []); })); this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidBreakpoint(event => { const id = event.body && event.body.breakpoint ? event.body.breakpoint.id : undefined; const breakpoint = this.model.getBreakpoints().filter(bp => bp.idFromAdapter === id).pop(); - if (breakpoint) { - if (!breakpoint.column) { - event.body.breakpoint.column = undefined; + const functionBreakpoint = this.model.getFunctionBreakpoints().filter(bp => bp.idFromAdapter === id).pop(); + + if (event.body.reason === 'new' && event.body.breakpoint.source) { + const source = process.getSource(event.body.breakpoint.source); + const bps = this.model.addBreakpoints(source.uri, [{ + column: event.body.breakpoint.column, + enabled: true, + lineNumber: event.body.breakpoint.line, + }], false); + if (bps.length === 1) { + this.model.updateBreakpoints({ [bps[0].getId()]: event.body.breakpoint }); + } + } + + if (event.body.reason === 'removed') { + if (breakpoint) { + this.model.removeBreakpoints([breakpoint]); + } + if (functionBreakpoint) { + this.model.removeFunctionBreakpoints(functionBreakpoint.getId()); + } + } + + // For compatibilty reasons check if wrong reason and source not present + // TODO@Isidor clean up these checks in October + if (event.body.reason === 'changed' || (event.body.reason === 'new' && !event.body.breakpoint.source) || event.body.reason === 'update') { + if (breakpoint) { + if (!breakpoint.column) { + event.body.breakpoint.column = undefined; + } + this.model.updateBreakpoints({ [breakpoint.getId()]: event.body.breakpoint }); } - this.model.updateBreakpoints({ [breakpoint.getId()]: event.body.breakpoint }); - } else { - const functionBreakpoint = this.model.getFunctionBreakpoints().filter(bp => bp.idFromAdapter === id).pop(); if (functionBreakpoint) { this.model.updateFunctionBreakpoints({ [functionBreakpoint.getId()]: event.body.breakpoint }); } @@ -363,12 +407,11 @@ export class DebugService implements debug.IDebugService { this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidExitAdapter(event => { // 'Run without debugging' mode VSCode must terminate the extension host. More details: #3905 - const process = this.viewModel.focusedProcess; - if (process && session && process.getId() === session.getId() && strings.equalsIgnoreCase(process.configuration.type, 'extensionhost') && this.sessionStates.get(session.getId()) === debug.State.Running && - process && this.contextService.hasWorkspace() && process.configuration.noDebug) { + if (strings.equalsIgnoreCase(process.configuration.type, 'extensionhost') && this.sessionStates.get(session.getId()) === debug.State.Running && + process && process.session.root && process.configuration.noDebug) { this.broadcastService.broadcast({ channel: EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, - payload: [process.session.root.fsPath] + payload: [process.session.root.uri.fsPath] }); } if (session && session.getId() === event.sessionId) { @@ -384,14 +427,14 @@ export class DebugService implements debug.IDebugService { private fetchThreads(session: RawDebugSession, stoppedDetails?: debug.IRawStoppedDetails): TPromise { return session.threads().then(response => { if (response && response.body && response.body.threads) { - response.body.threads.forEach(thread => + response.body.threads.forEach(thread => { this.model.rawUpdate({ sessionId: session.getId(), threadId: thread.id, thread, - stoppedDetails, - allThreadsStopped: stoppedDetails ? stoppedDetails.allThreadsStopped : undefined - })); + stoppedDetails: stoppedDetails && thread.id === stoppedDetails.threadId ? stoppedDetails : undefined + }); + }); } }); } @@ -400,7 +443,7 @@ export class DebugService implements debug.IDebugService { let result: Breakpoint[]; try { result = JSON.parse(this.storageService.get(DEBUG_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((breakpoint: any) => { - return new Breakpoint(uri.parse(breakpoint.uri.external || breakpoint.source.uri.external), breakpoint.lineNumber, breakpoint.column, breakpoint.enabled, breakpoint.condition, breakpoint.hitCondition); + return new Breakpoint(uri.parse(breakpoint.uri.external || breakpoint.source.uri.external), breakpoint.lineNumber, breakpoint.column, breakpoint.enabled, breakpoint.condition, breakpoint.hitCondition, breakpoint.adapterData); }); } catch (e) { } @@ -482,11 +525,14 @@ export class DebugService implements debug.IDebugService { } const state = this.state; - const stateLabel = debug.State[state]; - if (stateLabel) { - this.debugState.set(stateLabel.toLowerCase()); + if (this.previousState !== state) { + const stateLabel = debug.State[state]; + if (stateLabel) { + this.debugState.set(stateLabel.toLowerCase()); + } + this.previousState = state; + this._onDidChangeState.fire(state); } - this._onDidChangeState.fire(state); } public focusStackFrameAndEvaluate(stackFrame: debug.IStackFrame, process?: debug.IProcess, explicit?: boolean): TPromise { @@ -496,7 +542,7 @@ export class DebugService implements debug.IDebugService { } if (!stackFrame) { const threads = process ? process.getAllThreads() : null; - const callStack = threads && threads.length ? threads[0].getCallStack() : null; + const callStack = threads && threads.length === 1 ? threads[0].getCallStack() : null; stackFrame = callStack && callStack.length ? callStack[0] : null; } @@ -558,6 +604,9 @@ export class DebugService implements debug.IDebugService { } public addReplExpression(name: string): TPromise { + /* __GDPR__ + "debugService/addReplExpression" : {} + */ this.telemetryService.publicLog('debugService/addReplExpression'); return this.model.addReplExpression(this.viewModel.focusedProcess, this.viewModel.focusedStackFrame, name) // Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some. @@ -568,12 +617,12 @@ export class DebugService implements debug.IDebugService { this.model.removeReplExpressions(); } - public logToRepl(value: string | debug.IExpression, sev = severity.Info): void { + public logToRepl(value: string | debug.IExpression, sev = severity.Info, source?: debug.IReplElementSource): void { if (typeof value === 'string' && '[2J'.localeCompare(value) === 0) { // [2J is the ansi escape sequence for clearing the display http://ascii-table.com/ansi-escape-sequences.php this.model.removeReplExpressions(); } else { - this.model.appendToRepl(value, sev); + this.model.appendToRepl(value, sev, source); } } @@ -597,10 +646,10 @@ export class DebugService implements debug.IDebugService { return this.model.evaluateWatchExpressions(this.viewModel.focusedProcess, this.viewModel.focusedStackFrame); } - public startDebugging(root: uri, configOrName?: debug.IConfig | string, noDebug = false, topCompoundName?: string): TPromise { + public startDebugging(root: IWorkspaceFolder, configOrName?: debug.IConfig | string, noDebug = false, topCompoundName?: string): TPromise { // make sure to save all files and that the configuration is up to date - return this.extensionService.activateByEvent('onDebug').then(() => this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration().then(() => + return this.extensionService.activateByEvent('onDebug').then(() => this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration(root).then(() => this.extensionService.onReady().then(() => { if (this.model.getProcesses().length === 0) { this.removeReplExpressions(); @@ -608,7 +657,7 @@ export class DebugService implements debug.IDebugService { } this.launchJsonChanged = false; const manager = this.getConfigurationManager(); - const launch = root ? manager.getLaunches().filter(l => l.workspaceUri.toString() === root.toString()).pop() : undefined; + const launch = root ? manager.getLaunches().filter(l => l.workspace.uri.toString() === root.uri.toString()).pop() : undefined; let config: debug.IConfig, compound: debug.ICompound; if (!configOrName) { @@ -637,66 +686,45 @@ export class DebugService implements debug.IDebugService { return TPromise.wrapError(new Error(nls.localize('configMissing', "Configuration '{0}' is missing in 'launch.json'.", configOrName))); } - return manager.getStartSessionCommand(config ? config.type : undefined).then(commandAndType => { + // We keep the debug type in a separate variable 'type' so that a no-folder config has no attributes. + // Storing the type in the config would break extensions that assume that the no-folder case is indicated by an empty config. + let type: string; + if (config) { + type = config.type; + } else { + // a no-folder workspace has no launch.config + config = {}; + } + if (noDebug) { + config.noDebug = true; + } - if (!config) { - // no-folder workspace - config = {}; - if (commandAndType && commandAndType.type) { - config.type = commandAndType.type; - } + const sessionId = generateUuid(); + this.updateStateAndEmit(sessionId, debug.State.Initializing); + const wrapUpState = () => { + if (this.sessionStates.get(sessionId) === debug.State.Initializing) { + this.updateStateAndEmit(sessionId, debug.State.Inactive); } + }; - if (noDebug) { - config.noDebug = true; - } - - return this.configurationManager.resolveDebugConfiguration(launch ? launch.workspaceUri : undefined, config).then(config => { - - // deprecated code: use DebugConfigurationProvider instead of startSessionCommand - if (commandAndType && commandAndType.command) { - const defaultConfig = noDebug ? { noDebug: true } : {}; - return this.commandService.executeCommand(commandAndType.command, config || defaultConfig, launch ? launch.workspaceUri : undefined).then((result: StartSessionResult) => { - if (launch) { - if (result && result.status === 'initialConfiguration') { - return launch.openConfigFile(false, commandAndType.type); - } - - if (result && result.status === 'saveConfiguration') { - return this.fileService.updateContent(launch.uri, result.content).then(() => launch.openConfigFile(false)); - } - } - return undefined; - }); - } - // end of deprecation - - if (config.type) { - // TODO@AW: handle the 'initialConfiguration' and 'saveConfiguration' cases from above! - return this.createProcess(root, config); + return (type ? TPromise.as(null) : this.configurationManager.guessAdapter().then(a => type = a && a.type)).then(() => + this.configurationManager.resolveConfigurationByProviders(launch ? launch.workspace.uri : undefined, type, config).then(config => { + // a falsy config indicates an aborted launch + if (config && config.type) { + return this.createProcess(root, config, sessionId); } - if (launch && commandAndType) { - return launch.openConfigFile(false, commandAndType.type); - } - - return undefined; - }); + return launch.openConfigFile(false, type); // cast to ignore weird compile error + }) + ).then(() => wrapUpState(), err => { + wrapUpState(); + return TPromise.wrapError(err); }); }) ))); } - public findProcessByUUID(uuid: string): debug.IProcess | null { - const processes = this.getModel().getProcesses(); - const result = processes.filter(process => process.getId() === uuid); - if (result.length > 0) { - return result[0]; // there can only be one - } - return null; - } - - public createProcess(root: uri, config: debug.IConfig): TPromise { + private createProcess(root: IWorkspaceFolder, config: debug.IConfig, sessionId: string): TPromise { return this.textFileService.saveAll().then(() => (this.configurationManager.selectedLaunch ? this.configurationManager.selectedLaunch.resolveConfiguration(config) : TPromise.as(config)).then(resolvedConfig => { if (!resolvedConfig) { @@ -704,18 +732,31 @@ export class DebugService implements debug.IDebugService { return undefined; } - if (!this.configurationManager.getAdapter(resolvedConfig.type)) { - const message = resolvedConfig.type ? nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", resolvedConfig.type) : - nls.localize('debugTypeMissing', "Missing property 'type' for the chosen launch configuration."); + if (!this.configurationManager.getAdapter(resolvedConfig.type) || (config.request !== 'attach' && config.request !== 'launch')) { + let message: string; + if (config.request !== 'attach' && config.request !== 'launch') { + message = config.request ? nls.localize('debugRequestNotSupported', "Attribute `{0}` has an unsupported value '{1}' in the chosen debug configuration.", 'request', config.request) + : nls.localize('debugRequesMissing', "Attribute '{0}' is missing from the chosen debug configuration.", 'request'); + + } else { + message = resolvedConfig.type ? nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", resolvedConfig.type) : + nls.localize('debugTypeMissing', "Missing property `type` for the chosen launch configuration."); + } + return TPromise.wrapError(errors.create(message, { actions: [this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), CloseAction] })); } - return this.runPreLaunchTask(resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => { + const debugAnywayAction = new Action('debug.continue', nls.localize('debugAnyway', "Debug Anyway"), null, true, () => { + this.messageService.hideAll(); + return this.doCreateProcess(root, resolvedConfig, sessionId); + }); + + return this.runPreLaunchTask(root, resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => { const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0; const successExitCode = taskSummary && taskSummary.exitCode === 0; const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0; if (successExitCode || (errorCount === 0 && !failureExitCode)) { - return this.doCreateProcess(root, resolvedConfig); + return this.doCreateProcess(root, resolvedConfig, sessionId); } this.messageService.show(severity.Error, { @@ -723,10 +764,7 @@ export class DebugService implements debug.IDebugService { errorCount === 1 ? nls.localize('preLaunchTaskError', "Build error has been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) : nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", resolvedConfig.preLaunchTask, taskSummary.exitCode), actions: [ - new Action('debug.continue', nls.localize('debugAnyway', "Debug Anyway"), null, true, () => { - this.messageService.hideAll(); - return this.doCreateProcess(root, resolvedConfig); - }), + debugAnywayAction, this.instantiationService.createInstance(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL), CloseAction ] @@ -736,6 +774,7 @@ export class DebugService implements debug.IDebugService { this.messageService.show(err.severity, { message: err.message, actions: [ + debugAnywayAction, this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), this.taskService.configureAction(), CloseAction @@ -743,7 +782,7 @@ export class DebugService implements debug.IDebugService { }); }); }, err => { - if (!this.contextService.hasWorkspace()) { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(severity.Error, nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved on disk and that you have a debug extension installed for that file type.")); return undefined; } @@ -758,9 +797,9 @@ export class DebugService implements debug.IDebugService { ); } - private doCreateProcess(root: uri, configuration: debug.IConfig, sessionId = generateUuid()): TPromise { + private doCreateProcess(root: IWorkspaceFolder, configuration: debug.IConfig, sessionId: string): TPromise { configuration.__sessionId = sessionId; - this.updateStateAndEmit(sessionId, debug.State.Initializing); + this.inDebugMode.set(true); return this.telemetryService.getTelemetryInfo().then(info => { const telemetryInfo: { [key: string]: string } = Object.create(null); @@ -771,9 +810,9 @@ export class DebugService implements debug.IDebugService { const adapter = this.configurationManager.getAdapter(configuration.type); const { aiKey, type } = adapter; const publisher = adapter.extensionDescription.publisher; - this.customTelemetryService = null; let client: TelemetryClient; + let customTelemetryService: TelemetryService; if (aiKey) { client = new TelemetryClient( uri.parse(require.toUrl('bootstrap')).fsPath, @@ -792,10 +831,10 @@ export class DebugService implements debug.IDebugService { const channel = client.getChannel('telemetryAppender'); const appender = new TelemetryAppenderClient(channel); - this.customTelemetryService = new TelemetryService({ appender }, this.configurationService); + customTelemetryService = new TelemetryService({ appender }, this.configurationService); } - const session = this.instantiationService.createInstance(RawDebugSession, sessionId, configuration.debugServer, adapter, this.customTelemetryService, root); + const session = this.instantiationService.createInstance(RawDebugSession, sessionId, configuration.debugServer, adapter, customTelemetryService, root); const process = this.model.addProcess(configuration, session); this.allProcesses.set(process.getId(), process); @@ -813,7 +852,8 @@ export class DebugService implements debug.IDebugService { columnsStartAt1: true, supportsVariableType: true, // #8858 supportsVariablePaging: true, // #9537 - supportsRunInTerminalRequest: true // #10574 + supportsRunInTerminalRequest: true, // #10574 + locale: platform.locale }).then((result: DebugProtocol.InitializeResponse) => { this.model.setExceptionBreakpoints(session.capabilities.exceptionBreakpointFilters); return configuration.request === 'attach' ? session.attach(configuration) : session.launch(configuration); @@ -825,24 +865,34 @@ export class DebugService implements debug.IDebugService { this.focusStackFrameAndEvaluate(null, process); const internalConsoleOptions = configuration.internalConsoleOptions || this.configurationService.getConfiguration('debug').internalConsoleOptions; - if (internalConsoleOptions === 'openOnSessionStart' || (!this.viewModel.changedWorkbenchViewState && internalConsoleOptions === 'openOnFirstSessionStart')) { + if (internalConsoleOptions === 'openOnSessionStart' || (this.firstSessionStart && internalConsoleOptions === 'openOnFirstSessionStart')) { this.panelService.openPanel(debug.REPL_ID, false).done(undefined, errors.onUnexpectedError); } - if (!this.viewModel.changedWorkbenchViewState && (this.partService.isVisible(Parts.SIDEBAR_PART) || !this.contextService.hasWorkspace())) { - // We only want to change the workbench view state on the first debug session #5738 and if the side bar is not hidden - this.viewModel.changedWorkbenchViewState = true; + const openDebugOptions = this.configurationService.getConfiguration('debug').openDebug; + // Open debug viewlet based on the visibility of the side bar and openDebug setting + if (openDebugOptions === 'openOnSessionStart' || (openDebugOptions === 'openOnFirstSessionStart' && this.firstSessionStart)) { this.viewletService.openViewlet(debug.VIEWLET_ID); } + this.firstSessionStart = false; - this.extensionService.activateByEvent(`onDebug:${configuration.type}`).done(null, errors.onUnexpectedError); - this.inDebugMode.set(true); this.debugType.set(configuration.type); if (this.model.getProcesses().length > 1) { this.viewModel.setMultiProcessView(true); } this.updateStateAndEmit(session.getId(), debug.State.Running); + /* __GDPR__ + "debugSessionStart" : { + "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "breakpointCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "exceptionBreakpoints": { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "watchExpressionsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionName": { "classification": "PublicPersonalData", "purpose": "FeatureInsight" }, + "isBuiltin": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "launchJsonExists": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ return this.telemetryService.publicLog('debugSessionStart', { type: configuration.type, breakpointCount: this.model.getBreakpoints().length, @@ -850,7 +900,7 @@ export class DebugService implements debug.IDebugService { watchExpressionsCount: this.model.getWatchExpressions().length, extensionName: `${adapter.extensionDescription.publisher}.${adapter.extensionDescription.name}`, isBuiltin: adapter.extensionDescription.isBuiltin, - launchJsonExists: this.contextService.hasWorkspace() && !!this.configurationService.getConfiguration('launch', { resource: root }) + launchJsonExists: root && !!this.configurationService.getConfiguration('launch', { resource: root.uri }) }); }).then(() => process, (error: any) => { if (error instanceof Error && error.message === 'Canceled') { @@ -859,6 +909,12 @@ export class DebugService implements debug.IDebugService { } const errorMessage = error instanceof Error ? error.message : error; + /* __GDPR__ + "debugMisconfiguration" : { + "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "error": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('debugMisconfiguration', { type: configuration ? configuration.type : undefined, error: errorMessage }); this.updateStateAndEmit(session.getId(), debug.State.Inactive); if (!session.disconnected) { @@ -871,6 +927,9 @@ export class DebugService implements debug.IDebugService { if (this.model.getReplElements().length > 0) { this.panelService.openPanel(debug.REPL_ID, false).done(undefined, errors.onUnexpectedError); } + if (this.model.getReplElements().length === 0) { + this.inDebugMode.reset(); + } const configureAction = this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL); const actions = (error.actions && error.actions.length) ? error.actions.concat([configureAction]) : [CloseAction, configureAction]; @@ -880,18 +939,18 @@ export class DebugService implements debug.IDebugService { }); } - private runPreLaunchTask(taskName: string): TPromise { + private runPreLaunchTask(root: IWorkspaceFolder, taskName: string): TPromise { if (!taskName) { return TPromise.as(null); } // run a task before starting a debug session - return this.taskService.getTask(taskName).then(task => { + return this.taskService.getTask(root, taskName).then(task => { if (!task) { return TPromise.wrapError(errors.create(nls.localize('DebugTaskNotFound', "Could not find the preLaunchTask \'{0}\'.", taskName))); } - return this.taskService.getActiveTasks().then(tasks => { + const promise = this.taskService.getActiveTasks().then(tasks => { if (tasks.filter(t => t._id === task._id).length) { // task is already running - nothing to do. return TPromise.as(null); @@ -899,11 +958,27 @@ export class DebugService implements debug.IDebugService { const taskPromise = this.taskService.run(task); if (task.isBackground) { - return new TPromise((c, e) => this.taskService.addOneTimeListener(TaskServiceEvents.Inactive, () => c(null))); + return new TPromise((c, e) => this.toDispose.push(this.taskService.addOneTimeListener(TaskServiceEvents.Inactive, () => c(null)))); } return taskPromise; }); + + return new TPromise((c, e) => { + // If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340 + let taskStarted = false; + promise.then(result => { + taskStarted = true; + c(result); + }, error => e(error)); + + this.toDispose.push(this.taskService.addOneTimeListener(TaskServiceEvents.Active, () => taskStarted = true)); + setTimeout(() => { + if (!taskStarted) { + e({ severity: severity.Error, message: nls.localize('taskNotTracked', "The preLaunchTask '{0}' cannot be tracked.", taskName) }); + } + }, 10000); + }); }); } @@ -922,7 +997,7 @@ export class DebugService implements debug.IDebugService { if (strings.equalsIgnoreCase(process.configuration.type, 'extensionHost')) { return this.broadcastService.broadcast({ channel: EXTENSION_RELOAD_BROADCAST_CHANNEL, - payload: [process.session.root.fsPath] + payload: [process.session.root.uri.fsPath] }); } @@ -938,7 +1013,7 @@ export class DebugService implements debug.IDebugService { config.noDebug = process.configuration.noDebug; } config.__restart = restartData; - this.createProcess(process.session.root, config).then(() => c(null), err => e(err)); + this.createProcess(process.session.root, config, process.getId()).then(() => c(null), err => e(err)); }, 300); }); }).then(() => { @@ -970,6 +1045,15 @@ export class DebugService implements debug.IDebugService { private onSessionEnd(session: RawDebugSession): void { const bpsExist = this.model.getBreakpoints().length > 0; const process = this.model.getProcesses().filter(p => p.getId() === session.getId()).pop(); + /* __GDPR__ + "debugSessionStop" : { + "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "success": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "sessionLengthInSeconds": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "breakpointCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "watchExpressionsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('debugSessionStop', { type: process && process.configuration.type, success: session.emittedStopped || !bpsExist, @@ -980,6 +1064,7 @@ export class DebugService implements debug.IDebugService { this.model.removeProcess(session.getId()); if (process && process.state !== debug.ProcessState.INACTIVE) { + process.inactive = true; this._onDidEndProcess.fire(process); } @@ -1043,7 +1128,17 @@ export class DebugService implements debug.IDebugService { const breakpointsToSend = this.model.getBreakpoints().filter(bp => this.model.areBreakpointsActivated() && bp.enabled && bp.uri.toString() === modelUri.toString()); const source = process.sources.get(modelUri.toString()); - const rawSource = source ? source.raw : { path: paths.normalize(modelUri.fsPath, true), name: paths.basename(modelUri.fsPath) }; + let rawSource: DebugProtocol.Source; + if (source) { + rawSource = source.raw; + } else { + const data = Source.getEncodedDebugData(modelUri); + rawSource = { name: data.name, path: data.path, sourceReference: data.sourceReference }; + } + + if (breakpointsToSend.length && !rawSource.adapterData) { + rawSource.adapterData = breakpointsToSend[0].adapterData; + } return session.setBreakpoints({ source: rawSource, diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index 8b56ab78391..e3e0580f11a 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -8,13 +8,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as lifecycle from 'vs/base/common/lifecycle'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import * as errors from 'vs/base/common/errors'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import * as dom from 'vs/base/browser/dom'; import { IMouseEvent, DragMouseEvent } from 'vs/base/browser/mouseEvent'; import { getPathLabel } from 'vs/base/common/labels'; -import { IAction, IActionRunner } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITree, IAccessibilityProvider, ContextMenuEvent, IDataSource, IRenderer, DRAG_OVER_REJECT, IDragAndDropData, IDragOverReaction, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { InputBox, IInputValidationOptions } from 'vs/base/browser/ui/inputbox/inputBox'; @@ -22,7 +23,7 @@ import { DefaultController, DefaultDragAndDrop, ClickBehavior } from 'vs/base/pa import { Constants } from 'vs/editor/common/core/uint'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions'; import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; @@ -48,10 +49,11 @@ export interface IRenderValueOptions { showChanged?: boolean; maxValueLength?: number; showHover?: boolean; + colorize?: boolean; } function replaceWhitespace(value: string): string { - const map = { '\n': '\\n', '\r': '\\r', '\t': '\\t' }; + const map: { [x: string]: string } = { '\n': '\\n', '\r': '\\r', '\t': '\\t' }; return value.replace(/[\n\r\t]/g, char => map[char]); } @@ -66,12 +68,18 @@ export function renderExpressionValue(expressionOrValue: debug.IExpression | str if (value !== Expression.DEFAULT_VALUE) { dom.addClass(container, 'error'); } - } else if (!isNaN(+value)) { - dom.addClass(container, 'number'); - } else if (booleanRegex.test(value)) { - dom.addClass(container, 'boolean'); - } else if (stringRegex.test(value)) { - dom.addClass(container, 'string'); + } + + if (options.colorize && typeof expressionOrValue !== 'string') { + if (expressionOrValue.type === 'number' || expressionOrValue.type === 'boolean' || expressionOrValue.type === 'string') { + dom.addClass(container, expressionOrValue.type); + } else if (!isNaN(+value)) { + dom.addClass(container, 'number'); + } else if (booleanRegex.test(value)) { + dom.addClass(container, 'boolean'); + } else if (stringRegex.test(value)) { + dom.addClass(container, 'string'); + } } if (options.showChanged && (expressionOrValue).valueChanged && value !== Expression.DEFAULT_VALUE) { @@ -104,7 +112,8 @@ export function renderVariable(tree: ITree, variable: Variable, data: IVariableT showChanged, maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET, preserveWhitespace: false, - showHover: true + showHover: true, + colorize: true }); } else { data.value.textContent = ''; @@ -134,7 +143,7 @@ function renderRenameBox(debugService: debug.IDebugService, contextViewService: inputBox.select(); let disposed = false; - const toDispose: [lifecycle.IDisposable] = [inputBox, styler]; + const toDispose: lifecycle.IDisposable[] = [inputBox, styler]; const wrapUp = once((renamed: boolean) => { if (!disposed) { @@ -188,7 +197,7 @@ function getSourceName(source: Source, contextService: IWorkspaceContextService, return source.name; } - return paths.basename(source.uri.fsPath); + return resources.basenameOrAuthority(source.uri); } export class BaseDebugController extends DefaultController { @@ -209,7 +218,7 @@ export class BaseDebugController extends DefaultController { this.contributedContextMenu = menuService.createMenu(menuId, contextKeyService); } - public onContextMenu(tree: ITree, element: debug.IEnablement, event: ContextMenuEvent): boolean { + public onContextMenu(tree: ITree, element: debug.IEnablement, event: ContextMenuEvent, focusElement = true): boolean { if (event.target && event.target.tagName && event.target.tagName.toLowerCase() === 'input') { return false; } @@ -217,10 +226,12 @@ export class BaseDebugController extends DefaultController { event.preventDefault(); event.stopPropagation(); - tree.setFocus(element); + if (focusElement) { + tree.setFocus(element); + } if (this.actionProvider.hasSecondaryActions(tree, element)) { - const anchor = { x: event.posx + 1, y: event.posy }; + const anchor = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, getActions: () => this.actionProvider.getSecondaryActions(tree, element).then(actions => { @@ -271,6 +282,9 @@ export class CallStackController extends BaseDebugController { return element.source.uri.toString(); } + if (element instanceof Thread) { + return element.threadId; + } } // user clicked / pressed on 'Load More Stack Frames', get those stack frames and refresh the tree. @@ -296,7 +310,7 @@ export class CallStackController extends BaseDebugController { export class CallStackActionProvider implements IActionProvider { - constructor( @IInstantiationService private instantiationService: IInstantiationService, @debug.IDebugService private debugService: debug.IDebugService) { + constructor( @IInstantiationService private instantiationService: IInstantiationService) { // noop } @@ -502,7 +516,8 @@ export class CallStackRenderer implements IRenderer { data.label = dom.append(data.stackFrame, $('span.label.expression')); data.file = dom.append(data.stackFrame, $('.file')); data.fileName = dom.append(data.file, $('span.file-name')); - data.lineNumber = dom.append(data.file, $('span.line-number')); + const wrapper = dom.append(data.file, $('span.line-number-wrapper')); + data.lineNumber = dom.append(wrapper, $('span.line-number')); return data; } @@ -523,7 +538,7 @@ export class CallStackRenderer implements IRenderer { private renderProcess(process: debug.IProcess, data: IProcessTemplateData): void { data.process.title = nls.localize({ key: 'process', comment: ['Process is a noun'] }, "Process"); - data.name.textContent = process.getName(this.contextService.hasMultiFolderWorkspace()); + data.name.textContent = process.getName(this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE); const stoppedThread = process.getAllThreads().filter(t => t.stopped).pop(); data.stateLabel.textContent = stoppedThread ? nls.localize('paused', "Paused") @@ -870,17 +885,13 @@ export class WatchExpressionsRenderer implements IRenderer { private static WATCH_EXPRESSION_TEMPLATE_ID = 'watchExpression'; private static VARIABLE_TEMPLATE_ID = 'variables'; private toDispose: lifecycle.IDisposable[]; - private actionProvider: WatchExpressionsActionProvider; constructor( - actionProvider: IActionProvider, - private actionRunner: IActionRunner, @debug.IDebugService private debugService: debug.IDebugService, @IContextViewService private contextViewService: IContextViewService, @IThemeService private themeService: IThemeService ) { this.toDispose = []; - this.actionProvider = actionProvider; } public getHeight(tree: ITree, element: any): number { @@ -941,7 +952,8 @@ export class WatchExpressionsRenderer implements IRenderer { showChanged: true, maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET, preserveWhitespace: false, - showHover: true + showHover: true, + colorize: true }); data.name.title = watchExpression.type ? watchExpression.type : watchExpression.value; } @@ -1049,11 +1061,12 @@ export class BreakpointsActionProvider implements IActionProvider { } public getSecondaryActions(tree: ITree, element: any): TPromise { - const actions: IAction[] = []; - - if (element instanceof Breakpoint || element instanceof FunctionBreakpoint) { - actions.push(this.instantiationService.createInstance(RemoveBreakpointAction, RemoveBreakpointAction.ID, RemoveBreakpointAction.LABEL)); + if (element instanceof ExceptionBreakpoint) { + return TPromise.as([]); } + + const actions: IAction[] = []; + actions.push(this.instantiationService.createInstance(RemoveBreakpointAction, RemoveBreakpointAction.ID, RemoveBreakpointAction.LABEL)); if (this.debugService.getModel().getBreakpoints().length + this.debugService.getModel().getFunctionBreakpoints().length > 1) { actions.push(this.instantiationService.createInstance(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL)); actions.push(new Separator()); @@ -1115,8 +1128,6 @@ export class BreakpointsRenderer implements IRenderer { private static BREAKPOINT_TEMPLATE_ID = 'breakpoint'; constructor( - private actionProvider: BreakpointsActionProvider, - private actionRunner: IActionRunner, @IWorkspaceContextService private contextService: IWorkspaceContextService, @debug.IDebugService private debugService: debug.IDebugService, @IContextViewService private contextViewService: IContextViewService, @@ -1223,10 +1234,10 @@ export class BreakpointsRenderer implements IRenderer { if (breakpoint.column) { data.lineNumber.textContent += `:${breakpoint.column}`; } - data.filePath.textContent = getPathLabel(paths.dirname(breakpoint.uri.fsPath), this.contextService, this.environmentService); + data.filePath.textContent = getPathLabel(resources.dirname(breakpoint.uri), this.contextService, this.environmentService); data.checkbox.checked = breakpoint.enabled; - const debugActive = this.debugService.state === debug.State.Running || this.debugService.state === debug.State.Stopped || this.debugService.state === debug.State.Initializing; + const debugActive = this.debugService.state === debug.State.Running || this.debugService.state === debug.State.Stopped; if (debugActive && !breakpoint.verified) { tree.addTraits('disabled', [breakpoint]); if (breakpoint.message) { @@ -1250,7 +1261,7 @@ export class BreakpointsAccessibilityProvider implements IAccessibilityProvider public getAriaLabel(tree: ITree, element: any): string { if (element instanceof Breakpoint) { - return nls.localize('breakpointAriaLabel', "Breakpoint line {0} {1}, breakpoints, debug", (element).lineNumber, getPathLabel(paths.basename((element).uri.fsPath), this.contextService), this.contextService); + return nls.localize('breakpointAriaLabel', "Breakpoint line {0} {1}, breakpoints, debug", (element).lineNumber, getPathLabel(resources.basenameOrAuthority((element).uri), this.contextService), this.contextService); } if (element instanceof FunctionBreakpoint) { return nls.localize('functionBreakpointAriaLabel', "Function breakpoint {0}, breakpoints, debug", (element).name); @@ -1280,6 +1291,10 @@ export class BreakpointsController extends BaseDebugController { } public openBreakpointSource(breakpoint: Breakpoint, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { + if (breakpoint.uri.scheme === debug.DEBUG_SCHEME && this.debugService.state === debug.State.Inactive) { + return; + } + const sideBySide = (event && (event.ctrlKey || event.metaKey)); const selection = breakpoint.endLineNumber ? { startLineNumber: breakpoint.lineNumber, diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts index 29613fc217b..77c31005f1c 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as paths from 'vs/base/common/paths'; -import { RunOnceScheduler } from 'vs/base/common/async'; +import * as resources from 'vs/base/common/resources'; +import { RunOnceScheduler, sequence } from 'vs/base/common/async'; import * as dom from 'vs/base/browser/dom'; import * as builder from 'vs/base/browser/builder'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -15,9 +15,8 @@ import { IAction } from 'vs/base/common/actions'; import { prepareActions } from 'vs/workbench/browser/actions'; import { IHighlightEvent, ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; -import { CollapsibleState, ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; import { CollapseAction } from 'vs/workbench/browser/viewlet'; -import { CollapsibleView, IViewletViewOptions, IViewOptions } from 'vs/workbench/parts/views/browser/views'; +import { ViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IDebugService, State, IBreakpoint, IExpression, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED } from 'vs/workbench/parts/debug/common/debug'; import { Expression, Variable, ExceptionBreakpoint, FunctionBreakpoint, Thread, StackFrame, Breakpoint, ThreadAndProcessIds } from 'vs/workbench/parts/debug/common/debugModel'; import * as viewer from 'vs/workbench/parts/debug/electron-browser/debugViewer'; @@ -25,7 +24,6 @@ import { AddWatchExpressionAction, RemoveAllWatchExpressionsAction, AddFunctionB import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { MenuId } from 'vs/platform/actions/common/actions'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IListService } from 'vs/platform/list/browser/listService'; @@ -42,18 +40,17 @@ function renderViewTree(container: HTMLElement): HTMLElement { const $ = builder.$; const twistiePixels = 20; -export class VariablesView extends CollapsibleView { +export class VariablesView extends ViewsViewletPanel { private static MEMENTO = 'variablesview.memento'; private onFocusStackFrameScheduler: RunOnceScheduler; private variablesFocusedContext: IContextKey; private settings: any; + private expandedElements: any[]; constructor( - initialSize: number, - private options: IViewletViewOptions, + options: IViewletViewOptions, @IContextMenuService contextMenuService: IContextMenuService, - @ITelemetryService private telemetryService: ITelemetryService, @IDebugService private debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService, @IInstantiationService private instantiationService: IInstantiationService, @@ -61,36 +58,39 @@ export class VariablesView extends CollapsibleView { @IListService private listService: IListService, @IThemeService private themeService: IThemeService ) { - super(initialSize, { ...(options as IViewOptions), sizing: ViewSizing.Flexible, ariaHeaderLabel: nls.localize('variablesSection', "Variables Section") }, keybindingService, contextMenuService); + super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize('variablesSection', "Variables Section") }, keybindingService, contextMenuService); this.settings = options.viewletSettings; this.variablesFocusedContext = CONTEXT_VARIABLES_FOCUSED.bindTo(contextKeyService); + this.expandedElements = []; // Use scheduler to prevent unnecessary flashing this.onFocusStackFrameScheduler = new RunOnceScheduler(() => { + // Remember expanded elements when there are some (otherwise don't override/erase the previous ones) + const expanded = this.tree.getExpandedElements(); + if (expanded.length > 0) { + this.expandedElements = expanded; + } + // Always clear tree highlight to avoid ending up in a broken state #12203 this.tree.clearHighlight(); this.tree.refresh().then(() => { const stackFrame = this.debugService.getViewModel().focusedStackFrame; - if (stackFrame) { - return stackFrame.getScopes().then(scopes => { - if (scopes.length > 0 && !scopes[0].expensive) { - return this.tree.expand(scopes[0]); - } - return undefined; - }); - } - return undefined; + return sequence(this.expandedElements.map(e => () => this.tree.expand(e))).then(() => { + // If there is no preserved expansion state simply expand the first scope + if (stackFrame && this.tree.getExpandedElements().length === 0) { + return stackFrame.getScopes().then(scopes => { + if (scopes.length > 0 && !scopes[0].expensive) { + return this.tree.expand(scopes[0]); + } + return undefined; + }); + } + return undefined; + }); }).done(null, errors.onUnexpectedError); }, 400); } - public renderHeader(container: HTMLElement): void { - const titleDiv = $('div.title').appendTo(container); - $('span').text(this.options.name).appendTo(titleDiv); - - super.renderHeader(container); - } - public renderBody(container: HTMLElement): void { dom.addClass(container, 'debug-variables'); this.treeContainer = renderViewTree(container); @@ -106,17 +106,17 @@ export class VariablesView extends CollapsibleView { keyboardSupport: false }); - this.toDispose.push(attachListStyler(this.tree, this.themeService)); - this.toDispose.push(this.listService.register(this.tree, [this.variablesFocusedContext])); + this.disposables.push(attachListStyler(this.tree, this.themeService)); + this.disposables.push(this.listService.register(this.tree, [this.variablesFocusedContext])); const viewModel = this.debugService.getViewModel(); this.tree.setInput(viewModel); const collapseAction = this.instantiationService.createInstance(CollapseAction, this.tree, false, 'explorer-action collapse-explorer'); - this.toolBar.setActions(prepareActions([collapseAction]))(); + this.toolbar.setActions(prepareActions([collapseAction]))(); - this.toDispose.push(viewModel.onDidFocusStackFrame(sf => { + this.disposables.push(viewModel.onDidFocusStackFrame(sf => { // Refresh the tree immediately if it is not visible. // Otherwise postpone the refresh until user stops stepping. if (!this.tree.getContentHeight() || sf.explicit) { @@ -125,11 +125,11 @@ export class VariablesView extends CollapsibleView { this.onFocusStackFrameScheduler.schedule(); } })); - this.toDispose.push(this.debugService.onDidChangeState(state => { + this.disposables.push(this.debugService.onDidChangeState(state => { collapseAction.enabled = state === State.Running || state === State.Stopped; })); - this.toDispose.push(this.debugService.getViewModel().onDidSelectExpression(expression => { + this.disposables.push(this.debugService.getViewModel().onDidSelectExpression(expression => { if (!expression || !(expression instanceof Variable)) { return; } @@ -146,12 +146,12 @@ export class VariablesView extends CollapsibleView { } public shutdown(): void { - this.settings[VariablesView.MEMENTO] = (this.state === CollapsibleState.COLLAPSED); + this.settings[VariablesView.MEMENTO] = !this.isExpanded(); super.shutdown(); } } -export class WatchExpressionsView extends CollapsibleView { +export class WatchExpressionsView extends ViewsViewletPanel { private static MEMENTO = 'watchexpressionsview.memento'; private onWatchExpressionsUpdatedScheduler: RunOnceScheduler; @@ -160,8 +160,7 @@ export class WatchExpressionsView extends CollapsibleView { private settings: any; constructor( - size: number, - private options: IViewletViewOptions, + options: IViewletViewOptions, @IContextMenuService contextMenuService: IContextMenuService, @IDebugService private debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService, @@ -170,13 +169,13 @@ export class WatchExpressionsView extends CollapsibleView { @IListService private listService: IListService, @IThemeService private themeService: IThemeService ) { - super(size, { ...(options as IViewOptions), ariaHeaderLabel: nls.localize('expressionsSection', "Expressions Section"), sizing: ViewSizing.Flexible }, keybindingService, contextMenuService); + super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize('expressionsSection', "Expressions Section") }, keybindingService, contextMenuService); this.settings = options.viewletSettings; - this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(we => { + this.disposables.push(this.debugService.getModel().onDidChangeWatchExpressions(we => { // only expand when a new watch expression is added. if (we instanceof Expression) { - this.expand(); + this.setExpanded(true); } })); this.watchExpressionsFocusedContext = CONTEXT_WATCH_EXPRESSIONS_FOCUSED.bindTo(contextKeyService); @@ -188,13 +187,6 @@ export class WatchExpressionsView extends CollapsibleView { }, 50); } - public renderHeader(container: HTMLElement): void { - const titleDiv = $('div.title').appendTo(container); - $('span').text(this.options.name).appendTo(titleDiv); - - super.renderHeader(container); - } - public renderBody(container: HTMLElement): void { dom.addClass(container, 'debug-watch'); this.treeContainer = renderViewTree(container); @@ -202,7 +194,7 @@ export class WatchExpressionsView extends CollapsibleView { const actionProvider = new viewer.WatchExpressionsActionProvider(this.instantiationService); this.tree = new Tree(this.treeContainer, { dataSource: new viewer.WatchExpressionsDataSource(), - renderer: this.instantiationService.createInstance(viewer.WatchExpressionsRenderer, actionProvider, this.actionRunner), + renderer: this.instantiationService.createInstance(viewer.WatchExpressionsRenderer), accessibilityProvider: new viewer.WatchExpressionsAccessibilityProvider(), controller: this.instantiationService.createInstance(viewer.WatchExpressionsController, actionProvider, MenuId.DebugWatchContext), dnd: this.instantiationService.createInstance(viewer.WatchExpressionsDragAndDrop) @@ -212,24 +204,24 @@ export class WatchExpressionsView extends CollapsibleView { keyboardSupport: false }); - this.toDispose.push(attachListStyler(this.tree, this.themeService)); - this.toDispose.push(this.listService.register(this.tree, [this.watchExpressionsFocusedContext])); + this.disposables.push(attachListStyler(this.tree, this.themeService)); + this.disposables.push(this.listService.register(this.tree, [this.watchExpressionsFocusedContext])); this.tree.setInput(this.debugService.getModel()); const addWatchExpressionAction = this.instantiationService.createInstance(AddWatchExpressionAction, AddWatchExpressionAction.ID, AddWatchExpressionAction.LABEL); const collapseAction = this.instantiationService.createInstance(CollapseAction, this.tree, true, 'explorer-action collapse-explorer'); const removeAllWatchExpressionsAction = this.instantiationService.createInstance(RemoveAllWatchExpressionsAction, RemoveAllWatchExpressionsAction.ID, RemoveAllWatchExpressionsAction.LABEL); - this.toolBar.setActions(prepareActions([addWatchExpressionAction, collapseAction, removeAllWatchExpressionsAction]))(); + this.toolbar.setActions(prepareActions([addWatchExpressionAction, collapseAction, removeAllWatchExpressionsAction]))(); - this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(we => { + this.disposables.push(this.debugService.getModel().onDidChangeWatchExpressions(we => { if (!this.onWatchExpressionsUpdatedScheduler.isScheduled()) { this.onWatchExpressionsUpdatedScheduler.schedule(); } this.toReveal = we; })); - this.toDispose.push(this.debugService.getViewModel().onDidSelectExpression(expression => { + this.disposables.push(this.debugService.getViewModel().onDidSelectExpression(expression => { if (!expression || !(expression instanceof Expression)) { return; } @@ -246,12 +238,12 @@ export class WatchExpressionsView extends CollapsibleView { } public shutdown(): void { - this.settings[WatchExpressionsView.MEMENTO] = (this.state === CollapsibleState.COLLAPSED); + this.settings[WatchExpressionsView.MEMENTO] = !this.isExpanded(); super.shutdown(); } } -export class CallStackView extends CollapsibleView { +export class CallStackView extends ViewsViewletPanel { private static MEMENTO = 'callstackview.memento'; private pauseMessage: builder.Builder; @@ -260,17 +252,15 @@ export class CallStackView extends CollapsibleView { private settings: any; constructor( - size: number, private options: IViewletViewOptions, @IContextMenuService contextMenuService: IContextMenuService, - @ITelemetryService private telemetryService: ITelemetryService, @IDebugService private debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService, @IInstantiationService private instantiationService: IInstantiationService, @IListService private listService: IListService, @IThemeService private themeService: IThemeService ) { - super(size, { ...(options as IViewOptions), ariaHeaderLabel: nls.localize('callstackSection', "Call Stack Section"), sizing: ViewSizing.Flexible }, keybindingService, contextMenuService); + super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize('callstackSection', "Call Stack Section") }, keybindingService, contextMenuService); this.settings = options.viewletSettings; // Create scheduler to prevent unnecessary flashing of tree when reacting to changes @@ -301,14 +291,12 @@ export class CallStackView extends CollapsibleView { }, 50); } - public renderHeader(container: HTMLElement): void { - const title = $('div.debug-call-stack-title').appendTo(container); - $('span.title').text(this.options.name).appendTo(title); + protected renderHeaderTitle(container: HTMLElement): void { + const title = $('.title.debug-call-stack-title').appendTo(container); + $('span').text(this.options.name).appendTo(title); this.pauseMessage = $('span.pause-message').appendTo(title); this.pauseMessage.hide(); this.pauseMessageLabel = $('span.label').appendTo(this.pauseMessage); - - super.renderHeader(container); } public renderBody(container: HTMLElement): void { @@ -328,10 +316,10 @@ export class CallStackView extends CollapsibleView { keyboardSupport: false }); - this.toDispose.push(attachListStyler(this.tree, this.themeService)); - this.toDispose.push(this.listService.register(this.tree)); + this.disposables.push(attachListStyler(this.tree, this.themeService)); + this.disposables.push(this.listService.register(this.tree)); - this.toDispose.push(this.tree.addListener('selection', event => { + this.disposables.push(this.tree.addListener('selection', event => { if (event && event.payload && event.payload.origin === 'keyboard') { const element = this.tree.getFocus(); if (element instanceof ThreadAndProcessIds) { @@ -342,12 +330,12 @@ export class CallStackView extends CollapsibleView { } })); - this.toDispose.push(this.debugService.getModel().onDidChangeCallStack(() => { + this.disposables.push(this.debugService.getModel().onDidChangeCallStack(() => { if (!this.onCallStackChangeScheduler.isScheduled()) { this.onCallStackChangeScheduler.schedule(); } })); - this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => + this.disposables.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.updateTreeSelection().done(undefined, errors.onUnexpectedError))); // Schedule the update of the call stack tree if the viewlet is opened after a session started #14684 @@ -386,12 +374,12 @@ export class CallStackView extends CollapsibleView { } public shutdown(): void { - this.settings[CallStackView.MEMENTO] = (this.state === CollapsibleState.COLLAPSED); + this.settings[CallStackView.MEMENTO] = !this.isExpanded(); super.shutdown(); } } -export class BreakpointsView extends CollapsibleView { +export class BreakpointsView extends ViewsViewletPanel { private static MAX_VISIBLE_FILES = 9; private static MEMENTO = 'breakopintsview.memento'; @@ -399,8 +387,7 @@ export class BreakpointsView extends CollapsibleView { private settings: any; constructor( - size: number, - private options: IViewletViewOptions, + options: IViewletViewOptions, @IContextMenuService contextMenuService: IContextMenuService, @IDebugService private debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService, @@ -409,23 +396,15 @@ export class BreakpointsView extends CollapsibleView { @IListService private listService: IListService, @IThemeService private themeService: IThemeService ) { - super(size, { + super({ ...(options as IViewOptions), - ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section"), - sizing: ViewSizing.Fixed, - initialBodySize: BreakpointsView.getExpandedBodySize(debugService.getModel().getBreakpoints().length + debugService.getModel().getFunctionBreakpoints().length + debugService.getModel().getExceptionBreakpoints().length) + ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService); + this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize(); this.settings = options.viewletSettings; this.breakpointsFocusedContext = CONTEXT_BREAKPOINTS_FOCUSED.bindTo(contextKeyService); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange())); - } - - public renderHeader(container: HTMLElement): void { - const titleDiv = $('div.title').appendTo(container); - $('span').text(this.options.name).appendTo(titleDiv); - - super.renderHeader(container); + this.disposables.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange())); } public renderBody(container: HTMLElement): void { @@ -436,7 +415,7 @@ export class BreakpointsView extends CollapsibleView { this.tree = new Tree(this.treeContainer, { dataSource: new viewer.BreakpointsDataSource(), - renderer: this.instantiationService.createInstance(viewer.BreakpointsRenderer, actionProvider, this.actionRunner), + renderer: this.instantiationService.createInstance(viewer.BreakpointsRenderer), accessibilityProvider: this.instantiationService.createInstance(viewer.BreakpointsAccessibilityProvider), controller, sorter: { @@ -457,7 +436,7 @@ export class BreakpointsView extends CollapsibleView { } if (first.uri.toString() !== second.uri.toString()) { - return paths.basename(first.uri.fsPath).localeCompare(paths.basename(second.uri.fsPath)); + return resources.basenameOrAuthority(first.uri).localeCompare(resources.basenameOrAuthority(second.uri)); } if (first.lineNumber === second.lineNumber) { return first.column - second.column; @@ -472,10 +451,10 @@ export class BreakpointsView extends CollapsibleView { keyboardSupport: false }); - this.toDispose.push(attachListStyler(this.tree, this.themeService)); - this.toDispose.push(this.listService.register(this.tree, [this.breakpointsFocusedContext])); + this.disposables.push(attachListStyler(this.tree, this.themeService)); + this.disposables.push(this.listService.register(this.tree, [this.breakpointsFocusedContext])); - this.toDispose.push(this.tree.addListener('selection', event => { + this.disposables.push(this.tree.addListener('selection', event => { if (event && event.payload && event.payload.origin === 'keyboard') { const element = this.tree.getFocus(); if (element instanceof Breakpoint) { @@ -488,7 +467,7 @@ export class BreakpointsView extends CollapsibleView { this.tree.setInput(debugModel); - this.toDispose.push(this.debugService.getViewModel().onDidSelectFunctionBreakpoint(fbp => { + this.disposables.push(this.debugService.getViewModel().onDidSelectFunctionBreakpoint(fbp => { if (!fbp || !(fbp instanceof FunctionBreakpoint)) { return; } @@ -513,21 +492,20 @@ export class BreakpointsView extends CollapsibleView { } private onBreakpointsChange(): void { - const model = this.debugService.getModel(); - this.setBodySize(BreakpointsView.getExpandedBodySize( - model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length)); - + this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize(); if (this.tree) { this.tree.refresh(); } } - private static getExpandedBodySize(length: number): number { + private getExpandedBodySize(): number { + const model = this.debugService.getModel(); + const length = model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length; return Math.min(BreakpointsView.MAX_VISIBLE_FILES, length) * 22; } public shutdown(): void { - this.settings[BreakpointsView.MEMENTO] = (this.state === CollapsibleState.COLLAPSED); + this.settings[BreakpointsView.MEMENTO] = !this.isExpanded(); super.shutdown(); } } diff --git a/src/vs/workbench/parts/debug/electron-browser/media/continue-tb.png b/src/vs/workbench/parts/debug/electron-browser/media/continue-tb.png new file mode 100644 index 00000000000..32f8acec879 Binary files /dev/null and b/src/vs/workbench/parts/debug/electron-browser/media/continue-tb.png differ diff --git a/src/vs/workbench/parts/debug/electron-browser/media/pause-tb.png b/src/vs/workbench/parts/debug/electron-browser/media/pause-tb.png new file mode 100644 index 00000000000..bc6699fb56a Binary files /dev/null and b/src/vs/workbench/parts/debug/electron-browser/media/pause-tb.png differ diff --git a/src/vs/workbench/parts/debug/electron-browser/media/restart-tb.png b/src/vs/workbench/parts/debug/electron-browser/media/restart-tb.png new file mode 100644 index 00000000000..049f8f9f588 Binary files /dev/null and b/src/vs/workbench/parts/debug/electron-browser/media/restart-tb.png differ diff --git a/src/vs/workbench/parts/debug/electron-browser/media/stepinto-tb.png b/src/vs/workbench/parts/debug/electron-browser/media/stepinto-tb.png new file mode 100644 index 00000000000..9e793d5e6e7 Binary files /dev/null and b/src/vs/workbench/parts/debug/electron-browser/media/stepinto-tb.png differ diff --git a/src/vs/workbench/parts/debug/electron-browser/media/stepout-tb.png b/src/vs/workbench/parts/debug/electron-browser/media/stepout-tb.png new file mode 100644 index 00000000000..67bbb10f5ad Binary files /dev/null and b/src/vs/workbench/parts/debug/electron-browser/media/stepout-tb.png differ diff --git a/src/vs/workbench/parts/debug/electron-browser/media/stepover-tb.png b/src/vs/workbench/parts/debug/electron-browser/media/stepover-tb.png new file mode 100644 index 00000000000..408a47153f5 Binary files /dev/null and b/src/vs/workbench/parts/debug/electron-browser/media/stepover-tb.png differ diff --git a/src/vs/workbench/parts/debug/electron-browser/media/stop-tb.png b/src/vs/workbench/parts/debug/electron-browser/media/stop-tb.png new file mode 100644 index 00000000000..b5d38d8ceef Binary files /dev/null and b/src/vs/workbench/parts/debug/electron-browser/media/stop-tb.png differ diff --git a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts index e74a2cd53ac..6ed9ed23c88 100644 --- a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts @@ -6,7 +6,6 @@ import nls = require('vs/nls'); import cp = require('child_process'); import net = require('net'); -import uri from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import platform = require('vs/base/common/platform'); import objects = require('vs/base/common/objects'); @@ -23,6 +22,7 @@ import debug = require('vs/workbench/parts/debug/common/debug'); import { Adapter } from 'vs/workbench/parts/debug/node/debugAdapter'; import { V8Protocol } from 'vs/workbench/parts/debug/node/v8Protocol'; import { IOutputService } from 'vs/workbench/parts/output/common/output'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ExtensionsChannelId } from 'vs/platform/extensionManagement/common/extensionManagement'; import { TerminalSupport } from 'vs/workbench/parts/debug/electron-browser/terminalSupport'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -70,8 +70,8 @@ export class RawDebugSession extends V8Protocol implements debug.ISession { id: string, private debugServerPort: number, private adapter: Adapter, - private customTelemetryService: ITelemetryService, - public root: uri, + public customTelemetryService: ITelemetryService, + public root: IWorkspaceFolder, @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService, @IOutputService private outputService: IOutputService, @@ -164,8 +164,17 @@ export class RawDebugSession extends V8Protocol implements debug.ISession { const errorMessage = errorResponse ? errorResponse.message : ''; const telemetryMessage = error ? debug.formatPII(error.format, true, error.variables) : errorMessage; if (error && error.sendTelemetry) { + /* __GDPR__ + "debugProtocolErrorResponse" : { + "error" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage }); if (this.customTelemetryService) { + /* __GDPR__TODO__ + The message is sent in the name of the adapter but the adapter doesn't know about it. + However, since adapters are an open-ended set, we can not declared the events statically either. + */ this.customTelemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage }); } } diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index b097d3a3652..189ce191a23 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -180,7 +180,7 @@ export class Repl extends Panel implements IPrivateReplService { modes.SuggestRegistry.register({ scheme: debug.DEBUG_SCHEME }, { triggerCharacters: ['.'], - provideCompletionItems: (model: IReadOnlyModel, position: Position, token: CancellationToken): Thenable => { + provideCompletionItems: (model: IReadOnlyModel, position: Position, _context: modes.SuggestContext, token: CancellationToken): Thenable => { const word = this.replInput.getModel().getWordAtPosition(position); const overwriteBefore = word ? word.word.length : 0; const text = this.replInput.getModel().getLineContent(position.lineNumber); @@ -313,6 +313,7 @@ export class Repl extends Panel implements IPrivateReplService { } @editorAction +// @ts-ignore @editorAction uses the class class ReplHistoryPreviousAction extends EditorAction { constructor() { @@ -338,6 +339,7 @@ class ReplHistoryPreviousAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class ReplHistoryNextAction extends EditorAction { constructor() { @@ -363,6 +365,7 @@ class ReplHistoryNextAction extends EditorAction { } @editorAction +// @ts-ignore @editorAction uses the class class AcceptReplInputAction extends EditorAction { constructor() { diff --git a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts index 9ae5593472c..848ec016c5f 100644 --- a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts @@ -6,15 +6,17 @@ import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { IAction } from 'vs/base/common/actions'; +import * as lifecycle from 'vs/base/common/lifecycle'; +import * as errors from 'vs/base/common/errors'; import { isFullWidthCharacter, removeAnsiEscapeCodes, endsWith } from 'vs/base/common/strings'; import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import * as dom from 'vs/base/browser/dom'; import severity from 'vs/base/common/severity'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; -import { ITree, IAccessibilityProvider, IDataSource, IRenderer, IActionProvider } from 'vs/base/parts/tree/browser/tree'; +import { ITree, IAccessibilityProvider, ContextMenuEvent, IDataSource, IRenderer, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults'; -import { IExpressionContainer, IExpression } from 'vs/workbench/parts/debug/common/debug'; -import { Model, OutputNameValueElement, Expression, OutputElement, Variable } from 'vs/workbench/parts/debug/common/debugModel'; +import { IExpressionContainer, IExpression, IReplElementSource } from 'vs/workbench/parts/debug/common/debug'; +import { Model, RawObjectReplElement, Expression, SimpleReplElement, Variable } from 'vs/workbench/parts/debug/common/debugModel'; import { renderVariable, renderExpressionValue, IVariableTemplateData, BaseDebugController } from 'vs/workbench/parts/debug/electron-browser/debugViewer'; import { ClearReplAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { CopyAction, CopyAllAction } from 'vs/workbench/parts/debug/electron-browser/electronDebugActions'; @@ -38,10 +40,10 @@ export class ReplExpressionsDataSource implements IDataSource { if (element instanceof Model) { return TPromise.as(element.getReplElements()); } - if (element instanceof OutputNameValueElement) { + if (element instanceof RawObjectReplElement) { return TPromise.as(element.getChildren()); } - if (element instanceof OutputElement) { + if (element instanceof SimpleReplElement) { return TPromise.as(null); } @@ -60,12 +62,15 @@ interface IExpressionTemplateData { annotation: HTMLElement; } -interface IValueOutputTemplateData { +interface ISimpleReplElementTemplateData { container: HTMLElement; value: HTMLElement; + source: HTMLElement; + getReplElementSource(): IReplElementSource; + toDispose: lifecycle.IDisposable[]; } -interface IKeyValueOutputTemplateData { +interface IRawObjectReplTemplateData { container: HTMLElement; expression: HTMLElement; name: HTMLElement; @@ -76,9 +81,9 @@ interface IKeyValueOutputTemplateData { export class ReplExpressionsRenderer implements IRenderer { private static VARIABLE_TEMPLATE_ID = 'variable'; - private static EXPRESSION_TEMPLATE_ID = 'inputOutputPair'; - private static VALUE_OUTPUT_TEMPLATE_ID = 'outputValue'; - private static NAME_VALUE_OUTPUT_TEMPLATE_ID = 'outputNameValue'; + private static EXPRESSION_TEMPLATE_ID = 'expressionRepl'; + private static SIMPLE_REPL_ELEMENT_TEMPLATE_ID = 'simpleReplElement'; + private static RAW_OBJECT_REPL_ELEMENT_TEMPLATE_ID = 'rawObject'; private static LINE_HEIGHT_PX = 18; @@ -139,12 +144,12 @@ export class ReplExpressionsRenderer implements IRenderer { if (element instanceof Expression) { return ReplExpressionsRenderer.EXPRESSION_TEMPLATE_ID; } - if (element instanceof OutputElement || (element instanceof Variable && !element.name)) { - // Variable with no name is a top level variable which should be rendered like an output element #17404 - return ReplExpressionsRenderer.VALUE_OUTPUT_TEMPLATE_ID; + if (element instanceof SimpleReplElement || (element instanceof Variable && !element.name)) { + // Variable with no name is a top level variable which should be rendered like a repl element #17404 + return ReplExpressionsRenderer.SIMPLE_REPL_ELEMENT_TEMPLATE_ID; } - if (element instanceof OutputNameValueElement) { - return ReplExpressionsRenderer.NAME_VALUE_OUTPUT_TEMPLATE_ID; + if (element instanceof RawObjectReplElement) { + return ReplExpressionsRenderer.RAW_OBJECT_REPL_ELEMENT_TEMPLATE_ID; } return null; @@ -171,19 +176,34 @@ export class ReplExpressionsRenderer implements IRenderer { return data; } - if (templateId === ReplExpressionsRenderer.VALUE_OUTPUT_TEMPLATE_ID) { - let data: IValueOutputTemplateData = Object.create(null); + if (templateId === ReplExpressionsRenderer.SIMPLE_REPL_ELEMENT_TEMPLATE_ID) { + let data: ISimpleReplElementTemplateData = Object.create(null); dom.addClass(container, 'output'); - let expression = dom.append(container, $('.output.expression')); + let expression = dom.append(container, $('.output.expression.value-and-source')); data.container = container; data.value = dom.append(expression, $('span.value')); + data.source = dom.append(expression, $('.source')); + data.toDispose = []; + data.toDispose.push(dom.addDisposableListener(data.source, 'click', e => { + e.preventDefault(); + e.stopPropagation(); + const source = data.getReplElementSource(); + if (source) { + source.source.openInEditor(this.editorService, { + startLineNumber: source.lineNumber, + startColumn: source.column, + endLineNumber: source.lineNumber, + endColumn: source.column + }).done(undefined, errors.onUnexpectedError); + } + })); return data; } - if (templateId === ReplExpressionsRenderer.NAME_VALUE_OUTPUT_TEMPLATE_ID) { - let data: IKeyValueOutputTemplateData = Object.create(null); + if (templateId === ReplExpressionsRenderer.RAW_OBJECT_REPL_ELEMENT_TEMPLATE_ID) { + let data: IRawObjectReplTemplateData = Object.create(null); dom.addClass(container, 'output'); data.container = container; @@ -201,10 +221,10 @@ export class ReplExpressionsRenderer implements IRenderer { renderVariable(tree, element, templateData, false); } else if (templateId === ReplExpressionsRenderer.EXPRESSION_TEMPLATE_ID) { this.renderExpression(tree, element, templateData); - } else if (templateId === ReplExpressionsRenderer.VALUE_OUTPUT_TEMPLATE_ID) { - this.renderOutputValue(element, templateData); - } else if (templateId === ReplExpressionsRenderer.NAME_VALUE_OUTPUT_TEMPLATE_ID) { - this.renderOutputNameValue(tree, element, templateData); + } else if (templateId === ReplExpressionsRenderer.SIMPLE_REPL_ELEMENT_TEMPLATE_ID) { + this.renderSimpleReplElement(element, templateData); + } else if (templateId === ReplExpressionsRenderer.RAW_OBJECT_REPL_ELEMENT_TEMPLATE_ID) { + this.renderRawObjectReplElement(tree, element, templateData); } } @@ -212,7 +232,8 @@ export class ReplExpressionsRenderer implements IRenderer { templateData.input.textContent = expression.name; renderExpressionValue(expression, templateData.value, { preserveWhitespace: !expression.hasChildren, - showHover: false + showHover: false, + colorize: true }); if (expression.hasChildren) { templateData.annotation.className = 'annotation octicon octicon-info'; @@ -220,12 +241,13 @@ export class ReplExpressionsRenderer implements IRenderer { } } - private renderOutputValue(output: OutputElement, templateData: IValueOutputTemplateData): void { + private renderSimpleReplElement(element: SimpleReplElement, templateData: ISimpleReplElementTemplateData): void { // value dom.clearNode(templateData.value); - templateData.value.className = ''; - let result = this.handleANSIOutput(output.value); + // Reset classes to clear ansi decorations since templates are reused + templateData.value.className = 'value'; + let result = this.handleANSIOutput(element.value); if (typeof result === 'string') { renderExpressionValue(result, templateData.value, { preserveWhitespace: true, @@ -235,27 +257,30 @@ export class ReplExpressionsRenderer implements IRenderer { templateData.value.appendChild(result); } - dom.addClass(templateData.value, (output.severity === severity.Warning) ? 'warn' : (output.severity === severity.Error) ? 'error' : 'info'); + dom.addClass(templateData.value, (element.severity === severity.Warning) ? 'warn' : (element.severity === severity.Error) ? 'error' : 'info'); + templateData.source.textContent = element.sourceData ? `${element.sourceData.source.name}:${element.sourceData.lineNumber}` : ''; + templateData.source.title = element.sourceData ? element.sourceData.source.uri.toString() : ''; + templateData.getReplElementSource = () => element.sourceData; } - private renderOutputNameValue(tree: ITree, output: OutputNameValueElement, templateData: IKeyValueOutputTemplateData): void { + private renderRawObjectReplElement(tree: ITree, element: RawObjectReplElement, templateData: IRawObjectReplTemplateData): void { // key - if (output.name) { - templateData.name.textContent = `${output.name}:`; + if (element.name) { + templateData.name.textContent = `${element.name}:`; } else { templateData.name.textContent = ''; } // value - renderExpressionValue(output.value, templateData.value, { + renderExpressionValue(element.value, templateData.value, { preserveWhitespace: true, showHover: false }); // annotation if any - if (output.annotation) { + if (element.annotation) { templateData.annotation.className = 'annotation octicon octicon-info'; - templateData.annotation.title = output.annotation; + templateData.annotation.title = element.annotation; } else { templateData.annotation.className = ''; templateData.annotation.title = ''; @@ -352,7 +377,9 @@ export class ReplExpressionsRenderer implements IRenderer { } public disposeTemplate(tree: ITree, templateId: string, templateData: any): void { - // noop + if (templateData.toDispose) { + lifecycle.dispose(templateData.toDispose); + } } } @@ -365,11 +392,11 @@ export class ReplExpressionsAccessibilityProvider implements IAccessibilityProvi if (element instanceof Expression) { return nls.localize('replExpressionAriaLabel', "Expression {0} has value {1}, read eval print loop, debug", (element).name, (element).value); } - if (element instanceof OutputElement) { - return nls.localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", (element).value); + if (element instanceof SimpleReplElement) { + return nls.localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", (element).value); } - if (element instanceof OutputNameValueElement) { - return nls.localize('replKeyValueOutputAriaLabel', "Output variable {0} has value {1}, read eval print loop, debug", (element).name, (element).value); + if (element instanceof RawObjectReplElement) { + return nls.localize('replRawObjectAriaLabel', "Repl variable {0} has value {1}, read eval print loop, debug", (element).name, (element).value); } return null; @@ -416,7 +443,7 @@ export class ReplExpressionsController extends BaseDebugController { protected onLeftClick(tree: ITree, element: any, eventish: ICancelableEvent, origin: string = 'mouse'): boolean { const mouseEvent = eventish; // input and output are one element in the tree => we only expand if the user clicked on the output. - if ((element.reference > 0 || (element instanceof OutputNameValueElement && element.hasChildren)) && mouseEvent.target.className.indexOf('input expression') === -1) { + if ((element.reference > 0 || (element instanceof RawObjectReplElement && element.hasChildren)) && mouseEvent.target.className.indexOf('input expression') === -1) { super.onLeftClick(tree, element, eventish, origin); tree.clearFocus(); tree.deselect(element); @@ -431,4 +458,8 @@ export class ReplExpressionsController extends BaseDebugController { return true; } + + public onContextMenu(tree: ITree, element: any, event: ContextMenuEvent): boolean { + return super.onContextMenu(tree, element, event, false); + } } diff --git a/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts b/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts index f5c8e2040ce..a49f5ec93e9 100644 --- a/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts +++ b/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts @@ -9,7 +9,7 @@ import { registerColor, contrastBorder } from 'vs/platform/theme/common/colorReg import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { IDebugService, State } from 'vs/workbench/parts/debug/common/debug'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_BACKGROUND, Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_BORDER } from 'vs/workbench/common/theme'; import { addClass, removeClass } from 'vs/base/browser/dom'; @@ -49,7 +49,7 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri private registerListeners(): void { this.toUnbind.push(this.debugService.onDidChangeState(state => this.updateStyles())); - this.toUnbind.push(this.contextService.onDidChangeWorkspaceRoots(state => this.updateStyles())); + this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(state => this.updateStyles())); } protected updateStyles(): void { @@ -75,7 +75,7 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri // Not debugging if (!this.isDebugging()) { - if (this.contextService.hasWorkspace()) { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY) { return normalColor; } @@ -87,7 +87,7 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri } private isDebugging(): boolean { - if (this.debugService.state === State.Inactive) { + if (this.debugService.state === State.Inactive || this.debugService.state === State.Initializing) { return false; } diff --git a/src/vs/workbench/parts/debug/electron-browser/terminalSupport.ts b/src/vs/workbench/parts/debug/electron-browser/terminalSupport.ts index 3456d7b4f41..df6f2affc77 100644 --- a/src/vs/workbench/parts/debug/electron-browser/terminalSupport.ts +++ b/src/vs/workbench/parts/debug/electron-browser/terminalSupport.ts @@ -11,7 +11,7 @@ import { ITerminalService, ITerminalInstance, ITerminalConfiguration } from 'vs/ import { ITerminalService as IExternalTerminalService } from 'vs/workbench/parts/execution/common/execution'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -const enum ShellType { cmd, powershell, bash }; +const enum ShellType { cmd, powershell, bash } export class TerminalSupport { diff --git a/src/vs/workbench/parts/debug/node/debugAdapter.ts b/src/vs/workbench/parts/debug/node/debugAdapter.ts index 3ff1b2651e9..6f0aeb9bff9 100644 --- a/src/vs/workbench/parts/debug/node/debugAdapter.ts +++ b/src/vs/workbench/parts/debug/node/debugAdapter.ts @@ -5,25 +5,22 @@ import fs = require('fs'); import path = require('path'); -import { parse } from 'vs/base/common/json'; import * as nls from 'vs/nls'; -import uri from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import * as strings from 'vs/base/common/strings'; import * as objects from 'vs/base/common/objects'; import * as paths from 'vs/base/common/paths'; import * as platform from 'vs/base/common/platform'; import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IConfig, IRawAdapter, IAdapterExecutable, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/parts/debug/common/debug'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; export class Adapter { constructor(private rawAdapter: IRawAdapter, public extensionDescription: IExtensionDescription, - @IConfigurationResolverService private configurationResolverService: IConfigurationResolverService, @IConfigurationService private configurationService: IConfigurationService, @ICommandService private commandService: ICommandService ) { @@ -34,10 +31,10 @@ export class Adapter { public hasConfigurationProvider = false; - public getAdapterExecutable(root: uri, verifyAgainstFS = true): TPromise { + public getAdapterExecutable(root: IWorkspaceFolder, verifyAgainstFS = true): TPromise { - if (this.rawAdapter.adapterExecutableCommand) { - return this.commandService.executeCommand(this.rawAdapter.adapterExecutableCommand, root.toString()).then(ad => { + if (this.rawAdapter.adapterExecutableCommand && root) { + return this.commandService.executeCommand(this.rawAdapter.adapterExecutableCommand, root.uri.toString()).then(ad => { return this.verifyAdapterDetails(ad, verifyAgainstFS); }); } @@ -125,10 +122,6 @@ export class Adapter { return this.rawAdapter.languages; } - public get startSessionCommand(): string { - return this.rawAdapter.startSessionCommand; - } - public merge(secondRawAdapter: IRawAdapter, extensionDescription: IExtensionDescription): void { // Give priority to built in debug adapters if (extensionDescription.isBuiltin) { @@ -141,32 +134,7 @@ export class Adapter { return !!this.rawAdapter.initialConfigurations; } - public getInitialConfigurationContent(folderUri: uri, initialConfigs?: IConfig[]): TPromise { - const editorConfig = this.configurationService.getConfiguration(); - - // deprecated code: use DebugConfigurationProvider instead of command - if (typeof this.rawAdapter.initialConfigurations === 'string') { - // Contributed initialConfigurations is a command that needs to be invoked - // Debug adapter will dynamically provide the full launch.json - // TODO@Isidor stop supporting initialConfigurations - return this.commandService.executeCommand(this.rawAdapter.initialConfigurations, folderUri).then(content => { - // Debug adapter returned the full content of the launch.json - return it after format - try { - const config = parse(content); - config.configurations.push(...initialConfigs); - content = JSON.stringify(config, null, '\t').split('\n').map(line => '\t' + line).join('\n').trim(); - } catch (e) { - // noop - } - - if (editorConfig.editor && editorConfig.editor.insertSpaces) { - content = content.replace(new RegExp('\t', 'g'), strings.repeat(' ', editorConfig.editor.tabSize)); - } - return content; - }); - } - // end of deprecation - + public getInitialConfigurationContent(initialConfigs?: IConfig[]): TPromise { // at this point we got some configs from the package.json and/or from registered DebugConfigurationProviders let initialConfigurations = this.rawAdapter.initialConfigurations || []; if (initialConfigs) { @@ -174,7 +142,6 @@ export class Adapter { } const configs = JSON.stringify(initialConfigurations, null, '\t').split('\n').map(line => '\t' + line).join('\n').trim(); - const comment1 = nls.localize('launch.config.comment1', "Use IntelliSense to learn about possible attributes."); const comment2 = nls.localize('launch.config.comment2', "Hover to view descriptions of existing attributes."); const comment3 = nls.localize('launch.config.comment3', "For more information, visit: {0}", 'https://go.microsoft.com/fwlink/?linkid=830387'); @@ -190,12 +157,13 @@ export class Adapter { ].join('\n'); // fix formatting + const editorConfig = this.configurationService.getConfiguration(); if (editorConfig.editor && editorConfig.editor.insertSpaces) { content = content.replace(new RegExp('\t', 'g'), strings.repeat(' ', editorConfig.editor.tabSize)); } return TPromise.as(content); - }; + } public getSchemaAttributes(): IJSONSchema[] { if (!this.rawAdapter.configurationAttributes) { @@ -240,7 +208,7 @@ export class Adapter { }; properties['internalConsoleOptions'] = INTERNAL_CONSOLE_OPTIONS_SCHEMA; - const osProperties = objects.deepClone(properties); + const osProperties = objects.clone(properties); properties['windows'] = { type: 'object', description: nls.localize('debugWindowsConfiguration', "Windows specific launch configuration attributes."), diff --git a/src/vs/workbench/parts/debug/test/common/debugSource.test.ts b/src/vs/workbench/parts/debug/test/common/debugSource.test.ts index efba17f4728..072ee84d214 100644 --- a/src/vs/workbench/parts/debug/test/common/debugSource.test.ts +++ b/src/vs/workbench/parts/debug/test/common/debugSource.test.ts @@ -15,7 +15,7 @@ suite('Debug - Source', () => { path: '/xx/yy/zz', sourceReference: 0, presentationHint: 'emphasize' - }); + }, 'aDebugSessionId'); assert.equal(source.presentationHint, 'emphasize'); assert.equal(source.name, 'zz'); @@ -29,11 +29,12 @@ suite('Debug - Source', () => { name: 'internalModule.js', sourceReference: 11, presentationHint: 'deemphasize' - }); + }, 'aDebugSessionId'); assert.equal(source.presentationHint, 'deemphasize'); assert.equal(source.name, 'internalModule.js'); assert.equal(source.inMemory, true); assert.equal(source.reference, 11); + assert.equal(source.uri.toString(), 'debug:internalModule.js?session%3DaDebugSessionId%26ref%3D11'); }); }); diff --git a/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts b/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts index c5414c58f34..cd85afc69dd 100644 --- a/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts +++ b/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts @@ -42,7 +42,6 @@ suite('Debug - View Model', () => { }); test('multi process view and changed workbench state', () => { - assert.equal(model.changedWorkbenchViewState, false); assert.equal(model.isMultiProcessView(), false); model.setMultiProcessView(true); assert.equal(model.isMultiProcessView(), true); diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index f5db2ab8ca6..13ecfa2b511 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -7,6 +7,7 @@ import uri from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import * as debug from 'vs/workbench/parts/debug/common/debug'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export class MockDebugService implements debug.IDebugService { public _serviceBrand: any; @@ -87,18 +88,10 @@ export class MockDebugService implements debug.IDebugService { return TPromise.as(null); } - public startDebugging(root: uri, configOrName?: debug.IConfig | string, noDebug?: boolean): TPromise { + public startDebugging(root: IWorkspaceFolder, configOrName?: debug.IConfig | string, noDebug?: boolean): TPromise { return TPromise.as(null); } - public createProcess(root: uri, config: debug.IConfig): TPromise { - return TPromise.as(null); - } - - public findProcessByUUID(uuid: string): debug.IProcess | null { - return null; - } - public restartProcess(): TPromise { return TPromise.as(null); } @@ -128,7 +121,7 @@ export class MockSession implements debug.ISession { return 'mockrawsession'; } - public root: uri; + public root: IWorkspaceFolder; public getLengthInSeconds(): number { return 100; @@ -182,9 +175,15 @@ export class MockSession implements debug.ISession { public get onDidInitialize(): Event { const emitter = new Emitter(); - return emitter.event;; + return emitter.event; } + public get onDidExitAdapter(): Event { + const emitter = new Emitter(); + return emitter.event; + } + + public custom(request: string, args: any): TPromise { return TPromise.as(null); } diff --git a/src/vs/workbench/parts/debug/test/node/debugAdapter.test.ts b/src/vs/workbench/parts/debug/test/node/debugAdapter.test.ts index e65f7aa5193..9e626d4be69 100644 --- a/src/vs/workbench/parts/debug/test/node/debugAdapter.test.ts +++ b/src/vs/workbench/parts/debug/test/node/debugAdapter.test.ts @@ -44,7 +44,7 @@ suite('Debug - Adapter', () => { setup(() => { adapter = new Adapter(rawAdapter, { extensionFolderPath, id: 'adapter', name: 'myAdapter', version: '1.0.0', publisher: 'vscode', isBuiltin: false, engines: null }, - null, new TestConfigurationService(), null); + new TestConfigurationService(), null); }); teardown(() => { @@ -126,7 +126,7 @@ suite('Debug - Adapter', () => { ' ]', '}'].join('\n'); - return adapter.getInitialConfigurationContent(null).then(content => { + return adapter.getInitialConfigurationContent().then(content => { assert.equal(content, expected); }, err => assert.fail()); }); diff --git a/src/vs/workbench/parts/debug/test/node/debugModel.test.ts b/src/vs/workbench/parts/debug/test/node/debugModel.test.ts index d49226e1749..99ed1b8a150 100644 --- a/src/vs/workbench/parts/debug/test/node/debugModel.test.ts +++ b/src/vs/workbench/parts/debug/test/node/debugModel.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import uri from 'vs/base/common/uri'; import severity from 'vs/base/common/severity'; -import { OutputElement, Model, Process, Expression, OutputNameValueElement, StackFrame, Thread } from 'vs/workbench/parts/debug/common/debugModel'; +import { SimpleReplElement, Model, Process, Expression, RawObjectReplElement, StackFrame, Thread } from 'vs/workbench/parts/debug/common/debugModel'; import * as sinon from 'sinon'; import { MockSession } from 'vs/workbench/parts/debug/test/common/mockDebug'; @@ -150,9 +150,9 @@ suite('Debug - Model', () => { threadId: threadId1, stoppedDetails: { reason: stoppedReason, - threadId: 1 + threadId: 1, + allThreadsStopped: true }, - allThreadsStopped: true }); const process = model.getProcesses().filter(p => p.getId() === rawSession.getId()).pop(); @@ -241,9 +241,9 @@ suite('Debug - Model', () => { threadId: stoppedThreadId, stoppedDetails: { reason: stoppedReason, - threadId: 1 - }, - allThreadsStopped: false + threadId: 1, + allThreadsStopped: false + } }); const process = model.getProcesses().filter(p => p.getId() === rawSession.getId()).pop(); @@ -356,7 +356,7 @@ suite('Debug - Model', () => { model.appendToRepl('third line', severity.Warning); model.appendToRepl('fourth line', severity.Error); - let elements = model.getReplElements(); + let elements = model.getReplElements(); assert.equal(elements.length, 4); assert.equal(elements[0].value, 'first line'); assert.equal(elements[0].severity, severity.Error); @@ -368,14 +368,14 @@ suite('Debug - Model', () => { assert.equal(elements[3].severity, severity.Error); model.appendToRepl('1', severity.Warning); - elements = model.getReplElements(); + elements = model.getReplElements(); assert.equal(elements.length, 5); assert.equal(elements[4].value, '1'); assert.equal(elements[4].severity, severity.Warning); const keyValueObject = { 'key1': 2, 'key2': 'value' }; - model.appendToRepl(new OutputNameValueElement('fake', keyValueObject), null); - const element = model.getReplElements()[5]; + model.appendToRepl(new RawObjectReplElement('fake', keyValueObject), null); + const element = model.getReplElements()[5]; assert.equal(element.value, 'Object'); assert.deepEqual(element.valueObj, keyValueObject); diff --git a/src/vs/workbench/parts/emmet/browser/actions/showEmmetCommands.ts b/src/vs/workbench/parts/emmet/browser/actions/showEmmetCommands.ts index a11c3333fe8..289ca1d5e5b 100644 --- a/src/vs/workbench/parts/emmet/browser/actions/showEmmetCommands.ts +++ b/src/vs/workbench/parts/emmet/browser/actions/showEmmetCommands.ts @@ -16,6 +16,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; const EMMET_COMMANDS_PREFIX = '>Emmet: '; @editorAction +// @ts-ignore @editorAction uses the class class ShowEmmetCommandsAction extends EditorAction { constructor() { diff --git a/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts b/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts index fc9136fce72..02540f66630 100644 --- a/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts +++ b/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts @@ -12,6 +12,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @editorAction +// @ts-ignore @editorAction uses the class class ExpandAbbreviationAction extends EmmetEditorAction { constructor() { diff --git a/src/vs/workbench/parts/emmet/test/electron-browser/emmetAction.test.ts b/src/vs/workbench/parts/emmet/test/electron-browser/emmetAction.test.ts index 7cd89850e85..387beba3f81 100644 --- a/src/vs/workbench/parts/emmet/test/electron-browser/emmetAction.test.ts +++ b/src/vs/workbench/parts/emmet/test/electron-browser/emmetAction.test.ts @@ -16,7 +16,7 @@ import { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; // "name": "Stacks Tests", // "type": "node", // "request": "launch", -// "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", +// "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", // "stopOnEntry": false, // "args": [ // "--timeout", diff --git a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts index f6f5717b865..913c3e87ccf 100644 --- a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts +++ b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts @@ -11,8 +11,9 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IAction, Action } from 'vs/base/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions'; import uri from 'vs/base/common/uri'; import { explorerItemToFileResource } from 'vs/workbench/parts/files/common/files'; @@ -102,7 +103,7 @@ export abstract class AbstractOpenInTerminalAction extends Action { let pathToOpen: string; // Try workspace path first - const root = this.historyService.getLastActiveWorkspaceRoot(); + const root = this.historyService.getLastActiveWorkspaceRoot('file'); pathToOpen = this.resource ? this.resource.fsPath : (root && root.fsPath); // Otherwise check if we have an active file open @@ -182,7 +183,8 @@ export class ExplorerViewerActionContributor extends ActionBarContributor { } public hasSecondaryActions(context: any): boolean { - return !!explorerItemToFileResource(context.element); + const fileResource = explorerItemToFileResource(context.element); + return fileResource && fileResource.resource.scheme === 'file'; } public getSecondaryActions(context: any): IAction[] { @@ -191,7 +193,7 @@ export class ExplorerViewerActionContributor extends ActionBarContributor { // We want the parent unless this resource is a directory if (!fileResource.isDirectory) { - resource = uri.file(paths.dirname(resource.fsPath)); + resource = resources.dirname(resource); } const configuration = this.configurationService.getConfiguration(); diff --git a/src/vs/workbench/parts/execution/test/electron-browser/terminalService.test.ts b/src/vs/workbench/parts/execution/test/electron-browser/terminalService.test.ts index e26b830c9dd..9eb9e7b123e 100644 --- a/src/vs/workbench/parts/execution/test/electron-browser/terminalService.test.ts +++ b/src/vs/workbench/parts/execution/test/electron-browser/terminalService.test.ts @@ -10,9 +10,9 @@ import { WinTerminalService, LinuxTerminalService, MacTerminalService } from 'vs import { DEFAULT_TERMINAL_WINDOWS, DEFAULT_TERMINAL_LINUX_READY, DEFAULT_TERMINAL_OSX } from 'vs/workbench/parts/execution/electron-browser/terminal'; suite('Execution - TerminalService', () => { - let mockOnExit; - let mockOnError; - let mockConfig; + let mockOnExit: Function; + let mockOnError: Function; + let mockConfig: any; setup(() => { mockConfig = { @@ -25,22 +25,22 @@ suite('Execution - TerminalService', () => { } } }; - mockOnExit = s => s; - mockOnError = e => e; + mockOnExit = (s: any) => s; + mockOnError = (e: any) => e; }); test(`WinTerminalService - uses terminal from configuration`, done => { let testShell = 'cmd'; let testCwd = 'path/to/workspace'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert equal(command, testShell, 'shell should equal expected'); equal(args[args.length - 1], mockConfig.terminal.external.windowsExec, 'terminal should equal expected'); equal(opts.cwd, testCwd, 'opts.cwd should equal expected'); done(); return { - on: (evt) => evt + on: (evt: any) => evt }; } }; @@ -59,12 +59,12 @@ suite('Execution - TerminalService', () => { let testShell = 'cmd'; let testCwd = 'path/to/workspace'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert equal(args[args.length - 1], DEFAULT_TERMINAL_WINDOWS, 'terminal should equal expected'); done(); return { - on: (evt) => evt + on: (evt: any) => evt }; } }; @@ -84,12 +84,12 @@ suite('Execution - TerminalService', () => { let testShell = 'cmd'; let testCwd = 'c:/foo'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert equal(opts.cwd, 'C:/foo', 'cwd should be uppercase regardless of the case that\'s passed in'); done(); return { - on: (evt) => evt + on: (evt: any) => evt }; } }; @@ -109,12 +109,12 @@ suite('Execution - TerminalService', () => { mockConfig.terminal.external.windowsExec = 'cmder'; let testCwd = 'c:/foo'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert deepEqual(args, ['C:/foo']); equal(opts, undefined); done(); - return { on: (evt) => evt }; + return { on: (evt: any) => evt }; } }; let testService = new WinTerminalService(mockConfig); @@ -131,12 +131,12 @@ suite('Execution - TerminalService', () => { test(`MacTerminalService - uses terminal from configuration`, done => { let testCwd = 'path/to/workspace'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert equal(args[1], mockConfig.terminal.external.osxExec, 'terminal should equal expected'); done(); return { - on: (evt) => evt + on: (evt: any) => evt }; } }; @@ -153,12 +153,12 @@ suite('Execution - TerminalService', () => { test(`MacTerminalService - uses default terminal when configuration.terminal.external.osxExec is undefined`, done => { let testCwd = 'path/to/workspace'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert equal(args[1], DEFAULT_TERMINAL_OSX, 'terminal should equal expected'); done(); return { - on: (evt) => evt + on: (evt: any) => evt }; } }; @@ -176,13 +176,13 @@ suite('Execution - TerminalService', () => { test(`LinuxTerminalService - uses terminal from configuration`, done => { let testCwd = 'path/to/workspace'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert equal(command, mockConfig.terminal.external.linuxExec, 'terminal should equal expected'); equal(opts.cwd, testCwd, 'opts.cwd should equal expected'); done(); return { - on: (evt) => evt + on: (evt: any) => evt }; } }; @@ -200,12 +200,12 @@ suite('Execution - TerminalService', () => { DEFAULT_TERMINAL_LINUX_READY.then(defaultTerminalLinux => { let testCwd = 'path/to/workspace'; let mockSpawner = { - spawn: (command, args, opts) => { + spawn: (command: any, args: any, opts: any) => { // assert equal(command, defaultTerminalLinux, 'terminal should equal expected'); done(); return { - on: (evt) => evt + on: (evt: any) => evt }; } }; diff --git a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts index c0f2a2a7696..c468fb8b995 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionEditor.ts @@ -17,7 +17,7 @@ import Cache from 'vs/base/common/cache'; import { Action } from 'vs/base/common/actions'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import Severity from 'vs/base/common/severity'; -import { IDisposable, empty, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { Builder } from 'vs/base/browser/builder'; import { domEvent } from 'vs/base/browser/event'; import { append, $, addClass, removeClass, finalHandler, join } from 'vs/base/browser/dom'; @@ -25,13 +25,11 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IExtensionGalleryService, IExtensionManifest, IKeyBinding, IView } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManifest, IKeyBinding, IView, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, IExtensionDependencies } from 'vs/workbench/parts/extensions/common/extensions'; import { Renderer, DataSource, Controller } from 'vs/workbench/parts/extensions/browser/dependenciesViewer'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ITemplateData } from 'vs/workbench/parts/extensions/browser/extensionsList'; import { RatingsWidget, InstallWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets'; import { EditorOptions } from 'vs/workbench/common/editor'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -54,6 +52,7 @@ import { IContextKeyService, RawContextKey, ContextKeyExpr, IContextKey } from ' import { Command, ICommandOptions } from 'vs/editor/common/editorCommonExtensions'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { Color } from 'vs/base/common/color'; /** A context key that is set when an extension editor webview has focus. */ export const KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_FOCUS = new RawContextKey('extensionEditorWebviewFocus', undefined); @@ -162,9 +161,8 @@ export class ExtensionEditor extends BaseEditor { private extensionActionBar: ActionBar; private navbar: NavBar; private content: HTMLElement; - - private _highlight: ITemplateData; - private highlightDisposable: IDisposable; + private recommendation: HTMLElement; + private header: HTMLElement; private extensionReadme: Cache; private extensionChangelog: Cache; @@ -181,8 +179,6 @@ export class ExtensionEditor extends BaseEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, - @IExtensionGalleryService private galleryService: IExtensionGalleryService, - @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService private instantiationService: IInstantiationService, @IViewletService private viewletService: IViewletService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @@ -194,28 +190,27 @@ export class ExtensionEditor extends BaseEditor { @IPartService private partService: IPartService, @IContextViewService private contextViewService: IContextViewService, @IContextKeyService private contextKeyService: IContextKeyService, + @IExtensionTipsService private extensionTipsService: IExtensionTipsService ) { super(ExtensionEditor.ID, telemetryService, themeService); - this._highlight = null; - this.highlightDisposable = empty; this.disposables = []; this.extensionReadme = null; this.extensionChangelog = null; this.extensionManifest = null; this.extensionDependencies = null; - this.contextKey = KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_FOCUS.bindTo(contextKeyService); - this.findInputFocusContextKey = KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(contextKeyService); + this.contextKey = KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_FOCUS.bindTo(this.contextKeyService); + this.findInputFocusContextKey = KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(this.contextKeyService); } createEditor(parent: Builder): void { const container = parent.getHTMLElement(); const root = append(container, $('.extension-editor')); - const header = append(root, $('.header')); + this.header = append(root, $('.header')); - this.icon = append(header, $('img.icon', { draggable: false })); + this.icon = append(this.header, $('img.icon', { draggable: false })); - const details = append(header, $('.details')); + const details = append(this.header, $('.details')); const title = append(details, $('.title')); this.name = append(title, $('span.name.clickable', { title: localize('name', "Extension name") })); this.identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") })); @@ -248,6 +243,8 @@ export class ExtensionEditor extends BaseEditor { }); this.disposables.push(this.extensionActionBar); + this.recommendation = append(details, $('.recommendation')); + chain(fromEventEmitter<{ error?: any; }>(this.extensionActionBar, 'run')) .map(({ error }) => error) .filter(error => !!error) @@ -264,6 +261,13 @@ export class ExtensionEditor extends BaseEditor { this.transientDisposables = dispose(this.transientDisposables); + /* __GDPR__ + "extensionGallery:openExtension" : { + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ this.telemetryService.publicLog('extensionGallery:openExtension', extension.telemetryData); this.extensionReadme = new Cache(() => extension.getReadme()); @@ -281,6 +285,14 @@ export class ExtensionEditor extends BaseEditor { this.publisher.textContent = extension.publisherDisplayName; this.description.textContent = extension.description; + const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); + this.recommendation.textContent = extRecommendations[extension.id.toLowerCase()]; + if (extRecommendations[extension.id.toLowerCase()]) { + addClass(this.header, 'recommended'); + } else { + removeClass(this.header, 'recommended'); + } + if (extension.url) { this.name.onclick = finalHandler(() => window.open(extension.url)); this.rating.onclick = finalHandler(() => window.open(`${extension.url}#review-details`)); @@ -428,7 +440,9 @@ export class ExtensionEditor extends BaseEditor { this.renderSettings(content, manifest, layout), this.renderCommands(content, manifest, layout), this.renderLanguages(content, manifest, layout), - this.renderThemes(content, manifest, layout), + this.renderColorThemes(content, manifest, layout), + this.renderIconThemes(content, manifest, layout), + this.renderColors(content, manifest, layout), this.renderJSONValidation(content, manifest, layout), this.renderDebuggers(content, manifest, layout), this.renderViews(content, manifest, layout) @@ -536,6 +550,8 @@ export class ExtensionEditor extends BaseEditor { return true; } + + private renderDebuggers(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { const contributes = manifest.contributes; const contrib = contributes && contributes.debuggers || []; @@ -587,7 +603,7 @@ export class ExtensionEditor extends BaseEditor { return true; } - private renderThemes(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { + private renderColorThemes(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { const contributes = manifest.contributes; const contrib = contributes && contributes.themes || []; @@ -596,7 +612,7 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('themes', "Themes ({0})", contrib.length)), + $('summary', null, localize('colorThemes', "Color Themes ({0})", contrib.length)), $('ul', null, ...contrib.map(theme => $('li', null, theme.label))) ); @@ -604,6 +620,68 @@ export class ExtensionEditor extends BaseEditor { return true; } + private renderIconThemes(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { + const contributes = manifest.contributes; + const contrib = contributes && contributes.iconThemes || []; + + if (!contrib.length) { + return false; + } + + const details = $('details', { open: true, ontoggle: onDetailsToggle }, + $('summary', null, localize('iconThemes', "Icon Themes ({0})", contrib.length)), + $('ul', null, ...contrib.map(theme => $('li', null, theme.label))) + ); + + append(container, details); + return true; + } + + private renderColors(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { + const contributes = manifest.contributes; + const colors = contributes && contributes.colors; + + if (!colors || !colors.length) { + return false; + } + + function colorPreview(colorReference: string): Node[] { + let result: Node[] = []; + if (colorReference && colorReference[0] === '#') { + let color = Color.fromHex(colorReference); + if (color) { + result.push($('span', { class: 'colorBox', style: 'background-color: ' + Color.Format.CSS.format(color) }, '')); + } + } + result.push($('code', null, colorReference)); + return result; + } + + const details = $('details', { open: true, ontoggle: onDetailsToggle }, + $('summary', null, localize('colors', "Colors ({0})", colors.length)), + $('table', null, + $('tr', null, + $('th', null, localize('colorId', "Id")), + $('th', null, localize('description', "Description")), + $('th', null, localize('defaultDark', "Dark Default")), + $('th', null, localize('defaultLight', "Light Default")), + $('th', null, localize('defaultHC', "High Contrast Default")) + ), + ...colors.map(color => $('tr', null, + $('td', null, $('code', null, color.id)), + $('td', null, color.description), + $('td', null, ...colorPreview(color.defaults.dark)), + $('td', null, ...colorPreview(color.defaults.light)), + $('td', null, ...colorPreview(color.defaults.highContrast)) + )) + ) + ); + + append(container, details); + return true; + } + + private renderJSONValidation(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { const contributes = manifest.contributes; const contrib = contributes && contributes.jsonValidation || []; @@ -809,7 +887,6 @@ export class ExtensionEditor extends BaseEditor { } dispose(): void { - this._highlight = null; this.transientDisposables = dispose(this.transientDisposables); this.disposables = dispose(this.disposables); super.dispose(); @@ -841,22 +918,6 @@ const showCommand = new ShowExtensionEditorFindCommand({ }); KeybindingsRegistry.registerCommandAndKeybindingRule(showCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); -class HideExtensionEditorFindCommand extends Command { - public runCommand(accessor: ServicesAccessor, args: any): void { - const extensionEditor = this.getExtensionEditor(accessor); - if (extensionEditor) { - extensionEditor.hideFind(); - } - } - - private getExtensionEditor(accessor: ServicesAccessor): ExtensionEditor { - const activeEditor = accessor.get(IWorkbenchEditorService).getActiveEditor() as ExtensionEditor; - if (activeEditor instanceof ExtensionEditor) { - return activeEditor; - } - return null; - } -} const hideCommand = new ShowExtensionEditorFindCommand({ id: 'editor.action.extensioneditor.hidefind', precondition: KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_FOCUS, diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 7251ddc6149..b4a731de182 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -9,15 +9,15 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IAction, Action } from 'vs/base/common/actions'; import { Throttler } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; -import severity from 'vs/base/common/severity'; import paths = require('vs/base/common/paths'); import Event from 'vs/base/common/event'; +import * as json from 'vs/base/common/json'; import { ActionItem, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/parts/extensions/common/extensions'; +import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extensions/common/extensionsFileTemplate'; -import { LocalExtensionType, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { LocalExtensionType, IExtensionEnablementService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -25,16 +25,22 @@ import { ToggleViewletAction } from 'vs/workbench/browser/viewlet'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IFileService, IContent } from 'vs/platform/files/common/files'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IExtensionService, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import URI from 'vs/base/common/uri'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, registerColor, foreground } from 'vs/platform/theme/common/colorRegistry'; import { Color } from 'vs/base/common/color'; +import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; +import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; +import Severity from 'vs/base/common/severity'; +import { PagedModel } from 'vs/base/common/paging'; export class InstallAction extends Action { @@ -71,13 +77,16 @@ export class InstallAction extends Action { if (this.extension.state === ExtensionState.Installing) { this.label = InstallAction.InstallingLabel; this.class = InstallAction.InstallingClass; + this.tooltip = InstallAction.InstallingLabel; } else { this.label = InstallAction.InstallLabel; this.class = InstallAction.Class; + this.tooltip = InstallAction.InstallLabel; } } run(): TPromise { + this.extensionsWorkbenchService.open(this.extension); return this.extensionsWorkbenchService.install(this.extension); } @@ -101,9 +110,7 @@ export class UninstallAction extends Action { set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor( - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IMessageService private messageService: IMessageService, - @IInstantiationService private instantiationService: IInstantiationService + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super('extensions.uninstall', UninstallAction.UninstallLabel, UninstallAction.UninstallClass, false); @@ -190,22 +197,27 @@ export class CombinedInstallAction extends Action { this.enabled = true; this.label = this.installAction.label; this.class = this.installAction.class; + this.tooltip = this.installAction.tooltip; } else if (this.uninstallAction.enabled) { this.enabled = true; this.label = this.uninstallAction.label; this.class = this.uninstallAction.class; + this.tooltip = this.uninstallAction.tooltip; } else if (this.extension.state === ExtensionState.Installing) { this.enabled = false; this.label = this.installAction.label; this.class = this.installAction.class; + this.tooltip = this.installAction.tooltip; } else if (this.extension.state === ExtensionState.Uninstalling) { this.enabled = false; this.label = this.uninstallAction.label; this.class = this.uninstallAction.class; + this.tooltip = this.uninstallAction.tooltip; } else { this.enabled = false; this.label = this.installAction.label; this.class = this.installAction.class; + this.tooltip = this.installAction.tooltip; } } @@ -349,9 +361,7 @@ export class ManageExtensionAction extends Action { set extension(extension: IExtension) { this._extension = extension; this._actionItem.extension = extension; this.update(); } constructor( - @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, @IInstantiationService private instantiationService: IInstantiationService ) { super(ManageExtensionAction.ID); @@ -412,19 +422,19 @@ export class EnableForWorkspaceAction extends Action implements IExtensionAction constructor(label: string, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, - @IInstantiationService private instantiationService: IInstantiationService + @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(EnableForWorkspaceAction.ID, label); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); + this.disposables.push(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update())); this.update(); } private update(): void { this.enabled = false; if (this.extension) { - this.enabled = !this.extension.disabledGlobally && this.extension.disabledForWorkspace && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = !this.extension.disabledGlobally && this.extension.disabledForWorkspace && this.extensionEnablementService.canEnable(this.extension); } } @@ -451,8 +461,7 @@ export class EnableGloballyAction extends Action implements IExtensionAction { constructor(label: string, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, - @IInstantiationService private instantiationService: IInstantiationService + @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService ) { super(EnableGloballyAction.ID, label); @@ -463,7 +472,7 @@ export class EnableGloballyAction extends Action implements IExtensionAction { private update(): void { this.enabled = false; if (this.extension) { - this.enabled = this.extension.disabledGlobally && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = this.extension.disabledGlobally && this.extensionEnablementService.canEnable(this.extension); } } @@ -519,7 +528,7 @@ export class EnableAction extends Action { return; } - this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.disabledGlobally || this.extension.disabledForWorkspace) && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.disabledGlobally || this.extension.disabledForWorkspace) && this.extensionEnablementService.canEnable(this.extension); this.class = this.enabled ? EnableAction.EnabledClass : EnableAction.DisabledClass; } @@ -548,18 +557,18 @@ export class DisableForWorkspaceAction extends Action implements IExtensionActio constructor(label: string, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IInstantiationService private instantiationService: IInstantiationService + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(DisableForWorkspaceAction.ID, label); this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); } private update(): void { this.enabled = false; - if (this.extension && this.workspaceContextService.hasWorkspace()) { + if (this.extension && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { this.enabled = this.extension.type !== LocalExtensionType.System && !this.extension.disabledGlobally && !this.extension.disabledForWorkspace; } } @@ -586,8 +595,7 @@ export class DisableGloballyAction extends Action implements IExtensionAction { set extension(extension: IExtension) { this._extension = extension; this.update(); } constructor(label: string, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IInstantiationService private instantiationService: IInstantiationService + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(DisableGloballyAction.ID, label); @@ -691,20 +699,19 @@ export class ToggleAutoUpdateAction extends Action { id: string, label: string, private autoUpdateValue: boolean, - @IConfigurationService configurationService: IConfigurationService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label, '', true); this.updateEnablement(); - configurationService.onDidUpdateConfiguration(() => this.updateEnablement()); + configurationService.onDidChangeConfiguration(() => this.updateEnablement()); } private updateEnablement(): void { - this.enabled = this.extensionsWorkbenchService.isAutoUpdateEnabled !== this.autoUpdateValue; + this.enabled = this.configurationService.getValue(AutoUpdateConfigurationKey) !== this.autoUpdateValue; } run(): TPromise { - return this.extensionsWorkbenchService.setAutoUpdate(this.autoUpdateValue); + return this.configurationService.updateValue(AutoUpdateConfigurationKey, this.autoUpdateValue); } } @@ -716,10 +723,9 @@ export class EnableAutoUpdateAction extends ToggleAutoUpdateAction { constructor( id = EnableAutoUpdateAction.ID, label = EnableAutoUpdateAction.LABEL, - @IConfigurationService configurationService: IConfigurationService, - @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService + @IConfigurationService configurationService: IConfigurationService ) { - super(id, label, true, configurationService, extensionsWorkbenchService); + super(id, label, true, configurationService); } } @@ -731,10 +737,9 @@ export class DisableAutoUpdateAction extends ToggleAutoUpdateAction { constructor( id = EnableAutoUpdateAction.ID, label = EnableAutoUpdateAction.LABEL, - @IConfigurationService configurationService: IConfigurationService, - @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService + @IConfigurationService configurationService: IConfigurationService ) { - super(id, label, false, configurationService, extensionsWorkbenchService); + super(id, label, false, configurationService); } } @@ -789,7 +794,6 @@ export class ReloadAction extends Action { constructor( @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IMessageService private messageService: IMessageService, @IWindowService private windowService: IWindowService, @IExtensionService private extensionService: IExtensionService ) { @@ -865,10 +869,7 @@ export class ReloadAction extends Action { } run(): TPromise { - if (this.messageService.confirm({ message: this.reloadMessaage, type: 'question', primaryButton: localize('reload', "&&Reload Window") })) { - return this.windowService.reloadWindow(); - } - return TPromise.wrap(null); + return this.windowService.reloadWindow(); } } @@ -900,8 +901,7 @@ export class ShowEnabledExtensionsAction extends Action { constructor( id: string, label: string, - @IViewletService private viewletService: IViewletService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService + @IViewletService private viewletService: IViewletService ) { super(id, label, 'clear-extensions', true); } @@ -924,8 +924,7 @@ export class ShowInstalledExtensionsAction extends Action { constructor( id: string, label: string, - @IViewletService private viewletService: IViewletService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService + @IViewletService private viewletService: IViewletService ) { super(id, label, 'clear-extensions', true); } @@ -948,8 +947,7 @@ export class ShowDisabledExtensionsAction extends Action { constructor( id: string, label: string, - @IViewletService private viewletService: IViewletService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService + @IViewletService private viewletService: IViewletService ) { super(id, label, 'null', true); } @@ -975,8 +973,7 @@ export class ClearExtensionsInputAction extends Action { id: string, label: string, onSearchChange: Event, - @IViewletService private viewletService: IViewletService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService + @IViewletService private viewletService: IViewletService ) { super(id, label, 'clear-extensions', true); this.enabled = false; @@ -1082,34 +1079,134 @@ export class ShowRecommendedExtensionsAction extends Action { } } -export class ShowWorkspaceRecommendedExtensionsAction extends Action { +export class InstallWorkspaceRecommendedExtensionsAction extends Action { - static ID = 'workbench.extensions.action.showWorkspaceRecommendedExtensions'; - static LABEL = localize('showWorkspaceRecommendedExtensions', "Show Workspace Recommended Extensions"); + static ID = 'workbench.extensions.action.installWorkspaceRecommendedExtensions'; + static LABEL = localize('installWorkspaceRecommendedExtensions', "Install All Workspace Recommended Extensions"); + + private disposables: IDisposable[] = []; constructor( - id: string, - label: string, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IViewletService private viewletService: IViewletService + id: string = InstallWorkspaceRecommendedExtensionsAction.ID, + label: string = InstallWorkspaceRecommendedExtensionsAction.LABEL, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IViewletService private viewletService: IViewletService, + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionTipsService private extensionTipsService: IExtensionTipsService, + @IMessageService private messageService: IMessageService ) { - super(id, label, null, contextService.hasWorkspace()); + super(id, label, 'extension-action'); + this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables); + this.contextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); } - run(): TPromise { + private update(): void { + this.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY; + if (this.enabled) { + this.extensionTipsService.getWorkspaceRecommendations().then(names => { + const installed = this.extensionsWorkbenchService.local.map(x => x.id.toLowerCase()); + this.enabled = names.some(x => installed.indexOf(x.toLowerCase()) === -1); + }); + } + } + + run(): TPromise { + return this.extensionTipsService.getWorkspaceRecommendations().then(names => { + const installed = this.extensionsWorkbenchService.local.map(x => x.id.toLowerCase()); + const toInstall = names.filter(x => installed.indexOf(x.toLowerCase()) === -1); + + return this.viewletService.openViewlet(VIEWLET_ID, true) + .then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => { + if (!toInstall.length) { + this.enabled = false; + this.messageService.show(Severity.Info, localize('allExtensionsInstalled', "All extensions recommended for this workspace have already been installed")); + viewlet.focus(); + return TPromise.as(null); + } + + viewlet.search('@recommended'); + viewlet.focus(); + + return this.extensionsWorkbenchService.queryGallery({ names: toInstall, source: 'install-all-workspace-recommendations' }).then(pager => { + let installPromises = []; + let model = new PagedModel(pager); + let extensionsWithDependencies = []; + for (let i = 0; i < pager.total; i++) { + installPromises.push(model.resolve(i).then(e => { + if (e.dependencies && e.dependencies.length > 0) { + extensionsWithDependencies.push(e); + return TPromise.as(null); + } else { + return this.extensionsWorkbenchService.install(e); + } + })); + } + return TPromise.join(installPromises).then(() => { + return TPromise.join(extensionsWithDependencies.map(e => this.extensionsWorkbenchService.install(e))); + }); + }); + }); + }); + } + + protected isEnabled(): boolean { + return this.enabled; + } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } +} + +export class InstallRecommendedExtensionAction extends Action { + + static ID = 'workbench.extensions.action.installRecommendedExtension'; + static LABEL = localize('installRecommendedExtension', "Install Recommended Extension"); + + private extensionId: string; + + constructor( + extensionId: string, + @IViewletService private viewletService: IViewletService, + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, + @IMessageService private messageService: IMessageService + ) { + super(InstallRecommendedExtensionAction.ID, InstallRecommendedExtensionAction.LABEL, null); + this.extensionId = extensionId; + } + + run(): TPromise { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { - viewlet.search('@recommended:workspace '); + if (this.extensionsWorkbenchService.local.some(x => x.id.toLowerCase() === this.extensionId.toLowerCase())) { + this.enabled = false; + this.messageService.show(Severity.Info, localize('extensionInstalled', "The recommended extension has already been installed")); + viewlet.focus(); + return TPromise.as(null); + } + + viewlet.search('@recommended'); viewlet.focus(); + + return this.extensionsWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation' }).then(pager => { + return (pager && pager.firstPage && pager.firstPage.length) ? this.extensionsWorkbenchService.install(pager.firstPage[0]) : TPromise.as(null); + }); }); } protected isEnabled(): boolean { - return true; + return !this.extensionsWorkbenchService.local.some(x => x.id.toLowerCase() === this.extensionId.toLowerCase()); + } + + dispose(): void { + super.dispose(); } } + export class ShowRecommendedKeymapExtensionsAction extends Action { static ID = 'workbench.extensions.action.showRecommendedKeymapExtensions'; @@ -1237,47 +1334,82 @@ export class ChangeSortAction extends Action { } } -export class ConfigureWorkspaceRecommendedExtensionsAction extends Action { +interface IExtensionsContent { + recommendations: string[]; +} - static ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions'; - static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)"); +export abstract class AbstractConfigureRecommendedExtensionsAction extends Action { constructor( id: string, label: string, + @IWorkspaceContextService protected contextService: IWorkspaceContextService, @IFileService private fileService: IFileService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IExtensionsWorkbenchService private extensionsService: IExtensionsWorkbenchService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IMessageService private messageService: IMessageService + @IJSONEditingService private jsonEditingService: IJSONEditingService, + @ITextModelService private textModelResolverService: ITextModelService ) { - super(id, label, null, contextService.hasWorkspace()); + super(id, label, null); } - public run(event: any): TPromise { - return this.openExtensionsFile(); + protected openExtensionsFile(extensionsFileResource: URI): TPromise { + return this.getOrCreateExtensionsFile(extensionsFileResource) + .then(({ created }) => { + return this.editorService.openEditor({ + resource: extensionsFileResource, + options: { + forceOpen: true, + pinned: created + }, + }); + }, error => TPromise.wrapError(new Error(localize('OpenExtensionsFile.failed', "Unable to create 'extensions.json' file inside the '.vscode' folder ({0}).", error)))); } - private openExtensionsFile(): TPromise { - if (!this.contextService.hasWorkspace()) { - this.messageService.show(severity.Info, localize('ConfigureWorkspaceRecommendations.noWorkspace', 'Recommendations are only available on a workspace folder.')); - return TPromise.as(undefined); - } - - return this.getOrCreateExtensionsFile().then(value => { - return this.editorService.openEditor({ - resource: value.extensionsFileResource, + protected openWorkspaceConfigurationFile(workspaceConfigurationFile: URI): TPromise { + return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile) + .then(content => this.getSelectionPosition(content)) + .then(selection => this.editorService.openEditor({ + resource: workspaceConfigurationFile, options: { forceOpen: true, - pinned: value.created - }, - }); - }, (error) => TPromise.wrapError(new Error(localize('OpenExtensionsFile.failed', "Unable to create 'extensions.json' file inside the '.vscode' folder ({0}).", error)))); + selection + } + })); } - private getOrCreateExtensionsFile(): TPromise<{ created: boolean, extensionsFileResource: URI }> { - const extensionsFileResource = URI.file(paths.join(this.contextService.getLegacyWorkspace().resource.fsPath, '.vscode', 'extensions.json')); // TODO@Sandeep (https://github.com/Microsoft/vscode/issues/29242) + private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): TPromise { + return this.fileService.resolveContent(workspaceConfigurationFile) + .then(content => { + const workspaceRecommendations = json.parse(content.value)['extensions']; + if (!workspaceRecommendations || !workspaceRecommendations.recommendations) { + return this.jsonEditingService.write(workspaceConfigurationFile, { key: 'extensions', value: { recommendations: [] } }, true) + .then(() => this.fileService.resolveContent(workspaceConfigurationFile)); + } + return content; + }); + } + private getSelectionPosition(content: IContent): TPromise { + const tree = json.parseTree(content.value); + const node = json.findNodeAtLocation(tree, ['extensions', 'recommendations']); + if (node && node.parent.children[1]) { + const offset = node.parent.children[1].offset; + return this.textModelResolverService.createModelReference(content.resource) + .then(reference => { + const position = reference.object.textEditorModel.getPositionAt(offset); + reference.dispose(); + return { + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: position.lineNumber, + endColumn: position.column, + }; + }); + } + return TPromise.as(null); + } + + private getOrCreateExtensionsFile(extensionsFileResource: URI): TPromise<{ created: boolean, extensionsFileResource: URI }> { return this.fileService.resolveContent(extensionsFileResource).then(content => { return { created: false, extensionsFileResource }; }, err => { @@ -1288,6 +1420,91 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends Action { } } +export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction { + + static ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions'; + static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)"); + + private disposables: IDisposable[] = []; + + constructor( + id: string, + label: string, + @IFileService fileService: IFileService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IJSONEditingService jsonEditingService: IJSONEditingService, + @ITextModelService textModelResolverService: ITextModelService + ) { + super(id, label, contextService, fileService, editorService, jsonEditingService, textModelResolverService); + this.contextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); + this.update(); + } + + private update(): void { + this.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY; + } + + public run(event: any): TPromise { + switch (this.contextService.getWorkbenchState()) { + case WorkbenchState.FOLDER: + return this.openExtensionsFile(this.contextService.getWorkspace().folders[0].toResource(paths.join('.vscode', 'extensions.json'))); + case WorkbenchState.WORKSPACE: + return this.openWorkspaceConfigurationFile(this.contextService.getWorkspace().configuration); + } + return TPromise.as(null); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } +} + +export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction { + + static ID = 'workbench.extensions.action.configureWorkspaceFolderRecommendedExtensions'; + static LABEL = localize('configureWorkspaceFolderRecommendedExtensions', "Configure Recommended Extensions (Workspace Folder)"); + + private disposables: IDisposable[] = []; + + constructor( + id: string, + label: string, + @IFileService fileService: IFileService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IJSONEditingService jsonEditingService: IJSONEditingService, + @ITextModelService textModelResolverService: ITextModelService, + @ICommandService private commandService: ICommandService + ) { + super(id, label, contextService, fileService, editorService, jsonEditingService, textModelResolverService); + this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this, this.disposables); + this.update(); + } + + private update(): void { + this.enabled = this.contextService.getWorkspace().folders.length > 0; + } + + public run(): TPromise { + const folderCount = this.contextService.getWorkspace().folders.length; + const pickFolderPromise = folderCount === 1 ? TPromise.as(this.contextService.getWorkspace().folders[0]) : this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND); + return pickFolderPromise + .then(workspaceFolder => { + if (workspaceFolder) { + return this.openExtensionsFile(workspaceFolder.toResource(paths.join('.vscode', 'extensions.json'))); + } + return null; + }); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } +} + export class BuiltinStatusLabelAction extends Action { private static Class = 'extension-action built-in-status'; @@ -1322,8 +1539,7 @@ export class DisableAllAction extends Action { constructor( id: string = DisableAllAction.ID, label: string = DisableAllAction.LABEL, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(id, label); this.update(); @@ -1354,16 +1570,16 @@ export class DisableAllWorkpsaceAction extends Action { constructor( id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { super(id, label); this.update(); - this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); + this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables); } private update(): void { - this.enabled = this.workspaceContextService.hasWorkspace() && this.extensionsWorkbenchService.local.some(e => e.type === LocalExtensionType.User && !e.disabledForWorkspace && !e.disabledGlobally); + this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => e.type === LocalExtensionType.User && !e.disabledForWorkspace && !e.disabledGlobally); } run(): TPromise { @@ -1394,7 +1610,7 @@ export class EnableAllAction extends Action { } private update(): void { - this.enabled = this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.id) && e.disabledGlobally); + this.enabled = this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e) && e.disabledGlobally); } run(): TPromise { @@ -1422,11 +1638,12 @@ export class EnableAllWorkpsaceAction extends Action { ) { super(id, label); this.update(); - this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); + this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); } private update(): void { - this.enabled = this.workspaceContextService.hasWorkspace() && this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.id) && !e.disabledGlobally && e.disabledForWorkspace); + this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e) && !e.disabledGlobally && e.disabledForWorkspace); } run(): TPromise { diff --git a/src/vs/workbench/parts/extensions/browser/extensionsList.ts b/src/vs/workbench/parts/extensions/browser/extensionsList.ts index 8a9c326d6a6..24eacaef0a0 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsList.ts @@ -16,12 +16,13 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { once } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IExtension, IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions'; -import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ManageExtensionAction, ReloadAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; +import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ManageExtensionAction, ReloadAction, extensionButtonProminentBackground } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { Label, RatingsWidget, InstallWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets'; import { EventType } from 'vs/base/common/events'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; export interface ITemplateData { root: HTMLElement; @@ -48,15 +49,25 @@ export class Renderer implements IPagedRenderer { constructor( @IInstantiationService private instantiationService: IInstantiationService, - @IContextMenuService private contextMenuService: IContextMenuService, @IMessageService private messageService: IMessageService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionService private extensionService: IExtensionService + @IExtensionService private extensionService: IExtensionService, + @IExtensionTipsService private extensionTipsService: IExtensionTipsService, + @IThemeService private themeService: IThemeService ) { } get templateId() { return 'extension'; } renderTemplate(root: HTMLElement): ITemplateData { + const bookmark = append(root, $('span.bookmark')); + append(bookmark, $('span.octicon.octicon-star')); + const applyBookmarkStyle = (theme) => { + const borderColor = theme.getColor(extensionButtonProminentBackground); + bookmark.style.borderTopColor = borderColor ? borderColor.toString() : 'transparent'; + }; + applyBookmarkStyle(this.themeService.getTheme()); + const bookmarkStyler = this.themeService.onThemeChange(applyBookmarkStyle.bind(this)); + const element = append(root, $('.extension')); const icon = append(element, $('img.icon')); const details = append(element, $('.details')); @@ -91,7 +102,7 @@ export class Renderer implements IPagedRenderer { const manageAction = this.instantiationService.createInstance(ManageExtensionAction); actionbar.push([reloadAction, updateAction, installAction, builtinStatusAction, manageAction], actionOptions); - const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, updateAction, reloadAction, manageAction, actionbar]; + const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, updateAction, reloadAction, manageAction, actionbar, bookmarkStyler]; return { root, element, icon, name, installCount, ratings, author, description, disposables, @@ -127,10 +138,11 @@ export class Renderer implements IPagedRenderer { removeClass(data.element, 'loading'); data.extensionDisposables = dispose(data.extensionDisposables); + const isInstalled = this.extensionsWorkbenchService.local.some(e => e.id === extension.id); this.extensionService.getExtensions().then(enabledExtensions => { const isExtensionRunning = enabledExtensions.some(e => areSameExtensions(e, extension)); - const isInstalled = this.extensionsWorkbenchService.local.some(e => e.id === extension.id); + toggleClass(data.element, 'disabled', isInstalled && !isExtensionRunning); }); @@ -146,6 +158,15 @@ export class Renderer implements IPagedRenderer { } data.root.setAttribute('aria-label', extension.displayName); + removeClass(data.root, 'recommended'); + + const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); + if (extRecommendations[extension.id.toLowerCase()]) { + data.root.setAttribute('aria-label', extension.displayName + '. ' + extRecommendations[extension.id]); + addClass(data.root, 'recommended'); + data.root.title = extRecommendations[extension.id.toLowerCase()]; + } + data.name.textContent = extension.displayName; data.author.textContent = extension.publisherDisplayName; data.description.textContent = extension.description; diff --git a/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts b/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts index 7f99ba447e9..e2af2e4e734 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsQuickOpen.ts @@ -10,6 +10,7 @@ import { QuickOpenEntry, QuickOpenModel } from 'vs/base/parts/quickopen/browser/ import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; import { IExtensionsViewlet, VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; class SimpleEntry extends QuickOpenEntry { @@ -38,6 +39,8 @@ class SimpleEntry extends QuickOpenEntry { export class ExtensionsHandler extends QuickOpenHandler { + public static readonly ID = 'workbench.picker.extensions'; + constructor( @IViewletService private viewletService: IViewletService) { super(); } @@ -67,11 +70,43 @@ export class ExtensionsHandler extends QuickOpenHandler { export class GalleryExtensionsHandler extends QuickOpenHandler { - constructor( @IViewletService private viewletService: IViewletService) { + public static readonly ID = 'workbench.picker.gallery'; + + constructor( + @IViewletService private viewletService: IViewletService, + @IExtensionGalleryService private galleryService: IExtensionGalleryService, + @IExtensionManagementService private extensionsService: IExtensionManagementService + ) { super(); } getResults(text: string): TPromise> { + if (/\./.test(text)) { + return this.galleryService.query({ names: [text], pageSize: 1 }) + .then(galleryResult => { + const entries: SimpleEntry[] = []; + const galleryExtension = galleryResult.firstPage[0]; + + if (!galleryExtension) { + const label = nls.localize('notfound', "Extension '{0}' not found in the Marketplace.", text); + entries.push(new SimpleEntry(label, () => null)); + + } else { + const label = nls.localize('install', "Press Enter to install '{0}' from the Marketplace.", text); + const action = () => { + return this.viewletService.openViewlet(VIEWLET_ID, true) + .then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => viewlet.search(`@id:${text}`)) + .done(() => this.extensionsService.installFromGallery(galleryExtension)); + }; + + entries.push(new SimpleEntry(label, action)); + } + + return new QuickOpenModel(entries); + }); + } + const entries: SimpleEntry[] = []; if (text) { diff --git a/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css index 92ccbbde320..424f575504b 100644 --- a/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/browser/media/extensionEditor.css @@ -21,6 +21,10 @@ font-size: 14px; } +.extension-editor > .header.recommended { + height: 140px; +} + .extension-editor > .header > .icon { height: 128px; width: 128px; @@ -59,7 +63,7 @@ } .extension-editor > .header > .details > .subtitle { - padding-top: 10px; + padding-top: 6px; white-space: nowrap; height: 20px; line-height: 20px; @@ -81,14 +85,14 @@ } .extension-editor > .header > .details > .description { - margin-top: 14px; + margin-top: 10px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .extension-editor > .header > .details > .actions { - margin-top: 14px; + margin-top: 10px; } .extension-editor > .header > .details > .actions > .monaco-action-bar { @@ -104,6 +108,16 @@ padding: 1px 6px; } +.extension-editor > .header.recommended > .details > .recommendation { + display: none; +} + +.extension-editor > .header.recommended > .details > .recommendation { + display: block; + margin-top: 10px; + font-size: 13px; +} + .extension-editor > .body { height: calc(100% - 168px); overflow: hidden; @@ -223,6 +237,23 @@ padding: 1px 4px; } +.extension-editor > .body > .content table .colorBox { + box-sizing: border-box; + width: 0.8em; + height: 0.8em; + display: inline-block; + border-width: 0.1em; + border-style: solid; + border-color: rgb(0, 0, 0); + margin: 0em 0.2em; + vertical-align: middle; +} + +.vs-dark .extension-editor > .body > .content table .colorBox, +.hc-black .extension-editor > .body > .content table .colorBox { + border-color: rgb(238, 238, 238); +} + .extension-editor .subcontent .monaco-tree-row .content .unknown-dependency { line-height: 62px; } diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index 788e1135a2a..3327da7f2c9 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -29,6 +29,7 @@ export interface IExtension { name: string; displayName: string; id: string; + uuid: string; publisher: string; publisherDisplayName: string; version: string; @@ -67,7 +68,6 @@ export interface IExtensionsWorkbenchService { _serviceBrand: any; onChange: Event; local: IExtension[]; - isAutoUpdateEnabled: boolean; queryLocal(): TPromise; queryGallery(options?: IQueryOptions): TPromise>; canInstall(extension: IExtension): boolean; @@ -78,11 +78,11 @@ export interface IExtensionsWorkbenchService { loadDependencies(extension: IExtension): TPromise; open(extension: IExtension, sideByside?: boolean): TPromise; checkForUpdates(): TPromise; - setAutoUpdate(autoUpdate: boolean): TPromise; allowedBadgeProviders: string[]; } export const ConfigurationKey = 'extensions'; +export const AutoUpdateConfigurationKey = 'extensions.autoUpdate'; export interface IExtensionsConfiguration { autoUpdate: boolean; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 75ef396df9d..3f49d969024 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; import { forEach } from 'vs/base/common/collections'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { match } from 'vs/base/common/glob'; import * as json from 'vs/base/common/json'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, LocalExtensionType, EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -17,17 +17,17 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import product from 'vs/platform/node/product'; import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; +import { ShowRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction, InstallRecommendedExtensionAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import Severity from 'vs/base/common/severity'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspaceFolder, IWorkspace, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { Schemas } from 'vs/base/common/network'; import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import * as cp from 'child_process'; -import { distinct } from 'vs/base/common/arrays'; +import * as pfs from 'vs/base/node/pfs'; +import * as os from 'os'; +import { flatten, distinct } from 'vs/base/common/arrays'; interface IExtensionsContent { recommendations: string[]; @@ -36,18 +36,20 @@ interface IExtensionsContent { const empty: { [key: string]: any; } = Object.create(null); const milliSecondsInADay = 1000 * 60 * 60 * 24; -export class ExtensionTipsService implements IExtensionTipsService { +export class ExtensionTipsService extends Disposable implements IExtensionTipsService { _serviceBrand: any; private _fileBasedRecommendations: { [id: string]: number; } = Object.create(null); - private _exeBasedRecommendations: string[] = []; + private _exeBasedRecommendations: { [id: string]: string; } = Object.create(null); private _availableRecommendations: { [pattern: string]: string[] } = Object.create(null); private importantRecommendations: { [id: string]: { name: string; pattern: string; } } = Object.create(null); private importantRecommendationsIgnoreList: string[]; - private _allRecommendations: string[]; + private _allRecommendations: string[] = []; private _disposables: IDisposable[] = []; + private _allWorkspaceRecommendedExtensions: string[] = []; + constructor( @IExtensionGalleryService private _galleryService: IExtensionGalleryService, @IModelService private _modelService: IModelService, @@ -58,61 +60,104 @@ export class ExtensionTipsService implements IExtensionTipsService { @IFileService private fileService: IFileService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService ) { + super(); + if (!this._galleryService.isEnabled()) { return; } + this._suggestTips(); this._suggestWorkspaceRecommendations(); - this._suggestBasedOnExecutables(); + + // Executable based recommendations carry out a lot of file stats, so run them after 10 secs + // So that the startup is not affected + setTimeout(() => this._suggestBasedOnExecutables(this._exeBasedRecommendations), 10000); + this._register(this.contextService.onDidChangeWorkspaceFolders(e => this.onWorkspaceFoldersChanged(e))); + } + + getAllRecommendationsWithReason(): { [id: string]: string; } { + let output: { [id: string]: string; } = Object.create(null); + Object.keys(this._fileBasedRecommendations).forEach(x => output[x.toLowerCase()] = localize('fileBasedRecommendation', "This extension is recommended based on the files you recently opened.")); + this._allWorkspaceRecommendedExtensions.forEach(x => output[x.toLowerCase()] = localize('workspaceRecommendation', "This extension is recommended by users of the current workspace.")); + forEach(this._exeBasedRecommendations, entry => output[entry.key.toLowerCase()] = localize('exeBasedRecommendation', "This extension is recommended because you have {0} installed.", entry.value)); + return output; } getWorkspaceRecommendations(): TPromise { - if (!this.contextService.hasWorkspace()) { - return TPromise.as([]); + const workspace = this.contextService.getWorkspace(); + return TPromise.join([this.resolveWorkspaceRecommendations(workspace), ...workspace.folders.map(workspaceFolder => this.resolveWorkspaceFolderRecommendations(workspaceFolder))]) + .then(recommendations => { + this._allWorkspaceRecommendedExtensions = distinct(flatten(recommendations)); + return this._allWorkspaceRecommendedExtensions; + }); + } + + private resolveWorkspaceRecommendations(workspace: IWorkspace): TPromise { + if (workspace.configuration) { + return this.fileService.resolveContent(workspace.configuration) + .then(content => this.processWorkspaceRecommendations(json.parse(content.value, [])['extensions']), err => []); } - return this.fileService.resolveContent(this.contextService.toResource(paths.join('.vscode', 'extensions.json'))).then(content => { //TODO@Sandeep (https://github.com/Microsoft/vscode/issues/29242) - const extensionsContent = json.parse(content.value, []); - if (extensionsContent.recommendations) { - const regEx = new RegExp(EXTENSION_IDENTIFIER_PATTERN); - return extensionsContent.recommendations.filter((element, position) => { - return extensionsContent.recommendations.indexOf(element) === position && regEx.test(element); + return TPromise.as([]); + } + + private resolveWorkspaceFolderRecommendations(workspaceFolder: IWorkspaceFolder): TPromise { + return this.fileService.resolveContent(workspaceFolder.toResource(paths.join('.vscode', 'extensions.json'))) + .then(content => this.processWorkspaceRecommendations(json.parse(content.value, [])), err => []); + } + + private processWorkspaceRecommendations(extensionsContent: IExtensionsContent): string[] { + if (extensionsContent && extensionsContent.recommendations) { + const regEx = new RegExp(EXTENSION_IDENTIFIER_PATTERN); + return extensionsContent.recommendations.filter((element, position) => { + return extensionsContent.recommendations.indexOf(element) === position && regEx.test(element); + }); + } + return []; + } + + private onWorkspaceFoldersChanged(event: IWorkspaceFoldersChangeEvent): void { + if (event.added.length) { + TPromise.join(event.added.map(workspaceFolder => this.resolveWorkspaceFolderRecommendations(workspaceFolder))) + .then(result => { + const newRecommendations = flatten(result); + // Suggest only if atleast one of the newly added recommendtations was not suggested before + if (newRecommendations.some(e => this._allWorkspaceRecommendedExtensions.indexOf(e) === -1)) { + this._suggestWorkspaceRecommendations(); + } }); - } - return []; - }, err => []); + } } - getRecommendations(): string[] { - const allRecomendations = this._getAllRecommendationsInProduct(); + getFileBasedRecommendations(): string[] { const fileBased = Object.keys(this._fileBasedRecommendations) - .filter(recommendation => allRecomendations.indexOf(recommendation) !== -1); - - const exeBased = distinct(this._exeBasedRecommendations); - - this.telemetryService.publicLog('extensionRecommendations:unfiltered', { fileBased, exeBased }); - - return distinct([...fileBased, ...exeBased]); + .sort((a, b) => { + if (this._fileBasedRecommendations[a] === this._fileBasedRecommendations[b]) { + if (product.extensionImportantTips[a]) { + return -1; + } + if (product.extensionImportantTips[b]) { + return 1; + } + } + return this._fileBasedRecommendations[a] > this._fileBasedRecommendations[b] ? -1 : 1; + }); + return fileBased; } + getOtherRecommendations(): string[] { + return Object.keys(this._exeBasedRecommendations); + } + + + getKeymapRecommendations(): string[] { return product.keymapExtensionTips || []; } - private _getAllRecommendationsInProduct(): string[] { - if (!this._allRecommendations) { - this._allRecommendations = [...Object.keys(this.importantRecommendations)]; - forEach(this._availableRecommendations, ({ value: ids }) => { - this._allRecommendations.push(...ids); - }); - } - return this._allRecommendations; - } - private _suggestTips() { const extensionTips = product.extensionTips; if (!extensionTips) { @@ -121,26 +166,6 @@ export class ExtensionTipsService implements IExtensionTipsService { this.importantRecommendations = product.extensionImportantTips || Object.create(null); this.importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); - // retrieve ids of previous recommendations - const storedRecommendationsJson = JSON.parse(this.storageService.get('extensionsAssistant/recommendations', StorageScope.GLOBAL, '[]')); - if (Array.isArray(storedRecommendationsJson)) { - for (let id of storedRecommendationsJson) { - this._fileBasedRecommendations[id] = Date.now(); - } - } else { - const now = Date.now(); - forEach(storedRecommendationsJson, entry => { - if (typeof entry.value === 'number') { - const diff = (now - entry.value) / milliSecondsInADay; - if (diff > 7) { - delete this._fileBasedRecommendations[entry.value]; - } else { - this._fileBasedRecommendations[entry.key] = entry.value; - } - } - }); - } - // group ids by pattern, like {**/*.md} -> [ext.foo1, ext.bar2] this._availableRecommendations = Object.create(null); forEach(extensionTips, entry => { @@ -164,6 +189,31 @@ export class ExtensionTipsService implements IExtensionTipsService { } }); + forEach(this._availableRecommendations, ({ value: ids }) => { + this._allRecommendations.push(...ids); + }); + + // retrieve ids of previous recommendations + const storedRecommendationsJson = JSON.parse(this.storageService.get('extensionsAssistant/recommendations', StorageScope.GLOBAL, '[]')); + + if (Array.isArray(storedRecommendationsJson)) { + for (let id of storedRecommendationsJson) { + if (this._allRecommendations.indexOf(id) > -1) { + this._fileBasedRecommendations[id] = Date.now(); + } + } + } else { + const now = Date.now(); + forEach(storedRecommendationsJson, entry => { + if (typeof entry.value === 'number') { + const diff = (now - entry.value) / milliSecondsInADay; + if (diff <= 7 && this._allRecommendations.indexOf(entry.key) > -1) { + this._fileBasedRecommendations[entry.key] = entry.value; + } + } + }); + } + this._modelService.onModelAdded(this._suggest, this, this._disposables); this._modelService.getModels().forEach(model => this._suggest(model)); } @@ -216,32 +266,72 @@ export class ExtensionTipsService implements IExtensionTipsService { return; } - const message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name); + let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name); + // Temporary fix for the only extension pack we recommend. See https://github.com/Microsoft/vscode/issues/35364 + if (id === 'vscjava.vscode-java-pack') { + message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name); + } + const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + const installAction = this.instantiationService.createInstance(InstallRecommendedExtensionAction, id); const options = [ + localize('install', 'Install'), recommendationsAction.label, localize('neverShowAgain', "Don't show again"), localize('close', "Close") ]; - this.choiceService.choose(Severity.Info, message, options, 2).done(choice => { + this.choiceService.choose(Severity.Info, message, options, 3).done(choice => { switch (choice) { case 0: - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show' }); + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'install', extensionId: name }); + return installAction.run(); + case 1: + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show', extensionId: name }); return recommendationsAction.run(); - case 1: this.importantRecommendationsIgnoreList.push(id); + case 2: this.importantRecommendationsIgnoreList.push(id); this.storageService.store( 'extensionsAssistant/importantRecommendationsIgnore', JSON.stringify(this.importantRecommendationsIgnoreList), StorageScope.GLOBAL ); - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain' }); + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name }); return this.ignoreExtensionRecommendations(); - case 2: - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'close' }); + case 3: + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'close', extensionId: name }); } }, () => { - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled' }); + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name }); }); }); }); @@ -274,26 +364,56 @@ export class ExtensionTipsService implements IExtensionTipsService { } const message = localize('workspaceRecommended', "This workspace has extension recommendations."); - const action = this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + const showAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + const installAllAction = this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, localize('installAll', "Install All")); const options = [ - action.label, + installAllAction.label, + showAction.label, localize('neverShowAgain', "Don't show again"), localize('close', "Close") ]; - this.choiceService.choose(Severity.Info, message, options, 2).done(choice => { + this.choiceService.choose(Severity.Info, message, options, 3).done(choice => { switch (choice) { case 0: - this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'show' }); - return action.run(); + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'install' }); + return installAllAction.run(); case 1: + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'show' }); + return showAction.run(); + case 2: + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'neverShowAgain' }); return this.storageService.store(storageKey, true, StorageScope.WORKSPACE); - case 2: + case 3: + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'close' }); } }, () => { + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('extensionWorkspaceRecommendations:popup', { userReaction: 'cancelled' }); }); }); @@ -301,7 +421,7 @@ export class ExtensionTipsService implements IExtensionTipsService { } private ignoreExtensionRecommendations() { - const message = localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations ?"); + const message = localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"); const options = [ localize('ignoreAll', "Yes, Ignore All"), localize('no', "No"), @@ -319,21 +439,50 @@ export class ExtensionTipsService implements IExtensionTipsService { }); } - private _suggestBasedOnExecutables() { - const cmd = process.platform === 'win32' ? 'where' : 'which'; - forEach(product.exeBasedExtensionTips, entry => { - cp.exec(`${cmd} ${entry.value.replace(/,/g, ' ')}`, (err, stdout, stderr) => { - if (stdout) { - this._exeBasedRecommendations.push(entry.key); + private _suggestBasedOnExecutables(recommendations: { [id: string]: string; }): void { + const homeDir = os.homedir(); + let foundExecutables: Set = new Set(); + + let findExecutable = (exeName, path) => { + return pfs.fileExists(path).then(exists => { + if (exists && !foundExecutables.has(exeName)) { + foundExecutables.add(exeName); + (product.exeBasedExtensionTips[exeName]['recommendations'] || []) + .forEach(x => { + if (product.exeBasedExtensionTips[exeName]['friendlyName']) { + recommendations[x] = product.exeBasedExtensionTips[exeName]['friendlyName']; + } + }); } }); + }; + + // Loop through recommended extensions + forEach(product.exeBasedExtensionTips, entry => { + if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) { + return; + } + + let exeName = entry.key; + if (process.platform === 'win32') { + let windowsPath = entry.value['windowsPath']; + if (!windowsPath || typeof windowsPath !== 'string') { + return; + } + windowsPath = windowsPath.replace('%USERPROFILE%', process.env['USERPROFILE']) + .replace('%ProgramFiles(x86)%', process.env['ProgramFiles(x86)']) + .replace('%ProgramFiles%', process.env['ProgramFiles']) + .replace('%APPDATA%', process.env['APPDATA']); + findExecutable(exeName, windowsPath); + } else { + findExecutable(exeName, paths.join('/usr/local/bin', exeName)); + findExecutable(exeName, paths.join(homeDir, exeName)); + } }); } private setIgnoreRecommendationsConfig(configVal: boolean) { - let target = ConfigurationTarget.USER; - const configKey = 'extensions.ignoreRecommendations'; - this.configurationEditingService.writeConfiguration(target, { key: configKey, value: configVal }); + this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); if (configVal) { const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 470b1613dac..d5a64743889 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -12,25 +12,23 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtensionGalleryService, IExtensionTipsService, ExtensionsLabel, ExtensionsChannelId, PreferencesLabel } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/parts/output/common/output'; -import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { VIEWLET_ID, IExtensionsWorkbenchService } from '../common/extensions'; import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { - OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, - ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, UpdateAllAction, ConfigureWorkspaceRecommendedExtensionsAction, + OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction, + ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, UpdateAllAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import { OpenExtensionsFolderAction, InstallVSIXAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ExtensionEditor } from 'vs/workbench/parts/extensions/browser/extensionEditor'; -import { StatusUpdater } from 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; +import { StatusUpdater, ExtensionsViewlet } from 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; import { IQuickOpenRegistry, Extensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import jsonContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); @@ -39,6 +37,8 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeymapExtensions, BetterMergeDisabled } from 'vs/workbench/parts/extensions/electron-browser/extensionsUtils'; import { adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { GalleryExtensionsHandler, ExtensionsHandler } from 'vs/workbench/parts/extensions/browser/extensionsQuickOpen'; +import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; // Singletons registerSingleton(IExtensionGalleryService, ExtensionGalleryService); @@ -56,8 +56,8 @@ Registry.as(OutputExtensions.OutputChannels) // Quickopen Registry.as(Extensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/extensions/browser/extensionsQuickOpen', - 'ExtensionsHandler', + ExtensionsHandler, + ExtensionsHandler.ID, 'ext ', null, localize('extensionsCommands', "Manage Extensions"), @@ -67,8 +67,8 @@ Registry.as(Extensions.Quickopen).registerQuickOpenHandler( Registry.as(Extensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/extensions/browser/extensionsQuickOpen', - 'GalleryExtensionsHandler', + GalleryExtensionsHandler, + GalleryExtensionsHandler.ID, 'ext install ', null, localize('galleryExtensionsCommands', "Install Gallery Extensions"), @@ -78,10 +78,9 @@ Registry.as(Extensions.Quickopen).registerQuickOpenHandler( // Editor const editorDescriptor = new EditorDescriptor( + ExtensionEditor, ExtensionEditor.ID, - localize('extension', "Extension"), - 'vs/workbench/parts/extensions/browser/extensionEditor', - 'ExtensionEditor' + localize('extension', "Extension") ); Registry.as(EditorExtensions.Editors) @@ -89,8 +88,7 @@ Registry.as(EditorExtensions.Editors) // Viewlet const viewletDescriptor = new ViewletDescriptor( - 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet', - 'ExtensionsViewlet', + ExtensionsViewlet, VIEWLET_ID, localize('extensions', "Extensions"), 'extensions', @@ -124,9 +122,6 @@ actionRegistry.registerWorkbenchAction(languageExtensionsActionDescriptor, 'Pref const azureExtensionsActionDescriptor = new SyncActionDescriptor(ShowAzureExtensionsAction, ShowAzureExtensionsAction.ID, ShowAzureExtensionsAction.SHORT_LABEL); actionRegistry.registerWorkbenchAction(azureExtensionsActionDescriptor, 'Preferences: Azure Extensions', PreferencesLabel); -const workspaceRecommendationsActionDescriptor = new SyncActionDescriptor(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, ShowWorkspaceRecommendedExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(workspaceRecommendationsActionDescriptor, 'Extensions: Show Workspace Recommended Extensions', ExtensionsLabel); - const popularActionDescriptor = new SyncActionDescriptor(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(popularActionDescriptor, 'Extensions: Show Popular Extensions', ExtensionsLabel); @@ -145,8 +140,11 @@ actionRegistry.registerWorkbenchAction(updateAllActionDescriptor, 'Extensions: U const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL); actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel); -const openExtensionsFileActionDescriptor = new SyncActionDescriptor(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL); -actionRegistry.registerWorkbenchAction(openExtensionsFileActionDescriptor, 'Extensions: Configure Recommended Extensions (Workspace)', ExtensionsLabel); +const configureWorkspaceExtensionsDescriptor = new SyncActionDescriptor(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(configureWorkspaceExtensionsDescriptor, 'Extensions: Configure Recommended Extensions (Workspace)', ExtensionsLabel); + +const configureWorkspaceFolderRecommendationsDescriptor = new SyncActionDescriptor(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL); +actionRegistry.registerWorkbenchAction(configureWorkspaceFolderRecommendationsDescriptor, 'Extensions: Configure Recommended Extensions (Workspace Folder)', ExtensionsLabel); const installVSIXActionDescriptor = new SyncActionDescriptor(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL); actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: Install from VSIX...', ExtensionsLabel); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index f7102ec0601..e76d511962b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -13,12 +13,10 @@ import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/commo import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { remote } from 'electron'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; import { IFileService } from 'vs/platform/files/common/files'; import URI from 'vs/base/common/uri'; - -const dialog = remote.dialog; +import { mnemonicButtonLabel } from 'vs/base/common/labels'; export class OpenExtensionsFolderAction extends Action { @@ -65,15 +63,18 @@ export class InstallVSIXAction extends Action { label = InstallVSIXAction.LABEL, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IMessageService private messageService: IMessageService, - @IInstantiationService private instantiationService: IInstantiationService + @IInstantiationService private instantiationService: IInstantiationService, + @IWindowService private windowsService: IWindowService ) { super(id, label, 'extension-action install-vsix', true); } run(): TPromise { - const result = dialog.showOpenDialog(remote.getCurrentWindow(), { + const result = this.windowsService.showOpenDialog({ + title: localize('installFromVSIX', "Install from VSIX"), filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }], - properties: ['openFile'] + properties: ['openFile'], + buttonLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install")) }); if (!result) { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts index bfd75970a59..562531b1993 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts @@ -7,12 +7,12 @@ import * as arrays from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; -import Event, { chain, any, debounceEvent } from 'vs/base/common/event'; +import Event, { chain, anyEvent, debounceEvent } from 'vs/base/common/event'; import { onUnexpectedError, canceled } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, LocalExtensionType, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -20,10 +20,10 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/common/message'; import { Action } from 'vs/base/common/actions'; -import { BetterMergeDisabledNowKey, BetterMergeId, getIdAndVersionFromLocalExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { BetterMergeDisabledNowKey, BetterMergeId, getIdAndVersionFromLocalExtensionId, areSameExtensions, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; export interface IExtensionStatus { - identifier: string; + identifier: IExtensionIdentifier; local: ILocalExtension; globallyEnabled: boolean; } @@ -42,8 +42,8 @@ export class KeymapExtensions implements IWorkbenchContribution { ) { this.disposables.push( lifecycleService.onShutdown(() => this.dispose()), - instantiationService.invokeFunction(onExtensionChanged)((ids => { - TPromise.join(ids.map(id => this.checkForOtherKeymaps(id))) + instantiationService.invokeFunction(onExtensionChanged)((identifiers => { + TPromise.join(identifiers.map(identifier => this.checkForOtherKeymaps(identifier))) .then(null, onUnexpectedError); })) ); @@ -53,12 +53,12 @@ export class KeymapExtensions implements IWorkbenchContribution { return 'vs.extensions.keymapExtensions'; } - private checkForOtherKeymaps(extensionId: string): TPromise { + private checkForOtherKeymaps(extensionIdentifier: IExtensionIdentifier): TPromise { return this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => { const keymaps = extensions.filter(extension => isKeymapExtension(this.tipsService, extension)); - const extension = arrays.first(keymaps, extension => extension.identifier === extensionId); + const extension = arrays.first(keymaps, extension => extension.identifier.id === extensionIdentifier.id); if (extension && extension.globallyEnabled) { - const otherKeymaps = keymaps.filter(extension => extension.identifier !== extensionId && extension.globallyEnabled); + const otherKeymaps = keymaps.filter(extension => extension.identifier.id !== extensionIdentifier.id && extension.globallyEnabled); if (otherKeymaps.length) { return this.promptForDisablingOtherKeymaps(extension, otherKeymaps); } @@ -68,10 +68,24 @@ export class KeymapExtensions implements IWorkbenchContribution { } private promptForDisablingOtherKeymaps(newKeymap: IExtensionStatus, oldKeymaps: IExtensionStatus[]): TPromise { + /* __GDPR__FRAGMENT__ + "KeyMapsData" : { + "newKeymap" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "oldKeymaps": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ const telemetryData: { [key: string]: any; } = { newKeymap: newKeymap.identifier, oldKeymaps: oldKeymaps.map(k => k.identifier) }; + + /* __GDPR__ + "disableOtherKeymapsConfirmation" : { + "${include}": [ + "${KeyMapsData}" + ] + } + */ this.telemetryService.publicLog('disableOtherKeymapsConfirmation', telemetryData); const message = localize('disableOtherKeymapsConfirmation', "Disable other keymaps ({0}) to avoid conflicts between keybindings?", oldKeymaps.map(k => `'${k.local.manifest.displayName}'`).join(', ')); const options = [ @@ -82,10 +96,18 @@ export class KeymapExtensions implements IWorkbenchContribution { .then(value => { const confirmed = value === 0; telemetryData['confirmed'] = confirmed; + /* __GDPR__ + "disableOtherKeymaps" : { + "confirmed" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "${include}": [ + "${KeyMapsData}" + ] + } + */ this.telemetryService.publicLog('disableOtherKeymaps', telemetryData); if (confirmed) { return TPromise.join(oldKeymaps.map(keymap => { - return this.extensionEnablementService.setEnablement(keymap.identifier, false); + return this.extensionEnablementService.setEnablement(keymap.local.identifier, false); })); } return undefined; @@ -98,18 +120,18 @@ export class KeymapExtensions implements IWorkbenchContribution { } } -export function onExtensionChanged(accessor: ServicesAccessor): Event { +export function onExtensionChanged(accessor: ServicesAccessor): Event { const extensionService = accessor.get(IExtensionManagementService); const extensionEnablementService = accessor.get(IExtensionEnablementService); - return debounceEvent(any( - chain(any(extensionService.onDidInstallExtension, extensionService.onDidUninstallExtension)) - .map(e => stripVersion(e.id)) + return debounceEvent(anyEvent( + chain(anyEvent(extensionService.onDidInstallExtension, extensionService.onDidUninstallExtension)) + .map(e => ({ id: stripVersion(e.identifier.id), uuid: e.identifier.uuid })) .event, extensionEnablementService.onEnablementChanged ), (list, id) => { if (!list) { return [id]; - } else if (list.indexOf(id) === -1) { + } else if (list.some(l => !areSameExtensions(l, id))) { list.push(id); } return list; @@ -122,11 +144,10 @@ export function getInstalledExtensions(accessor: ServicesAccessor): TPromise { const globallyDisabled = extensionEnablementService.getGloballyDisabledExtensions(); return extensions.map(extension => { - const identifier = stripVersion(extension.id); return { - identifier, + identifier: { id: adoptToGalleryExtensionId(extension.identifier.id), uuid: extension.identifier.uuid }, local: extension, - globallyEnabled: globallyDisabled.indexOf(identifier) === -1 + globallyEnabled: globallyDisabled.every(disabled => !areSameExtensions(disabled, extension.identifier)) }; }); }); @@ -134,7 +155,7 @@ export function getInstalledExtensions(accessor: ServicesAccessor): TPromise { if (storageService.getBoolean(BetterMergeDisabledNowKey, StorageScope.GLOBAL, false)) { storageService.remove(BetterMergeDisabledNowKey, StorageScope.GLOBAL); + /* __GDPR__ + "betterMergeDisabled" : {} + */ telemetryService.publicLog('betterMergeDisabled'); messageService.show(Severity.Info, { message: localize('betterMergeDisabled', "The Better Merge extension is now built-in, the installed extension was disabled and can be uninstalled."), actions: [ new Action('uninstall', localize('uninstall', "Uninstall"), null, true, () => { + /* __GDPR__ + "betterMergeUninstall" : { + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ telemetryService.publicLog('betterMergeUninstall', { outcome: 'uninstall', }); return extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => { - return Promise.all(extensions.filter(e => stripVersion(e.id) === BetterMergeId) + return Promise.all(extensions.filter(e => stripVersion(e.identifier.id) === BetterMergeId) .map(e => extensionManagementService.uninstall(e, true))); }); }), new Action('later', localize('later', "Later"), null, true, () => { + /* __GDPR__ + "betterMergeUninstall" : { + "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ telemetryService.publicLog('betterMergeUninstall', { outcome: 'later', }); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index eb578a11c94..361ecfb1c9d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -25,30 +25,30 @@ import { append, $, addStandardDisposableListener, EventType, addClass, removeCl import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, ExtensionState } from '../common/extensions'; +import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, ExtensionState, AutoUpdateConfigurationKey } from '../common/extensions'; import { - ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction, + ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction, EnableAutoUpdateAction, DisableAutoUpdateAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import { LocalExtensionType, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { InstallVSIXAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; -import { ExtensionsListView, InstalledExtensionsView, RecommendedExtensionsView } from './extensionsViews'; +import { ExtensionsListView, InstalledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView } from './extensionsViews'; import { OpenGlobalSettingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IMessageService, CloseAction } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; -import { IActivityBarService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { inputForeground, inputBackground, inputBorder } from 'vs/platform/theme/common/colorRegistry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/parts/views/browser/viewsRegistry'; -import { PersistentViewsViewlet, IView } from 'vs/workbench/parts/views/browser/views'; +import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/browser/parts/views/viewsRegistry'; +import { PersistentViewsViewlet, ViewsViewletPanel } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -57,18 +57,18 @@ interface SearchInputEvent extends Event { immediate?: boolean; } -const ExtensionsViewletVisibleContext = new RawContextKey('extensionsViewletVisible', false); +const NonEmptyWorkspaceContext = new RawContextKey('nonEmptyWorkspace', false); const SearchExtensionsContext = new RawContextKey('searchExtensions', false); const SearchInstalledExtensionsContext = new RawContextKey('searchInstalledExtensions', false); -const SearchRecommendedExtensionsContext = new RawContextKey('searchRecommendedExtensions', false); +const RecommendedExtensionsContext = new RawContextKey('recommendedExtensions', false); export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtensionsViewlet { private onSearchChange: EventOf; - private extensionsViewletVisibleContextKey: IContextKey; + private nonEmptyWorkspaceContextKey: IContextKey; private searchExtensionsContextKey: IContextKey; private searchInstalledExtensionsContextKey: IContextKey; - private searchRecommendedExtensionsContextKey: IContextKey; + private recommendedExtensionsContextKey: IContextKey; private searchDelayer: ThrottledDelayer; private root: HTMLElement; @@ -79,15 +79,12 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens private secondaryActions: IAction[]; private disposables: IDisposable[] = []; - private isAutoUpdateEnabled: boolean; - constructor( @ITelemetryService telemetryService: ITelemetryService, @IProgressService private progressService: IProgressService, @IInstantiationService instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorInputService: IEditorGroupService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionManagementService private extensionManagementService: IExtensionManagementService, @IMessageService private messageService: IMessageService, @IViewletService private viewletService: IViewletService, @@ -103,18 +100,15 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens this.registerViews(); this.searchDelayer = new ThrottledDelayer(500); - this.extensionsViewletVisibleContextKey = ExtensionsViewletVisibleContext.bindTo(contextKeyService); + this.nonEmptyWorkspaceContextKey = NonEmptyWorkspaceContext.bindTo(contextKeyService); this.searchExtensionsContextKey = SearchExtensionsContext.bindTo(contextKeyService); this.searchInstalledExtensionsContextKey = SearchInstalledExtensionsContext.bindTo(contextKeyService); - this.searchRecommendedExtensionsContextKey = SearchRecommendedExtensionsContext.bindTo(contextKeyService); + this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService); - this.disposables.push(viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables)); - this.isAutoUpdateEnabled = this.extensionsWorkbenchService.isAutoUpdateEnabled; + this.disposables.push(this.viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables)); - this.configurationService.onDidUpdateConfiguration(() => { - const isAutoUpdateEnabled = this.extensionsWorkbenchService.isAutoUpdateEnabled; - if (this.isAutoUpdateEnabled !== isAutoUpdateEnabled) { - this.isAutoUpdateEnabled = isAutoUpdateEnabled; + this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(AutoUpdateConfigurationKey)) { this.secondaryActions = null; this.updateTitleArea(); } @@ -126,7 +120,9 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens viewDescriptors.push(this.createMarketPlaceExtensionsListViewDescriptor()); viewDescriptors.push(this.createInstalledExtensionsListViewDescriptor()); viewDescriptors.push(this.createSearchInstalledExtensionsListViewDescriptor()); - viewDescriptors.push(this.createRecommendedExtensionsListViewDescriptor()); + viewDescriptors.push(this.createDefaultRecommendedExtensionsListViewDescriptor()); + viewDescriptors.push(this.createOtherRecommendedExtensionsListViewDescriptor()); + viewDescriptors.push(this.createWorkspaceRecommendedExtensionsListViewDescriptor()); ViewsRegistry.registerViews(viewDescriptors); } @@ -136,7 +132,7 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens name: localize('marketPlace', "Marketplace"), location: ViewLocation.Extensions, ctor: ExtensionsListView, - when: ContextKeyExpr.and(ContextKeyExpr.has('extensionsViewletVisible'), ContextKeyExpr.has('searchExtensions'), ContextKeyExpr.not('searchInstalledExtensions')), + when: ContextKeyExpr.and(ContextKeyExpr.has('searchExtensions'), ContextKeyExpr.not('searchInstalledExtensions'), ContextKeyExpr.not('recommendedExtensions')), size: 100 }; } @@ -147,8 +143,8 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens name: localize('installedExtensions', "Installed"), location: ViewLocation.Extensions, ctor: InstalledExtensionsView, - when: ContextKeyExpr.and(ContextKeyExpr.has('extensionsViewletVisible'), ContextKeyExpr.not('searchExtensions')), - size: 50 + when: ContextKeyExpr.and(ContextKeyExpr.not('searchExtensions')), + size: 200 }; } @@ -158,24 +154,50 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens name: localize('searchInstalledExtensions', "Installed"), location: ViewLocation.Extensions, ctor: InstalledExtensionsView, - when: ContextKeyExpr.and(ContextKeyExpr.has('extensionsViewletVisible'), ContextKeyExpr.has('searchInstalledExtensions')), + when: ContextKeyExpr.and(ContextKeyExpr.has('searchInstalledExtensions')), size: 50 }; } - private createRecommendedExtensionsListViewDescriptor(): IViewDescriptor { + private createDefaultRecommendedExtensionsListViewDescriptor(): IViewDescriptor { return { id: 'extensions.recommendedList', name: localize('recommendedExtensions', "Recommended"), location: ViewLocation.Extensions, ctor: RecommendedExtensionsView, - when: ContextKeyExpr.and(ContextKeyExpr.has('extensionsViewletVisible'), ContextKeyExpr.not('searchExtensions')), - size: 50, + when: ContextKeyExpr.and(ContextKeyExpr.not('searchExtensions')), + size: 600, canToggleVisibility: true }; } - create(parent: Builder): TPromise { + private createOtherRecommendedExtensionsListViewDescriptor(): IViewDescriptor { + return { + id: 'extensions.otherrecommendedList', + name: localize('otherRecommendedExtensions', "Other Recommendations"), + location: ViewLocation.Extensions, + ctor: RecommendedExtensionsView, + when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions')), + size: 600, + canToggleVisibility: true, + order: 2 + }; + } + + private createWorkspaceRecommendedExtensionsListViewDescriptor(): IViewDescriptor { + return { + id: 'extensions.workspaceRecommendedList', + name: localize('workspaceRecommendedExtensions', "Workspace Recommendations"), + location: ViewLocation.Extensions, + ctor: WorkspaceRecommendedExtensionsView, + when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions'), ContextKeyExpr.has('nonEmptyWorkspace')), + size: 200, + canToggleVisibility: true, + order: 1 + }; + } + + async create(parent: Builder): TPromise { parent.addClass('extensions-viewlet'); this.root = parent.getHTMLElement(); @@ -204,14 +226,14 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens this.onSearchChange = mapEvent(onSearchInput, e => e.target.value); - return this.extensionManagementService.getInstalled(LocalExtensionType.User) - .then(installed => { - if (installed.length === 0) { - this.searchBox.value = '@sort:installs'; - this.searchExtensionsContextKey.set(true); - } - return super.create(new Builder(this.extensionsBox)); - }); + await super.create(new Builder(this.extensionsBox)); + + const installed = await this.extensionManagementService.getInstalled(LocalExtensionType.User); + + if (installed.length === 0) { + this.searchBox.value = '@sort:installs'; + this.searchExtensionsContextKey.set(true); + } } public updateStyles(): void { @@ -230,7 +252,6 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens const isVisibilityChanged = this.isVisible() !== visible; return super.setVisible(visible).then(() => { if (isVisibilityChanged) { - this.extensionsViewletVisibleContextKey.set(visible); if (visible) { this.searchBox.focus(); this.searchBox.setSelectionRange(0, this.searchBox.value.length); @@ -269,7 +290,6 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, ShowEnabledExtensionsAction.LABEL), this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL), this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL), - this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, ShowWorkspaceRecommendedExtensionsAction.LABEL), this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL), new Separator(), this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Sort By: Install Count"), this.onSearchChange, 'installs'), @@ -277,7 +297,7 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Sort By: Name"), this.onSearchChange, 'name'), new Separator(), this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL), - ...(this.isAutoUpdateEnabled ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]), + ...(this.configurationService.getValue(AutoUpdateConfigurationKey) ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]), this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL), new Separator(), this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL), @@ -305,12 +325,13 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens const value = this.searchBox.value || ''; this.searchExtensionsContextKey.set(!!value); this.searchInstalledExtensionsContextKey.set(InstalledExtensionsView.isInsalledExtensionsQuery(value)); - this.searchRecommendedExtensionsContextKey.set(RecommendedExtensionsView.isRecommendedExtensionsQuery(value)); + this.recommendedExtensionsContextKey.set(ExtensionsListView.isRecommendedExtensionsQuery(value)); + this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY); await this.updateViews([], !!value); } - protected async updateViews(unregisteredViews: IViewDescriptor[] = [], showAll = false): TPromise { + protected async updateViews(unregisteredViews: IViewDescriptor[] = [], showAll = false): TPromise { const created = await super.updateViews(); const toShow = showAll ? this.views : created; if (toShow.length) { @@ -404,7 +425,7 @@ export class StatusUpdater implements IWorkbenchContribution { private badgeHandle: IDisposable; constructor( - @IActivityBarService private activityBarService: IActivityBarService, + @IActivityService private activityService: IActivityService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService ) { extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables); @@ -419,14 +440,14 @@ export class StatusUpdater implements IWorkbenchContribution { dispose(this.badgeHandle); if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) { - this.badgeHandle = this.activityBarService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge'); + this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge'); return; } const outdated = this.extensionsWorkbenchService.local.reduce((r, e) => r + (e.outdated ? 1 : 0), 0); if (outdated > 0) { const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n)); - this.badgeHandle = this.activityBarService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge'); + this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge'); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts index 97fa6bb3a14..4f44869ebc0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts @@ -7,21 +7,17 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { dispose } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; -import { distinct } from 'vs/base/common/arrays'; import { chain } from 'vs/base/common/event'; import { isPromiseCanceledError, create as createError } from 'vs/base/common/errors'; import Severity from 'vs/base/common/severity'; import { PagedModel, IPagedModel, mergePagers, IPager } from 'vs/base/common/paging'; -import { ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; import { IMessageService, CloseAction } from 'vs/platform/message/common/message'; import { SortBy, SortOrder, IQueryOptions, LocalExtensionType, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ICommandService } from 'vs/platform/commands/common/commands'; import { append, $, toggleClass } from 'vs/base/browser/dom'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -32,51 +28,50 @@ import { IListService } from 'vs/platform/list/browser/listService'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachListStyler, attachBadgeStyler } from 'vs/platform/theme/common/styler'; -import { CollapsibleView, IViewletViewOptions, IViewOptions } from 'vs/workbench/parts/views/browser/views'; +import { ViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { OpenGlobalSettingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IProgressService } from 'vs/platform/progress/common/progress'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { EventType } from 'vs/base/common/events'; +import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; -export class ExtensionsListView extends CollapsibleView { +export class ExtensionsListView extends ViewsViewletPanel { private messageBox: HTMLElement; private extensionsList: HTMLElement; private badge: CountBadge; - + protected badgeContainer: HTMLElement; private list: PagedList; - private disposables: IDisposable[] = []; constructor( - initialSize: number, private options: IViewletViewOptions, - @IMessageService private messageService: IMessageService, + @IMessageService protected messageService: IMessageService, @IKeybindingService keybindingService: IKeybindingService, @IContextMenuService contextMenuService: IContextMenuService, - @IInstantiationService private instantiationService: IInstantiationService, + @IInstantiationService protected instantiationService: IInstantiationService, @IListService private listService: IListService, @IThemeService private themeService: IThemeService, - @IContextKeyService private contextKeyService: IContextKeyService, @IExtensionService private extensionService: IExtensionService, - @ICommandService private commandService: ICommandService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorInputService: IEditorGroupService, @IExtensionTipsService private tipsService: IExtensionTipsService, @IModeService private modeService: IModeService, - @ITelemetryService private telemetryService: ITelemetryService, - @IProgressService private progressService: IProgressService + @ITelemetryService private telemetryService: ITelemetryService ) { - super(initialSize, { ...(options as IViewOptions), ariaHeaderLabel: options.name, sizing: ViewSizing.Flexible, collapsed: !!options.collapsed, initialBodySize: 1 * 62 }, keybindingService, contextMenuService); + super({ ...(options as IViewOptions), ariaHeaderLabel: options.name }, keybindingService, contextMenuService); } renderHeader(container: HTMLElement): void { const titleDiv = append(container, $('div.title')); append(titleDiv, $('span')).textContent = this.options.name; - this.badge = new CountBadge(append(container, $('.count-badge-wrapper'))); + + this.badgeContainer = append(container, $('.count-badge-wrapper')); + this.badge = new CountBadge(this.badgeContainer); this.disposables.push(attachBadgeStyler(this.badge, this.themeService)); } @@ -104,14 +99,6 @@ export class ExtensionsListView extends CollapsibleView { .on(this.pin, this, this.disposables); } - setVisible(visible: boolean): TPromise { - return super.setVisible(visible).then(() => { - if (!visible) { - this.setModel(new PagedModel([])); - } - }); - } - layoutBody(size: number): void { this.extensionsList.style.height = size + 'px'; this.list.layout(size); @@ -193,6 +180,15 @@ export class ExtensionsListView extends CollapsibleView { return new PagedModel(result); } + const idMatch = /@id:([a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*)/.exec(value); + + if (idMatch) { + const name = idMatch[1]; + + return this.extensionsWorkbenchService.queryGallery({ names: [name], source: 'queryById' }) + .then(pager => new PagedModel(pager)); + } + if (/@outdated/i.test(value)) { value = value.replace(/@outdated/g, '').trim().toLowerCase(); @@ -236,7 +232,7 @@ export class ExtensionsListView extends CollapsibleView { return this.getWorkspaceRecommendationsModel(query, options); } else if (ExtensionsListView.isKeymapsRecommendedExtensionsQuery(query.value)) { return this.getKeymapRecommendationsModel(query, options); - } else if (/@recommended:all/i.test(query.value)) { + } else if (/@recommended:all/i.test(query.value) || ExtensionsListView.isSearchRecommendedExtensionsQuery(query.value)) { return this.getAllRecommendationsModel(query, options); } else if (ExtensionsListView.isRecommendedExtensionsQuery(query.value)) { return this.getRecommendationsModel(query, options); @@ -265,13 +261,15 @@ export class ExtensionsListView extends CollapsibleView { }); if (names.length) { - const namesOptions = assign({}, options, { names }); + const namesOptions = assign({}, options, { names, source: 'extRegex' }); pagerPromises.push(this.extensionsWorkbenchService.queryGallery(namesOptions)); } } if (text) { - options = assign(options, { text: text.substr(0, 350) }); + options = assign(options, { text: text.substr(0, 350), source: 'searchText' }); + } else { + options.source = 'viewlet'; } pagerPromises.push(this.extensionsWorkbenchService.queryGallery(options)); @@ -283,23 +281,29 @@ export class ExtensionsListView extends CollapsibleView { } private getAllRecommendationsModel(query: Query, options: IQueryOptions): TPromise> { - const value = query.value.replace(/@recommended:all/g, '').trim().toLowerCase(); + const value = query.value.replace(/@recommended:all/g, '').replace(/@recommended/g, '').trim().toLowerCase(); return this.extensionsWorkbenchService.queryLocal() .then(result => result.filter(e => e.type === LocalExtensionType.User)) .then(local => { - return TPromise.join([TPromise.as(this.tipsService.getRecommendations()), this.tipsService.getWorkspaceRecommendations()]) - .then(([recommendations, workspaceRecommendations]) => { - const names = distinct([...recommendations, ...workspaceRecommendations]) - .filter(name => local.every(ext => `${ext.publisher}.${ext.name}` !== name)) - .filter(name => name.toLowerCase().indexOf(value) > -1); + const installedExtensions = local.map(x => `${x.publisher}.${x.name}`); + let fileBasedRecommendations = this.tipsService.getFileBasedRecommendations(); + let others = this.tipsService.getOtherRecommendations(); + return this.tipsService.getWorkspaceRecommendations() + .then(workspaceRecommendations => { + const names = this.getTrimmedRecommendations(installedExtensions, value, fileBasedRecommendations, others, workspaceRecommendations); + + this.telemetryService.publicLog('extensionAllRecommendations:open', { count: names.length }); if (!names.length) { return TPromise.as(new PagedModel([])); } options.source = 'recommendations-all'; return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length })) - .then(pager => new PagedModel(pager || [])); + .then(pager => { + this.sortFirstPage(pager, names); + return new PagedModel(pager || []); + }); }); }); } @@ -310,10 +314,18 @@ export class ExtensionsListView extends CollapsibleView { return this.extensionsWorkbenchService.queryLocal() .then(result => result.filter(e => e.type === LocalExtensionType.User)) .then(local => { - const names = this.tipsService.getRecommendations() - .filter(name => local.every(ext => `${ext.publisher}.${ext.name}` !== name)) - .filter(name => name.toLowerCase().indexOf(value) > -1); + let fileBasedRecommendations = this.tipsService.getFileBasedRecommendations(); + let others = this.tipsService.getOtherRecommendations(); + const installedExtensions = local.map(x => `${x.publisher}.${x.name}`); + + const names = this.getTrimmedRecommendations(installedExtensions, value, fileBasedRecommendations, others, []); + + /* __GDPR__ + "extensionRecommendations:open" : { + "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('extensionRecommendations:open', { count: names.length }); if (!names.length) { @@ -321,15 +333,52 @@ export class ExtensionsListView extends CollapsibleView { } options.source = 'recommendations'; return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length })) - .then(pager => new PagedModel(pager || [])); + .then(pager => { + this.sortFirstPage(pager, names); + return new PagedModel(pager || []); + }); }); } + // Given all recommendations, trims and returns recommendations in the relevant order after filtering out installed extensions + private getTrimmedRecommendations(installedExtensions: string[], value: string, fileBasedRecommendations: string[], otherRecommendations: string[], workpsaceRecommendations: string[], ) { + const totalCount = 8; + workpsaceRecommendations = workpsaceRecommendations + .filter(name => { + return installedExtensions.indexOf(name) === -1 + && name.toLowerCase().indexOf(value) > -1; + }); + fileBasedRecommendations = fileBasedRecommendations.filter(x => { + return installedExtensions.indexOf(x) === -1 + && workpsaceRecommendations.indexOf(x) === -1 + && x.toLowerCase().indexOf(value) > -1; + }); + otherRecommendations = otherRecommendations.filter(x => { + return installedExtensions.indexOf(x) === -1 + && fileBasedRecommendations.indexOf(x) === -1 + && workpsaceRecommendations.indexOf(x) === -1 + && x.toLowerCase().indexOf(value) > -1; + }); + + let otherCount = Math.min(2, otherRecommendations.length); + let fileBasedCount = Math.min(fileBasedRecommendations.length, totalCount - workpsaceRecommendations.length - otherCount); + let names = workpsaceRecommendations; + names.push(...fileBasedRecommendations.splice(0, fileBasedCount)); + names.push(...otherRecommendations.splice(0, otherCount)); + + return names; + } + private getWorkspaceRecommendationsModel(query: Query, options: IQueryOptions): TPromise> { const value = query.value.replace(/@recommended:workspace/g, '').trim().toLowerCase(); return this.tipsService.getWorkspaceRecommendations() .then(recommendations => { const names = recommendations.filter(name => name.toLowerCase().indexOf(value) > -1); + /* __GDPR__ + "extensionWorkspaceRecommendations:open" : { + "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('extensionWorkspaceRecommendations:open', { count: names.length }); if (!names.length) { @@ -345,6 +394,11 @@ export class ExtensionsListView extends CollapsibleView { const value = query.value.replace(/@recommended:keymaps/g, '').trim().toLowerCase(); const names = this.tipsService.getKeymapRecommendations() .filter(name => name.toLowerCase().indexOf(value) > -1); + /* __GDPR__ + "extensionKeymapRecommendations:open" : { + "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('extensionKeymapRecommendations:open', { count: names.length }); if (!names.length) { @@ -355,6 +409,14 @@ export class ExtensionsListView extends CollapsibleView { .then(result => new PagedModel(result)); } + // Sorts the firsPage of the pager in the same order as given array of extension ids + private sortFirstPage(pager: IPager, ids: string[]) { + ids = ids.map(x => x.toLowerCase()); + pager.firstPage.sort((a, b) => { + return ids.indexOf(a.id.toLowerCase()) < ids.indexOf(b.id.toLowerCase()) ? -1 : 1; + }); + } + private setModel(model: IPagedModel) { this.list.model = model; this.list.scrollTop = 0; @@ -427,7 +489,11 @@ export class ExtensionsListView extends CollapsibleView { } static isRecommendedExtensionsQuery(query: string): boolean { - return /@recommended/i.test(query); + return /^@recommended$/i.test(query.trim()); + } + + static isSearchRecommendedExtensionsQuery(query: string): boolean { + return /@recommended/i.test(query) && !ExtensionsListView.isRecommendedExtensionsQuery(query); } static isWorkspaceRecommendedExtensionsQuery(query: string): boolean { @@ -456,23 +522,43 @@ export class InstalledExtensionsView extends ExtensionsListView { searchInstalledQuery = query ? searchInstalledQuery + ' ' + query : searchInstalledQuery; return super.show(searchInstalledQuery); } - } export class RecommendedExtensionsView extends ExtensionsListView { - public static isRecommendedExtensionsQuery(query: string): boolean { - return ExtensionsListView.isRecommendedExtensionsQuery(query) - || ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query); + async show(query: string): TPromise> { + return super.show(!query.trim() ? '@recommended:all' : '@recommended'); + } +} + +export class WorkspaceRecommendedExtensionsView extends ExtensionsListView { + + renderHeader(container: HTMLElement): void { + super.renderHeader(container); + + const listActionBar = $('.list-actionbar-container'); + container.insertBefore(listActionBar, this.badgeContainer); + + const actionbar = new ActionBar(listActionBar, { + animated: false + }); + actionbar.addListener(EventType.RUN, ({ error }) => error && this.messageService.show(Severity.Error, error)); + const installAllAction = this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL); + const configureWorkspaceFolderAction = this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL); + + installAllAction.class = 'octicon octicon-cloud-download'; + configureWorkspaceFolderAction.class = 'octicon octicon-pencil'; + + actionbar.push([installAllAction], { icon: true, label: false }); + actionbar.push([configureWorkspaceFolderAction], { icon: true, label: false }); + + this.disposables.push(actionbar); } async show(query: string): TPromise> { - if (RecommendedExtensionsView.isRecommendedExtensionsQuery(query)) { - return super.show(query); - } - let searchInstalledQuery = '@recommended:all'; - searchInstalledQuery = query ? searchInstalledQuery + ' ' + query : searchInstalledQuery; - return super.show(searchInstalledQuery); + let model = await super.show('@recommended:workspace'); + this.setExpanded(model.length > 0); + return model; } } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index 35a4e5bcb39..ac002d15828 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -27,17 +27,31 @@ height: calc(100% - 38px); } +.extensions-viewlet > .extensions .extensions-list > .monaco-list { + height: auto; +} + +.extensions-viewlet > .extensions .list-actionbar-container .monaco-action-bar .action-item > .octicon { + font-size: 12px; + line-height: 1; + margin-right: 10px; +} + +.extensions-viewlet > .extensions .list-actionbar-container .monaco-action-bar .action-item.disabled { + display: none; +} + .extensions-viewlet > .extensions .extensions-list.hidden, .extensions-viewlet > .extensions .message.hidden { display: none; visibility: hidden; } -.extensions-viewlet > .extensions .header { +.extensions-viewlet > .extensions .panel-header { padding-right: 12px; } -.extensions-viewlet > .extensions .header > .title { +.extensions-viewlet > .extensions .panel-header > .title { flex: 1; } @@ -46,6 +60,27 @@ cursor: default; } +.extensions-viewlet > .extensions .monaco-list-row > .bookmark { + display: none; +} + +.extensions-viewlet > .extensions .monaco-list-row.recommended > .bookmark { + display: inline-block; + height: 20px; + width: 20px; + border-right: 20px solid transparent; + border-top: 20px solid; + box-sizing: border-box; +} + +.extensions-viewlet > .extensions .monaco-list-row > .bookmark > .octicon { + position: absolute; + top: 1px; + left: 1px; + color: white; + font-size: 90%; +} + .extensions-viewlet > .extensions .extension { box-sizing: border-box; width: 100%; @@ -53,6 +88,8 @@ padding: 0 11px 0 16px; overflow: hidden; display: flex; + position: absolute; + top: 0; } .extensions-viewlet > .extensions .extension.loading { @@ -94,7 +131,6 @@ overflow: hidden; flex: 1; min-width: 0; - } .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .name { diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index 029bed45771..3c57bee6e70 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -20,21 +20,20 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest, - InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService + InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; -import { IExtension, IExtensionDependencies, ExtensionState, IExtensionsWorkbenchService, IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; +import { IExtension, IExtensionDependencies, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IURLService } from 'vs/platform/url/common/url'; import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import product from 'vs/platform/node/product'; interface IExtensionStateProvider { @@ -50,7 +49,8 @@ class Extension implements IExtension { private galleryService: IExtensionGalleryService, private stateProvider: IExtensionStateProvider, public local: ILocalExtension, - public gallery: IGalleryExtension = null + public gallery: IGalleryExtension, + private telemetryService: ITelemetryService ) { } get type(): LocalExtensionType { @@ -71,11 +71,15 @@ class Extension implements IExtension { get id(): string { if (this.gallery) { - return this.gallery.id; + return this.gallery.identifier.id; } return getGalleryExtensionIdFromLocal(this.local); } + get uuid(): string { + return this.gallery ? this.gallery.identifier.uuid : this.local.identifier.uuid; + } + get publisher(): string { return this.gallery ? this.gallery.publisher : this.local.manifest.publisher; } @@ -173,7 +177,10 @@ class Extension implements IExtension { getManifest(): TPromise { if (this.gallery) { - return this.galleryService.getManifest(this.gallery); + if (this.gallery.assets.manifest) { + return this.galleryService.getManifest(this.gallery); + } + this.telemetryService.publicLog('extensions:NotFoundManifest', this.telemetryData); } return TPromise.as(this.local.manifest); @@ -181,7 +188,10 @@ class Extension implements IExtension { getReadme(): TPromise { if (this.gallery) { - return this.galleryService.getReadme(this.gallery); + if (this.gallery.assets.readme) { + return this.galleryService.getReadme(this.gallery); + } + this.telemetryService.publicLog('extensions:NotFoundReadMe', this.telemetryData); } if (this.local && this.local.readmeUrl) { @@ -309,8 +319,6 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private _onChange: Emitter = new Emitter(); get onChange(): Event { return this._onChange.event; } - private _isAutoUpdateEnabled: boolean; - private _extensionAllowedBadgeProviders: string[]; constructor( @@ -319,13 +327,11 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { @IExtensionManagementService private extensionService: IExtensionManagementService, @IExtensionGalleryService private galleryService: IExtensionGalleryService, @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @ITelemetryService private telemetryService: ITelemetryService, @IMessageService private messageService: IMessageService, @IChoiceService private choiceService: IChoiceService, @IURLService urlService: IURLService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, - @IExtensionTipsService private tipsService: IExtensionTipsService, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IWindowService private windowService: IWindowService ) { @@ -344,12 +350,9 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { .filter(uri => /^extension/.test(uri.path)) .on(this.onOpenExtensionUrl, this, this.disposables); - this._isAutoUpdateEnabled = this.configurationService.getConfiguration(ConfigurationKey).autoUpdate; - this.configurationService.onDidUpdateConfiguration(() => { - const isAutoUpdateEnabled = this.configurationService.getConfiguration(ConfigurationKey).autoUpdate; - if (this._isAutoUpdateEnabled !== isAutoUpdateEnabled) { - this._isAutoUpdateEnabled = isAutoUpdateEnabled; - if (this._isAutoUpdateEnabled) { + this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(AutoUpdateConfigurationKey)) { + if (this.isAutoUpdateEnabled()) { this.checkForUpdates(); } } @@ -368,14 +371,14 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { queryLocal(): TPromise { return this.extensionService.getInstalled().then(result => { - const installedById = index(this.installed, e => e.local.id); + const installedById = index(this.installed, e => e.local.identifier.id); const globallyDisabledExtensions = this.extensionEnablementService.getGloballyDisabledExtensions(); const workspaceDisabledExtensions = this.extensionEnablementService.getWorkspaceDisabledExtensions(); this.installed = result.map(local => { - const extension = installedById[local.id] || new Extension(this.galleryService, this.stateProvider, local); + const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, local, null, this.telemetryService); extension.local = local; - extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.id) !== -1; - extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.id) !== -1; + extension.disabledGlobally = globallyDisabledExtensions.some(d => areSameExtensions(d, extension)); + extension.disabledForWorkspace = workspaceDisabledExtensions.some(d => areSameExtensions(d, extension)); return extension; }); @@ -414,12 +417,19 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } open(extension: IExtension, sideByside: boolean = false): TPromise { + /* __GDPR__ + "extensionGallery:open" : { + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ this.telemetryService.publicLog('extensionGallery:open', extension.telemetryData); return this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), null, sideByside); } private fromGallery(gallery: IGalleryExtension): Extension { - const installed = this.installed.filter(installed => installed.id === gallery.id)[0]; + const installed = this.getInstalledExtensionMatchingGallery(gallery); if (installed) { // Loading the compatible version only there is an engine property @@ -432,28 +442,41 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return installed; } - return new Extension(this.galleryService, this.stateProvider, null, gallery); + return new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); + } + + private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): Extension { + for (const installed of this.installed) { + if (installed.uuid) { // Installed from Gallery + if (installed.uuid === gallery.identifier.uuid) { + return installed; + } + } else { + if (installed.id === gallery.identifier.id) { // Installed from other sources + return installed; + } + } + } + return null; } private syncLocalWithGalleryExtension(local: Extension, gallery: IGalleryExtension) { - local.gallery = gallery; - this._onChange.fire(); - this.eventuallyAutoUpdateExtensions(); + // Sync the local extension with gallery extension if local extension doesnot has metadata + (local.local.metadata ? TPromise.as(local.local) : this.extensionService.updateMetadata(local.local, { id: gallery.identifier.uuid, publisherDisplayName: gallery.publisherDisplayName, publisherId: gallery.publisherId })) + .then(localExtension => { + local.local = localExtension; + local.gallery = gallery; + this._onChange.fire(); + this.eventuallyAutoUpdateExtensions(); + }); } checkForUpdates(): TPromise { return this.syncDelayer.trigger(() => this.syncWithGallery(), 0); } - get isAutoUpdateEnabled(): boolean { - return this._isAutoUpdateEnabled; - } - - setAutoUpdate(autoUpdate: boolean): TPromise { - if (this.isAutoUpdateEnabled === autoUpdate) { - return TPromise.as(null); - } - return this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'extensions.autoUpdate', value: autoUpdate }); + private isAutoUpdateEnabled(): boolean { + return this.configurationService.getValue(AutoUpdateConfigurationKey); } private eventuallySyncWithGallery(immediate = false): void { @@ -465,15 +488,26 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } private syncWithGallery(): TPromise { - const names = this.installed - .filter(e => e.type === LocalExtensionType.User) - .map(e => e.id); - - if (names.length === 0) { - return TPromise.as(null); + const ids = [], names = []; + for (const installed of this.installed) { + if (installed.type === LocalExtensionType.User) { + if (installed.uuid) { + ids.push(installed.uuid); + } else { + names.push(installed.id); + } + } } - return this.queryGallery({ names, pageSize: names.length }) as TPromise; + const promises = []; + if (ids.length) { + promises.push(this.queryGallery({ ids, pageSize: ids.length })); + } + if (names.length) { + promises.push(this.queryGallery({ names, pageSize: names.length })); + } + + return TPromise.join(promises) as TPromise; } private eventuallyAutoUpdateExtensions(): void { @@ -482,12 +516,12 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } private autoUpdateExtensions(): TPromise { - if (!this.isAutoUpdateEnabled) { + if (!this.isAutoUpdateEnabled()) { return TPromise.as(null); } const toUpdate = this.local.filter(e => e.outdated && (e.state !== ExtensionState.Installing)); - return TPromise.join(toUpdate.map(e => this.install(e, false))); + return TPromise.join(toUpdate.map(e => this.install(e))); } canInstall(extension: IExtension): boolean { @@ -498,7 +532,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return !!(extension as Extension).gallery; } - install(extension: string | IExtension, promptToInstallDependencies: boolean = true): TPromise { + install(extension: string | IExtension): TPromise { if (typeof extension === 'string') { return this.extensionService.install(extension); } @@ -514,7 +548,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return TPromise.wrapError(new Error('Missing gallery')); } - return this.extensionService.installFromGallery(gallery, promptToInstallDependencies); + return this.extensionService.installFromGallery(gallery); } setEnablement(extension: IExtension, enable: boolean, workspace: boolean = false): TPromise { @@ -523,6 +557,20 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } return this.promptAndSetEnablement(extension, enable, workspace).then(reload => { + /* __GDPR__ + "extension:enable" : { + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ + /* __GDPR__ + "extension:disable" : { + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ this.telemetryService.publicLog(enable ? 'extension:enable' : 'extension:disable', extension.telemetryData); }); } @@ -659,12 +707,12 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private doSetEnablement(extension: IExtension, enable: boolean, workspace: boolean): TPromise { if (workspace) { - return this.extensionEnablementService.setEnablement(extension.id, enable, workspace); + return this.extensionEnablementService.setEnablement(extension, enable, workspace); } - const globalElablement = this.extensionEnablementService.setEnablement(extension.id, enable, false); - if (enable && this.workspaceContextService.hasWorkspace()) { - const workspaceEnablement = this.extensionEnablementService.setEnablement(extension.id, enable, true); + const globalElablement = this.extensionEnablementService.setEnablement(extension, enable, false); + if (enable && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { + const workspaceEnablement = this.extensionEnablementService.setEnablement(extension, enable, true); return TPromise.join([globalElablement, workspaceEnablement]).then(values => values[0] || values[1]); } return globalElablement; @@ -684,10 +732,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return; } - let extension = this.installed.filter(e => e.id === gallery.id)[0]; + let extension = this.installed.filter(e => areSameExtensions(e, gallery.identifier))[0]; if (!extension) { - extension = new Extension(this.galleryService, this.stateProvider, null, gallery); + extension = new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); } extension.gallery = gallery; @@ -701,8 +749,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private onDidInstallExtension(event: DidInstallExtensionEvent): void { const { local, zipPath, error, gallery } = event; - const installing = gallery ? this.installing.filter(e => e.extension.id === gallery.id)[0] : null; - const extension: Extension = installing ? installing.extension : zipPath ? new Extension(this.galleryService, this.stateProvider, null) : null; + const installing = gallery ? this.installing.filter(e => areSameExtensions(e.extension, gallery.identifier))[0] : null; + const extension: Extension = installing ? installing.extension : zipPath ? new Extension(this.galleryService, this.stateProvider, null, null, this.telemetryService) : null; if (extension) { this.installing = installing ? this.installing.filter(e => e !== installing) : this.installing; @@ -721,15 +769,15 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } if (extension.gallery) { // Report telemetry only for gallery extensions - this.reportTelemetry(installing, !error); + this.reportTelemetry(installing, error); } } this._onChange.fire(); } - private onUninstallExtension(id: string): void { - const extension = this.installed.filter(e => e.local.id === id)[0]; - const newLength = this.installed.filter(e => e.local.id !== id).length; + private onUninstallExtension({ id }: IExtensionIdentifier): void { + const extension = this.installed.filter(e => e.local.identifier.id === id)[0]; + const newLength = this.installed.filter(e => e.local.identifier.id !== id).length; // TODO: Ask @Joao why is this? if (newLength === this.installed.length) { return; @@ -737,43 +785,44 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { const start = new Date(); const operation = Operation.Uninstalling; - const uninstalling = this.uninstalling.filter(e => e.extension.local.id === id)[0] || { id, operation, extension, start }; - this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => e.extension.local.id !== id)]; + const uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id === id)[0] || { id, operation, extension, start }; + this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => e.extension.local.identifier.id !== id)]; this._onChange.fire(); } - private onDidUninstallExtension({ id, error }: DidUninstallExtensionEvent): void { + private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void { + const id = identifier.id; if (!error) { - this.installed = this.installed.filter(e => e.local.id !== id); + this.installed = this.installed.filter(e => e.local.identifier.id !== id); } - const uninstalling = this.uninstalling.filter(e => e.extension.local.id === id)[0]; - this.uninstalling = this.uninstalling.filter(e => e.extension.local.id !== id); + const uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id === id)[0]; + this.uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id !== id); if (!uninstalling) { return; } if (!error) { - this.reportTelemetry(uninstalling, true); + this.reportTelemetry(uninstalling); } this._onChange.fire(); } - private onEnablementChanged(extensionIdentifier: string) { - const [extension] = this.local.filter(e => e.id === extensionIdentifier); + private onEnablementChanged(extensionIdentifier: IExtensionIdentifier) { + const [extension] = this.local.filter(e => areSameExtensions(e, extensionIdentifier)); if (extension) { const globallyDisabledExtensions = this.extensionEnablementService.getGloballyDisabledExtensions(); const workspaceDisabledExtensions = this.extensionEnablementService.getWorkspaceDisabledExtensions(); - extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.id) !== -1; - extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.id) !== -1; + extension.disabledGlobally = globallyDisabledExtensions.some(disabled => areSameExtensions(disabled, extension)); + extension.disabledForWorkspace = workspaceDisabledExtensions.some(disabled => areSameExtensions(disabled, extension)); this._onChange.fire(); } } private getExtensionState(extension: Extension): ExtensionState { - if (extension.gallery && this.installing.some(e => e.extension.gallery && e.extension.gallery.id === extension.gallery.id)) { + if (extension.gallery && this.installing.some(e => e.extension.gallery && areSameExtensions(e.extension.gallery.identifier, extension.gallery.identifier))) { return ExtensionState.Installing; } @@ -781,16 +830,46 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return ExtensionState.Uninstalling; } - const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && e.gallery.id === extension.gallery.id))[0]; + const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && areSameExtensions(e.gallery.identifier, extension.gallery.identifier)))[0]; return local ? ExtensionState.Installed : ExtensionState.Uninstalled; } - private reportTelemetry(active: IActiveExtension, success: boolean): void { + private reportTelemetry(active: IActiveExtension, errorcode?: string): void { const data = active.extension.telemetryData; const duration = new Date().getTime() - active.start.getTime(); const eventName = toTelemetryEventName(active.operation); - this.telemetryService.publicLog(eventName, assign(data, { success, duration })); + /* __GDPR__ + "extensionGallery:install" : { + "success": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "errorcode": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ + /* __GDPR__ + "extensionGallery:update" : { + "success": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "errorcode": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ + /* __GDPR__ + "extensionGallery:uninstall" : { + "success": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "errorcode": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ + this.telemetryService.publicLog(eventName, assign(data, { success: !errorcode, duration, errorcode })); } private onError(err: any): void { @@ -821,7 +900,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return TPromise.as(null); } - return this.queryGallery({ names: [extensionId] }).then(result => { + return this.queryGallery({ names: [extensionId], source: 'uri' }).then(result => { if (result.total < 1) { return TPromise.as(null); } diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts index 405be3a135f..518df124a0e 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts @@ -14,10 +14,10 @@ import * as ExtensionsActions from 'vs/workbench/parts/extensions/browser/extens import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromManifest, getGalleryExtensionId, getLocalExtensionIdFromGallery } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ExtensionManagementService, getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -38,14 +38,14 @@ suite('ExtensionsActions Test', () => { let installEvent: Emitter, didInstallEvent: Emitter, - uninstallEvent: Emitter, + uninstallEvent: Emitter, didUninstallEvent: Emitter; suiteSetup(() => { installEvent = new Emitter(); didInstallEvent = new Emitter(); - uninstallEvent = new Emitter(); + uninstallEvent = new Emitter(); didUninstallEvent = new Emitter(); instantiationService = new TestInstantiationService(); @@ -53,7 +53,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); - instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, getConfiguration: () => ({}) }); + instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, onDidChangeConfiguration: () => { }, getConfiguration: () => ({}) }); instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); @@ -94,7 +94,7 @@ suite('ExtensionsActions Test', () => { const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); workbenchService.queryLocal().done(() => { - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier }))); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; assert.ok(!testObject.enabled); @@ -112,7 +112,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('Installing', testObject.label); @@ -140,8 +140,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); testObject.extension = extensions[0]; assert.ok(!testObject.enabled); done(); @@ -154,8 +154,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); testObject.extension = extensions[0]; assert.ok(!testObject.enabled); done(); @@ -175,7 +175,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('Uninstalling', testObject.label); assert.equal('extension-action uninstall uninstalling', testObject.class); @@ -219,8 +219,8 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(paged => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Uninstall', testObject.label); @@ -285,7 +285,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('Installing', testObject.label); @@ -301,7 +301,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('Uninstalling', testObject.label); assert.equal('extension-action uninstall uninstalling', testObject.class); @@ -333,7 +333,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: local.manifest.version }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: local.manifest.version }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(!testObject.enabled); done(); @@ -348,7 +348,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(!testObject.enabled); done(); @@ -363,7 +363,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(testObject.enabled); done(); @@ -378,10 +378,10 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.1' }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { - installEvent.fire({ id: local.id, gallery }); + installEvent.fire({ identifier: local.identifier, gallery }); assert.ok(!testObject.enabled); done(); }); @@ -432,7 +432,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('extension-action manage hide', testObject.class); assert.equal('', testObject.tooltip); @@ -448,8 +448,8 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('extension-action manage', testObject.class); @@ -481,7 +481,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('extension-action manage', testObject.class); @@ -510,7 +510,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when there extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -523,7 +523,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -536,8 +536,8 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when the extension is disabled in both', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -568,7 +568,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -581,7 +581,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -594,8 +594,8 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled in both', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -626,7 +626,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableAction when extension is installed and disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -639,7 +639,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableAction when extension is installed and disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -671,7 +671,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -685,7 +685,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -698,7 +698,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableForWorkspaceAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -711,7 +711,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableForWorkspaceAction when the extension is disabled workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -742,7 +742,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableGloballyAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -755,7 +755,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableGloballyAction when the extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -798,7 +798,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableAction when extension is installed and disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -811,7 +811,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableAction when extension is installed and disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -843,7 +843,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -857,7 +857,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -884,7 +884,7 @@ suite('ExtensionsActions Test', () => { const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest))); workbenchService.queryGallery().done(() => { assert.ok(testObject.enabled); done(); @@ -895,13 +895,13 @@ suite('ExtensionsActions Test', () => { test('Test UpdateAllAction when some installed extensions are outdated and some outdated are being installed', (done) => { const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; - const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; + const gallery = [aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); workbenchService.queryGallery().done(() => { - installEvent.fire({ id: local[0].id, gallery: gallery[0] }); + installEvent.fire({ identifier: local[0].identifier, gallery: gallery[0] }); assert.ok(testObject.enabled); done(); }); @@ -911,14 +911,14 @@ suite('ExtensionsActions Test', () => { test('Test UpdateAllAction when some installed extensions are outdated and all outdated are being installed', (done) => { const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; - const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; + const gallery = [aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); workbenchService.queryGallery().done(() => { - installEvent.fire({ id: local[0].id, gallery: gallery[0] }); - installEvent.fire({ id: local[1].id, gallery: gallery[1] }); + installEvent.fire({ identifier: local[0].identifier, gallery: gallery[0] }); + installEvent.fire({ identifier: local[1].identifier, gallery: gallery[1] }); assert.ok(!testObject.enabled); done(); }); @@ -938,7 +938,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -952,7 +952,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -965,8 +965,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Reload to activate', testObject.tooltip); @@ -982,11 +982,11 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); - installEvent.fire({ id, gallery }); - didInstallEvent.fire({ id, gallery, local: aLocalExtension('a', gallery, { id }) }); - uninstallEvent.fire(id); - didUninstallEvent.fire({ id }); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version) }; + installEvent.fire({ identifier: identifier, gallery }); + didInstallEvent.fire({ identifier: identifier, gallery, local: aLocalExtension('a', gallery, { identifier }) }); + uninstallEvent.fire(identifier); + didUninstallEvent.fire({ identifier: identifier }); assert.ok(!testObject.enabled); done(); @@ -1000,8 +1000,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(testObject.enabled); assert.equal('Reload to deactivate', testObject.tooltip); @@ -1017,13 +1017,13 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); const gallery = aGalleryExtension('a'); const id = getLocalExtensionIdFromGallery(gallery, gallery.version); - installEvent.fire({ id, gallery }); - didInstallEvent.fire({ id, gallery, local }); + installEvent.fire({ identifier: { id }, gallery }); + didInstallEvent.fire({ identifier: { id }, gallery, local }); assert.ok(!testObject.enabled); done(); @@ -1039,9 +1039,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { uuid: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { uuid: local.identifier.id, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Reload to update', testObject.tooltip); @@ -1053,7 +1053,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a', { version: '1.0.1' }); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1061,9 +1061,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(!testObject.enabled); done(); @@ -1105,7 +1105,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is enabled when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1123,7 +1123,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension enablement is toggled when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1140,7 +1140,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running and enabled', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a', { version: '1.0.1' }); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1148,9 +1148,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); workbenchService.setEnablement(extensions[0], true); assert.ok(testObject.enabled); @@ -1164,17 +1164,17 @@ suite('ExtensionsActions Test', () => { const localExtension = Object.create({ manifest: {} }); assign(localExtension, { type: LocalExtensionType.User, manifest: {} }, properties); assign(localExtension.manifest, { name, publisher: 'pub', version: '1.0.0' }, manifest); - localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; - localExtension.id = getLocalExtensionIdFromManifest(localExtension.manifest); + localExtension.identifier = { id: getLocalExtensionIdFromManifest(localExtension.manifest) }; + localExtension.metadata = { id: localExtension.identifier.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; return localExtension; } function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: any = {}): IGalleryExtension { const galleryExtension = Object.create({}); - assign(galleryExtension, { name, publisher: 'pub', uuid: generateUuid(), version: '1.0.0', properties: {}, assets: {} }, properties); + assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); assign(galleryExtension.assets, assets); - galleryExtension.id = getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name); + galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; return galleryExtension; } diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 3cfe083cd16..d7c1978b713 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -15,10 +15,10 @@ import { IExtensionsWorkbenchService, ExtensionState } from 'vs/workbench/parts/ import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromManifest, getGalleryExtensionId, getLocalExtensionIdFromGallery } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ExtensionManagementService, getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -40,13 +40,13 @@ suite('ExtensionsWorkbenchService Test', () => { let installEvent: Emitter, didInstallEvent: Emitter, - uninstallEvent: Emitter, + uninstallEvent: Emitter, didUninstallEvent: Emitter; suiteSetup(() => { installEvent = new Emitter(); didInstallEvent = new Emitter(); - uninstallEvent = new Emitter(); + uninstallEvent = new Emitter(); didUninstallEvent = new Emitter(); instantiationService = new TestInstantiationService(); @@ -56,7 +56,7 @@ suite('ExtensionsWorkbenchService Test', () => { instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); - instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, getConfiguration: () => ({}) }); + instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, onDidChangeConfiguration: () => { }, getConfiguration: () => ({}) }); instantiationService.stub(IExtensionManagementService, ExtensionManagementService); instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event); @@ -232,7 +232,7 @@ suite('ExtensionsWorkbenchService Test', () => { changelogUrl: 'localChangelogUrl2', }); const gallery1 = aGalleryExtension(local1.manifest.name, { - id: local1.id, + identifier: local1.identifier, displayName: 'expectedDisplayName', version: '1.5.0', publisherId: 'expectedPublisherId', @@ -309,10 +309,10 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Uninstalled, extension.state); testObject.install(extension); - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version) }; // Installing - installEvent.fire({ id, gallery }); + installEvent.fire({ identifier, gallery }); let local = testObject.local; assert.equal(1, local.length); const actual = local[0]; @@ -320,18 +320,18 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Installing, actual.state); // Installed - didInstallEvent.fire({ id, gallery, local: aLocalExtension(gallery.name, gallery, { id }) }); + didInstallEvent.fire({ identifier, gallery, local: aLocalExtension(gallery.name, gallery, { identifier }) }); assert.equal(ExtensionState.Installed, actual.state); assert.equal(1, testObject.local.length); testObject.uninstall(actual); // Uninstalling - uninstallEvent.fire(id); + uninstallEvent.fire(identifier); assert.equal(ExtensionState.Uninstalling, actual.state); // Uninstalled - didUninstallEvent.fire({ id }); + didUninstallEvent.fire({ identifier }); assert.equal(ExtensionState.Uninstalled, actual.state); assert.equal(0, testObject.local.length); @@ -341,7 +341,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test extension doesnot show outdated for system extensions', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id, version: '1.0.2' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier, version: '1.0.2' }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); assert.ok(!testObject.local[0].outdated); @@ -353,8 +353,8 @@ suite('ExtensionsWorkbenchService Test', () => { testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; testObject.uninstall(target); - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(!testObject.canInstall(target)); }); @@ -362,7 +362,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test canInstall returns false for a system extension', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; @@ -372,7 +372,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test canInstall returns true for extensions with gallery', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.User }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; @@ -392,11 +392,11 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Uninstalled, extension.state); testObject.install(extension); - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); testObject.onChange(target); // Installed - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); assert.ok(target.calledOnce); }); @@ -416,7 +416,7 @@ suite('ExtensionsWorkbenchService Test', () => { testObject.onChange(target); // Installing - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(target.calledOnce); }); @@ -430,7 +430,7 @@ suite('ExtensionsWorkbenchService Test', () => { testObject.uninstall(testObject.local[0]); testObject.onChange(target); - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(target.calledOnce); }); @@ -442,9 +442,9 @@ suite('ExtensionsWorkbenchService Test', () => { const target = sinon.spy(); testObject.uninstall(testObject.local[0]); - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); testObject.onChange(target); - didUninstallEvent.fire({ id: local.id }); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(target.calledOnce); }); @@ -692,8 +692,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are false for uninstalled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); return testObject.queryGallery().then(pagedResponse => { @@ -705,8 +705,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are false for installed enabled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -717,10 +717,10 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled for workspace is set', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.e', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.d' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.e' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -732,9 +732,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled globally is set', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.d' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -746,8 +746,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable flags are updated for user extensions', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -759,7 +759,7 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension globally when extension is disabled for workspace', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -793,12 +793,12 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are updated on change from outside', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const actual = testObject.local[0]; assert.ok(!actual.disabledForWorkspace); @@ -806,9 +806,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with dependencies disable only itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -819,9 +819,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with dependencies disable all', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); instantiationService.stubPromise(IChoiceService, 'choose', 1); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -833,9 +833,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension fails if extension is a dependent of other', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -843,9 +843,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension does not fail if its dependency is a dependent of other but chosen to disable only itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -856,9 +856,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension fails if its dependency is a dependent of other', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -868,9 +868,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependency is a dependent of other disabled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -883,9 +883,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependencys dependency is itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.a'] }), aLocalExtension('c')]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -898,9 +898,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependency is dependent and is disabled', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -912,9 +912,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with cyclic dependencies', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.c'] }), aLocalExtension('c', { extensionDependencies: ['pub.a'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -928,9 +928,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension with dependencies enable all', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -941,9 +941,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension with cyclic dependencies', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.c'] }), aLocalExtension('c', { extensionDependencies: ['pub.a'] })]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -956,8 +956,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test change event is fired when disablement flags are changed', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = sinon.spy(); @@ -969,14 +969,14 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test change event is fired when disablement flags are changed from outside', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = sinon.spy(); testObject.onChange(target); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); assert.ok(target.calledOnce); }); @@ -985,8 +985,8 @@ suite('ExtensionsWorkbenchService Test', () => { const localExtension = Object.create({ manifest: {} }); assign(localExtension, { type: LocalExtensionType.User, manifest: {} }, properties); assign(localExtension.manifest, { name, publisher: 'pub', version: '1.0.0' }, manifest); - localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; - localExtension.id = getLocalExtensionIdFromManifest(localExtension.manifest); + localExtension.identifier = { id: getLocalExtensionIdFromManifest(localExtension.manifest) }; + localExtension.metadata = { id: localExtension.identifier.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; return localExtension; } @@ -1001,10 +1001,10 @@ suite('ExtensionsWorkbenchService Test', () => { function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: IGalleryExtensionAssets = noAssets): IGalleryExtension { const galleryExtension = Object.create({}); - assign(galleryExtension, { name, publisher: 'pub', uuid: generateUuid(), version: '1.0.0', properties: {}, assets: {} }, properties); + assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); assign(galleryExtension.assets, assets); - galleryExtension.id = getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name); + galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; return galleryExtension; } diff --git a/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts b/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts index 7a93025af9d..6af8ce910c7 100644 --- a/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts +++ b/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts @@ -13,7 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import product from 'vs/platform/node/product'; import { Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; class TwitterFeedbackService implements IFeedbackService { @@ -26,7 +26,7 @@ class TwitterFeedbackService implements IFeedbackService { } public submitFeedback(feedback: IFeedback): void { - const queryString = `?${feedback.sentiment === 1 ? `hashtags=${this.combineHashTagsAsString()}&` : null}ref_src=twsrc%5Etfw&related=twitterapi%2Ctwitter&text=${feedback.feedback}&tw_p=tweetbutton&via=${TwitterFeedbackService.VIA_NAME}`; + const queryString = `?${feedback.sentiment === 1 ? `hashtags=${this.combineHashTagsAsString()}&` : null}ref_src=twsrc%5Etfw&related=twitterapi%2Ctwitter&text=${encodeURIComponent(feedback.feedback)}&tw_p=tweetbutton&via=${TwitterFeedbackService.VIA_NAME}`; const url = TwitterFeedbackService.TWITTER_URL + queryString; window.open(url); @@ -63,14 +63,14 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem { } private registerListeners(): void { - this.toUnbind.push(this.contextService.onDidChangeWorkspaceRoots(() => this.updateStyles())); + this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); } protected updateStyles(): void { super.updateStyles(); if (this.dropdown) { - this.dropdown.label.style('background-color', this.getColor(this.contextService.hasWorkspace() ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND)); + this.dropdown.label.style('background-color', this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND)); } } diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index 5b402c26afc..3fb83c894cd 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -24,13 +24,11 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CancelAction } from 'vs/platform/message/common/message'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { ScrollType } from 'vs/editor/common/editorCommon'; /** @@ -47,15 +45,13 @@ export class TextFileEditor extends BaseTextEditor { @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IStorageService storageService: IStorageService, - @IHistoryService private historyService: IHistoryService, @ITextResourceConfigurationService configurationService: ITextResourceConfigurationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IThemeService themeService: IThemeService, @IEditorGroupService editorGroupService: IEditorGroupService, - @IModeService modeService: IModeService, @ITextFileService textFileService: ITextFileService, ) { - super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService, textFileService, editorGroupService); + super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorGroupService); // Clear view state for deleted files this.toUnbind.push(this.fileService.onFileChanges(e => this.onFilesChanged(e))); @@ -87,16 +83,6 @@ export class TextFileEditor extends BaseTextEditor { public setInput(input: FileEditorInput, options?: EditorOptions): TPromise { - // We have a current input in this editor and are about to either open a new editor or jump to a different - // selection inside the editor. Thus we store the current selection into the navigation history so that - // a user can navigate back to the exact position he left off. - if (this.input) { - const selection = this.getControl().getSelection(); - if (selection) { - this.historyService.add(this.input, { selection: { startLineNumber: selection.startLineNumber, startColumn: selection.startColumn } }); - } - } - // Return early for same input unless we force to open const forceOpen = options && options.forceOpen; if (!forceOpen && input.matches(this.input)) { @@ -204,8 +190,8 @@ export class TextFileEditor extends BaseTextEditor { // Best we can do is to reveal the folder in the explorer if (this.contextService.isInsideWorkspace(input.getResource())) { - this.viewletService.openViewlet(VIEWLET_ID, true).done((viewlet: ExplorerViewlet) => { - return viewlet.getExplorerView().select(input.getResource(), true); + this.viewletService.openViewlet(VIEWLET_ID, true).done(viewlet => { + return (viewlet as ExplorerViewlet).getExplorerView().select(input.getResource(), true); }, errors.onUnexpectedError); } }, errors.onUnexpectedError); diff --git a/src/vs/workbench/parts/files/browser/explorerViewlet.ts b/src/vs/workbench/parts/files/browser/explorerViewlet.ts index 704dc4c1088..e0bb4bc7d1e 100644 --- a/src/vs/workbench/parts/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/parts/files/browser/explorerViewlet.ts @@ -12,9 +12,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as DOM from 'vs/base/browser/dom'; import { Builder } from 'vs/base/browser/builder'; import { VIEWLET_ID, ExplorerViewletVisibleContext, IFilesConfiguration, OpenEditorsVisibleContext, OpenEditorsVisibleCondition } from 'vs/workbench/parts/files/common/files'; -import { PersistentViewsViewlet, IView, IViewletViewOptions } from 'vs/workbench/parts/views/browser/views'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { PersistentViewsViewlet, ViewsViewletPanel, IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { ActionRunner, FileViewletState } from 'vs/workbench/parts/files/browser/views/explorerViewer'; import { ExplorerView, IExplorerViewOptions } from 'vs/workbench/parts/files/browser/views/explorerView'; import { EmptyView } from 'vs/workbench/parts/files/browser/views/emptyView'; @@ -22,17 +21,16 @@ import { OpenEditorsView } from 'vs/workbench/parts/files/browser/views/openEdit import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/parts/views/browser/viewsRegistry'; +import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/browser/parts/views/viewsRegistry'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; export class ExplorerViewlet extends PersistentViewsViewlet { @@ -52,7 +50,6 @@ export class ExplorerViewlet extends PersistentViewsViewlet { @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService protected instantiationService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IThemeService themeService: IThemeService, @IContextMenuService contextMenuService: IContextMenuService, @IExtensionService extensionService: IExtensionService @@ -64,27 +61,59 @@ export class ExplorerViewlet extends PersistentViewsViewlet { this.openEditorsVisibleContextKey = OpenEditorsVisibleContext.bindTo(contextKeyService); this.registerViews(); - this.onConfigurationUpdated(); - this._register(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated())); + this.updateOpenEditorsVisibility(); + + this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); this._register(this.contextService.onDidChangeWorkspaceName(e => this.updateTitleArea())); + this._register(this.contextService.onDidChangeWorkbenchState(() => this.registerViews())); + this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.registerViews())); } - public create(parent: Builder): TPromise { - return super.create(parent).then(() => DOM.addClass(this.viewletContainer, 'explorer-viewlet')); + async create(parent: Builder): TPromise { + await super.create(parent); + + const el = parent.getHTMLElement(); + DOM.addClass(el, 'explorer-viewlet'); } private registerViews(): void { - let viewDescriptors = []; + const viewDescriptors = ViewsRegistry.getViews(ViewLocation.Explorer); - viewDescriptors.push(this.createOpenEditorsViewDescriptor()); + let viewDescriptorsToRegister = []; + let viewDescriptorsToDeregister: string[] = []; - if (this.contextService.hasWorkspace()) { - viewDescriptors.push(this.createExplorerViewDescriptor()); + const openEditorsViewDescriptor = this.createOpenEditorsViewDescriptor(); + const openEditorsViewDescriptorExists = viewDescriptors.some(v => v.id === openEditorsViewDescriptor.id); + const explorerViewDescriptor = this.createExplorerViewDescriptor(); + const explorerViewDescriptorExists = viewDescriptors.some(v => v.id === explorerViewDescriptor.id); + const emptyViewDescriptor = this.createEmptyViewDescriptor(); + const emptyViewDescriptorExists = viewDescriptors.some(v => v.id === emptyViewDescriptor.id); + + if (!openEditorsViewDescriptorExists) { + viewDescriptorsToRegister.push(openEditorsViewDescriptor); + } + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY || this.contextService.getWorkspace().folders.length === 0) { + if (explorerViewDescriptorExists) { + viewDescriptorsToDeregister.push(explorerViewDescriptor.id); + } + if (!emptyViewDescriptorExists) { + viewDescriptorsToRegister.push(emptyViewDescriptor); + } } else { - viewDescriptors.push(this.createEmptyViewDescriptor()); + if (emptyViewDescriptorExists) { + viewDescriptorsToDeregister.push(emptyViewDescriptor.id); + } + if (!explorerViewDescriptorExists) { + viewDescriptorsToRegister.push(explorerViewDescriptor); + } } - ViewsRegistry.registerViews(viewDescriptors); + if (viewDescriptorsToRegister.length) { + ViewsRegistry.registerViews(viewDescriptorsToRegister); + } + if (viewDescriptorsToDeregister.length) { + ViewsRegistry.deregisterViews(viewDescriptorsToDeregister, ViewLocation.Explorer); + } } private createOpenEditorsViewDescriptor(): IViewDescriptor { @@ -121,11 +150,21 @@ export class ExplorerViewlet extends PersistentViewsViewlet { }; } - private onConfigurationUpdated(): void { - this.openEditorsVisibleContextKey.set(!this.contextService.hasWorkspace() || (this.configurationService.getConfiguration()).explorer.openEditors.visible !== 0); + private onConfigurationUpdated(e: IConfigurationChangeEvent): void { + if (e.affectsConfiguration('explorer.openEditors.visible')) { + this.updateOpenEditorsVisibility(); + } } - protected createView(viewDescriptor: IViewDescriptor, initialSize: number, options: IViewletViewOptions): IView { + private updateOpenEditorsVisibility(): void { + this.openEditorsVisibleContextKey.set(this.isOpenEditorsVisible()); + } + + private isOpenEditorsVisible(): boolean { + return this.contextService.getWorkbenchState() === WorkbenchState.EMPTY || this.configurationService.getValue('explorer.openEditors.visible') !== 0; + } + + protected createView(viewDescriptor: IViewDescriptor, options: IViewletViewOptions): ViewsViewletPanel { if (viewDescriptor.id === ExplorerView.ID) { // Create a delegating editor service for the explorer to be able to delay the refresh in the opened // editors view above. This is a workaround for being able to double click on a file to make it pinned @@ -165,9 +204,9 @@ export class ExplorerViewlet extends PersistentViewsViewlet { }); const explorerInstantiator = this.instantiationService.createChild(new ServiceCollection([IWorkbenchEditorService, delegatingEditorService])); - return explorerInstantiator.createInstance(ExplorerView, initialSize, { ...options, viewletState: this.viewletState }); + return explorerInstantiator.createInstance(ExplorerView, { ...options, viewletState: this.viewletState }); } - return super.createView(viewDescriptor, initialSize, options); + return super.createView(viewDescriptor, options); } public getExplorerView(): ExplorerView { @@ -191,28 +230,28 @@ export class ExplorerViewlet extends PersistentViewsViewlet { const hasOpenedEditors = !!this.editorGroupService.getStacksModel().activeGroup; let openEditorsView = this.getOpenEditorsView(); - if (this.lastFocusedView && this.lastFocusedView.isExpanded() && this.hasSelectionOrFocus(this.lastFocusedView)) { - if (this.lastFocusedView !== openEditorsView || hasOpenedEditors) { - this.lastFocusedView.focusBody(); + if (this.lastFocusedPanel && this.lastFocusedPanel.isExpanded() && this.hasSelectionOrFocus(this.lastFocusedPanel as ViewsViewletPanel)) { + if (this.lastFocusedPanel !== openEditorsView || hasOpenedEditors) { + this.lastFocusedPanel.focus(); return; } } if (this.hasSelectionOrFocus(openEditorsView) && hasOpenedEditors) { - return openEditorsView.focusBody(); + return openEditorsView.focus(); } let explorerView = this.getExplorerView(); if (this.hasSelectionOrFocus(explorerView)) { - return explorerView.focusBody(); + return explorerView.focus(); } if (openEditorsView && openEditorsView.isExpanded() && hasOpenedEditors) { - return openEditorsView.focusBody(); // we have entries in the opened editors view to focus on + return openEditorsView.focus(); // we have entries in the opened editors view to focus on } if (explorerView && explorerView.isExpanded()) { - return explorerView.focusBody(); + return explorerView.focus(); } let emptyView = this.getEmptyView(); @@ -223,7 +262,7 @@ export class ExplorerViewlet extends PersistentViewsViewlet { super.focus(); } - private hasSelectionOrFocus(view: IView): boolean { + private hasSelectionOrFocus(view: ViewsViewletPanel): boolean { if (!view) { return false; } @@ -255,4 +294,13 @@ export class ExplorerViewlet extends PersistentViewsViewlet { public getViewletState(): FileViewletState { return this.viewletState; } + + protected loadViewsStates(): void { + super.loadViewsStates(); + + // Remove the open editors view state if it is removed globally + if (!this.isOpenEditorsVisible()) { + this.viewsStates.delete(OpenEditorsView.ID); + } + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index 28b7e4920f9..2dddb2c5105 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -7,33 +7,28 @@ import nls = require('vs/nls'); import { Registry } from 'vs/platform/registry/common/platform'; import { Action, IAction } from 'vs/base/common/actions'; -import { isMacintosh } from 'vs/base/common/platform'; import { ActionItem, BaseActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions'; -import { GlobalNewUntitledFileAction, SaveFileAsAction, OpenFileAction, ShowOpenedFileInNewWindow, CopyPathAction, GlobalCopyPathAction, RevealInOSAction, GlobalRevealInOSAction, pasteIntoFocusedFilesExplorerViewItem, FocusOpenEditorsView, FocusFilesExplorer, GlobalCompareResourcesAction, GlobalNewFileAction, GlobalNewFolderAction, RevertFileAction, SaveFilesAction, SaveAllAction, SaveFileAction, MoveFileToTrashAction, TriggerRenameFileAction, PasteFileAction, CopyFileAction, SelectResourceForCompareAction, CompareResourcesAction, NewFolderAction, NewFileAction, OpenToSideAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithSavedAction } from 'vs/workbench/parts/files/browser/fileActions'; +import { GlobalNewUntitledFileAction, SaveFileAsAction, ShowOpenedFileInNewWindow, CopyPathAction, GlobalCopyPathAction, RevealInOSAction, GlobalRevealInOSAction, pasteIntoFocusedFilesExplorerViewItem, FocusOpenEditorsView, FocusFilesExplorer, GlobalCompareResourcesAction, GlobalNewFileAction, GlobalNewFolderAction, RevertFileAction, SaveFilesAction, SaveAllAction, SaveFileAction, MoveFileToTrashAction, TriggerRenameFileAction, PasteFileAction, CopyFileAction, SelectResourceForCompareAction, CompareResourcesAction, NewFolderAction, NewFileAction, OpenToSideAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithSavedAction } from 'vs/workbench/parts/files/browser/fileActions'; import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/parts/files/browser/saveErrorHandler'; import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { FileStat, Model } from 'vs/workbench/parts/files/common/explorerModel'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; -import { OpenFolderAction, OpenFileFolderAction, AddRootFolderAction, RemoveRootFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; -import { copyFocusedFilesExplorerViewItem, revealInOSFocusedFilesExplorerItem, openFocusedExplorerItemSideBySideCommand, copyPathOfFocusedExplorerItem, copyPathCommand, revealInExplorerCommand, revealInOSCommand, openFolderPickerCommand, openWindowCommand, openFileInNewWindowCommand, deleteFocusedFilesExplorerViewItemCommand, moveFocusedFilesExplorerViewItemToTrashCommand, renameFocusedFilesExplorerViewItemCommand } from 'vs/workbench/parts/files/browser/fileCommands'; +import { AddRootFolderAction, RemoveRootFolderAction, OpenFolderSettingsAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { copyFocusedFilesExplorerViewItem, revealInOSFocusedFilesExplorerItem, openFocusedExplorerItemSideBySideCommand, copyPathOfFocusedExplorerItem, copyPathCommand, revealInExplorerCommand, revealInOSCommand, openWindowCommand, deleteFocusedFilesExplorerViewItemCommand, moveFocusedFilesExplorerViewItemToTrashCommand, renameFocusedFilesExplorerViewItemCommand } from 'vs/workbench/parts/files/browser/fileCommands'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { explorerItemToFileResource, ExplorerFocusCondition, FilesExplorerFocusCondition } from 'vs/workbench/parts/files/common/files'; class FilesViewerActionContributor extends ActionBarContributor { constructor( @IInstantiationService private instantiationService: IInstantiationService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IKeybindingService private keybindingService: IKeybindingService, - @IEnvironmentService private environmentService: IEnvironmentService + @IKeybindingService private keybindingService: IKeybindingService ) { super(); } @@ -65,7 +60,7 @@ class FilesViewerActionContributor extends ActionBarContributor { } // Directory Actions - if (stat.isDirectory && stat.exists) { + if (stat.isDirectory && !stat.nonexistentRoot) { // New File actions.push(this.instantiationService.createInstance(NewFileAction, tree, stat)); @@ -91,16 +86,20 @@ class FilesViewerActionContributor extends ActionBarContributor { actions.push(new Separator(null, 100)); } - if (stat.isRoot && this.environmentService.appQuality !== 'stable') { - let action: Action = this.instantiationService.createInstance(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL); - action.order = 52; - actions.push(action); - if (this.contextService.getWorkspace().roots.length > 1) { - action = this.instantiationService.createInstance(RemoveRootFolderAction, stat.resource, RemoveRootFolderAction.ID, RemoveRootFolderAction.LABEL); - action.order = 53; - actions.push(action); - } - actions.push(new Separator(null, 54)); + // Workspace Root Folder Actions + if (stat.isRoot) { + const addRootFolderAction: Action = this.instantiationService.createInstance(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL); + addRootFolderAction.order = 52; + actions.push(addRootFolderAction); + + const openFolderSettingsActions = this.instantiationService.createInstance(OpenFolderSettingsAction, stat.resource, OpenFolderSettingsAction.ID, OpenFolderSettingsAction.LABEL); + openFolderSettingsActions.order = 53; + actions.push(openFolderSettingsActions); + const removeRootFolderAction = this.instantiationService.createInstance(RemoveRootFolderAction, stat.resource, RemoveRootFolderAction.ID, RemoveRootFolderAction.LABEL); + removeRootFolderAction.order = 54; + actions.push(removeRootFolderAction); + + actions.push(new Separator(null, 55)); } // Copy File/Folder @@ -165,18 +164,17 @@ class ExplorerViewersActionContributor extends ActionBarContributor { public getSecondaryActions(context: any): IAction[] { const actions: IAction[] = []; + const fileResource = explorerItemToFileResource(context.element); + const resource = fileResource.resource; - if (this.hasSecondaryActions(context)) { - const fileResource = explorerItemToFileResource(context.element); - const resource = fileResource.resource; - - // Reveal file in OS native explorer + // Reveal file in OS native explorer + if (resource.scheme === 'file') { actions.push(this.instantiationService.createInstance(RevealInOSAction, resource)); - - // Copy Path - actions.push(this.instantiationService.createInstance(CopyPathAction, resource)); } + // Copy Path + actions.push(this.instantiationService.createInstance(CopyPathAction, resource)); + return actions; } } @@ -187,39 +185,30 @@ actionBarRegistry.registerActionBarContributor(Scope.VIEWER, FilesViewerActionCo actionBarRegistry.registerActionBarContributor(Scope.VIEWER, ExplorerViewersActionContributor); // Contribute Global Actions -const category = nls.localize('filesCategory', "Files"); +const category = nls.localize('filesCategory', "File"); const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCopyPathAction, GlobalCopyPathAction.ID, GlobalCopyPathAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_P) }), 'Files: Copy Path of Active File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_S }), 'Files: Save', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: void 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'Files: Save All', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFilesAction, SaveFilesAction.ID, null /* only for programmatic trigger */), null); -registry.registerWorkbenchAction(new SyncActionDescriptor(RevertFileAction, RevertFileAction.ID, RevertFileAction.LABEL), 'Files: Revert File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFileAction, GlobalNewFileAction.ID, GlobalNewFileAction.LABEL), 'Files: New File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFolderAction, GlobalNewFolderAction.ID, GlobalNewFolderAction.LABEL), 'Files: New Folder', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCompareResourcesAction, GlobalCompareResourcesAction.ID, GlobalCompareResourcesAction.LABEL), 'Files: Compare Active File With...', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusOpenEditorsView, FocusOpenEditorsView.ID, FocusOpenEditorsView.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_E) }), 'Files: Focus on Open Editors View', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(FocusFilesExplorer, FocusFilesExplorer.ID, FocusFilesExplorer.LABEL), 'Files: Focus on Files Explorer', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowActiveFileInExplorer, ShowActiveFileInExplorer.ID, ShowActiveFileInExplorer.LABEL), 'Files: Reveal Active File in Side Bar', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'Files: Collapse Folders in Explorer', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), 'Files: Refresh Explorer', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAsAction, SaveFileAsAction.ID, SaveFileAsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S }), 'Files: Save As...', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'Files: New Untitled File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRevealInOSAction, GlobalRevealInOSAction.ID, GlobalRevealInOSAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R) }), 'Files: Reveal Active File', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'Files: Open Active File in New Window', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithSavedAction, CompareWithSavedAction.ID, CompareWithSavedAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D) }), 'Files: Compare Active File with Saved', category); - -if (isMacintosh) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'Files: Open...', category); -} else { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'Files: Open File...', category); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'Files: Open Folder...', category); -} +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCopyPathAction, GlobalCopyPathAction.ID, GlobalCopyPathAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_P) }), 'File: Copy Path of Active File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_S }), 'File: Save', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: void 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'File: Save All', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFilesAction, SaveFilesAction.ID, SaveFilesAction.LABEL), 'File: Save All Files', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(RevertFileAction, RevertFileAction.ID, RevertFileAction.LABEL), 'File: Revert File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFileAction, GlobalNewFileAction.ID, GlobalNewFileAction.LABEL), 'File: New File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFolderAction, GlobalNewFolderAction.ID, GlobalNewFolderAction.LABEL), 'File: New Folder', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCompareResourcesAction, GlobalCompareResourcesAction.ID, GlobalCompareResourcesAction.LABEL), 'File: Compare Active File With...', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusOpenEditorsView, FocusOpenEditorsView.ID, FocusOpenEditorsView.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_E) }), 'File: Focus on Open Editors View', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(FocusFilesExplorer, FocusFilesExplorer.ID, FocusFilesExplorer.LABEL), 'File: Focus on Files Explorer', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(ShowActiveFileInExplorer, ShowActiveFileInExplorer.ID, ShowActiveFileInExplorer.LABEL), 'File: Reveal Active File in Side Bar', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'File: Collapse Folders in Explorer', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), 'File: Refresh Explorer', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAsAction, SaveFileAsAction.ID, SaveFileAsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S }), 'File: Save As...', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'File: New Untitled File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRevealInOSAction, GlobalRevealInOSAction.ID, GlobalRevealInOSAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R) }), 'File: Reveal Active File', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithSavedAction, CompareWithSavedAction.ID, CompareWithSavedAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D) }), 'File: Compare Active File with Saved', category); // Commands -CommandsRegistry.registerCommand('_files.pickFolderAndOpen', openFolderPickerCommand); CommandsRegistry.registerCommand('_files.windowOpen', openWindowCommand); -CommandsRegistry.registerCommand('workbench.action.files.openFileInNewWindow', openFileInNewWindowCommand); const explorerCommandsWeightBonus = 10; // give our commands a little bit more weight over other default list/tree commands diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 3c609e62030..ccc0d2ba899 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -11,6 +11,7 @@ import nls = require('vs/nls'); import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { sequence, ITask } from 'vs/base/common/async'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); import { toErrorMessage } from 'vs/base/common/errorMessage'; @@ -26,7 +27,7 @@ import { VIEWLET_ID, FileOnDiskContentProvider } from 'vs/workbench/parts/files/ import labels = require('vs/base/common/labels'); import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService, IFileStat } from 'vs/platform/files/common/files'; -import { toResource, IEditorIdentifier, EditorInput } from 'vs/workbench/common/editor'; +import { toResource, IEditorIdentifier } from 'vs/workbench/common/editor'; import { FileStat, Model, NewStatPlaceholder } from 'vs/workbench/parts/files/common/explorerModel'; import { ExplorerView } from 'vs/workbench/parts/files/browser/views/explorerView'; import { ExplorerViewlet } from 'vs/workbench/parts/files/browser/explorerViewlet'; @@ -34,21 +35,21 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CollapseAction } from 'vs/workbench/browser/viewlet'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IQuickOpenService, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { Position, IResourceInput, IEditorInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; +import { Position, IResourceInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature2, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction } from 'vs/platform/message/common/message'; +import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction, IConfirmationResult } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import { withFocusedFilesExplorer, revealInOSCommand, revealInExplorerCommand, copyPathCommand } from 'vs/workbench/parts/files/browser/fileCommands'; -import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { once } from 'vs/base/common/event'; export interface IEditableData { action: IAction; @@ -296,22 +297,20 @@ class RenameFileAction extends BaseRenameAction { } public runAction(newName: string): TPromise { - - const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, this.element.resource.fsPath, !isLinux /* ignorecase */)); + const dirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, this.element.resource, !isLinux /* ignorecase */)); const dirtyRenamed: URI[] = []; return TPromise.join(dirty.map(d => { - - const targetPath = paths.join(this.element.parent.resource.fsPath, newName); let renamed: URI; // If the dirty file itself got moved, just reparent it to the target folder - if (paths.isEqual(this.element.resource.fsPath, d.fsPath)) { - renamed = URI.file(targetPath); + const targetPath = paths.join(this.element.parent.resource.path, newName); + if (this.element.resource.toString() === d.toString()) { + renamed = this.element.parent.resource.with({ path: targetPath }); } // Otherwise, a parent of the dirty resource got moved, so we have to reparent more complicated. Example: else { - renamed = URI.file(paths.join(targetPath, d.fsPath.substr(this.element.resource.fsPath.length + 1))); + renamed = this.element.parent.resource.with({ path: paths.join(targetPath, d.path.substr(this.element.resource.path.length + 1)) }); } dirtyRenamed.push(renamed); @@ -498,7 +497,7 @@ export abstract class BaseGlobalNewAction extends Action { } if (!explorerView.isExpanded()) { - explorerView.expand(); + explorerView.setExpanded(true); } const action = this.toDispose = this.instantiationService.createInstance(this.getAction(), explorerView.getViewer(), null); @@ -589,7 +588,8 @@ export class CreateFileAction extends BaseCreateAction { } public runAction(fileName: string): TPromise { - return this.fileService.createFile(URI.file(paths.join(this.element.parent.resource.fsPath, fileName))).then(stat => { + const resource = this.element.parent.resource; + return this.fileService.createFile(resource.with({ path: paths.join(resource.path, fileName) })).then(stat => { return this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }); }, (error) => { this.onErrorWithRetry(error, () => this.runAction(fileName)); @@ -615,13 +615,17 @@ export class CreateFolderAction extends BaseCreateAction { } public runAction(fileName: string): TPromise { - return this.fileService.createFolder(URI.file(paths.join(this.element.parent.resource.fsPath, fileName))).then(null, (error) => { + const resource = this.element.parent.resource; + return this.fileService.createFolder(resource.with({ path: paths.join(resource.path, fileName) })).then(null, (error) => { this.onErrorWithRetry(error, () => this.runAction(fileName)); }); } } export class BaseDeleteFileAction extends BaseFileAction { + + private static CONFIRM_DELETE_SETTING_KEY = 'explorer.confirmDelete'; + private tree: ITree; private useTrash: boolean; private skipConfirm: boolean; @@ -634,7 +638,8 @@ export class BaseDeleteFileAction extends BaseFileAction { useTrash: boolean, @IFileService fileService: IFileService, @IMessageService messageService: IMessageService, - @ITextFileService textFileService: ITextFileService + @ITextFileService textFileService: ITextFileService, + @IConfigurationService private configurationService: IConfigurationService ) { super(id, label, fileService, messageService, textFileService); @@ -673,7 +678,7 @@ export class BaseDeleteFileAction extends BaseFileAction { // Handle dirty let revertPromise: TPromise = TPromise.as(null); - const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, this.element.resource.fsPath, !isLinux /* ignorecase */)); + const dirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, this.element.resource, !isLinux /* ignorecase */)); if (dirty.length) { let message: string; if (this.element.isDirectory) { @@ -686,7 +691,7 @@ export class BaseDeleteFileAction extends BaseFileAction { message = nls.localize('dirtyMessageFileDelete', "You are deleting a file with unsaved changes. Do you want to continue?"); } - const res = this.messageService.confirm({ + const res = this.messageService.confirmSync({ message, type: 'warning', detail: nls.localize('dirtyWarning', "Your changes will be lost if you don't save them."), @@ -703,51 +708,73 @@ export class BaseDeleteFileAction extends BaseFileAction { // Check if file is dirty in editor and save it to avoid data loss return revertPromise.then(() => { + let confirmPromise: TPromise; - // Ask for Confirm - if (!this.skipConfirm) { - let confirm: IConfirmation; - if (this.useTrash) { - confirm = { - message: this.element.isDirectory ? nls.localize('confirmMoveTrashMessageFolder', "Are you sure you want to delete '{0}' and its contents?", this.element.name) : nls.localize('confirmMoveTrashMessageFile', "Are you sure you want to delete '{0}'?", this.element.name), - detail: isWindows ? nls.localize('undoBin', "You can restore from the recycle bin.") : nls.localize('undoTrash', "You can restore from the trash."), - primaryButton, - type: 'question' - }; - } else { - confirm = { - message: this.element.isDirectory ? nls.localize('confirmDeleteMessageFolder', "Are you sure you want to permanently delete '{0}' and its contents?", this.element.name) : nls.localize('confirmDeleteMessageFile', "Are you sure you want to permanently delete '{0}'?", this.element.name), - detail: nls.localize('irreversible', "This action is irreversible!"), - primaryButton, - type: 'warning' - }; - } - - if (!this.messageService.confirm(confirm)) { - return TPromise.as(null); - } + // Check if we need to ask for confirmation at all + if (this.skipConfirm || (this.useTrash && this.configurationService.getValue(BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY) === false)) { + confirmPromise = TPromise.as({ confirmed: true } as IConfirmationResult); } - // Call function - const servicePromise = this.fileService.del(this.element.resource, this.useTrash).then(() => { - if (this.element.parent) { - this.tree.setFocus(this.element.parent); // move focus to parent - } - }, (error: any) => { + // Confirm for moving to trash + else if (this.useTrash) { + confirmPromise = this.messageService.confirm({ + message: this.element.isDirectory ? nls.localize('confirmMoveTrashMessageFolder', "Are you sure you want to delete '{0}' and its contents?", this.element.name) : nls.localize('confirmMoveTrashMessageFile', "Are you sure you want to delete '{0}'?", this.element.name), + detail: isWindows ? nls.localize('undoBin', "You can restore from the recycle bin.") : nls.localize('undoTrash', "You can restore from the trash."), + primaryButton, + checkbox: { + label: nls.localize('doNotAskAgain', "Do not ask me again") + }, + type: 'question' + }); + } - // Allow to retry - let extraAction: Action; - if (this.useTrash) { - extraAction = new Action('permanentDelete', nls.localize('permDelete', "Delete Permanently"), null, true, () => { this.useTrash = false; this.skipConfirm = true; return this.run(); }); + // Confirm for deleting permanently + else { + confirmPromise = this.messageService.confirm({ + message: this.element.isDirectory ? nls.localize('confirmDeleteMessageFolder', "Are you sure you want to permanently delete '{0}' and its contents?", this.element.name) : nls.localize('confirmDeleteMessageFile', "Are you sure you want to permanently delete '{0}'?", this.element.name), + detail: nls.localize('irreversible', "This action is irreversible!"), + primaryButton, + type: 'warning' + }); + } + + return confirmPromise.then(confirmation => { + + // Check for confirmation checkbox + let updateConfirmSettingsPromise: TPromise = TPromise.as(void 0); + if (confirmation.confirmed && confirmation.checkboxChecked === true) { + updateConfirmSettingsPromise = this.configurationService.updateValue(BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY, false, ConfigurationTarget.USER); } - this.onErrorWithRetry(error, () => this.run(), extraAction); + return updateConfirmSettingsPromise.then(() => { - // Focus back to tree - this.tree.DOMFocus(); + // Check for confirmation + if (!confirmation.confirmed) { + return TPromise.as(null); + } + + // Call function + const servicePromise = this.fileService.del(this.element.resource, this.useTrash).then(() => { + if (this.element.parent) { + this.tree.setFocus(this.element.parent); // move focus to parent + } + }, (error: any) => { + + // Allow to retry + let extraAction: Action; + if (this.useTrash) { + extraAction = new Action('permanentDelete', nls.localize('permDelete', "Delete Permanently"), null, true, () => { this.useTrash = false; this.skipConfirm = true; return this.run(); }); + } + + this.onErrorWithRetry(error, () => this.run(), extraAction); + + // Focus back to tree + this.tree.DOMFocus(); + }); + + return servicePromise; + }); }); - - return servicePromise; }); } } @@ -761,9 +788,10 @@ export class MoveFileToTrashAction extends BaseDeleteFileAction { element: FileStat, @IFileService fileService: IFileService, @IMessageService messageService: IMessageService, - @ITextFileService textFileService: ITextFileService + @ITextFileService textFileService: ITextFileService, + @IConfigurationService configurationService: IConfigurationService ) { - super(MoveFileToTrashAction.ID, nls.localize('delete', "Delete"), tree, element, true, fileService, messageService, textFileService); + super(MoveFileToTrashAction.ID, nls.localize('delete', "Delete"), tree, element, true, fileService, messageService, textFileService, configurationService); } } @@ -798,10 +826,9 @@ export class ImportFileAction extends BaseFileAction { return this.tree; } - public run(context?: any): TPromise { + public run(resources: URI[]): TPromise { const importPromise = TPromise.as(null).then(() => { - const input = context.input as { paths: string[] }; - if (input.paths && input.paths.length > 0) { + if (resources && resources.length > 0) { // Find parent for import let targetElement: FileStat; @@ -826,8 +853,8 @@ export class ImportFileAction extends BaseFileAction { }); let overwrite = true; - if (input.paths.some(path => { - return !!targetNames[isLinux ? paths.basename(path) : paths.basename(path).toLowerCase()]; + if (resources.some(resource => { + return !!targetNames[isLinux ? paths.basename(resource.fsPath) : paths.basename(resource.fsPath).toLowerCase()]; })) { const confirm: IConfirmation = { message: nls.localize('confirmOverwrite', "A file or folder with the same name already exists in the destination folder. Do you want to replace it?"), @@ -836,7 +863,7 @@ export class ImportFileAction extends BaseFileAction { type: 'warning' }; - overwrite = this.messageService.confirm(confirm); + overwrite = this.messageService.confirmSync(confirm); } if (!overwrite) { @@ -845,10 +872,10 @@ export class ImportFileAction extends BaseFileAction { // Run import in sequence const importPromisesFactory: ITask>[] = []; - input.paths.forEach(path => { + resources.forEach(resource => { importPromisesFactory.push(() => { - const sourceFile = URI.file(path); - const targetFile = URI.file(paths.join(targetElement.resource.fsPath, paths.basename(path))); + const sourceFile = resource; + const targetFile = targetElement.resource.with({ path: paths.join(targetElement.resource.path, paths.basename(sourceFile.path)) }); // if the target exists and is dirty, make sure to revert it. otherwise the dirty contents // of the target file would replace the contents of the imported file. since we already @@ -862,7 +889,7 @@ export class ImportFileAction extends BaseFileAction { return this.fileService.importFile(sourceFile, targetElement.resource).then(res => { // if we only import one file, just open it directly - if (input.paths.length === 1) { + if (resources.length === 1) { this.editorService.openEditor({ resource: res.stat.resource, options: { pinned: true } }).done(null, errors.onUnexpectedError); } }, error => this.onError(error)); @@ -964,7 +991,7 @@ export class PasteFileAction extends BaseFileAction { } // Check if target is ancestor of pasted folder - if (!paths.isEqual(this.element.resource.fsPath, fileToCopy.resource.fsPath) && paths.isEqualOrParent(this.element.resource.fsPath, fileToCopy.resource.fsPath, !isLinux /* ignorecase */)) { + if (this.element.resource.toString() !== fileToCopy.resource.toString() && resources.isEqualOrParent(this.element.resource, fileToCopy.resource, !isLinux /* ignorecase */)) { return false; } @@ -1047,14 +1074,14 @@ export class DuplicateFileAction extends BaseFileAction { private findTarget(): URI { let name = this.element.name; - let candidate = URI.file(paths.join(this.target.resource.fsPath, name)); + let candidate = this.target.resource.with({ path: paths.join(this.target.resource.path, name) }); while (true) { if (!this.element.root.find(candidate)) { break; } name = this.toCopyName(name, this.element.isDirectory); - candidate = URI.file(paths.join(this.target.resource.fsPath, name)); + candidate = this.target.resource.with({ path: paths.join(this.target.resource.path, name) }); } return candidate; @@ -1166,64 +1193,34 @@ export class GlobalCompareResourcesAction extends Action { id: string, label: string, @IQuickOpenService private quickOpenService: IQuickOpenService, - @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IHistoryService private historyService: IHistoryService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @IMessageService private messageService: IMessageService, - @IEnvironmentService private environmentService: IEnvironmentService + @IEditorGroupService private editorGroupService: IEditorGroupService ) { super(id, label); } public run(): TPromise { - const activeResource = toResource(this.editorService.getActiveEditorInput(), { filter: ['file', 'untitled'] }); + const activeInput = this.editorService.getActiveEditorInput(); + const activeResource = activeInput ? activeInput.getResource() : void 0; if (activeResource) { - // Keep as resource to compare - globalResourceToCompare = activeResource; - - // Pick another entry from history - interface IHistoryPickEntry extends IFilePickOpenEntry { - input: IEditorInput | IResourceInput; - } - - const history = this.historyService.getHistory(); - const picks: IHistoryPickEntry[] = history.map(input => { - let resource: URI; - let label: string; - let description: string; - - if (input instanceof EditorInput) { - resource = toResource(input, { filter: ['file', 'untitled'] }); - } else { - resource = (input as IResourceInput).resource; + // Compare with next editor that opens + const unbind = once(this.editorGroupService.onEditorOpening)(e => { + const resource = e.input.getResource(); + if (resource) { + e.prevent(() => { + return this.editorService.openEditor({ + leftResource: activeResource, + rightResource: resource + }); + }); } + }); - // Cannot compare file with self - exclude active file - if (!!resource && resource.toString() === globalResourceToCompare.toString()) { - return void 0; - } - - if (!resource) { - return void 0; // only support to compare with files and untitled - } - - label = paths.basename(resource.fsPath); - description = resource.scheme === 'file' ? labels.getPathLabel(paths.dirname(resource.fsPath), this.contextService, this.environmentService) : void 0; - - return { input, resource, label, description }; - }).filter(p => !!p); - - return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickHistory', "Select a previously opened file to compare with"), autoFocus: { autoFocusFirstEntry: true }, matchOnDescription: true }).then(pick => { - if (pick) { - const compareAction = this.instantiationService.createInstance(CompareResourcesAction, pick.resource, null); - if (compareAction._isEnabled()) { - compareAction.run().done(() => compareAction.dispose()); - } else { - this.messageService.show(Severity.Info, nls.localize('unableToFileToCompare', "The selected file can not be compared with '{0}'.", paths.basename(globalResourceToCompare.fsPath))); - } - } + // Bring up quick open + this.quickOpenService.show('', { autoFocus: { autoFocusSecondEntry: true } }).then(() => { + unbind.dispose(); // make sure to unbind if quick open is closing }); } else { this.messageService.show(Severity.Info, nls.localize('openFileToCompare', "Open a file first to compare it with another file.")); @@ -1259,8 +1256,8 @@ export class CompareResourcesAction extends Action { // If the file names are identical, add more context by looking at the parent folder if (leftResourceName === rightResourceName) { const folderPaths = labels.shorten([ - labels.getPathLabel(paths.dirname(globalResourceToCompare.fsPath), contextService, environmentService), - labels.getPathLabel(paths.dirname(resource.fsPath), contextService, environmentService) + labels.getPathLabel(resources.dirname(globalResourceToCompare), contextService, environmentService), + labels.getPathLabel(resources.dirname(resource), contextService, environmentService) ]); leftResourceName = paths.join(folderPaths[0], leftResourceName); @@ -1273,7 +1270,7 @@ export class CompareResourcesAction extends Action { return nls.localize('compareFiles', "Compare Files"); } - _isEnabled(): boolean { + public _isEnabled(): boolean { // Need at least a resource to compare if (!globalResourceToCompare) { @@ -1352,7 +1349,8 @@ export abstract class BaseSaveOneFileAction extends BaseSaveFileAction { @ITextFileService private textFileService: ITextFileService, @IEditorGroupService private editorGroupService: IEditorGroupService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IMessageService messageService: IMessageService + @IMessageService messageService: IMessageService, + @IFileService private fileService: IFileService ) { super(id, label, messageService); @@ -1370,10 +1368,10 @@ export abstract class BaseSaveOneFileAction extends BaseSaveFileAction { if (this.resource) { source = this.resource; } else { - source = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: ['file', 'untitled'] }); + source = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true }); } - if (source) { + if (source && (this.fileService.canHandleResource(source) || source.scheme === 'untitled')) { // Save As (or Save untitled with associated path) if (this.isSaveAs() || source.scheme === 'untitled') { @@ -1389,8 +1387,8 @@ export abstract class BaseSaveOneFileAction extends BaseSaveFileAction { const activeEditor = this.editorService.getActiveEditor(); const editor = getCodeEditor(activeEditor); if (editor) { - const activeResource = toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] }); - if (activeResource && activeResource.toString() === source.toString()) { + const activeResource = toResource(activeEditor.input, { supportSideBySide: true }); + if (activeResource && (this.fileService.canHandleResource(activeResource) || source.scheme === 'untitled') && activeResource.toString() === source.toString()) { viewStateOfSource = editor.saveViewState(); } } @@ -1480,7 +1478,8 @@ export abstract class BaseSaveAllAction extends BaseSaveFileAction { @IEditorGroupService private editorGroupService: IEditorGroupService, @ITextFileService private textFileService: ITextFileService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IMessageService messageService: IMessageService + @IMessageService messageService: IMessageService, + @IFileService protected fileService: IFileService ) { super(id, label, messageService); @@ -1632,8 +1631,8 @@ export class SaveAllInGroupAction extends BaseSaveAllAction { const editorGroup = editorIdentifier.group; const resourcesToSave: URI[] = []; editorGroup.getEditors().forEach(editor => { - const resource = toResource(editor, { supportSideBySide: true, filter: ['file', 'untitled'] }); - if (resource) { + const resource = toResource(editor, { supportSideBySide: true }); + if (resource && (resource.scheme === 'untitled' || this.fileService.canHandleResource(resource))) { resourcesToSave.push(resource); } }); @@ -1649,7 +1648,7 @@ export class SaveAllInGroupAction extends BaseSaveAllAction { export class SaveFilesAction extends BaseSaveAllAction { public static ID = 'workbench.action.files.saveFiles'; - public static LABEL = nls.localize('saveFiles', "Save Dirty Files"); + public static LABEL = nls.localize('saveFiles', "Save All Files"); protected getSaveAllArguments(): boolean { return this.includeUntitled(); @@ -1715,7 +1714,7 @@ export class FocusOpenEditorsView extends Action { return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { const openEditorsView = viewlet.getOpenEditorsView(); if (openEditorsView) { - openEditorsView.expand(); + openEditorsView.setExpanded(true); openEditorsView.getViewer().DOMFocus(); } }); @@ -1739,7 +1738,7 @@ export class FocusFilesExplorer extends Action { return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { const view = viewlet.getExplorerView(); if (view) { - view.expand(); + view.setExpanded(true); view.getViewer().DOMFocus(); } }); @@ -1762,9 +1761,9 @@ export class ShowActiveFileInExplorer extends Action { } public run(): TPromise { - const fileResource = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' }); - if (fileResource) { - this.instantiationService.invokeFunction.apply(this.instantiationService, [revealInExplorerCommand, fileResource]); + const resource = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true }); + if (resource) { + this.instantiationService.invokeFunction.apply(this.instantiationService, [revealInExplorerCommand, resource]); } else { this.messageService.show(severity.Info, nls.localize('openFileToShow', "Open a file first to show it in the explorer")); } @@ -1824,27 +1823,6 @@ export class RefreshExplorerView extends Action { } } -export class OpenFileAction extends Action { - - static ID = 'workbench.action.files.openFile'; - static LABEL = nls.localize('openFile', "Open File..."); - - constructor( - id: string, - label: string, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IWindowService private windowService: IWindowService - ) { - super(id, label); - } - - run(event?: any, data?: ITelemetryData): TPromise { - const fileResource = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' }); - - return this.windowService.pickFileAndOpen({ telemetryExtraData: data, dialogOptions: { defaultPath: fileResource ? paths.dirname(fileResource.fsPath) : void 0 } }); - } -} - export class ShowOpenedFileInNewWindow extends Action { public static ID = 'workbench.action.files.showOpenedFileInNewWindow'; @@ -1900,9 +1878,7 @@ export class GlobalRevealInOSAction extends Action { constructor( id: string, label: string, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IInstantiationService private instantiationService: IInstantiationService, - @IMessageService private messageService: IMessageService + @IInstantiationService private instantiationService: IInstantiationService ) { super(id, label); } @@ -1942,9 +1918,6 @@ export class GlobalCopyPathAction extends Action { constructor( id: string, label: string, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IEditorGroupService private editorGroupService: IEditorGroupService, - @IMessageService private messageService: IMessageService, @IInstantiationService private instantiationService: IInstantiationService ) { super(id, label); @@ -1982,20 +1955,28 @@ export function validateFileName(parent: IFileStat, name: string, allowOverwriti // Invalid File name if (!paths.isValidBasename(name)) { - return nls.localize('invalidFileNameError', "The name **{0}** is not valid as a file or folder name. Please choose a different name.", name); + return nls.localize('invalidFileNameError', "The name **{0}** is not valid as a file or folder name. Please choose a different name.", trimLongName(name)); } // Max length restriction (on Windows) if (isWindows) { const fullPathLength = name.length + parent.resource.fsPath.length + 1 /* path segment */; if (fullPathLength > 255) { - return nls.localize('filePathTooLongError', "The name **{0}** results in a path that is too long. Please choose a shorter name.", name); + return nls.localize('filePathTooLongError', "The name **{0}** results in a path that is too long. Please choose a shorter name.", trimLongName(name)); } } return null; } +function trimLongName(name: string): string { + if (name && name.length > 255) { + return `${name.substr(0, 255)}...`; + } + + return name; +} + export function getWellFormedFileName(filename: string): string { if (!filename) { return filename; diff --git a/src/vs/workbench/parts/files/browser/fileCommands.ts b/src/vs/workbench/parts/files/browser/fileCommands.ts index f33e0388704..8a0a4629dc2 100644 --- a/src/vs/workbench/parts/files/browser/fileCommands.ts +++ b/src/vs/workbench/parts/files/browser/fileCommands.ts @@ -12,7 +12,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { toResource } from 'vs/workbench/common/editor'; -import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -22,9 +22,9 @@ import { FileStat, OpenEditor } from 'vs/workbench/parts/files/common/explorerMo import errors = require('vs/base/common/errors'); import { ITree } from 'vs/base/parts/tree/browser/tree'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import labels = require('vs/base/common/labels'); import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IMessageService } from 'vs/platform/message/common/message'; +import { getPathLabel } from 'vs/base/common/labels'; // Commands @@ -36,7 +36,7 @@ export const copyPathCommand = (accessor: ServicesAccessor, resource?: URI) => { const editorService = accessor.get(IWorkbenchEditorService); const activeEditor = editorService.getActiveEditor(); - resource = activeEditor ? toResource(activeEditor.input, { supportSideBySide: true, filter: 'file' }) : void 0; + resource = activeEditor ? toResource(activeEditor.input, { supportSideBySide: true }) : void 0; if (activeEditor) { editorGroupService.focusGroup(activeEditor.position); // focus back to active editor group } @@ -44,33 +44,18 @@ export const copyPathCommand = (accessor: ServicesAccessor, resource?: URI) => { if (resource) { const clipboardService = accessor.get(IClipboardService); - clipboardService.writeText(labels.getPathLabel(resource)); + clipboardService.writeText(resource.scheme === 'file' ? getPathLabel(resource) : resource.toString()); } else { const messageService = accessor.get(IMessageService); messageService.show(severity.Info, nls.localize('openFileToCopy', "Open a file first to copy its path")); } }; -export const openFolderPickerCommand = (accessor: ServicesAccessor, forceNewWindow: boolean) => { - const windowService = accessor.get(IWindowService); - - windowService.pickFolderAndOpen({ forceNewWindow }); -}; - export const openWindowCommand = (accessor: ServicesAccessor, paths: string[], forceNewWindow: boolean) => { const windowsService = accessor.get(IWindowsService); windowsService.openWindow(paths, { forceNewWindow }); }; -export const openFileInNewWindowCommand = (accessor: ServicesAccessor) => { - const windowService = accessor.get(IWindowService); - const editorService = accessor.get(IWorkbenchEditorService); - - const fileResource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' }); - - windowService.pickFileAndOpen({ forceNewWindow: true, dialogOptions: { defaultPath: fileResource ? paths.dirname(fileResource.fsPath) : void 0 } }); -}; - export const revealInOSCommand = (accessor: ServicesAccessor, resource?: URI) => { // Without resource, try to look at the active editor @@ -98,13 +83,13 @@ export const revealInExplorerCommand = (accessor: ServicesAccessor, resource: UR if (isInsideWorkspace) { const explorerView = viewlet.getExplorerView(); if (explorerView) { - explorerView.expand(); + explorerView.setExpanded(true); explorerView.select(resource, true); } } else { const openEditorsView = viewlet.getOpenEditorsView(); if (openEditorsView) { - openEditorsView.expand(); + openEditorsView.setExpanded(true); } } }); @@ -155,7 +140,7 @@ function withVisibleExplorer(accessor: ServicesAccessor): TPromise; -}; +} export function withFocusedFilesExplorerViewItem(accessor: ServicesAccessor): TPromise<{ explorer: ExplorerViewlet, tree: ITree, item: FileStat }> { return withFocusedFilesExplorer(accessor).then(res => { @@ -170,7 +155,7 @@ export function withFocusedFilesExplorerViewItem(accessor: ServicesAccessor): TP return { explorer, tree, item: tree.getFocus() }; }); -}; +} export function withFocusedFilesExplorer(accessor: ServicesAccessor): TPromise<{ explorer: ExplorerViewlet, tree: ITree }> { return withVisibleExplorer(accessor).then(explorer => { @@ -187,7 +172,7 @@ export function withFocusedFilesExplorer(accessor: ServicesAccessor): TPromise<{ return { explorer, tree }; }); -}; +} function withFocusedOpenEditorsViewItem(accessor: ServicesAccessor): TPromise<{ explorer: ExplorerViewlet, tree: ITree, item: OpenEditor }> { return withVisibleExplorer(accessor).then(explorer => { @@ -205,7 +190,7 @@ function withFocusedOpenEditorsViewItem(accessor: ServicesAccessor): TPromise<{ return { explorer, tree, item: focus }; }); -}; +} function withFocusedExplorerItem(accessor: ServicesAccessor): TPromise { return withFocusedFilesExplorerViewItem(accessor).then(res => { @@ -221,7 +206,7 @@ function withFocusedExplorerItem(accessor: ServicesAccessor): TPromise { runActionOnFocusedFilesExplorerViewItem(accessor, 'renameFile'); diff --git a/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts b/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts index 7151d614f6f..9174477d966 100644 --- a/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts +++ b/src/vs/workbench/parts/files/browser/fileResultsNavigation.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { Throttler } from 'vs/base/common/async'; import Event, { Emitter } from 'vs/base/common/event'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { ITree } from 'vs/base/parts/tree/browser/tree'; @@ -21,11 +20,8 @@ export default class FileResultsNavigation extends Disposable { private _openFile: Emitter = new Emitter(); public readonly openFile: Event = this._openFile.event; - private throttler: Throttler; - constructor(private tree: ITree) { super(); - this.throttler = new Throttler(); this._register(this.tree.addListener('focus', e => this.onFocus(e))); this._register(this.tree.addListener('selection', e => this.onSelection(e))); } diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 03d76fd8aaa..15b4a09a9fa 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -11,11 +11,10 @@ import nls = require('vs/nls'); import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, EditorInput, IFileEditorInput } from 'vs/workbench/common/editor'; +import { IEditorInputFactory, EditorInput, IFileEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor'; import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files'; -import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { FILE_EDITOR_INPUT_ID, VIEWLET_ID, SortOrderConfiguration } from 'vs/workbench/parts/files/common/files'; import { FileEditorTracker } from 'vs/workbench/parts/files/common/editors/fileEditorTracker'; import { SaveErrorHandler } from 'vs/workbench/parts/files/browser/saveErrorHandler'; @@ -29,8 +28,9 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import * as platform from 'vs/base/common/platform'; -import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { DirtyFilesTracker } from 'vs/workbench/parts/files/common/dirtyFilesTracker'; +import { ExplorerViewlet } from 'vs/workbench/parts/files/browser/explorerViewlet'; +import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; // Viewlet Action export class OpenExplorerViewletAction extends ToggleViewletAction { @@ -49,8 +49,7 @@ export class OpenExplorerViewletAction extends ToggleViewletAction { // Register Viewlet Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( - 'vs/workbench/parts/files/browser/explorerViewlet', - 'ExplorerViewlet', + ExplorerViewlet, VIEWLET_ID, nls.localize('explore', "Explorer"), 'explore', @@ -74,10 +73,9 @@ registry.registerWorkbenchAction( // Register file editors Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( - TextFileEditor.ID, // explicit dependency because we don't want these editors lazy loaded - nls.localize('textFileEditor', "Text File Editor"), - 'vs/workbench/parts/files/browser/editors/textFileEditor', - 'TextFileEditor' + TextFileEditor, + TextFileEditor.ID, + nls.localize('textFileEditor', "Text File Editor") ), [ new SyncDescriptor(FileEditorInput) @@ -86,10 +84,9 @@ Registry.as(EditorExtensions.Editors).registerEditor( Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( - BinaryFileEditor.ID, // explicit dependency because we don't want these editors lazy loaded - nls.localize('binaryFileEditor', "Binary File Editor"), - 'vs/workbench/parts/files/browser/editors/binaryFileEditor', - 'BinaryFileEditor' + BinaryFileEditor, + BinaryFileEditor.ID, + nls.localize('binaryFileEditor', "Binary File Editor") ), [ new SyncDescriptor(FileEditorInput) @@ -97,7 +94,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( ); // Register default file input factory -Registry.as(EditorExtensions.Editors).registerFileInputFactory({ +Registry.as(EditorInputExtensions.EditorInputFactories).registerFileInputFactory({ createFileInput: (resource, encoding, instantiationService): IFileEditorInput => { return instantiationService.createInstance(FileEditorInput, resource, encoding); } @@ -112,24 +109,17 @@ interface ISerializedFileInput { // Register Editor Input Factory class FileEditorInputFactory implements IEditorInputFactory { - constructor( - @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService - ) { - } + constructor() { } public serialize(editorInput: EditorInput): string { const fileEditorInput = editorInput; const resource = fileEditorInput.getResource(); const fileInput: ISerializedFileInput = { resource: resource.toString(), // Keep for backwards compatibility - resourceJSON: resource.toJSON() + resourceJSON: resource.toJSON(), + encoding: fileEditorInput.getEncoding() }; - const encoding = fileEditorInput.getPreferredEncoding(); - if (encoding && encoding !== this.configurationService.lookup('files.encoding', { resource }).value) { - fileInput.encoding = encoding; - } - return JSON.stringify(fileInput); } @@ -144,7 +134,7 @@ class FileEditorInputFactory implements IEditorInputFactory { } } -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(FILE_EDITOR_INPUT_ID, FileEditorInputFactory); +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(FILE_EDITOR_INPUT_ID, FileEditorInputFactory); // Register File Editor Tracker Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( @@ -172,7 +162,7 @@ configurationRegistry.registerConfiguration({ 'properties': { 'files.exclude': { 'type': 'object', - 'description': nls.localize('exclude', "Configure glob patterns for excluding files and folders."), + 'description': nls.localize('exclude', "Configure glob patterns for excluding files and folders. For example, the files explorer decides which files and folders to show or hide based on this setting."), 'default': { '**/.git': true, '**/.svn': true, '**/.hg': true, '**/CVS': true, '**/.DS_Store': true }, 'scope': ConfigurationScope.RESOURCE, 'additionalProperties': { @@ -201,15 +191,18 @@ configurationRegistry.registerConfiguration({ }, 'files.encoding': { 'type': 'string', + 'overridable': true, 'enum': Object.keys(SUPPORTED_ENCODINGS), 'default': 'utf8', - 'description': nls.localize('encoding', "The default character set encoding to use when reading and writing files."), - 'scope': ConfigurationScope.RESOURCE + 'description': nls.localize('encoding', "The default character set encoding to use when reading and writing files. This setting can be configured per language too."), + 'scope': ConfigurationScope.RESOURCE, + 'enumDescriptions': Object.keys(SUPPORTED_ENCODINGS).map(key => SUPPORTED_ENCODINGS[key].labelLong) }, 'files.autoGuessEncoding': { 'type': 'boolean', + 'overridable': true, 'default': false, - 'description': nls.localize('autoGuessEncoding', "When enabled, will attempt to guess the character set encoding when opening files"), + 'description': nls.localize('autoGuessEncoding', "When enabled, will attempt to guess the character set encoding when opening files. This setting can be configured per language too."), 'scope': ConfigurationScope.RESOURCE }, 'files.eol': { @@ -236,6 +229,13 @@ configurationRegistry.registerConfiguration({ 'overridable': true, 'scope': ConfigurationScope.RESOURCE }, + 'files.trimFinalNewlines': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('trimFinalNewlines', "When enabled, will trim all new lines after the final new line at the end of the file when saving it."), + 'overridable': true, + 'scope': ConfigurationScope.RESOURCE + }, 'files.autoSave': { 'type': 'string', 'enum': [AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, , AutoSaveConfiguration.ON_WINDOW_CHANGE], @@ -292,7 +292,8 @@ configurationRegistry.registerConfiguration({ 'type': 'boolean', 'default': false, 'description': nls.localize('formatOnSave', "Format a file on save. A formatter must be available, the file must not be auto-saved, and editor must not be shutting down."), - 'overridable': true + 'overridable': true, + 'scope': ConfigurationScope.RESOURCE } } }); @@ -323,6 +324,16 @@ configurationRegistry.registerConfiguration({ 'description': nls.localize('enableDragAndDrop', "Controls if the explorer should allow to move files and folders via drag and drop."), 'default': true }, + 'explorer.confirmDragAndDrop': { + 'type': 'boolean', + 'description': nls.localize('confirmDragAndDrop', "Controls if the explorer should ask for confirmation to move files and folders via drag and drop."), + 'default': true + }, + 'explorer.confirmDelete': { + 'type': 'boolean', + 'description': nls.localize('confirmDelete', "Controls if the explorer should ask for confirmation when deleting a file via the trash."), + 'default': true + }, 'explorer.sortOrder': { 'type': 'string', 'enum': [SortOrderConfiguration.DEFAULT, SortOrderConfiguration.MIXED, SortOrderConfiguration.FILES_FIRST, SortOrderConfiguration.TYPE, SortOrderConfiguration.MODIFIED], @@ -335,6 +346,16 @@ configurationRegistry.registerConfiguration({ nls.localize('sortOrder.modified', 'Files and folders are sorted by last modified date, in descending order. Folders are displayed before files.') ], 'description': nls.localize({ key: 'sortOrder', comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'] }, "Controls sorting order of files and folders in the explorer. In addition to the default sorting, you can set the order to 'mixed' (files and folders sorted combined), 'type' (by file type), 'modified' (by last modified date) or 'filesFirst' (sort files before folders).") - } + }, + 'explorer.decorations.colors': { + type: 'boolean', + description: nls.localize('explorer.decorations.colors', "Controls if file decorations should use colors."), + default: true + }, + 'explorer.decorations.badges': { + type: 'boolean', + description: nls.localize('explorer.decorations.badges', "Controls if file decorations should use badges."), + default: true + }, } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css index b02fed754ab..07ff1c0ca4b 100644 --- a/src/vs/workbench/parts/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/parts/files/browser/media/explorerviewlet.css @@ -26,7 +26,7 @@ } .explorer-viewlet .explorer-item > a, -.explorer-viewlet .open-editor, +.explorer-viewlet .open-editor > a, .explorer-viewlet .editor-group { text-overflow: ellipsis; overflow: hidden; @@ -37,10 +37,6 @@ flex: 1; } -.explorer-viewlet .explorer-item::before { - flex-shrink: 0; /* fix for https://github.com/Microsoft/vscode/issues/13787 */ -} - .explorer-viewlet .explorer-item.explorer-item-edited .label-name { flex: 0; /* do not steal space when label is hidden because we are in edit mode */ } @@ -53,9 +49,12 @@ visibility: hidden; } -.explorer-viewlet .header .monaco-count-badge.hidden { +.explorer-viewlet .panel-header .count { + min-width: fit-content; +} + +.explorer-viewlet .panel-header .monaco-count-badge.hidden { display: none; - visibility: hidden; } .explorer-folders-view .monaco-tree-row .content { @@ -103,6 +102,10 @@ background-image: url("collapsed-hc.svg"); } +.explorer-folders-view.hide-arrows .monaco-tree-row .content::before { + display: none; +} + .explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row:hover > .content .monaco-action-bar, .explorer-viewlet .explorer-open-editors .monaco-tree.focused .monaco-tree-row.focused > .content .monaco-action-bar, .explorer-viewlet .explorer-open-editors .monaco-tree .monaco-tree-row > .content.dirty > .monaco-action-bar { @@ -186,4 +189,4 @@ .hc-black .monaco-workbench .explorer-viewlet .open-editor, .hc-black .monaco-workbench .explorer-viewlet .editor-group { line-height: 20px; -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/files/browser/media/fileactions.css b/src/vs/workbench/parts/files/browser/media/fileactions.css index f064ef66e0c..0954b8841ce 100644 --- a/src/vs/workbench/parts/files/browser/media/fileactions.css +++ b/src/vs/workbench/parts/files/browser/media/fileactions.css @@ -21,7 +21,7 @@ } .vs-dark .monaco-workbench .explorer-action.save-all, -.hc-blck .monaco-workbench .explorer-action.save-all { +.hc-black .monaco-workbench .explorer-action.save-all { background: url('saveall_inverse.svg') center center no-repeat; } @@ -124,4 +124,4 @@ .vs-dark .monaco-workbench .explorer-viewlet .explorer-open-editors .close-editor-action, .hc-black .monaco-workbench .explorer-viewlet .explorer-open-editors .close-editor-action { background: url("action-close-dark.svg") center center no-repeat; -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/files/browser/media/new-file-tb.png b/src/vs/workbench/parts/files/browser/media/new-file-tb.png new file mode 100644 index 00000000000..ad6d778d72c Binary files /dev/null and b/src/vs/workbench/parts/files/browser/media/new-file-tb.png differ diff --git a/src/vs/workbench/parts/files/browser/views/emptyView.ts b/src/vs/workbench/parts/files/browser/views/emptyView.ts index 754e255a2bf..6a577a40ad3 100644 --- a/src/vs/workbench/parts/files/browser/views/emptyView.ts +++ b/src/vs/workbench/parts/files/browser/views/emptyView.ts @@ -11,53 +11,53 @@ import DOM = require('vs/base/browser/dom'); import { TPromise } from 'vs/base/common/winjs.base'; import { IAction } from 'vs/base/common/actions'; import { Button } from 'vs/base/browser/ui/button/button'; -import { $ } from 'vs/base/browser/builder'; +import { $, Builder } from 'vs/base/browser/builder'; import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { CollapsibleView, IViewletViewOptions, IViewOptions } from 'vs/workbench/parts/views/browser/views'; +import { ViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { OpenFolderAction, OpenFileFolderAction, AddRootFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { attachButtonStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -export class EmptyView extends CollapsibleView { +export class EmptyView extends ViewsViewletPanel { public static ID: string = 'workbench.explorer.emptyView'; public static NAME = nls.localize('noWorkspace', "No Folder Opened"); - private openFolderButton: Button; + private button: Button; + private messageDiv: Builder; + private titleDiv: Builder; constructor( - initialSize: number, options: IViewletViewOptions, @IThemeService private themeService: IThemeService, @IInstantiationService private instantiationService: IInstantiationService, @IKeybindingService keybindingService: IKeybindingService, - @IContextMenuService contextMenuService: IContextMenuService + @IContextMenuService contextMenuService: IContextMenuService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { - super(initialSize, { ...(options as IViewOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section"), sizing: ViewSizing.Flexible }, keybindingService, contextMenuService); + super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService); + this.contextService.onDidChangeWorkbenchState(() => this.setLabels()); } public renderHeader(container: HTMLElement): void { - let titleDiv = $('div.title').appendTo(container); - $('span').text(this.name).appendTo(titleDiv); + this.titleDiv = $('span').text(name).appendTo($('div.title').appendTo(container)); } protected renderBody(container: HTMLElement): void { DOM.addClass(container, 'explorer-empty-view'); - let titleDiv = $('div.section').appendTo(container); - $('p').text(nls.localize('noWorkspaceHelp', "You have not yet opened a folder.")).appendTo(titleDiv); + this.messageDiv = $('p').appendTo($('div.section').appendTo(container)); let section = $('div.section').appendTo(container); - this.openFolderButton = new Button(section); - attachButtonStyler(this.openFolderButton, this.themeService); - this.openFolderButton.label = nls.localize('openFolder', "Open Folder"); - this.openFolderButton.addListener('click', () => { - const actionClass = env.isMacintosh ? OpenFileFolderAction : OpenFolderAction; + this.button = new Button(section); + attachButtonStyler(this.button, this.themeService); + this.button.addListener('click', () => { + const actionClass = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? AddRootFolderAction : env.isMacintosh ? OpenFileFolderAction : OpenFolderAction; const action = this.instantiationService.createInstance(actionClass, actionClass.ID, actionClass.LABEL); this.actionRunner.run(action).done(() => { action.dispose(); @@ -66,6 +66,23 @@ export class EmptyView extends CollapsibleView { errors.onUnexpectedError(err); }); }); + this.setLabels(); + } + + private setLabels(): void { + if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + this.messageDiv.text(nls.localize('noWorkspaceHelp', "You have not yet added a folder to the workspace.")); + if (this.button) { + this.button.label = nls.localize('addFolder', "Add Folder"); + } + this.titleDiv.text(this.contextService.getWorkspace().name); + } else { + this.messageDiv.text(nls.localize('noFolderHelp', "You have not yet opened a folder.")); + if (this.button) { + this.button.label = nls.localize('openFolder', "Open Folder"); + } + this.titleDiv.text(this.name); + } } layoutBody(size: number): void { @@ -81,8 +98,8 @@ export class EmptyView extends CollapsibleView { } public focusBody(): void { - if (this.openFolderButton) { - this.openFolderButton.getElement().focus(); + if (this.button) { + this.button.getElement().focus(); } } diff --git a/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.ts b/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.ts new file mode 100644 index 00000000000..38b6e7d6f3e --- /dev/null +++ b/src/vs/workbench/parts/files/browser/views/explorerDecorationsProvider.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import URI from 'vs/base/common/uri'; +import Event, { Emitter } from 'vs/base/common/event'; +import { localize } from 'vs/nls'; +import { Model } from 'vs/workbench/parts/files/common/explorerModel'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { listInvalidItemForeground } from 'vs/platform/theme/common/colorRegistry'; + +export class ExplorerDecorationsProvider implements IDecorationsProvider { + readonly label: string = localize('label', "Explorer"); + private _onDidChange = new Emitter(); + + constructor( + private model: Model, + @IWorkspaceContextService contextService: IWorkspaceContextService + ) { + contextService.onDidChangeWorkspaceFolders(e => { + this._onDidChange.fire(e.changed.map(wf => wf.uri)); + }); + } + + get onDidChange(): Event { + return this._onDidChange.event; + } + + provideDecorations(resource: URI): IDecorationData { + const fileStat = this.model.roots.filter(r => r.resource.toString() === resource.toString()).pop(); + if (fileStat && fileStat.nonexistentRoot) { + return { + tooltip: localize('canNotResolve', "Can not resolve workspace folder"), + letter: '!', + color: listInvalidItemForeground, + }; + } + + return undefined; + } +} diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index a299d91412a..0969df39c49 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -8,10 +8,10 @@ import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import { Builder, $ } from 'vs/base/browser/builder'; import URI from 'vs/base/common/uri'; -import { ThrottledDelayer } from 'vs/base/common/async'; +import { ThrottledDelayer, sequence, Delayer } from 'vs/base/common/async'; import errors = require('vs/base/common/errors'); -import labels = require('vs/base/common/labels'); import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import glob = require('vs/base/common/glob'); import { Action, IAction } from 'vs/base/common/actions'; import { prepareActions } from 'vs/workbench/browser/actions'; @@ -19,7 +19,7 @@ import { memoize } from 'vs/base/common/decorators'; import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, SortOrderConfiguration, SortOrder } from 'vs/workbench/parts/files/common/files'; -import { FileOperation, FileOperationEvent, IResolveFileOptions, FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; +import { FileOperation, FileOperationEvent, IResolveFileOptions, FileChangeType, FileChangesEvent, IFileService, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files'; import { RefreshViewExplorerAction, NewFolderAction, NewFileAction } from 'vs/workbench/parts/files/browser/fileActions'; import { FileDragAndDrop, FileFilter, FileSorter, FileController, FileRenderer, FileDataSource, FileViewletState, FileAccessibilityProvider } from 'vs/workbench/parts/files/browser/views/explorerViewer'; import { toResource } from 'vs/workbench/common/editor'; @@ -27,13 +27,14 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import * as DOM from 'vs/base/browser/dom'; import { CollapseAction } from 'vs/workbench/browser/viewlet'; -import { CollapsibleView, IViewletViewOptions, IViewOptions } from 'vs/workbench/parts/views/browser/views'; +import { ViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { FileStat, Model } from 'vs/workbench/parts/files/common/explorerModel'; import { IListService } from 'vs/platform/list/browser/listService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ExplorerDecorationsProvider } from 'vs/workbench/parts/files/browser/views/explorerDecorationsProvider'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressService } from 'vs/platform/progress/common/progress'; @@ -43,20 +44,18 @@ import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/c import { ResourceContextKey, ResourceGlobMatcher } from 'vs/workbench/common/resources'; import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { isLinux } from 'vs/base/common/platform'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { attachListStyler } from 'vs/platform/theme/common/styler'; -import { ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; +import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; export interface IExplorerViewOptions extends IViewletViewOptions { viewletState: FileViewletState; } -export class ExplorerView extends CollapsibleView { +export class ExplorerView extends ViewsViewletPanel { public static ID: string = 'workbench.explorer.fileView'; private static EXPLORER_FILE_CHANGES_REACT_DELAY = 500; // delay in ms to react to file changes to give our internal events a chance to react first private static EXPLORER_FILE_CHANGES_REFRESH_DELAY = 100; // delay in ms to refresh the explorer from disk file changes - private static EXPLORER_IMPORT_REFRESH_DELAY = 300; // delay in ms to refresh the explorer from imports private static MEMENTO_LAST_ACTIVE_FILE_RESOURCE = 'explorer.memento.lastActiveFileResource'; private static MEMENTO_EXPANDED_FOLDER_RESOURCES = 'explorer.memento.expandedFolderResources'; @@ -68,7 +67,6 @@ export class ExplorerView extends CollapsibleView { private viewletState: FileViewletState; private explorerRefreshDelayer: ThrottledDelayer; - private explorerImportDelayer: ThrottledDelayer; private resourceContext: ResourceContextKey; private folderContext: IContextKey; @@ -84,7 +82,6 @@ export class ExplorerView extends CollapsibleView { private settings: object; constructor( - initialSize: number, options: IExplorerViewOptions, @IMessageService private messageService: IMessageService, @IContextMenuService contextMenuService: IContextMenuService, @@ -100,17 +97,15 @@ export class ExplorerView extends CollapsibleView { @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService private configurationService: IConfigurationService, @IWorkbenchThemeService private themeService: IWorkbenchThemeService, - @IEnvironmentService private environmentService: IEnvironmentService + @IDecorationsService decorationService: IDecorationsService ) { - super(initialSize, { ...(options as IViewOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section"), sizing: ViewSizing.Flexible }, keybindingService, contextMenuService); + super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService); this.settings = options.viewletSettings; this.viewletState = options.viewletState; - this.actionRunner = options.actionRunner; this.autoReveal = true; this.explorerRefreshDelayer = new ThrottledDelayer(ExplorerView.EXPLORER_FILE_CHANGES_REFRESH_DELAY); - this.explorerImportDelayer = new ThrottledDelayer(ExplorerView.EXPLORER_IMPORT_REFRESH_DELAY); this.resourceContext = instantiationService.createInstance(ResourceContextKey); this.folderContext = ExplorerFolderContext.bindTo(contextKeyService); @@ -118,34 +113,49 @@ export class ExplorerView extends CollapsibleView { this.filesExplorerFocusedContext = FilesExplorerFocusedContext.bindTo(contextKeyService); this.explorerFocusedContext = ExplorerFocusedContext.bindTo(contextKeyService); - this.fileEventsFilter = instantiationService.createInstance(ResourceGlobMatcher, (root: URI) => this.getFileEventsExcludes(root), (expression: glob.IExpression) => glob.parse(expression)); + this.fileEventsFilter = instantiationService.createInstance( + ResourceGlobMatcher, + (root: URI) => this.getFileEventsExcludes(root), + (event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) + ); + + decorationService.registerDecorationsProvider(new ExplorerDecorationsProvider(this.model, contextService)); } private getFileEventsExcludes(root?: URI): glob.IExpression { const scope = root ? { resource: root } : void 0; - const configuration = this.configurationService.getConfiguration(undefined, scope); + const configuration = this.configurationService.getConfiguration(scope); return (configuration && configuration.files && configuration.files.exclude) || Object.create(null); } - public renderHeader(container: HTMLElement): void { - const titleDiv = $('div.title').appendTo(container); - const titleSpan = $('span').appendTo(titleDiv); + protected renderHeader(container: HTMLElement): void { + super.renderHeader(container); + + const titleElement = container.querySelector('.title') as HTMLElement; const setHeader = () => { const workspace = this.contextService.getWorkspace(); - const title = workspace.roots.map(root => labels.getPathLabel(root.fsPath, void 0, this.environmentService)).join(); - titleSpan.text(this.name).title(title); + const title = workspace.folders.map(folder => folder.name).join(); + titleElement.textContent = this.name; + titleElement.title = title; }; - this.toDispose.push(this.contextService.onDidChangeWorkspaceName(() => setHeader())); - setHeader(); - super.renderHeader(container); + this.disposables.push(this.contextService.onDidChangeWorkspaceName(setHeader)); + setHeader(); } public get name(): string { return this.contextService.getWorkspace().name; } + public get title(): string { + return this.name; + } + + public set title(value: string) { + // noop + } + public set name(value) { // noop } @@ -157,16 +167,18 @@ export class ExplorerView extends CollapsibleView { this.tree = this.createViewer($(this.treeContainer)); - if (this.toolBar) { - this.toolBar.setActions(prepareActions(this.getActions()), this.getSecondaryActions())(); + if (this.toolbar) { + this.toolbar.setActions(prepareActions(this.getActions()), this.getSecondaryActions())(); } const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => { DOM.toggleClass(this.treeContainer, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons); + DOM.toggleClass(this.treeContainer, 'hide-arrows', fileIconTheme.hidesExplorerArrows === true); }; - this.toDispose.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange)); - this.toDispose.push(this.contextService.onDidChangeWorkspaceRoots(() => this.refreshFromEvent())); + this.disposables.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange)); + this.disposables.push(this.contextService.onDidChangeWorkspaceFolders(e => this.refreshFromEvent(e.added))); + this.disposables.push(this.contextService.onDidChangeWorkbenchState(e => this.refreshFromEvent())); onFileIconThemeChange(this.themeService.getFileIconTheme()); } @@ -194,17 +206,23 @@ export class ExplorerView extends CollapsibleView { this.onConfigurationUpdated(configuration); // Load and Fill Viewer - return this.doRefresh().then(() => { + let targetsToExpand = []; + if (this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES]) { + targetsToExpand = this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES].map((e: string) => URI.parse(e)); + } + return this.doRefresh(targetsToExpand).then(() => { // When the explorer viewer is loaded, listen to changes to the editor input - this.toDispose.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); + this.disposables.push(this.editorGroupService.onEditorsChanged(() => this.revealActiveFile())); // Also handle configuration updates - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), true))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration(), e))); + + this.revealActiveFile(); }); } - private onEditorsChanged(): void { + private revealActiveFile(): void { if (!this.autoReveal) { return; // do not touch selection or focus if autoReveal === false } @@ -247,7 +265,7 @@ export class ExplorerView extends CollapsibleView { } } - private onConfigurationUpdated(configuration: IFilesConfiguration, refresh?: boolean): void { + private onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): void { if (this.isDisposed) { return; // guard against possible race condition when config change causes recreate of views } @@ -266,13 +284,20 @@ export class ExplorerView extends CollapsibleView { needsRefresh = true; } - // Refresh viewer as needed - if (refresh && needsRefresh) { + if (event && !needsRefresh) { + needsRefresh = event.affectsConfiguration('explorer.decorations.colors') + || event.affectsConfiguration('explorer.decorations.badges'); + } + + // Refresh viewer as needed if this originates from a config event + if (event && needsRefresh) { this.doRefresh().done(null, errors.onUnexpectedError); } } - public focusBody(): void { + public focus(): void { + super.focus(); + let keepFocus = false; // Make sure the current selected element is revealed @@ -365,7 +390,7 @@ export class ExplorerView extends CollapsibleView { } // check for files - return toResource(input, { supportSideBySide: true, filter: 'file' }); + return toResource(input, { supportSideBySide: true }); } private get isCreated(): boolean { @@ -374,7 +399,10 @@ export class ExplorerView extends CollapsibleView { @memoize private get model(): Model { - return this.instantiationService.createInstance(Model); + const model = this.instantiationService.createInstance(Model); + this.disposables.push(model); + + return model; } public createViewer(container: Builder): ITree { @@ -382,7 +410,9 @@ export class ExplorerView extends CollapsibleView { const renderer = this.instantiationService.createInstance(FileRenderer, this.viewletState); const controller = this.instantiationService.createInstance(FileController, this.viewletState); const sorter = this.instantiationService.createInstance(FileSorter); + this.disposables.push(sorter); this.filter = this.instantiationService.createInstance(FileFilter); + this.disposables.push(this.filter); const dnd = this.instantiationService.createInstance(FileDragAndDrop); const accessibilityProvider = this.instantiationService.createInstance(FileAccessibilityProvider); @@ -403,23 +433,23 @@ export class ExplorerView extends CollapsibleView { }); // Theme styler - this.toDispose.push(attachListStyler(this.explorerViewer, this.themeService)); + this.disposables.push(attachListStyler(this.explorerViewer, this.themeService)); // Register to list service - this.toDispose.push(this.listService.register(this.explorerViewer, [this.explorerFocusedContext, this.filesExplorerFocusedContext])); + this.disposables.push(this.listService.register(this.explorerViewer, [this.explorerFocusedContext, this.filesExplorerFocusedContext])); // Update Viewer based on File Change Events - this.toDispose.push(this.fileService.onAfterOperation(e => this.onFileOperation(e))); - this.toDispose.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); + this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e))); + this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); // Update resource context based on focused element - this.toDispose.push(this.explorerViewer.addListener('focus', (e: { focus: FileStat }) => { + this.disposables.push(this.explorerViewer.addListener('focus', (e: { focus: FileStat }) => { this.resourceContext.set(e.focus && e.focus.resource); this.folderContext.set(e.focus && e.focus.isDirectory); })); // Open when selecting via keyboard - this.toDispose.push(this.explorerViewer.addListener('selection', event => { + this.disposables.push(this.explorerViewer.addListener('selection', event => { if (event && event.payload && event.payload.origin === 'keyboard') { const element = this.tree.getSelection(); @@ -438,7 +468,7 @@ export class ExplorerView extends CollapsibleView { public getOptimalWidth(): number { const parentNode = this.explorerViewer.getHTMLElement(); - const childNodes = [].slice.call(parentNode.querySelectorAll('.explorer-item > a')); + const childNodes = [].slice.call(parentNode.querySelectorAll('.explorer-item .label-name')); // select all file labels return DOM.getLargestChildWidth(parentNode, childNodes); } @@ -451,7 +481,7 @@ export class ExplorerView extends CollapsibleView { // Add if (e.operation === FileOperation.CREATE || e.operation === FileOperation.IMPORT || e.operation === FileOperation.COPY) { const addedElement = e.target; - const parentResource = URI.file(paths.dirname(addedElement.resource.fsPath)); + const parentResource = resources.dirname(addedElement.resource); const parents = this.model.findAll(parentResource); if (parents.length) { @@ -486,8 +516,8 @@ export class ExplorerView extends CollapsibleView { const oldResource = e.resource; const newElement = e.target; - const oldParentResource = URI.file(paths.dirname(oldResource.fsPath)); - const newParentResource = URI.file(paths.dirname(newElement.resource.fsPath)); + const oldParentResource = resources.dirname(oldResource); + const newParentResource = resources.dirname(newElement.resource); // Only update focus if renamed/moved element is selected let restoreFocus = false; @@ -671,11 +701,17 @@ export class ExplorerView extends CollapsibleView { })); } - private refreshFromEvent(): void { + private refreshFromEvent(newRoots: IWorkspaceFolder[] = []): void { if (this.isVisible()) { this.explorerRefreshDelayer.trigger(() => { if (!this.explorerViewer.getHighlight()) { - return this.doRefresh(); + return this.doRefresh(newRoots.map(r => r.uri)).then(() => { + if (newRoots.length === 1) { + return this.reveal(this.model.findClosest(newRoots[0].uri), 0.5); + } + + return undefined; + }); } return TPromise.as(null); @@ -717,35 +753,24 @@ export class ExplorerView extends CollapsibleView { }); } - private doRefresh(): TPromise { - const targetsToResolve: { root: FileStat, resource: URI, options: { resolveTo: URI[] } }[] = []; - this.model.roots.forEach(root => { - const rootAndTargets = { root, resource: root.resource, options: { resolveTo: [] } }; - targetsToResolve.push(rootAndTargets); - }); - - let targetsToExpand: URI[] = []; - if (this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES]) { - targetsToExpand = this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES].map((e: string) => URI.parse(e)); - } else if (this.contextService.hasFolderWorkspace() || (this.contextService.hasMultiFolderWorkspace() && this.model.roots.length === 1)) { - targetsToExpand = this.model.roots.map(root => root.resource); // always expand single folder workspace and multi folder workspace with only 1 root - } + private doRefresh(targetsToExpand: URI[] = []): TPromise { + const targetsToResolve = this.model.roots.map(root => ({ root, resource: root.resource, options: { resolveTo: [] } })); // First time refresh: Receive target through active editor input or selection and also include settings from previous session if (!this.isCreated) { const activeFile = this.getActiveFile(); if (activeFile) { - const root = this.contextService.getRoot(activeFile); - if (root) { - const found = targetsToResolve.filter(t => t.root.resource.toString() === root.toString()).pop(); + const workspaceFolder = this.contextService.getWorkspaceFolder(activeFile); + if (workspaceFolder) { + const found = targetsToResolve.filter(t => t.root.resource.toString() === workspaceFolder.uri.toString()).pop(); found.options.resolveTo.push(activeFile); } } targetsToExpand.forEach(toExpand => { - const root = this.contextService.getRoot(toExpand); - if (root) { - const found = targetsToResolve.filter(ttr => ttr.resource.toString() === root.toString()).pop(); + const workspaceFolder = this.contextService.getWorkspaceFolder(toExpand); + if (workspaceFolder) { + const found = targetsToResolve.filter(ttr => ttr.resource.toString() === workspaceFolder.uri.toString()).pop(); found.options.resolveTo.push(toExpand); } }); @@ -759,40 +784,45 @@ export class ExplorerView extends CollapsibleView { } // Load Root Stat with given target path configured - const promise = this.fileService.resolveFiles(targetsToResolve).then(results => { - // Convert to model - const modelStats = results.map((result, index) => { - if (result.success) { - return FileStat.create(result.stat, targetsToResolve[index].root, targetsToResolve[index].options.resolveTo); + let statsToExpand: FileStat[] = []; + let delayer = new Delayer(100); + let delayerPromise: TPromise; + + const promise = TPromise.join(targetsToResolve.map((target, index) => this.fileService.resolveFile(target.resource, target.options) + .then(result => FileStat.create(result, target.root, target.options.resolveTo), err => FileStat.create({ + resource: target.resource, + name: resources.basenameOrAuthority(target.resource), + mtime: 0, + etag: undefined, + isDirectory: true, + hasChildren: false + }, target.root)) + .then(modelStat => { + // Subsequent refresh: Merge stat into our local model and refresh tree + FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index]); + + const input = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? this.model.roots[0] : this.model; + let toExpand: FileStat[] = this.explorerViewer.getExpandedElements().concat(targetsToExpand.map(target => this.model.findClosest(target))); + if (input === this.explorerViewer.getInput()) { + statsToExpand = statsToExpand.concat(toExpand); + if (!delayer.isTriggered()) { + delayerPromise = delayer.trigger(() => this.explorerViewer.refresh() + .then(() => sequence(statsToExpand.map(e => () => this.explorerViewer.expand(e)))) + .then(() => statsToExpand = []) + ); + } + + return delayerPromise; } - return FileStat.create({ - resource: targetsToResolve[index].resource, - name: paths.basename(targetsToResolve[index].resource.fsPath), - mtime: 0, - etag: undefined, - isDirectory: true, - hasChildren: false - }, targetsToResolve[index].root); - }); - // Subsequent refresh: Merge stat into our local model and refresh tree - modelStats.forEach((modelStat, index) => FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index])); - - const input = this.contextService.hasFolderWorkspace() ? this.model.roots[0] : this.model; - if (input === this.explorerViewer.getInput()) { - return this.explorerViewer.refresh(); - } - - // Preserve expanded elements if tree input changed. - // If it is a brand new tree just expand elements from memento - const expanded = this.explorerViewer.getExpandedElements(); - const statsToExpand = expanded.length ? [this.model.roots[0]].concat(expanded) : - targetsToExpand.map(expand => this.model.findClosest(expand)); - - // Display roots only when multi folder workspace - // Make sure to expand all folders that where expanded in the previous session - return this.explorerViewer.setInput(input).then(() => this.explorerViewer.expandAll(statsToExpand)); - }, e => TPromise.wrapError(e)); + // Display roots only when multi folder workspace + // Make sure to expand all folders that where expanded in the previous session + if (input === this.model) { + // We have transitioned into workspace view -> expand all roots + toExpand = this.model.roots.concat(toExpand); + } + return this.explorerViewer.setInput(input).then(() => sequence(toExpand.map(e => () => this.explorerViewer.expand(e)))); + }))); this.progressService.showWhile(promise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */); @@ -809,7 +839,7 @@ export class ExplorerView extends CollapsibleView { // Drop those path which are parents of the current one for (let i = resolvedDirectories.length - 1; i >= 0; i--) { const resource = resolvedDirectories[i]; - if (paths.isEqualOrParent(stat.resource.fsPath, resource.fsPath, !isLinux /* ignorecase */)) { + if (resources.isEqualOrParent(stat.resource, resource, !isLinux /* ignorecase */)) { resolvedDirectories.splice(i); } } @@ -855,7 +885,8 @@ export class ExplorerView extends CollapsibleView { // Stat needs to be resolved first and then revealed const options: IResolveFileOptions = { resolveTo: [resource] }; - const rootUri = this.contextService.getRoot(resource) || this.model.roots[0].resource; + const workspaceFolder = this.contextService.getWorkspaceFolder(resource); + const rootUri = workspaceFolder ? workspaceFolder.uri : this.model.roots[0].resource; return this.fileService.resolveFile(rootUri, options).then(stat => { // Convert to model @@ -935,12 +966,4 @@ export class ExplorerView extends CollapsibleView { super.shutdown(); } - - public dispose(): void { - if (this.toolBar) { - this.toolBar.dispose(); - } - - super.dispose(); - } } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 5eca34ae11a..6b80e582f28 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -13,6 +13,7 @@ import URI from 'vs/base/common/uri'; import { MIME_BINARY } from 'vs/base/common/mime'; import { once } from 'vs/base/common/functional'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import errors = require('vs/base/common/errors'); import { isString } from 'vs/base/common/types'; import { IAction, ActionRunner as BaseActionRunner, IActionRunner } from 'vs/base/common/actions'; @@ -21,7 +22,7 @@ import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { isMacintosh, isLinux } from 'vs/base/common/platform'; import glob = require('vs/base/common/glob'); import { FileLabel, IFileLabelOptions } from 'vs/workbench/browser/labels'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; import { IFilesConfiguration, SortOrder } from 'vs/workbench/parts/files/common/files'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -35,12 +36,12 @@ import { FileStat, NewStatPlaceholder, Model } from 'vs/workbench/parts/files/co import { DragMouseEvent, IMouseEvent } from 'vs/base/browser/mouseEvent'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService, IConfirmation, Severity } from 'vs/platform/message/common/message'; +import { IMessageService, IConfirmation, Severity, IConfirmationResult } from 'vs/platform/message/common/message'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -52,18 +53,15 @@ import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { distinct } from 'vs/base/common/arrays'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { getPathLabel } from 'vs/base/common/labels'; -import { extractResources } from 'vs/base/browser/dnd'; +import { extractResources } from 'vs/workbench/browser/editor'; export class FileDataSource implements IDataSource { constructor( @IProgressService private progressService: IProgressService, @IMessageService private messageService: IMessageService, @IFileService private fileService: IFileService, - @IPartService private partService: IPartService, - @IWorkspaceContextService private contextService: IWorkspaceContextService + @IPartService private partService: IPartService ) { } public getId(tree: ITree, stat: FileStat | Model): string { @@ -106,14 +104,8 @@ export class FileDataSource implements IDataSource { return stat.children; }, (e: any) => { - stat.exists = false; stat.hasChildren = false; - if (!stat.isRoot) { - this.messageService.show(Severity.Error, e); - } else { - // We render the roots that do not exist differently, nned to do a refresh - tree.refresh(stat, false); - } + this.messageService.show(Severity.Error, e); return []; // we could not resolve any children because of an error }); @@ -283,14 +275,27 @@ export class FileRenderer implements IRenderer { private static FILE_TEMPLATE_ID = 'file'; private state: FileViewletState; + private config: IFilesConfiguration; + private configListener: IDisposable; constructor( state: FileViewletState, @IContextViewService private contextViewService: IContextViewService, @IInstantiationService private instantiationService: IInstantiationService, - @IThemeService private themeService: IThemeService + @IThemeService private themeService: IThemeService, + @IConfigurationService private configurationService: IConfigurationService ) { this.state = state; + this.config = this.configurationService.getConfiguration(); + this.configListener = this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('explorer')) { + this.config = this.configurationService.getConfiguration(); + } + }); + } + + dispose(): void { + this.configListener.dispose(); } public getHeight(tree: ITree, element: any): number { @@ -316,12 +321,14 @@ export class FileRenderer implements IRenderer { // File Label if (!editableData) { - templateData.label.element.style.display = 'block'; + templateData.label.element.style.display = 'flex'; const extraClasses = ['explorer-item']; - if (!stat.exists && stat.isRoot) { - extraClasses.push('nonexistent-root'); - } - templateData.label.setFile(stat.resource, { hidePath: true, fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, extraClasses }); + templateData.label.setFile(stat.resource, { + hidePath: true, + fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, + extraClasses, + fileDecorations: this.config.explorer.decorations + }); } // Input Box @@ -343,16 +350,15 @@ export class FileRenderer implements IRenderer { // Input field for name const inputBox = new InputBox(label.element, this.contextViewService, { validationOptions: { - validation: editableData.validator, - showMessage: true + validation: editableData.validator }, ariaLabel: nls.localize('fileInputAriaLabel', "Type file name. Press Enter to confirm or Escape to cancel.") }); const styler = attachInputBoxStyler(inputBox, this.themeService); - const parent = paths.dirname(stat.resource.fsPath); + const parent = resources.dirname(stat.resource); inputBox.onDidChange(value => { - label.setFile(URI.file(paths.join(parent, value)), labelOptions); // update label icon while typing! + label.setFile(parent.with({ path: paths.join(parent.path, value) }), labelOptions); // update label icon while typing! }); const value = stat.name || ''; @@ -416,9 +422,7 @@ export class FileController extends DefaultController { constructor(state: FileViewletState, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IContextMenuService private contextMenuService: IContextMenuService, - @IInstantiationService private instantiationService: IInstantiationService, @ITelemetryService private telemetryService: ITelemetryService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @IMenuService menuService: IMenuService, @IContextKeyService contextKeyService: IContextKeyService ) { @@ -507,7 +511,7 @@ export class FileController extends DefaultController { return true; } - const anchor = { x: event.posx + 1, y: event.posy }; + const anchor = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, getActions: () => { @@ -536,6 +540,12 @@ export class FileController extends DefaultController { public openEditor(stat: FileStat, options: { preserveFocus: boolean; sideBySide: boolean; pinned: boolean; }): void { if (stat && !stat.isDirectory) { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: 'workbench.files.openFile', from: 'explorer' }); this.editorService.openEditor({ resource: stat.resource, options }, options.sideBySide).done(null, errors.onUnexpectedError); @@ -549,29 +559,35 @@ export class FileSorter implements ISorter { private sortOrder: SortOrder; constructor( - @IConfigurationService private configurationService: IConfigurationService + @IConfigurationService private configurationService: IConfigurationService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { this.toDispose = []; - this.onConfigurationUpdated(configurationService.getConfiguration()); + this.updateSortOrder(); this.registerListeners(); } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.updateSortOrder())); } - private onConfigurationUpdated(configuration: IFilesConfiguration): void { - this.sortOrder = configuration && configuration.explorer && configuration.explorer.sortOrder || 'default'; + private updateSortOrder(): void { + this.sortOrder = this.configurationService.getValue('explorer.sortOrder') || 'default'; } public compare(tree: ITree, statA: FileStat, statB: FileStat): number { // Do not sort roots if (statA.isRoot) { + if (statB.isRoot) { + return this.contextService.getWorkspaceFolder(statA.resource).index - this.contextService.getWorkspaceFolder(statB.resource).index; + } + return -1; } + if (statB.isRoot) { return 1; } @@ -604,6 +620,9 @@ export class FileSorter implements ISorter { break; + case 'mixed': + break; // not sorting when "mixed" is on + default: /* 'default', 'modified' */ if (statA.isDirectory && !statB.isDirectory) { return -1; @@ -641,6 +660,10 @@ export class FileSorter implements ISorter { return comparers.compareFileNames(statA.name, statB.name); } } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + } } // Explorer Filter @@ -649,22 +672,28 @@ export class FileFilter implements IFilter { private static MAX_SIBLINGS_FILTER_THRESHOLD = 2000; private hiddenExpressionPerRoot: Map; + private workspaceFolderChangeListener: IDisposable; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService ) { this.hiddenExpressionPerRoot = new Map(); - this.contextService.onDidChangeWorkspaceRoots(() => this.updateConfiguration()); + + this.registerListeners(); + } + + public registerListeners(): void { + this.workspaceFolderChangeListener = this.contextService.onDidChangeWorkspaceFolders(() => this.updateConfiguration()); } public updateConfiguration(): boolean { let needsRefresh = false; - this.contextService.getWorkspace().roots.forEach(root => { - const configuration = this.configurationService.getConfiguration(undefined, { resource: root }); + this.contextService.getWorkspace().folders.forEach(folder => { + const configuration = this.configurationService.getConfiguration({ resource: folder.uri }); const excludesConfig = (configuration && configuration.files && configuration.files.exclude) || Object.create(null); - needsRefresh = needsRefresh || !objects.equals(this.hiddenExpressionPerRoot.get(root.toString()), excludesConfig); - this.hiddenExpressionPerRoot.set(root.toString(), objects.clone(excludesConfig)); // do not keep the config, as it gets mutated under our hoods + needsRefresh = needsRefresh || !objects.equals(this.hiddenExpressionPerRoot.get(folder.uri.toString()), excludesConfig); + this.hiddenExpressionPerRoot.set(folder.uri.toString(), objects.clone(excludesConfig)); // do not keep the config, as it gets mutated under our hoods }); return needsRefresh; @@ -694,31 +723,36 @@ export class FileFilter implements IFilter { return true; } + + public dispose(): void { + this.workspaceFolderChangeListener = dispose(this.workspaceFolderChangeListener); + } } // Explorer Drag And Drop Controller export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { + + private static CONFIRM_DND_SETTING_KEY = 'explorer.confirmDragAndDrop'; + private toDispose: IDisposable[]; private dropEnabled: boolean; constructor( @IMessageService private messageService: IMessageService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IProgressService private progressService: IProgressService, @IFileService private fileService: IFileService, @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService private instantiationService: IInstantiationService, @ITextFileService private textFileService: ITextFileService, @IBackupFileService private backupFileService: IBackupFileService, @IWindowService private windowService: IWindowService, - @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, - @IEnvironmentService private environmentService: IEnvironmentService + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService ) { super(stat => this.statToResource(stat)); this.toDispose = []; - this.onConfigurationUpdated(configurationService.getConfiguration()); + this.updateDropEnablement(); this.registerListeners(); } @@ -729,18 +763,18 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { } if (stat.isDirectory) { - return URI.from({ scheme: 'folder', path: stat.resource.fsPath }); // indicates that we are dragging a folder + return URI.from({ scheme: 'folder', path: stat.resource.path }); // indicates that we are dragging a folder } return stat.resource; } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.updateDropEnablement())); } - private onConfigurationUpdated(config: IFilesConfiguration): void { - this.dropEnabled = config && config.explorer && config.explorer.enableDragAndDrop; + private updateDropEnablement(): void { + this.dropEnabled = this.configurationService.getValue('explorer.enableDragAndDrop'); } public onDragStart(tree: ITree, data: IDragAndDropData, originalEvent: DragMouseEvent): void { @@ -813,11 +847,11 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { return true; // Can not move anything onto itself } - if (!isCopy && paths.isEqual(paths.dirname(source.resource.fsPath), target.resource.fsPath)) { + if (!isCopy && resources.dirname(source.resource).toString() === target.resource.toString()) { return true; // Can not move a file to the same parent unless we copy } - if (paths.isEqualOrParent(target.resource.fsPath, source.resource.fsPath, !isLinux /* ignorecase */)) { + if (resources.isEqualOrParent(target.resource, source.resource, !isLinux /* ignorecase */)) { return true; // Can not move a parent folder into one of its children } @@ -829,7 +863,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // All (target = model) if (target instanceof Model) { - return this.contextService.hasMultiFolderWorkspace() ? DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY(false) : DRAG_OVER_REJECT; // can only drop folders to workspace + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY(false) : DRAG_OVER_REJECT; // can only drop folders to workspace } // All (target = file/folder) @@ -838,8 +872,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { return fromDesktop || isCopy ? DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY(true) : DRAG_OVER_ACCEPT_BUBBLE_DOWN(true); } - const workspace = this.contextService.getWorkspace(); - if (workspace && workspace.roots.every(r => r.toString() !== target.resource.toString())) { + if (this.contextService.getWorkspace().folders.every(folder => folder.uri.toString() !== target.resource.toString())) { return fromDesktop || isCopy ? DRAG_OVER_ACCEPT_BUBBLE_UP_COPY : DRAG_OVER_ACCEPT_BUBBLE_UP; } } @@ -862,8 +895,6 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { } } - this.progressService.showWhile(promise, 800); - promise.done(null, errors.onUnexpectedError); } @@ -877,37 +908,29 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { this.windowService.focusWindow(); // Handle folders by adding to workspace if we are in workspace context - const folders = result.filter(result => result.stat.isDirectory).map(result => result.stat.resource); + const folders = result.filter(r => r.success && r.stat.isDirectory).map(result => ({ uri: result.stat.resource })); if (folders.length > 0) { - if (this.environmentService.appQuality === 'stable') { - return void 0; // TODO@Ben multi root + + // If we are in no-workspace context, ask for confirmation to create a workspace + let confirmed = true; + if (this.contextService.getWorkbenchState() !== WorkbenchState.WORKSPACE) { + confirmed = this.messageService.confirmSync({ + message: folders.length > 1 ? nls.localize('dropFolders', "Do you want to add the folders to the workspace?") : nls.localize('dropFolder', "Do you want to add the folder to the workspace?"), + type: 'question', + primaryButton: folders.length > 1 ? nls.localize('addFolders', "&&Add Folders") : nls.localize('addFolder', "&&Add Folder") + }); } - if (this.contextService.hasMultiFolderWorkspace()) { - return this.workspaceEditingService.addRoots(folders); - } - - // If we are in single-folder context, ask for confirmation to create a workspace - const result = this.messageService.confirm({ - message: folders.length > 1 ? nls.localize('dropFolders', "Do you want to add the folders to the workspace?") : nls.localize('dropFolder', "Do you want to add the folder to the workspace?"), - type: 'question', - primaryButton: folders.length > 1 ? nls.localize('addFolders', "&&Add Folders") : nls.localize('addFolder', "&&Add Folder") - }); - - if (result) { - const currentRoots = this.contextService.getWorkspace().roots; - const newRoots = [...currentRoots, ...folders]; - - return this.windowService.createAndOpenWorkspace(distinct(newRoots.map(root => root.fsPath))); + if (confirmed) { + return this.workspaceEditingService.addFolders(folders); } } // Handle dropped files (only support FileStat as target) else if (target instanceof FileStat) { const importAction = this.instantiationService.createInstance(ImportFileAction, tree, target, null); - return importAction.run({ - input: { paths: droppedResources.map(res => res.resource.fsPath) } - }); + + return importAction.run(droppedResources.map(res => res.resource)); } return void 0; @@ -918,6 +941,42 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { const source: FileStat = data.getData()[0]; const isCopy = (originalEvent.ctrlKey && !isMacintosh) || (originalEvent.altKey && isMacintosh); + let confirmPromise: TPromise; + + // Handle confirm setting + const confirmDragAndDrop = !isCopy && this.configurationService.getValue(FileDragAndDrop.CONFIRM_DND_SETTING_KEY); + if (confirmDragAndDrop) { + confirmPromise = this.messageService.confirm({ + message: nls.localize('confirmMove', "Are you sure you want to move '{0}'?", source.name), + checkbox: { + label: nls.localize('doNotAskAgain', "Do not ask me again") + }, + type: 'question', + primaryButton: nls.localize({ key: 'moveButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Move") + }); + } else { + confirmPromise = TPromise.as({ confirmed: true } as IConfirmationResult); + } + + return confirmPromise.then(confirmation => { + + // Check for confirmation checkbox + let updateConfirmSettingsPromise: TPromise = TPromise.as(void 0); + if (confirmation.confirmed && confirmation.checkboxChecked === true) { + updateConfirmSettingsPromise = this.configurationService.updateValue(FileDragAndDrop.CONFIRM_DND_SETTING_KEY, false, ConfigurationTarget.USER); + } + + return updateConfirmSettingsPromise.then(() => { + if (confirmation.confirmed) { + return this.doHandleExplorerDrop(tree, data, source, target, isCopy); + } + + return TPromise.as(void 0); + }); + }); + } + + private doHandleExplorerDrop(tree: ITree, data: IDragAndDropData, source: FileStat, target: FileStat, isCopy: boolean): TPromise { return tree.expand(target).then(() => { // Reuse duplicate action if user copies @@ -939,18 +998,18 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { }; // 1. check for dirty files that are being moved and backup to new target - const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, source.resource.fsPath, !isLinux /* ignorecase */)); + const dirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, source.resource, !isLinux /* ignorecase */)); return TPromise.join(dirty.map(d => { let moved: URI; // If the dirty file itself got moved, just reparent it to the target folder - if (paths.isEqual(source.resource.fsPath, d.fsPath)) { - moved = URI.file(paths.join(target.resource.fsPath, source.name)); + if (source.resource.toString() === d.toString()) { + moved = target.resource.with({ path: paths.join(target.resource.path, source.name) }); } // Otherwise, a parent of the dirty resource got moved, so we have to reparent more complicated. Example: else { - moved = URI.file(paths.join(target.resource.fsPath, d.fsPath.substr(source.parent.resource.fsPath.length + 1))); + moved = target.resource.with({ path: paths.join(target.resource.path, d.path.substr(source.parent.resource.path.length + 1)) }); } dirtyMoved.push(moved); @@ -965,15 +1024,12 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // 3.) run the move operation .then(() => { - const targetResource = URI.file(paths.join(target.resource.fsPath, source.name)); - let didHandleConflict = false; + const targetResource = target.resource.with({ path: paths.join(target.resource.path, source.name) }); return this.fileService.moveFile(source.resource, targetResource).then(null, error => { // Conflict if ((error).fileOperationResult === FileOperationResult.FILE_MOVE_CONFLICT) { - didHandleConflict = true; - const confirm: IConfirmation = { message: nls.localize('confirmOverwriteMessage', "'{0}' already exists in the destination folder. Do you want to replace it?", source.name), detail: nls.localize('irreversible', "This action is irreversible!"), @@ -982,8 +1038,8 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { }; // Move with overwrite if the user confirms - if (this.messageService.confirm(confirm)) { - const targetDirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, targetResource.fsPath, !isLinux /* ignorecase */)); + if (this.messageService.confirmSync(confirm)) { + const targetDirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, targetResource, !isLinux /* ignorecase */)); // Make sure to revert all dirty in target first to be able to overwrite properly return this.textFileService.revertAll(targetDirty, { soft: true /* do not attempt to load content from disk */ }).then(() => { diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts index 38a407ede00..e248d36c195 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts @@ -14,12 +14,12 @@ import { IItemCollapseEvent } from 'vs/base/parts/tree/browser/treeModel'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorStacksModel, IStacksModelChangeEvent, IEditorGroup } from 'vs/workbench/common/editor'; import { SaveAllAction } from 'vs/workbench/parts/files/browser/fileActions'; -import { CollapsibleView, IViewletViewOptions, IViewOptions } from 'vs/workbench/parts/views/browser/views'; -import { IFilesConfiguration, VIEWLET_ID, OpenEditorsFocusedContext, ExplorerFocusedContext } from 'vs/workbench/parts/files/common/files'; +import { ViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { VIEWLET_ID, OpenEditorsFocusedContext, ExplorerFocusedContext } from 'vs/workbench/parts/files/common/files'; import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { OpenEditor } from 'vs/workbench/parts/files/common/explorerModel'; @@ -33,20 +33,16 @@ import { EditorGroup } from 'vs/workbench/common/editor/editorStacksModel'; import { attachListStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; -import { ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; const $ = dom.$; -export class OpenEditorsView extends CollapsibleView { +export class OpenEditorsView extends ViewsViewletPanel { private static DEFAULT_VISIBLE_OPEN_EDITORS = 9; private static DEFAULT_DYNAMIC_HEIGHT = true; static ID = 'workbench.explorer.openEditorsView'; static NAME = nls.localize({ key: 'openEditors', comment: ['Open is an adjective'] }, "Open Editors"); - private visibleOpenEditors: number; - private dynamicHeight: boolean; - private model: IEditorStacksModel; private dirtyCountElement: HTMLElement; private structuralTreeRefreshScheduler: RunOnceScheduler; @@ -58,7 +54,6 @@ export class OpenEditorsView extends CollapsibleView { private explorerFocusedContext: IContextKey; constructor( - initialSize: number, options: IViewletViewOptions, @IInstantiationService private instantiationService: IInstantiationService, @IContextMenuService contextMenuService: IContextMenuService, @@ -72,11 +67,9 @@ export class OpenEditorsView extends CollapsibleView { @IViewletService private viewletService: IViewletService, @IThemeService private themeService: IThemeService ) { - super(initialSize, { + super({ ...(options as IViewOptions), ariaHeaderLabel: nls.localize({ key: 'openEditosrSection', comment: ['Open is an adjective'] }, "Open Editors Section"), - sizing: ViewSizing.Fixed, - initialBodySize: OpenEditorsView.computeExpandedBodySize(editorGroupService.getStacksModel()) }, keybindingService, contextMenuService); this.model = editorGroupService.getStacksModel(); @@ -88,14 +81,14 @@ export class OpenEditorsView extends CollapsibleView { this.structuralTreeRefreshScheduler = new RunOnceScheduler(() => this.structuralTreeUpdate(), this.structuralRefreshDelay); } - public renderHeader(container: HTMLElement): void { - const titleDiv = dom.append(container, $('.title')); - const titleSpan = dom.append(titleDiv, $('span')); - titleSpan.textContent = this.name; + protected renderHeaderTitle(container: HTMLElement): void { + const title = dom.append(container, $('.title')); + dom.append(title, $('span', null, this.name)); - this.dirtyCountElement = dom.append(titleDiv, $('.monaco-count-badge')); + const count = dom.append(container, $('.count')); + this.dirtyCountElement = dom.append(count, $('.monaco-count-badge')); - this.toDispose.push((attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { + this.disposables.push((attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : null; const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; @@ -109,8 +102,6 @@ export class OpenEditorsView extends CollapsibleView { }))); this.updateDirtyIndicator(); - - super.renderHeader(container); } public getActions(): IAction[] { @@ -148,20 +139,20 @@ export class OpenEditorsView extends CollapsibleView { }); // Theme styler - this.toDispose.push(attachListStyler(this.tree, this.themeService)); + this.disposables.push(attachListStyler(this.tree, this.themeService)); // Register to list service - this.toDispose.push(this.listService.register(this.tree, [this.explorerFocusedContext, this.openEditorsFocusedContext])); + this.disposables.push(this.listService.register(this.tree, [this.explorerFocusedContext, this.openEditorsFocusedContext])); // Open when selecting via keyboard - this.toDispose.push(this.tree.addListener('selection', event => { + this.disposables.push(this.tree.addListener('selection', event => { if (event && event.payload && event.payload.origin === 'keyboard') { controller.openEditor(this.tree.getFocus(), { pinned: false, sideBySide: false, preserveFocus: false }); } })); // Prevent collapsing of editor groups - this.toDispose.push(this.tree.addListener('item:collapsed', (event: IItemCollapseEvent) => { + this.disposables.push(this.tree.addListener('item:collapsed', (event: IItemCollapseEvent) => { if (event.item && event.item.getElement() instanceof EditorGroup) { setTimeout(() => this.tree.expand(event.item.getElement())); // unwind from callback } @@ -174,8 +165,7 @@ export class OpenEditorsView extends CollapsibleView { public create(): TPromise { // Load Config - const configuration = this.configurationService.getConfiguration(); - this.onConfigurationUpdated(configuration); + this.updateSize(); // listeners this.registerListeners(); @@ -186,20 +176,20 @@ export class OpenEditorsView extends CollapsibleView { private registerListeners(): void { // update on model changes - this.toDispose.push(this.model.onModelChanged(e => this.onEditorStacksModelChanged(e))); + this.disposables.push(this.model.onModelChanged(e => this.onEditorStacksModelChanged(e))); // Also handle configuration updates - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(e))); // Handle dirty counter - this.toDispose.push(this.untitledEditorService.onDidChangeDirty(e => this.updateDirtyIndicator())); - this.toDispose.push(this.textFileService.models.onModelsDirty(e => this.updateDirtyIndicator())); - this.toDispose.push(this.textFileService.models.onModelsSaved(e => this.updateDirtyIndicator())); - this.toDispose.push(this.textFileService.models.onModelsSaveError(e => this.updateDirtyIndicator())); - this.toDispose.push(this.textFileService.models.onModelsReverted(e => this.updateDirtyIndicator())); + this.disposables.push(this.untitledEditorService.onDidChangeDirty(e => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsDirty(e => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsSaved(e => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsSaveError(e => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsReverted(e => this.updateDirtyIndicator())); // We are not updating the tree while the viewlet is not visible. Thus refresh when viewlet becomes visible #6702 - this.toDispose.push(this.viewletService.onDidViewletOpen(viewlet => { + this.disposables.push(this.viewletService.onDidViewletOpen(viewlet => { if (viewlet.getId() === VIEWLET_ID) { this.fullRefreshNeeded = true; this.structuralTreeUpdate(); @@ -231,7 +221,7 @@ export class OpenEditorsView extends CollapsibleView { private structuralTreeUpdate(): void { // View size - this.setBodySize(this.getExpandedBodySize(this.model)); + this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize(this.model); // Show groups only if there is more than 1 group const treeInput = this.model.groups.length === 1 ? this.model.groups[0] : this.model; // TODO@Isidor temporary workaround due to a partial tree refresh issue @@ -265,27 +255,24 @@ export class OpenEditorsView extends CollapsibleView { } } - private onConfigurationUpdated(configuration: IFilesConfiguration): void { + private onConfigurationChange(event: IConfigurationChangeEvent): void { if (this.isDisposed) { return; // guard against possible race condition when config change causes recreate of views } - let visibleOpenEditors = configuration && configuration.explorer && configuration.explorer.openEditors && configuration.explorer.openEditors.visible; - if (typeof visibleOpenEditors === 'number') { - this.visibleOpenEditors = visibleOpenEditors; - } else { - this.visibleOpenEditors = OpenEditorsView.DEFAULT_VISIBLE_OPEN_EDITORS; + if (event.affectsConfiguration('explorer.openEditors')) { + this.updateSize(); } - let dynamicHeight = configuration && configuration.explorer && configuration.explorer.openEditors && configuration.explorer.openEditors.dynamicHeight; - if (typeof dynamicHeight === 'boolean') { - this.dynamicHeight = dynamicHeight; - } else { - this.dynamicHeight = OpenEditorsView.DEFAULT_DYNAMIC_HEIGHT; + // Trigger a 'repaint' when decoration settings change + if (event.affectsConfiguration('explorer.decorations')) { + this.tree.refresh(); } + } + private updateSize(): void { // Adjust expanded body size - this.setBodySize(this.getExpandedBodySize(this.model)); + this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize(this.model); } private updateDirtyIndicator(): void { @@ -300,7 +287,16 @@ export class OpenEditorsView extends CollapsibleView { } private getExpandedBodySize(model: IEditorStacksModel): number { - return OpenEditorsView.computeExpandedBodySize(model, this.visibleOpenEditors, this.dynamicHeight); + let visibleOpenEditors = this.configurationService.getValue('explorer.openEditors.visible'); + if (typeof visibleOpenEditors !== 'number') { + visibleOpenEditors = OpenEditorsView.DEFAULT_VISIBLE_OPEN_EDITORS; + } + + let dynamicHeight = this.configurationService.getValue('explorer.openEditors.dynamicHeight'); + if (typeof dynamicHeight !== 'boolean') { + dynamicHeight = OpenEditorsView.DEFAULT_DYNAMIC_HEIGHT; + } + return OpenEditorsView.computeExpandedBodySize(model, visibleOpenEditors, dynamicHeight); } private static computeExpandedBodySize(model: IEditorStacksModel, visibleOpenEditors = OpenEditorsView.DEFAULT_VISIBLE_OPEN_EDITORS, dynamicHeight = OpenEditorsView.DEFAULT_DYNAMIC_HEIGHT): number { diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts index d0b0abf6ca6..c72ae86cbaa 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts @@ -24,13 +24,14 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorGroup, IEditorStacksModel } from 'vs/workbench/common/editor'; import { OpenEditor } from 'vs/workbench/parts/files/common/explorerModel'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; -import { explorerItemToFileResource } from 'vs/workbench/parts/files/common/files'; +import { explorerItemToFileResource, IFilesConfiguration } from 'vs/workbench/parts/files/common/files'; import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EditorStacksModel, EditorGroup } from 'vs/workbench/common/editor/editorStacksModel'; import { SaveFileAction, RevertFileAction, SaveFileAsAction, OpenToSideAction, SelectResourceForCompareAction, CompareResourcesAction, SaveAllInGroupAction, CompareWithSavedAction } from 'vs/workbench/parts/files/browser/fileActions'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { CloseOtherEditorsInGroupAction, CloseEditorAction, CloseEditorsInGroupAction, CloseUnmodifiedEditorsInGroupAction } from 'vs/workbench/browser/parts/editor/editorActions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const $ = dom.$; @@ -86,7 +87,8 @@ export class Renderer implements IRenderer { constructor( private actionProvider: ActionProvider, @IInstantiationService private instantiationService: IInstantiationService, - @IKeybindingService private keybindingService: IKeybindingService + @IKeybindingService private keybindingService: IKeybindingService, + @IConfigurationService private configurationService: IConfigurationService ) { // noop } @@ -149,7 +151,11 @@ export class Renderer implements IRenderer { private renderOpenEditor(tree: ITree, editor: OpenEditor, templateData: IOpenEditorTemplateData): void { editor.isDirty() ? dom.addClass(templateData.container, 'dirty') : dom.removeClass(templateData.container, 'dirty'); - templateData.root.setEditor(editor.editorInput, { italic: editor.isPreview(), extraClasses: ['open-editor'] }); + templateData.root.setEditor(editor.editorInput, { + italic: editor.isPreview(), + extraClasses: ['open-editor'], + fileDecorations: this.configurationService.getConfiguration().explorer.decorations + }); templateData.actionBar.context = { group: editor.editorGroup, editor: editor.editorInput }; } @@ -256,7 +262,7 @@ export class Controller extends DefaultController { const group = element instanceof EditorGroup ? element : (element).editorGroup; const editor = element instanceof OpenEditor ? (element).editorInput : undefined; - let anchor = { x: event.posx + 1, y: event.posy }; + let anchor = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, getActions: () => this.actionProvider.getSecondaryActions(tree, element), @@ -273,6 +279,12 @@ export class Controller extends DefaultController { public openEditor(element: OpenEditor, options: { preserveFocus: boolean; pinned: boolean; sideBySide: boolean; }): void { if (element) { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: 'workbench.files.openFile', from: 'openEditors' }); let position = this.model.positionOfGroup(element.editorGroup); if (options.sideBySide && position !== Position.THREE) { diff --git a/src/vs/workbench/parts/files/common/dirtyFilesTracker.ts b/src/vs/workbench/parts/files/common/dirtyFilesTracker.ts index f02e1e86e24..31c62f9d546 100644 --- a/src/vs/workbench/parts/files/common/dirtyFilesTracker.ts +++ b/src/vs/workbench/parts/files/common/dirtyFilesTracker.ts @@ -19,7 +19,7 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import URI from 'vs/base/common/uri'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IActivityBarService, NumberBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import arrays = require('vs/base/common/arrays'); @@ -35,7 +35,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution { @ILifecycleService private lifecycleService: ILifecycleService, @IEditorGroupService editorGroupService: IEditorGroupService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IActivityBarService private activityBarService: IActivityBarService, + @IActivityService private activityService: IActivityService, @IWindowService private windowService: IWindowService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService ) { @@ -141,7 +141,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution { this.lastDirtyCount = dirtyCount; dispose(this.badgeHandle); if (dirtyCount > 0) { - this.badgeHandle = this.activityBarService.showActivity(VIEWLET_ID, new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), 'explorer-viewlet-label'); + this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), 'explorer-viewlet-label'); } } diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index 4ab1512df6a..c6ac6973969 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -6,7 +6,9 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; +import { memoize } from 'vs/base/common/decorators'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditorModel } from 'vs/workbench/common/editor'; @@ -22,6 +24,7 @@ import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetryUt import { Verbosity } from 'vs/platform/editor/common/editor'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * A file editor input is the input type for the file editor of file system resources. @@ -32,12 +35,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { private textModelReference: TPromise>; private name: string; - private description: string; - private verboseDescription: string; - - private shortTitle: string; - private mediumTitle: string; - private longTitle: string; private toUnbind: IDisposable[]; @@ -51,7 +48,8 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextFileService private textFileService: ITextFileService, @IEnvironmentService private environmentService: IEnvironmentService, - @ITextModelService private textModelResolverService: ITextModelService + @ITextModelService private textModelResolverService: ITextModelService, + @IHashService private hashService: IHashService ) { super(); @@ -122,37 +120,71 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { public getName(): string { if (!this.name) { - this.name = paths.basename(this.resource.fsPath); + this.name = resources.basenameOrAuthority(this.resource); } return this.decorateOrphanedFiles(this.name); } - public getDescription(verbose?: boolean): string { - if (verbose) { - if (!this.verboseDescription) { - this.verboseDescription = labels.getPathLabel(paths.dirname(this.resource.fsPath), void 0, this.environmentService); - } - } else { - if (!this.description) { - this.description = labels.getPathLabel(paths.dirname(this.resource.fsPath), this.contextService, this.environmentService); - } + @memoize + private get shortDescription(): string { + return paths.basename(labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService)); + } + + @memoize + private get mediumDescription(): string { + return labels.getPathLabel(resources.dirname(this.resource), this.contextService, this.environmentService); + } + + @memoize + private get longDescription(): string { + return labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService); + } + + public getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string { + let description: string; + switch (verbosity) { + case Verbosity.SHORT: + description = this.shortDescription; + break; + case Verbosity.LONG: + description = this.longDescription; + break; + case Verbosity.MEDIUM: + default: + description = this.mediumDescription; + break; } - return verbose ? this.verboseDescription : this.description; + return description; + } + + @memoize + private get shortTitle(): string { + return this.getName(); + } + + @memoize + private get mediumTitle(): string { + return labels.getPathLabel(this.resource, this.contextService, this.environmentService); + } + + @memoize + private get longTitle(): string { + return labels.getPathLabel(this.resource, void 0, this.environmentService); } public getTitle(verbosity: Verbosity): string { let title: string; switch (verbosity) { case Verbosity.SHORT: - title = this.shortTitle ? this.shortTitle : (this.shortTitle = this.getName()); + title = this.shortTitle; break; case Verbosity.MEDIUM: - title = this.mediumTitle ? this.mediumTitle : (this.mediumTitle = labels.getPathLabel(this.resource, this.contextService, this.environmentService)); + title = this.mediumTitle; break; case Verbosity.LONG: - title = this.longTitle ? this.longTitle : (this.longTitle = labels.getPathLabel(this.resource, void 0, this.environmentService)); + title = this.longTitle; break; } @@ -244,8 +276,13 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { public getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); - descriptor['resource'] = telemetryURIDescriptor(this.getResource()); + descriptor['resource'] = telemetryURIDescriptor(this.getResource(), path => this.hashService.createSHA1(path)); + /* __GDPR__FRAGMENT__ + "EditorTelemetryDescriptor" : { + "resource": { "${inline}": [ "${URIDescriptor}" ] } + } + */ return descriptor; } @@ -274,4 +311,4 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return false; } -} +} \ No newline at end of file diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index 52124b9fb7e..771cde62269 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -10,7 +10,7 @@ import errors = require('vs/base/common/errors'); import URI from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); import { IEditorViewState, isCommonCodeEditor } from 'vs/editor/common/editorCommon'; -import { toResource, IEditorStacksModel, SideBySideEditorInput, IEditorGroup, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; +import { toResource, SideBySideEditorInput, IEditorGroup, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/parts/files/common/files'; import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent, indexOf } from 'vs/platform/files/common/files'; @@ -24,14 +24,16 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { isLinux } from 'vs/base/common/platform'; import { ResourceQueue } from 'vs/base/common/async'; +import { ResourceMap } from 'vs/base/common/map'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export class FileEditorTracker implements IWorkbenchContribution { protected closeOnFileDelete: boolean; - private stacks: IEditorStacksModel; private toUnbind: IDisposable[]; - private modelLoadQueue: ResourceQueue; + private modelLoadQueue: ResourceQueue; + private activeOutOfWorkspaceWatchers: ResourceMap; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -40,11 +42,12 @@ export class FileEditorTracker implements IWorkbenchContribution { @IEditorGroupService private editorGroupService: IEditorGroupService, @IFileService private fileService: IFileService, @IEnvironmentService private environmentService: IEnvironmentService, - @IConfigurationService private configurationService: IConfigurationService + @IConfigurationService private configurationService: IConfigurationService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, ) { this.toUnbind = []; - this.stacks = editorGroupService.getStacksModel(); - this.modelLoadQueue = new ResourceQueue(); + this.modelLoadQueue = new ResourceQueue(); + this.activeOutOfWorkspaceWatchers = new ResourceMap(); this.onConfigurationUpdated(configurationService.getConfiguration()); @@ -63,11 +66,14 @@ export class FileEditorTracker implements IWorkbenchContribution { // Update editors from disk changes this.toUnbind.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); + // Editor changing + this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); + // Lifecycle this.lifecycleService.onShutdown(this.dispose, this); // Configuration - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration()))); } private onConfigurationUpdated(configuration: IWorkbenchEditorConfiguration): void { @@ -205,8 +211,8 @@ export class FileEditorTracker implements IWorkbenchContribution { if (oldResource.toString() === resource.toString()) { reopenFileResource = newResource; // file got moved } else { - const index = indexOf(resource.fsPath, oldResource.fsPath, !isLinux /* ignorecase */); - reopenFileResource = URI.file(paths.join(newResource.fsPath, resource.fsPath.substr(index + oldResource.fsPath.length + 1))); // parent folder got moved + const index = indexOf(resource.path, oldResource.path, !isLinux /* ignorecase */); + reopenFileResource = newResource.with({ path: paths.join(newResource.path, resource.path.substr(index + oldResource.path.length + 1)) }); // parent folder got moved } // Reopen @@ -232,9 +238,9 @@ export class FileEditorTracker implements IWorkbenchContribution { for (let i = 0; i < editors.length; i++) { const editor = editors[i]; - if (editor && editor.position === stacks.positionOfGroup(group)) { - const resource = toResource(editor.input, { filter: 'file' }); - if (resource && paths.isEqual(resource.fsPath, resource.fsPath)) { + if (editor && editor.input && editor.position === stacks.positionOfGroup(group)) { + const editorResource = editor.input.getResource(); + if (editorResource && resource.toString() === editorResource.toString()) { const control = editor.getControl(); if (isCommonCodeEditor(control)) { return control.saveViewState(); @@ -258,10 +264,10 @@ export class FileEditorTracker implements IWorkbenchContribution { private handleUpdatesToVisibleBinaryEditors(e: FileChangesEvent): void { const editors = this.editorService.getVisibleEditors(); editors.forEach(editor => { - const fileResource = toResource(editor.input, { filter: 'file', supportSideBySide: true }); + const resource = toResource(editor.input, { supportSideBySide: true }); // Binary editor that should reload from event - if (fileResource && editor.getId() === BINARY_FILE_EDITOR_ID && (e.contains(fileResource, FileChangeType.UPDATED) || e.contains(fileResource, FileChangeType.ADDED))) { + if (resource && editor.getId() === BINARY_FILE_EDITOR_ID && (e.contains(resource, FileChangeType.UPDATED) || e.contains(resource, FileChangeType.ADDED))) { this.editorService.openEditor(editor.input, { forceOpen: true, preserveFocus: true }, editor.position).done(null, errors.onUnexpectedError); } }); @@ -290,7 +296,42 @@ export class FileEditorTracker implements IWorkbenchContribution { } } + private onEditorsChanged(): void { + this.handleOutOfWorkspaceWatchers(); + } + + private handleOutOfWorkspaceWatchers(): void { + const visibleOutOfWorkspacePaths = new ResourceMap(); + this.editorService.getVisibleEditors().map(editor => { + return toResource(editor.input, { supportSideBySide: true }); + }).filter(resource => { + return !!resource && this.fileService.canHandleResource(resource) && !this.contextService.isInsideWorkspace(resource); + }).forEach(resource => { + visibleOutOfWorkspacePaths.set(resource, resource); + }); + + // Handle no longer visible out of workspace resources + this.activeOutOfWorkspaceWatchers.forEach(resource => { + if (!visibleOutOfWorkspacePaths.get(resource)) { + this.fileService.unwatchFileChanges(resource); + this.activeOutOfWorkspaceWatchers.delete(resource); + } + }); + + // Handle newly visible out of workspace resources + visibleOutOfWorkspacePaths.forEach(resource => { + if (!this.activeOutOfWorkspaceWatchers.get(resource)) { + this.fileService.watchFileChanges(resource); + this.activeOutOfWorkspaceWatchers.set(resource, resource); + } + }); + } + public dispose(): void { this.toUnbind = dispose(this.toUnbind); + + // Dispose watchers if any + this.activeOutOfWorkspaceWatchers.forEach(resource => this.fileService.unwatchFileChanges(resource)); + this.activeOutOfWorkspaceWatchers.clear(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/files/common/explorerModel.ts b/src/vs/workbench/parts/files/common/explorerModel.ts index e3d97b1d97b..3d011a1c2a1 100644 --- a/src/vs/workbench/parts/files/common/explorerModel.ts +++ b/src/vs/workbench/parts/files/common/explorerModel.ts @@ -13,6 +13,7 @@ import { IFileStat, isParent } from 'vs/platform/files/common/files'; import { IEditorInput } from 'vs/platform/editor/common/editor'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEditorGroup, toResource } from 'vs/workbench/common/editor'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; export enum StatType { FILE, @@ -23,10 +24,16 @@ export enum StatType { export class Model { private _roots: FileStat[]; + private _listener: IDisposable; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService) { - const setRoots = () => this._roots = this.contextService.getWorkspace().roots.map(uri => new FileStat(uri, undefined)); - this.contextService.onDidChangeWorkspaceRoots(() => setRoots()); + const setRoots = () => this._roots = this.contextService.getWorkspace().folders.map(folder => { + const root = new FileStat(folder.uri, undefined); + root.name = folder.name; + + return root; + }); + this._listener = this.contextService.onDidChangeWorkspaceFolders(() => setRoots()); setRoots(); } @@ -49,9 +56,9 @@ export class Model { * Will return null in case the FileStat does not exist. */ public findClosest(resource: URI): FileStat { - const rootUri = this.contextService.getRoot(resource); - if (rootUri) { - const root = this.roots.filter(r => r.resource.toString() === rootUri.toString()).pop(); + const folder = this.contextService.getWorkspaceFolder(resource); + if (folder) { + const root = this.roots.filter(r => r.resource.toString() === folder.uri.toString()).pop(); if (root) { return root.find(resource); } @@ -59,6 +66,10 @@ export class Model { return null; } + + public dispose(): void { + this._listener = dispose(this._listener); + } } export class FileStat implements IFileStat { @@ -66,12 +77,11 @@ export class FileStat implements IFileStat { public name: string; public mtime: number; public etag: string; - public isDirectory: boolean; + private _isDirectory: boolean; public hasChildren: boolean; public children: FileStat[]; public parent: FileStat; - public exists: boolean; public isDirectoryResolved: boolean; constructor(resource: URI, public root: FileStat, isDirectory?: boolean, hasChildren?: boolean, name: string = paths.basename(resource.fsPath), mtime?: number, etag?: string) { @@ -82,16 +92,31 @@ export class FileStat implements IFileStat { this.etag = etag; this.mtime = mtime; - // Prepare child stat array - if (this.isDirectory) { - this.children = []; - } if (!this.root) { this.root = this; } this.isDirectoryResolved = false; - this.exists = true; + } + + public get isDirectory(): boolean { + return this._isDirectory; + } + + public set isDirectory(value: boolean) { + if (value !== this._isDirectory) { + this._isDirectory = value; + if (this._isDirectory) { + this.children = []; + } else { + this.children = undefined; + } + } + + } + + public get nonexistentRoot(): boolean { + return this.isRoot && !this.isDirectoryResolved && this.isDirectory; } public getId(): string { @@ -262,7 +287,8 @@ export class FileStat implements IFileStat { } private updateResource(recursive: boolean): void { - this.resource = URI.file(paths.join(this.parent.resource.fsPath, this.name)); + this.resource = this.parent.resource.with({ path: paths.join(this.parent.resource.path, this.name) }); + // this.resource = URI.file(paths.join(this.parent.resource.fsPath, this.name)); if (recursive) { if (this.isDirectory && this.hasChildren && this.children) { @@ -421,6 +447,6 @@ export class OpenEditor { } public getResource(): URI { - return toResource(this.editor, { supportSideBySide: true, filter: ['file', 'untitled'] }); + return toResource(this.editor, { supportSideBySide: true }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index f25ed1b9106..e63b3e56b59 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -11,7 +11,7 @@ import { IFilesConfiguration, FileChangeType, IFileService } from 'vs/platform/f import { FileStat, OpenEditor } from 'vs/workbench/parts/files/common/explorerModel'; import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IModel } from 'vs/editor/common/editorCommon'; @@ -69,7 +69,12 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit }; autoReveal: boolean; enableDragAndDrop: boolean; + confirmDelete: boolean; sortOrder: SortOrder; + decorations: { + colors: boolean; + badges: boolean; + }; }; editor: IEditorOptions; } @@ -95,9 +100,9 @@ export function explorerItemToFileResource(obj: FileStat | OpenEditor): IFileRes if (obj instanceof OpenEditor) { const editor = obj as OpenEditor; const resource = editor.getResource(); - if (resource && resource.scheme === 'file') { + if (resource) { return { - resource: editor.getResource() + resource }; } } @@ -127,6 +132,7 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider { } public provideTextContent(resource: URI): TPromise { + const fileOnDiskResource = URI.file(resource.fsPath); // Make sure our file from disk is resolved up to date return this.resolveEditorModel(resource).then(codeEditorModel => { @@ -134,15 +140,14 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider { // Make sure to keep contents on disk up to date when it changes if (!this.fileWatcher) { this.fileWatcher = this.fileService.onFileChanges(changes => { - if (changes.contains(resource, FileChangeType.UPDATED)) { + if (changes.contains(fileOnDiskResource, FileChangeType.UPDATED)) { // this.resolveEditorModel(resource, false /* do not create if missing */).done(null, onUnexpectedError); // update model when resource changes } }); const disposeListener = codeEditorModel.onWillDispose(() => { disposeListener.dispose(); - this.fileWatcher.dispose(); - this.fileWatcher = void 0; + this.fileWatcher = dispose(this.fileWatcher); }); } @@ -175,9 +180,6 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider { } public dispose(): void { - if (this.fileWatcher) { - this.fileWatcher.dispose(); - this.fileWatcher = void 0; - } + this.fileWatcher = dispose(this.fileWatcher); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts index 4f19a7f53e8..494443216a4 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts @@ -19,8 +19,8 @@ import { Verbosity } from 'vs/platform/editor/common/editor'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IModelService } from 'vs/editor/common/services/modelService'; -function toResource(path) { - return URI.file(join('C:\\', new Buffer(this.test.fullTitle()).toString('base64'), path)); +function toResource(self, path) { + return URI.file(join('C:\\', new Buffer(self.test.fullTitle()).toString('base64'), path)); } class ServiceAccessor { @@ -44,9 +44,9 @@ suite('Files - FileEditorInput', () => { }); test('Basics', function (done) { - let input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), void 0); - const otherInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/otherfile.js'), void 0); - const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/file.js'), void 0); + let input = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/file.js'), void 0); + const otherInput = instantiationService.createInstance(FileEditorInput, toResource(this, 'foo/bar/otherfile.js'), void 0); + const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource(this, 'foo/bar/file.js'), void 0); assert(input.matches(input)); assert(input.matches(otherInputSame)); @@ -58,13 +58,13 @@ suite('Files - FileEditorInput', () => { assert.strictEqual('file.js', input.getName()); - assert.strictEqual(toResource.call(this, '/foo/bar/file.js').fsPath, input.getResource().fsPath); + assert.strictEqual(toResource(this, '/foo/bar/file.js').fsPath, input.getResource().fsPath); assert(input.getResource() instanceof URI); - input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar.html'), void 0); + input = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar.html'), void 0); - const inputToResolve: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), void 0); - const sameOtherInput: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), void 0); + const inputToResolve: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/file.js'), void 0); + const sameOtherInput: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/file.js'), void 0); return inputToResolve.resolve(true).then(resolved => { assert.ok(inputToResolve.isResolved()); @@ -86,16 +86,16 @@ suite('Files - FileEditorInput', () => { resolvedModelA.dispose(); - return inputToResolve.resolve(true).then((resolved: TextFileEditorModel) => { + return inputToResolve.resolve(true).then(resolved => { assert(resolvedModelA !== resolved); // Different instance, because input got disposed - let stat = resolved.getStat(); - return inputToResolve.resolve(true).then((resolved: TextFileEditorModel) => { - assert(stat !== resolved.getStat()); // Different stat, because resolve always goes to the server for refresh + let stat = (resolved as TextFileEditorModel).getStat(); + return inputToResolve.resolve(true).then(resolved => { + assert(stat !== (resolved as TextFileEditorModel).getStat()); // Different stat, because resolve always goes to the server for refresh - stat = resolved.getStat(); - return inputToResolve.resolve(false).then((resolved: TextFileEditorModel) => { - assert(stat === resolved.getStat()); // Same stat, because not refreshed + stat = (resolved as TextFileEditorModel).getStat(); + return inputToResolve.resolve(false).then(resolved => { + assert(stat === (resolved as TextFileEditorModel).getStat()); // Same stat, because not refreshed done(); }); @@ -108,10 +108,10 @@ suite('Files - FileEditorInput', () => { }); test('matches', function () { - const input1 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); - const input2 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); - const input3 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/other.js'), void 0); - const input2Upper = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/UPDATEFILE.js'), void 0); + const input1 = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/updatefile.js'), void 0); + const input2 = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/updatefile.js'), void 0); + const input3 = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/other.js'), void 0); + const input2Upper = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/UPDATEFILE.js'), void 0); assert.strictEqual(input1.matches(null), false); assert.strictEqual(input1.matches(input1), true); @@ -122,7 +122,7 @@ suite('Files - FileEditorInput', () => { }); test('getEncoding/setEncoding', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/updatefile.js'), void 0); input.setEncoding('utf16', EncodingMode.Encode); assert.equal(input.getEncoding(), 'utf16'); @@ -137,7 +137,7 @@ suite('Files - FileEditorInput', () => { }); test('save', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/updatefile.js'), void 0); return input.resolve(true).then((resolved: TextFileEditorModel) => { resolved.textEditorModel.setValue('changed'); @@ -154,7 +154,7 @@ suite('Files - FileEditorInput', () => { }); test('revert', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/updatefile.js'), void 0); return input.resolve(true).then((resolved: TextFileEditorModel) => { resolved.textEditorModel.setValue('changed'); @@ -171,7 +171,7 @@ suite('Files - FileEditorInput', () => { }); test('resolve handles binary files', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource(this, '/foo/bar/updatefile.js'), void 0); accessor.textFileService.setResolveTextContentErrorOnce(new FileOperationError('error', FileOperationResult.FILE_IS_BINARY)); @@ -185,7 +185,7 @@ suite('Files - FileEditorInput', () => { }); test('disposes model when not open anymore', function (done) { - const resource = toResource.call(this, '/path/index.txt'); + const resource = toResource(this, '/path/index.txt'); const input = createFileInput(instantiationService, resource); diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorTracker.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorTracker.test.ts index 93b1c4d0ae9..dab717dcf66 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorTracker.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorTracker.test.ts @@ -27,8 +27,8 @@ class TestFileEditorTracker extends FileEditorTracker { } } -function toResource(path) { - return URI.file(join('C:\\', new Buffer(this.test.fullTitle()).toString('base64'), path)); +function toResource(self: any, path: string) { + return URI.file(join('C:\\', new Buffer(self.test.fullTitle()).toString('base64'), path)); } class ServiceAccessor { @@ -58,8 +58,8 @@ suite('Files - FileEditorTracker', () => { const tracker = instantiationService.createInstance(FileEditorTracker); assert.ok(tracker); - const parent = toResource.call(this, '/foo/bar'); - const resource = toResource.call(this, '/foo/bar/updatefile.js'); + const parent = toResource(this, '/foo/bar'); + const resource = toResource(this, '/foo/bar/updatefile.js'); let input = instantiationService.createInstance(FileEditorInput, resource, void 0); group.openEditor(input); @@ -72,7 +72,7 @@ suite('Files - FileEditorTracker', () => { input = instantiationService.createInstance(FileEditorInput, resource, void 0); group.openEditor(input); - const other = toResource.call(this, '/foo/barfoo'); + const other = toResource(this, '/foo/barfoo'); accessor.fileService.fireAfterOperation(new FileOperationEvent(other, FileOperation.DELETE)); assert.ok(!input.isDisposed()); @@ -81,7 +81,7 @@ suite('Files - FileEditorTracker', () => { assert.ok(input.isDisposed()); // Move - const to = toResource.call(this, '/foo/barfoo/change.js'); + const to: any = toResource(this, '/foo/barfoo/change.js'); accessor.fileService.fireAfterOperation(new FileOperationEvent(resource, FileOperation.MOVE, to)); assert.ok(input.isDisposed()); @@ -96,8 +96,8 @@ suite('Files - FileEditorTracker', () => { tracker.setCloseOnFileDelete(false); assert.ok(tracker); - const parent = toResource.call(this, '/foo/bar'); - const resource = toResource.call(this, '/foo/bar/updatefile.js'); + const parent = toResource(this, '/foo/bar'); + const resource = toResource(this, '/foo/bar/updatefile.js'); let input = instantiationService.createInstance(FileEditorInput, resource, void 0); group.openEditor(input); @@ -110,7 +110,7 @@ suite('Files - FileEditorTracker', () => { input = instantiationService.createInstance(FileEditorInput, resource, void 0); group.openEditor(input); - const other = toResource.call(this, '/foo/barfoo'); + const other = toResource(this, '/foo/barfoo'); accessor.fileService.fireAfterOperation(new FileOperationEvent(other, FileOperation.DELETE)); assert.ok(!input.isDisposed()); @@ -119,7 +119,7 @@ suite('Files - FileEditorTracker', () => { assert.ok(input.isDisposed()); // Move - const to = toResource.call(this, '/foo/barfoo/change.js'); + const to: any = toResource(this, '/foo/barfoo/change.js'); accessor.fileService.fireAfterOperation(new FileOperationEvent(resource, FileOperation.MOVE, to)); assert.ok(input.isDisposed()); @@ -133,8 +133,8 @@ suite('Files - FileEditorTracker', () => { const tracker = instantiationService.createInstance(FileEditorTracker); assert.ok(tracker); - const parent = toResource.call(this, '/foo/bar'); - const resource = toResource.call(this, '/foo/bar/updatefile.js'); + const parent = toResource(this, '/foo/bar'); + const resource = toResource(this, '/foo/bar/updatefile.js'); let input = instantiationService.createInstance(FileEditorInput, resource, void 0); group.openEditor(input); @@ -149,7 +149,7 @@ suite('Files - FileEditorTracker', () => { input = instantiationService.createInstance(FileEditorInput, resource, void 0); group.openEditor(input); - const other = toResource.call(this, '/foo/barfoo'); + const other = toResource(this, '/foo/barfoo'); accessor.fileService.fireFileChanges(new FileChangesEvent([{ resource: other, type: FileChangeType.DELETED }])); assert.ok(!input.isDisposed()); @@ -173,7 +173,7 @@ suite('Files - FileEditorTracker', () => { tracker.setCloseOnFileDelete(false); assert.ok(tracker); - const resource = toResource.call(this, '/foo/bar/updatefile.js'); + const resource = toResource(this, '/foo/bar/updatefile.js'); let input = instantiationService.createInstance(FileEditorInput, resource, void 0); group.openEditor(input); @@ -187,7 +187,7 @@ suite('Files - FileEditorTracker', () => { test('file change event updates model', function (done) { const tracker = instantiationService.createInstance(FileEditorTracker); - const resource = toResource.call(this, '/path/index.txt'); + const resource = toResource(this, '/path/index.txt'); accessor.textFileService.models.loadOrCreate(resource).then((model: TextFileEditorModel) => { model.textEditorModel.setValue('Super Good'); diff --git a/src/vs/workbench/parts/html/browser/html.contribution.ts b/src/vs/workbench/parts/html/browser/html.contribution.ts index 0362b085b92..8201c1cfe1d 100644 --- a/src/vs/workbench/parts/html/browser/html.contribution.ts +++ b/src/vs/workbench/parts/html/browser/html.contribution.ts @@ -14,27 +14,26 @@ import { Position as EditorPosition } from 'vs/platform/editor/common/editor'; import { HtmlInput, HtmlInputOptions } from '../common/htmlInput'; import { HtmlPreviewPart } from 'vs/workbench/parts/html/browser/htmlPreviewPart'; import { Registry } from 'vs/platform/registry/common/platform'; -import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { WebviewElement } from 'vs/workbench/parts/html/browser/webview'; import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions'; +import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; function getActivePreviewsForResource(accessor: ServicesAccessor, resource: URI | string) { const uri = resource instanceof URI ? resource : URI.parse(resource); return accessor.get(IWorkbenchEditorService).getVisibleEditors() .filter(c => c instanceof HtmlPreviewPart && c.model) .map(e => e as HtmlPreviewPart) - .filter(e => e.model.uri.scheme === uri.scheme && e.model.uri.fsPath === uri.fsPath); + .filter(e => e.model.uri.scheme === uri.scheme && e.model.uri.toString() === uri.toString()); } // --- Register Editor -(Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(HtmlPreviewPart.ID, - localize('html.editor.label', "Html Preview"), - 'vs/workbench/parts/html/browser/htmlPreviewPart', - 'HtmlPreviewPart'), +(Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor( + HtmlPreviewPart, + HtmlPreviewPart.ID, + localize('html.editor.label', "Html Preview")), [new SyncDescriptor(HtmlInput)]); // --- Register Commands diff --git a/src/vs/workbench/parts/html/browser/webviewEditor.ts b/src/vs/workbench/parts/html/browser/webviewEditor.ts index e859ca71b30..60de417f8e7 100644 --- a/src/vs/workbench/parts/html/browser/webviewEditor.ts +++ b/src/vs/workbench/parts/html/browser/webviewEditor.ts @@ -23,7 +23,7 @@ export interface HtmlPreviewEditorViewState { } /** A context key that is set when a webview editor has focus. */ -export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS = new RawContextKey('webviewEditorFocus', undefined); +export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS = new RawContextKey('webviewEditorFocus', false); /** A context key that is set when a webview editor does not have focus. */ export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.toNegated(); /** A context key that is set when the find widget find input in webview editor webview is focused. */ @@ -31,6 +31,12 @@ export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED = new Ra /** A context key that is set when the find widget find input in webview editor webview is not focused. */ export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.toNegated(); +/** A context key that is set when the find widget in a webview is visible. */ +export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE = new RawContextKey('webviewFindWidgetVisible', false); +/** A context key that is set when the find widget in a webview is not visible. */ +export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.toNegated(); + + /** * This class is only intended to be subclassed and not instantiated. */ @@ -40,6 +46,7 @@ export abstract class WebviewEditor extends BaseWebviewEditor { protected _webview: WebView; protected content: HTMLElement; protected contextKey: IContextKey; + private findWidgetVisible: IContextKey; protected findInputFocusContextKey: IContextKey; constructor( @@ -53,16 +60,19 @@ export abstract class WebviewEditor extends BaseWebviewEditor { if (contextKeyService) { this.contextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.bindTo(contextKeyService); this.findInputFocusContextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(contextKeyService); + this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(contextKeyService); } } public showFind() { if (this._webview) { this._webview.showFind(); + this.findWidgetVisible.set(true); } } public hideFind() { + this.findWidgetVisible.reset(); if (this._webview) { this._webview.hideFind(); } @@ -137,7 +147,9 @@ class HideWebViewEditorFindCommand extends Command { } const hideCommand = new HideWebViewEditorFindCommand({ id: 'editor.action.webvieweditor.hideFind', - precondition: KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, + precondition: ContextKeyExpr.and( + KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, + KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE), kbOpts: { primary: KeyCode.Escape } diff --git a/src/vs/workbench/parts/html/browser/webviewFindWidget.ts b/src/vs/workbench/parts/html/browser/webviewFindWidget.ts index fe9ecaa3fef..3f35b6d15b6 100644 --- a/src/vs/workbench/parts/html/browser/webviewFindWidget.ts +++ b/src/vs/workbench/parts/html/browser/webviewFindWidget.ts @@ -25,7 +25,7 @@ export class WebviewFindWidget extends SimpleFindWidget { if (this.webview !== null && val) { this.webview.find(val, { findNext: true, forward: !previous }); } - }; + } public hide() { super.hide(); diff --git a/src/vs/workbench/parts/html/common/htmlInput.ts b/src/vs/workbench/parts/html/common/htmlInput.ts index fe8955dc0c7..8338d4fd5b6 100644 --- a/src/vs/workbench/parts/html/common/htmlInput.ts +++ b/src/vs/workbench/parts/html/common/htmlInput.ts @@ -7,6 +7,7 @@ import URI from 'vs/base/common/uri'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export interface HtmlInputOptions { @@ -25,8 +26,9 @@ export class HtmlInput extends ResourceEditorInput { description: string, resource: URI, public readonly options: HtmlInputOptions, - @ITextModelService textModelResolverService: ITextModelService + @ITextModelService textModelResolverService: ITextModelService, + @IHashService hashService: IHashService ) { - super(name, description, resource, textModelResolverService); + super(name, description, resource, textModelResolverService, hashService); } } diff --git a/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts new file mode 100644 index 00000000000..5f9edce74d8 --- /dev/null +++ b/src/vs/workbench/parts/markers/browser/markersFileDecorations.ts @@ -0,0 +1,111 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { IMarkerService, IMarker } from 'vs/platform/markers/common/markers'; +import { IDecorationsService, IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import URI from 'vs/base/common/uri'; +import Event from 'vs/base/common/event'; +import { localize } from 'vs/nls'; +import { Registry } from 'vs/platform/registry/common/platform'; +import Severity from 'vs/base/common/severity'; +import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; + +class MarkersDecorationsProvider implements IDecorationsProvider { + + readonly label: string = localize('label', "Problems"); + readonly onDidChange: Event; + + constructor( + private readonly _markerService: IMarkerService + ) { + this.onDidChange = _markerService.onMarkerChanged; + } + + provideDecorations(resource: URI): IDecorationData { + let markers = this._markerService.read({ resource }); + let first: IMarker; + for (const marker of markers) { + if (!first || marker.severity > first.severity) { + first = marker; + } + } + + if (!first) { + return undefined; + } + + return { + weight: 100 * first.severity, + bubble: true, + tooltip: markers.length === 1 ? localize('tooltip.1', "1 problem in this file") : localize('tooltip.N', "{0} problems in this file", markers.length), + letter: markers.length < 10 ? markers.length.toString() : '+9', + color: first.severity === Severity.Error ? editorErrorForeground : editorWarningForeground, + }; + } +} + +class MarkersFileDecorations implements IWorkbenchContribution { + + private readonly _disposables: IDisposable[]; + private _provider: IDisposable; + private _enabled: boolean; + + constructor( + @IMarkerService private _markerService: IMarkerService, + @IDecorationsService private _decorationsService: IDecorationsService, + @IConfigurationService private _configurationService: IConfigurationService + ) { + // + this._disposables = [ + this._configurationService.onDidChangeConfiguration(this._updateEnablement, this), + ]; + this._updateEnablement(); + } + + dispose(): void { + dispose(this._provider); + dispose(this._disposables); + } + + getId(): string { + return 'markers.MarkersFileDecorations'; + } + + private _updateEnablement(): void { + let value = this._configurationService.getConfiguration<{ decorations: { enabled: boolean } }>('problems'); + if (value.decorations.enabled === this._enabled) { + return; + } + this._enabled = value.decorations.enabled; + if (this._enabled) { + const provider = new MarkersDecorationsProvider(this._markerService); + this._provider = this._decorationsService.registerDecorationsProvider(provider); + } else if (this._provider) { + this._enabled = value.decorations.enabled; + this._provider.dispose(); + } + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MarkersFileDecorations); + +Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ + 'id': 'problems', + 'order': 101, + 'type': 'object', + 'properties': { + 'problems.decorations.enabled': { + 'description': localize('markers.showOnFile', "Show Errors & Warnings on files and folder."), + 'type': 'boolean', + 'default': false + } + } +}); diff --git a/src/vs/workbench/parts/markers/browser/markersPanel.ts b/src/vs/workbench/parts/markers/browser/markersPanel.ts index d5554647c19..86daa95eeb3 100644 --- a/src/vs/workbench/parts/markers/browser/markersPanel.ts +++ b/src/vs/workbench/parts/markers/browser/markersPanel.ts @@ -16,11 +16,10 @@ import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { toResource } from 'vs/workbench/common/editor'; import { Panel } from 'vs/workbench/browser/panel'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import Constants from 'vs/workbench/parts/markers/common/constants'; -import { IProblemsConfiguration, MarkersModel, Marker, Resource, FilterOptions } from 'vs/workbench/parts/markers/common/markersModel'; +import { MarkersModel, Marker, Resource, FilterOptions } from 'vs/workbench/parts/markers/common/markersModel'; import { Controller } from 'vs/workbench/parts/markers/browser/markersTreeController'; import Tree = require('vs/base/parts/tree/browser/tree'); import TreeImpl = require('vs/base/parts/tree/browser/treeImpl'); @@ -47,8 +46,7 @@ export class MarkersPanel extends Panel { private delayedRefresh: Delayer; private lastSelectedRelativeTop: number = 0; - private currentActiveFile: URI = null; - private hasToAutoReveal: boolean; + private currentActiveResource: URI = null; private tree: Tree.ITree; private autoExpanded: Set; @@ -63,7 +61,7 @@ export class MarkersPanel extends Panel { private messageBox: HTMLElement; private markerFocusContextKey: IContextKey; - private currentFileGotAddedToMarkersData: boolean = false; + private currentResourceGotAddedToMarkersData: boolean = false; constructor( @IInstantiationService private instantiationService: IInstantiationService, @@ -71,6 +69,7 @@ export class MarkersPanel extends Panel { @IEditorGroupService private editorGroupService: IEditorGroupService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IConfigurationService private configurationService: IConfigurationService, + // @ts-ignore unused injected service @IContextKeyService private contextKeyService: IContextKeyService, @ITelemetryService telemetryService: ITelemetryService, @IListService private listService: IListService, @@ -91,9 +90,6 @@ export class MarkersPanel extends Panel { dom.addClass(parent.getHTMLElement(), 'markers-panel'); - const conf = this.configurationService.getConfiguration(); - this.onConfigurationsUpdated(conf); - let container = dom.append(parent.getHTMLElement(), dom.$('.markers-panel-container')); this.createMessageBox(container); @@ -148,6 +144,11 @@ export class MarkersPanel extends Panel { public openFileAtElement(element: any, preserveFocus: boolean, sideByside: boolean, pinned: boolean): boolean { if (element instanceof Marker) { const marker: Marker = element; + /* __GDPR__ + "problems.marker.opened" : { + "source" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('problems.marker.opened', { source: marker.marker.source }); this.editorService.openEditor({ resource: marker.resource, @@ -249,45 +250,41 @@ export class MarkersPanel extends Panel { } private createListeners(): void { - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationsUpdated(this.configurationService.getConfiguration()))); this.toUnbind.push(this.markerService.onMarkerChanged(this.onMarkerChanged, this)); this.toUnbind.push(this.editorGroupService.onEditorsChanged(this.onEditorsChanged, this)); this.toUnbind.push(this.tree.addListener('selection', () => this.onSelected())); } private onMarkerChanged(changedResources: URI[]) { - this.currentFileGotAddedToMarkersData = this.currentFileGotAddedToMarkersData || this.isCurrentFileGotAddedToMarkersData(changedResources); + this.currentResourceGotAddedToMarkersData = this.currentResourceGotAddedToMarkersData || this.isCurrentResourceGotAddedToMarkersData(changedResources); this.updateResources(changedResources); this.delayedRefresh.trigger(() => { this.refreshPanel(); this.updateRangeHighlights(); - if (this.currentFileGotAddedToMarkersData) { + if (this.currentResourceGotAddedToMarkersData) { this.autoReveal(); - this.currentFileGotAddedToMarkersData = false; + this.currentResourceGotAddedToMarkersData = false; } }); } - private isCurrentFileGotAddedToMarkersData(changedResources: URI[]) { - if (!this.currentActiveFile) { + private isCurrentResourceGotAddedToMarkersData(changedResources: URI[]) { + if (!this.currentActiveResource) { return false; } - const resourceForCurrentActiveFile = this.getResourceForCurrentActiveFile(); - if (resourceForCurrentActiveFile) { + const resourceForCurrentActiveResource = this.getResourceForCurrentActiveResource(); + if (resourceForCurrentActiveResource) { return false; } - return changedResources.some(r => r.toString() === this.currentActiveFile.toString()); + return changedResources.some(r => r.toString() === this.currentActiveResource.toString()); } private onEditorsChanged(): void { - this.currentActiveFile = toResource(this.editorService.getActiveEditorInput(), { filter: 'file' }); + const activeInput = this.editorService.getActiveEditorInput(); + this.currentActiveResource = activeInput ? activeInput.getResource() : void 0; this.autoReveal(); } - private onConfigurationsUpdated(conf: IProblemsConfiguration): void { - this.hasToAutoReveal = conf && conf.problems && conf.problems.autoReveal; - } - private onSelected(): void { let selection = this.tree.getSelection(); if (selection && selection.length > 0) { @@ -333,14 +330,14 @@ export class MarkersPanel extends Panel { } private autoReveal(focus: boolean = false): void { - let conf = this.configurationService.getConfiguration(); - if (conf && conf.problems && conf.problems.autoReveal) { + let autoReveal = this.configurationService.getValue('problems.autoReveal'); + if (typeof autoReveal === 'boolean' && autoReveal) { this.revealMarkersForCurrentActiveEditor(focus); } } private revealMarkersForCurrentActiveEditor(focus: boolean = false): void { - let currentActiveResource = this.getResourceForCurrentActiveFile(); + let currentActiveResource = this.getResourceForCurrentActiveResource(); if (currentActiveResource) { if (this.tree.isExpanded(currentActiveResource) && this.hasSelectedMarkerFor(currentActiveResource)) { this.tree.reveal(this.tree.getSelection()[0], this.lastSelectedRelativeTop); @@ -360,10 +357,10 @@ export class MarkersPanel extends Panel { } } - private getResourceForCurrentActiveFile(): Resource { - if (this.currentActiveFile) { + private getResourceForCurrentActiveResource(): Resource { + if (this.currentActiveResource) { let resources = this.markersModel.filteredResources.filter((resource): boolean => { - return this.currentActiveFile.toString() === resource.uri.toString(); + return this.currentActiveResource.toString() === resource.uri.toString(); }); return resources.length > 0 ? resources[0] : null; } diff --git a/src/vs/workbench/parts/markers/browser/markersPanelActions.ts b/src/vs/workbench/parts/markers/browser/markersPanelActions.ts index fe2ce8c5d8f..a2c0a03bfff 100644 --- a/src/vs/workbench/parts/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/parts/markers/browser/markersPanelActions.ts @@ -41,12 +41,36 @@ export class ToggleMarkersPanelAction extends TogglePanelAction { public run(): TPromise { let promise = super.run(); if (this.isPanelFocused()) { + /* __GDPR__ + "problems.used" : {} + */ this.telemetryService.publicLog('problems.used'); } return promise; } } +export class ShowProblemsPanelAction extends Action { + + public static ID = 'workbench.action.problems.focus'; + public static LABEL = Messages.MARKERS_PANEL_SHOW_LABEL; + + constructor(id: string, label: string, + @IPanelService private panelService: IPanelService, + @ITelemetryService private telemetryService: ITelemetryService + ) { + super(id, label); + } + + public run(): TPromise { + /* __GDPR__ + "problems.used" : {} + */ + this.telemetryService.publicLog('problems.used'); + return this.panelService.openPanel(Constants.MARKERS_PANEL_ID, true); + } +} + export class ToggleErrorsAndWarningsAction extends TogglePanelAction { public static ID: string = 'workbench.action.showErrorsWarnings'; @@ -63,6 +87,9 @@ export class ToggleErrorsAndWarningsAction extends TogglePanelAction { public run(): TPromise { let promise = super.run(); if (this.isPanelFocused()) { + /* __GDPR__ + "problems.used" : {} + */ this.telemetryService.publicLog('problems.used'); } return promise; @@ -77,6 +104,9 @@ export class CollapseAllAction extends TreeCollapseAction { } public run(context?: any): TPromise { + /* __GDPR__ + "problems.collapseAll.used" : {} + */ this.telemetryService.publicLog('problems.collapseAll.used'); return super.run(context); } @@ -87,6 +117,7 @@ export class FilterAction extends Action { public static ID: string = 'workbench.actions.problems.filter'; + // @ts-ignore unused property constructor(private markersPanel: MarkersPanel) { super(FilterAction.ID, Messages.MARKERS_PANEL_ACTION_TOOLTIP_FILTER, 'markers-panel-action-filter', true); } @@ -132,6 +163,13 @@ export class FilterInputBoxActionItem extends BaseActionItem { data['errors'] = this.markersPanel.markersModel.filterOptions.filterErrors; data['warnings'] = this.markersPanel.markersModel.filterOptions.filterWarnings; data['infos'] = this.markersPanel.markersModel.filterOptions.filterInfos; + /* __GDPR__ + "problems.filter" : { + "errors" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "warnings": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "infos": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('problems.filter', data); } diff --git a/src/vs/workbench/parts/markers/browser/markersTreeController.ts b/src/vs/workbench/parts/markers/browser/markersTreeController.ts index 9b420131e3c..51f591e42cd 100644 --- a/src/vs/workbench/parts/markers/browser/markersTreeController.ts +++ b/src/vs/workbench/parts/markers/browser/markersTreeController.ts @@ -51,7 +51,7 @@ export class Controller extends treedefaults.DefaultController { if (!actions.length) { return true; } - const anchor = { x: event.posx + 1, y: event.posy }; + const anchor = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, diff --git a/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts b/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts index a01620d3e42..9e9e050f737 100644 --- a/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts @@ -81,8 +81,11 @@ export class Renderer implements IRenderer { private static FILE_RESOURCE_TEMPLATE_ID = 'file-resource-template'; private static MARKER_TEMPLATE_ID = 'marker-template'; + // @ts-ignore unused property constructor(private actionRunner: IActionRunner, + // @ts-ignore unused property private actionProvider: IActionProvider, + // @ts-ignore unused injected service @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService, @IThemeService private themeService: IThemeService diff --git a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts index b57d35ab938..1ab41b88d24 100644 --- a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts +++ b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts @@ -9,10 +9,10 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { ToggleMarkersPanelAction, ToggleErrorsAndWarningsAction } from 'vs/workbench/parts/markers/browser/markersPanelActions'; +import { ToggleMarkersPanelAction, ToggleErrorsAndWarningsAction, ShowProblemsPanelAction } from 'vs/workbench/parts/markers/browser/markersPanelActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { MarkersPanel } from 'vs/workbench/parts/markers/browser/markersPanel'; @@ -48,10 +48,10 @@ export function registerContributions(): void { } }); + // markers panel Registry.as(PanelExtensions.Panels).registerPanel(new PanelDescriptor( - 'vs/workbench/parts/markers/browser/markersPanel', - 'MarkersPanel', + MarkersPanel, Constants.MARKERS_PANEL_ID, Messages.MARKERS_PANEL_TITLE_PROBLEMS, 'markersPanel', @@ -63,8 +63,9 @@ export function registerContributions(): void { const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_M - }), 'View: Show Problems', Messages.MARKERS_PANEL_VIEW_CATEGORY); + }), 'View: Toggle Problems', Messages.MARKERS_PANEL_VIEW_CATEGORY); + registry.registerWorkbenchAction(new SyncActionDescriptor(ShowProblemsPanelAction, ShowProblemsPanelAction.ID, ShowProblemsPanelAction.LABEL), 'View: Show Problems', Messages.MARKERS_PANEL_VIEW_CATEGORY); // Retaining old action to show errors and warnings, so that custom bindings to this action for existing users works. registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleErrorsAndWarningsAction, ToggleErrorsAndWarningsAction.ID, ToggleErrorsAndWarningsAction.LABEL), 'Show Errors and Warnings'); -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/markers/browser/media/markers.css b/src/vs/workbench/parts/markers/browser/media/markers.css index 78b9a6132bd..91252ec8466 100644 --- a/src/vs/workbench/parts/markers/browser/media/markers.css +++ b/src/vs/workbench/parts/markers/browser/media/markers.css @@ -5,7 +5,7 @@ .monaco-action-bar .action-item.markers-panel-action-filter { max-width: 400px; - min-width: 100px; + min-width: 150px; flex: 1; cursor: default; margin: 4px 10px 0 0; diff --git a/src/vs/workbench/parts/markers/common/constants.ts b/src/vs/workbench/parts/markers/common/constants.ts index 2ac068df006..d470ebfc8b0 100644 --- a/src/vs/workbench/parts/markers/common/constants.ts +++ b/src/vs/workbench/parts/markers/common/constants.ts @@ -8,6 +8,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export default { MARKERS_PANEL_ID: 'workbench.panel.markers', MARKER_COPY_ACTION_ID: 'problems.action.copy', + MARKER_COPY_MESSAGE_ACTION_ID: 'problems.action.copyMessage', MARKER_OPEN_SIDE_ACTION_ID: 'problems.action.openToSide', MarkerFocusContextKey: new RawContextKey('problemFocus', false) diff --git a/src/vs/workbench/parts/markers/common/markersModel.ts b/src/vs/workbench/parts/markers/common/markersModel.ts index 561705c5a60..735d45e845b 100644 --- a/src/vs/workbench/parts/markers/common/markersModel.ts +++ b/src/vs/workbench/parts/markers/common/markersModel.ts @@ -58,11 +58,14 @@ export class Marker { } public toString(): string { - return [`file: '${this.marker.resource}'`, - `severity: '${Severity.toString(this.marker.severity)}'`, - `message: '${this.marker.message}'`, - `at: '${this.marker.startLineNumber},${this.marker.startColumn}'`, - `source: '${this.marker.source ? this.marker.source : ''}'`].join('\n'); + return [ + `file: '${this.marker.resource}'`, + `severity: '${Severity.toString(this.marker.severity)}'`, + `message: '${this.marker.message}'`, + `at: '${this.marker.startLineNumber},${this.marker.startColumn}'`, + `source: '${this.marker.source ? this.marker.source : ''}'`, + `code: '${this.marker.code ? this.marker.code : ''}'` + ].join('\n'); } } diff --git a/src/vs/workbench/parts/markers/common/messages.ts b/src/vs/workbench/parts/markers/common/messages.ts index 81d430a00e7..86438ee2875 100644 --- a/src/vs/workbench/parts/markers/common/messages.ts +++ b/src/vs/workbench/parts/markers/common/messages.ts @@ -11,7 +11,9 @@ import { IMarker } from 'vs/platform/markers/common/markers'; export default class Messages { public static MARKERS_PANEL_VIEW_CATEGORY: string = nls.localize('viewCategory', "View"); - public static MARKERS_PANEL_TOGGLE_LABEL: string = nls.localize('problems.view.show.label', "Show Problems"); + public static MARKERS_PANEL_TOGGLE_LABEL: string = nls.localize('problems.view.toggle.label', "Toggle Problems"); + public static MARKERS_PANEL_SHOW_LABEL: string = nls.localize('problems.view.focus.label', "Focus Problems"); + public static MARKERS_PANEL_HIDE_LABEL: string = nls.localize('problems.view.hide.label', "Hide Problems"); public static PROBLEMS_PANEL_CONFIGURATION_TITLE: string = nls.localize('problems.panel.configuration.title', "Problems View"); public static PROBLEMS_PANEL_CONFIGURATION_AUTO_REVEAL: string = nls.localize('problems.panel.configuration.autoreveal', "Controls if Problems view should automatically reveal files when opening them"); diff --git a/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts index dabfc282a26..8664daaf52b 100644 --- a/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts +++ b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts @@ -25,7 +25,8 @@ export function registerContributions(): void { }, menu: { menuId: MenuId.ProblemsPanelContext, - when: Constants.MarkerFocusContextKey + when: Constants.MarkerFocusContextKey, + group: 'navigation' }, keybinding: { keys: { @@ -34,6 +35,18 @@ export function registerContributions(): void { when: Constants.MarkerFocusContextKey } }); + registerAction({ + id: Constants.MARKER_COPY_MESSAGE_ACTION_ID, + title: localize('copyMarkerMessage', "Copy Message"), + handler(accessor) { + copyMessage(accessor.get(IPanelService)); + }, + menu: { + menuId: MenuId.ProblemsPanelContext, + when: Constants.MarkerFocusContextKey, + group: 'navigation' + } + }); } function copyMarker(panelService: IPanelService) { @@ -46,6 +59,16 @@ function copyMarker(panelService: IPanelService) { } } +function copyMessage(panelService: IPanelService) { + const activePanel = panelService.getActivePanel(); + if (activePanel instanceof MarkersPanel) { + const element = (activePanel).getFocusElement(); + if (element instanceof Marker) { + clipboard.writeText(element.marker.message); + } + } +} + interface IActionDescriptor { id: string; handler: ICommandHandler; diff --git a/src/vs/workbench/parts/markers/markers.contribution.ts b/src/vs/workbench/parts/markers/markers.contribution.ts index 8e93a5abe41..b7b91dbc852 100644 --- a/src/vs/workbench/parts/markers/markers.contribution.ts +++ b/src/vs/workbench/parts/markers/markers.contribution.ts @@ -5,5 +5,7 @@ import { registerContributions } from 'vs/workbench/parts/markers/browser/markersWorkbenchContributions'; import { registerContributions as registerElectronContributions } from 'vs/workbench/parts/markers/electron-browser/markersElectronContributions'; +import './browser/markersFileDecorations'; + registerContributions(); -registerElectronContributions(); \ No newline at end of file +registerElectronContributions(); diff --git a/src/vs/workbench/parts/markers/test/common/markersModel.test.ts b/src/vs/workbench/parts/markers/test/common/markersModel.test.ts index 450eb2d2ff9..eacdf1fcc13 100644 --- a/src/vs/workbench/parts/markers/test/common/markersModel.test.ts +++ b/src/vs/workbench/parts/markers/test/common/markersModel.test.ts @@ -121,10 +121,12 @@ suite('MarkersModel Test', () => { }); test('toString()', function () { - assert.equal(`file: 'file:///a/res1'\nseverity: 'Error'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'`, new Marker('', aMarker('a/res1')).toString()); - assert.equal(`file: 'file:///a/res2'\nseverity: 'Warning'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'`, new Marker('', aMarker('a/res2', Severity.Warning)).toString()); - assert.equal(`file: 'file:///a/res2'\nseverity: 'Info'\nmessage: 'Info'\nat: '1,2'\nsource: ''`, new Marker('', aMarker('a/res2', Severity.Info, 1, 2, 1, 8, 'Info', '')).toString()); - assert.equal(`file: 'file:///a/res2'\nseverity: ''\nmessage: 'Ignore message'\nat: '1,2'\nsource: 'Ignore'`, new Marker('', aMarker('a/res2', Severity.Ignore, 1, 2, 1, 8, 'Ignore message', 'Ignore')).toString()); + const res1Marker = aMarker('a/res1'); + res1Marker.code = '1234'; + assert.equal(`file: 'file:///a/res1'\nseverity: 'Error'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'\ncode: '1234'`, new Marker('', res1Marker).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: 'Warning'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'\ncode: ''`, new Marker('', aMarker('a/res2', Severity.Warning)).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: 'Info'\nmessage: 'Info'\nat: '1,2'\nsource: ''\ncode: ''`, new Marker('', aMarker('a/res2', Severity.Info, 1, 2, 1, 8, 'Info', '')).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: ''\nmessage: 'Ignore message'\nat: '1,2'\nsource: 'Ignore'\ncode: ''`, new Marker('', aMarker('a/res2', Severity.Ignore, 1, 2, 1, 8, 'Ignore message', 'Ignore')).toString()); }); function hasMarker(markers: Marker[], marker: IMarker): boolean { diff --git a/src/vs/workbench/parts/output/browser/output.contribution.ts b/src/vs/workbench/parts/output/browser/output.contribution.ts index 5852791b7f7..2809a152fc1 100644 --- a/src/vs/workbench/parts/output/browser/output.contribution.ts +++ b/src/vs/workbench/parts/output/browser/output.contribution.ts @@ -10,13 +10,14 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { OutputService } from 'vs/workbench/parts/output/browser/outputServices'; import { ToggleOutputAction, ClearOutputAction } from 'vs/workbench/parts/output/browser/outputActions'; import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_PANEL_ID, IOutputService, CONTEXT_IN_OUTPUT } from 'vs/workbench/parts/output/common/output'; import { PanelRegistry, Extensions, PanelDescriptor } from 'vs/workbench/browser/panel'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { OutputPanel } from 'vs/workbench/parts/output/browser/outputPanel'; // Register Service registerSingleton(IOutputService, OutputService); @@ -31,8 +32,7 @@ ModesRegistry.registerLanguage({ // Register Output Panel Registry.as(Extensions.Panels).registerPanel(new PanelDescriptor( - 'vs/workbench/parts/output/browser/outputPanel', - 'OutputPanel', + OutputPanel, OUTPUT_PANEL_ID, nls.localize('output', "Output"), 'output', diff --git a/src/vs/workbench/parts/output/browser/outputPanel.ts b/src/vs/workbench/parts/output/browser/outputPanel.ts index 811e8d69a05..73c2d9a89be 100644 --- a/src/vs/workbench/parts/output/browser/outputPanel.ts +++ b/src/vs/workbench/parts/output/browser/outputPanel.ts @@ -22,7 +22,6 @@ import { OutputEditors, OUTPUT_PANEL_ID, IOutputService, CONTEXT_IN_OUTPUT } fro import { SwitchOutputAction, SwitchOutputActionItem, ClearOutputAction, ToggleOutputScrollLockAction } from 'vs/workbench/parts/output/browser/outputActions'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; export class OutputPanel extends TextResourceEditor { @@ -38,10 +37,9 @@ export class OutputPanel extends TextResourceEditor { @IOutputService private outputService: IOutputService, @IContextKeyService private contextKeyService: IContextKeyService, @IEditorGroupService editorGroupService: IEditorGroupService, - @IModeService modeService: IModeService, @ITextFileService textFileService: ITextFileService ) { - super(telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, modeService, textFileService); + super(telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService); this.scopedInstantiationService = instantiationService; } diff --git a/src/vs/workbench/parts/output/browser/outputServices.ts b/src/vs/workbench/parts/output/browser/outputServices.ts index 6f7f7326885..37aa71b666d 100644 --- a/src/vs/workbench/parts/output/browser/outputServices.ts +++ b/src/vs/workbench/parts/output/browser/outputServices.ts @@ -91,7 +91,6 @@ export class OutputService implements IOutputService { private _onOutputChannel: Emitter; private _onActiveOutputChannel: Emitter; - private _outputLinkDetector: OutputLinkProvider; private _outputContentProvider: OutputContentProvider; private _outputPanel: OutputPanel; @@ -110,7 +109,7 @@ export class OutputService implements IOutputService { const channels = this.getChannels(); this.activeChannelId = this.storageService.get(OUTPUT_ACTIVE_CHANNEL_KEY, StorageScope.WORKSPACE, channels && channels.length > 0 ? channels[0].id : null); - this._outputLinkDetector = instantiationService.createInstance(OutputLinkProvider); + instantiationService.createInstance(OutputLinkProvider); this._outputContentProvider = instantiationService.createInstance(OutputContentProvider, this); diff --git a/src/vs/workbench/parts/output/common/outputLinkProvider.ts b/src/vs/workbench/parts/output/common/outputLinkProvider.ts index abdd048bdad..817e5e9b973 100644 --- a/src/vs/workbench/parts/output/common/outputLinkProvider.ts +++ b/src/vs/workbench/parts/output/common/outputLinkProvider.ts @@ -23,13 +23,11 @@ export class OutputLinkProvider { private worker: MonacoWebWorker; private disposeWorkerScheduler: RunOnceScheduler; private linkProviderRegistration: IDisposable; - private workspacesCount: number; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, @IModelService private modelService: IModelService ) { - this.workspacesCount = 0; this.disposeWorkerScheduler = new RunOnceScheduler(() => this.disposeWorker(), OutputLinkProvider.DISPOSE_WORKER_TIME); this.registerListeners(); @@ -37,15 +35,14 @@ export class OutputLinkProvider { } private registerListeners(): void { - this.contextService.onDidChangeWorkspaceRoots(() => this.updateLinkProviderWorker()); + this.contextService.onDidChangeWorkspaceFolders(() => this.updateLinkProviderWorker()); } private updateLinkProviderWorker(): void { - // We have a workspace - if (this.contextService.hasWorkspace()) { - - // Register link provider unless done already + // Setup link provider depending on folders being opened or not + const folders = this.contextService.getWorkspace().folders; + if (folders.length > 0) { if (!this.linkProviderRegistration) { this.linkProviderRegistration = LinkProviderRegistry.register({ language: OUTPUT_MODE_ID, scheme: '*' }, { provideLinks: (model, token): Thenable => { @@ -53,26 +50,13 @@ export class OutputLinkProvider { } }); } - - // Update link provider worker if workspace roots changed - const newWorkspacesCount = this.contextService.getWorkspace().roots.length; - if (this.workspacesCount !== newWorkspacesCount) { - this.workspacesCount = newWorkspacesCount; - - // Next computer will trigger recompute - this.disposeWorker(); - this.disposeWorkerScheduler.cancel(); - } + } else { + this.linkProviderRegistration = dispose(this.linkProviderRegistration); } - // Dispose link provider when no longer having a workspace - else if (this.linkProviderRegistration) { - this.workspacesCount = 0; - dispose(this.linkProviderRegistration); - this.linkProviderRegistration = void 0; - this.disposeWorker(); - this.disposeWorkerScheduler.cancel(); - } + // Dispose worker to recreate with folders on next provideLinks request + this.disposeWorker(); + this.disposeWorkerScheduler.cancel(); } private getOrCreateWorker(): MonacoWebWorker { @@ -80,7 +64,7 @@ export class OutputLinkProvider { if (!this.worker) { const createData: ICreateData = { - workspaceFolders: this.contextService.getWorkspace().roots.map(root => root.toString()) + workspaceFolders: this.contextService.getWorkspace().folders.map(folder => folder.uri.toString()) }; this.worker = createWebWorker(this.modelService, { diff --git a/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts b/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts index 8b04c59fd2f..d860eb770b9 100644 --- a/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts +++ b/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts @@ -5,142 +5,20 @@ 'use strict'; -import product from 'vs/platform/node/product'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ITimerService } from 'vs/workbench/services/timer/common/timerService'; import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ReportPerformanceIssueAction } from 'vs/workbench/electron-browser/actions'; import { TPromise } from 'vs/base/common/winjs.base'; import { join } from 'path'; import { localize } from 'vs/nls'; -import { toPromise, filterEvent } from 'vs/base/common/event'; -import { platform, Platform } from 'vs/base/common/platform'; import { readdir } from 'vs/base/node/pfs'; -import { release } from 'os'; import { stopProfiling } from 'vs/base/node/profiler'; -import { virtualMachineHint } from 'vs/base/node/id'; - -class ProfilingHint implements IWorkbenchContribution { - - // p95 to p95 by os&release - static readonly _percentiles: { [key: string]: [number, number] } = { - ['Windows_6.3.9600']: [35782, 35782], - ['Windows_6.1.7601']: [11160, 18366], - ['Windows_10.0.16199']: [10423, 17222], - ['Windows_10.0.16193']: [7503, 11033], - ['Windows_10.0.16188']: [8544, 8807], - ['Windows_10.0.15063']: [11085, 16837], - ['Windows_10.0.14393']: [12585, 32662], - ['Windows_10.0.10586']: [7047, 10944], - ['Windows_10.0.10240']: [16176, 16176], - ['Mac_16.7.0']: [2192, 4050], - ['Mac_16.6.0']: [8043, 10608], - ['Mac_16.5.0']: [4912, 11348], - ['Mac_16.4.0']: [3900, 4200], - ['Mac_16.3.0']: [7327, 7327], - ['Mac_16.1.0']: [6090, 6555], - ['Mac_16.0.0']: [32574, 32574], - ['Mac_15.6.0']: [16082, 17469], - ['Linux_4.9.0-3-amd64']: [2092, 2197], - ['Linux_4.9.0-2-amd64']: [9779, 9779], - ['Linux_4.8.0-52-generic']: [12803, 13257], - ['Linux_4.8.0-51-generic']: [2670, 2797], - ['Linux_4.8.0-040800-generic']: [3954, 3954], - ['Linux_4.4.0-78-generic']: [4218, 5891], - ['Linux_4.4.0-77-generic']: [6166, 6166], - ['Linux_4.11.2']: [1323, 1323], - ['Linux_4.10.15-200.fc25.x86_64']: [9270, 9480], - ['Linux_4.10.13-1-ARCH']: [7116, 8511], - ['Linux_4.10.11-100.fc24.x86_64']: [1845, 1845], - ['Linux_4.10.0-21-generic']: [14805, 16050], - ['Linux_3.19.0-84-generic']: [4840, 4840], - ['Linux_3.11.10-29-desktop']: [1637, 2891], - }; - - private static readonly _myPercentiles = ProfilingHint._percentiles[`${Platform[platform]}_${release()}`]; - - constructor( - @IWindowsService private readonly _windowsService: IWindowsService, - @ITimerService private readonly _timerService: ITimerService, - @IMessageService private readonly _messageService: IMessageService, - @IEnvironmentService private readonly _envService: IEnvironmentService, - @IStorageService private readonly _storageService: IStorageService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, - ) { - - setTimeout(() => this._checkTimersAndSuggestToProfile(), 5000); - } - - getId(): string { - return 'performance.ProfilingHint'; - } - - private _checkTimersAndSuggestToProfile() { - - // Only initial startups, not when already profiling - if (!this._timerService.isInitialStartup || this._envService.args['prof-startup']) { - return; - } - - // Check that we have some data about this - // OS version to which we can compare this startup. - // Then only go for startups between the 90 and - // 95th percentile. - if (!Array.isArray(ProfilingHint._myPercentiles)) { - return; - } - const [p80, p90] = ProfilingHint._myPercentiles; - const { ellapsed } = this._timerService.startupMetrics; - if (ellapsed < p80 || ellapsed > p90) { - return; - } - - // Ignore virtual machines and only ask users - // to profile with a certain propability - if (virtualMachineHint.value() >= .5 || Math.ceil(Math.random() * 1000) !== 1) { - return; - } - - // Don't ask for the stable version, only - // ask once per version/build - if (this._envService.appQuality === 'stable') { - // don't ask in stable - return; - } - const mementoKey = `performance.didPromptToProfile.${product.commit}`; - const value = this._storageService.get(mementoKey, StorageScope.GLOBAL, undefined); - if (value !== undefined) { - // only ask once per version - return; - } - - const profile = this._messageService.confirm({ - type: 'info', - message: localize('slow', "Slow startup detected"), - detail: localize('slow.detail', "Sorry that you just had a slow startup. Please restart '{0}' with profiling enabled, share the profiles with us, and we will work hard to make startup great again.", this._envService.appNameLong), - primaryButton: 'Restart and profile' - }); - - this._telemetryService.publicLog('profileStartupInvite', { - acceptedInvite: profile - }); - - if (profile) { - this._storageService.store(mementoKey, 'didProfile', StorageScope.GLOBAL); - this._windowsService.relaunch({ addArgs: ['--prof-startup'] }); - } else { - this._storageService.store(mementoKey, 'didReject', StorageScope.GLOBAL); - } - } -} class StartupProfiler implements IWorkbenchContribution { @@ -154,8 +32,8 @@ class StartupProfiler implements IWorkbenchContribution { ) { // wait for everything to be ready TPromise.join([ + lifecycleService.when(LifecyclePhase.Running), extensionService.onReady(), - toPromise(filterEvent(lifecycleService.onDidChangePhase, phase => phase === LifecyclePhase.Running)), ]).then(() => { this._stopProfiling(); }); @@ -178,7 +56,7 @@ class StartupProfiler implements IWorkbenchContribution { }).then(files => { const profileFiles = files.reduce((prev, cur) => `${prev}${join(profileStartup.dir, cur)}\n`, '\n'); - const primaryButton = this._messageService.confirm({ + const primaryButton = this._messageService.confirmSync({ type: 'info', message: localize('prof.message', "Successfully created profiles."), detail: localize('prof.detail', "Please create an issue and manually attach the following files:\n{0}", profileFiles), @@ -193,7 +71,7 @@ class StartupProfiler implements IWorkbenchContribution { action.run(`:warning: Make sure to **attach** these files from your *home*-directory: :warning:\n${files.map(file => `-\`${file}\``).join('\n')}`) ]).then(() => { // keep window stable until restart is selected - this._messageService.confirm({ + this._messageService.confirmSync({ type: 'info', message: localize('prof.thanks', "Thanks for helping us."), detail: localize('prof.detail.restart', "A final restart is required to continue to use '{0}'. Again, thank you for your contribution.", this._environmentService.appNameLong), @@ -214,5 +92,4 @@ class StartupProfiler implements IWorkbenchContribution { } const registry = Registry.as(Extensions.Workbench); -registry.registerWorkbenchContribution(ProfilingHint); registry.registerWorkbenchContribution(StartupProfiler); diff --git a/src/vs/workbench/parts/preferences/browser/keybindingWidgets.ts b/src/vs/workbench/parts/preferences/browser/keybindingWidgets.ts index 2bf9edfc5c2..e8afc26ae6b 100644 --- a/src/vs/workbench/parts/preferences/browser/keybindingWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/keybindingWidgets.ts @@ -152,6 +152,7 @@ export class DefineKeybindingWidget extends Widget { constructor( parent: HTMLElement, + // @ts-ignore unused injected service @IKeybindingService private keybindingService: IKeybindingService, @IInstantiationService private instantiationService: IInstantiationService, @IThemeService private themeService: IThemeService diff --git a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts index acd16f4f9f3..b594c4cfff0 100644 --- a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts @@ -49,6 +49,7 @@ export class KeybindingsEditorInput extends EditorInput { public static ID: string = 'workbench.input.keybindings'; public readonly keybindingsModel: KeybindingsEditorModel; + // @ts-ignore unused injected service constructor( @IInstantiationService private instantiationService: IInstantiationService) { super(); this.keybindingsModel = instantiationService.createInstance(KeybindingsEditorModel, OS); @@ -106,6 +107,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor @IKeybindingEditingService private keybindingEditingService: IKeybindingEditingService, @IListService private listService: IListService, @IContextKeyService private contextKeyService: IContextKeyService, + // @ts-ignore unused injected service @IChoiceService private choiceService: IChoiceService, @IMessageService private messageService: IMessageService, @IClipboardService private clipboardService: IClipboardService, @@ -251,6 +253,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.searchWidget.focus(); } + clearSearchResults(): void { + this.searchWidget.clear(); + } + showConflicts(keybindingEntry: IKeybindingItemEntry): TPromise { const value = `"${keybindingEntry.keybindingItem.keybinding.getAriaLabel()}"`; if (value !== this.searchWidget.getValue()) { @@ -517,6 +523,12 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor emptyFilters: this.getLatestEmptyFiltersForTelemetry() }; this.latestEmptyFilters = []; + /* __GDPR__ + "keybindings.filter" : { + "filter": { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "emptyFilters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('keybindings.filter', data); } } @@ -531,6 +543,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } private reportKeybindingAction(action: string, command: string, keybinding: ResolvedKeybinding | string): void { + // __GDPR__TODO__ Need to move off dynamic event names and properties as they cannot be registered statically this.telemetryService.publicLog(action, { command, keybinding: keybinding ? (typeof keybinding === 'string' ? keybinding : keybinding.getUserSettingsLabel()) : '' }); } @@ -712,16 +725,21 @@ class CommandColumn extends Column { const commandDefaultLabelMatched = !!keybindingItemEntry.commandDefaultLabelMatches; DOM.toggleClass(this.commandColumn, 'vertical-align-column', commandIdMatched || commandDefaultLabelMatched); this.commandColumn.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry)); + let commandLabel: HighlightedLabel; if (keybindingItem.commandLabel) { - const commandLabel = new HighlightedLabel(this.commandColumn); + commandLabel = new HighlightedLabel(this.commandColumn); commandLabel.set(keybindingItem.commandLabel, keybindingItemEntry.commandLabelMatches); - commandLabel.element.title = keybindingItem.command; } if (keybindingItemEntry.commandDefaultLabelMatches) { - new HighlightedLabel(DOM.append(this.commandColumn, $('.command-default-label'))).set(keybindingItem.commandDefaultLabel, keybindingItemEntry.commandDefaultLabelMatches); + commandLabel = new HighlightedLabel(DOM.append(this.commandColumn, $('.command-default-label'))); + commandLabel.set(keybindingItem.commandDefaultLabel, keybindingItemEntry.commandDefaultLabelMatches); } if (keybindingItemEntry.commandIdMatches || !keybindingItem.commandLabel) { - new HighlightedLabel(DOM.append(this.commandColumn, $('.code'))).set(keybindingItem.command, keybindingItemEntry.commandIdMatches); + commandLabel = new HighlightedLabel(DOM.append(this.commandColumn, $('.code'))); + commandLabel.set(keybindingItem.command, keybindingItemEntry.commandIdMatches); + } + if (commandLabel) { + commandLabel.element.title = keybindingItem.command; } } diff --git a/src/vs/workbench/parts/preferences/browser/media/preferences.css b/src/vs/workbench/parts/preferences/browser/media/preferences.css index 22b490dcd6b..4084078ea86 100644 --- a/src/vs/workbench/parts/preferences/browser/media/preferences.css +++ b/src/vs/workbench/parts/preferences/browser/media/preferences.css @@ -73,18 +73,38 @@ padding-right: 32px; } -.settings-header-widget > .settings-count-widget { +.settings-header-widget > .settings-search-controls > .settings-count-widget { margin: 6px 0px; padding: 0px 8px; - position: absolute; - right: 10px; border-radius: 2px; + float: left; } -.settings-header-widget > .settings-count-widget.hide { +.settings-header-widget > .settings-search-controls { + position: absolute; + right: 10px; +} + +.settings-header-widget > .settings-search-controls > .settings-count-widget.hide { display: none; } +.settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle { + margin: 5px 3px 5px 0px; +} + +.settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle.hidden { + display: none; +} + +.vs .settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle { + background: url('regex.svg') center center no-repeat; +} + +.vs-dark .settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle { + background: url('regex-dark.svg') center center no-repeat; +} + .settings-header-widget > .settings-search-container { flex: 1; } @@ -106,8 +126,13 @@ padding-left:10px; } +.monaco-editor .view-zones > .settings-header-widget { + z-index: 1; +} + .monaco-editor .settings-header-widget .title-container { display: flex; + user-select: none; } .vs .monaco-editor .settings-header-widget .title-container { @@ -130,6 +155,16 @@ white-space: nowrap; } +.monaco-editor .settings-header-widget .title-container .settings-header-fuzzy-link { + margin-left: 4px; + text-decoration: underline; + cursor: pointer; +} + +.monaco-editor .settings-header-widget .title-container .settings-header-fuzzy-link.hidden { + display: none; +} + .monaco-editor .settings-group-title-widget { z-index: 1; } diff --git a/src/vs/workbench/parts/preferences/browser/media/regex-dark.svg b/src/vs/workbench/parts/preferences/browser/media/regex-dark.svg new file mode 100644 index 00000000000..c303032e6a9 --- /dev/null +++ b/src/vs/workbench/parts/preferences/browser/media/regex-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/media/regex.svg b/src/vs/workbench/parts/preferences/browser/media/regex.svg new file mode 100644 index 00000000000..c677843beef --- /dev/null +++ b/src/vs/workbench/parts/preferences/browser/media/regex.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts b/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts index 95f958289ec..d24ed6250c3 100644 --- a/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts @@ -8,35 +8,36 @@ import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; -import { EditorInput, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory } from 'vs/workbench/common/editor'; -import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { EditorInput, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { DefaultPreferencesEditorInput, PreferencesEditor, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor'; import { KeybindingsEditor, KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor'; -import { OpenGlobalSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenWorkspaceSettingsAction, OpenFolderSettingsAction, ConfigureLanguageBasedSettingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions'; +import { OpenGlobalSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenWorkspaceSettingsAction, OpenFolderSettingsAction, ConfigureLanguageBasedSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND } from 'vs/workbench/parts/preferences/browser/preferencesActions'; import { IPreferencesService, IKeybindingsEditor, CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_SEARCH, - KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS + KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/parts/preferences/common/preferences'; import { PreferencesService } from 'vs/workbench/parts/preferences/browser/preferencesService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { PreferencesContentProvider } from 'vs/workbench/parts/preferences/common/preferencesContentProvider'; +import { PreferencesContribution } from 'vs/workbench/parts/preferences/common/preferencesContribution'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; registerSingleton(IPreferencesService, PreferencesService); Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( + PreferencesEditor, PreferencesEditor.ID, - nls.localize('defaultPreferencesEditor', "Default Preferences Editor"), - 'vs/workbench/parts/preferences/browser/preferencesEditor', - 'PreferencesEditor' + nls.localize('defaultPreferencesEditor', "Default Preferences Editor") ), [ new SyncDescriptor(PreferencesEditorInput) @@ -45,10 +46,9 @@ Registry.as(EditorExtensions.Editors).registerEditor( Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( + KeybindingsEditor, KeybindingsEditor.ID, - nls.localize('keybindingsEditor', "Keybindings Editor"), - 'vs/workbench/parts/preferences/browser/keybindingsEditor', - 'KeybindingsEditor' + nls.localize('keybindingsEditor', "Keybindings Editor") ), [ new SyncDescriptor(KeybindingsEditorInput) @@ -73,7 +73,7 @@ class PreferencesEditorInputFactory implements IEditorInputFactory { const input = editorInput; if (input.details && input.master) { - const registry = Registry.as(EditorExtensions.Editors); + const registry = Registry.as(EditorInputExtensions.EditorInputFactories); const detailsInputFactory = registry.getEditorInputFactory(input.details.getTypeId()); const masterInputFactory = registry.getEditorInputFactory(input.master.getTypeId()); @@ -100,7 +100,7 @@ class PreferencesEditorInputFactory implements IEditorInputFactory { public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput { const deserialized: ISerializedPreferencesEditorInput = JSON.parse(serializedEditorInput); - const registry = Registry.as(EditorExtensions.Editors); + const registry = Registry.as(EditorInputExtensions.EditorInputFactories); const detailsInputFactory = registry.getEditorInputFactory(deserialized.detailsTypeId); const masterInputFactory = registry.getEditorInputFactory(deserialized.masterTypeId); @@ -155,9 +155,9 @@ class DefaultPreferencesEditorInputFactory implements IEditorInputFactory { } } -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(PreferencesEditorInput.ID, PreferencesEditorInputFactory); -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(DefaultPreferencesEditorInput.ID, DefaultPreferencesEditorInputFactory); -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(KeybindingsEditorInput.ID, KeybindingsEditorInputFactory); +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(PreferencesEditorInput.ID, PreferencesEditorInputFactory); +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(DefaultPreferencesEditorInput.ID, DefaultPreferencesEditorInputFactory); +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(KeybindingsEditorInput.ID, KeybindingsEditorInputFactory); // Contribute Global Actions const category = nls.localize('preferences', "Preferences"); @@ -246,4 +246,20 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContentProvider); \ No newline at end of file +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS), + primary: KeyCode.Escape, + handler: (accessor, args: any) => { + const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor; + editor.clearSearchResults(); + } +}); + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContribution); + +CommandsRegistry.registerCommand(OPEN_FOLDER_SETTINGS_COMMAND, function (accessor: ServicesAccessor, args?: IWorkspaceFolder) { + const preferencesService = accessor.get(IPreferencesService); + return preferencesService.openFolderSettings(args.uri); +}); \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts index 1cee1d5d6c2..8a31da0bdfc 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts @@ -8,11 +8,13 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; -import { IPreferencesService, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; export class OpenGlobalSettingsAction extends Action { @@ -73,6 +75,8 @@ export class OpenWorkspaceSettingsAction extends Action { public static ID = 'workbench.action.openWorkspaceSettings'; public static LABEL = nls.localize('openWorkspaceSettings', "Open Workspace Settings"); + private disposables: IDisposable[] = []; + constructor( id: string, label: string, @@ -80,46 +84,64 @@ export class OpenWorkspaceSettingsAction extends Action { @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService ) { super(id, label); - this.enabled = this.workspaceContextService.hasWorkspace(); + this.update(); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); + } + + private update(): void { + this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY; } public run(event?: any): TPromise { return this.preferencesService.openWorkspaceSettings(); } + + public dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } +export const OPEN_FOLDER_SETTINGS_COMMAND = '_workbench.action.openFolderSettings'; export class OpenFolderSettingsAction extends Action { public static ID = 'workbench.action.openFolderSettings'; public static LABEL = nls.localize('openFolderSettings', "Open Folder Settings"); + private disposables: IDisposable[] = []; + + constructor( id: string, label: string, + // @ts-ignore unused injected service @IPreferencesService private preferencesService: IPreferencesService, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IQuickOpenService private quickOpenService: IQuickOpenService + @ICommandService private commandService: ICommandService ) { super(id, label); - this.enabled = this.workspaceContextService.hasMultiFolderWorkspace(); + this.update(); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); + this.workspaceContextService.onDidChangeWorkspaceFolders(() => this.update(), this, this.disposables); + } + + private update(): void { + this.enabled = this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.workspaceContextService.getWorkspace().folders.length > 0; } public run(): TPromise { - const picks: IPickOpenEntry[] = this.workspaceContextService.getWorkspace().roots.map((root, index) => { - return { - label: getSettingsTargetName(ConfigurationTarget.FOLDER, root, this.workspaceContextService), - id: `${index}` - }; - }); - - return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickFolder', "Select Folder") }) - .then(pick => { - if (pick) { - return this.preferencesService.openFolderSettings(this.workspaceContextService.getWorkspace().roots[parseInt(pick.id)]); + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) + .then(workspaceFolder => { + if (workspaceFolder) { + return this.commandService.executeCommand(OPEN_FOLDER_SETTINGS_COMMAND, workspaceFolder); } - return undefined; + return null; }); + } + public dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); } } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 7b92f7a36ff..1acd6036909 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -6,14 +6,15 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; +import { onUnexpectedError } from 'vs/base/common/errors'; import * as DOM from 'vs/base/browser/dom'; -import { Delayer } from 'vs/base/common/async'; +import { Delayer, ThrottledDelayer } from 'vs/base/common/async'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { ArrayNavigator, INavigator } from 'vs/base/common/iterator'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { toResource, SideBySideEditorInput, EditorOptions, EditorInput, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; -import { BaseEditor, EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { SideBySideEditorInput, EditorOptions, EditorInput } from 'vs/workbench/common/editor'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; import { IEditorControl, Position, Verbosity } from 'vs/platform/editor/common/editor'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; @@ -23,23 +24,22 @@ import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IPreferencesService, ISettingsGroup, ISetting, IFilterResult, - CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel + CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { ICodeEditor, IEditorContributionCtor } from 'vs/editor/browser/editorBrowser'; import { SearchWidget, SettingsTargetsWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; +import { PreferencesSearchProvider, PreferencesSearchModel } from 'vs/workbench/parts/preferences/browser/preferencesSearch'; import { ContextKeyExpr, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Command } from 'vs/editor/common/editorCommonExtensions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { VSash } from 'vs/base/browser/ui/sash/sash'; import { Widget } from 'vs/base/browser/ui/widget'; @@ -47,11 +47,10 @@ import { IPreferencesRenderer, DefaultSettingsRenderer, UserSettingsRenderer, Wo import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; - -// Ignore following contributions +import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { FoldingController } from 'vs/editor/contrib/folding/browser/folding'; import { FindController } from 'vs/editor/contrib/find/browser/find'; -import { SelectionHighlighter } from 'vs/editor/contrib/find/common/findController'; +import { SelectionHighlighter } from 'vs/editor/contrib/multicursor/common/multicursor'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { attachStylerCallback } from 'vs/platform/theme/common/styler'; @@ -59,6 +58,9 @@ import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; +import { MessageController } from 'vs/editor/contrib/message/messageController'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export class PreferencesEditorInput extends SideBySideEditorInput { public static ID: string = 'workbench.editorinputs.preferencesEditorInput'; @@ -75,9 +77,10 @@ export class PreferencesEditorInput extends SideBySideEditorInput { export class DefaultPreferencesEditorInput extends ResourceEditorInput { public static ID = 'workbench.editorinputs.defaultpreferences'; constructor(defaultSettingsResource: URI, - @ITextModelService textModelResolverService: ITextModelService + @ITextModelService textModelResolverService: ITextModelService, + @IHashService hashService: IHashService ) { - super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, textModelResolverService); + super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, textModelResolverService, hashService); } getTypeId(): string { @@ -85,10 +88,10 @@ export class DefaultPreferencesEditorInput extends ResourceEditorInput { } matches(other: any): boolean { - if (!super.matches(other)) { - return false; + if (other instanceof DefaultPreferencesEditorInput) { + return true; } - if (!(other instanceof DefaultPreferencesEditorInput)) { + if (!super.matches(other)) { return false; } return true; @@ -106,14 +109,17 @@ export class PreferencesEditor extends BaseEditor { private settingsTargetsWidget: SettingsTargetsWidget; private sideBySidePreferencesWidget: SideBySidePreferencesWidget; private preferencesRenderers: PreferencesRenderers; + private searchProvider: PreferencesSearchProvider; private delayedFilterLogging: Delayer; + private filterThrottle: ThrottledDelayer; private latestEmptyFilters: string[] = []; private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget = null; constructor( @IPreferencesService private preferencesService: IPreferencesService, + // @ts-ignore unused injected service @IEnvironmentService private environmentService: IEnvironmentService, @ITelemetryService telemetryService: ITelemetryService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -126,6 +132,8 @@ export class PreferencesEditor extends BaseEditor { this.defaultSettingsEditorContextKey = CONTEXT_SETTINGS_EDITOR.bindTo(this.contextKeyService); this.focusSettingsContextKey = CONTEXT_SETTINGS_SEARCH_FOCUS.bindTo(this.contextKeyService); this.delayedFilterLogging = new Delayer(1000); + this.searchProvider = this.instantiationService.createInstance(PreferencesSearchProvider); + this.filterThrottle = new ThrottledDelayer(200); } public createEditor(parent: Builder): void { @@ -139,8 +147,9 @@ export class PreferencesEditor extends BaseEditor { placeholder: nls.localize('SearchSettingsWidget.Placeholder', "Search Settings"), focusKey: this.focusSettingsContextKey })); - this._register(this.searchWidget.onDidChange(value => this.filterPreferences(value.trim()))); - this._register(this.searchWidget.onNavigate(shift => this.preferencesRenderers.focusNextPreference(!shift))); + this.searchWidget.setFuzzyToggleVisible(this.searchProvider.remoteSearchEnabled); + this._register(this.searchProvider.onRemoteSearchEnablementChanged(enabled => this.searchWidget.setFuzzyToggleVisible(enabled))); + this._register(this.searchWidget.onDidChange(value => this.onInputChanged())); this._register(this.searchWidget.onFocus(() => this.lastFocusedWidget = this.searchWidget)); this.lastFocusedWidget = this.searchWidget; @@ -152,7 +161,31 @@ export class PreferencesEditor extends BaseEditor { this._register(this.sideBySidePreferencesWidget.onFocus(() => this.lastFocusedWidget = this.sideBySidePreferencesWidget)); this.preferencesRenderers = this._register(new PreferencesRenderers()); - this._register(this.workspaceContextService.onDidChangeWorkspaceRoots(() => this.onWorkspaceRootsChanged())); + this._register(this.workspaceContextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged())); + this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.onWorkbenchStateChanged())); + + this._register(this.preferencesRenderers.onTriggeredFuzzy(() => { + this.searchWidget.fuzzyEnabled = true; + this.filterPreferences(); + })); + } + + public clearSearchResults(): void { + if (this.searchWidget) { + this.searchWidget.clear(); + } + } + + public focusNextResult(): void { + if (this.preferencesRenderers) { + this.preferencesRenderers.focusNextPreference(true); + } + } + + public focusPreviousResult(): void { + if (this.preferencesRenderers) { + this.preferencesRenderers.focusNextPreference(false); + } } public setInput(newInput: PreferencesEditorInput, options?: EditorOptions): TPromise { @@ -209,43 +242,60 @@ export class PreferencesEditor extends BaseEditor { } private updateInput(oldInput: PreferencesEditorInput, newInput: PreferencesEditorInput, options?: EditorOptions): TPromise { - const resource = toResource(newInput.master); - this.settingsTargetsWidget.setTarget(this.getSettingsConfigurationTargetUri(resource), this.getSettingsConfigurationTarget(resource)); + const resource = newInput.master.getResource(); + this.settingsTargetsWidget.updateTargets(this.getSettingsConfigurationTargetUri(resource), this.getSettingsConfigurationTarget(resource)); return this.sideBySidePreferencesWidget.setInput(newInput.details, newInput.master, options).then(({ defaultPreferencesRenderer, editablePreferencesRenderer }) => { this.preferencesRenderers.defaultPreferencesRenderer = defaultPreferencesRenderer; this.preferencesRenderers.editablePreferencesRenderer = editablePreferencesRenderer; - this.filterPreferences(this.searchWidget.getValue()); + this.onInputChanged(); }); } + private onInputChanged(): void { + if (this.searchWidget.fuzzyEnabled) { + this.triggerThrottledFilter(); + } else { + this.filterPreferences(); + } + } + + private triggerThrottledFilter(): void { + this.filterThrottle.trigger(() => this.filterPreferences()); + } + private getSettingsConfigurationTarget(resource: URI): ConfigurationTarget { - if (this.preferencesService.userSettingsResource.fsPath === resource.fsPath) { + if (this.preferencesService.userSettingsResource.toString() === resource.toString()) { return ConfigurationTarget.USER; } - if (this.preferencesService.workspaceSettingsResource.fsPath === resource.fsPath) { + + const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource; + if (workspaceSettingsResource && workspaceSettingsResource.toString() === resource.toString()) { return ConfigurationTarget.WORKSPACE; } - if (this.workspaceContextService.getRoot(resource)) { - return ConfigurationTarget.FOLDER; + + if (this.workspaceContextService.getWorkspaceFolder(resource)) { + return ConfigurationTarget.WORKSPACE_FOLDER; } + return null; } private getSettingsConfigurationTargetUri(resource: URI): URI { - if (this.preferencesService.userSettingsResource.fsPath === resource.fsPath) { + if (this.preferencesService.userSettingsResource.toString() === resource.toString()) { return resource; } - if (this.preferencesService.workspaceSettingsResource.fsPath === resource.fsPath) { + if (this.preferencesService.workspaceSettingsResource.toString() === resource.toString()) { return resource; } - return this.workspaceContextService.getRoot(resource); + const workspaceFolder = this.workspaceContextService.getWorkspaceFolder(resource); + return workspaceFolder ? workspaceFolder.uri : null; } - private onWorkspaceRootsChanged(): void { + private onWorkspaceFoldersChanged(): void { if (this.input) { - const settingsResource = toResource((this.input).master); + const settingsResource = (this.input).master.getResource(); const targetResource = this.getSettingsConfigurationTargetUri(settingsResource); if (!targetResource) { this.switchSettings(this.preferencesService.userSettingsResource); @@ -253,6 +303,21 @@ export class PreferencesEditor extends BaseEditor { } } + private onWorkbenchStateChanged(): void { + if (this.input) { + const editableSettingsResource = (this.input).master.getResource(); + const newConfigurationTarget = this.getSettingsConfigurationTarget(editableSettingsResource); + if (newConfigurationTarget) { + if (newConfigurationTarget !== this.settingsTargetsWidget.configurationTarget) { + // Update the editor if the configuration target of the settings resource changed + this.switchSettings(editableSettingsResource); + } + } else { + this.switchSettings(this.preferencesService.userSettingsResource); + } + } + } + private switchSettings(resource: URI): void { // Focus the editor if this editor is not active editor if (this.editorService.getActiveEditor() !== this) { @@ -262,14 +327,16 @@ export class PreferencesEditor extends BaseEditor { promise.done(value => this.preferencesService.switchSettings(this.getSettingsConfigurationTarget(resource), resource)); } - private filterPreferences(filter: string) { - const count = this.preferencesRenderers.filterPreferences(filter); - const message = filter ? this.showSearchResultsMessage(count) : nls.localize('totalSettingsMessage', "Total {0} Settings", count); - this.searchWidget.showMessage(message, count); - if (count === 0) { - this.latestEmptyFilters.push(filter); - } - this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter)); + private filterPreferences(): TPromise { + const filter = this.searchWidget.getValue().trim(); + return this.preferencesRenderers.filterPreferences(filter, this.searchProvider, this.searchWidget.fuzzyEnabled).then(count => { + const message = filter ? this.showSearchResultsMessage(count) : nls.localize('totalSettingsMessage', "Total {0} Settings", count); + this.searchWidget.showMessage(message, count); + if (count === 0) { + this.latestEmptyFilters.push(filter); + } + this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter)); + }, onUnexpectedError); } private showSearchResultsMessage(count: number): string { @@ -285,6 +352,12 @@ export class PreferencesEditor extends BaseEditor { emptyFilters: this.getLatestEmptyFiltersForTelemetry() }; this.latestEmptyFilters = []; + /* __GDPR__ + "defaultSettings.filter" : { + "filter": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "emptyFilters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('defaultSettings.filter', data); } } @@ -337,9 +410,13 @@ class PreferencesRenderers extends Disposable { private _defaultPreferencesRenderer: IPreferencesRenderer; private _editablePreferencesRenderer: IPreferencesRenderer; private _settingsNavigator: SettingsNavigator; + private _filtersInProgress: TPromise[]; private _disposables: IDisposable[] = []; + private _onTriggeredFuzzy: Emitter = new Emitter(); + public onTriggeredFuzzy: Event = this._onTriggeredFuzzy.event; + public get defaultPreferencesRenderer(): IPreferencesRenderer { return this._defaultPreferencesRenderer; } @@ -354,6 +431,9 @@ class PreferencesRenderers extends Disposable { this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source }) => this._updatePreference(key, value, source, this._editablePreferencesRenderer), this, this._disposables); this._defaultPreferencesRenderer.onFocusPreference(preference => this._focusPreference(preference, this._editablePreferencesRenderer), this, this._disposables); this._defaultPreferencesRenderer.onClearFocusPreference(preference => this._clearFocus(preference, this._editablePreferencesRenderer), this, this._disposables); + if (this._defaultPreferencesRenderer.onTriggeredFuzzy) { + this._register(this._defaultPreferencesRenderer.onTriggeredFuzzy(() => this._onTriggeredFuzzy.fire())); + } } } } @@ -362,19 +442,37 @@ class PreferencesRenderers extends Disposable { this._editablePreferencesRenderer = editableSettingsRenderer; } - public filterPreferences(filter: string): number { - const defaultPreferencesFilterResult = this._filterPreferences(filter, this._defaultPreferencesRenderer); - const editablePreferencesFilterResult = this._filterPreferences(filter, this._editablePreferencesRenderer); + public filterPreferences(filter: string, searchProvider: PreferencesSearchProvider, fuzzy: boolean): TPromise { + if (this._filtersInProgress) { + // Resolved/rejected promises have no .cancel() + this._filtersInProgress.forEach(p => p.cancel && p.cancel()); + } - const defaultPreferencesFilteredGroups = defaultPreferencesFilterResult ? defaultPreferencesFilterResult.filteredGroups : this._getAllPreferences(this._defaultPreferencesRenderer); - const editablePreferencesFilteredGroups = editablePreferencesFilterResult ? editablePreferencesFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer); - const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups); - this._settingsNavigator = new SettingsNavigator(filter ? consolidatedSettings : []); + const searchModel = searchProvider.startSearch(filter, fuzzy); + this._filtersInProgress = [ + this._filterPreferences(searchModel, searchProvider, this._defaultPreferencesRenderer), + this._filterPreferences(searchModel, searchProvider, this._editablePreferencesRenderer)]; - return consolidatedSettings.length; + return TPromise.join(this._filtersInProgress).then(filterResults => { + this._filtersInProgress = null; + const defaultPreferencesFilterResult = filterResults[0]; + const editablePreferencesFilterResult = filterResults[1]; + + const defaultPreferencesFilteredGroups = defaultPreferencesFilterResult ? defaultPreferencesFilterResult.filteredGroups : this._getAllPreferences(this._defaultPreferencesRenderer); + const editablePreferencesFilteredGroups = editablePreferencesFilterResult ? editablePreferencesFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer); + const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups); + + this._settingsNavigator = new SettingsNavigator(filter ? consolidatedSettings : []); + + return consolidatedSettings.length; + }); } public focusNextPreference(forward: boolean = true) { + if (!this._settingsNavigator) { + return; + } + const setting = forward ? this._settingsNavigator.next() : this._settingsNavigator.previous(); this._focusPreference(setting, this._defaultPreferencesRenderer); this._focusPreference(setting, this._editablePreferencesRenderer); @@ -384,13 +482,17 @@ class PreferencesRenderers extends Disposable { return preferencesRenderer ? (preferencesRenderer.preferencesModel).settingsGroups : []; } - private _filterPreferences(filter: string, preferencesRenderer: IPreferencesRenderer): IFilterResult { - let filterResult = null; + private _filterPreferences(searchModel: PreferencesSearchModel, searchProvider: PreferencesSearchProvider, preferencesRenderer: IPreferencesRenderer): TPromise { if (preferencesRenderer) { - filterResult = filter ? (preferencesRenderer.preferencesModel).filterSettings(filter) : null; - preferencesRenderer.filterPreferences(filterResult); + const prefSearchP = searchModel.filterPreferences(preferencesRenderer.preferencesModel); + + return prefSearchP.then(filterResult => { + preferencesRenderer.filterPreferences(filterResult, searchProvider.remoteSearchEnabled); + return filterResult; + }); } - return filterResult; + + return TPromise.wrap(null); } private _focusPreference(preference: ISetting, preferencesRenderer: IPreferencesRenderer): void { @@ -483,13 +585,11 @@ class SideBySidePreferencesWidget extends Widget { } public setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options?: EditorOptions): TPromise<{ defaultPreferencesRenderer: IPreferencesRenderer, editablePreferencesRenderer: IPreferencesRenderer }> { - return this.getOrCreateEditablePreferencesEditor(editablePreferencesEditorInput) - .then(() => { - this.dolayout(this.sash.getVerticalSashLeft()); - return TPromise.join([this.updateInput(this.defaultPreferencesEditor, defaultPreferencesEditorInput, DefaultSettingsEditorContribution.ID, toResource(editablePreferencesEditorInput), options), - this.updateInput(this.editablePreferencesEditor, editablePreferencesEditorInput, SettingsEditorContribution.ID, defaultPreferencesEditorInput.getResource(), options)]) - .then(([defaultPreferencesRenderer, editablePreferencesRenderer]) => ({ defaultPreferencesRenderer, editablePreferencesRenderer })); - }); + this.getOrCreateEditablePreferencesEditor(editablePreferencesEditorInput); + this.dolayout(this.sash.getVerticalSashLeft()); + return TPromise.join([this.updateInput(this.defaultPreferencesEditor, defaultPreferencesEditorInput, DefaultSettingsEditorContribution.ID, editablePreferencesEditorInput.getResource(), options), + this.updateInput(this.editablePreferencesEditor, editablePreferencesEditorInput, SettingsEditorContribution.ID, defaultPreferencesEditorInput.getResource(), options)]) + .then(([defaultPreferencesRenderer, editablePreferencesRenderer]) => ({ defaultPreferencesRenderer, editablePreferencesRenderer })); } public layout(dimension: Dimension): void { @@ -508,6 +608,9 @@ class SideBySidePreferencesWidget extends Widget { } public clearInput(): void { + if (this.defaultPreferencesEditor) { + this.defaultPreferencesEditor.clearInput(); + } if (this.editablePreferencesEditor) { this.editablePreferencesEditor.clearInput(); } @@ -525,20 +628,19 @@ class SideBySidePreferencesWidget extends Widget { } } - private getOrCreateEditablePreferencesEditor(editorInput: EditorInput): TPromise { + private getOrCreateEditablePreferencesEditor(editorInput: EditorInput): BaseEditor { if (this.editablePreferencesEditor) { - return TPromise.as(this.editablePreferencesEditor); + return this.editablePreferencesEditor; } const descriptor = Registry.as(EditorExtensions.Editors).getEditor(editorInput); - return this.instantiationService.createInstance(descriptor) - .then((editor: BaseEditor) => { - this.editablePreferencesEditor = editor; - this.editablePreferencesEditor.create(new Builder(this.editablePreferencesEditorContainer)); - this.editablePreferencesEditor.setVisible(true); - (this.editablePreferencesEditor.getControl()).onDidFocusEditor(() => this.lastFocusedEditor = this.editablePreferencesEditor); - this.lastFocusedEditor = this.editablePreferencesEditor; - return editor; - }); + const editor = descriptor.instantiate(this.instantiationService); + this.editablePreferencesEditor = editor; + this.editablePreferencesEditor.create(new Builder(this.editablePreferencesEditorContainer)); + this.editablePreferencesEditor.setVisible(true); + (this.editablePreferencesEditor.getControl()).onDidFocusEditor(() => this.lastFocusedEditor = this.editablePreferencesEditor); + this.lastFocusedEditor = this.editablePreferencesEditor; + + return editor; } private updateInput(editor: BaseEditor, input: EditorInput, editorContributionId: string, associatedPreferencesModelUri: URI, options: EditorOptions): TPromise> { @@ -596,18 +698,19 @@ export class EditableSettingsEditor extends BaseTextEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, + // @ts-ignore unused injected service @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IInstantiationService instantiationService: IInstantiationService, @IStorageService storageService: IStorageService, @ITextResourceConfigurationService configurationService: ITextResourceConfigurationService, @IThemeService themeService: IThemeService, @IPreferencesService private preferencesService: IPreferencesService, + // @ts-ignore unused injected service @IModelService private modelService: IModelService, - @IModeService modeService: IModeService, @ITextFileService textFileService: ITextFileService, @IEditorGroupService editorGroupService: IEditorGroupService ) { - super(EditableSettingsEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService, textFileService, editorGroupService); + super(EditableSettingsEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorGroupService); this._register({ dispose: () => dispose(this.modelDisposables) }); this.saveDelayer = new Delayer(1000); } @@ -667,22 +770,37 @@ export class DefaultPreferencesEditor extends BaseTextEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, + // @ts-ignore unused injected service @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IInstantiationService instantiationService: IInstantiationService, @IStorageService storageService: IStorageService, @ITextResourceConfigurationService configurationService: ITextResourceConfigurationService, @IThemeService themeService: IThemeService, + // @ts-ignore unused injected service @IPreferencesService private preferencesService: IPreferencesService, + // @ts-ignore unused injected service @IModelService private modelService: IModelService, - @IModeService modeService: IModeService, @ITextFileService textFileService: ITextFileService, @IEditorGroupService editorGroupService: IEditorGroupService ) { - super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService, textFileService, editorGroupService); + super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorGroupService); } public createEditorControl(parent: Builder, configuration: IEditorOptions): editorCommon.IEditor { - return this.instantiationService.createInstance(DefaultPreferencesCodeEditor, parent.getHTMLElement(), configuration); + const editor = this.instantiationService.createInstance(DefaultPreferencesCodeEditor, parent.getHTMLElement(), configuration); + + // Inform user about editor being readonly if user starts type + this.toUnbind.push(editor.onDidType(() => this.showReadonlyHint(editor))); + this.toUnbind.push(editor.onDidPaste(() => this.showReadonlyHint(editor))); + + return editor; + } + + private showReadonlyHint(editor: editorCommon.ICommonCodeEditor): void { + const messageController = MessageController.get(editor); + if (!messageController.isVisible()) { + messageController.showMessage(nls.localize('defaultEditorReadonly', "Edit in the right hand side editor to override defaults."), editor.getSelection().getPosition()); + } } protected getConfigurationOverrides(): IEditorOptions { @@ -712,6 +830,14 @@ export class DefaultPreferencesEditor extends BaseTextEditor { .then(editorModel => this.getControl().setModel((editorModel).textEditorModel))); } + public clearInput(): void { + // Clear Model + this.getControl().setModel(null); + + // Pass to super + super.clearInput(); + } + public layout(dimension: Dimension) { this.getControl().layout(dimension); } @@ -765,7 +891,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable { return TPromise.as(null); } - private _onModelChanged(): void { + protected _onModelChanged(): void { const model = this.editor.getModel(); this.disposePreferencesRenderer(); if (model) { @@ -775,7 +901,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable { private _hasAssociatedPreferencesModelChanged(associatedPreferencesModelUri: URI): TPromise { return this.preferencesRendererCreationPromise.then(preferencesRenderer => { - return !(preferencesRenderer && preferencesRenderer.associatedPreferencesModel && preferencesRenderer.associatedPreferencesModel.uri.fsPath === associatedPreferencesModelUri.fsPath); + return !(preferencesRenderer && preferencesRenderer.associatedPreferencesModel && preferencesRenderer.associatedPreferencesModel.uri.toString() === associatedPreferencesModelUri.toString()); }); } @@ -801,6 +927,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable { if (preferencesRenderer.associatedPreferencesModel) { preferencesRenderer.associatedPreferencesModel.dispose(); } + preferencesRenderer.preferencesModel.dispose(); preferencesRenderer.dispose(); } }); @@ -842,22 +969,31 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl static ID: string = 'editor.contrib.settings'; + constructor(editor: ICodeEditor, + @IInstantiationService instantiationService: IInstantiationService, + @IPreferencesService preferencesService: IPreferencesService, + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService + ) { + super(editor, instantiationService, preferencesService, workspaceContextService); + this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this._onModelChanged())); + } + getId(): string { return SettingsEditorContribution.ID; } protected _createPreferencesRenderer(): TPromise> { if (this.isSettingsModel()) { - return TPromise.join([this.preferencesService.createPreferencesEditorModel(this.preferencesService.defaultSettingsResource), this.preferencesService.createPreferencesEditorModel(this.editor.getModel().uri)]) - .then(([defaultSettingsModel, settingsModel]) => { + return this.preferencesService.createPreferencesEditorModel(this.editor.getModel().uri) + .then(settingsModel => { if (settingsModel instanceof SettingsEditorModel && this.editor.getModel()) { switch (settingsModel.configurationTarget) { case ConfigurationTarget.USER: - return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); + return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel); case ConfigurationTarget.WORKSPACE: - return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); - case ConfigurationTarget.FOLDER: - return this.instantiationService.createInstance(FolderSettingsRenderer, this.editor, settingsModel, defaultSettingsModel); + return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel); + case ConfigurationTarget.WORKSPACE_FOLDER: + return this.instantiationService.createInstance(FolderSettingsRenderer, this.editor, settingsModel); } } return null; @@ -878,21 +1014,18 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl return false; } - if (this.preferencesService.userSettingsResource && this.preferencesService.userSettingsResource.fsPath === model.uri.fsPath) { + if (this.preferencesService.userSettingsResource && this.preferencesService.userSettingsResource.toString() === model.uri.toString()) { return true; } - if (this.preferencesService.workspaceSettingsResource && this.preferencesService.workspaceSettingsResource.fsPath === model.uri.fsPath) { + if (this.preferencesService.workspaceSettingsResource && this.preferencesService.workspaceSettingsResource.toString() === model.uri.toString()) { return true; } - const workspace = this.workspaceContextService.getWorkspace(); - if (workspace) { - for (const root of workspace.roots) { - const folderSettingsResource = this.preferencesService.getFolderSettingsResource(root); - if (folderSettingsResource && folderSettingsResource.fsPath === model.uri.fsPath) { - return true; - } + for (const folder of this.workspaceContextService.getWorkspace().folders) { + const folderSettingsResource = this.preferencesService.getFolderSettingsResource(folder.uri); + if (folderSettingsResource && folderSettingsResource.toString() === model.uri.toString()) { + return true; } } @@ -946,3 +1079,54 @@ const focusSettingsFileEditorCommand = new FocusSettingsFileEditorCommand({ kbOpts: { primary: KeyCode.DownArrow } }); KeybindingsRegistry.registerCommandAndKeybindingRule(focusSettingsFileEditorCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); + +class ClearSearchResultsCommand extends SettingsCommand { + + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor) { + preferencesEditor.clearSearchResults(); + } + } + +} +const clearSearchResultsCommand = new ClearSearchResultsCommand({ + id: SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, + precondition: CONTEXT_SETTINGS_SEARCH_FOCUS, + kbOpts: { primary: KeyCode.Escape } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule(clearSearchResultsCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); + +class FocusNextSearchResultCommand extends SettingsCommand { + + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor) { + preferencesEditor.focusNextResult(); + } + } + +} +const focusNextSearchResultCommand = new FocusNextSearchResultCommand({ + id: SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, + precondition: CONTEXT_SETTINGS_SEARCH_FOCUS, + kbOpts: { primary: KeyCode.Enter } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule(focusNextSearchResultCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); + +class FocusPreviousSearchResultCommand extends SettingsCommand { + + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor) { + preferencesEditor.focusPreviousResult(); + } + } + +} +const focusPreviousSearchResultCommand = new FocusPreviousSearchResultCommand({ + id: SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, + precondition: CONTEXT_SETTINGS_SEARCH_FOCUS, + kbOpts: { primary: KeyMod.Shift | KeyCode.Enter } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule(focusPreviousSearchResultCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index 681d18159da..9e7aebc3f21 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -6,6 +6,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import { Delayer } from 'vs/base/common/async'; +import * as strings from 'vs/base/common/strings'; +import { tail } from 'vs/base/common/arrays'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IAction } from 'vs/base/common/actions'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; @@ -15,24 +17,24 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { Range, IRange } from 'vs/editor/common/core/range'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IPreferencesService, ISettingsGroup, ISetting, IPreferencesEditorModel, IFilterResult, ISettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferences'; -import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; +import { IPreferencesService, ISettingsGroup, ISetting, IPreferencesEditorModel, IFilterResult, ISettingsEditorModel, IScoredResults, IWorkbenchSettingsConfiguration } from 'vs/workbench/parts/preferences/common/preferences'; +import { SettingsEditorModel, DefaultSettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/browser/contextView'; -import { SettingsGroupTitleWidget, EditPreferenceWidget, SettingsHeaderWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; +import { SettingsGroupTitleWidget, EditPreferenceWidget, SettingsHeaderWidget, DefaultSettingsHeaderWidget, FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; -import { IConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { overrideIdentifierFromKey } from 'vs/platform/configuration/common/model'; import { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { MarkdownString } from 'vs/base/common/htmlContent'; +import { overrideIdentifierFromKey, IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; export interface IPreferencesRenderer extends IDisposable { preferencesModel: IPreferencesEditorModel; @@ -41,21 +43,22 @@ export interface IPreferencesRenderer extends IDisposable { onFocusPreference: Event; onClearFocusPreference: Event; onUpdatePreference: Event<{ key: string, value: any, source: T }>; + onTriggeredFuzzy?: Event; render(): void; updatePreference(key: string, value: any, source: T): void; - filterPreferences(filterResult: IFilterResult): void; + filterPreferences(filterResult: IFilterResult, fuzzySearchAvailable: boolean): void; focusPreference(setting: T): void; clearFocus(setting: T): void; } - export class UserSettingsRenderer extends Disposable implements IPreferencesRenderer { private settingHighlighter: SettingHighlighter; private editSettingActionRenderer: EditSettingRenderer; private highlightMatchesRenderer: HighlightMatchesRenderer; private modelChangeDelayer: Delayer = new Delayer(200); + private _associatedPreferencesModel: IPreferencesEditorModel; private _onFocusPreference: Emitter = new Emitter(); public readonly onFocusPreference: Event = this._onFocusPreference.event; @@ -68,16 +71,15 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend private filterResult: IFilterResult; - constructor(protected editor: ICodeEditor, public readonly preferencesModel: SettingsEditorModel, private _associatedPreferencesModel: IPreferencesEditorModel, + constructor(protected editor: ICodeEditor, public readonly preferencesModel: SettingsEditorModel, @IPreferencesService protected preferencesService: IPreferencesService, @ITelemetryService private telemetryService: ITelemetryService, + // @ts-ignore unused injected service @ITextFileService private textFileService: ITextFileService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, - @IMessageService private messageService: IMessageService, + @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService protected instantiationService: IInstantiationService ) { super(); - this._register(preferencesModel); this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference)); this.highlightMatchesRenderer = this._register(instantiationService.createInstance(HighlightMatchesRenderer, editor)); this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter)); @@ -108,22 +110,16 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend } public updatePreference(key: string, value: any, source: ISetting): void { + /* __GDPR__ + "defaultSettingsActions.copySetting" : { + "userConfigurationKeys" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('defaultSettingsActions.copySetting', { userConfigurationKeys: [key] }); const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null; const resource = this.preferencesModel.uri; - this.configurationEditingService.writeConfiguration(this.preferencesModel.configurationTarget, { key, value }, { donotSave: this.textFileService.isDirty(resource), donotNotifyError: true, scopes: { overrideIdentifier, resource } }) - .then(() => this.onSettingUpdated(source), error => { - this.messageService.show(Severity.Error, this.toErrorMessage(error, this.preferencesModel.configurationTarget)); - }); - } - - private toErrorMessage(error: ConfigurationEditingError, target: ConfigurationTarget): string { - switch (error.code) { - case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: { - return nls.localize('errorInvalidConfiguration', "Unable to write into settings. Correct errors/warnings in the file and try again."); - }; - } - return error.message; + this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget) + .then(() => this.onSettingUpdated(source)); } private onModelChanged(): void { @@ -180,19 +176,18 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer { - private untrustedSettingRenderer: UnsupportedWorkspaceSettingsRenderer; + private unsupportedSettingsRenderer: UnsupportedSettingsRenderer; private workspaceConfigurationRenderer: WorkspaceConfigurationRenderer; - constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, associatedPreferencesModel: IPreferencesEditorModel, + constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, @IPreferencesService preferencesService: IPreferencesService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService, - @IMessageService messageService: IMessageService, + @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationEditingService, messageService, instantiationService); - this.untrustedSettingRenderer = this._register(instantiationService.createInstance(UnsupportedWorkspaceSettingsRenderer, editor, preferencesModel)); + super(editor, preferencesModel, preferencesService, telemetryService, textFileService, configurationService, instantiationService); + this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel)); this.workspaceConfigurationRenderer = this._register(instantiationService.createInstance(WorkspaceConfigurationRenderer, editor, preferencesModel)); } @@ -202,25 +197,24 @@ export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements I public render(): void { super.render(); - this.untrustedSettingRenderer.render(); + this.unsupportedSettingsRenderer.render(); this.workspaceConfigurationRenderer.render(); } } export class FolderSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer { - private unsupportedWorkbenchSettingsRenderer: UnsupportedWorkbenchSettingsRenderer; + private unsupportedSettingsRenderer: UnsupportedSettingsRenderer; - constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, associatedPreferencesModel: IPreferencesEditorModel, + constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel, @IPreferencesService preferencesService: IPreferencesService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService, - @IMessageService messageService: IMessageService, + @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService ) { - super(editor, preferencesModel, associatedPreferencesModel, preferencesService, telemetryService, textFileService, configurationEditingService, messageService, instantiationService); - this.unsupportedWorkbenchSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedWorkbenchSettingsRenderer, editor, preferencesModel)); + super(editor, preferencesModel, preferencesService, telemetryService, textFileService, configurationService, instantiationService); + this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel)); } protected createHeader(): void { @@ -229,7 +223,7 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre public render(): void { super.render(); - this.unsupportedWorkbenchSettingsRenderer.render(); + this.unsupportedSettingsRenderer.render(); } } @@ -242,6 +236,7 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR private filteredMatchesRenderer: FilteredMatchesRenderer; private hiddenAreasRenderer: HiddenAreasRenderer; private editSettingActionRenderer: EditSettingRenderer; + private feedbackWidgetRenderer: FeedbackWidgetRenderer; private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>(); public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting }> = this._onUpdatePreference.event; @@ -252,10 +247,13 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR private _onClearFocusPreference: Emitter = new Emitter(); public readonly onClearFocusPreference: Event = this._onClearFocusPreference.event; + public readonly onTriggeredFuzzy: Event; + private filterResult: IFilterResult; constructor(protected editor: ICodeEditor, public readonly preferencesModel: DefaultSettingsEditorModel, @IPreferencesService protected preferencesService: IPreferencesService, + // @ts-ignore unused injected service @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IInstantiationService protected instantiationService: IInstantiationService ) { @@ -265,11 +263,17 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR this.settingsGroupTitleRenderer = this._register(instantiationService.createInstance(SettingsGroupTitleRenderer, editor)); this.filteredMatchesRenderer = this._register(instantiationService.createInstance(FilteredMatchesRenderer, editor)); this.editSettingActionRenderer = this._register(instantiationService.createInstance(EditSettingRenderer, editor, preferencesModel, this.settingHighlighter)); + this.feedbackWidgetRenderer = this._register(instantiationService.createInstance(FeedbackWidgetRenderer, editor)); + this._register(this.editSettingActionRenderer.onUpdateSetting(e => this._onUpdatePreference.fire(e))); - const paranthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel.settingsGroups)); - this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, paranthesisHidingRenderer])); + const parenthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel.settingsGroups)); + + const hiddenAreasProviders = [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, parenthesisHidingRenderer]; + this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, hiddenAreasProviders)); this._register(this.settingsGroupTitleRenderer.onHiddenAreasChanged(() => this.hiddenAreasRenderer.render())); + + this.onTriggeredFuzzy = this.settingsHeaderRenderer.onClick; } public get associatedPreferencesModel(): IPreferencesEditorModel { @@ -284,28 +288,32 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR public render() { this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups); this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel); + this.feedbackWidgetRenderer.render(null); this.hiddenAreasRenderer.render(); this.settingHighlighter.clear(true); - this.settingsGroupTitleRenderer.showGroup(1); + this.settingsGroupTitleRenderer.showGroup(0); this.hiddenAreasRenderer.render(); } - public filterPreferences(filterResult: IFilterResult): void { + public filterPreferences(filterResult: IFilterResult, fuzzySearchAvailable: boolean): void { this.filterResult = filterResult; - if (!filterResult) { - this.settingHighlighter.clear(true); - this.filteredMatchesRenderer.render(null); - this.settingsHeaderRenderer.render(this.preferencesModel.settingsGroups); - this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups); - this.settingsGroupTitleRenderer.showGroup(1); - this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel); - } else { - this.filteredMatchesRenderer.render(filterResult); - this.settingsHeaderRenderer.render(filterResult.filteredGroups); + if (filterResult) { + this.filteredMatchesRenderer.render(filterResult, this.preferencesModel.settingsGroups); this.settingsGroupTitleRenderer.render(filterResult.filteredGroups); + this.feedbackWidgetRenderer.render(filterResult); + this.settingsHeaderRenderer.render(filterResult, fuzzySearchAvailable); this.settingHighlighter.clear(true); this.editSettingActionRenderer.render(filterResult.filteredGroups, this._associatedPreferencesModel); + } else { + this.settingHighlighter.clear(true); + this.filteredMatchesRenderer.render(null, this.preferencesModel.settingsGroups); + this.feedbackWidgetRenderer.render(null); + this.settingsHeaderRenderer.render(null); + this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups); + this.settingsGroupTitleRenderer.showGroup(0); + this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel); } + this.hiddenAreasRenderer.render(); } @@ -372,6 +380,9 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre get hiddenAreas(): IRange[] { const model = this.editor.getModel(); + + // Hide extra chars for "search results" and "commonly used" groups + const lastGroup = tail(this.settingsGroups); return [ { startLineNumber: 1, @@ -385,6 +396,12 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre endLineNumber: this.settingsGroups[0].range.endLineNumber + 4, endColumn: model.getLineMaxColumn(this.settingsGroups[0].range.endLineNumber + 4) }, + { + startLineNumber: lastGroup.range.endLineNumber + 1, + startColumn: model.getLineMinColumn(lastGroup.range.endLineNumber + 1), + endLineNumber: Math.min(model.getLineCount(), lastGroup.range.endLineNumber + 4), + endColumn: model.getLineMaxColumn(Math.min(model.getLineCount(), lastGroup.range.endLineNumber + 4)) + }, { startLineNumber: model.getLineCount() - 1, startColumn: model.getLineMinColumn(model.getLineCount() - 1), @@ -398,27 +415,28 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre class DefaultSettingsHeaderRenderer extends Disposable { - private settingsHeaderWidget: SettingsHeaderWidget; + private settingsHeaderWidget: DefaultSettingsHeaderWidget; + public onClick: Event; + // @ts-ignore unused property constructor(private editor: ICodeEditor, scope: ConfigurationScope) { super(); const title = scope === ConfigurationScope.RESOURCE ? nls.localize('defaultFolderSettingsTitle', "Default Folder Settings") : nls.localize('defaultSettingsTitle', "Default Settings"); - this.settingsHeaderWidget = this._register(new SettingsHeaderWidget(editor, title)); + this.settingsHeaderWidget = this._register(new DefaultSettingsHeaderWidget(editor, title)); + this.onClick = this.settingsHeaderWidget.onClick; } - public render(settingsGroups: ISettingsGroup[]) { - if (settingsGroups.length) { - this.settingsHeaderWidget.setMessage(''); - } else { - this.settingsHeaderWidget.setMessage(nls.localize('noSettingsFound', "No Settings Found.")); - } + public render(filterResult: IFilterResult, fuzzySearchAvailable = false) { + const hasSettings = !filterResult || filterResult.filteredGroups.length > 0; + const promptFuzzy = fuzzySearchAvailable && filterResult && !filterResult.metadata; + this.settingsHeaderWidget.toggleMessage(hasSettings, promptFuzzy); } } export class SettingsGroupTitleRenderer extends Disposable implements HiddenAreasProvider { private _onHiddenAreasChanged: Emitter = new Emitter(); - get onHiddenAreasChanged(): Event { return this._onHiddenAreasChanged.event; }; + get onHiddenAreasChanged(): Event { return this._onHiddenAreasChanged.event; } private settingsGroups: ISettingsGroup[]; private hiddenGroups: ISettingsGroup[] = []; @@ -441,9 +459,17 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea public render(settingsGroups: ISettingsGroup[]) { this.disposeWidgets(); + if (!settingsGroups) { + return; + } + this.settingsGroups = settingsGroups.slice(); this.settingsGroupTitleWidgets = []; for (const group of this.settingsGroups.slice().reverse()) { + if (group.sections.every(sect => sect.settings.length === 0)) { + continue; + } + const settingsGroupTitleWidget = this.instantiationService.createInstance(SettingsGroupTitleWidget, this.editor, group); settingsGroupTitleWidget.render(); this.settingsGroupTitleWidgets.push(settingsGroupTitleWidget); @@ -453,9 +479,11 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea this.settingsGroupTitleWidgets.reverse(); } - public showGroup(group: number) { - this.hiddenGroups = this.settingsGroups.filter((g, i) => i !== group - 1); - for (const groupTitleWidget of this.settingsGroupTitleWidgets.filter((g, i) => i !== group - 1)) { + public showGroup(groupIdx: number) { + const shownGroup = this.settingsGroupTitleWidgets[groupIdx].settingsGroup; + + this.hiddenGroups = this.settingsGroups.filter(g => g !== shownGroup); + for (const groupTitleWidget of this.settingsGroupTitleWidgets.filter(widget => widget.settingsGroup !== shownGroup)) { groupTitleWidget.toggleCollapse(true); } this._onHiddenAreasChanged.fire(); @@ -507,6 +535,7 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea export class HiddenAreasRenderer extends Disposable { constructor(private editor: ICodeEditor, private hiddenAreasProviders: HiddenAreasProvider[], + // @ts-ignore unused injected service @IInstantiationService private instantiationService: IInstantiationService ) { super(); @@ -526,18 +555,177 @@ export class HiddenAreasRenderer extends Disposable { } } +export class FeedbackWidgetRenderer extends Disposable { + private static DEFAULT_COMMENT_TEXT = 'Replace this comment with any text feedback.'; + private static DEFAULT_ALTS = ['alt 1', 'alt 2']; + private static INSTRUCTION_TEXT = [ + '// Modify the "resultScores" section to contain only your expected results. Assign scores to indicate their relevance.', + '// Results present in "resultScores" will be automatically "boosted" for this query, if they are not already at the top of the result set.', + '// Add phrase pairs to the "alts" section to have them considered to be synonyms in queries.' + ].join('\n'); + + private _feedbackWidget: FloatingClickWidget; + private _currentResult: IFilterResult; + + constructor(private editor: ICodeEditor, + @IInstantiationService private instantiationService: IInstantiationService, + @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @ITelemetryService private telemetryService: ITelemetryService, + @IMessageService private messageService: IMessageService, + @IEnvironmentService private environmentService: IEnvironmentService, + @IConfigurationService private configurationService: IConfigurationService + ) { + super(); + } + + public render(result: IFilterResult): void { + this._currentResult = result; + if (result && result.metadata) { + this.showWidget(); + } else if (this._feedbackWidget) { + this.disposeWidget(); + } + } + + private showWidget(): void { + if (!this._feedbackWidget) { + this._feedbackWidget = this._register(this.instantiationService.createInstance(FloatingClickWidget, this.editor, 'Provide feedback', null)); + this._register(this._feedbackWidget.onClick(() => this.getFeedback())); + this._feedbackWidget.render(); + } + } + + private getFeedback(): void { + if (!this.telemetryService.isOptedIn && this.environmentService.appQuality) { + this.messageService.show(Severity.Error, 'Can\'t send feedback, user is opted out of telemetry'); + return; + } + + const result = this._currentResult; + const actualResultNames = Object.keys(result.metadata.scoredResults); + + const feedbackQuery = {}; + feedbackQuery['comment'] = FeedbackWidgetRenderer.DEFAULT_COMMENT_TEXT; + feedbackQuery['queryString'] = result.query; + feedbackQuery['resultScores'] = {}; + actualResultNames.forEach(settingKey => { + feedbackQuery['resultScores'][settingKey] = 10; + }); + feedbackQuery['alts'] = [FeedbackWidgetRenderer.DEFAULT_ALTS]; + + const contents = FeedbackWidgetRenderer.INSTRUCTION_TEXT + '\n' + JSON.stringify(feedbackQuery, undefined, ' '); + this.editorService.openEditor({ contents, language: 'json' }, /*sideBySide=*/true).then(feedbackEditor => { + const sendFeedbackWidget = this._register(this.instantiationService.createInstance(FloatingClickWidget, feedbackEditor.getControl(), 'Send feedback', null)); + sendFeedbackWidget.render(); + + this._register(sendFeedbackWidget.onClick(() => { + this.sendFeedback(feedbackEditor.getControl() as ICodeEditor, result, result.metadata.scoredResults).then(() => { + sendFeedbackWidget.dispose(); + this.messageService.show(Severity.Info, 'Feedback sent successfully'); + }, err => { + this.messageService.show(Severity.Error, 'Error sending feedback: ' + err.message); + }); + })); + }); + } + + private sendFeedback(feedbackEditor: ICodeEditor, result: IFilterResult, actualResults: IScoredResults): TPromise { + const model = feedbackEditor.getModel(); + const expectedQueryLines = model.getLinesContent() + .filter(line => !strings.startsWith(line, '//')); + + let expectedQuery: any; + try { + expectedQuery = JSON.parse(expectedQueryLines.join('\n')); + } catch (e) { + // invalid JSON + return TPromise.wrapError(new Error('Invalid JSON: ' + e.message)); + } + + const userComment = expectedQuery.comment === FeedbackWidgetRenderer.DEFAULT_COMMENT_TEXT ? undefined : expectedQuery.comment; + + // validate alts + if (!this.validateAlts(expectedQuery.alts)) { + return TPromise.wrapError(new Error('alts must be an array of 2-element string arrays')); + } + + const altsAdded = expectedQuery.alts && expectedQuery.alts[0] && (expectedQuery.alts[0][0] !== FeedbackWidgetRenderer.DEFAULT_ALTS[0] || expectedQuery.alts[0][1] !== FeedbackWidgetRenderer.DEFAULT_ALTS[1]); + const alts = altsAdded ? expectedQuery.alts : undefined; + const workbenchSettings = this.configurationService.getConfiguration().workbench.settings; + const autoIngest = workbenchSettings.experimentalFuzzySearchAutoIngestFeedback; + + /* __GDPR__ + "settingsSearchResultFeedback" : { + "query" : { "classification": "CustomContent", "purpose": "FeatureInsight" }, + "userComment" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "actualResults" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "expectedResults" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "url" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "timestamp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + return this.telemetryService.publicLog('settingsSearchResultFeedback', { + query: result.query, + userComment, + actualResults, + expectedResults: expectedQuery.resultScores, + url: result.metadata.remoteUrl, + duration: result.metadata.duration, + timestamp: result.metadata.timestamp, + buildNumber: this.environmentService.settingsSearchBuildId, + alts, + autoIngest + }); + } + + private validateAlts(alts?: string[][]): boolean { + if (!alts) { + return true; + } + + if (!Array.isArray(alts)) { + return false; + } + + if (!alts.length) { + return true; + } + + if (!alts.every(altPair => Array.isArray(altPair) && altPair.length === 2 && typeof altPair[0] === 'string' && typeof altPair[1] === 'string')) { + return false; + } + + return true; + } + + private disposeWidget(): void { + if (this._feedbackWidget) { + this._feedbackWidget.dispose(); + this._feedbackWidget = null; + } + } + + public dispose() { + this.disposeWidget(); + + super.dispose(); + } +} + export class FilteredMatchesRenderer extends Disposable implements HiddenAreasProvider { private decorationIds: string[] = []; public hiddenAreas: IRange[] = []; constructor(private editor: ICodeEditor, + // @ts-ignore unused injected service @IInstantiationService private instantiationService: IInstantiationService ) { super(); } - public render(result: IFilterResult): void { + public render(result: IFilterResult, allSettingsGroups: ISettingsGroup[]): void { const model = this.editor.getModel(); this.hiddenAreas = []; this.editor.changeDecorations(changeAccessor => { @@ -548,6 +736,8 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr this.editor.changeDecorations(changeAccessor => { this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, result.matches.map(match => this.createDecoration(match, model))); }); + } else { + this.hiddenAreas = this.computeHiddenRanges(allSettingsGroups, allSettingsGroups, model); } } @@ -558,6 +748,7 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'findMatch' } + }; } @@ -565,7 +756,7 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr const notMatchesRanges: IRange[] = []; for (const group of allSettingsGroups) { const filteredGroup = filteredGroups.filter(g => g.title === group.title)[0]; - if (!filteredGroup) { + if (!filteredGroup || filteredGroup.sections.every(sect => sect.settings.length === 0)) { notMatchesRanges.push({ startLineNumber: group.range.startLineNumber - 1, startColumn: model.getLineMinColumn(group.range.startLineNumber - 1), @@ -633,6 +824,7 @@ export class HighlightMatchesRenderer extends Disposable { private decorationIds: string[] = []; constructor(private editor: ICodeEditor, + // @ts-ignore unused injected service @IInstantiationService private instantiationService: IInstantiationService ) { super(); @@ -686,6 +878,7 @@ class EditSettingRenderer extends Disposable { constructor(private editor: ICodeEditor, private masterSettingsModel: ISettingsEditorModel, private settingHighlighter: SettingHighlighter, + // @ts-ignore unused injected service @IPreferencesService private preferencesService: IPreferencesService, @IInstantiationService private instantiationService: IInstantiationService, @IContextMenuService private contextMenuService: IContextMenuService @@ -796,10 +989,14 @@ class EditSettingRenderer extends Disposable { let configurationNode = configurationMap[setting.key]; if (configurationNode) { if (this.isDefaultSettings()) { + if (setting.key === 'launch') { + // Do not show because of https://github.com/Microsoft/vscode/issues/32593 + return false; + } return true; } if (configurationNode.type === 'boolean' || configurationNode.enum) { - if ((this.masterSettingsModel).configurationTarget !== ConfigurationTarget.FOLDER) { + if ((this.masterSettingsModel).configurationTarget !== ConfigurationTarget.WORKSPACE_FOLDER) { return true; } if (configurationNode.scope === ConfigurationScope.RESOURCE) { @@ -847,7 +1044,7 @@ class EditSettingRenderer extends Disposable { } private onEditSettingClicked(editPreferenceWidget: EditPreferenceWidget, e: IEditorMouseEvent): void { - const anchor = { x: e.event.posx + 1, y: e.event.posy + 10 }; + const anchor = { x: e.event.posx, y: e.event.posy + 10 }; const actions = this.getSettings(editPreferenceWidget.getLine()).length === 1 ? this.getActions(editPreferenceWidget.preferences[0], this.getConfigurationsMap()[editPreferenceWidget.preferences[0].key]) : editPreferenceWidget.preferences.map(setting => new ContextSubMenu(setting.key, this.getActions(setting, this.getConfigurationsMap()[setting.key]))); this.contextMenuService.showContextMenu({ @@ -888,8 +1085,8 @@ class EditSettingRenderer extends Disposable { } private getDefaultActions(setting: ISetting): IAction[] { - const settingInOtherModel = this.associatedPreferencesModel.getPreference(setting.key); if (this.isDefaultSettings()) { + const settingInOtherModel = this.associatedPreferencesModel.getPreference(setting.key); return [{ id: 'setDefaultValue', label: settingInOtherModel ? nls.localize('replaceDefaultValue', "Replace in Settings") : nls.localize('copyDefaultValue', "Copy to Settings"), @@ -945,14 +1142,70 @@ class SettingHighlighter extends Disposable { } } -class UnsupportedWorkspaceSettingsRenderer extends Disposable { +class UnsupportedSettingsRenderer extends Disposable { - constructor(private editor: editorCommon.ICommonCodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel, + private decorationIds: string[] = []; + private renderingDelayer: Delayer = new Delayer(200); + + constructor( + private editor: editorCommon.ICommonCodeEditor, + private settingsEditorModel: SettingsEditorModel, + // @ts-ignore unused injected service @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, - @IMarkerService private markerService: IMarkerService + @IMarkerService private markerService: IMarkerService, + @IEnvironmentService private environmentService: IEnvironmentService ) { super(); - this._register(this.configurationService.onDidUpdateConfiguration(() => this.render())); + this._register(this.editor.getModel().onDidChangeContent(() => this.renderingDelayer.trigger(() => this.render()))); + } + + public render(): void { + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); + const ranges: IRange[] = []; + const markerData: IMarkerData[] = []; + for (const settingsGroup of this.settingsEditorModel.settingsGroups) { + for (const section of settingsGroup.sections) { + for (const setting of section.settings) { + if (this.settingsEditorModel.configurationTarget === ConfigurationTarget.WORKSPACE || this.settingsEditorModel.configurationTarget === ConfigurationTarget.WORKSPACE_FOLDER) { + // Show warnings for executable settings + if (configurationRegistry[setting.key] && configurationRegistry[setting.key].isExecutable) { + markerData.push({ + severity: Severity.Warning, + startLineNumber: setting.keyRange.startLineNumber, + startColumn: setting.keyRange.startColumn, + endLineNumber: setting.keyRange.endLineNumber, + endColumn: setting.keyRange.endColumn, + message: this.getMarkerMessage(setting.key) + }); + } + } + if (this.settingsEditorModel.configurationTarget === ConfigurationTarget.WORKSPACE_FOLDER) { + // Dim and show information for window settings + if (configurationRegistry[setting.key] && configurationRegistry[setting.key].scope === ConfigurationScope.WINDOW) { + ranges.push({ + startLineNumber: setting.keyRange.startLineNumber, + startColumn: setting.keyRange.startColumn - 1, + endLineNumber: setting.valueRange.endLineNumber, + endColumn: setting.valueRange.endColumn + }); + } + } + } + } + } + if (markerData.length) { + this.markerService.changeOne('preferencesEditor', this.settingsEditorModel.uri, markerData); + } else { + this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]); + } + this.editor.changeDecorations(changeAccessor => this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, ranges.map(range => this.createDecoration(range, this.editor.getModel())))); + } + + private createDecoration(range: IRange, model: editorCommon.IModel): editorCommon.IModelDeltaDecoration { + return { + range, + options: !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment ? UnsupportedSettingsRenderer._DIM_CONFIGUARATION_DEV_MODE : UnsupportedSettingsRenderer._DIM_CONFIGUARATION_ + }; } private getMarkerMessage(settingKey: string): string { @@ -964,67 +1217,14 @@ class UnsupportedWorkspaceSettingsRenderer extends Disposable { } } - public render(): void { - const unsupportedWorkspaceKeys = this.configurationService.getUnsupportedWorkspaceKeys(); - if (unsupportedWorkspaceKeys.length) { - const markerData: IMarkerData[] = []; - for (const unsupportedKey of unsupportedWorkspaceKeys) { - const setting = this.workspaceSettingsEditorModel.getPreference(unsupportedKey); - if (setting) { - markerData.push({ - severity: Severity.Warning, - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn, - endLineNumber: setting.keyRange.endLineNumber, - endColumn: setting.keyRange.endColumn, - message: this.getMarkerMessage(unsupportedKey) - }); - } - } - if (markerData.length) { - this.markerService.changeOne('preferencesEditor', this.workspaceSettingsEditorModel.uri, markerData); - } else { - this.markerService.remove('preferencesEditor', [this.workspaceSettingsEditorModel.uri]); - } - } - } - public dispose(): void { - this.markerService.remove('preferencesEditor', [this.workspaceSettingsEditorModel.uri]); - super.dispose(); - } -} - -class UnsupportedWorkbenchSettingsRenderer extends Disposable { - - private decorationIds: string[] = []; - private renderingDelayer: Delayer = new Delayer(200); - - constructor(private editor: editorCommon.ICommonCodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel, - @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, - ) { - super(); - this._register(this.editor.getModel().onDidChangeContent(() => this.renderingDelayer.trigger(() => this.render()))); - } - - public render(): void { - const ranges: IRange[] = []; - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); - for (const settingsGroup of this.workspaceSettingsEditorModel.settingsGroups) { - for (const section of settingsGroup.sections) { - for (const setting of section.settings) { - if (configurationRegistry[setting.key] && configurationRegistry[setting.key].scope === ConfigurationScope.WINDOW) { - ranges.push({ - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn - 1, - endLineNumber: setting.valueRange.endLineNumber, - endColumn: setting.valueRange.endColumn - }); - } - } - } + this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]); + if (this.decorationIds) { + this.decorationIds = this.editor.changeDecorations(changeAccessor => { + return changeAccessor.deltaDecorations(this.decorationIds, []); + }); } - this.editor.changeDecorations(changeAccessor => this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, ranges.map(range => this.createDecoration(range, this.editor.getModel())))); + super.dispose(); } private static _DIM_CONFIGUARATION_ = ModelDecorationOptions.register({ @@ -1034,21 +1234,12 @@ class UnsupportedWorkbenchSettingsRenderer extends Disposable { hoverMessage: new MarkdownString().appendText(nls.localize('unsupportedWorkbenchSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.")) }); - private createDecoration(range: IRange, model: editorCommon.IModel): editorCommon.IModelDeltaDecoration { - return { - range, - options: UnsupportedWorkbenchSettingsRenderer._DIM_CONFIGUARATION_ - }; - } - - public dispose(): void { - if (this.decorationIds) { - this.decorationIds = this.editor.changeDecorations(changeAccessor => { - return changeAccessor.deltaDecorations(this.decorationIds, []); - }); - } - super.dispose(); - } + private static _DIM_CONFIGUARATION_DEV_MODE = ModelDecorationOptions.register({ + stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + inlineClassName: 'dim-configuration', + beforeContentClassName: 'unsupportedWorkbenhSettingInfo', + hoverMessage: new MarkdownString().appendText(nls.localize('unsupportedWorkbenchSettingDevMode', "This setting cannot be applied now. It will be applied if you define it's scope as 'resource' while registering, or when you open this folder directly.")) + }); } class WorkspaceConfigurationRenderer extends Disposable { @@ -1064,11 +1255,11 @@ class WorkspaceConfigurationRenderer extends Disposable { } public render(): void { - if (this.workspaceContextService.hasMultiFolderWorkspace()) { + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.workspaceSettingsEditorModel instanceof WorkspaceConfigurationEditorModel) { this.editor.changeDecorations(changeAccessor => this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, [])); const ranges: IRange[] = []; - for (const settingsGroup of this.workspaceSettingsEditorModel.settingsGroups) { + for (const settingsGroup of this.workspaceSettingsEditorModel.configurationGroups) { for (const section of settingsGroup.sections) { for (const setting of section.settings) { if (setting.key !== 'settings') { diff --git a/src/vs/workbench/parts/preferences/browser/preferencesSearch.ts b/src/vs/workbench/parts/preferences/browser/preferencesSearch.ts new file mode 100644 index 00000000000..eda9991fce8 --- /dev/null +++ b/src/vs/workbench/parts/preferences/browser/preferencesSearch.ts @@ -0,0 +1,331 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; +import { ISettingsEditorModel, IFilterResult, ISetting, ISettingsGroup, IWorkbenchSettingsConfiguration, IFilterMetadata } from 'vs/workbench/parts/preferences/common/preferences'; +import { IRange, Range } from 'vs/editor/common/core/range'; +import { distinct } from 'vs/base/common/arrays'; +import * as strings from 'vs/base/common/strings'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; +import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; + +export interface IEndpointDetails { + urlBase: string; + key: string; + boost: number; +} + +export class PreferencesSearchProvider { + private _onRemoteSearchEnablementChanged = new Emitter(); + public onRemoteSearchEnablementChanged: Event = this._onRemoteSearchEnablementChanged.event; + + constructor( + @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, + @IEnvironmentService private environmentService: IEnvironmentService + ) { + configurationService.onDidChangeConfiguration(() => this._onRemoteSearchEnablementChanged.fire(this.remoteSearchEnabled)); + } + + get remoteSearchEnabled(): boolean { + if (this.environmentService.appQuality === 'stable') { + return false; + } + + const endpoint = this.endpoint; + return !!endpoint.urlBase && !!endpoint.key; + } + + get endpoint(): IEndpointDetails { + const workbenchSettings = this.configurationService.getConfiguration().workbench.settings; + return { + urlBase: workbenchSettings.experimentalFuzzySearchEndpoint, + key: workbenchSettings.experimentalFuzzySearchKey, + boost: workbenchSettings.experimentalFuzzySearchBoost + }; + } + + startSearch(filter: string, remote: boolean): PreferencesSearchModel { + return new PreferencesSearchModel(this, filter, remote, this.environmentService); + } +} + +export class PreferencesSearchModel { + private _localProvider: LocalSearchProvider; + private _remoteProvider: RemoteSearchProvider; + + constructor(private provider: PreferencesSearchProvider, private filter: string, remote: boolean, environmentService: IEnvironmentService) { + this._localProvider = new LocalSearchProvider(filter); + + if (remote && filter) { + this._remoteProvider = new RemoteSearchProvider(filter, this.provider.endpoint, environmentService); + } + } + + filterPreferences(preferencesModel: ISettingsEditorModel): TPromise { + if (!this.filter) { + return TPromise.wrap(null); + } + + if (this._remoteProvider) { + return this._remoteProvider.filterPreferences(preferencesModel).then(null, err => { + return this._localProvider.filterPreferences(preferencesModel); + }); + } else { + return this._localProvider.filterPreferences(preferencesModel); + } + } +} + +class LocalSearchProvider { + private _filter: string; + + constructor(filter: string) { + this._filter = filter; + } + + filterPreferences(preferencesModel: ISettingsEditorModel): TPromise { + const regex = strings.createRegExp(this._filter, false, { global: true }); + + const groupFilter = (group: ISettingsGroup) => { + return regex.test(group.title); + }; + + const settingFilter = (setting: ISetting) => { + return new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + }; + + return TPromise.wrap(preferencesModel.filterSettings(this._filter, groupFilter, settingFilter)); + } +} + +class RemoteSearchProvider { + private _filter: string; + private _remoteSearchP: TPromise; + + constructor(filter: string, endpoint: IEndpointDetails, private environmentService: IEnvironmentService) { + this._filter = filter; + this._remoteSearchP = filter ? this.getSettingsFromBing(filter, endpoint) : TPromise.wrap(null); + } + + filterPreferences(preferencesModel: ISettingsEditorModel): TPromise { + return this._remoteSearchP.then(remoteResult => { + const settingFilter = (setting: ISetting) => { + if (!!remoteResult.scoredResults[setting.key]) { + const settingMatches = new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; + if (settingMatches.length) { + return settingMatches; + } else { + return [new Range(setting.keyRange.startLineNumber, setting.keyRange.startColumn, setting.keyRange.endLineNumber, setting.keyRange.startColumn)]; + } + } else { + return null; + } + }; + + if (remoteResult) { + const sortedNames = Object.keys(remoteResult.scoredResults).sort((a, b) => remoteResult.scoredResults[b] - remoteResult.scoredResults[a]); + const result = preferencesModel.filterSettings(this._filter, group => null, settingFilter, sortedNames); + result.metadata = remoteResult; + return result; + } else { + return null; + } + }); + } + + private getSettingsFromBing(filter: string, endpoint: IEndpointDetails): TPromise { + const url = prepareUrl(filter, endpoint, this.environmentService.settingsSearchBuildId); + console.log('fetching: ' + url); + const start = Date.now(); + const p = fetch(url, { + headers: new Headers({ + 'User-Agent': 'request', + 'Content-Type': 'application/json; charset=utf-8', + 'api-key': endpoint.key + }) + }) + .then(r => r.json()) + .then(result => { + const timestamp = Date.now(); + const duration = timestamp - start; + console.log('time: ' + duration / 1000); + const suggestions = (result.value || []) + .map(r => ({ + name: r.setting || r.Setting, + score: r['@search.score'] + })); + + const scoredResults = Object.create(null); + suggestions.forEach(s => { + const name = s.name + .replace(/^"/, '') + .replace(/"$/, ''); + scoredResults[name] = s.score; + }); + + return { + remoteUrl: url, + duration, + timestamp, + scoredResults + }; + }); + + return TPromise.as(p as any); + } +} + +const API_VERSION = 'api-version=2016-09-01-Preview'; +const QUERY_TYPE = 'querytype=full'; +const SCORING_PROFILE = 'scoringProfile=ranking'; + +function escapeSpecialChars(query: string): string { + return query.replace(/\./g, ' ') + .replace(/[\\/+\-&|!"~*?:(){}\[\]\^]/g, '\\$&') + .replace(/ /g, ' ') // collapse spaces + .trim(); +} + +function prepareUrl(query: string, endpoint: IEndpointDetails, buildNumber: number): string { + query = escapeSpecialChars(query); + const boost = endpoint.boost || 1; + const userQuery = `(${query})^${boost}`; + + // Appending Fuzzy after each word. + query = query.replace(/\ +/g, '~ ') + '~'; + + let url = `${endpoint.urlBase}?${API_VERSION}&search=${encodeURIComponent(userQuery + ' || ' + query)}&${QUERY_TYPE}&${SCORING_PROFILE}`; + if (buildNumber) { + url += `&$filter startbuildno le ${buildNumber} and endbuildno ge ${buildNumber}`; + } + + return url; +} + +class SettingMatches { + + private readonly descriptionMatchingWords: Map = new Map(); + private readonly keyMatchingWords: Map = new Map(); + private readonly valueMatchingWords: Map = new Map(); + + public readonly matches: IRange[]; + + constructor(searchString: string, setting: ISetting, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { + this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`); + } + + private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] { + const result = this._doFindMatchesInSetting(searchString, setting); + if (setting.overrides && setting.overrides.length) { + for (const subSetting of setting.overrides) { + const subSettingMatches = new SettingMatches(searchString, subSetting, this.valuesMatcher); + let words = searchString.split(' '); + const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]); + result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges); + result.push(...subSettingMatches.matches); + } + } + return result; + } + + private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] { + const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as(Extensions.Configuration).getConfigurationProperties(); + const schema: IJSONSchema = registry[setting.key]; + + let words = searchString.split(' '); + const settingKeyAsWords: string = setting.key.split('.').join(' '); + + for (const word of words) { + for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { + const descriptionMatches = matchesWords(word, setting.description[lineIndex], true); + if (descriptionMatches) { + this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex))); + } + } + + const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords); + if (keyMatches) { + this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match))); + } + + const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null; + if (valueMatches) { + this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match))); + } else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) { + this.valueMatchingWords.set(word, []); + } + } + + const descriptionRanges: IRange[] = []; + for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { + const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || []; + descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex))); + } + if (descriptionRanges.length === 0) { + descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords])); + } + + const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key); + const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]); + + let valueRanges: IRange[] = []; + if (setting.value && typeof setting.value === 'string') { + const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value); + valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]); + } else { + valueRanges = this.valuesMatcher(searchString, setting); + } + + return [...descriptionRanges, ...keyRanges, ...valueRanges]; + } + + private getRangesForWords(words: string[], from: Map, others: Map[]): IRange[] { + const result: IRange[] = []; + for (const word of words) { + const ranges = from.get(word); + if (ranges) { + result.push(...ranges); + } else if (others.every(o => !o.has(word))) { + return []; + } + } + return result; + } + + private toKeyRange(setting: ISetting, match: IMatch): IRange { + return { + startLineNumber: setting.keyRange.startLineNumber, + startColumn: setting.keyRange.startColumn + match.start, + endLineNumber: setting.keyRange.startLineNumber, + endColumn: setting.keyRange.startColumn + match.end + }; + } + + private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange { + return { + startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber, + startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start, + endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber, + endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end + }; + } + + private toValueRange(setting: ISetting, match: IMatch): IRange { + return { + startLineNumber: setting.valueRange.startLineNumber, + startColumn: setting.valueRange.startColumn + match.start + 1, + endLineNumber: setting.valueRange.startLineNumber, + endColumn: setting.valueRange.startColumn + match.end + 1 + }; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index d37e517d962..c9f691030ed 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -8,18 +8,16 @@ import * as network from 'vs/base/common/network'; import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; -import { ResourceMap } from 'vs/base/common/map'; import * as labels from 'vs/base/common/labels'; import * as strings from 'vs/base/common/strings'; import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; import { EditorInput } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { Position as EditorPosition, IEditor } from 'vs/platform/editor/common/editor'; -import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; +import { Position as EditorPosition, IEditor, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { ICommonCodeEditor, IModel } from 'vs/editor/common/editorCommon'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; @@ -27,9 +25,8 @@ import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/c import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences'; -import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, WorkspaceConfigModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; +import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; +import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, DefaultSettingsModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor'; import { KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor'; @@ -41,15 +38,9 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; - - -interface IWorkbenchSettingsConfiguration { - workbench: { - settings: { - openDefaultSettings: boolean; - } - }; -} +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { parse } from 'vs/base/common/json'; const emptyEditableSettingsContent = '{\n}'; @@ -57,33 +48,37 @@ export class PreferencesService extends Disposable implements IPreferencesServic _serviceBrand: any; - // TODO:@sandy merge these models into editor inputs by extending resource editor model - private defaultPreferencesEditorModels: ResourceMap>>; private lastOpenedSettingsInput: PreferencesEditorInput = null; private _onDispose: Emitter = new Emitter(); + private _defaultSettingsUriCounter = 0; + private _defaultSettingsContentModel: DefaultSettingsModel; + private _defaultResourceSettingsUriCounter = 0; + private _defaultResourceSettingsContentModel: DefaultSettingsModel; + constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService, @IFileService private fileService: IFileService, @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, @IMessageService private messageService: IMessageService, + // @ts-ignore unused injected service @IChoiceService private choiceService: IChoiceService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService, + // @ts-ignore unused injected service @IStorageService private storageService: IStorageService, @IEnvironmentService private environmentService: IEnvironmentService, @ITelemetryService private telemetryService: ITelemetryService, @ITextModelService private textModelResolverService: ITextModelService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IExtensionService private extensionService: IExtensionService, @IKeybindingService keybindingService: IKeybindingService, @IModelService private modelService: IModelService, - @IJSONEditingService private jsonEditingService: IJSONEditingService + @IJSONEditingService private jsonEditingService: IJSONEditingService, + @IModeService private modeService: IModeService ) { super(); - this.defaultPreferencesEditorModels = new ResourceMap>>(); this.editorGroupService.onEditorsChanged(() => { const activeEditorInput = this.editorService.getActiveEditorInput(); if (activeEditorInput instanceof PreferencesEditorInput) { @@ -103,10 +98,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - readonly defaultSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/settings.json' }); - readonly defaultResourceSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/resourceSettings.json' }); readonly defaultKeybindingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/keybindings.json' }); - private readonly workspaceConfigSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'settings', path: '/workspaceSettings.json' }); get userSettingsResource(): URI { return this.getEditableSettingsURI(ConfigurationTarget.USER); @@ -117,89 +109,66 @@ export class PreferencesService extends Disposable implements IPreferencesServic } getFolderSettingsResource(resource: URI): URI { - return this.getEditableSettingsURI(ConfigurationTarget.FOLDER, resource); + return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource); } - resolveContent(uri: URI): TPromise { - const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); - if (workspaceSettingsUri && workspaceSettingsUri.fsPath === uri.fsPath) { - return this.resolveSettingsContentFromWorkspaceConfiguration(); + resolveModel(uri: URI): TPromise { + if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) { + return this.extensionService.onReady() + .then(() => { + const scope = this.isDefaultSettingsResource(uri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE; + const settingsModel = this.getDefaultSettingsModel(scope); + const mode = this.modeService.getOrCreateMode('json'); + const model = this._register(this.modelService.createModel(settingsModel.content, mode, uri)); + return model; + }); } - return this.createPreferencesEditorModel(uri) - .then(preferencesEditorModel => preferencesEditorModel ? preferencesEditorModel.content : null); + + if (this.defaultKeybindingsResource.toString() === uri.toString()) { + const defaultKeybindingsEditorModel = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri); + const mode = this.modeService.getOrCreateMode('json'); + const model = this._register(this.modelService.createModel(defaultKeybindingsEditorModel.content, mode, uri)); + return TPromise.as(model); + } + + return TPromise.as(null); } createPreferencesEditorModel(uri: URI): TPromise> { - let promise = this.defaultPreferencesEditorModels.get(uri); - if (promise) { - return promise; + if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) { + return this.createDefaultSettingsEditorModel(uri); } - if (this.defaultSettingsResource.fsPath === uri.fsPath) { - promise = TPromise.join([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()]) - .then(result => { - const mostCommonSettings = result[1]; - const model = this.instantiationService.createInstance(DefaultSettingsEditorModel, uri, mostCommonSettings, ConfigurationScope.WINDOW); - return model; - }); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; - } - - if (this.defaultResourceSettingsResource.fsPath === uri.fsPath) { - promise = TPromise.join([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()]) - .then(result => { - const mostCommonSettings = result[1]; - const model = this.instantiationService.createInstance(DefaultSettingsEditorModel, uri, mostCommonSettings, ConfigurationScope.RESOURCE); - return model; - }); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; - } - - if (this.defaultKeybindingsResource.fsPath === uri.fsPath) { - const model = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri); - promise = TPromise.wrap(model); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; - } - - if (this.workspaceConfigSettingsResource.fsPath === uri.fsPath) { - promise = this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri); - this.defaultPreferencesEditorModels.set(uri, promise); - return promise; - } - - if (this.getEditableSettingsURI(ConfigurationTarget.USER).fsPath === uri.fsPath) { + if (this.getEditableSettingsURI(ConfigurationTarget.USER).toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.USER, uri); } const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); - if (workspaceSettingsUri && workspaceSettingsUri.fsPath === uri.fsPath) { + if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, workspaceSettingsUri); } - if (this.contextService.hasMultiFolderWorkspace()) { - return this.createEditableSettingsEditorModel(ConfigurationTarget.FOLDER, uri); + if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); } return TPromise.wrap>(null); } - openGlobalSettings(): TPromise { - return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource); + openGlobalSettings(options?: IEditorOptions, position?: EditorPosition): TPromise { + return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource, options, position); } - openWorkspaceSettings(): TPromise { - if (!this.contextService.hasWorkspace()) { + openWorkspaceSettings(options?: IEditorOptions, position?: EditorPosition): TPromise { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(Severity.Info, nls.localize('openFolderFirst', "Open a folder first to create workspace settings")); return TPromise.as(null); } - return this.doOpenSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource); + return this.doOpenSettings(ConfigurationTarget.WORKSPACE, this.workspaceSettingsResource, options, position); } - openFolderSettings(folder: URI): TPromise { - return this.doOpenSettings(ConfigurationTarget.FOLDER, this.getEditableSettingsURI(ConfigurationTarget.FOLDER, folder)); + openFolderSettings(folder: URI, options?: IEditorOptions, position?: EditorPosition): TPromise { + return this.doOpenSettings(ConfigurationTarget.WORKSPACE_FOLDER, this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder), options, position); } switchSettings(target: ConfigurationTarget, resource: URI): TPromise { @@ -223,6 +192,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic } openGlobalKeybindingSettings(textual: boolean): TPromise { + /* __GDPR__ + "openKeybindings" : { + "textual" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('openKeybindings', { textual }); if (textual) { const emptyContents = '// ' + nls.localize('emptyKeybindingsHeader', "Place your key bindings in this file to overwrite the defaults") + '\n[\n]'; @@ -254,30 +228,45 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI): TPromise { - const openDefaultSettings = !!this.configurationService.getConfiguration().workbench.settings.openDefaultSettings; + private doOpenSettings(configurationTarget: ConfigurationTarget, resource: URI, options?: IEditorOptions, position?: EditorPosition): TPromise { + const openDefaultSettings = !!this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING); return this.getOrCreateEditableSettingsEditorInput(configurationTarget, resource) .then(editableSettingsEditorInput => { + if (!options) { + options = { pinned: true }; + } else { + options.pinned = true; + } + if (openDefaultSettings) { const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.getDefaultSettingsResource(configurationTarget)); const preferencesEditorInput = new PreferencesEditorInput(this.getPreferencesEditorInputName(configurationTarget, resource), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, editableSettingsEditorInput); this.lastOpenedSettingsInput = preferencesEditorInput; - return this.editorService.openEditor(preferencesEditorInput, { pinned: true }); + return this.editorService.openEditor(preferencesEditorInput, options, position); } - return this.editorService.openEditor(editableSettingsEditorInput, { pinned: true }); + return this.editorService.openEditor(editableSettingsEditorInput, options, position); }); } + private isDefaultSettingsResource(uri: URI): boolean { + return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?settings\.json$/); + } + + private isDefaultResourceSettingsResource(uri: URI): boolean { + return uri.authority === 'defaultsettings' && uri.scheme === network.Schemas.vscode && !!uri.path.match(/\/(\d+\/)?resourceSettings\.json$/); + } + private getDefaultSettingsResource(configurationTarget: ConfigurationTarget): URI { - if (configurationTarget === ConfigurationTarget.FOLDER) { - return this.defaultResourceSettingsResource; + if (configurationTarget === ConfigurationTarget.WORKSPACE_FOLDER) { + return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultResourceSettingsUriCounter++}/resourceSettings.json` }); + } else { + return URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: `/${this._defaultSettingsUriCounter++}/settings.json` }); } - return this.defaultSettingsResource; } private getPreferencesEditorInputName(target: ConfigurationTarget, resource: URI): string { const name = getSettingsTargetName(target, resource, this.contextService); - return target === ConfigurationTarget.FOLDER ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name; + return target === ConfigurationTarget.WORKSPACE_FOLDER ? nls.localize('folderSettingsName', "{0} (Folder Settings)", name) : name; } private getOrCreateEditableSettingsEditorInput(target: ConfigurationTarget, resource: URI): TPromise { @@ -288,9 +277,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): TPromise { const settingsUri = this.getEditableSettingsURI(configurationTarget, resource); if (settingsUri) { - if (settingsUri.fsPath === this.workspaceConfigSettingsResource.fsPath) { - return TPromise.join([this.textModelResolverService.createModelReference(settingsUri), this.textModelResolverService.createModelReference(this.contextService.getWorkspace().configuration)]) - .then(([reference, workspaceConfigReference]) => this.instantiationService.createInstance(WorkspaceConfigModel, reference, workspaceConfigReference, configurationTarget, this._onDispose.event)); + const workspace = this.contextService.getWorkspace(); + if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { + return this.textModelResolverService.createModelReference(settingsUri) + .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); } return this.textModelResolverService.createModelReference(settingsUri) .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); @@ -298,17 +288,27 @@ export class PreferencesService extends Disposable implements IPreferencesServic return TPromise.wrap(null); } - private resolveSettingsContentFromWorkspaceConfiguration(): TPromise { - if (this.contextService.hasMultiFolderWorkspace()) { - return this.textModelResolverService.createModelReference(this.contextService.getWorkspace().configuration) - .then(reference => { - const model = reference.object.textEditorModel; - const settingsContent = WorkspaceConfigModel.getSettingsContentFromConfigContent(model.getValue()); - reference.dispose(); - return TPromise.as(settingsContent ? settingsContent : emptyEditableSettingsContent); - }); + private createDefaultSettingsEditorModel(defaultSettingsUri: URI): TPromise { + return this.textModelResolverService.createModelReference(defaultSettingsUri) + .then(reference => { + const scope = this.isDefaultSettingsResource(defaultSettingsUri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE; + return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, scope, this.getDefaultSettingsModel(scope).settingsGroups); + }); + } + + private getDefaultSettingsModel(scope: ConfigurationScope): DefaultSettingsModel { + switch (scope) { + case ConfigurationScope.WINDOW: + if (!this._defaultSettingsContentModel) { + this._defaultSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope); + } + return this._defaultSettingsContentModel; + case ConfigurationScope.RESOURCE: + if (!this._defaultResourceSettingsContentModel) { + this._defaultResourceSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope); + } + return this._defaultResourceSettingsContentModel; } - return TPromise.as(null); } private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI { @@ -316,30 +316,27 @@ export class PreferencesService extends Disposable implements IPreferencesServic case ConfigurationTarget.USER: return URI.file(this.environmentService.appSettingsPath); case ConfigurationTarget.WORKSPACE: + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + return null; + } const workspace = this.contextService.getWorkspace(); - if (this.contextService.hasFolderWorkspace()) { - return this.toResource(paths.join('.vscode', 'settings.json'), workspace.roots[0]); - } - if (this.contextService.hasMultiFolderWorkspace()) { - return workspace.configuration; - } - return null; - case ConfigurationTarget.FOLDER: - const root = this.contextService.getRoot(resource); - return root ? this.toResource(paths.join('.vscode', 'settings.json'), root) : null; + return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); + case ConfigurationTarget.WORKSPACE_FOLDER: + const folder = this.contextService.getWorkspaceFolder(resource); + return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; } return null; } - private toResource(relativePath: string, root: URI): URI { - return URI.file(paths.join(root.fsPath, relativePath)); - } - private createSettingsIfNotExists(target: ConfigurationTarget, resource: URI): TPromise { - if (this.contextService.hasMultiFolderWorkspace() && target === ConfigurationTarget.WORKSPACE) { - if (!this.configurationService.keys().workspace.length) { - return this.jsonEditingService.write(resource, { key: 'settings', value: {} }, true).then(null, () => { }); - } + if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && target === ConfigurationTarget.WORKSPACE) { + return this.fileService.resolveContent(this.contextService.getWorkspace().configuration) + .then(content => { + if (Object.keys(parse(content.value)).indexOf('settings') === -1) { + return this.jsonEditingService.write(resource, { key: 'settings', value: {} }, true).then(null, () => { }); + } + return null; + }); } return this.createIfNotExists(resource, emptyEditableSettingsContent).then(() => { }); } @@ -356,8 +353,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic }); } - private fetchMostCommonlyUsedSettings(): TPromise { - return TPromise.wrap([ + private getMostCommonlyUsedSettings(): string[] { + return [ 'files.autoSave', 'editor.fontSize', 'editor.fontFamily', @@ -369,7 +366,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic 'editor.wordWrap', 'files.exclude', 'files.associations' - ]); + ]; } private getPosition(language: string, codeEditor: ICommonCodeEditor): TPromise { @@ -395,7 +392,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic } return { lineNumber: setting.valueRange.startLineNumber, column: setting.valueRange.startColumn + 1 }; } - return this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: languageKey, value: {} }, { donotSave: true }) + return this.configurationService.updateValue(languageKey, {}, ConfigurationTarget.USER) .then(() => { setting = settingsModel.getPreference(languageKey); let content = eol + this.spaces(2, configuration) + eol + this.spaces(1, configuration); @@ -414,7 +411,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic public dispose(): void { this._onDispose.fire(); - this.defaultPreferencesEditorModels.clear(); super.dispose(); } } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts index c2212fcb657..0057f2d43d2 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts @@ -10,6 +10,7 @@ import * as DOM from 'vs/base/browser/dom'; import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/base/common/lifecycle'; import { Widget } from 'vs/base/browser/ui/widget'; +import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import Event, { Emitter } from 'vs/base/common/event'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -20,9 +21,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ISettingsGroup, IPreferencesService, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IAction, IActionRunner } from 'vs/base/common/actions'; -import { attachInputBoxStyler, attachStylerCallback, attachSelectBoxStyler } from 'vs/platform/theme/common/styler'; +import { attachInputBoxStyler, attachStylerCallback, attachSelectBoxStyler, attachCheckboxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Position } from 'vs/editor/common/core/position'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -32,19 +33,20 @@ import { ISelectBoxStyles, defaultStyles } from 'vs/base/browser/ui/selectBox/se import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Color } from 'vs/base/common/color'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { MarkdownString } from 'vs/base/common/htmlContent'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; export class SettingsHeaderWidget extends Widget implements IViewZone { private id: number; private _domNode: HTMLElement; - private titleContainer: HTMLElement; + protected titleContainer: HTMLElement; private messageElement: HTMLElement; - constructor(private editor: ICodeEditor, private title: string) { + constructor(protected editor: ICodeEditor, private title: string) { super(); this.create(); this._register(this.editor.onDidChangeConfiguration(() => this.layout())); @@ -63,7 +65,7 @@ export class SettingsHeaderWidget extends Widget implements IViewZone { return 0; } - private create() { + protected create() { this._domNode = DOM.$('.settings-header-widget'); this.titleContainer = DOM.append(this._domNode, DOM.$('.title-container')); @@ -101,6 +103,38 @@ export class SettingsHeaderWidget extends Widget implements IViewZone { } } +export class DefaultSettingsHeaderWidget extends SettingsHeaderWidget { + + private linkElement: HTMLElement; + private _onClick = this._register(new Emitter()); + public onClick: Event = this._onClick.event; + + protected create() { + super.create(); + + this.linkElement = DOM.append(this.titleContainer, DOM.$('a.settings-header-fuzzy-link')); + this.linkElement.textContent = localize('defaultSettingsFuzzyPrompt', "Try fuzzy search!"); + + this.onclick(this.linkElement, e => this._onClick.fire()); + this.toggleMessage(true); + } + + public toggleMessage(hasSettings: boolean, promptFuzzy = false): void { + if (hasSettings) { + this.setMessage(localize('defaultSettings', "Place your settings in the right hand side editor to override.")); + DOM.addClass(this.linkElement, 'hidden'); + } else { + this.setMessage(localize('noSettingsFound', "No Settings Found.")); + + if (promptFuzzy) { + DOM.removeClass(this.linkElement, 'hidden'); + } else { + DOM.addClass(this.linkElement, 'hidden'); + } + } + } +} + export class SettingsGroupTitleWidget extends Widget implements IViewZone { private id: number; @@ -271,7 +305,7 @@ export class SettingsTargetsWidget extends Widget { private borderColor: Color; - constructor(parent: HTMLElement, private uri: URI, private target: ConfigurationTarget, + constructor(parent: HTMLElement, private _uri: URI, private _configuartionTarget: ConfigurationTarget, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IPreferencesService private preferencesService: IPreferencesService, @IContextMenuService private contextMenuService: IContextMenuService, @@ -285,15 +319,19 @@ export class SettingsTargetsWidget extends Widget { })); } - public setTarget(uri: URI, target: ConfigurationTarget): void { - this.uri = uri; - this.target = target; + get configurationTarget(): ConfigurationTarget { + return this._configuartionTarget; + } + + public updateTargets(uri: URI, configuartionTarget: ConfigurationTarget): void { + this._uri = uri; + this._configuartionTarget = configuartionTarget; this.updateLabel(); } private create(parent: HTMLElement): void { this.settingsTargetsContainer = DOM.append(parent, DOM.$('.settings-targets-widget')); - this.settingsTargetsContainer.style.width = this.workspaceContextService.hasMultiFolderWorkspace() ? '200px' : '150px'; + this.settingsTargetsContainer.style.width = this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? '200px' : '150px'; const targetElement = DOM.append(this.settingsTargetsContainer, DOM.$('.settings-target')); this.targetLabel = DOM.append(targetElement, DOM.$('.settings-target-label')); @@ -308,8 +346,8 @@ export class SettingsTargetsWidget extends Widget { } private updateLabel(): void { - this.targetLabel.textContent = getSettingsTargetName(this.target, this.uri, this.workspaceContextService); - const details = ConfigurationTarget.FOLDER === this.target ? localize('folderSettingsDetails', "Folder Settings") : ''; + this.targetLabel.textContent = getSettingsTargetName(this._configuartionTarget, this._uri, this.workspaceContextService); + const details = ConfigurationTarget.WORKSPACE_FOLDER === this._configuartionTarget ? localize('folderSettingsDetails', "Folder Settings") : ''; this.targetDetails.textContent = details; DOM.toggleClass(this.targetDetails, 'empty', !details); } @@ -332,31 +370,32 @@ export class SettingsTargetsWidget extends Widget { actions.push({ id: 'userSettingsTarget', label: getSettingsTargetName(ConfigurationTarget.USER, userSettingsResource, this.workspaceContextService), - checked: this.uri.fsPath === userSettingsResource.fsPath, + checked: this._uri.toString() === userSettingsResource.toString(), enabled: true, run: () => this.onTargetClicked(userSettingsResource) }); - if (this.workspaceContextService.hasWorkspace()) { + if (this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource; actions.push({ id: 'workspaceSettingsTarget', label: getSettingsTargetName(ConfigurationTarget.WORKSPACE, workspaceSettingsResource, this.workspaceContextService), - checked: this.uri.fsPath === workspaceSettingsResource.fsPath, + checked: this._uri.toString() === workspaceSettingsResource.toString(), enabled: true, run: () => this.onTargetClicked(workspaceSettingsResource) }); } - if (this.workspaceContextService.hasMultiFolderWorkspace()) { + const workspaceFolders = this.workspaceContextService.getWorkspace().folders; + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && workspaceFolders.length > 0) { actions.push(new Separator()); - actions.push(...this.workspaceContextService.getWorkspace().roots.map((root, index) => { + actions.push(...workspaceFolders.map((folder, index) => { return { id: 'folderSettingsTarget' + index, - label: getSettingsTargetName(ConfigurationTarget.FOLDER, root, this.workspaceContextService), - checked: this.uri.fsPath === root.fsPath, + label: getSettingsTargetName(ConfigurationTarget.WORKSPACE_FOLDER, folder.uri, this.workspaceContextService), + checked: this._uri.toString() === folder.uri.toString(), enabled: true, - run: () => this.onTargetClicked(root) + run: () => this.onTargetClicked(folder.uri) }; })); } @@ -365,7 +404,7 @@ export class SettingsTargetsWidget extends Widget { } private onTargetClicked(target: URI): void { - if (this.uri.fsPath === target.fsPath) { + if (this._uri.toString() === target.toString()) { return; } this._onDidTargetChange.fire(target); @@ -394,18 +433,18 @@ export class SearchWidget extends Widget { private countElement: HTMLElement; private searchContainer: HTMLElement; private inputBox: InputBox; + private fuzzyToggle: Checkbox; + private controlsDiv: HTMLElement; private _onDidChange: Emitter = this._register(new Emitter()); public readonly onDidChange: Event = this._onDidChange.event; - private _onNavigate: Emitter = this._register(new Emitter()); - public readonly onNavigate: Event = this._onNavigate.event; - private _onFocus: Emitter = this._register(new Emitter()); public readonly onFocus: Event = this._onFocus.event; constructor(parent: HTMLElement, protected options: SearchOptions, @IContextViewService private contextViewService: IContextViewService, + // @ts-ignore unused injected service @IContextMenuService private contextMenuService: IContextMenuService, @IInstantiationService protected instantiationService: IInstantiationService, @IThemeService private themeService: IThemeService @@ -414,10 +453,31 @@ export class SearchWidget extends Widget { this.create(parent); } + public get fuzzyEnabled(): boolean { + return this.fuzzyToggle.checked && this.fuzzyToggle.enabled; + } + + public set fuzzyEnabled(value: boolean) { + this.fuzzyToggle.checked = value; + } + private create(parent: HTMLElement) { this.domNode = DOM.append(parent, DOM.$('div.settings-header-widget')); this.createSearchContainer(DOM.append(this.domNode, DOM.$('div.settings-search-container'))); - this.countElement = DOM.append(this.domNode, DOM.$('.settings-count-widget')); + this.controlsDiv = DOM.append(this.domNode, DOM.$('div.settings-search-controls')); + this.fuzzyToggle = this._register(new Checkbox({ + actionClassName: 'prefs-fuzzy-search-toggle', + isChecked: false, + onChange: () => { + this.inputBox.focus(); + this._onDidChange.fire(); + }, + title: localize('enableFuzzySearch', 'Enable experimental fuzzy search') + })); + DOM.append(this.controlsDiv, this.fuzzyToggle.domNode); + this._register(attachCheckboxStyler(this.fuzzyToggle, this.themeService)); + + this.countElement = DOM.append(this.controlsDiv, DOM.$('.settings-count-widget')); this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder }, colors => { const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; @@ -446,7 +506,6 @@ export class SearchWidget extends Widget { const searchInput = DOM.append(this.searchContainer, DOM.$('div.settings-search-input')); this.inputBox = this._register(this.createInputBox(searchInput)); this._register(this.inputBox.onDidChange(value => this._onDidChange.fire(value))); - this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown(e)); } protected createInputBox(parent: HTMLElement): InputBox { @@ -460,10 +519,20 @@ export class SearchWidget extends Widget { this.countElement.textContent = message; this.inputBox.inputElement.setAttribute('aria-label', message); DOM.toggleClass(this.countElement, 'no-results', count === 0); - this.inputBox.inputElement.style.paddingRight = DOM.getTotalWidth(this.countElement) + 20 + 'px'; + this.inputBox.inputElement.style.paddingRight = this.getControlsWidth() + 'px'; this.styleCountElementForeground(); } + public setFuzzyToggleVisible(visible: boolean): void { + if (visible) { + this.fuzzyToggle.domNode.classList.remove('hidden'); + this.fuzzyToggle.enable(); + } else { + this.fuzzyToggle.domNode.classList.add('hidden'); + this.fuzzyToggle.disable(); + } + } + private styleCountElementForeground() { const colorId = DOM.hasClass(this.countElement, 'no-results') ? errorForeground : badgeForeground; const color = this.themeService.getTheme().getColor(colorId); @@ -476,10 +545,14 @@ export class SearchWidget extends Widget { this.inputBox.inputElement.style.paddingRight = '0px'; } else { DOM.removeClass(this.countElement, 'hide'); - this.inputBox.inputElement.style.paddingRight = DOM.getTotalWidth(this.countElement) + 20 + 'px'; + this.inputBox.inputElement.style.paddingRight = this.getControlsWidth() + 'px'; } } + private getControlsWidth(): number { + return DOM.getTotalWidth(this.countElement) + DOM.getTotalWidth(this.fuzzyToggle.domNode) + 20; + } + public focus() { this.inputBox.focus(); if (this.getValue()) { @@ -503,24 +576,6 @@ export class SearchWidget extends Widget { return this.inputBox.value = value; } - private _onKeyDown(keyboardEvent: IKeyboardEvent): void { - let handled = false; - switch (keyboardEvent.keyCode) { - case KeyCode.Enter: - this._onNavigate.fire(keyboardEvent.shiftKey); - handled = true; - break; - case KeyCode.Escape: - this.clear(); - handled = true; - break; - } - if (handled) { - keyboardEvent.preventDefault(); - keyboardEvent.stopPropagation(); - } - } - public dispose(): void { if (this.options.focusKey) { this.options.focusKey.set(false); @@ -539,6 +594,7 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget { constructor( private editor: ICodeEditor, private label: string, + // @ts-ignore unused property private keyBindingAction: string, @IKeybindingService keybindingService: IKeybindingService, @IThemeService private themeService: IThemeService @@ -602,7 +658,8 @@ export class EditPreferenceWidget extends Disposable { super(); this._editPreferenceDecoration = []; this._register(this.editor.onMouseDown((e: IEditorMouseEvent) => { - if (e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || /* after last line */ e.target.detail || !this.isVisible()) { + const data = e.target.detail as IMarginData; + if (e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.isVisible()) { return; } this._onClick.fire(e); diff --git a/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts b/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts index e83490c05ff..65e93c3b212 100644 --- a/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts +++ b/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts @@ -13,8 +13,8 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ResolvedKeybinding, ResolvedKeybindingPart } from 'vs/base/common/keyCodes'; import { AriaLabelProvider, UserSettingsLabelProvider, UILabelProvider, ModifierLabels as ModLabels } from 'vs/base/common/keybindingLabels'; import { CommonEditorRegistry, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { MenuRegistry, ILocalizedString, SyncActionDescriptor, ICommandAction } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { MenuRegistry, ILocalizedString, ICommandAction } from 'vs/platform/actions/common/actions'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { EditorModel } from 'vs/workbench/common/editor'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -77,6 +77,7 @@ export class KeybindingsEditorModel extends EditorModel { private modifierLabels: ModifierLabels; constructor( + // @ts-ignore unused property private os: OperatingSystem, @IKeybindingService private keybindingsService: IKeybindingService, @IExtensionService private extensionService: IExtensionService @@ -200,26 +201,21 @@ export class KeybindingsEditorModel extends EditorModel { } private static toKeybindingEntry(command: string, keybindingItem: ResolvedKeybindingItem, workbenchActionsRegistry: IWorkbenchActionRegistry, editorActions: {}): IKeybindingItem { - const workbenchAction = workbenchActionsRegistry.getWorkbenchAction(command); const menuCommand = MenuRegistry.getCommand(command); const editorAction: EditorAction = editorActions[command]; return { keybinding: keybindingItem.resolvedKeybinding, keybindingItem, command, - commandLabel: KeybindingsEditorModel.getCommandLabel(workbenchAction, menuCommand, editorAction), - commandDefaultLabel: KeybindingsEditorModel.getCommandDefaultLabel(workbenchAction, menuCommand, workbenchActionsRegistry), + commandLabel: KeybindingsEditorModel.getCommandLabel(menuCommand, editorAction), + commandDefaultLabel: KeybindingsEditorModel.getCommandDefaultLabel(menuCommand, workbenchActionsRegistry), when: keybindingItem.when ? keybindingItem.when.serialize() : '', source: keybindingItem.isDefault ? localize('default', "Default") : localize('user', "User") }; } - private static getCommandDefaultLabel(workbenchAction: SyncActionDescriptor, menuCommand: ICommandAction, workbenchActionsRegistry: IWorkbenchActionRegistry): string { + private static getCommandDefaultLabel(menuCommand: ICommandAction, workbenchActionsRegistry: IWorkbenchActionRegistry): string { if (language !== LANGUAGE_DEFAULT) { - if (workbenchAction) { - return workbenchActionsRegistry.getAlias(workbenchAction.id); - } - if (menuCommand && menuCommand.title && (menuCommand.title).original) { return (menuCommand.title).original; } @@ -227,11 +223,7 @@ export class KeybindingsEditorModel extends EditorModel { return null; } - private static getCommandLabel(workbenchAction: SyncActionDescriptor, menuCommand: ICommandAction, editorAction: EditorAction): string { - if (workbenchAction) { - return workbenchAction.label; - } - + private static getCommandLabel(menuCommand: ICommandAction, editorAction: EditorAction): string { if (menuCommand) { return typeof menuCommand.title === 'string' ? menuCommand.title : menuCommand.title.value; } @@ -253,6 +245,7 @@ class KeybindingItemMatches { public readonly whenMatches: IMatch[] = null; public readonly keybindingMatches: KeybindingMatches = null; + // @ts-ignore unused property constructor(private modifierLabels: ModifierLabels, keybindingItem: IKeybindingItem, private searchValue: string, private words: string[], private keybindingWords: string[], private completeMatch: boolean) { this.commandIdMatches = this.matches(searchValue, keybindingItem.command, or(matchesWords, matchesCamelCase), words); this.commandLabelMatches = keybindingItem.commandLabel ? this.matches(searchValue, keybindingItem.commandLabel, (word, wordToMatchAgainst) => matchesWords(word, keybindingItem.commandLabel, true), words) : null; @@ -560,4 +553,4 @@ class KeybindingItemMatches { } return false; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index 7037e86c7e7..1490704ca4a 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -4,16 +4,29 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import * as paths from 'vs/base/common/paths'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IEditor } from 'vs/platform/editor/common/editor'; +import { IEditor, Position, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IModel } from 'vs/editor/common/editorCommon'; import { IKeybindingItemEntry } from 'vs/workbench/parts/preferences/common/keybindingsEditorModel'; import { IRange } from 'vs/editor/common/core/range'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { join } from 'vs/base/common/paths'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; + +export interface IWorkbenchSettingsConfiguration { + workbench: { + settings: { + openDefaultSettings: boolean; + experimentalFuzzySearchEndpoint: string; + experimentalFuzzySearchKey: string; + experimentalFuzzySearchBoost: number; + experimentalFuzzySearchAutoIngestFeedback: boolean; + } + }; +} export interface ISettingsGroup { id: string; @@ -42,22 +55,39 @@ export interface ISetting { } export interface IFilterResult { + query: string; filteredGroups: ISettingsGroup[]; allGroups: ISettingsGroup[]; matches: IRange[]; + fuzzySearchAvailable?: boolean; + metadata?: IFilterMetadata; +} + +export interface IScoredResults { + [key: string]: number; +} + +export interface IFilterMetadata { + remoteUrl: string; + timestamp: number; + duration: number; + scoredResults: IScoredResults; } export interface IPreferencesEditorModel { uri: URI; - content: string; getPreference(key: string): T; dispose(): void; } +export type IGroupFilter = (group: ISettingsGroup) => boolean; +export type ISettingFilter = (setting: ISetting) => IRange[]; + export interface ISettingsEditorModel extends IPreferencesEditorModel { settingsGroups: ISettingsGroup[]; groupsTerms: string[]; - filterSettings(filter: string): IFilterResult; + filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult; + findValueMatches(filter: string, setting: ISetting): IRange[]; } export interface IKeybindingsEditorModel extends IPreferencesEditorModel { @@ -68,18 +98,16 @@ export const IPreferencesService = createDecorator('prefere export interface IPreferencesService { _serviceBrand: any; - defaultSettingsResource: URI; - defaultResourceSettingsResource: URI; userSettingsResource: URI; workspaceSettingsResource: URI; getFolderSettingsResource(resource: URI): URI; - resolveContent(uri: URI): TPromise; + resolveModel(uri: URI): TPromise; createPreferencesEditorModel(uri: URI): TPromise>; - openGlobalSettings(): TPromise; - openWorkspaceSettings(): TPromise; - openFolderSettings(folder: URI): TPromise; + openGlobalSettings(options?: IEditorOptions, position?: Position): TPromise; + openWorkspaceSettings(options?: IEditorOptions, position?: Position): TPromise; + openFolderSettings(folder: URI, options?: IEditorOptions, position?: Position): TPromise; switchSettings(target: ConfigurationTarget, resource: URI): TPromise; openGlobalKeybindingSettings(textual: boolean): TPromise; @@ -92,6 +120,7 @@ export interface IKeybindingsEditor extends IEditor { activeKeybindingEntry: IKeybindingItemEntry; search(filter: string): void; + clearSearchResults(): void; focusKeybindings(): void; defineKeybinding(keybindingEntry: IKeybindingItemEntry): TPromise; removeKeybinding(keybindingEntry: IKeybindingItemEntry): TPromise; @@ -106,10 +135,11 @@ export function getSettingsTargetName(target: ConfigurationTarget, resource: URI return localize('userSettingsTarget', "User Settings"); case ConfigurationTarget.WORKSPACE: return localize('workspaceSettingsTarget', "Workspace Settings"); - case ConfigurationTarget.FOLDER: - const root = workspaceContextService.getRoot(resource); - return root ? paths.basename(root.fsPath) : ''; + case ConfigurationTarget.WORKSPACE_FOLDER: + const folder = workspaceContextService.getWorkspaceFolder(resource); + return folder ? folder.name : ''; } + return ''; } export const CONTEXT_SETTINGS_EDITOR = new RawContextKey('inSettingsEditor', false); @@ -119,11 +149,18 @@ export const CONTEXT_KEYBINDINGS_SEARCH_FOCUS = new RawContextKey('inKe export const CONTEXT_KEYBINDING_FOCUS = new RawContextKey('keybindingFocus', false); export const SETTINGS_EDITOR_COMMAND_SEARCH = 'settings.action.search'; +export const SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'settings.action.clearSearchResults'; +export const SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING = 'settings.action.focusNextSetting'; +export const SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING = 'settings.action.focusPreviousSetting'; export const SETTINGS_EDITOR_COMMAND_FOCUS_FILE = 'settings.action.focusSettingsFile'; export const KEYBINDINGS_EDITOR_COMMAND_SEARCH = 'keybindings.editor.searchKeybindings'; +export const KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'keybindings.editor.clearSearchResults'; export const KEYBINDINGS_EDITOR_COMMAND_DEFINE = 'keybindings.editor.defineKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_REMOVE = 'keybindings.editor.removeKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_RESET = 'keybindings.editor.resetKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_COPY = 'keybindings.editor.copyKeybindingEntry'; export const KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS = 'keybindings.editor.showConflicts'; -export const KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS = 'keybindings.editor.focusKeybindings'; \ No newline at end of file +export const KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS = 'keybindings.editor.focusKeybindings'; + +export const FOLDER_SETTINGS_PATH = join('.vscode', 'settings.json'); +export const DEFAULT_SETTINGS_EDITOR_SETTING = 'workbench.settings.openDefaultSettings'; \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts b/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts deleted file mode 100644 index 4b58705c22b..00000000000 --- a/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts +++ /dev/null @@ -1,62 +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 { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import URI from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IModel } from 'vs/editor/common/editorCommon'; -import JSONContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; - -const schemaRegistry = Registry.as(JSONContributionRegistry.Extensions.JSONContribution); - -export class PreferencesContentProvider implements IWorkbenchContribution { - - constructor( - @IModelService private modelService: IModelService, - @ITextModelService private textModelResolverService: ITextModelService, - @IPreferencesService private preferencesService: IPreferencesService, - @IModeService private modeService: IModeService - ) { - this.start(); - } - - public getId(): string { - return 'vs.contentprovider'; - } - - private start(): void { - this.textModelResolverService.registerTextModelContentProvider('vscode', { - provideTextContent: (uri: URI): TPromise => { - if (uri.scheme !== 'vscode') { - return null; - } - if (uri.authority === 'schemas') { - let schemas = schemaRegistry.getSchemaContributions().schemas; - let schema = schemas[uri.toString()]; - if (schema) { - let modelContent = JSON.stringify(schema); - let mode = this.modeService.getOrCreateMode('json'); - return TPromise.as(this.modelService.createModel(modelContent, mode, uri)); - } - } - return this.preferencesService.resolveContent(uri) - .then(content => { - if (content !== null && content !== void 0) { - let mode = this.modeService.getOrCreateMode('json'); - const model = this.modelService.createModel(content, mode, uri); - return TPromise.as(model); - } - return null; - }); - } - }); - } -} diff --git a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts new file mode 100644 index 00000000000..b9021dc6437 --- /dev/null +++ b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts @@ -0,0 +1,153 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IModel } from 'vs/editor/common/editorCommon'; +import JSONContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IPreferencesService, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { endsWith } from 'vs/base/common/strings'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEditorOpeningEvent } from 'vs/workbench/common/editor'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +const schemaRegistry = Registry.as(JSONContributionRegistry.Extensions.JSONContribution); + +export class PreferencesContribution implements IWorkbenchContribution { + private editorOpeningListener: IDisposable; + private settingsListener: IDisposable; + + constructor( + @IModelService private modelService: IModelService, + @ITextModelService private textModelResolverService: ITextModelService, + @IPreferencesService private preferencesService: IPreferencesService, + @IModeService private modeService: IModeService, + @IEditorGroupService private editorGroupService: IEditorGroupService, + @IEnvironmentService private environmentService: IEnvironmentService, + @IWorkspaceContextService private workspaceService: IWorkspaceContextService, + @IConfigurationService private configurationService: IConfigurationService + ) { + this.settingsListener = this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(DEFAULT_SETTINGS_EDITOR_SETTING)) { + this.handleSettingsEditorOverride(); + } + }); + this.handleSettingsEditorOverride(); + + this.start(); + } + + private handleSettingsEditorOverride(): void { + + // dispose any old listener we had + this.editorOpeningListener = dispose(this.editorOpeningListener); + + // install editor opening listener unless user has disabled this + if (!!this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING)) { + this.editorOpeningListener = this.editorGroupService.onEditorOpening(e => this.onEditorOpening(e)); + } + } + + private onEditorOpening(event: IEditorOpeningEvent): void { + const resource = event.input.getResource(); + if ( + !resource || resource.scheme !== 'file' || // require a file path opening + !endsWith(resource.fsPath, 'settings.json') || // file must end in settings.json + !this.configurationService.getValue(DEFAULT_SETTINGS_EDITOR_SETTING) // user has not disabled default settings editor + ) { + return; + } + + // If the file resource was already opened before in the group, do not prevent + // the opening of that resource. Otherwise we would have the same settings + // opened twice (https://github.com/Microsoft/vscode/issues/36447) + const stacks = this.editorGroupService.getStacksModel(); + const group = stacks.groupAt(event.position); + if (group && group.contains(event.input)) { + return; + } + + // Global User Settings File + if (resource.fsPath === this.environmentService.appSettingsPath) { + return event.prevent(() => this.preferencesService.openGlobalSettings(event.options, event.position)); + } + + // Single Folder Workspace Settings File + const state = this.workspaceService.getWorkbenchState(); + if (state === WorkbenchState.FOLDER) { + const folders = this.workspaceService.getWorkspace().folders; + if (resource.fsPath === folders[0].toResource(FOLDER_SETTINGS_PATH).fsPath) { + return event.prevent(() => this.preferencesService.openWorkspaceSettings(event.options, event.position)); + } + } + + // Multi Folder Workspace Settings File + else if (state === WorkbenchState.WORKSPACE) { + const folders = this.workspaceService.getWorkspace().folders; + for (let i = 0; i < folders.length; i++) { + if (resource.fsPath === folders[i].toResource(FOLDER_SETTINGS_PATH).fsPath) { + return event.prevent(() => this.preferencesService.openFolderSettings(folders[i].uri, event.options, event.position)); + } + } + } + } + + public getId(): string { + return 'vs.contentprovider'; + } + + private start(): void { + + this.textModelResolverService.registerTextModelContentProvider('vscode', { + provideTextContent: (uri: URI): TPromise => { + if (uri.scheme !== 'vscode') { + return null; + } + if (uri.authority === 'schemas') { + const schemaModel = this.getSchemaModel(uri); + if (schemaModel) { + return TPromise.as(schemaModel); + } + } + return this.preferencesService.resolveModel(uri); + } + }); + } + + private getSchemaModel(uri: URI): IModel { + let schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; + if (schema) { + const modelContent = JSON.stringify(schema); + const mode = this.modeService.getOrCreateMode('json'); + const model = this.modelService.createModel(modelContent, mode, uri); + + let disposables = []; + disposables.push(schemaRegistry.onDidChangeSchema(schemaUri => { + if (schemaUri === uri.toString()) { + schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; + model.setValue(JSON.stringify(schema)); + } + })); + disposables.push(model.onWillDispose(() => dispose(disposables))); + + return model; + } + return null; + } + + public dispose(): void { + this.editorOpeningListener = dispose(this.editorOpeningListener); + this.settingsListener = dispose(this.settingsListener); + } +} diff --git a/src/vs/workbench/parts/preferences/common/preferencesModels.ts b/src/vs/workbench/parts/preferences/common/preferencesModels.ts index f17231a589b..f68e560cf0f 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesModels.ts @@ -4,150 +4,25 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as strings from 'vs/base/common/strings'; import { assign } from 'vs/base/common/objects'; -import { distinct } from 'vs/base/common/arrays'; +import { tail } from 'vs/base/common/arrays'; import URI from 'vs/base/common/uri'; import { IReference } from 'vs/base/common/lifecycle'; import Event from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; import { visit, JSONVisitor } from 'vs/base/common/json'; import { IModel } from 'vs/editor/common/editorCommon'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { EditorModel } from 'vs/workbench/common/editor'; import { IConfigurationNode, IConfigurationRegistry, Extensions, OVERRIDE_PROPERTY_PATTERN, IConfigurationPropertySchema, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection } from 'vs/workbench/parts/preferences/common/preferences'; +import { ISettingsEditorModel, IKeybindingsEditorModel, ISettingsGroup, ISetting, IFilterResult, ISettingsSection, IGroupFilter, ISettingFilter } from 'vs/workbench/parts/preferences/common/preferences'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IRange } from 'vs/editor/common/core/range'; +import { IRange, Range } from 'vs/editor/common/core/range'; import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles'; import { TPromise } from 'vs/base/common/winjs.base'; import { Queue } from 'vs/base/common/async'; import { IFileService } from 'vs/platform/files/common/files'; - -class SettingMatches { - - private readonly descriptionMatchingWords: Map = new Map(); - private readonly keyMatchingWords: Map = new Map(); - private readonly valueMatchingWords: Map = new Map(); - - public readonly matches: IRange[]; - - constructor(searchString: string, setting: ISetting, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { - this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`); - } - - private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] { - const result = this._doFindMatchesInSetting(searchString, setting); - if (setting.overrides && setting.overrides.length) { - for (const subSetting of setting.overrides) { - const subSettingMatches = new SettingMatches(searchString, subSetting, this.valuesMatcher); - let words = searchString.split(' '); - const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]); - result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges); - result.push(...subSettingMatches.matches); - } - } - return result; - } - - private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] { - const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as(Extensions.Configuration).getConfigurationProperties(); - const schema: IJSONSchema = registry[setting.key]; - - let words = searchString.split(' '); - const settingKeyAsWords: string = setting.key.split('.').join(' '); - - for (const word of words) { - for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { - const descriptionMatches = matchesWords(word, setting.description[lineIndex], true); - if (descriptionMatches) { - this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex))); - } - } - - const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords); - if (keyMatches) { - this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match))); - } - - const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null; - if (valueMatches) { - this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match))); - } else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) { - this.valueMatchingWords.set(word, []); - } - } - - const descriptionRanges: IRange[] = []; - for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { - const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || []; - descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex))); - } - if (descriptionRanges.length === 0) { - descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords])); - } - - const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key); - const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]); - - let valueRanges: IRange[] = []; - if (setting.value && typeof setting.value === 'string') { - const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value); - valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]); - } else { - valueRanges = this.valuesMatcher(searchString, setting); - } - - return [...descriptionRanges, ...keyRanges, ...valueRanges]; - } - - private getRangesForWords(words: string[], from: Map, others: Map[]): IRange[] { - const result: IRange[] = []; - for (const word of words) { - const ranges = from.get(word); - if (ranges) { - result.push(...ranges); - } else if (others.every(o => !o.has(word))) { - return []; - } - } - return result; - } - - private toKeyRange(setting: ISetting, match: IMatch): IRange { - return { - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn + match.start, - endLineNumber: setting.keyRange.startLineNumber, - endColumn: setting.keyRange.startColumn + match.end - }; - } - - private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange { - return { - startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber, - startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start, - endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber, - endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end - }; - } - - private toValueRange(setting: ISetting, match: IMatch): IRange { - return { - startLineNumber: setting.valueRange.startLineNumber, - startColumn: setting.valueRange.startColumn + match.start + 1, - endLineNumber: setting.valueRange.startLineNumber, - endColumn: setting.valueRange.startColumn + match.end + 1 - }; - } -} - +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export abstract class AbstractSettingsModel extends EditorModel { @@ -155,12 +30,15 @@ export abstract class AbstractSettingsModel extends EditorModel { return this.settingsGroups.map(group => '@' + group.id); } - protected doFilterSettings(filter: string, allGroups: ISettingsGroup[]): IFilterResult { + protected doFilterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter): IFilterResult { + const allGroups = this.settingsGroups; + if (!filter) { return { filteredGroups: allGroups, allGroups, - matches: [] + matches: [], + query: filter }; } @@ -169,24 +47,27 @@ export abstract class AbstractSettingsModel extends EditorModel { return { filteredGroups: [group], allGroups, - matches: [] + matches: [], + query: filter }; } const matches: IRange[] = []; const filteredGroups: ISettingsGroup[] = []; - const regex = strings.createRegExp(filter, false, { global: true }); for (const group of allGroups) { - const groupMatched = regex.test(group.title); + const groupMatched = groupFilter(group); const sections: ISettingsSection[] = []; for (const section of group.sections) { const settings: ISetting[] = []; for (const setting of section.settings) { - const settingMatches = new SettingMatches(filter, setting, (filter, setting) => this.findValueMatches(filter, setting)).matches; - if (groupMatched || settingMatches.length > 0) { + const settingMatches = settingFilter(setting); + if (groupMatched || settingMatches && settingMatches.length) { settings.push(setting); } - matches.push(...settingMatches); + + if (settingMatches) { + matches.push(...settingMatches); + } } if (settings.length) { sections.push({ @@ -206,7 +87,7 @@ export abstract class AbstractSettingsModel extends EditorModel { }); } } - return { filteredGroups, matches, allGroups }; + return { filteredGroups, matches, allGroups, query: filter }; } private filterByGroupTerm(filter: string): ISettingsGroup { @@ -232,7 +113,7 @@ export abstract class AbstractSettingsModel extends EditorModel { public abstract settingsGroups: ISettingsGroup[]; - protected abstract findValueMatches(filter: string, setting: ISetting): IRange[]; + public abstract findValueMatches(filter: string, setting: ISetting): IRange[]; } export class SettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { @@ -245,9 +126,7 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti super(); this.settingsModel = reference.object.textEditorModel; this._register(this.onDispose(() => reference.dispose())); - this._register(this.settingsModel.onDidChangeContent(() => { - this._settingsGroups = null; - })); + this._register(this.settingsModel.onDidChangeContent(() => this._settingsGroups = null)); this.queue = new Queue(); } @@ -270,188 +149,216 @@ export class SettingsEditorModel extends AbstractSettingsModel implements ISetti return this.settingsModel.getValue(); } - public filterSettings(filter: string): IFilterResult { - return this.doFilterSettings(filter, this.settingsGroups); + public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter): IFilterResult { + return this.doFilterSettings(filter, groupFilter, settingFilter); + } + + public findValueMatches(filter: string, setting: ISetting): IRange[] { + return this.settingsModel.findMatches(filter, setting.valueRange, false, false, null, false).map(match => match.range); } public save(): TPromise { return this.queue.queue(() => this.doSave()); } + protected isSettingsProperty(property: string, previousParents: string[]): boolean { + return previousParents.length === 0; // Settings is root + } + protected doSave(): TPromise { return this.textFileService.save(this.uri); } - protected findValueMatches(filter: string, setting: ISetting): IRange[] { - return this.settingsModel.findMatches(filter, setting.valueRange, false, false, null, false).map(match => match.range); + protected parse(): void { + this._settingsGroups = parse(this.settingsModel, (property: string, previousParents: string[]): boolean => this.isSettingsProperty(property, previousParents)); } +} - private parse() { - const model = this.settingsModel; - const settings: ISetting[] = []; - let overrideSetting: ISetting = null; +function parse(model: IModel, isSettingsProperty: (currentProperty: string, previousParents: string[]) => boolean): ISettingsGroup[] { + const settings: ISetting[] = []; + let overrideSetting: ISetting = null; - let currentProperty: string = null; - let currentParent: any = []; - let previousParents: any[] = []; - let range = { - startLineNumber: 0, - startColumn: 0, - endLineNumber: 0, - endColumn: 0 - }; + let currentProperty: string = null; + let currentParent: any = []; + let previousParents: any[] = []; + let settingsPropertyIndex: number = -1; + let range = { + startLineNumber: 0, + startColumn: 0, + endLineNumber: 0, + endColumn: 0 + }; - function onValue(value: any, offset: number, length: number) { - if (Array.isArray(currentParent)) { - (currentParent).push(value); - } else if (currentProperty) { - currentParent[currentProperty] = value; + function onValue(value: any, offset: number, length: number) { + if (Array.isArray(currentParent)) { + (currentParent).push(value); + } else if (currentProperty) { + currentParent[currentProperty] = value; + } + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // settings value started + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + if (setting) { + let valueStartPosition = model.getPositionAt(offset); + let valueEndPosition = model.getPositionAt(offset + length); + setting.value = value; + setting.valueRange = { + startLineNumber: valueStartPosition.lineNumber, + startColumn: valueStartPosition.column, + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }; + setting.range = assign(setting.range, { + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }); } - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // settings value started - const setting = previousParents.length === 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + } + } + let visitor: JSONVisitor = { + onObjectBegin: (offset: number, length: number) => { + if (isSettingsProperty(currentProperty, previousParents)) { + // Settings started + settingsPropertyIndex = previousParents.length; + let position = model.getPositionAt(offset); + range.startLineNumber = position.lineNumber; + range.startColumn = position.column; + } + let object = {}; + onValue(object, offset, length); + currentParent = object; + currentProperty = null; + previousParents.push(currentParent); + }, + onObjectProperty: (name: string, offset: number, length: number) => { + currentProperty = name; + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // setting started + let settingStartPosition = model.getPositionAt(offset); + const setting: ISetting = { + description: [], + key: name, + keyRange: { + startLineNumber: settingStartPosition.lineNumber, + startColumn: settingStartPosition.column + 1, + endLineNumber: settingStartPosition.lineNumber, + endColumn: settingStartPosition.column + length + }, + range: { + startLineNumber: settingStartPosition.lineNumber, + startColumn: settingStartPosition.column, + endLineNumber: 0, + endColumn: 0 + }, + value: null, + valueRange: null, + descriptionRanges: null, + overrides: [], + overrideOf: overrideSetting + }; + if (previousParents.length === settingsPropertyIndex + 1) { + settings.push(setting); + if (OVERRIDE_PROPERTY_PATTERN.test(name)) { + overrideSetting = setting; + } + } else { + overrideSetting.overrides.push(setting); + } + } + }, + onObjectEnd: (offset: number, length: number) => { + currentParent = previousParents.pop(); + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // setting ended + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; if (setting) { - let valueStartPosition = model.getPositionAt(offset); let valueEndPosition = model.getPositionAt(offset + length); - setting.value = value; - setting.valueRange = { - startLineNumber: valueStartPosition.lineNumber, - startColumn: valueStartPosition.column, + setting.valueRange = assign(setting.valueRange, { endLineNumber: valueEndPosition.lineNumber, endColumn: valueEndPosition.column - }; + }); + setting.range = assign(setting.range, { + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }); + } + + if (previousParents.length === settingsPropertyIndex + 1) { + overrideSetting = null; + } + } + if (previousParents.length === settingsPropertyIndex) { + // settings ended + let position = model.getPositionAt(offset); + range.endLineNumber = position.lineNumber; + range.endColumn = position.column; + } + }, + onArrayBegin: (offset: number, length: number) => { + let array: any[] = []; + onValue(array, offset, length); + previousParents.push(currentParent); + currentParent = array; + currentProperty = null; + }, + onArrayEnd: (offset: number, length: number) => { + currentParent = previousParents.pop(); + if (previousParents.length === settingsPropertyIndex + 1 || (previousParents.length === settingsPropertyIndex + 2 && overrideSetting !== null)) { + // setting value ended + const setting = previousParents.length === settingsPropertyIndex + 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; + if (setting) { + let valueEndPosition = model.getPositionAt(offset + length); + setting.valueRange = assign(setting.valueRange, { + endLineNumber: valueEndPosition.lineNumber, + endColumn: valueEndPosition.column + }); setting.range = assign(setting.range, { endLineNumber: valueEndPosition.lineNumber, endColumn: valueEndPosition.column }); } } - } - let visitor: JSONVisitor = { - onObjectBegin: (offset: number, length: number) => { - if (previousParents.length === 0) { - // Settings started - let position = model.getPositionAt(offset); - range.startLineNumber = position.lineNumber; - range.startColumn = position.column; - } - let object = {}; - onValue(object, offset, length); - currentParent = object; - currentProperty = null; - previousParents.push(currentParent); - }, - onObjectProperty: (name: string, offset: number, length: number) => { - currentProperty = name; - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // setting started - let settingStartPosition = model.getPositionAt(offset); - const setting: ISetting = { - description: [], - key: name, - keyRange: { - startLineNumber: settingStartPosition.lineNumber, - startColumn: settingStartPosition.column + 1, - endLineNumber: settingStartPosition.lineNumber, - endColumn: settingStartPosition.column + length - }, - range: { - startLineNumber: settingStartPosition.lineNumber, - startColumn: settingStartPosition.column, - endLineNumber: 0, - endColumn: 0 - }, - value: null, - valueRange: null, - descriptionRanges: null, - overrides: [], - overrideOf: overrideSetting - }; - if (previousParents.length === 1) { - settings.push(setting); - if (OVERRIDE_PROPERTY_PATTERN.test(name)) { - overrideSetting = setting; - } - } else { - overrideSetting.overrides.push(setting); - } - } - }, - onObjectEnd: (offset: number, length: number) => { - currentParent = previousParents.pop(); - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // setting ended - const setting = previousParents.length === 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; - if (setting) { - let valueEndPosition = model.getPositionAt(offset + length); - setting.valueRange = assign(setting.valueRange, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - setting.range = assign(setting.range, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - } - - if (previousParents.length === 1) { - overrideSetting = null; - } - } - if (previousParents.length === 0) { - // settings ended - let position = model.getPositionAt(offset); - range.endLineNumber = position.lineNumber; - range.endColumn = position.column; - } - }, - onArrayBegin: (offset: number, length: number) => { - let array: any[] = []; - onValue(array, offset, length); - previousParents.push(currentParent); - currentParent = array; - currentProperty = null; - }, - onArrayEnd: (offset: number, length: number) => { - currentParent = previousParents.pop(); - if (previousParents.length === 1 || (previousParents.length === 2 && overrideSetting !== null)) { - // setting value ended - const setting = previousParents.length === 1 ? settings[settings.length - 1] : overrideSetting.overrides[overrideSetting.overrides.length - 1]; - if (setting) { - let valueEndPosition = model.getPositionAt(offset + length); - setting.valueRange = assign(setting.valueRange, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - setting.range = assign(setting.range, { - endLineNumber: valueEndPosition.lineNumber, - endColumn: valueEndPosition.column - }); - } - } - }, - onLiteralValue: onValue, - onError: (error) => { - const setting = settings[settings.length - 1]; - if (setting && (!setting.range || !setting.keyRange || !setting.valueRange)) { - settings.pop(); - } + }, + onLiteralValue: onValue, + onError: (error) => { + const setting = settings[settings.length - 1]; + if (setting && (!setting.range || !setting.keyRange || !setting.valueRange)) { + settings.pop(); } - }; - if (!model.isDisposed()) { - visit(model.getValue(), visitor); } - this._settingsGroups = settings.length > 0 ? [{ - sections: [ - { - settings - } - ], - title: null, - titleRange: null, - range - }] : []; + }; + if (!model.isDisposed()) { + visit(model.getValue(), visitor); } + return settings.length > 0 ? [{ + sections: [ + { + settings + } + ], + title: null, + titleRange: null, + range + }] : []; +} + +export class WorkspaceConfigurationEditorModel extends SettingsEditorModel { + + private _configurationGroups: ISettingsGroup[]; + + get configurationGroups(): ISettingsGroup[] { + return this._configurationGroups; + } + + protected parse(): void { + super.parse(); + this._configurationGroups = parse(this.settingsModel, (property: string, previousParents: string[]): boolean => previousParents.length === 0); + } + + protected isSettingsProperty(property: string, previousParents: string[]): boolean { + return property === 'settings' && previousParents.length === 1; + } + } export class WorkspaceConfigModel extends SettingsEditorModel implements ISettingsEditorModel { @@ -465,6 +372,7 @@ export class WorkspaceConfigModel extends SettingsEditorModel implements ISettin _configurationTarget: ConfigurationTarget, onDispose: Event, @IFileService private fileService: IFileService, + // @ts-ignore unused injected service @ITextModelService private textModelResolverService: ITextModelService, @ITextFileService textFileService: ITextFileService ) { @@ -592,18 +500,16 @@ export class WorkspaceConfigModel extends SettingsEditorModel implements ISettin } } -export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { +export class DefaultSettingsModel { private _allSettingsGroups: ISettingsGroup[]; private _content: string; - private _contentByLines: string[]; + private _settingsByName: Map; - constructor(private _uri: URI, private _mostCommonlyUsedSettingsKeys: string[], readonly configurationScope: ConfigurationScope) { - super(); - } - - public get uri(): URI { - return this._uri; + constructor( + private _mostCommonlyUsedSettingsKeys: string[], + readonly configurationScope: ConfigurationScope, + ) { } public get content(): string { @@ -620,46 +526,29 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements return this._allSettingsGroups; } - public get mostCommonlyUsedSettings(): ISettingsGroup { - return this.settingsGroups[0]; - } - - public filterSettings(filter: string): IFilterResult { - return this.doFilterSettings(filter, this.settingsGroups); - } - - public getPreference(key: string): ISetting { - for (const group of this.settingsGroups) { - for (const section of group.sections) { - for (const setting of section.settings) { - if (setting.key === key) { - return setting; - } - } - } - } - return null; - } - private parse() { const configurations = Registry.as(Extensions.Configuration).getConfigurations().slice(); const settingsGroups = this.removeEmptySettingsGroups(configurations.sort(this.compareConfigurationNodes).reduce((result, config, index, array) => this.parseConfig(config, result, array), [])); + this.initAllSettingsMap(settingsGroups); const mostCommonlyUsed = this.getMostCommonlyUsedSettings(settingsGroups); this._allSettingsGroups = [mostCommonlyUsed, ...settingsGroups]; this._content = this.toContent(mostCommonlyUsed, settingsGroups); } - private getMostCommonlyUsedSettings(allSettingsGroups: ISettingsGroup[]): ISettingsGroup { - const map: Map = new Map(); + private initAllSettingsMap(allSettingsGroups: ISettingsGroup[]): void { + this._settingsByName = new Map(); for (const group of allSettingsGroups) { for (const section of group.sections) { for (const setting of section.settings) { - map.set(setting.key, setting); + this._settingsByName.set(setting.key, setting); } } } + } + + private getMostCommonlyUsedSettings(allSettingsGroups: ISettingsGroup[]): ISettingsGroup { const settings = this._mostCommonlyUsedSettingsKeys.map(key => { - const setting = map.get(key); + const setting = this._settingsByName.get(key); if (setting) { return { description: setting.description, @@ -773,25 +662,181 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements } private toContent(mostCommonlyUsed: ISettingsGroup, settingsGroups: ISettingsGroup[]): string { - this._contentByLines = []; - this._contentByLines.push('['); - this.pushGroups([mostCommonlyUsed]); - this._contentByLines.push(','); - this.pushGroups(settingsGroups); - this._contentByLines.push(']'); - return this._contentByLines.join('\n'); + const builder = new SettingsContentBuilder(); + builder.pushLine('['); + builder.pushGroups([mostCommonlyUsed]); + builder.pushLine(','); + builder.pushGroups(settingsGroups); + builder.pushLine(']'); + return builder.getContent(); } - private pushGroups(settingsGroups: ISettingsGroup[]): void { +} + +export class DefaultSettingsEditorModel extends AbstractSettingsModel implements ISettingsEditorModel { + + private _model: IModel; + private _settingsByName: Map; + private _mostRelevantLineOffset: number; + + constructor( + private _uri: URI, + reference: IReference, + readonly configurationScope: ConfigurationScope, + readonly settingsGroups: ISettingsGroup[] + ) { + super(); + this._model = reference.object.textEditorModel; + this._register(this.onDispose(() => reference.dispose())); + + this.initAllSettingsMap(); + this._mostRelevantLineOffset = tail(this.settingsGroups).range.endLineNumber + 2; + } + + public get uri(): URI { + return this._uri; + } + + public filterSettings(filter: string, groupFilter: IGroupFilter, settingFilter: ISettingFilter, mostRelevantSettings?: string[]): IFilterResult { + if (mostRelevantSettings) { + const mostRelevantGroup = this.renderMostRelevantSettings(mostRelevantSettings); + + return { + allGroups: [...this.settingsGroups, mostRelevantGroup], + filteredGroups: mostRelevantGroup.sections[0].settings.length ? [mostRelevantGroup] : [], + matches: [], + query: filter + }; + } else { + // Do local search and add empty 'most relevant' group + const mostRelevantGroup = this.renderMostRelevantSettings([]); + const result = this.doFilterSettings(filter, groupFilter, settingFilter); + result.allGroups = [...result.allGroups, mostRelevantGroup]; + return result; + } + } + + private renderMostRelevantSettings(mostRelevantSettings: string[]): ISettingsGroup { + const builder = new SettingsContentBuilder(this._mostRelevantLineOffset - 1); + builder.pushLine(','); + const mostRelevantGroup = this.getMostRelevantSettings(mostRelevantSettings); + builder.pushGroups([mostRelevantGroup]); + builder.pushLine(''); + + // note: 1-indexed line numbers here + const mostRelevantContent = builder.getContent(); + const mostRelevantEndLine = this._model.getLineCount(); + this._model.applyEdits([ + { + text: mostRelevantContent, + forceMoveMarkers: false, + range: new Range(this._mostRelevantLineOffset, 1, mostRelevantEndLine, 1), + identifier: { major: 1, minor: 0 } + } + ]); + + return mostRelevantGroup; + } + + public findValueMatches(filter: string, setting: ISetting): IRange[] { + return []; + } + + public getPreference(key: string): ISetting { + for (const group of this.settingsGroups) { + for (const section of group.sections) { + for (const setting of section.settings) { + if (setting.key === key) { + return setting; + } + } + } + } + return null; + } + + private initAllSettingsMap(): void { + this._settingsByName = new Map(); + for (const group of this.settingsGroups) { + for (const section of group.sections) { + for (const setting of section.settings) { + this._settingsByName.set(setting.key, setting); + } + } + } + } + + private getMostRelevantSettings(rankedSettingNames: string[]): ISettingsGroup { + const settings = rankedSettingNames.map(key => { + const setting = this._settingsByName.get(key); + if (setting) { + return { + description: setting.description, + key: setting.key, + value: setting.value, + range: null, + valueRange: null, + overrides: [] + }; + } + return null; + }).filter(setting => !!setting); + + return { + id: 'mostRelevant', + range: null, + title: nls.localize('mostRelevant', "Most Relevant"), + titleRange: null, + sections: [ + { + settings + } + ] + }; + } +} + +class SettingsContentBuilder { + private _contentByLines: string[]; + + get lines(): string[] { + return this._contentByLines; + } + + private get lineCountWithOffset(): number { + return this._contentByLines.length + this._rangeOffset; + } + + private get lastLine(): string { + return this._contentByLines[this._contentByLines.length - 1] || ''; + } + + // @ts-ignore unused property + constructor(private _rangeOffset = 0, private _maxLines = Infinity) { + this._contentByLines = []; + } + + private offsetIndexToIndex(offsetIdx: number): number { + return offsetIdx - this._rangeOffset; + } + + pushLine(...lineText: string[]): void { + this._contentByLines.push(...lineText); + } + + pushGroups(settingsGroups: ISettingsGroup[]): void { let lastSetting: ISetting = null; this._contentByLines.push('{'); this._contentByLines.push(''); for (const group of settingsGroups) { + this._contentByLines.push(''); lastSetting = this.pushGroup(group); } if (lastSetting) { - const content = this._contentByLines[lastSetting.range.endLineNumber - 2]; - this._contentByLines[lastSetting.range.endLineNumber - 2] = content.substring(0, content.length - 1); + // Strip the comma from the last setting + const lineIdx = this.offsetIndexToIndex(lastSetting.range.endLineNumber); + const content = this._contentByLines[lineIdx - 2]; + this._contentByLines[lineIdx - 2] = content.substring(0, content.length - 1); } this._contentByLines.push('}'); } @@ -799,13 +844,12 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements private pushGroup(group: ISettingsGroup): ISetting { const indent = ' '; let lastSetting: ISetting = null; - this._contentByLines.push(''); - let groupStart = this._contentByLines.length + 1; + let groupStart = this.lineCountWithOffset + 1; for (const section of group.sections) { if (section.title) { - let sectionTitleStart = this._contentByLines.length + 1; + let sectionTitleStart = this.lineCountWithOffset + 1; this.addDescription([section.title], indent, this._contentByLines); - section.titleRange = { startLineNumber: sectionTitleStart, startColumn: 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }; + section.titleRange = { startLineNumber: sectionTitleStart, startColumn: 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }; } if (section.settings.length) { @@ -813,38 +857,39 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements this.pushSetting(setting, indent); lastSetting = setting; } - } else { - this._contentByLines.push('// ' + nls.localize('noSettings', "No Settings")); - this._contentByLines.push(''); } } - group.range = { startLineNumber: groupStart, startColumn: 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }; + group.range = { startLineNumber: groupStart, startColumn: 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }; return lastSetting; } + getContent(): string { + return this._contentByLines.join('\n'); + } + private pushSetting(setting: ISetting, indent: string): void { - const settingStart = this._contentByLines.length + 1; + const settingStart = this.lineCountWithOffset + 1; setting.descriptionRanges = []; const descriptionPreValue = indent + '// '; for (const line of setting.description) { this._contentByLines.push(descriptionPreValue + line); - setting.descriptionRanges.push({ startLineNumber: this._contentByLines.length, startColumn: this._contentByLines[this._contentByLines.length - 1].indexOf(line) + 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }); + setting.descriptionRanges.push({ startLineNumber: this.lineCountWithOffset, startColumn: this.lastLine.indexOf(line) + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }); } let preValueConent = indent; const keyString = JSON.stringify(setting.key); preValueConent += keyString; - setting.keyRange = { startLineNumber: this._contentByLines.length + 1, startColumn: preValueConent.indexOf(setting.key) + 1, endLineNumber: this._contentByLines.length + 1, endColumn: setting.key.length }; + setting.keyRange = { startLineNumber: this.lineCountWithOffset + 1, startColumn: preValueConent.indexOf(setting.key) + 1, endLineNumber: this.lineCountWithOffset + 1, endColumn: setting.key.length }; preValueConent += ': '; - const valueStart = this._contentByLines.length + 1; + const valueStart = this.lineCountWithOffset + 1; this.pushValue(setting, preValueConent, indent); - setting.valueRange = { startLineNumber: valueStart, startColumn: preValueConent.length + 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length + 1 }; + setting.valueRange = { startLineNumber: valueStart, startColumn: preValueConent.length + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length + 1 }; this._contentByLines[this._contentByLines.length - 1] += ','; this._contentByLines.push(''); - setting.range = { startLineNumber: settingStart, startColumn: 1, endLineNumber: this._contentByLines.length, endColumn: this._contentByLines[this._contentByLines.length - 1].length }; + setting.range = { startLineNumber: settingStart, startColumn: 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }; } private pushValue(setting: ISetting, preValueConent: string, indent: string): void { @@ -877,14 +922,6 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements result.push(indent + '// ' + line); } } - - protected findValueMatches(filter: string, setting: ISetting): IRange[] { - return []; - } - - public dispose(): void { - // Not disposable - } } export function defaultKeybindingsContents(keybindingService: IKeybindingService): string { @@ -896,7 +933,8 @@ export class DefaultKeybindingsEditorModel implements IKeybindingsEditorModel this.updateConfiguration()); + this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration()); once(this.lifecycleService.onShutdown)(reason => this.save()); } @@ -157,7 +157,6 @@ export class ClearCommandHistoryAction extends Action { constructor( id: string, label: string, - @IStorageService private storageService: IStorageService, @IConfigurationService private configurationService: IConfigurationService ) { super(id, label); @@ -175,6 +174,7 @@ export class ClearCommandHistoryAction extends Action { } @editorAction +// @ts-ignore @editorAction uses the class class CommandPaletteEditorAction extends EditorAction { constructor() { @@ -264,9 +264,13 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { return nls.localize('entryAriaLabel', "{0}, commands", this.getLabel()); } - protected onError(error?: Error): void; - protected onError(messagesWithAction?: IMessageWithAction): void; - protected onError(arg1?: any): void { + private onError(error?: Error): void; + private onError(messagesWithAction?: IMessageWithAction): void; + private onError(arg1?: any): void { + if (isPromiseCanceledError(arg1)) { + return; + } + const messagesWithAction: IMessageWithAction = arg1; if (messagesWithAction && typeof messagesWithAction.message === 'string' && Array.isArray(messagesWithAction.actions)) { this.messageService.show(Severity.Error, messagesWithAction); @@ -296,6 +300,12 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { TPromise.timeout(50).done(() => { if (action && (!(action instanceof Action) || action.enabled)) { try { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'quick open' }); (action.run() || TPromise.as(null)).done(() => { if (action instanceof Action) { @@ -312,28 +322,6 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { } } -class CommandEntry extends BaseCommandEntry { - - constructor( - commandId: string, - keybinding: ResolvedKeybinding, - label: string, - meta: string, - highlights: { label: IHighlight[], alias: IHighlight[] }, - private actionDescriptor: SyncActionDescriptor, - onBeforeRun: (commandId: string) => void, - @IInstantiationService private instantiationService: IInstantiationService, - @IMessageService messageService: IMessageService, - @ITelemetryService telemetryService: ITelemetryService - ) { - super(commandId, keybinding, label, meta, highlights, onBeforeRun, messageService, telemetryService); - } - - protected getAction(): Action | IEditorAction { - return this.instantiationService.createInstance(this.actionDescriptor.syncDescriptor); - } -} - class EditorActionCommandEntry extends BaseCommandEntry { constructor( @@ -379,23 +367,26 @@ class ActionCommandEntry extends BaseCommandEntry { const wordFilter = or(matchesPrefix, matchesWords, matchesContiguousSubString); export class CommandsHandler extends QuickOpenHandler { + + public static readonly ID = 'workbench.picker.commands'; + private lastSearchValue: string; private commandHistoryEnabled: boolean; private commandsHistory: CommandsHistory; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @IEditorGroupService private editorGroupService: IEditorGroupService, @IInstantiationService private instantiationService: IInstantiationService, @IKeybindingService private keybindingService: IKeybindingService, @IMenuService private menuService: IMenuService, - @IContextKeyService private contextKeyService: IContextKeyService, @IConfigurationService private configurationService: IConfigurationService ) { super(); this.commandsHistory = this.instantiationService.createInstance(CommandsHistory); - this.configurationService.onDidUpdateConfiguration(e => this.updateConfiguration()); + this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration()); this.updateConfiguration(); } @@ -407,11 +398,6 @@ export class CommandsHandler extends QuickOpenHandler { searchValue = searchValue.trim(); this.lastSearchValue = searchValue; - // Workbench Actions - let workbenchEntries: CommandEntry[] = []; - const workbenchActions = Registry.as(ActionExtensions.WorkbenchActions).getWorkbenchActions(); - workbenchEntries = this.actionDescriptorsToEntries(workbenchActions, searchValue); - // Editor Actions const activeEditor = this.editorService.getActiveEditor(); const activeEditorControl = activeEditor ? activeEditor.getControl() : null; @@ -427,15 +413,12 @@ export class CommandsHandler extends QuickOpenHandler { const editorEntries = this.editorActionsToEntries(editorActions, searchValue); // Other Actions - const menu = isCommonCodeEditor(activeEditorControl) - ? activeEditorControl.invokeWithinContext(accessor => this.menuService.createMenu(MenuId.CommandPalette, accessor.get(IContextKeyService))) - : this.menuService.createMenu(MenuId.CommandPalette, this.contextKeyService); - + const menu = this.editorGroupService.invokeWithinEditorContext(accessor => this.menuService.createMenu(MenuId.CommandPalette, accessor.get(IContextKeyService))); const menuActions = menu.getActions().reduce((r, [, actions]) => [...r, ...actions], []); const commandEntries = this.menuItemActionsToEntries(menuActions, searchValue); // Concat - let entries = [...workbenchEntries, ...editorEntries, ...commandEntries]; + let entries = [...editorEntries, ...commandEntries]; // Remove duplicates entries = arrays.distinct(entries, entry => `${entry.getLabel()}${entry.getGroupLabel()}${entry.getCommandId()}`); @@ -490,35 +473,6 @@ export class CommandsHandler extends QuickOpenHandler { return TPromise.as(new QuickOpenModel(entries)); } - private actionDescriptorsToEntries(actionDescriptors: SyncActionDescriptor[], searchValue: string): CommandEntry[] { - const entries: CommandEntry[] = []; - const registry = Registry.as(ActionExtensions.WorkbenchActions); - - for (let i = 0; i < actionDescriptors.length; i++) { - const actionDescriptor = actionDescriptors[i]; - if (actionDescriptor.label) { - - // Label (with optional category) - let label = actionDescriptor.label; - const category = registry.getCategory(actionDescriptor.id); - if (category) { - label = nls.localize('commandLabel', "{0}: {1}", category, label); - } - - // Alias for non default languages - const alias = (language !== LANGUAGE_DEFAULT) ? registry.getAlias(actionDescriptor.id) : null; - const labelHighlights = wordFilter(searchValue, label); - const aliasHighlights = alias ? wordFilter(searchValue, alias) : null; - - if (labelHighlights || aliasHighlights) { - entries.push(this.instantiationService.createInstance(CommandEntry, actionDescriptor.id, this.keybindingService.lookupKeybinding(actionDescriptor.id), label, alias, { label: labelHighlights, alias: aliasHighlights }, actionDescriptor, (id: string) => this.onBeforeRunCommand(id))); - } - } - } - - return entries; - } - private editorActionsToEntries(actions: IEditorAction[], searchValue: string): EditorActionCommandEntry[] { const entries: EditorActionCommandEntry[] = []; @@ -613,4 +567,4 @@ export class CommandsHandler extends QuickOpenHandler { lastCommandPaletteInput = void 0; // clear last input when user canceled quick open } } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts b/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts index 986741b8c4e..520766ae206 100644 --- a/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts @@ -20,6 +20,7 @@ import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { IRange } from 'vs/editor/common/core/range'; import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; export const GOTO_LINE_PREFIX = ':'; @@ -28,8 +29,44 @@ export class GotoLineAction extends QuickOpenAction { public static ID = 'workbench.action.gotoLine'; public static LABEL = nls.localize('gotoLine', "Go to Line..."); - constructor(actionId: string, actionLabel: string, @IQuickOpenService quickOpenService: IQuickOpenService) { - super(actionId, actionLabel, GOTO_LINE_PREFIX, quickOpenService); + constructor(actionId: string, actionLabel: string, + @IQuickOpenService private readonly _quickOpenService: IQuickOpenService, + @IWorkbenchEditorService private readonly editorService: IWorkbenchEditorService + ) { + super(actionId, actionLabel, GOTO_LINE_PREFIX, _quickOpenService); + } + + public run(): TPromise { + + const editor = getCodeEditor(this.editorService.getActiveEditor()); + let restoreOptions: IEditorOptions = null; + + if (editor) { + const config = editor.getConfiguration(); + if (config.viewInfo.renderLineNumbers && config.viewInfo.renderRelativeLineNumbers) { + editor.updateOptions({ + lineNumbers: 'on' + }); + restoreOptions = { + lineNumbers: 'relative' + }; + } + } + + const result = super.run(); + + if (restoreOptions) { + let toDispose = this._quickOpenService.onHide(() => { + if (!toDispose) { + return; + } + toDispose.dispose(); + toDispose = null; + editor.updateOptions(restoreOptions); + }); + } + + return result; } } @@ -167,6 +204,9 @@ interface IEditorLineDecoration { } export class GotoLineHandler extends QuickOpenHandler { + + public static readonly ID = 'workbench.picker.line'; + private rangeHighlightDecorationId: IEditorLineDecoration; private lastKnownEditorViewState: IEditorViewState; diff --git a/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts index e15e452bde3..e5fd83df571 100644 --- a/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts @@ -369,6 +369,9 @@ interface IEditorLineDecoration { } export class GotoSymbolHandler extends QuickOpenHandler { + + public static readonly ID = 'workbench.picker.filesymbols'; + private outlineToModelCache: { [modelId: string]: OutlineModel; }; private rangeHighlightDecorationId: IEditorLineDecoration; private lastKnownEditorViewState: IEditorViewState; diff --git a/src/vs/workbench/parts/quickopen/browser/helpHandler.ts b/src/vs/workbench/parts/quickopen/browser/helpHandler.ts index 873703bbd7e..283a487dc96 100644 --- a/src/vs/workbench/parts/quickopen/browser/helpHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/helpHandler.ts @@ -16,6 +16,7 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; export const HELP_PREFIX = '?'; class HelpEntry extends QuickOpenEntryGroup { + private prefixLabel: string; private prefix: string; private description: string; private quickOpenService: IQuickOpenService; @@ -24,14 +25,20 @@ class HelpEntry extends QuickOpenEntryGroup { constructor(prefix: string, description: string, quickOpenService: IQuickOpenService, openOnPreview: boolean) { super(); - this.prefix = prefix || '\u2026'; + if (!prefix) { + this.prefix = ''; + this.prefixLabel = '\u2026' /* ... */; + } else { + this.prefix = this.prefixLabel = prefix; + } + this.description = description; this.quickOpenService = quickOpenService; this.openOnPreview = openOnPreview; } public getLabel(): string { - return this.prefix; + return this.prefixLabel; } public getAriaLabel(): string { @@ -53,6 +60,8 @@ class HelpEntry extends QuickOpenEntryGroup { export class HelpHandler extends QuickOpenHandler { + public static readonly ID = 'workbench.picker.help'; + constructor( @IQuickOpenService private quickOpenService: IQuickOpenService) { super(); } diff --git a/src/vs/workbench/parts/quickopen/browser/quickopen.contribution.ts b/src/vs/workbench/parts/quickopen/browser/quickopen.contribution.ts index c8ce1a69c59..6d6da7ea870 100644 --- a/src/vs/workbench/parts/quickopen/browser/quickopen.contribution.ts +++ b/src/vs/workbench/parts/quickopen/browser/quickopen.contribution.ts @@ -10,13 +10,13 @@ import nls = require('vs/nls'); import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions } from 'vs/workbench/browser/quickopen'; import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { GotoSymbolAction, GOTO_SYMBOL_PREFIX, SCOPE_PREFIX } from 'vs/workbench/parts/quickopen/browser/gotoSymbolHandler'; -import { ShowAllCommandsAction, ALL_COMMANDS_PREFIX, ClearCommandHistoryAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; -import { GotoLineAction, GOTO_LINE_PREFIX } from 'vs/workbench/parts/quickopen/browser/gotoLineHandler'; -import { HELP_PREFIX } from 'vs/workbench/parts/quickopen/browser/helpHandler'; -import { VIEW_PICKER_PREFIX, OpenViewPickerAction, QuickOpenViewPickerAction } from 'vs/workbench/parts/quickopen/browser/viewPickerHandler'; +import { GotoSymbolAction, GOTO_SYMBOL_PREFIX, SCOPE_PREFIX, GotoSymbolHandler } from 'vs/workbench/parts/quickopen/browser/gotoSymbolHandler'; +import { ShowAllCommandsAction, ALL_COMMANDS_PREFIX, ClearCommandHistoryAction, CommandsHandler } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; +import { GotoLineAction, GOTO_LINE_PREFIX, GotoLineHandler } from 'vs/workbench/parts/quickopen/browser/gotoLineHandler'; +import { HELP_PREFIX, HelpHandler } from 'vs/workbench/parts/quickopen/browser/helpHandler'; +import { VIEW_PICKER_PREFIX, OpenViewPickerAction, QuickOpenViewPickerAction, ViewPickerHandler } from 'vs/workbench/parts/quickopen/browser/viewPickerHandler'; import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -74,8 +74,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/commandsHandler', - 'CommandsHandler', + CommandsHandler, + CommandsHandler.ID, ALL_COMMANDS_PREFIX, 'inCommandsPicker', nls.localize('commandsHandlerDescriptionDefault', "Show and Run Commands") @@ -84,8 +84,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/gotoLineHandler', - 'GotoLineHandler', + GotoLineHandler, + GotoLineHandler.ID, GOTO_LINE_PREFIX, null, [ @@ -100,8 +100,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/gotoSymbolHandler', - 'GotoSymbolHandler', + GotoSymbolHandler, + GotoSymbolHandler.ID, GOTO_SYMBOL_PREFIX, 'inFileSymbolsPicker', [ @@ -121,8 +121,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/helpHandler', - 'HelpHandler', + HelpHandler, + HelpHandler.ID, HELP_PREFIX, null, nls.localize('helpDescription', "Show Help") @@ -131,8 +131,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpen Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/viewPickerHandler', - 'ViewPickerHandler', + ViewPickerHandler, + ViewPickerHandler.ID, VIEW_PICKER_PREFIX, inViewsPickerContextKey, [ diff --git a/src/vs/workbench/parts/quickopen/browser/viewPickerHandler.ts b/src/vs/workbench/parts/quickopen/browser/viewPickerHandler.ts index cf7a4d18419..e785486a71f 100644 --- a/src/vs/workbench/parts/quickopen/browser/viewPickerHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/viewPickerHandler.ts @@ -7,8 +7,6 @@ import { TPromise } from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import errors = require('vs/base/common/errors'); -import strings = require('vs/base/common/strings'); -import scorer = require('vs/base/common/scorer'); import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen'; import { QuickOpenModel, QuickOpenEntryGroup, QuickOpenEntry } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenHandler, QuickOpenAction } from 'vs/workbench/browser/quickopen'; @@ -19,6 +17,8 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Action } from 'vs/base/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { fuzzyContains, stripWildcards } from 'vs/base/common/strings'; +import { matchesFuzzy } from 'vs/base/common/filters'; export const VIEW_PICKER_PREFIX = 'view '; @@ -63,6 +63,8 @@ export class ViewEntry extends QuickOpenEntryGroup { export class ViewPickerHandler extends QuickOpenHandler { + public static readonly ID = 'workbench.picker.views'; + constructor( @IViewletService private viewletService: IViewletService, @IOutputService private outputService: IOutputService, @@ -74,7 +76,7 @@ export class ViewPickerHandler extends QuickOpenHandler { public getResults(searchValue: string): TPromise { searchValue = searchValue.trim(); - const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase(); + const normalizedSearchValueLowercase = stripWildcards(searchValue).toLowerCase(); const viewEntries = this.getViewEntries(); @@ -83,12 +85,14 @@ export class ViewPickerHandler extends QuickOpenHandler { return true; } - if (!scorer.matches(e.getLabel(), normalizedSearchValueLowercase) && !scorer.matches(e.getCategory(), normalizedSearchValueLowercase)) { - return false; + const highlights = matchesFuzzy(normalizedSearchValueLowercase, e.getLabel(), true); + if (highlights) { + e.setHighlights(highlights); } - const { labelHighlights, descriptionHighlights } = QuickOpenEntry.highlight(e, searchValue); - e.setHighlights(labelHighlights, descriptionHighlights); + if (!highlights && !fuzzyContains(e.getCategory(), normalizedSearchValueLowercase)) { + return false; + } return true; }); diff --git a/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts b/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts index f83349ff4f7..9f0570fbc06 100644 --- a/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts +++ b/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts @@ -9,13 +9,16 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { IMessageService } from 'vs/platform/message/common/message'; -import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; import { IWindowsService, IWindowService, IWindowsConfiguration } from 'vs/platform/windows/common/windows'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import URI from 'vs/base/common/uri'; +import { isEqual } from 'vs/base/common/resources'; +import { isLinux } from 'vs/base/common/platform'; interface IConfiguration extends IWindowsConfiguration { update: { channel: string; }; @@ -30,35 +33,34 @@ export class SettingsChangeRelauncher implements IWorkbenchContribution { private nativeTabs: boolean; private updateChannel: string; private enableCrashReporter: boolean; - private rootCount: number; - private firstRootPath: string; + + private firstFolderResource: URI; + private extensionHostRestarter: RunOnceScheduler; + + private onDidChangeWorkspaceFoldersUnbind: IDisposable; constructor( @IWindowsService private windowsService: IWindowsService, @IWindowService private windowService: IWindowService, @IConfigurationService private configurationService: IConfigurationService, - @IPreferencesService private preferencesService: IPreferencesService, @IEnvironmentService private envService: IEnvironmentService, @IMessageService private messageService: IMessageService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IExtensionService private extensionService: IExtensionService ) { const workspace = this.contextService.getWorkspace(); - if (workspace) { - this.rootCount = workspace.roots.length; - this.firstRootPath = workspace.roots.length > 0 ? workspace.roots[0].fsPath : void 0; - } else { - this.rootCount = 0; - } + this.firstFolderResource = workspace.folders.length > 0 ? workspace.folders[0].uri : void 0; + this.extensionHostRestarter = new RunOnceScheduler(() => this.extensionService.restartExtensionHost(), 10); this.onConfigurationChange(configurationService.getConfiguration(), false); + this.handleWorkbenchState(); this.registerListeners(); } private registerListeners(): void { - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration(), true))); - this.toDispose.push(this.contextService.onDidChangeWorkspaceRoots(() => this.onDidChangeWorkspaceRoots())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration(), true))); + this.toDispose.push(this.contextService.onDidChangeWorkbenchState(() => setTimeout(() => this.handleWorkbenchState()))); } private onConfigurationChange(config: IConfiguration, notify: boolean): void { @@ -93,54 +95,49 @@ export class SettingsChangeRelauncher implements IWorkbenchContribution { this.doConfirm( localize('relaunchSettingMessage', "A setting has changed that requires a restart to take effect."), localize('relaunchSettingDetail', "Press the restart button to restart {0} and enable the setting.", this.envService.appNameLong), - localize('restart', "Restart"), + localize('restart', "&&Restart"), () => this.windowsService.relaunch(Object.create(null)) ); } } - private onDidChangeWorkspaceRoots(): void { + private handleWorkbenchState(): void { + + // React to folder changes when we are in workspace state + if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + + // Update our known first folder path if we entered workspace + const workspace = this.contextService.getWorkspace(); + this.firstFolderResource = workspace.folders.length > 0 ? workspace.folders[0].uri : void 0; + + // Install workspace folder listener + if (!this.onDidChangeWorkspaceFoldersUnbind) { + this.onDidChangeWorkspaceFoldersUnbind = this.contextService.onDidChangeWorkspaceFolders(() => this.onDidChangeWorkspaceFolders()); + } + } + + // Ignore the workspace folder changes in EMPTY or FOLDER state + else { + this.onDidChangeWorkspaceFoldersUnbind = dispose(this.onDidChangeWorkspaceFoldersUnbind); + } + } + + private onDidChangeWorkspaceFolders(): void { const workspace = this.contextService.getWorkspace(); - const newRootCount = workspace ? workspace.roots.length : 0; - const newFirstRootPath = workspace && workspace.roots.length > 0 ? workspace.roots[0].fsPath : void 0; + // Restart extension host if first root folder changed (impact on deprecated workspace.rootPath API) + const newFirstFolderResource = workspace.folders.length > 0 ? workspace.folders[0].uri : void 0; + if (!isEqual(this.firstFolderResource, newFirstFolderResource, !isLinux)) { + this.firstFolderResource = newFirstFolderResource; - let reloadWindow = false; - let reloadExtensionHost = false; - - if (this.rootCount === 0 && newRootCount > 0) { - reloadWindow = true; // transition: from 0 folders to 1+ - } else if (this.rootCount > 0 && newRootCount === 0) { - reloadWindow = true; // transition: from 1+ folders to 0 - } - - if (this.firstRootPath !== newFirstRootPath) { - reloadExtensionHost = true; // first root folder changed (impact on deprecated workspace.rootPath API) - } - - this.rootCount = newRootCount; - this.firstRootPath = newFirstRootPath; - - // Reload window if this is needed - if (reloadWindow) { - this.doConfirm( - localize('relaunchWorkspaceMessage', "This workspace change requires a reload of our extension system."), - void 0, - localize('reload', "Reload"), - () => this.windowService.reloadWindow() - ); - } - - // Reload extension host if this is needed - else if (reloadExtensionHost) { - this.extensionService.restartExtensionHost(); + this.extensionHostRestarter.schedule(); // buffer calls to extension host restart } } private doConfirm(message: string, detail: string, primaryButton: string, confirmed: () => void): void { this.windowService.isFocused().then(focused => { if (focused) { - const confirm = this.messageService.confirm({ + const confirm = this.messageService.confirmSync({ type: 'info', message, detail, diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index e512ed141a0..939e661a75b 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -9,106 +9,884 @@ import nls = require('vs/nls'); import 'vs/css!./media/dirtydiffDecorator'; import { ThrottledDelayer, always } from 'vs/base/common/async'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter, anyEvent as anyEvent, filterEvent, once } from 'vs/base/common/event'; import * as ext from 'vs/workbench/common/contributions'; -import * as common from 'vs/editor/common/editorCommon'; -import * as widget from 'vs/editor/browser/codeEditor'; +import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IModelService } from 'vs/editor/common/services/modelService'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import URI from 'vs/base/common/uri'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { ISCMService } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; -import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId, IThemeService } from 'vs/platform/theme/common/themeService'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { localize } from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; +import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; +import { editorAction, ServicesAccessor, EditorAction, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; +import { PeekViewWidget, getOuterEditor } from 'vs/editor/contrib/referenceSearch/browser/peekViewWidget'; +import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { Position } from 'vs/editor/common/core/position'; +import { rot } from 'vs/base/common/numbers'; +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/browser/referencesWidget'; +import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; +import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { Action, IAction, ActionRunner } from 'vs/base/common/actions'; +import { IActionBarOptions, ActionsOrientation, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { basename } from 'vs/base/common/paths'; +import { MenuId, IMenuService, IMenu, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { fillInActions, MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; +import { IChange, ICommonCodeEditor, IEditorModel, ScrollType, IEditorContribution, OverviewRulerLane, IModel } from 'vs/editor/common/editorCommon'; +import { sortedDiff, Splice, firstIndex } from 'vs/base/common/arrays'; +import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; +import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; + +// TODO@Joao +// Need to subclass MenuItemActionItem in order to respect +// the action context coming from any action bar, without breaking +// existing users +class DiffMenuItemActionItem extends MenuItemActionItem { + + onClick(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + + this.actionRunner.run(this._commandAction, this._context) + .done(undefined, err => this._messageService.show(Severity.Error, err)); + } +} + +class DiffActionRunner extends ActionRunner { + + runAction(action: IAction, context: any): TPromise { + if (action instanceof MenuItemAction) { + return action.run(...context); + } + + return super.runAction(action, context); + } +} + +export interface IModelRegistry { + getModel(editorModel: IEditorModel): DirtyDiffModel; +} + +export const isDirtyDiffVisible = new RawContextKey('dirtyDiffVisible', false); + +function getChangeHeight(change: IChange): number { + const modified = change.modifiedEndLineNumber - change.modifiedStartLineNumber + 1; + const original = change.originalEndLineNumber - change.originalStartLineNumber + 1; + + if (change.originalEndLineNumber === 0) { + return modified; + } else if (change.modifiedEndLineNumber === 0) { + return original; + } else { + return modified + original; + } +} + +function getModifiedEndLineNumber(change: IChange): number { + if (change.modifiedEndLineNumber === 0) { + return change.modifiedStartLineNumber === 0 ? 1 : change.modifiedStartLineNumber; + } else { + return change.modifiedEndLineNumber; + } +} + +function lineIntersectsChange(lineNumber: number, change: IChange): boolean { + // deletion at the beginning of the file + if (lineNumber === 1 && change.modifiedStartLineNumber === 0 && change.modifiedEndLineNumber === 0) { + return true; + } + + return lineNumber >= change.modifiedStartLineNumber && lineNumber <= (change.modifiedEndLineNumber || change.modifiedStartLineNumber); +} + +class UIEditorAction extends Action { + + private editor: ICommonCodeEditor; + private action: EditorAction; + private instantiationService: IInstantiationService; + + constructor( + editor: ICommonCodeEditor, + action: EditorAction, + cssClass: string, + @IKeybindingService keybindingService: IKeybindingService, + @IInstantiationService instantiationService: IInstantiationService + ) { + const keybinding = keybindingService.lookupKeybinding(action.id); + const label = action.label + (keybinding ? ` (${keybinding.getLabel()})` : ''); + + super(action.id, label, cssClass); + + this.instantiationService = instantiationService; + this.action = action; + this.editor = editor; + } + + run(): TPromise { + return TPromise.wrap(this.instantiationService.invokeFunction(accessor => this.action.run(accessor, this.editor, null))); + } +} + +enum ChangeType { + Modify, + Add, + Delete +} + +function getChangeType(change: IChange): ChangeType { + if (change.originalEndLineNumber === 0) { + return ChangeType.Add; + } else if (change.modifiedEndLineNumber === 0) { + return ChangeType.Delete; + } else { + return ChangeType.Modify; + } +} + +function getChangeTypeColor(theme: ITheme, changeType: ChangeType): Color { + switch (changeType) { + case ChangeType.Modify: return theme.getColor(editorGutterModifiedBackground); + case ChangeType.Add: return theme.getColor(editorGutterAddedBackground); + case ChangeType.Delete: return theme.getColor(editorGutterDeletedBackground); + } +} + +function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICommonCodeEditor { + const diffEditors = accessor.get(ICodeEditorService).listDiffEditors(); + + for (const diffEditor of diffEditors) { + if (diffEditor.isFocused() && diffEditor instanceof EmbeddedDiffEditorWidget) { + return diffEditor.getParentEditor(); + } + } + + return getOuterEditor(accessor); +} + +class DirtyDiffWidget extends PeekViewWidget { + + private diffEditor: EmbeddedDiffEditorWidget; + private title: string; + private menu: IMenu; + private index: number; + private change: IChange; + private height: number | undefined = undefined; + private contextKeyService: IContextKeyService; + + constructor( + editor: ICodeEditor, + private model: DirtyDiffModel, + @IThemeService private themeService: IThemeService, + @IInstantiationService private instantiationService: IInstantiationService, + @IMenuService menuService: IMenuService, + @IKeybindingService private keybindingService: IKeybindingService, + @IMessageService private messageService: IMessageService, + @IContextKeyService contextKeyService: IContextKeyService + ) { + super(editor, { isResizeable: true, frameWidth: 1 }); + + themeService.onThemeChange(this._applyTheme, this, this._disposables); + this._applyTheme(themeService.getTheme()); + + this.contextKeyService = contextKeyService.createScoped(); + this.contextKeyService.createKey('originalResourceScheme', this.model.original.uri.scheme); + this.menu = menuService.createMenu(MenuId.SCMChangeContext, this.contextKeyService); + + this.create(); + this.title = basename(editor.getModel().uri.fsPath); + this.setTitle(this.title); + + model.onDidChange(this.renderTitle, this, this._disposables); + } + + showChange(index: number): void { + const change = this.model.changes[index]; + this.index = index; + this.change = change; + + const originalModel = this.model.original; + + if (!originalModel) { + return; + } + + const onFirstDiffUpdate = once(this.diffEditor.onDidUpdateDiff); + + // TODO@joao TODO@alex need this setTimeout probably because the + // non-side-by-side diff still hasn't created the view zones + onFirstDiffUpdate(() => setTimeout(() => this.revealChange(change), 0)); + + this.diffEditor.setModel(this.model); + + const position = new Position(getModifiedEndLineNumber(change), 1); + + const lineHeight = this.editor.getConfiguration().lineHeight; + const editorHeight = this.editor.getLayoutInfo().height; + const editorHeightInLines = Math.floor(editorHeight / lineHeight); + const height = Math.min(getChangeHeight(change) + /* padding */ 8, Math.floor(editorHeightInLines / 3)); + + this.renderTitle(); + + const changeType = getChangeType(change); + const changeTypeColor = getChangeTypeColor(this.themeService.getTheme(), changeType); + this.style({ frameColor: changeTypeColor }); + + this._actionbarWidget.context = [this.model.modified.uri, this.model.changes, index]; + this.show(position, height); + this.editor.focus(); + } + + private renderTitle(): void { + const detail = this.model.changes.length > 1 + ? localize('changes', "{0} of {1} changes", this.index + 1, this.model.changes.length) + : localize('change', "{0} of {1} change", this.index + 1, this.model.changes.length); + + this.setTitle(this.title, detail); + } + + protected _fillHead(container: HTMLElement): void { + super._fillHead(container); + + const previous = this.instantiationService.createInstance(UIEditorAction, this.editor, new ShowPreviousChangeAction(), 'show-previous-change octicon octicon-chevron-up'); + const next = this.instantiationService.createInstance(UIEditorAction, this.editor, new ShowNextChangeAction(), 'show-next-change octicon octicon-chevron-down'); + + this._disposables.push(previous); + this._disposables.push(next); + this._actionbarWidget.push([previous, next], { label: false, icon: true }); + + const actions: IAction[] = []; + fillInActions(this.menu, { shouldForwardArgs: true }, actions); + this._actionbarWidget.push(actions, { label: false, icon: true }); + } + + protected _getActionBarOptions(): IActionBarOptions { + return { + actionRunner: new DiffActionRunner(), + actionItemProvider: action => this.getActionItem(action), + orientation: ActionsOrientation.HORIZONTAL_REVERSE + }; + } + + getActionItem(action: IAction): IActionItem { + if (!(action instanceof MenuItemAction)) { + return undefined; + } + + return new DiffMenuItemActionItem(action, this.keybindingService, this.messageService); + } + + protected _fillBody(container: HTMLElement): void { + const options: IDiffEditorOptions = { + scrollBeyondLastLine: true, + scrollbar: { + verticalScrollbarSize: 14, + horizontal: 'auto', + useShadows: true, + verticalHasArrows: false, + horizontalHasArrows: false + }, + overviewRulerLanes: 2, + fixedOverflowWidgets: true, + minimap: { enabled: false }, + renderSideBySide: false, + readOnly: true + }; + + this.diffEditor = this.instantiationService.createInstance(EmbeddedDiffEditorWidget, container, options, this.editor); + } + + _onWidth(width: number): void { + if (typeof this.height === 'undefined') { + return; + } + + this.diffEditor.layout({ height: this.height, width }); + } + + protected _doLayoutBody(height: number, width: number): void { + super._doLayoutBody(height, width); + this.diffEditor.layout({ height, width }); + + if (typeof this.height === 'undefined') { + this.revealChange(this.change); + } + + this.height = height; + } + + private revealChange(change: IChange): void { + let start: number, end: number; + + if (change.modifiedEndLineNumber === 0) { // deletion + start = change.modifiedStartLineNumber; + end = change.modifiedStartLineNumber + 1; + } else if (change.originalEndLineNumber > 0) { // modification + start = change.modifiedStartLineNumber - 1; + end = change.modifiedEndLineNumber + 1; + } else { // insertion + start = change.modifiedStartLineNumber; + end = change.modifiedEndLineNumber; + } + + this.diffEditor.revealLinesInCenter(start, end, ScrollType.Immediate); + } + + private _applyTheme(theme: ITheme) { + let borderColor = theme.getColor(peekViewBorder) || Color.transparent; + this.style({ + arrowColor: borderColor, + frameColor: borderColor, + headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent, + primaryHeadingColor: theme.getColor(peekViewTitleForeground), + secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) + }); + } + + protected revealLine(lineNumber: number) { + this.editor.revealLineInCenterIfOutsideViewport(lineNumber, ScrollType.Smooth); + } +} + +@editorAction +export class ShowPreviousChangeAction extends EditorAction { + + constructor() { + super({ + id: 'editor.action.dirtydiff.previous', + label: nls.localize('show previous change', "Show Previous Change"), + alias: 'Show Previous Change', + precondition: null, + kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F3 } + }); + } + + run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + const outerEditor = getOuterEditorFromDiffEditor(accessor); + + if (!outerEditor) { + return; + } + + const controller = DirtyDiffController.get(outerEditor); + + if (!controller) { + return; + } + + if (!controller.canNavigate()) { + return; + } + + controller.previous(); + } +} + +@editorAction +export class ShowNextChangeAction extends EditorAction { + + constructor() { + super({ + id: 'editor.action.dirtydiff.next', + label: nls.localize('show next change', "Show Next Change"), + alias: 'Show Next Change', + precondition: null, + kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.Alt | KeyCode.F3 } + }); + } + + run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + const outerEditor = getOuterEditorFromDiffEditor(accessor); + + if (!outerEditor) { + return; + } + + const controller = DirtyDiffController.get(outerEditor); + + if (!controller) { + return; + } + + if (!controller.canNavigate()) { + return; + } + + controller.next(); + } +} + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'closeDirtyDiff', + weight: CommonEditorRegistry.commandWeight(50), + primary: KeyCode.Escape, + secondary: [KeyMod.Shift | KeyCode.Escape], + when: ContextKeyExpr.and(isDirtyDiffVisible), + handler: (accessor: ServicesAccessor) => { + const outerEditor = getOuterEditorFromDiffEditor(accessor); + + if (!outerEditor) { + return; + } + + const controller = DirtyDiffController.get(outerEditor); + + if (!controller) { + return; + } + + controller.close(); + } +}); + +@editorContribution +export class DirtyDiffController implements IEditorContribution { + + private static ID = 'editor.contrib.dirtydiff'; + + static get(editor: ICommonCodeEditor): DirtyDiffController { + return editor.getContribution(DirtyDiffController.ID); + } + + modelRegistry: IModelRegistry | null = null; + + private model: DirtyDiffModel | null = null; + private widget: DirtyDiffWidget | null = null; + private currentIndex: number = -1; + private readonly isDirtyDiffVisible: IContextKey; + private session: IDisposable = EmptyDisposable; + private mouseDownInfo: { lineNumber: number } | null = null; + private enabled = false; + private disposables: IDisposable[] = []; + + constructor( + private editor: ICodeEditor, + @IContextKeyService contextKeyService: IContextKeyService, + @IInstantiationService private instantiationService: IInstantiationService + ) { + this.enabled = !contextKeyService.getContextKeyValue('isInDiffEditor'); + + if (this.enabled) { + this.isDirtyDiffVisible = isDirtyDiffVisible.bindTo(contextKeyService); + this.disposables.push(editor.onMouseDown(e => this.onEditorMouseDown(e))); + this.disposables.push(editor.onMouseUp(e => this.onEditorMouseUp(e))); + this.disposables.push(editor.onDidChangeModel(() => this.close())); + } + } + + getId(): string { + return DirtyDiffController.ID; + } + + canNavigate(): boolean { + return this.currentIndex === -1 || this.model.changes.length > 1; + } + + next(lineNumber?: number): void { + if (!this.assertWidget()) { + return; + } + + if (typeof lineNumber === 'number' || this.currentIndex === -1) { + this.currentIndex = this.findNextClosestChange(typeof lineNumber === 'number' ? lineNumber : this.editor.getPosition().lineNumber); + } else { + this.currentIndex = rot(this.currentIndex + 1, this.model.changes.length); + } + + this.widget.showChange(this.currentIndex); + } + + previous(lineNumber?: number): void { + if (!this.assertWidget()) { + return; + } + + if (typeof lineNumber === 'number' || this.currentIndex === -1) { + this.currentIndex = this.findPreviousClosestChange(typeof lineNumber === 'number' ? lineNumber : this.editor.getPosition().lineNumber); + } else { + this.currentIndex = rot(this.currentIndex - 1, this.model.changes.length); + } + + this.widget.showChange(this.currentIndex); + } + + close(): void { + this.session.dispose(); + this.session = EmptyDisposable; + } + + private assertWidget(): boolean { + if (!this.enabled) { + return false; + } + + if (this.widget) { + if (this.model.changes.length === 0) { + this.close(); + return false; + } + + return true; + } + + if (!this.modelRegistry) { + return false; + } + + const editorModel = this.editor.getModel(); + + if (!editorModel) { + return false; + } + + const model = this.modelRegistry.getModel(editorModel); + + if (!model) { + return false; + } + + if (model.changes.length === 0) { + return false; + } + + this.currentIndex = -1; + this.model = model; + this.widget = this.instantiationService.createInstance(DirtyDiffWidget, this.editor, model); + this.isDirtyDiffVisible.set(true); + + const disposables: IDisposable[] = []; + once(this.widget.onDidClose)(this.close, this, disposables); + model.onDidChange(this.onDidModelChange, this, disposables); + + disposables.push( + this.widget, + toDisposable(() => { + this.model = null; + this.widget = null; + this.currentIndex = -1; + this.isDirtyDiffVisible.set(false); + this.editor.focus(); + }) + ); + + this.session = combinedDisposable(disposables); + return true; + } + + private onDidModelChange(splices: Splice[]): void { + for (const splice of splices) { + if (splice.start <= this.currentIndex) { + if (this.currentIndex < splice.start + splice.deleteCount) { + this.currentIndex = -1; + this.next(); + } else { + this.currentIndex = rot(this.currentIndex + splice.inserted.length - splice.deleteCount - 1, this.model.changes.length); + this.next(); + } + } + } + } + + private onEditorMouseDown(e: IEditorMouseEvent): void { + this.mouseDownInfo = null; + + const range = e.target.range; + + if (!range) { + return; + } + + if (!e.event.leftButton) { + return; + } + + if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) { + return; + } + + const data = e.target.detail as IMarginData; + const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth; + + // TODO@joao TODO@alex TODO@martin this is such that we don't collide with folding + if (gutterOffsetX > 10) { + return; + } + + this.mouseDownInfo = { lineNumber: range.startLineNumber }; + } + + private onEditorMouseUp(e: IEditorMouseEvent): void { + if (!this.mouseDownInfo) { + return; + } + + const { lineNumber } = this.mouseDownInfo; + this.mouseDownInfo = null; + + const range = e.target.range; + + if (!range || range.startLineNumber !== lineNumber) { + return; + } + + if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) { + return; + } + + if (!this.modelRegistry) { + return; + } + + const editorModel = this.editor.getModel(); + + if (!editorModel) { + return; + } + + const model = this.modelRegistry.getModel(editorModel); + + if (!model) { + return; + } + + const index = firstIndex(model.changes, change => lineIntersectsChange(lineNumber, change)); + + if (index < 0) { + return; + } + + if (index === this.currentIndex) { + this.close(); + } else { + this.next(lineNumber); + } + } + + private findNextClosestChange(lineNumber: number): number { + for (let i = 0; i < this.model.changes.length; i++) { + const change = this.model.changes[i]; + + if (lineIntersectsChange(lineNumber, change)) { + return i; + } + } + + return 0; + } + + private findPreviousClosestChange(lineNumber: number): number { + for (let i = this.model.changes.length - 1; i >= 0; i--) { + const change = this.model.changes[i]; + + if (change.modifiedStartLineNumber <= lineNumber) { + return i; + } + } + + return 0; + } + + dispose(): void { + return; + } +} export const editorGutterModifiedBackground = registerColor('editorGutter.modifiedBackground', { - dark: Color.fromHex('#00bcf2').transparent(0.6), - light: Color.fromHex('#007acc').transparent(0.6), - hc: Color.fromHex('#007acc').transparent(0.6) + dark: new Color(new RGBA(12, 125, 157)), + light: new Color(new RGBA(102, 175, 224)), + hc: new Color(new RGBA(0, 73, 122)) }, localize('editorGutterModifiedBackground', "Editor gutter background color for lines that are modified.")); export const editorGutterAddedBackground = registerColor('editorGutter.addedBackground', { - dark: Color.fromHex('#7fba00').transparent(0.6), - light: Color.fromHex('#2d883e').transparent(0.6), - hc: Color.fromHex('#2d883e').transparent(0.6) + dark: new Color(new RGBA(88, 124, 12)), + light: new Color(new RGBA(129, 184, 139)), + hc: new Color(new RGBA(27, 82, 37)) }, localize('editorGutterAddedBackground', "Editor gutter background color for lines that are added.")); export const editorGutterDeletedBackground = registerColor('editorGutter.deletedBackground', { - dark: Color.fromHex('#b9131a').transparent(0.76), - light: Color.fromHex('#b9131a').transparent(0.76), - hc: Color.fromHex('#b9131a').transparent(0.76) + dark: new Color(new RGBA(148, 21, 27)), + light: new Color(new RGBA(202, 75, 81)), + hc: new Color(new RGBA(141, 14, 20)) }, localize('editorGutterDeletedBackground', "Editor gutter background color for lines that are deleted.")); - const overviewRulerDefault = new Color(new RGBA(0, 122, 204, 0.6)); export const overviewRulerModifiedForeground = registerColor('editorOverviewRuler.modifiedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerModifiedForeground', 'Overview ruler marker color for modified content.')); export const overviewRulerAddedForeground = registerColor('editorOverviewRuler.addedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerAddedForeground', 'Overview ruler marker color for added content.')); export const overviewRulerDeletedForeground = registerColor('editorOverviewRuler.deletedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerDeletedForeground', 'Overview ruler marker color for deleted content.')); - -class DirtyDiffModelDecorator { +class DirtyDiffDecorator { static MODIFIED_DECORATION_OPTIONS = ModelDecorationOptions.register({ - linesDecorationsClassName: 'dirty-diff-modified-glyph', + linesDecorationsClassName: 'dirty-diff-glyph dirty-diff-modified', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerModifiedForeground), darkColor: themeColorFromId(overviewRulerModifiedForeground), - position: common.OverviewRulerLane.Left + position: OverviewRulerLane.Left } }); static ADDED_DECORATION_OPTIONS = ModelDecorationOptions.register({ - linesDecorationsClassName: 'dirty-diff-added-glyph', + linesDecorationsClassName: 'dirty-diff-glyph dirty-diff-added', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerAddedForeground), darkColor: themeColorFromId(overviewRulerAddedForeground), - position: common.OverviewRulerLane.Left + position: OverviewRulerLane.Left } }); static DELETED_DECORATION_OPTIONS = ModelDecorationOptions.register({ - linesDecorationsClassName: 'dirty-diff-deleted-glyph', + linesDecorationsClassName: 'dirty-diff-glyph dirty-diff-deleted', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerDeletedForeground), darkColor: themeColorFromId(overviewRulerDeletedForeground), - position: common.OverviewRulerLane.Left + position: OverviewRulerLane.Left } }); - private decorations: string[]; - private baselineModel: common.IModel; - private diffDelayer: ThrottledDelayer; - private _originalURIPromise: TPromise; - private toDispose: IDisposable[]; + private decorations: string[] = []; + private disposables: IDisposable[] = []; constructor( - private model: common.IModel, - private uri: URI, + private editorModel: IModel, + private model: DirtyDiffModel + ) { + model.onDidChange(this.onDidChange, this, this.disposables); + } + + private onDidChange(): void { + const decorations = this.model.changes.map((change) => { + const changeType = getChangeType(change); + const startLineNumber = change.modifiedStartLineNumber; + const endLineNumber = change.modifiedEndLineNumber || startLineNumber; + + switch (changeType) { + case ChangeType.Add: + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: endLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.ADDED_DECORATION_OPTIONS + }; + case ChangeType.Delete: + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: startLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.DELETED_DECORATION_OPTIONS + }; + case ChangeType.Modify: + return { + range: { + startLineNumber: startLineNumber, startColumn: 1, + endLineNumber: endLineNumber, endColumn: 1 + }, + options: DirtyDiffDecorator.MODIFIED_DECORATION_OPTIONS + }; + } + }); + + this.decorations = this.editorModel.deltaDecorations(this.decorations, decorations); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + + if (this.editorModel && !this.editorModel.isDisposed()) { + this.editorModel.deltaDecorations(this.decorations, []); + } + + this.editorModel = null; + this.decorations = []; + } +} + +function compareChanges(a: IChange, b: IChange): number { + let result = a.modifiedStartLineNumber - b.modifiedStartLineNumber; + + if (result !== 0) { + return result; + } + + result = a.modifiedEndLineNumber - b.modifiedEndLineNumber; + + if (result !== 0) { + return result; + } + + result = a.originalStartLineNumber - b.originalStartLineNumber; + + if (result !== 0) { + return result; + } + + return a.originalEndLineNumber - b.originalEndLineNumber; +} + +export class DirtyDiffModel { + + private _originalModel: IModel; + get original(): IModel { return this._originalModel; } + get modified(): IModel { return this._editorModel; } + + private diffDelayer: ThrottledDelayer; + private _originalURIPromise: TPromise; + private repositoryDisposables = new Set(); + private disposables: IDisposable[] = []; + + private _onDidChange = new Emitter[]>(); + readonly onDidChange: Event[]> = this._onDidChange.event; + + private _changes: IChange[] = []; + get changes(): IChange[] { + return this._changes; + } + + constructor( + private _editorModel: IModel, @ISCMService private scmService: ISCMService, - @IModelService private modelService: IModelService, @IEditorWorkerService private editorWorkerService: IEditorWorkerService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextModelService private textModelResolverService: ITextModelService ) { - this.decorations = []; - this.diffDelayer = new ThrottledDelayer(200); - this.toDispose = []; + this.diffDelayer = new ThrottledDelayer(200); + + this.disposables.push(_editorModel.onDidChangeContent(() => this.triggerDiff())); + scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); + scmService.repositories.forEach(r => this.onDidAddRepository(r)); + + this.triggerDiff(); + } + + private onDidAddRepository(repository: ISCMRepository): void { + const disposables: IDisposable[] = []; + + this.repositoryDisposables.add(disposables); + disposables.push(toDisposable(() => this.repositoryDisposables.delete(disposables))); + + const onDidChange = anyEvent(repository.provider.onDidChange, repository.provider.onDidChangeResources); + onDidChange(this.triggerDiff, this, disposables); + + const onDidRemoveThis = filterEvent(this.scmService.onDidRemoveRepository, r => r === repository); + onDidRemoveThis(() => dispose(disposables)); + this.triggerDiff(); - this.toDispose.push(model.onDidChangeContent(() => this.triggerDiff())); - this.toDispose.push(scmService.onDidChangeRepository(() => this.triggerDiff())); } private triggerDiff(): TPromise { @@ -118,30 +896,35 @@ class DirtyDiffModelDecorator { return this.diffDelayer .trigger(() => this.diff()) - .then((diff: common.IChange[]) => { - if (!this.model || this.model.isDisposed() || !this.baselineModel || this.baselineModel.isDisposed()) { + .then((changes: IChange[]) => { + if (!this._editorModel || this._editorModel.isDisposed() || !this._originalModel || this._originalModel.isDisposed()) { return undefined; // disposed } - if (this.baselineModel.getValueLength() === 0) { - diff = []; + if (this._originalModel.getValueLength() === 0) { + changes = []; } - return this.decorations = this.model.deltaDecorations(this.decorations, DirtyDiffModelDecorator.changesToDecorations(diff || [])); + const diff = sortedDiff(this._changes, changes, compareChanges); + this._changes = changes; + + if (diff.length > 0) { + this._onDidChange.fire(diff); + } }); } - private diff(): TPromise { + private diff(): TPromise { return this.getOriginalURIPromise().then(originalURI => { - if (!this.model || this.model.isDisposed() || !originalURI) { + if (!this._editorModel || this._editorModel.isDisposed() || !originalURI) { return TPromise.as([]); // disposed } - if (!this.editorWorkerService.canComputeDirtyDiff(originalURI, this.model.uri)) { + if (!this.editorWorkerService.canComputeDirtyDiff(originalURI, this._editorModel.uri)) { return TPromise.as([]); // Files too large } - return this.editorWorkerService.computeDirtyDiff(originalURI, this.model.uri, true); + return this.editorWorkerService.computeDirtyDiff(originalURI, this._editorModel.uri, true); }); } @@ -153,15 +936,16 @@ class DirtyDiffModelDecorator { this._originalURIPromise = this.getOriginalResource() .then(originalUri => { if (!originalUri) { + this._originalModel = null; return null; } return this.textModelResolverService.createModelReference(originalUri) .then(ref => { - this.baselineModel = ref.object.textEditorModel; + this._originalModel = ref.object.textEditorModel; - this.toDispose.push(ref); - this.toDispose.push(ref.object.textEditorModel.onDidChangeContent(() => this.triggerDiff())); + this.disposables.push(ref); + this.disposables.push(ref.object.textEditorModel.onDidChangeContent(() => this.triggerDiff())); return originalUri; }); @@ -173,8 +957,12 @@ class DirtyDiffModelDecorator { } private async getOriginalResource(): TPromise { + if (!this._editorModel) { + return null; + } + for (const repository of this.scmService.repositories) { - const result = repository.provider.getOriginalResource(this.uri); + const result = repository.provider.getOriginalResource(this._editorModel.uri); if (result) { return result; @@ -184,76 +972,44 @@ class DirtyDiffModelDecorator { return null; } - private static changesToDecorations(diff: common.IChange[]): common.IModelDeltaDecoration[] { - return diff.map((change) => { - const startLineNumber = change.modifiedStartLineNumber; - const endLineNumber = change.modifiedEndLineNumber || startLineNumber; - - // Added - if (change.originalEndLineNumber === 0) { - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: endLineNumber, endColumn: 1 - }, - options: DirtyDiffModelDecorator.ADDED_DECORATION_OPTIONS - }; - } - - // Removed - if (change.modifiedEndLineNumber === 0) { - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: startLineNumber, endColumn: 1 - }, - options: DirtyDiffModelDecorator.DELETED_DECORATION_OPTIONS - }; - } - - // Modified - return { - range: { - startLineNumber: startLineNumber, startColumn: 1, - endLineNumber: endLineNumber, endColumn: 1 - }, - options: DirtyDiffModelDecorator.MODIFIED_DECORATION_OPTIONS - }; - }); - } - dispose(): void { - this.toDispose = dispose(this.toDispose); + this.disposables = dispose(this.disposables); - if (this.model && !this.model.isDisposed()) { - this.model.deltaDecorations(this.decorations, []); - } - - this.model = null; - this.baselineModel = null; - this.decorations = null; + this._editorModel = null; + this._originalModel = null; if (this.diffDelayer) { this.diffDelayer.cancel(); this.diffDelayer = null; } + + this.repositoryDisposables.forEach(d => dispose(d)); + this.repositoryDisposables.clear(); } } -export class DirtyDiffDecorator implements ext.IWorkbenchContribution { +class DirtyDiffItem { - private models: common.IModel[] = []; - private decorators: { [modelId: string]: DirtyDiffModelDecorator } = Object.create(null); - private toDispose: IDisposable[] = []; + constructor(readonly model: DirtyDiffModel, readonly decorator: DirtyDiffDecorator) { } + + dispose(): void { + this.decorator.dispose(); + this.model.dispose(); + } +} + +export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, IModelRegistry { + + private models: IModel[] = []; + private items: { [modelId: string]: DirtyDiffItem; } = Object.create(null); + private disposables: IDisposable[] = []; constructor( - @IMessageService private messageService: IMessageService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService editorGroupService: IEditorGroupService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService ) { - this.toDispose.push(editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); + this.disposables.push(editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); } getId(): string { @@ -271,62 +1027,93 @@ export class DirtyDiffDecorator implements ext.IWorkbenchContribution { .map(e => e.getControl()) // only interested in code editor widgets - .filter(c => c instanceof widget.CodeEditor) + .filter(c => c instanceof CodeEditor) - // map to models - .map(e => (e).getModel()) + // set model registry and map to models + .map(editor => { + const codeEditor = editor as CodeEditor; + const controller = DirtyDiffController.get(codeEditor); + controller.modelRegistry = this; + return codeEditor.getModel(); + }) // remove nulls and duplicates - .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1) + .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1); - // get the associated resource - .map(m => ({ model: m, uri: m.uri })); + const newModels = models.filter(o => this.models.every(m => o !== m)); + const oldModels = this.models.filter(m => models.every(o => o !== m)); - const newModels = models.filter(p => this.models.every(m => p.model !== m)); - const oldModels = this.models.filter(m => models.every(p => p.model !== m)); - - newModels.forEach(({ model, uri }) => this.onModelVisible(model, uri)); oldModels.forEach(m => this.onModelInvisible(m)); + newModels.forEach(m => this.onModelVisible(m)); - this.models = models.map(p => p.model); + this.models = models; } - private onModelVisible(model: common.IModel, uri: URI): void { - this.decorators[model.id] = this.instantiationService.createInstance(DirtyDiffModelDecorator, model, uri); + private onModelVisible(editorModel: IModel): void { + const model = this.instantiationService.createInstance(DirtyDiffModel, editorModel); + const decorator = new DirtyDiffDecorator(editorModel, model); + + this.items[editorModel.id] = new DirtyDiffItem(model, decorator); } - private onModelInvisible(model: common.IModel): void { - this.decorators[model.id].dispose(); - delete this.decorators[model.id]; + private onModelInvisible(editorModel: IModel): void { + this.items[editorModel.id].dispose(); + delete this.items[editorModel.id]; + } + + getModel(editorModel: IModel): DirtyDiffModel | null { + const item = this.items[editorModel.id]; + + if (!item) { + return null; + } + + return item.model; } dispose(): void { - this.toDispose = dispose(this.toDispose); - this.models.forEach(m => this.decorators[m.id].dispose()); + this.disposables = dispose(this.disposables); + this.models.forEach(m => this.items[m.id].dispose()); + this.models = null; - this.decorators = null; + this.items = null; } } registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const editorGutterModifiedBackgroundColor = theme.getColor(editorGutterModifiedBackground); if (editorGutterModifiedBackgroundColor) { - collector.addRule(`.monaco-editor .dirty-diff-modified-glyph { border-left: 3px solid ${editorGutterModifiedBackgroundColor}; }`); + collector.addRule(` + .monaco-editor .dirty-diff-modified { + border-left: 3px solid ${editorGutterModifiedBackgroundColor}; + } + .monaco-editor .dirty-diff-modified:before { + background: ${editorGutterModifiedBackgroundColor}; + } + `); } const editorGutterAddedBackgroundColor = theme.getColor(editorGutterAddedBackground); if (editorGutterAddedBackgroundColor) { - collector.addRule(`.monaco-editor .dirty-diff-added-glyph { border-left: 3px solid ${editorGutterAddedBackgroundColor}; }`); + collector.addRule(` + .monaco-editor .dirty-diff-added { + border-left: 3px solid ${editorGutterAddedBackgroundColor}; + } + .monaco-editor .dirty-diff-added:before { + background: ${editorGutterAddedBackgroundColor}; + } + `); } const editorGutteDeletedBackgroundColor = theme.getColor(editorGutterDeletedBackground); if (editorGutteDeletedBackgroundColor) { collector.addRule(` - .monaco-editor .dirty-diff-deleted-glyph:after { - border-top: 4px solid transparent; - border-bottom: 4px solid transparent; + .monaco-editor .dirty-diff-deleted:after { border-left: 4px solid ${editorGutteDeletedBackgroundColor}; } + .monaco-editor .dirty-diff-deleted:before { + background: ${editorGutteDeletedBackgroundColor}; + } `); } }); diff --git a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css index beaf772629e..e55cb63c612 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/dirtydiffDecorator.css @@ -3,13 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .dirty-diff-modified-glyph, -.monaco-editor .dirty-diff-added-glyph, -.monaco-editor .dirty-diff-deleted-glyph:after { +.monaco-editor .dirty-diff-glyph { margin-left: 5px; + cursor: pointer; } -.monaco-editor .dirty-diff-deleted-glyph:after { +.monaco-editor .dirty-diff-deleted:after { content: ''; position: absolute; bottom: -4px; @@ -17,4 +16,37 @@ width: 4px; height: 0; z-index: 9; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + transition: border-top-width 80ms linear, border-bottom-width 80ms linear, bottom 80ms linear; +} + +.monaco-editor .dirty-diff-glyph:before { + position: absolute; + content: ''; + height: 100%; + width: 0; + left: -2px; + transition: width 80ms linear, left 80ms linear; +} + +.monaco-editor .dirty-diff-deleted:before { + margin-left: 3px; + height: 0; + bottom: 0; + transition: height 80ms linear; +} + +.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-glyph:before { + position: absolute; + content: ''; + height: 100%; + width: 9px; + left: -6px; +} + +.monaco-editor .margin-view-overlays > div:hover > .dirty-diff-deleted:after { + bottom: 0; + border-top-width: 0; + border-bottom-width: 0; } \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css index c2027e6fd4f..ff68aea9db1 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css @@ -19,7 +19,7 @@ } .scm-viewlet:not(.empty) .empty-message, -.scm-viewlet.empty .monaco-split-view{ +.scm-viewlet.empty .monaco-panel-view { display: none; } @@ -27,6 +27,30 @@ height: 100%; } +.scm-viewlet .monaco-list-row > .scm-provider { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.scm-viewlet .monaco-list-row > .scm-provider > input { + flex-shrink: 0; +} + +.scm-viewlet .scm-provider > .count { + margin: 0 0.5em; +} + +.scm-viewlet .scm-provider > .count.hidden { + display: none; +} + +.scm-viewlet .scm-provider > .name > .type { + opacity: 0.7; + margin-left: 0.5em; + font-size: 0.9em; +} + .scm-viewlet .monaco-list-row { padding: 0 12px 0 20px; line-height: 22px; @@ -60,15 +84,12 @@ overflow: hidden; } -.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label { - width: 100%; - height: 100%; - overflow: hidden; - text-overflow: ellipsis; +.scm-viewlet .monaco-list-row > .resource > .name.strike-through > .monaco-icon-label > .monaco-icon-label-description-container > .label-name { + text-decoration: line-through; } -.scm-viewlet .monaco-list-row > .resource > .name.strike-through > .monaco-icon-label > .label-name { - text-decoration: line-through; +.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label::after { + padding: 0 4px; } .scm-viewlet .monaco-list-row > .resource > .decoration-icon { @@ -78,23 +99,26 @@ background-position: 50% 50%; } +.scm-viewlet .monaco-list .monaco-list-row > .resource > .name > .monaco-icon-label > .actions { + flex-grow: 100; +} .scm-viewlet .monaco-list .monaco-list-row > .resource-group > .actions, -.scm-viewlet .monaco-list .monaco-list-row > .resource > .actions { +.scm-viewlet .monaco-list .monaco-list-row > .resource > .name > .monaco-icon-label > .actions { display: none; } .scm-viewlet .monaco-list .monaco-list-row:hover > .resource-group > .actions, -.scm-viewlet .monaco-list .monaco-list-row:hover > .resource > .actions, +.scm-viewlet .monaco-list .monaco-list-row:hover > .resource > .name > .monaco-icon-label > .actions, .scm-viewlet .monaco-list .monaco-list-row.selected > .resource-group > .actions, .scm-viewlet .monaco-list .monaco-list-row.focused > .resource-group > .actions, -.scm-viewlet .monaco-list .monaco-list-row.selected > .resource > .actions, -.scm-viewlet .monaco-list .monaco-list-row.focused > .resource > .actions, +.scm-viewlet .monaco-list .monaco-list-row.selected > .resource > .name > .monaco-icon-label > .actions, +.scm-viewlet .monaco-list .monaco-list-row.focused > .resource > .name > .monaco-icon-label > .actions, .scm-viewlet .monaco-list:not(.selection-multiple) .monaco-list-row > .resource:hover > .actions { display: block; } -.scm-viewlet .monaco-list-row > .resource > .actions .action-label, +.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label, .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label { width: 16px; height: 100%; @@ -125,4 +149,8 @@ .scm-viewlet .scm-editor.scroll > .monaco-inputbox > .wrapper > textarea.input { overflow-y: scroll; -} \ No newline at end of file +} + +.scm-viewlet .spacer { + flex: 1; +} diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index 5b962ef04ef..b5465c83f69 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -8,15 +8,16 @@ import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { DirtyDiffDecorator } from './dirtydiffDecorator'; +import { DirtyDiffWorkbenchController } from './dirtydiffDecorator'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet'; import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { StatusUpdater, StatusBarController } from './scmActivity'; +import { SCMViewlet } from 'vs/workbench/parts/scm/electron-browser/scmViewlet'; class OpenSCMViewletAction extends ToggleViewletAction { @@ -29,11 +30,10 @@ class OpenSCMViewletAction extends ToggleViewletAction { } Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(DirtyDiffDecorator); + .registerWorkbenchContribution(DirtyDiffWorkbenchController); const viewletDescriptor = new ViewletDescriptor( - 'vs/workbench/parts/scm/electron-browser/scmViewlet', - 'SCMViewlet', + SCMViewlet, VIEWLET_ID, localize('source control', "Source Control"), 'scm', diff --git a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts index 3eca92d73f3..0ecdc26d618 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts @@ -6,11 +6,12 @@ 'use strict'; import { localize } from 'vs/nls'; +import { basename } from 'vs/base/common/paths'; import { IDisposable, dispose, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; -import { filterEvent } from 'vs/base/common/event'; +import { filterEvent, anyEvent as anyEvent } from 'vs/base/common/event'; import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; -import { IActivityBarService, NumberBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar'; @@ -24,14 +25,16 @@ export class StatusUpdater implements IWorkbenchContribution { constructor( @ISCMService private scmService: ISCMService, - @IActivityBarService private activityBarService: IActivityBarService + @IActivityService private activityService: IActivityService ) { this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); this.render(); } private onDidAddRepository(repository: ISCMRepository): void { - const changeDisposable = repository.provider.onDidChange(() => this.render()); + const provider = repository.provider; + const onDidChange = anyEvent(provider.onDidChange, provider.onDidChangeResources); + const changeDisposable = onDidChange(() => this.render()); const onDidRemove = filterEvent(this.scmService.onDidRemoveRepository, e => e === repository); const removeDisposable = onDidRemove(() => { @@ -55,13 +58,13 @@ export class StatusUpdater implements IWorkbenchContribution { if (typeof repository.provider.count === 'number') { return r + repository.provider.count; } else { - return r + repository.provider.resources.reduce((r, g) => r + g.resources.length, 0); + return r + repository.provider.resources.reduce((r, g) => r + g.resourceCollection.resources.length, 0); } }, 0); if (count > 0) { const badge = new NumberBadge(count, num => localize('scmPendingChangesBadge', '{0} pending changes', num)); - this.badgeDisposable = this.activityBarService.showActivity(VIEWLET_ID, badge, 'scm-viewlet-label'); + this.badgeDisposable = this.activityService.showActivity(VIEWLET_ID, badge, 'scm-viewlet-label'); } else { this.badgeDisposable = EmptyDisposable; } @@ -137,9 +140,13 @@ export class StatusBarController implements IWorkbenchContribution { this.statusBarDisposable.dispose(); const commands = repository.provider.statusBarCommands || []; + const label = repository.provider.rootUri + ? `${basename(repository.provider.rootUri.fsPath)} (${repository.provider.label})` + : repository.provider.label; + const disposables = commands.map(c => this.statusbarService.addEntry({ text: c.title, - tooltip: `${repository.provider.label} - ${c.tooltip}`, + tooltip: `${label} - ${c.tooltip}`, command: c.id, arguments: c.arguments }, MainThreadStatusBarAlignment.LEFT, 10000)); @@ -152,4 +159,4 @@ export class StatusBarController implements IWorkbenchContribution { this.statusBarDisposable.dispose(); this.disposables = dispose(this.disposables); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts index 89e93eccac8..dd70573afa9 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts @@ -28,7 +28,7 @@ export class SCMMenus implements IDisposable { private disposables: IDisposable[] = []; constructor( - private provider: ISCMProvider | undefined, + provider: ISCMProvider | undefined, @IContextKeyService contextKeyService: IContextKeyService, @IMenuService private menuService: IMenuService ) { diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index 64b9c613544..7b5ef35705e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -8,15 +8,17 @@ import 'vs/css!./media/scmViewlet'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { chain } from 'vs/base/common/event'; +import Event, { Emitter, chain, mapEvent } from 'vs/base/common/event'; +import { domEvent, stop } from 'vs/base/browser/event'; +import { basename } from 'vs/base/common/paths'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { Builder } from 'vs/base/browser/builder'; -import { PersistentViewsViewlet, CollapsibleView, IViewletViewOptions, IView, IViewOptions } from 'vs/workbench/parts/views/browser/views'; -import { append, $, toggleClass, trackFocus } from 'vs/base/browser/dom'; +import { IDisposable, dispose, combinedDisposable, empty as EmptyDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Builder, Dimension } from 'vs/base/browser/builder'; +import { PanelViewlet, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; +import { append, $, addClass, toggleClass, trackFocus } from 'vs/base/browser/dom'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { List } from 'vs/base/browser/ui/list/listWidget'; -import { IDelegate, IRenderer, IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; +import { IDelegate, IRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list'; import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; import { FileLabel } from 'vs/workbench/browser/labels'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; @@ -30,28 +32,28 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IMessageService } from 'vs/platform/message/common/message'; import { IListService } from 'vs/platform/list/browser/listService'; -import { MenuItemAction } from 'vs/platform/actions/common/actions'; +import { MenuItemAction, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IAction, Action, IActionItem, ActionRunner } from 'vs/base/common/actions'; -import { MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; +import { MenuItemActionItem, fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { SCMMenus } from './scmMenus'; -import { ActionBar, IActionItemProvider, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionItemProvider, Separator, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; -import { comparePaths } from 'vs/base/common/comparers'; import { isSCMResource } from './scmUtil'; import { attachListStyler, attachBadgeStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import Severity from 'vs/base/common/severity'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { ViewLocation, ViewsRegistry, IViewDescriptor } from 'vs/workbench/parts/views/browser/viewsRegistry'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions'; import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; -import * as platform from 'vs/base/common/platform'; -import { domEvent } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; +import { Command } from 'vs/editor/common/modes'; +import { render as renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import * as platform from 'vs/base/common/platform'; +import { format } from 'vs/base/common/strings'; // TODO@Joao // Need to subclass MenuItemActionItem in order to respect @@ -68,20 +70,268 @@ class SCMMenuItemActionItem extends MenuItemActionItem { } } -function identityProvider(r: ISCMResourceGroup | ISCMResource): string { - if (isSCMResource(r)) { - const group = r.resourceGroup; - const provider = group.provider; - return `${provider.contextValue}/${group.id}/${r.sourceUri.toString()}`; - } else { - const provider = r.provider; - return `${provider.contextValue}/${r.id}`; +export interface ISpliceEvent { + index: number; + deleteCount: number; + elements: T[]; +} + +export interface IViewModel { + readonly repositories: ISCMRepository[]; + readonly selectedRepositories: ISCMRepository[]; + readonly onDidSplice: Event>; + hide(repository: ISCMRepository): void; +} + +class ProvidersListDelegate implements IDelegate { + + getHeight(element: ISCMRepository): number { + return 22; + } + + getTemplateId(element: ISCMRepository): string { + return 'provider'; } } -interface SearchInputEvent extends Event { - target: HTMLInputElement; - immediate?: boolean; +class StatusBarAction extends Action { + + constructor( + private command: Command, + private commandService: ICommandService + ) { + super(`statusbaraction{${command.id}}`, command.title, '', true); + this.tooltip = command.tooltip; + } + + run(): TPromise { + return this.commandService.executeCommand(this.command.id, ...this.command.arguments); + } +} + +class StatusBarActionItem extends ActionItem { + + constructor(action: StatusBarAction) { + super(null, action, {}); + } + + _updateLabel(): void { + if (this.options.label) { + this.$e.innerHtml(renderOcticons(this.getAction().label)); + } + } +} + +interface RepositoryTemplateData { + title: HTMLElement; + type: HTMLElement; + countContainer: HTMLElement; + count: CountBadge; + actionBar: ActionBar; + disposable: IDisposable; + templateDisposable: IDisposable; +} + +class ProviderRenderer implements IRenderer { + + readonly templateId = 'provider'; + + constructor( + @ICommandService protected commandService: ICommandService, + @IThemeService protected themeService: IThemeService + ) { } + + renderTemplate(container: HTMLElement): RepositoryTemplateData { + const provider = append(container, $('.scm-provider')); + const name = append(provider, $('.name')); + const title = append(name, $('span.title')); + const type = append(name, $('span.type')); + const countContainer = append(provider, $('.count')); + + append(provider, $('.spacer')); + + const count = new CountBadge(countContainer); + const badgeStyler = attachBadgeStyler(count, this.themeService); + const actionBar = new ActionBar(provider, { actionItemProvider: a => new StatusBarActionItem(a as StatusBarAction) }); + const disposable = EmptyDisposable; + const templateDisposable = combinedDisposable([actionBar, badgeStyler]); + + return { title, type, countContainer, count, actionBar, disposable, templateDisposable }; + } + + renderElement(repository: ISCMRepository, index: number, templateData: RepositoryTemplateData): void { + templateData.disposable.dispose(); + const disposables: IDisposable[] = []; + + if (repository.provider.rootUri) { + templateData.title.textContent = basename(repository.provider.rootUri.fsPath); + templateData.type.textContent = repository.provider.label; + } else { + templateData.title.textContent = repository.provider.label; + templateData.type.textContent = ''; + } + + // const disposables = commands.map(c => this.statusbarService.addEntry({ + // text: c.title, + // tooltip: `${repository.provider.label} - ${c.tooltip}`, + // command: c.id, + // arguments: c.arguments + // }, MainThreadStatusBarAlignment.LEFT, 10000)); + + const actions = []; + const disposeActions = () => dispose(actions); + disposables.push({ dispose: disposeActions }); + + const update = () => { + disposeActions(); + + const commands = repository.provider.statusBarCommands || []; + actions.splice(0, actions.length, ...commands.map(c => new StatusBarAction(c, this.commandService))); + templateData.actionBar.clear(); + templateData.actionBar.push(actions); + + const count = repository.provider.count || 0; + toggleClass(templateData.countContainer, 'hidden', count === 0); + templateData.count.setCount(repository.provider.count); + }; + + repository.provider.onDidChange(update, null, disposables); + update(); + + templateData.disposable = combinedDisposable(disposables); + } + + disposeTemplate(templateData: RepositoryTemplateData): void { + templateData.disposable.dispose(); + templateData.templateDisposable.dispose(); + } +} + +class MainPanel extends ViewletPanel { + + private list: List; + + private _onSelectionChange = new Emitter(); + readonly onSelectionChange: Event = this._onSelectionChange.event; + + constructor( + protected viewModel: IViewModel, + @IKeybindingService protected keybindingService: IKeybindingService, + @IContextMenuService protected contextMenuService: IContextMenuService, + @ISCMService protected scmService: ISCMService, + @IInstantiationService private instantiationService: IInstantiationService, + @IThemeService private themeService: IThemeService, + @IContextKeyService private contextKeyService: IContextKeyService, + @IMenuService private menuService: IMenuService + ) { + super(localize('scm providers', "Source Control Providers"), {}, keybindingService, contextMenuService); + this.updateBodySize(); + } + + focus(): void { + super.focus(); + this.list.domFocus(); + } + + hide(repository: ISCMRepository): void { + const selectedElements = this.list.getSelectedElements(); + const index = selectedElements.indexOf(repository); + + if (index === -1) { + return; + } + + const selection = this.list.getSelection(); + this.list.setSelection([...selection.slice(0, index), ...selection.slice(index + 1)]); + } + + getSelection(): ISCMRepository[] { + return this.list.getSelectedElements(); + } + + private splice(index: number, deleteCount: number, repositories: ISCMRepository[] = []): void { + const wasEmpty = this.list.length === 0; + + this.list.splice(index, deleteCount, repositories); + this.updateBodySize(); + + // Automatically select the first one + if (wasEmpty && this.list.length > 0) { + this.list.setSelection([0]); + } + } + + protected renderBody(container: HTMLElement): void { + const delegate = new ProvidersListDelegate(); + const renderer = this.instantiationService.createInstance(ProviderRenderer); + + this.list = new List(container, delegate, [renderer], { + identityProvider: repository => repository.provider.id + }); + + this.disposables.push(this.list); + this.disposables.push(attachListStyler(this.list, this.themeService)); + this.list.onSelectionChange(this.onListSelectionChange, this, this.disposables); + this.list.onContextMenu(this.onListContextMenu, this, this.disposables); + + this.viewModel.onDidSplice(({ index, deleteCount, elements }) => this.splice(index, deleteCount, elements), null, this.disposables); + this.splice(0, 0, this.viewModel.repositories); + } + + protected layoutBody(size: number): void { + this.list.layout(size); + } + + private updateBodySize(): void { + const count = this.viewModel.repositories.length; + + if (count <= 5) { + const size = count * 22; + this.minimumBodySize = size; + this.maximumBodySize = size; + } else { + this.minimumBodySize = 5 * 22; + this.maximumBodySize = Number.POSITIVE_INFINITY; + } + } + + private onListContextMenu(e: IListContextMenuEvent): void { + const repository = e.element; + + const contextKeyService = this.contextKeyService.createScoped(); + const scmProviderKey = contextKeyService.createKey('scmProvider', void 0); + scmProviderKey.set(repository.provider.contextValue); + + const menu = this.menuService.createMenu(MenuId.SCMSourceControl, contextKeyService); + const primary: IAction[] = []; + const secondary: IAction[] = []; + const result = { primary, secondary }; + + fillInActions(menu, { shouldForwardArgs: true }, result, g => g === 'inline'); + + menu.dispose(); + contextKeyService.dispose(); + + if (secondary.length === 0) { + return; + } + + this.contextMenuService.showContextMenu({ + getAnchor: () => e.anchor, + getActions: () => TPromise.as(secondary), + getActionsContext: () => repository.provider + }); + } + + private onListSelectionChange(e: IListEvent): void { + // select one repository if the selected one is gone + if (e.elements.length === 0 && this.list.length > 0) { + this.list.setSelection([0]); + return; + } + + this._onSelectionChange.fire(e.elements); + } } interface ResourceGroupTemplate { @@ -121,7 +371,7 @@ class ResourceGroupRenderer implements IRenderer { const element = append(container, $('.resource')); const name = append(element, $('.name')); const fileLabel = this.instantiationService.createInstance(FileLabel, name, void 0); - const actionsContainer = append(element, $('.actions')); + const actionsContainer = append(fileLabel.element, $('.actions')); const actionBar = new ActionBar(actionsContainer, { actionItemProvider: this.actionItemProvider, actionRunner: new MultipleSelectionActionRunner(this.getSelectedResources) @@ -197,20 +447,23 @@ class ResourceRenderer implements IRenderer { } renderElement(resource: ISCMResource, index: number, template: ResourceTemplate): void { - template.fileLabel.setFile(resource.sourceUri); + + const theme = this.themeService.getTheme(); + const icon = theme.type === LIGHT ? resource.decorations.icon : resource.decorations.iconDark; + + template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon, data: resource.decorations } }); template.actionBar.clear(); template.actionBar.context = resource; template.actionBar.push(this.scmMenus.getResourceActions(resource), { icon: true, label: false }); toggleClass(template.name, 'strike-through', resource.decorations.strikeThrough); toggleClass(template.element, 'faded', resource.decorations.faded); - const theme = this.themeService.getTheme(); - const icon = theme.type === LIGHT ? resource.decorations.icon : resource.decorations.iconDark; - if (icon) { + template.decorationIcon.style.display = ''; template.decorationIcon.style.backgroundImage = `url('${icon}')`; template.decorationIcon.title = resource.decorations.tooltip; } else { + template.decorationIcon.style.display = 'none'; template.decorationIcon.style.backgroundImage = ''; } } @@ -220,7 +473,7 @@ class ResourceRenderer implements IRenderer { } } -class Delegate implements IDelegate { +class ProviderListDelegate implements IDelegate { getHeight() { return 22; } @@ -229,51 +482,29 @@ class Delegate implements IDelegate { } } -function resourceSorter(a: ISCMResource, b: ISCMResource): number { - return comparePaths(a.sourceUri.fsPath, b.sourceUri.fsPath); -} - -class SourceControlViewDescriptor implements IViewDescriptor { - - // This ID magic needs to happen in order to preserve - // good splitview state when reloading the workbench - static idCount = 0; - static freeIds: string[] = []; - - readonly id: string; - - get repository(): ISCMRepository { return this._repository; } - get name(): string { return this._repository.provider.label; } - get ctor(): any { return null; } - get location(): ViewLocation { return ViewLocation.SCM; } - - constructor(private _repository: ISCMRepository) { - if (SourceControlViewDescriptor.freeIds.length > 0) { - this.id = SourceControlViewDescriptor.freeIds.shift(); - } else { - this.id = `scm${SourceControlViewDescriptor.idCount++}`; - } - } - - dispose(): void { - SourceControlViewDescriptor.freeIds.push(this.id); +function scmResourceIdentityProvider(r: ISCMResourceGroup | ISCMResource): string { + if (isSCMResource(r)) { + const group = r.resourceGroup; + const provider = group.provider; + return `${provider.contextValue}/${group.id}/${r.sourceUri.toString()}`; + } else { + const provider = r.provider; + return `${provider.contextValue}/${r.id}`; } } -class SourceControlView extends CollapsibleView { +export class RepositoryPanel extends ViewletPanel { - private cachedHeight: number | undefined; + private cachedHeight: number | undefined = undefined; private inputBoxContainer: HTMLElement; private inputBox: InputBox; private listContainer: HTMLElement; private list: List; private menus: SCMMenus; - private disposables: IDisposable[] = []; constructor( - initialSize: number, - private repository: ISCMRepository, - options: IViewletViewOptions, + readonly repository: ISCMRepository, + private viewModel: IViewModel, @IKeybindingService protected keybindingService: IKeybindingService, @IThemeService protected themeService: IThemeService, @IContextMenuService protected contextMenuService: IContextMenuService, @@ -285,20 +516,50 @@ class SourceControlView extends CollapsibleView { @IEditorGroupService protected editorGroupService: IEditorGroupService, @IInstantiationService protected instantiationService: IInstantiationService ) { - super(initialSize, { ...(options as IViewOptions), sizing: ViewSizing.Flexible }, keybindingService, contextMenuService); - + super(repository.provider.label, {}, keybindingService, contextMenuService); this.menus = instantiationService.createInstance(SCMMenus, repository.provider); + } + + render(container: HTMLElement): void { + super.render(container); this.menus.onDidChangeTitle(this.updateActions, this, this.disposables); } - renderHeader(container: HTMLElement): void { - const title = append(container, $('div.title')); - title.textContent = this.name; + protected renderHeaderTitle(container: HTMLElement): void { + const header = append(container, $('.title.scm-provider')); + const name = append(header, $('.name')); + const title = append(name, $('span.title')); + const type = append(name, $('span.type')); - super.renderHeader(container); + if (this.repository.provider.rootUri) { + title.textContent = basename(this.repository.provider.rootUri.fsPath); + type.textContent = this.repository.provider.label; + } else { + title.textContent = this.repository.provider.label; + type.textContent = ''; + } + + const onContextMenu = mapEvent(stop(domEvent(container, 'contextmenu')), e => new StandardMouseEvent(e)); + onContextMenu(this.onContextMenu, this, this.disposables); } - renderBody(container: HTMLElement): void { + private onContextMenu(event: StandardMouseEvent): void { + if (this.viewModel.selectedRepositories.length <= 1) { + return; + } + + this.contextMenuService.showContextMenu({ + getAnchor: () => ({ x: event.posx, y: event.posy }), + getActions: () => TPromise.as([{ + id: `scm.hideRepository`, + label: localize('hideRepository', "Hide"), + enabled: true, + run: () => this.viewModel.hide(this.repository) + }]), + }); + } + + protected renderBody(container: HTMLElement): void { const focusTracker = trackFocus(container); this.disposables.push(focusTracker.addFocusListener(() => this.repository.focus())); this.disposables.push(focusTracker); @@ -306,16 +567,22 @@ class SourceControlView extends CollapsibleView { // Input this.inputBoxContainer = append(container, $('.scm-editor')); - this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { - placeholder: localize('commitMessage', "Message (press {0} to commit)", platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'), - flexibleHeight: true - }); + const updatePlaceholder = () => { + const placeholder = format(this.repository.input.placeholder, platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'); + this.inputBox.setPlaceHolder(placeholder); + }; + + this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true }); this.disposables.push(attachInputBoxStyler(this.inputBox, this.themeService)); this.disposables.push(this.inputBox); this.inputBox.value = this.repository.input.value; this.inputBox.onDidChange(value => this.repository.input.value = value, null, this.disposables); this.repository.input.onDidChange(value => this.inputBox.value = value, null, this.disposables); + + updatePlaceholder(); + this.repository.input.onDidChangePlaceholder(updatePlaceholder, null, this.disposables); + this.disposables.push(this.inputBox.onDidHeightChange(() => this.layoutBody())); chain(domEvent(this.inputBox.inputElement, 'keydown')) @@ -332,7 +599,7 @@ class SourceControlView extends CollapsibleView { // List this.listContainer = append(container, $('.scm-status.show-file-icons')); - const delegate = new Delegate(); + const delegate = new ProviderListDelegate(); const actionItemProvider = (action: IAction) => this.getActionItem(action); @@ -342,7 +609,7 @@ class SourceControlView extends CollapsibleView { ]; this.list = new List(this.listContainer, delegate, renderers, { - identityProvider, + identityProvider: scmResourceIdentityProvider, keyboardSupport: false }); @@ -362,12 +629,12 @@ class SourceControlView extends CollapsibleView { this.list.onContextMenu(this.onListContextMenu, this, this.disposables); this.disposables.push(this.list); - this.repository.provider.onDidChange(this.updateList, this, this.disposables); + this.repository.provider.onDidChangeResources(this.updateList, this, this.disposables); this.updateList(); } layoutBody(height: number = this.cachedHeight): void { - if (!height === undefined) { + if (height === undefined) { return; } @@ -384,6 +651,8 @@ class SourceControlView extends CollapsibleView { } focus(): void { + super.focus(); + if (this.isExpanded()) { this.inputBox.focus(); } @@ -411,23 +680,29 @@ class SourceControlView extends CollapsibleView { private updateList(): void { const elements = this.repository.provider.resources - .reduce<(ISCMResourceGroup | ISCMResource)[]>((r, g) => [...r, g, ...g.resources.sort(resourceSorter)], []); + .reduce<(ISCMResourceGroup | ISCMResource)[]>((r, g) => { + if (g.resourceCollection.resources.length === 0 && g.hideWhenEmpty) { + return r; + } + + return [...r, g, ...g.resourceCollection.resources]; + }, []); this.list.splice(0, this.list.length, elements); } private open(e: ISCMResource): void { - if (!e.command) { - return; - } - - this.commandService.executeCommand(e.command.id, ...e.command.arguments) - .done(undefined, onUnexpectedError); + e.open().done(undefined, onUnexpectedError); } private pin(): void { const activeEditor = this.editorService.getActiveEditor(); const activeEditorInput = this.editorService.getActiveEditorInput(); + + if (!activeEditor) { + return; + } + this.editorGroupService.pinEditor(activeEditor.position, activeEditorInput); } @@ -495,16 +770,29 @@ class InstallAdditionalSCMProvidersAction extends Action { } } -export class SCMViewlet extends PersistentViewsViewlet { +export class SCMViewlet extends PanelViewlet implements IViewModel { + private el: HTMLElement; private menus: SCMMenus; - private repositoryToViewDescriptor = new Map(); + private mainPanel: MainPanel | null = null; + private mainPanelDisposable: IDisposable = EmptyDisposable; + private _repositories: ISCMRepository[] = []; + private repositoryPanels: RepositoryPanel[] = []; private disposables: IDisposable[] = []; + private _onDidSplice = new Emitter>(); + readonly onDidSplice: Event> = this._onDidSplice.event; + + private _height: number | undefined = undefined; + get height(): number | undefined { return this._height; } + + get repositories(): ISCMRepository[] { return this._repositories; } + get selectedRepositories(): ISCMRepository[] { return this.repositoryPanels.map(p => p.repository); } + constructor( @ITelemetryService telemetryService: ITelemetryService, @ISCMService protected scmService: ISCMService, - @IInstantiationService instantiationService: IInstantiationService, + @IInstantiationService protected instantiationService: IInstantiationService, @IContextViewService protected contextViewService: IContextViewService, @IContextKeyService contextKeyService: IContextKeyService, @IKeybindingService protected keybindingService: IKeybindingService, @@ -519,53 +807,79 @@ export class SCMViewlet extends PersistentViewsViewlet { @IStorageService storageService: IStorageService, @IExtensionService extensionService: IExtensionService ) { - super(VIEWLET_ID, ViewLocation.SCM, 'scm', true, - telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService); + super(VIEWLET_ID, { showHeaderInTitleWhenSingleView: true }, telemetryService, themeService); this.menus = instantiationService.createInstance(SCMMenus, undefined); this.menus.onDidChangeTitle(this.updateTitleArea, this, this.disposables); } - private onDidAddRepository(repository: ISCMRepository): void { - const viewDescriptor = new SourceControlViewDescriptor(repository); - this.repositoryToViewDescriptor.set(repository.provider.id, viewDescriptor); - - ViewsRegistry.registerViews([viewDescriptor]); - toggleClass(this.getContainer().getHTMLElement(), 'empty', this.views.length === 0); - this.updateTitleArea(); - } - - private onDidRemoveRepository(repository: ISCMRepository): void { - const viewDescriptor = this.repositoryToViewDescriptor.get(repository.provider.id); - this.repositoryToViewDescriptor.delete(repository.provider.id); - viewDescriptor.dispose(); - - ViewsRegistry.deregisterViews([viewDescriptor.id], ViewLocation.SCM); - toggleClass(this.getContainer().getHTMLElement(), 'empty', this.views.length === 0); - this.updateTitleArea(); - } - async create(parent: Builder): TPromise { await super.create(parent); - parent.addClass('scm-viewlet', 'empty'); - append(parent.getHTMLElement(), $('div.empty-message', null, localize('no open repo', "There are no source controls active."))); + this.el = parent.getHTMLElement(); + addClass(this.el, 'scm-viewlet'); + addClass(this.el, 'empty'); + append(parent.getHTMLElement(), $('div.empty-message', null, localize('no open repo', "There are no active source control providers."))); this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables); - this.scmService.repositories.forEach(p => this.onDidAddRepository(p)); + this.scmService.repositories.forEach(r => this.onDidAddRepository(r)); + this.onDidChangeRepositories(); } - protected createView(viewDescriptor: IViewDescriptor, initialSize: number, options: IViewletViewOptions): IView { - if (viewDescriptor instanceof SourceControlViewDescriptor) { - return this.instantiationService.createInstance(SourceControlView, initialSize, viewDescriptor.repository, options); + private onDidAddRepository(repository: ISCMRepository): void { + const index = this._repositories.length; + this._repositories.push(repository); + this._onDidSplice.fire({ index, deleteCount: 0, elements: [repository] }); + this.onDidChangeRepositories(); + + if (!this.mainPanel) { + this.onSelectionChange(this.repositories); + } + } + + private onDidRemoveRepository(repository: ISCMRepository): void { + const index = this._repositories.indexOf(repository); + + if (index === -1) { + return; } - return this.instantiationService.createInstance(viewDescriptor.ctor, initialSize, options); + this._repositories.splice(index, 1); + this._onDidSplice.fire({ index, deleteCount: 1, elements: [] }); + this.onDidChangeRepositories(); + + if (!this.mainPanel) { + this.onSelectionChange(this.repositories); + } } - protected getDefaultViewSize(): number | undefined { - return this.dimension && this.dimension.height / Math.max(this.views.length, 1); + private onDidChangeRepositories(): void { + toggleClass(this.el, 'empty', this.scmService.repositories.length === 0); + + const shouldMainPanelBeVisible = this.scmService.repositories.length > 1; + + if (!!this.mainPanel === shouldMainPanelBeVisible) { + return; + } + + if (shouldMainPanelBeVisible) { + this.mainPanel = this.instantiationService.createInstance(MainPanel, this); + this.addPanel(this.mainPanel, this.mainPanel.minimumSize, 0); + + const selectionChangeDisposable = this.mainPanel.onSelectionChange(this.onSelectionChange, this); + this.onSelectionChange(this.mainPanel.getSelection()); + + this.mainPanelDisposable = toDisposable(() => { + this.removePanel(this.mainPanel); + selectionChangeDisposable.dispose(); + this.mainPanel.dispose(); + }); + } else { + this.mainPanelDisposable.dispose(); + this.mainPanelDisposable = EmptyDisposable; + this.mainPanel = null; + } } getOptimalWidth(): number { @@ -574,19 +888,19 @@ export class SCMViewlet extends PersistentViewsViewlet { getTitle(): string { const title = localize('source control', "Source Control"); - const views = ViewsRegistry.getViews(ViewLocation.SCM); - if (views.length === 1) { - const view = views[0]; - return localize('viewletTitle', "{0}: {1}", title, view.name); + if (this.repositories.length === 1) { + const [repository] = this.repositories; + return localize('viewletTitle', "{0}: {1}", title, repository.provider.label); } else { return title; } } getActions(): IAction[] { - if (this.showHeaderInTitleArea() && this.views.length === 1) { - return this.views[0].getActions(); + if (this.isSingleView()) { + const [panel] = this.repositoryPanels; + return panel.getActions(); } return this.menus.getTitleActions(); @@ -595,9 +909,11 @@ export class SCMViewlet extends PersistentViewsViewlet { getSecondaryActions(): IAction[] { let result: IAction[]; - if (this.showHeaderInTitleArea() && this.views.length === 1) { + if (this.isSingleView()) { + const [panel] = this.repositoryPanels; + result = [ - ...this.views[0].getSecondaryActions(), + ...panel.getSecondaryActions(), new Separator() ]; } else { @@ -621,8 +937,60 @@ export class SCMViewlet extends PersistentViewsViewlet { return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService); } + layout(dimension: Dimension): void { + super.layout(dimension); + this._height = dimension.height; + } + + private onSelectionChange(repositories: ISCMRepository[]): void { + // Collect unselected panels + const panelsToRemove = this.repositoryPanels + .filter(p => repositories.every(r => p.repository !== r)); + + // Collect panels still selected + const repositoryPanels = this.repositoryPanels + .filter(p => repositories.some(r => p.repository === r)); + + // Collect new selected panels + const newRepositoryPanels = repositories + .filter(r => this.repositoryPanels.every(p => p.repository !== r)) + .map(r => this.instantiationService.createInstance(RepositoryPanel, r, this)); + + // Add new selected panels + this.repositoryPanels = [...repositoryPanels, ...newRepositoryPanels]; + newRepositoryPanels.forEach(panel => { + this.addPanel(panel, panel.minimumSize, this.length); + panel.repository.focus(); + }); + + // Remove unselected panels + panelsToRemove.forEach(panel => this.removePanel(panel)); + + // Resize all panels equally + const height = typeof this.height === 'number' ? this.height : 1000; + const mainPanelHeight = this.getPanelSize(this.mainPanel); + const size = (height - mainPanelHeight) / repositories.length; + + for (const panel of this.repositoryPanels) { + this.resizePanel(panel, size); + } + } + + protected isSingleView(): boolean { + return super.isSingleView() && this.repositoryPanels.length === 1; + } + + hide(repository: ISCMRepository): void { + if (!this.mainPanel) { + return; + } + + this.mainPanel.hide(repository); + } + dispose(): void { this.disposables = dispose(this.disposables); + this.mainPanelDisposable.dispose(); super.dispose(); } } diff --git a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts index 3eae07844b7..7e9faa28fd4 100644 --- a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts @@ -11,10 +11,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import { ThrottledDelayer } from 'vs/base/common/async'; import types = require('vs/base/common/types'); -import { isWindows } from 'vs/base/common/platform'; -import strings = require('vs/base/common/strings'); import { IAutoFocus } from 'vs/base/parts/quickopen/common/quickOpen'; -import { QuickOpenEntry, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel'; +import { QuickOpenEntry, QuickOpenModel, QuickOpenItemAccessor } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; import { FileEntry, OpenFileHandler, FileQuickOpenModel } from 'vs/workbench/parts/search/browser/openFileHandler'; import * as openSymbolHandler from 'vs/workbench/parts/search/browser/openSymbolHandler'; @@ -24,6 +22,10 @@ import { ISearchStats, ICachedSearchStats, IUncachedSearchStats } from 'vs/platf import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchSearchConfiguration } from 'vs/workbench/parts/search/common/search'; +import { IRange } from 'vs/editor/common/core/range'; +import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; + +export import OpenSymbolHandler = openSymbolHandler.OpenSymbolHandler; // OpenSymbolHandler is used from an extension and must be in the main bundle file so it can load const objects_assign: (destination: T, source: U) => T & U = objects.assign; @@ -32,6 +34,38 @@ interface ISearchWithRange { range: IRange; } +/* __GDPR__FRAGMENT__ + "ITimerEventData" : { + "searchLength" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "unsortedResultDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "sortedResultDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "resultCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "symbols.fromCache": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.fromCache": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.unsortedResultDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.sortedResultDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.resultCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.traversal": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.errors": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.fileWalkStartDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.fileWalkResultDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.directoriesWalked": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.filesWalked": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.cmdForkStartTime": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.cmdForkResultTime": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.cmdResultCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.cacheLookupStartDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.cacheFilterStartDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.cacheLookupResultDuration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "files.cacheEntryCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${wildcard}": [ + { + "${prefix}": "files.joined", + "${classification}": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + ] + } +*/ interface ITimerEventData { searchLength: number; unsortedResultDuration: number; @@ -75,12 +109,10 @@ interface ITelemetryData { files: ISearchStats; } -// OpenSymbolHandler is used from an extension and must be in the main bundle file so it can load -export import OpenSymbolHandler = openSymbolHandler.OpenSymbolHandler; -import { IRange } from 'vs/editor/common/core/range'; - export class OpenAnythingHandler extends QuickOpenHandler { + public static readonly ID = 'workbench.picker.anything'; + private static LINE_COLON_PATTERN = /[#|:|\(](\d*)([#|:|,](\d*))?\)?$/; private static FILE_SEARCH_DELAY = 300; @@ -93,7 +125,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { private searchDelayer: ThrottledDelayer; private pendingSearch: TPromise; private isClosed: boolean; - private scorerCache: { [key: string]: number }; + private scorerCache: ScorerCache; private includeSymbols: boolean; constructor( @@ -116,7 +148,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { } private registerListeners(): void { - this.configurationService.onDidUpdateConfiguration(e => this.updateHandlers(this.configurationService.getConfiguration())); + this.configurationService.onDidChangeConfiguration(e => this.updateHandlers(this.configurationService.getConfiguration())); } private updateHandlers(configuration: IWorkbenchSearchConfiguration): void { @@ -141,18 +173,16 @@ export class OpenAnythingHandler extends QuickOpenHandler { this.cancelPendingSearch(); this.isClosed = false; // Treat this call as the handler being in use - // Massage search value - searchValue = searchValue.replace(/ /g, ''); // get rid of all whitespace - if (isWindows) { - searchValue = searchValue.replace(/\//g, '\\'); // Help Windows users to search for paths when using slash - } + // Prepare search for scoring + const query = prepareQuery(searchValue); - const searchWithRange = this.extractRange(searchValue); // Find a suitable range from the pattern looking for ":" and "#" + const searchWithRange = this.extractRange(query.value); // Find a suitable range from the pattern looking for ":" and "#" if (searchWithRange) { - searchValue = searchWithRange.search; // ignore range portion in query + query.value = searchWithRange.search; // ignore range portion in query + query.lowercase = query.value.toLowerCase(); } - if (!searchValue) { + if (!query.value) { return TPromise.as(new QuickOpenModel()); // Respond directly to empty search } @@ -161,12 +191,12 @@ export class OpenAnythingHandler extends QuickOpenHandler { const resultPromises: TPromise[] = []; // File Results - const filePromise = this.openFileHandler.getResults(searchValue, OpenAnythingHandler.MAX_DISPLAYED_RESULTS); + const filePromise = this.openFileHandler.getResults(query.value, OpenAnythingHandler.MAX_DISPLAYED_RESULTS); resultPromises.push(filePromise); // Symbol Results (unless disabled or a range or absolute path is specified) if (this.includeSymbols && !searchWithRange) { - resultPromises.push(this.openSymbolHandler.getResults(searchValue)); + resultPromises.push(this.openSymbolHandler.getResults(query.value)); } // Join and sort unified @@ -183,8 +213,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { // Sort const unsortedResultTime = Date.now(); - const normalizedSearchValue = strings.stripWildcards(searchValue).toLowerCase(); - const compare = (elementA: QuickOpenEntry, elementB: QuickOpenEntry) => QuickOpenEntry.compareByScore(elementA, elementB, searchValue, normalizedSearchValue, this.scorerCache); + const compare = (elementA: QuickOpenEntry, elementB: QuickOpenEntry) => compareItemsByScore(elementA, elementB, query, true, QuickOpenItemAccessor, this.scorerCache); const viewResults = arrays.top(mergedResults, compare, OpenAnythingHandler.MAX_DISPLAYED_RESULTS); const sortedResultTime = Date.now(); @@ -193,15 +222,15 @@ export class OpenAnythingHandler extends QuickOpenHandler { if (entry instanceof FileEntry) { entry.setRange(searchWithRange ? searchWithRange.range : null); - const { labelHighlights, descriptionHighlights } = QuickOpenEntry.highlight(entry, searchValue, true /* fuzzy highlight */); - entry.setHighlights(labelHighlights, descriptionHighlights); + const itemScore = scoreItem(entry, query, true, QuickOpenItemAccessor, this.scorerCache); + entry.setHighlights(itemScore.labelMatch, itemScore.descriptionMatch); } }); const duration = new Date().getTime() - startTime; filePromise.then(fileModel => { const data = this.createTimerEventData(startTime, { - searchLength: searchValue.length, + searchLength: query.value.length, unsortedResultTime, sortedResultTime, resultCount: mergedResults.length, @@ -209,13 +238,25 @@ export class OpenAnythingHandler extends QuickOpenHandler { files: fileModel.stats, }); + /* __GDPR__ + "openAnything" : { + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${include}": [ + "${ITimerEventData}" + ] + } + */ this.telemetryService.publicLog('openAnything', objects.assign(data, { duration })); }); return TPromise.as(new QuickOpenModel(viewResults)); - }, (error: Error) => { + }, (error: Error[]) => { this.pendingSearch = null; - this.messageService.show(Severity.Error, error); + if (error && error[0] && error[0].message) { + this.messageService.show(Severity.Error, error[0].message.replace(/[\*_\[\]]/g, '\\$&')); + } else { + this.messageService.show(Severity.Error, error); + } return null; }); diff --git a/src/vs/workbench/parts/search/browser/openFileHandler.ts b/src/vs/workbench/parts/search/browser/openFileHandler.ts index 631ad5a1ac7..0c72fa5787d 100644 --- a/src/vs/workbench/parts/search/browser/openFileHandler.ts +++ b/src/vs/workbench/parts/search/browser/openFileHandler.ts @@ -12,6 +12,7 @@ import labels = require('vs/base/common/labels'); import * as objects from 'vs/base/common/objects'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import URI from 'vs/base/common/uri'; +import * as resources from 'vs/base/common/resources'; import { IIconLabelOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IModeService } from 'vs/editor/common/services/modeService'; import { getIconClasses } from 'vs/workbench/browser/labels'; @@ -162,14 +163,14 @@ export class OpenFileHandler extends QuickOpenHandler { iconClass = 'file'; // only use a generic file icon if we are forced to use an icon and have no icon theme set otherwise } - const folderResources = this.contextService.hasWorkspace() ? this.contextService.getWorkspace().roots : []; + const folderResources = this.contextService.getWorkspace().folders.map(folder => folder.uri); return this.searchService.search(this.queryBuilder.file(folderResources, query)).then((complete) => { const results: QuickOpenEntry[] = []; for (let i = 0; i < complete.results.length; i++) { const fileMatch = complete.results[i]; const label = paths.basename(fileMatch.resource.fsPath); - const description = labels.getPathLabel(paths.dirname(fileMatch.resource.fsPath), this.contextService, this.environmentService); + const description = labels.getPathLabel(resources.dirname(fileMatch.resource), this.contextService, this.environmentService); results.push(this.instantiationService.createInstance(FileEntry, fileMatch.resource, label, description, iconClass)); } @@ -193,10 +194,10 @@ export class OpenFileHandler extends QuickOpenHandler { filePattern: '', cacheKey: cacheKey, maxResults: 0, - sortByScore: true + sortByScore: true, }; - const folderResources = this.contextService.hasWorkspace() ? this.contextService.getWorkspace().roots : []; + const folderResources = this.contextService.getWorkspace().folders.map(folder => folder.uri); const query = this.queryBuilder.file(folderResources, options); return query; diff --git a/src/vs/workbench/parts/search/browser/openSymbolHandler.ts b/src/vs/workbench/parts/search/browser/openSymbolHandler.ts index 9ac3c54aa86..4e552a9ca1a 100644 --- a/src/vs/workbench/parts/search/browser/openSymbolHandler.ts +++ b/src/vs/workbench/parts/search/browser/openSymbolHandler.ts @@ -10,7 +10,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { onUnexpectedError } from 'vs/base/common/errors'; import { ThrottledDelayer } from 'vs/base/common/async'; import { QuickOpenHandler, EditorQuickOpenEntry } from 'vs/workbench/browser/quickopen'; -import { QuickOpenModel, QuickOpenEntry } from 'vs/base/parts/quickopen/browser/quickOpenModel'; +import { QuickOpenModel, QuickOpenEntry, compareEntries } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { IAutoFocus, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen'; import filters = require('vs/base/common/filters'); import strings = require('vs/base/common/strings'); @@ -118,7 +118,7 @@ class SymbolEntry extends EditorQuickOpenEntry { return elementAType.localeCompare(elementBType); } - return QuickOpenEntry.compare(elementA, elementB, searchValue); + return compareEntries(elementA, elementB, searchValue); } } @@ -130,6 +130,8 @@ export interface IOpenSymbolOptions { export class OpenSymbolHandler extends QuickOpenHandler { + public static readonly ID = 'workbench.picker.symbols'; + private static SEARCH_DELAY = 500; // This delay accommodates for the user typing a word and then stops typing to start searching private delayer: ThrottledDelayer; diff --git a/src/vs/workbench/parts/search/browser/patternInputWidget.ts b/src/vs/workbench/parts/search/browser/patternInputWidget.ts index 2f3509b593d..d3101e9b681 100644 --- a/src/vs/workbench/parts/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/parts/search/browser/patternInputWidget.ts @@ -37,6 +37,7 @@ export class PatternInputWidget extends Widget { private ariaLabel: string; private domNode: HTMLElement; + // @ts-ignore unused property private inputNode: HTMLInputElement; protected inputBox: InputBox; @@ -167,8 +168,7 @@ export class PatternInputWidget extends Widget { placeholder: this.placeholder || '', ariaLabel: this.ariaLabel || '', validationOptions: { - validation: null, - showMessage: true + validation: null } }); this._register(attachInputBoxStyler(this.inputBox, this.themeService)); @@ -241,6 +241,9 @@ export class ExcludePatternInputWidget extends PatternInputWidget { title: nls.localize('useIgnoreFilesDescription', "Use Ignore Files"), isChecked: false, onChange: (viaKeyboard) => { + /* __GDPR__ + "search.useIgnoreFiles.toggled" : {} + */ this.telemetryService.publicLog('search.useIgnoreFiles.toggled'); this.onOptionChange(null); if (!viaKeyboard) { @@ -255,6 +258,9 @@ export class ExcludePatternInputWidget extends PatternInputWidget { title: nls.localize('useExcludeSettingsDescription', "Use Exclude Settings"), isChecked: false, onChange: (viaKeyboard) => { + /* __GDPR__ + "search.useExcludeSettings.toggled" : {} + */ this.telemetryService.publicLog('search.useExcludeSettings.toggled'); this.onOptionChange(null); if (!viaKeyboard) { diff --git a/src/vs/workbench/parts/search/browser/replaceService.ts b/src/vs/workbench/parts/search/browser/replaceService.ts index e4575c62f80..90c0895a44d 100644 --- a/src/vs/workbench/parts/search/browser/replaceService.ts +++ b/src/vs/workbench/parts/search/browser/replaceService.ts @@ -99,15 +99,17 @@ export class ReplaceService implements IReplaceService { @ITelemetryService private telemetryService: ITelemetryService, @IFileService private fileService: IFileService, @IEditorService private editorService: IWorkbenchEditorService, + // @ts-ignore unused injected service @IInstantiationService private instantiationService: IInstantiationService, @ITextModelService private textModelResolverService: ITextModelService, + // @ts-ignore unused injected service @ISearchWorkbenchService private searchWorkbenchService: ISearchWorkbenchService ) { } - public replace(match: Match): TPromise - public replace(files: FileMatch[], progress?: IProgressRunner): TPromise - public replace(match: FileMatchOrMatch, progress?: IProgressRunner, resource?: URI): TPromise + public replace(match: Match): TPromise; + public replace(files: FileMatch[], progress?: IProgressRunner): TPromise; + public replace(match: FileMatchOrMatch, progress?: IProgressRunner, resource?: URI): TPromise; public replace(arg: any, progress: IProgressRunner = null, resource: URI = null): TPromise { let bulkEdit: BulkEdit = createBulkEdit(this.textModelResolverService, null, this.fileService); @@ -137,6 +139,9 @@ export class ReplaceService implements IReplaceService { } public openReplacePreview(element: FileMatchOrMatch, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): TPromise { + /* __GDPR__ + "replace.open.previewEditor" : {} + */ this.telemetryService.publicLog('replace.open.previewEditor'); const fileMatch = element instanceof Match ? element.parent() : element; diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index 3326a57b1b7..0431d6bea30 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -13,11 +13,13 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import { IAction, Action } from 'vs/base/common/actions'; +import * as objects from 'vs/base/common/objects'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { explorerItemToFileResource } from 'vs/workbench/parts/files/common/files'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions } from 'vs/workbench/browser/quickopen'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -41,6 +43,8 @@ import { SearchViewlet } from 'vs/workbench/parts/search/browser/searchViewlet'; import { ListFocusContext } from 'vs/platform/list/browser/listService'; import { IOutputChannelRegistry, Extensions as OutputExt } from 'vs/workbench/parts/output/common/output'; import { defaultQuickOpenContextKey } from 'vs/workbench/browser/parts/quickopen/quickopen'; +import { OpenSymbolHandler } from 'vs/workbench/parts/search/browser/openSymbolHandler'; +import { OpenAnythingHandler } from 'vs/workbench/parts/search/browser/openAnythingHandler'; registerSingleton(ISearchWorkbenchService, SearchWorkbenchService); replaceContributions(); @@ -168,6 +172,7 @@ CommandsRegistry.registerCommand(searchActions.FindInFolderAction.ID, searchActi class ExplorerViewerActionContributor extends ActionBarContributor { private _instantiationService: IInstantiationService; + // @ts-ignore unused injected service private _contextService: IWorkspaceContextService; constructor( @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService contextService: IWorkspaceContextService) { @@ -190,7 +195,7 @@ class ExplorerViewerActionContributor extends ActionBarContributor { return false; } - return fileResource.isDirectory; + return fileResource.isDirectory && fileResource.resource.scheme === 'file'; } public getSecondaryActions(context: any): IAction[] { @@ -248,8 +253,7 @@ class ShowAllSymbolsAction extends Action { // Register Viewlet Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( - 'vs/workbench/parts/search/browser/searchViewlet', - 'SearchViewlet', + SearchViewlet, Constants.VIEWLET_ID, nls.localize('name', "Search"), 'search', @@ -258,32 +262,61 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie // Actions const registry = Registry.as(ActionExtensions.WorkbenchActions); +const category = nls.localize('search', "Search"); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.OpenSearchViewletAction, Constants.VIEWLET_ID, nls.localize('showSearchViewlet', "Show Search"), { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, - Constants.SearchViewletVisibleKey.toNegated()), 'View: Show Search', nls.localize('view', "View")); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusActiveEditorAction, Constants.FocusActiveEditorActionId, '', { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, - ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey)), ''); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FindInFilesAction, Constants.FindInFilesActionId, nls.localize('findInFiles', "Find in Files"), { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, - Constants.SearchInputBoxFocusedKey.toNegated()), 'Find in Files'); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.OpenSearchViewletAction, Constants.VIEWLET_ID, searchActions.OpenSearchViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, + ContextKeyExpr.and(Constants.SearchViewletVisibleKey.toNegated(), EditorContextKeys.focus.toNegated())), 'View: Show Search', nls.localize('view', "View")); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FindInFilesAction, Constants.FindInFilesActionId, searchActions.FindInFilesAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, + ContextKeyExpr.and(Constants.SearchInputBoxFocusedKey.toNegated(), EditorContextKeys.focus.toNegated())), 'Find in Files', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ReplaceInFilesAction, searchActions.ReplaceInFilesAction.ID, searchActions.ReplaceInFilesAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H }, + EditorContextKeys.focus.toNegated()), 'Replace in Files', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusNextSearchResultAction, searchActions.FocusNextSearchResultAction.ID, searchActions.FocusNextSearchResultAction.LABEL, { primary: KeyCode.F4 }), ''); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusPreviousSearchResultAction, searchActions.FocusPreviousSearchResultAction.ID, searchActions.FocusPreviousSearchResultAction.LABEL, { primary: KeyMod.Shift | KeyCode.F4 }), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FindInFilesWithSelectedTextAction, searchActions.FindInFilesWithSelectedTextAction.ID, searchActions.FindInFilesWithSelectedTextAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, + EditorContextKeys.focus), 'Find in Files With Selected Text', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ReplaceInFilesWithSelectedTextAction, searchActions.ReplaceInFilesWithSelectedTextAction.ID, searchActions.ReplaceInFilesWithSelectedTextAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H }, + EditorContextKeys.focus), 'Replace in Files With Selected Text', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ReplaceInFilesAction, searchActions.ReplaceInFilesAction.ID, searchActions.ReplaceInFilesAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H }), 'Replace in Files'); +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: Constants.FocusActiveEditorCommandId, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey), + handler: searchActions.FocusActiveEditorCommand, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F +}); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleCaseSensitiveAction, Constants.ToggleCaseSensitiveActionId, '', ToggleCaseSensitiveKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey)), ''); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleWholeWordAction, Constants.ToggleWholeWordActionId, '', ToggleWholeWordKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey)), ''); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleRegexAction, Constants.ToggleRegexActionId, '', ToggleRegexKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusNextSearchResultAction, searchActions.FocusNextSearchResultAction.ID, searchActions.FocusNextSearchResultAction.LABEL, { primary: KeyCode.F4 }), 'Focus Next Search Result', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusPreviousSearchResultAction, searchActions.FocusPreviousSearchResultAction.ID, searchActions.FocusPreviousSearchResultAction.LABEL, { primary: KeyMod.Shift | KeyCode.F4 }), 'Focus Previous Search Result', category); + +KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({ + id: Constants.ToggleCaseSensitiveCommandId, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey), + handler: searchActions.toggleCaseSensitiveCommand +}, ToggleCaseSensitiveKeybinding)); + +KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({ + id: Constants.ToggleWholeWordCommandId, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey), + handler: searchActions.toggleWholeWordCommand +}, ToggleWholeWordKeybinding)); + +KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({ + id: Constants.ToggleRegexCommandId, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocusedKey), + handler: searchActions.toggleRegexCommand +}, ToggleRegexKeybinding)); // Terms navigation actions -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchTermAction, searchActions.ShowNextSearchTermAction.ID, searchActions.ShowNextSearchTermAction.LABEL, ShowNextFindTermKeybinding, searchActions.ShowNextSearchTermAction.CONTEXT_KEY_EXPRESSION), 'Show Next Search Term', 'Search'); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchTermAction, searchActions.ShowPreviousSearchTermAction.ID, searchActions.ShowPreviousSearchTermAction.LABEL, ShowPreviousFindTermKeybinding, searchActions.ShowPreviousSearchTermAction.CONTEXT_KEY_EXPRESSION), 'Show Previous Search Term', 'Search'); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchTermAction, searchActions.ShowNextSearchTermAction.ID, searchActions.ShowNextSearchTermAction.LABEL, ShowNextFindTermKeybinding, searchActions.ShowNextSearchTermAction.CONTEXT_KEY_EXPRESSION), 'Search: Show Next Search Term', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchTermAction, searchActions.ShowPreviousSearchTermAction.ID, searchActions.ShowPreviousSearchTermAction.LABEL, ShowPreviousFindTermKeybinding, searchActions.ShowPreviousSearchTermAction.CONTEXT_KEY_EXPRESSION), 'Search: Show Previous Search Term', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchIncludeAction, searchActions.ShowNextSearchIncludeAction.ID, searchActions.ShowNextSearchIncludeAction.LABEL, ShowNextFindTermKeybinding, searchActions.ShowNextSearchIncludeAction.CONTEXT_KEY_EXPRESSION), 'Show Next Search Include Pattern', 'Search'); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchIncludeAction, searchActions.ShowPreviousSearchIncludeAction.ID, searchActions.ShowPreviousSearchIncludeAction.LABEL, ShowPreviousFindTermKeybinding, searchActions.ShowPreviousSearchIncludeAction.CONTEXT_KEY_EXPRESSION), 'Show Previous Search Include Pattern', 'Search'); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchIncludeAction, searchActions.ShowNextSearchIncludeAction.ID, searchActions.ShowNextSearchIncludeAction.LABEL, ShowNextFindTermKeybinding, searchActions.ShowNextSearchIncludeAction.CONTEXT_KEY_EXPRESSION), 'Search: Show Next Search Include Pattern', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchIncludeAction, searchActions.ShowPreviousSearchIncludeAction.ID, searchActions.ShowPreviousSearchIncludeAction.LABEL, ShowPreviousFindTermKeybinding, searchActions.ShowPreviousSearchIncludeAction.CONTEXT_KEY_EXPRESSION), 'Search: Show Previous Search Include Pattern', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchExcludeAction, searchActions.ShowNextSearchExcludeAction.ID, searchActions.ShowNextSearchExcludeAction.LABEL, ShowNextFindTermKeybinding, searchActions.ShowNextSearchExcludeAction.CONTEXT_KEY_EXPRESSION), 'Show Next Search Exclude Pattern', 'Search'); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchExcludeAction, searchActions.ShowPreviousSearchExcludeAction.ID, searchActions.ShowPreviousSearchExcludeAction.LABEL, ShowPreviousFindTermKeybinding, searchActions.ShowPreviousSearchExcludeAction.CONTEXT_KEY_EXPRESSION), 'Show Previous Search Exclude Pattern', 'Search'); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchExcludeAction, searchActions.ShowNextSearchExcludeAction.ID, searchActions.ShowNextSearchExcludeAction.LABEL, ShowNextFindTermKeybinding, searchActions.ShowNextSearchExcludeAction.CONTEXT_KEY_EXPRESSION), 'Search: Show Next Search Exclude Pattern', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchExcludeAction, searchActions.ShowPreviousSearchExcludeAction.ID, searchActions.ShowPreviousSearchExcludeAction.LABEL, ShowPreviousFindTermKeybinding, searchActions.ShowPreviousSearchExcludeAction.CONTEXT_KEY_EXPRESSION), 'Search: Show Previous Search Exclude Pattern', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction, ACTION_ID, ACTION_LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...'); @@ -294,8 +327,8 @@ actionBarRegistry.registerActionBarContributor(Scope.VIEWER, ExplorerViewerActio // Register Quick Open Handler Registry.as(QuickOpenExtensions.Quickopen).registerDefaultQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/search/browser/openAnythingHandler', - 'OpenAnythingHandler', + OpenAnythingHandler, + OpenAnythingHandler.ID, '', defaultQuickOpenContextKey, nls.localize('openAnythingHandlerDescription', "Go to File") @@ -304,8 +337,8 @@ Registry.as(QuickOpenExtensions.Quickopen).registerDefaultQu Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/search/browser/openAnythingHandler', - 'OpenSymbolHandler', + OpenSymbolHandler, + OpenSymbolHandler.ID, ALL_SYMBOLS_PREFIX, 'inWorkspaceSymbolsPicker', [ @@ -357,18 +390,29 @@ configurationRegistry.registerConfiguration({ }, 'search.useRipgrep': { 'type': 'boolean', - 'description': nls.localize('useRipgrep', "Controls whether to use ripgrep in text search"), + 'description': nls.localize('useRipgrep', "Controls whether to use ripgrep in text and file search"), 'default': true }, 'search.useIgnoreFilesByDefault': { 'type': 'boolean', - 'description': nls.localize('useIgnoreFilesByDefault', "Controls whether to use .gitignore and .ignore files by default when searching in a new workspace."), + 'description': nls.localize('useIgnoreFilesByDefault', "Controls whether to use .gitignore and .ignore files by default when searching for text in a new workspace."), 'default': false }, + 'search.useIgnoreFiles': { + 'type': 'boolean', + 'description': nls.localize('useIgnoreFiles', "Controls whether to use .gitignore and .ignore files when searching for files."), + 'default': false, + 'scope': ConfigurationScope.RESOURCE + }, 'search.quickOpen.includeSymbols': { 'type': 'boolean', 'description': nls.localize('search.quickOpen.includeSymbols', "Configure to include results from a global symbol search in the file results for Quick Open."), 'default': false + }, + 'search.followSymlinks': { + 'type': 'boolean', + 'description': nls.localize('search.followSymlinks', "Controls whether to follow symlinks while searching."), + 'default': true } } }); diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 3b328409d7d..b9939f0339f 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -6,7 +6,7 @@ import nls = require('vs/nls'); import DOM = require('vs/base/browser/dom'); import errors = require('vs/base/common/errors'); -import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; @@ -18,12 +18,10 @@ import { SearchViewlet } from 'vs/workbench/parts/search/browser/searchViewlet'; import { Match, FileMatch, FileMatchOrMatch, FolderMatch, RenderableMatch } from 'vs/workbench/parts/search/common/searchModel'; import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; import * as Constants from 'vs/workbench/parts/search/common/constants'; -import { CollapseAllAction as TreeCollapseAction } from 'vs/base/parts/tree/browser/treeDefaults'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ResolvedKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { toResource } from 'vs/workbench/common/editor'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IListService } from 'vs/platform/list/browser/listService'; import { explorerItemToFileResource } from 'vs/workbench/parts/files/common/files'; @@ -49,44 +47,23 @@ function doAppendKeyBindingLabel(label: string, keyBinding: ResolvedKeybinding): return keyBinding ? label + ' (' + keyBinding.getLabel() + ')' : label; } -export class ToggleCaseSensitiveAction extends Action { +export const toggleCaseSensitiveCommand = (accessor: ServicesAccessor) => { + const viewletService = accessor.get(IViewletService); + let searchViewlet = viewletService.getActiveViewlet(); + searchViewlet.toggleCaseSensitive(); +}; - constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { - super(id, label); - } +export const toggleWholeWordCommand = (accessor: ServicesAccessor) => { + const viewletService = accessor.get(IViewletService); + let searchViewlet = viewletService.getActiveViewlet(); + searchViewlet.toggleWholeWords(); +}; - public run(): TPromise { - let searchViewlet = this.viewletService.getActiveViewlet(); - searchViewlet.toggleCaseSensitive(); - return TPromise.as(null); - } -} - -export class ToggleWholeWordAction extends Action { - - constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { - super(id, label); - } - - public run(): TPromise { - let searchViewlet = this.viewletService.getActiveViewlet(); - searchViewlet.toggleWholeWords(); - return TPromise.as(null); - } -} - -export class ToggleRegexAction extends Action { - - constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { - super(id, label); - } - - public run(): TPromise { - let searchViewlet = this.viewletService.getActiveViewlet(); - searchViewlet.toggleRegex(); - return TPromise.as(null); - } -} +export const toggleRegexCommand = (accessor: ServicesAccessor) => { + const viewletService = accessor.get(IViewletService); + let searchViewlet = viewletService.getActiveViewlet(); + searchViewlet.toggleRegex(); +}; export class ShowNextSearchIncludeAction extends Action { @@ -246,6 +223,8 @@ export class FocusPreviousInputAction extends Action { export class OpenSearchViewletAction extends ToggleViewletAction { + public static LABEL = nls.localize('showSearchViewlet', "Show Search"); + constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { super(id, label, Constants.VIEWLET_ID, viewletService, editorService); } @@ -268,26 +247,26 @@ export class OpenSearchViewletAction extends ToggleViewletAction { } -export class FocusActiveEditorAction extends Action { - - constructor(id: string, label: string, @IWorkbenchEditorService private editorService: IWorkbenchEditorService) { - super(id, label); - } - - public run(): TPromise { - let editor = this.editorService.getActiveEditor(); - if (editor) { - editor.focus(); - } - return TPromise.as(true); +export const FocusActiveEditorCommand = (accessor: ServicesAccessor) => { + const editorService = accessor.get(IWorkbenchEditorService); + const editor = editorService.getActiveEditor(); + if (editor) { + editor.focus(); } + return TPromise.as(true); +}; +export interface IFindOrReplaceActionOpts { + selectWidgetText: boolean; + focusReplace: boolean; + expandSearchReplaceWidget: boolean; + takeEditorText?: boolean; } export abstract class FindOrReplaceInFilesAction extends Action { constructor(id: string, label: string, private viewletService: IViewletService, - private expandSearchReplaceWidget: boolean, private selectWidgetText: boolean, private focusReplace: boolean) { + private options: IFindOrReplaceActionOpts) { super(id, label); } @@ -295,19 +274,46 @@ export abstract class FindOrReplaceInFilesAction extends Action { const viewlet = this.viewletService.getActiveViewlet(); const searchViewletWasOpen = viewlet && viewlet.getId() === Constants.VIEWLET_ID; return this.viewletService.openViewlet(Constants.VIEWLET_ID, true).then((viewlet) => { - if (!searchViewletWasOpen || this.expandSearchReplaceWidget) { - const searchAndReplaceWidget = (viewlet).searchAndReplaceWidget; - searchAndReplaceWidget.toggleReplace(this.expandSearchReplaceWidget); - searchAndReplaceWidget.focus(this.selectWidgetText, this.focusReplace); + if (this.options.takeEditorText) { + (viewlet).takeEditorText(); } + + if (!searchViewletWasOpen || this.options.expandSearchReplaceWidget) { + const searchAndReplaceWidget = (viewlet).searchAndReplaceWidget; + searchAndReplaceWidget.toggleReplace(this.options.expandSearchReplaceWidget); + searchAndReplaceWidget.focus(this.options.selectWidgetText, this.options.focusReplace); + } + + return viewlet; }); } } export class FindInFilesAction extends FindOrReplaceInFilesAction { + public static LABEL = nls.localize('findInFiles', "Find in Files"); + constructor(id: string, label: string, @IViewletService viewletService: IViewletService) { - super(id, label, viewletService, /*expandSearchReplaceWidget=*/false, /*selectWidgetText=*/true, /*focusReplace=*/false); + super(id, label, viewletService, { + expandSearchReplaceWidget: false, + selectWidgetText: true, + focusReplace: false + }); + } +} + +export class FindInFilesWithSelectedTextAction extends FindOrReplaceInFilesAction { + + public static ID = 'workbench.action.findInFilesWithSelectedText'; + public static LABEL = nls.localize('findInFilesWithSelectedText', "Find in Files With Selected Text"); + + constructor(id: string, label: string, @IViewletService viewletService: IViewletService) { + super(id, label, viewletService, { + expandSearchReplaceWidget: false, + selectWidgetText: true, + focusReplace: false, + takeEditorText: true + }); } } @@ -317,7 +323,26 @@ export class ReplaceInFilesAction extends FindOrReplaceInFilesAction { public static LABEL = nls.localize('replaceInFiles', "Replace in Files"); constructor(id: string, label: string, @IViewletService viewletService: IViewletService) { - super(id, label, viewletService, /*expandSearchReplaceWidget=*/true, /*selectWidgetText=*/false, /*focusReplace=*/true); + super(id, label, viewletService, { + expandSearchReplaceWidget: true, + selectWidgetText: false, + focusReplace: true + }); + } +} + +export class ReplaceInFilesWithSelectedTextAction extends FindOrReplaceInFilesAction { + + public static ID = 'workbench.action.replaceInFilesWithSelectedText'; + public static LABEL = nls.localize('replaceInFilesWithSelectedText', "Replace in Files With Selected Text"); + + constructor(id: string, label: string, @IViewletService viewletService: IViewletService) { + super(id, label, viewletService, { + expandSearchReplaceWidget: true, + selectWidgetText: false, + focusReplace: true, + takeEditorText: true + }); } } @@ -344,8 +369,8 @@ export class FindInWorkspaceAction extends Action { } public run(event?: any): TPromise { - return this.viewletService.openViewlet(Constants.VIEWLET_ID, true).then((viewlet: SearchViewlet) => { - viewlet.searchInFolder(null); + return this.viewletService.openViewlet(Constants.VIEWLET_ID, true).then(viewlet => { + (viewlet as SearchViewlet).searchInFolder(null); }); } } @@ -376,14 +401,14 @@ export const findInFolderCommand = (accessor: ServicesAccessor, resource?: URI) if (focused) { const file = explorerItemToFileResource(focused); if (file) { - resource = file.isDirectory ? file.resource : URI.file(paths.dirname(file.resource.fsPath)); + resource = file.isDirectory ? file.resource : resources.dirname(file.resource); } } } - viewletService.openViewlet(Constants.VIEWLET_ID, true).then((viewlet: SearchViewlet) => { + viewletService.openViewlet(Constants.VIEWLET_ID, true).then(viewlet => { if (resource) { - viewlet.searchInFolder(resource); + (viewlet as SearchViewlet).searchInFolder(resource); } }).done(null, errors.onUnexpectedError); }; @@ -405,12 +430,28 @@ export class RefreshAction extends Action { } } -export class CollapseAllAction extends TreeCollapseAction { +export class CollapseDeepestExpandedLevelAction extends Action { + private viewer: ITree; - constructor(viewlet: SearchViewlet) { - super(viewlet.getControl(), false); + constructor(viewlet: SearchViewlet, enabled: boolean = false) { + super('vs.tree.collapse', nls.localize('collapse', "Collapse"), 'monaco-tree-action collapse-all', enabled); + this.viewer = viewlet.getControl(); this.class = 'search-action collapse'; } + + public run(context?: any): TPromise { + if (this.viewer.getHighlight()) { + return TPromise.as(null); // Global action disabled if user is in edit mode from another action + } + + this.viewer.collapseDeepestExpandedLevel(); + this.viewer.clearSelection(); + this.viewer.clearFocus(); + this.viewer.DOMFocus(); + this.viewer.focusFirst(); + + return TPromise.as(null); + } } export class ClearSearchResultsAction extends Action { @@ -439,8 +480,8 @@ export class FocusNextSearchResultAction extends Action { } public run(): TPromise { - return this.viewletService.openViewlet(Constants.VIEWLET_ID).then((searchViewlet: SearchViewlet) => { - searchViewlet.selectNextMatch(); + return this.viewletService.openViewlet(Constants.VIEWLET_ID).then(searchViewlet => { + (searchViewlet as SearchViewlet).selectNextMatch(); }); } } @@ -454,8 +495,8 @@ export class FocusPreviousSearchResultAction extends Action { } public run(): TPromise { - return this.viewletService.openViewlet(Constants.VIEWLET_ID).then((searchViewlet: SearchViewlet) => { - searchViewlet.selectPreviousMatch(); + return this.viewletService.openViewlet(Constants.VIEWLET_ID).then(searchViewlet => { + (searchViewlet as SearchViewlet).selectPreviousMatch(); }); } } @@ -477,10 +518,10 @@ export abstract class AbstractSearchAndReplaceAction extends Action { let navigator: INavigator = this.getNavigatorAt(element, viewer); if (element instanceof FolderMatch) { // If file match is removed then next element is the next file match - while (!!navigator.next() && !(navigator.current() instanceof FolderMatch)) { }; + while (!!navigator.next() && !(navigator.current() instanceof FolderMatch)) { } } else if (element instanceof FileMatch) { // If file match is removed then next element is the next file match - while (!!navigator.next() && !(navigator.current() instanceof FileMatch)) { }; + while (!!navigator.next() && !(navigator.current() instanceof FileMatch)) { } } else { navigator.next(); } @@ -508,7 +549,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action { export class RemoveAction extends AbstractSearchAndReplaceAction { constructor(private viewer: ITree, private element: RenderableMatch) { - super('remove', nls.localize('RemoveAction.label', "Remove"), 'action-remove'); + super('remove', nls.localize('RemoveAction.label', "Dismiss"), 'action-remove'); } public run(): TPromise { @@ -542,6 +583,7 @@ export class RemoveAction extends AbstractSearchAndReplaceAction { export class ReplaceAllAction extends AbstractSearchAndReplaceAction { constructor(private viewer: ITree, private fileMatch: FileMatch, private viewlet: SearchViewlet, + // @ts-ignore unused injected service @IReplaceService private replaceService: IReplaceService, @IKeybindingService keyBindingService: IKeybindingService, @ITelemetryService private telemetryService: ITelemetryService) { @@ -549,6 +591,9 @@ export class ReplaceAllAction extends AbstractSearchAndReplaceAction { } public run(): TPromise { + /* __GDPR__ + "replaceAll.action.selected" : {} + */ this.telemetryService.publicLog('replaceAll.action.selected'); let nextFocusElement = this.getElementToFocusAfterRemoved(this.viewer, this.fileMatch); return this.fileMatch.parent().replace(this.fileMatch).then(() => { @@ -573,6 +618,9 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { public run(): TPromise { this.enabled = false; + /* __GDPR__ + "replace.action.selected" : {} + */ this.telemetryService.publicLog('replace.action.selected'); return this.element.parent().replace(this.element).then(() => { @@ -633,9 +681,10 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } private hasToOpenFile(): boolean { - const file = toResource(this.editorService.getActiveEditorInput(), { filter: 'file' }); + const activeInput = this.editorService.getActiveEditorInput(); + const file = activeInput ? activeInput.getResource() : void 0; if (file) { - return paths.isEqual(file.fsPath, this.element.parent().resource().fsPath); + return file.toString() === this.element.parent().resource().toString(); } return false; } diff --git a/src/vs/workbench/parts/search/browser/searchResultsView.ts b/src/vs/workbench/parts/search/browser/searchResultsView.ts index 752b44681bc..d9eebd8932c 100644 --- a/src/vs/workbench/parts/search/browser/searchResultsView.ts +++ b/src/vs/workbench/parts/search/browser/searchResultsView.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as paths from 'vs/base/common/paths'; import * as DOM from 'vs/base/browser/dom'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { IAction, IActionRunner } from 'vs/base/common/actions'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -14,7 +14,7 @@ import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { FileLabel } from 'vs/workbench/browser/labels'; import { ITree, IDataSource, ISorter, IAccessibilityProvider, IFilter, IRenderer } from 'vs/base/parts/tree/browser/tree'; import { Match, SearchResult, FileMatch, FileMatchOrMatch, SearchModel, FolderMatch } from 'vs/workbench/parts/search/common/searchModel'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { Range } from 'vs/editor/common/core/range'; import { SearchViewlet } from 'vs/workbench/parts/search/browser/searchViewlet'; import { RemoveAction, ReplaceAllAction, ReplaceAction } from 'vs/workbench/parts/search/browser/searchActions'; @@ -28,7 +28,17 @@ export class SearchDataSource implements IDataSource { private static AUTOEXPAND_CHILD_LIMIT = 10; - constructor(private includeFolderMatch: boolean = true) { } + private includeFolderMatch: boolean; + private listener: IDisposable; + + constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService) { + this.updateIncludeFolderMatch(); + this.listener = this.contextService.onDidChangeWorkbenchState(() => this.updateIncludeFolderMatch()); + } + + private updateIncludeFolderMatch(): void { + this.includeFolderMatch = (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE); + } public getId(tree: ITree, element: any): string { if (element instanceof FolderMatch) { @@ -90,6 +100,10 @@ export class SearchDataSource implements IDataSource { } return numChildren < SearchDataSource.AUTOEXPAND_CHILD_LIMIT || element instanceof FolderMatch; } + + public dispose(): void { + this.listener = dispose(this.listener); + } } export class SearchSorter implements ISorter { @@ -141,6 +155,7 @@ export class SearchRenderer extends Disposable implements IRenderer { constructor( actionRunner: IActionRunner, private viewlet: SearchViewlet, + // @ts-ignore unused injected service @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService, @IThemeService private themeService: IThemeService @@ -310,12 +325,12 @@ export class SearchAccessibilityProvider implements IAccessibilityProvider { const match = element; const searchModel: SearchModel = (tree.getInput()).searchModel; const replace = searchModel.isReplaceActive() && !!searchModel.replaceString; - const preview = match.preview(); + const matchString = match.getMatchString(); const range = match.range(); if (replace) { - return nls.localize('replacePreviewResultAria', "Replace term {0} with {1} at column position {2} in line with text {3}", preview.inside, match.replaceString, range.startColumn + 1, match.text()); + return nls.localize('replacePreviewResultAria', "Replace term {0} with {1} at column position {2} in line with text {3}", matchString, match.replaceString, range.startColumn + 1, match.text()); } - return nls.localize('searchResultAria', "Found term {0} at column position {1} in line with text {2}", preview.inside, range.startColumn + 1, match.text()); + return nls.localize('searchResultAria', "Found term {0} at column position {1} in line with text {2}", matchString, range.startColumn + 1, match.text()); } return undefined; } diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index 04582723b8e..679dd2d65bd 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -41,14 +41,14 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; import { IProgressService } from 'vs/platform/progress/common/progress'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { KeyCode } from 'vs/base/common/keyCodes'; import { PatternInputWidget, ExcludePatternInputWidget } from 'vs/workbench/parts/search/browser/patternInputWidget'; import { SearchRenderer, SearchDataSource, SearchSorter, SearchAccessibilityProvider, SearchFilter } from 'vs/workbench/parts/search/browser/searchResultsView'; import { SearchWidget, ISearchWidgetOptions } from 'vs/workbench/parts/search/browser/searchWidget'; -import { RefreshAction, CollapseAllAction, ClearSearchResultsAction } from 'vs/workbench/parts/search/browser/searchActions'; +import { RefreshAction, CollapseDeepestExpandedLevelAction, ClearSearchResultsAction } from 'vs/workbench/parts/search/browser/searchActions'; import { IReplaceService } from 'vs/workbench/parts/search/common/replace'; import Severity from 'vs/base/common/severity'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; @@ -71,9 +71,11 @@ export class SearchViewlet extends Viewlet { private isDisposed: boolean; + // @ts-ignore unused property private loading: boolean; private queryBuilder: QueryBuilder; private viewModel: SearchModel; + // @ts-ignore unused property private callOnModelChange: lifecycle.IDisposable[]; private viewletVisible: IContextKey; @@ -88,6 +90,7 @@ export class SearchViewlet extends Viewlet { private actionRegistry: { [key: string]: Action; }; private tree: ITree; private viewletSettings: any; + // @ts-ignore unused property private domNode: Builder; private messages: Builder; private searchWidgetsContainer: Builder; @@ -103,6 +106,8 @@ export class SearchViewlet extends Viewlet { private selectCurrentMatchEmitter: Emitter; private delayedRefresh: Delayer; + private searchWithoutFolderMessageBuilder: Builder; + constructor( @ITelemetryService telemetryService: ITelemetryService, @IFileService private fileService: IFileService, @@ -141,6 +146,7 @@ export class SearchViewlet extends Viewlet { this.toUnbind.push(this.fileService.onFileChanges(e => this.onFilesChanged(e))); this.toUnbind.push(this.untitledEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e))); + this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.onDidChangeWorkbenchState())); this.selectCurrentMatchEmitter = new Emitter(); debounceEvent(this.selectCurrentMatchEmitter.event, (l, e) => e, 100, /*leading=*/true) @@ -149,6 +155,12 @@ export class SearchViewlet extends Viewlet { this.delayedRefresh = new Delayer(250); } + private onDidChangeWorkbenchState(): void { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.searchWithoutFolderMessageBuilder) { + this.searchWithoutFolderMessageBuilder.hide(); + } + } + public create(parent: Builder): TPromise { super.create(parent); @@ -239,14 +251,14 @@ export class SearchViewlet extends Viewlet { }).getHTMLElement(); this.messages = builder.div({ 'class': 'messages' }).hide().clone(); - if (!this.contextService.hasWorkspace()) { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.searchWithoutFolderMessage(this.clearMessage()); } this.createSearchResultsView(builder); - this.actionRegistry = {}; - let actions: Action[] = [new CollapseAllAction(this), new RefreshAction(this), new ClearSearchResultsAction(this)]; + this.actionRegistry = {}; + let actions: Action[] = [new CollapseDeepestExpandedLevelAction(this), new RefreshAction(this), new ClearSearchResultsAction(this)]; actions.forEach((action) => { this.actionRegistry[action.id] = action; }); @@ -375,11 +387,11 @@ export class SearchViewlet extends Viewlet { let confirmation: IConfirmation = { title: nls.localize('replaceAll.confirmation.title', "Replace All"), message: this.buildReplaceAllConfirmationMessage(occurrences, fileCount, replaceValue), - primaryButton: nls.localize('replaceAll.confirm.button', "Replace"), + primaryButton: nls.localize('replaceAll.confirm.button', "&&Replace"), type: 'question' }; - if (this.messageService.confirm(confirmation)) { + if (this.messageService.confirmSync(confirmation)) { this.searchWidget.setReplaceAllActionState(false); this.viewModel.searchResult.replaceAll(progressRunner).then(() => { progressRunner.done(); @@ -458,6 +470,8 @@ export class SearchViewlet extends Viewlet { } private clearMessage(): Builder { + this.searchWithoutFolderMessageBuilder = void 0; + return this.messages.empty().show() .asContainer().div({ 'class': 'message' }) .asContainer(); @@ -468,8 +482,12 @@ export class SearchViewlet extends Viewlet { this.results = div; this.results.addClass('show-file-icons'); - let dataSource = new SearchDataSource(this.contextService.hasMultiFolderWorkspace()); + let dataSource = this.instantiationService.createInstance(SearchDataSource); + this.toUnbind.push(dataSource); + let renderer = this.instantiationService.createInstance(SearchRenderer, this.getActionRunner(), this); + this.toUnbind.push(renderer); + let dnd = new SimpleFileResourceDragAndDrop(obj => obj instanceof FileMatch ? obj.resource() : void 0); this.tree = new Tree(div.getHTMLElement(), { @@ -640,11 +658,15 @@ export class SearchViewlet extends Viewlet { public focus(): void { super.focus(); - let selectedText = this.getSearchTextFromEditor(); + this.searchWidget.focus(); + } + + public takeEditorText(): void { + const selectedText = this.getSearchTextFromEditor(); if (selectedText) { this.searchWidget.searchInput.setValue(selectedText); + this.searchWidget.focus(); } - this.searchWidget.focus(); } public focusNextInputBox(): void { @@ -749,7 +771,7 @@ export class SearchViewlet extends Viewlet { public clearSearchResults(): void { this.viewModel.searchResult.clear(); this.showEmptyStage(); - if (!this.contextService.hasWorkspace()) { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.searchWithoutFolderMessage(this.clearMessage()); } this.searchWidget.clear(); @@ -834,6 +856,9 @@ export class SearchViewlet extends Viewlet { } public toggleQueryDetails(moveFocus?: boolean, show?: boolean, skipLayout?: boolean, reverse?: boolean): void { + /* __GDPR__ + "search.toggleQueryDetails" : {} + */ this.telemetryService.publicLog('search.toggleQueryDetails'); let cls = 'more'; @@ -867,22 +892,22 @@ export class SearchViewlet extends Viewlet { public searchInFolder(resource: URI): void { let folderPath = null; const workspace = this.contextService.getWorkspace(); - if (workspace && resource) { - if (this.contextService.hasFolderWorkspace()) { + if (resource) { + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { // Show relative path from the root for single-root mode - folderPath = paths.relative(workspace.roots[0].fsPath, resource.fsPath); + folderPath = paths.relative(workspace.folders[0].uri.fsPath, resource.fsPath); if (folderPath && folderPath !== '.') { folderPath = './' + folderPath; } } else { - const owningRoot = this.contextService.getRoot(resource); - if (owningRoot) { - const owningRootBasename = paths.basename(owningRoot.fsPath); + const owningFolder = this.contextService.getWorkspaceFolder(resource); + if (owningFolder) { + const owningRootBasename = paths.basename(owningFolder.uri.fsPath); // If this root is the only one with its basename, use a relative ./ path. If there is another, use an absolute path - const isUniqueRoot = workspace.roots.filter(root => paths.basename(root.fsPath) === owningRootBasename).length === 1; - if (isUniqueRoot) { - folderPath = `./${owningRootBasename}/${paths.relative(owningRoot.fsPath, resource.fsPath)}`; + const isUniqueFolder = workspace.folders.filter(folder => paths.basename(folder.uri.fsPath) === owningRootBasename).length === 1; + if (isUniqueFolder) { + folderPath = `./${owningRootBasename}/${paths.relative(owningFolder.uri.fsPath, resource.fsPath)}`; } else { folderPath = resource.fsPath; } @@ -956,7 +981,7 @@ export class SearchViewlet extends Viewlet { excludePattern, includePattern }; - const folderResources = this.contextService.hasWorkspace() ? this.contextService.getWorkspace().roots : []; + const folderResources = this.contextService.getWorkspace().folders; const onQueryValidationError = (err: Error) => { this.searchWidget.searchInput.showMessage({ content: err.message, type: MessageType.ERROR }); @@ -965,7 +990,7 @@ export class SearchViewlet extends Viewlet { let query: ISearchQuery; try { - query = this.queryBuilder.text(content, folderResources, options); + query = this.queryBuilder.text(content, folderResources.map(folder => folder.uri), options); } catch (err) { onQueryValidationError(err); return; @@ -988,11 +1013,12 @@ export class SearchViewlet extends Viewlet { }); return TPromise.join(folderQueriesExistP).then(existResults => { - const nonExistantFolders = existResults.map((exists, i) => ({ exists, query: query.folderQueries[i] })) - .filter(folderExists => !folderExists.exists); - - if (nonExistantFolders.length) { - const nonExistantPath = nonExistantFolders[0].query.folder.fsPath; + // If no folders exist, show an error message about the first one + const existingFolderQueries = query.folderQueries.filter((folderQuery, i) => existResults[i]); + if (!query.folderQueries.length || existingFolderQueries.length) { + query.folderQueries = existingFolderQueries; + } else { + const nonExistantPath = query.folderQueries[0].folder.fsPath; const searchPathNotFoundError = nls.localize('searchPathNotFoundError', "Search path not found: {0}", nonExistantPath); return TPromise.wrapError(new Error(searchPathNotFoundError)); } @@ -1119,7 +1145,7 @@ export class SearchViewlet extends Viewlet { }).on(dom.EventType.CLICK, (e: MouseEvent) => { dom.EventHelper.stop(e, false); - let editorPromise = this.contextService.hasWorkspace() ? this.preferencesService.openWorkspaceSettings() : this.preferencesService.openGlobalSettings(); + let editorPromise = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? this.preferencesService.openWorkspaceSettings() : this.preferencesService.openGlobalSettings(); editorPromise.done(editor => { if (editor instanceof PreferencesEditor) { editor.focusSearch('.exclude'); @@ -1144,7 +1170,7 @@ export class SearchViewlet extends Viewlet { }); } - if (!this.contextService.hasWorkspace()) { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.searchWithoutFolderMessage(div); } } else { @@ -1267,7 +1293,9 @@ export class SearchViewlet extends Viewlet { } private searchWithoutFolderMessage(div: Builder): void { - $(div).p({ text: nls.localize('searchWithoutFolder', "You have not yet opened a folder. Only open files are currently searched - ") }) + this.searchWithoutFolderMessageBuilder = $(div); + + this.searchWithoutFolderMessageBuilder.p({ text: nls.localize('searchWithoutFolder', "You have not yet opened a folder. Only open files are currently searched - ") }) .asContainer().a({ 'class': ['pointer', 'prominent'], 'tabindex': '0', @@ -1307,6 +1335,9 @@ export class SearchViewlet extends Viewlet { return TPromise.as(true); } + /* __GDPR__ + "searchResultChosen" : {} + */ this.telemetryService.publicLog('searchResultChosen'); return (this.viewModel.isReplaceActive() && !!this.viewModel.replaceString) ? diff --git a/src/vs/workbench/parts/search/browser/searchWidget.ts b/src/vs/workbench/parts/search/browser/searchWidget.ts index fba9afa5f1c..b0215734b21 100644 --- a/src/vs/workbench/parts/search/browser/searchWidget.ts +++ b/src/vs/workbench/parts/search/browser/searchWidget.ts @@ -11,7 +11,7 @@ import { Widget } from 'vs/base/browser/ui/widget'; import { Action } from 'vs/base/common/actions'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput'; -import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; +import { InputBox, IMessage } from 'vs/base/browser/ui/inputbox/inputBox'; import { Button } from 'vs/base/browser/ui/button/button'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -128,11 +128,6 @@ export class SearchWidget extends Widget { } public focus(select: boolean = true, focusReplace: boolean = false): void { - if ((!focusReplace && this.searchInput.inputBox.hasFocus()) - || (focusReplace && this.replaceInput.hasFocus())) { - return; - } - if (focusReplace && this.isReplaceShown()) { this.replaceInput.focus(); if (select) { @@ -225,11 +220,11 @@ export class SearchWidget extends Widget { private renderSearchInput(parent: HTMLElement, options: ISearchWidgetOptions): void { let inputOptions: IFindInputOptions = { label: nls.localize('label.Search', 'Search: Type Search Term and press Enter to search or Escape to cancel'), - validation: (value: string) => this.validatSearchInput(value), + validation: (value: string) => this.validateSearchInput(value), placeholder: nls.localize('search.placeHolder', "Search"), - appendCaseSensitiveLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybinding(Constants.ToggleCaseSensitiveActionId), this.keyBindingService2), - appendWholeWordsLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybinding(Constants.ToggleWholeWordActionId), this.keyBindingService2), - appendRegexLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybinding(Constants.ToggleRegexActionId), this.keyBindingService2) + appendCaseSensitiveLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybinding(Constants.ToggleCaseSensitiveCommandId), this.keyBindingService2), + appendWholeWordsLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybinding(Constants.ToggleWholeWordCommandId), this.keyBindingService2), + appendRegexLabel: appendKeyBindingLabel('', this.keyBindingService2.lookupKeybinding(Constants.ToggleRegexCommandId), this.keyBindingService2) }; let searchInputContainer = dom.append(parent, dom.$('.search-container.input-box')); @@ -314,7 +309,7 @@ export class SearchWidget extends Widget { } } - private validatSearchInput(value: string): any { + private validateSearchInput(value: string): IMessage { if (value.length === 0) { return null; } @@ -330,6 +325,12 @@ export class SearchWidget extends Widget { if (strings.regExpLeadsToEndlessLoop(regExp)) { return { content: nls.localize('regexp.validationFailure', "Expression matches everything") }; } + + if (strings.regExpContainsBackreference(value)) { + return { content: nls.localize('regexp.backreferenceValidationFailure', "Backreferences are not supported") }; + } + + return null; } private onSearchInputChanged(): void { diff --git a/src/vs/workbench/parts/search/common/constants.ts b/src/vs/workbench/parts/search/common/constants.ts index 68b0c417bbd..1a46fed10ea 100644 --- a/src/vs/workbench/parts/search/common/constants.ts +++ b/src/vs/workbench/parts/search/common/constants.ts @@ -8,7 +8,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const VIEWLET_ID = 'workbench.view.search'; export const FindInFilesActionId = 'workbench.action.findInFiles'; -export const FocusActiveEditorActionId = 'search.action.focusActiveEditor'; +export const FocusActiveEditorCommandId = 'search.action.focusActiveEditor'; export const FocusSearchFromResults = 'search.action.focusSearchFromResults'; export const OpenMatchToSide = 'search.action.openResultToSide'; @@ -16,10 +16,10 @@ export const CancelActionId = 'search.action.cancel'; export const RemoveActionId = 'search.action.remove'; export const ReplaceActionId = 'search.action.replace'; export const ReplaceAllInFileActionId = 'search.action.replaceAllInFile'; -export const ToggleCaseSensitiveActionId = 'toggleSearchCaseSensitive'; -export const ToggleWholeWordActionId = 'toggleSearchWholeWord'; -export const ToggleRegexActionId = 'toggleSearchRegex'; export const CloseReplaceWidgetActionId = 'closeReplaceInFilesWidget'; +export const ToggleCaseSensitiveCommandId = 'toggleSearchCaseSensitive'; +export const ToggleWholeWordCommandId = 'toggleSearchWholeWord'; +export const ToggleRegexCommandId = 'toggleSearchRegex'; export const SearchViewletVisibleKey = new RawContextKey('searchViewletVisible', true); export const InputBoxFocusedKey = new RawContextKey('inputBoxFocus', false); diff --git a/src/vs/workbench/parts/search/common/queryBuilder.ts b/src/vs/workbench/parts/search/common/queryBuilder.ts index e1d3f65cb28..72749033959 100644 --- a/src/vs/workbench/parts/search/common/queryBuilder.ts +++ b/src/vs/workbench/parts/search/common/queryBuilder.ts @@ -12,7 +12,7 @@ import * as glob from 'vs/base/common/glob'; import * as paths from 'vs/base/common/paths'; import * as strings from 'vs/base/common/strings'; import uri from 'vs/base/common/uri'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IPatternInfo, IQueryOptions, IFolderQuery, ISearchQuery, QueryType, ISearchConfiguration, getExcludes, pathIncludedInQuery } from 'vs/platform/search/common/search'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -46,7 +46,7 @@ export class QueryBuilder { let excludePattern = this.parseExcludePattern(options.excludePattern); // Build folderQueries from searchPaths, if given, otherwise folderResources - let folderQueries = folderResources && folderResources.map(uri => this.getFolderQueryForRoot(uri, options)); + let folderQueries = folderResources && folderResources.map(uri => this.getFolderQueryForRoot(uri, type === QueryType.File, options)); if (searchPaths && searchPaths.length) { const allRootExcludes = folderQueries && this.mergeExcludesFromFolderQueries(folderQueries); folderQueries = searchPaths.map(searchPath => this.getFolderQueryForSearchPath(searchPath)); @@ -56,10 +56,12 @@ export class QueryBuilder { } const useRipgrep = !folderResources || folderResources.every(folder => { - const folderConfig = this.configurationService.getConfiguration(undefined, { resource: folder }); + const folderConfig = this.configurationService.getConfiguration({ resource: folder }); return folderConfig.search.useRipgrep; }); + const ignoreSymlinks = !this.configurationService.getConfiguration().search.followSymlinks; + const query = { type, folderQueries, @@ -74,7 +76,8 @@ export class QueryBuilder { contentPattern: contentPattern, useRipgrep, disregardIgnoreFiles: options.disregardIgnoreFiles, - disregardExcludeSettings: options.disregardExcludeSettings + disregardExcludeSettings: options.disregardExcludeSettings, + ignoreSymlinks }; // Filter extraFileResources against global include/exclude patterns - they are already expected to not belong to a workspace @@ -184,7 +187,7 @@ export class QueryBuilder { * Split search paths (./ or absolute paths in the includePatterns) into absolute paths and globs applied to those paths */ private expandSearchPathPatterns(searchPaths: string[]): ISearchPathPattern[] { - if (!this.workspaceContextService.hasWorkspace() || !searchPaths || !searchPaths.length) { + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY || !searchPaths || !searchPaths.length) { // No workspace => ignore search paths return []; } @@ -195,7 +198,7 @@ export class QueryBuilder { const pathPortions = this.expandAbsoluteSearchPaths(pathPortion); return pathPortions.map(searchPath => { return { - searchPath: uri.file(searchPath), + searchPath, pattern: globPortion }; }); @@ -207,27 +210,27 @@ export class QueryBuilder { /** * Takes a searchPath like `./a/foo` and expands it to absolute paths for all the workspaces it matches. */ - private expandAbsoluteSearchPaths(searchPath: string): string[] { + private expandAbsoluteSearchPaths(searchPath: string): uri[] { if (paths.isAbsolute(searchPath)) { - return [paths.normalize(searchPath)]; + // Currently only local resources can be searched for with absolute search paths + return [uri.file(paths.normalize(searchPath))]; } - const workspace = this.workspaceContextService.getWorkspace(); - if (this.workspaceContextService.hasFolderWorkspace()) { - return [paths.normalize( - paths.join(workspace.roots[0].fsPath, searchPath))]; + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.FOLDER) { // TODO: @Sandy Try checking workspace folders length instead. + const workspaceUri = this.workspaceContextService.getWorkspace().folders[0].uri; + return [workspaceUri.with({ path: paths.normalize(paths.join(workspaceUri.path, searchPath)) })]; } else if (searchPath === './') { return []; // ./ or ./**/foo makes sense for single-folder but not multi-folder workspaces } else { const relativeSearchPathMatch = searchPath.match(/\.[\/\\]([^\/\\]+)([\/\\].+)?/); if (relativeSearchPathMatch) { const searchPathRoot = relativeSearchPathMatch[1]; - const matchingRoots = workspace.roots.filter(root => paths.basename(root.fsPath) === searchPathRoot); + const matchingRoots = this.workspaceContextService.getWorkspace().folders.filter(folder => paths.basename(folder.uri.fsPath) === searchPathRoot); if (matchingRoots.length) { return matchingRoots.map(root => { return relativeSearchPathMatch[2] ? - paths.normalize(paths.join(root.fsPath, relativeSearchPathMatch[2])) : - root.fsPath; + root.uri.with({ path: paths.normalize(paths.join(root.uri.path, relativeSearchPathMatch[2])) }) : + root.uri; }); } else { // No root folder with name @@ -244,7 +247,7 @@ export class QueryBuilder { private getFolderQueryForSearchPath(searchPath: ISearchPathPattern): IFolderQuery { const folder = searchPath.searchPath; - const folderConfig = this.configurationService.getConfiguration(undefined, { resource: folder }); + const folderConfig = this.configurationService.getConfiguration({ resource: folder }); return { folder, includePattern: searchPath.pattern && patternListToIExpression([searchPath.pattern]), @@ -252,12 +255,13 @@ export class QueryBuilder { }; } - private getFolderQueryForRoot(folder: uri, options?: IQueryOptions): IFolderQuery { - const folderConfig = this.configurationService.getConfiguration(undefined, { resource: folder }); + private getFolderQueryForRoot(folder: uri, perFolderUseIgnoreFiles: boolean, options?: IQueryOptions): IFolderQuery { + const folderConfig = this.configurationService.getConfiguration({ resource: folder }); return { folder, excludePattern: this.getExcludesForFolder(folderConfig, options), - fileEncoding: folderConfig.files && folderConfig.files.encoding + fileEncoding: folderConfig.files && folderConfig.files.encoding, + disregardIgnoreFiles: perFolderUseIgnoreFiles ? !folderConfig.search.useIgnoreFiles : undefined }; } } diff --git a/src/vs/workbench/parts/search/common/search.ts b/src/vs/workbench/parts/search/common/search.ts index a6f98af6b22..e2f821151e4 100644 --- a/src/vs/workbench/parts/search/common/search.ts +++ b/src/vs/workbench/parts/search/common/search.ts @@ -80,7 +80,15 @@ export interface IWorkbenchSearchConfiguration extends ISearchConfiguration { }, exclude: glob.IExpression, useRipgrep: boolean, - useIgnoreFilesByDefault: boolean + /** + * Use ignore file for text search. + */ + useIgnoreFilesByDefault: boolean, + /** + * Use ignore file for file search. + */ + useIgnoreFiles: boolean, + followSymlinks: boolean; }; } @@ -93,9 +101,9 @@ export function getOutOfWorkspaceEditorResources(editorGroupService: IEditorGrou editorGroupService.getStacksModel().groups.forEach(group => { const editors = group.getEditors(); editors.forEach(editor => { - const fileResource = toResource(editor, { supportSideBySide: true, filter: 'file' }); - if (fileResource && !contextService.isInsideWorkspace(fileResource)) { - resources.push(fileResource); + const resource = toResource(editor, { supportSideBySide: true }); + if (resource && !contextService.isInsideWorkspace(resource)) { + resources.push(resource); } }); }); diff --git a/src/vs/workbench/parts/search/common/searchModel.ts b/src/vs/workbench/parts/search/common/searchModel.ts index 3c3da515ec3..a3ada6ff325 100644 --- a/src/vs/workbench/parts/search/common/searchModel.ts +++ b/src/vs/workbench/parts/search/common/searchModel.ts @@ -11,8 +11,8 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { TPromise, PPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; -import { values, ResourceMap, TrieMap } from 'vs/base/common/map'; -import Event, { Emitter, fromPromise, stopwatch, any } from 'vs/base/common/event'; +import { values, ResourceMap, TernarySearchTree } from 'vs/base/common/map'; +import Event, { Emitter, fromPromise, stopwatch, anyEvent } from 'vs/base/common/event'; import { ISearchService, ISearchProgressItem, ISearchComplete, ISearchQuery, IPatternInfo, IFileMatch } from 'vs/platform/search/common/search'; import { ReplacePattern } from 'vs/platform/search/common/replace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -348,6 +348,7 @@ export class FolderMatch extends Disposable { private _unDisposedFileMatches: ResourceMap; private _replacingAll: boolean = false; + // @ts-ignore unused injected service constructor(private _resource: URI, private _id: string, private _index: number, private _query: ISearchQuery, private _parent: SearchResult, private _searchModel: SearchModel, @IReplaceService private replaceService: IReplaceService, @ITelemetryService private telemetryService: ITelemetryService, @IInstantiationService private instantiationService: IInstantiationService) { super(); @@ -496,7 +497,8 @@ export class SearchResult extends Disposable { public onChange: Event = this._onChange.event; private _folderMatches: FolderMatch[] = []; - private _folderMatchesMap: TrieMap = new TrieMap(); + private _folderMatchesMap: TernarySearchTree = TernarySearchTree.forPaths(); + // @ts-ignore unused property private _query: ISearchQuery = null; private _showHighlights: boolean; @@ -522,7 +524,7 @@ export class SearchResult extends Disposable { }); // otherFiles is the fallback for missing values in the TrieMap. So we do not insert it. this._folderMatches.slice(0, this.folderMatches.length - 1) - .forEach(fm => this._folderMatchesMap.insert(fm.resource().fsPath, fm)); + .forEach(fm => this._folderMatchesMap.set(fm.resource().fsPath, fm)); } public get searchModel(): SearchModel { @@ -568,6 +570,11 @@ export class SearchResult extends Disposable { const promise = this.replaceService.replace(this.matches(), progressRunner); const onDone = stopwatch(fromPromise(promise)); + /* __GDPR__ + "replaceAll.started" : { + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ onDone(duration => this.telemetryService.publicLog('replaceAll.started', { duration })); return promise.then(() => { @@ -654,7 +661,7 @@ export class SearchResult extends Disposable { private disposeMatches(): void { this._folderMatches.forEach(folderMatch => folderMatch.dispose()); this._folderMatches = []; - this._folderMatchesMap = new TrieMap(); + this._folderMatchesMap = TernarySearchTree.forPaths(); this._rangeHighlightDecorations.removeHighlightRange(); } @@ -723,13 +730,23 @@ export class SearchModel extends Disposable { const onDone = fromPromise(this.currentRequest); const progressEmitter = new Emitter(); - const onFirstRender = any(onDone, progressEmitter.event); + const onFirstRender = anyEvent(onDone, progressEmitter.event); const onFirstRenderStopwatch = stopwatch(onFirstRender); + /* __GDPR__ + "searchResultsFirstRender" : { + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ onFirstRenderStopwatch(duration => this.telemetryService.publicLog('searchResultsFirstRender', { duration })); const onDoneStopwatch = stopwatch(onDone); const start = Date.now(); + /* __GDPR__ + "searchResultsFinished" : { + "duration" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ onDoneStopwatch(duration => this.telemetryService.publicLog('searchResultsFinished', { duration })); const currentRequest = this.currentRequest; @@ -754,6 +771,15 @@ export class SearchModel extends Disposable { } const options: IPatternInfo = objects.assign({}, this._searchQuery.contentPattern); delete options.pattern; + /* __GDPR__ + "searchResultsShown" : { + "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "fileCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "options": { "${inline}": [ "${IPatternInfo}" ] }, + "duration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "useRipgrep": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('searchResultsShown', { count: this._searchResult.count(), fileCount: this._searchResult.fileCount(), diff --git a/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts b/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts index 3ccd1cc1896..f30f81170d3 100644 --- a/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts +++ b/src/vs/workbench/parts/search/test/browser/searchViewlet.test.ts @@ -14,6 +14,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { IModelService } from 'vs/editor/common/services/modelService'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { TestContextService } from 'vs/workbench/test/workbenchTestServices'; +import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; suite('Search - Viewlet', () => { let instantiation: TestInstantiationService; @@ -21,10 +24,11 @@ suite('Search - Viewlet', () => { setup(() => { instantiation = new TestInstantiationService(); instantiation.stub(IModelService, stubModelService(instantiation)); + instantiation.set(IWorkspaceContextService, new TestContextService(TestWorkspace)); }); test('Data Source', function () { - let ds = new SearchDataSource(); + let ds = instantiation.createInstance(SearchDataSource); let result: SearchResult = instantiation.createInstance(SearchResult, null); result.query = { type: 1, folderQueries: [{ folder: uri.parse('file://c:/') }] }; result.add([{ diff --git a/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts b/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts index 9a492fa3f65..5f5fa458e07 100644 --- a/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts +++ b/src/vs/workbench/parts/search/test/common/queryBuilder.test.ts @@ -11,7 +11,7 @@ import * as arrays from 'vs/base/common/arrays'; import uri from 'vs/base/common/uri'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { QueryBuilder, ISearchPathsResult } from 'vs/workbench/parts/search/common/queryBuilder'; import { TestContextService } from 'vs/workbench/test/workbenchTestServices'; @@ -37,7 +37,7 @@ suite('QueryBuilder', () => { instantiationService.stub(IConfigurationService, mockConfigService); mockContextService = new TestContextService(); - mockWorkspace = new Workspace('workspace', 'workspace', [ROOT_1_URI]); + mockWorkspace = new Workspace('workspace', 'workspace', toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }])); mockContextService.setWorkspace(mockWorkspace); instantiationService.stub(IWorkspaceContextService, mockContextService); @@ -154,7 +154,7 @@ suite('QueryBuilder', () => { const ROOT_2_URI = getUri(ROOT_2); const ROOT_3 = fixPath('/project/root3'); const ROOT_3_URI = getUri(ROOT_3); - mockWorkspace.roots = [ROOT_1_URI, ROOT_2_URI, ROOT_3_URI]; + mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: ROOT_2_URI.fsPath }, { path: ROOT_3_URI.fsPath }]); mockWorkspace.configuration = uri.file(fixPath('/config')); mockConfigService.setUserConfiguration('search', { @@ -356,12 +356,12 @@ suite('QueryBuilder', () => { includePattern); } - function testIncludesDataItem([includePattern, expectedResult]): void { - testIncludes(includePattern, expectedResult); + function testIncludesDataItem([includePattern, expectedResult]: [string, ISearchPathsResult]): void { + testIncludes(includePattern, expectedResult); } test('absolute includes', () => { - [ + const cases: [string, ISearchPathsResult][] = [ [ fixPath('/foo/bar'), { @@ -425,11 +425,12 @@ suite('QueryBuilder', () => { }] } ] - ].forEach(testIncludesDataItem); + ]; + cases.forEach(testIncludesDataItem); }); test('relative includes w/single root folder', () => { - [ + const cases: [string, ISearchPathsResult][] = [ [ './a', { @@ -468,15 +469,16 @@ suite('QueryBuilder', () => { }] } ], - ].forEach(testIncludesDataItem); + ]; + cases.forEach(testIncludesDataItem); }); test('relative includes w/two root folders', () => { const ROOT_2 = '/project/root2'; - mockWorkspace.roots = [ROOT_1_URI, getUri(ROOT_2)]; + mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: getUri(ROOT_2).fsPath }]); mockWorkspace.configuration = uri.file(fixPath('config')); - [ + const cases: [string, ISearchPathsResult][] = [ [ './root1', { @@ -507,16 +509,17 @@ suite('QueryBuilder', () => { }] } ] - ].forEach(testIncludesDataItem); + ]; + cases.forEach(testIncludesDataItem); }); test('relative includes w/multiple ambiguous root folders', () => { const ROOT_2 = '/project/rootB'; const ROOT_3 = '/otherproject/rootB'; - mockWorkspace.roots = [ROOT_1_URI, getUri(ROOT_2), getUri(ROOT_3)]; + mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: getUri(ROOT_2).fsPath }, { path: getUri(ROOT_3).fsPath }]); mockWorkspace.configuration = uri.file(fixPath('/config')); - [ + const cases: [string, ISearchPathsResult][] = [ [ '', { @@ -579,7 +582,8 @@ suite('QueryBuilder', () => { }] } ] - ].forEach(testIncludesDataItem); + ]; + cases.forEach(testIncludesDataItem); }); }); }); @@ -594,6 +598,8 @@ function assertEqualQueries(actual: ISearchQuery, expected: ISearchQuery): void }; }; + delete actual.ignoreSymlinks; + // Avoid comparing URI objects, not a good idea if (expected.folderQueries) { assert.deepEqual(actual.folderQueries.map(folderQueryToCompareObject), expected.folderQueries.map(folderQueryToCompareObject)); diff --git a/src/vs/workbench/parts/search/test/common/searchModel.test.ts b/src/vs/workbench/parts/search/test/common/searchModel.test.ts index c969aa57335..315d2b182fe 100644 --- a/src/vs/workbench/parts/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/parts/search/test/common/searchModel.test.ts @@ -44,7 +44,7 @@ const nullEvent = new class { suite('SearchModel', () => { let instantiationService: TestInstantiationService; - let restoreStubs; + let restoreStubs: sinon.SinonStub[]; const testSearchStats: IUncachedSearchStats = { fromCache: false, @@ -306,7 +306,7 @@ suite('SearchModel', () => { return { preview, lineNumber, offsetAndLengths }; } - function stub(arg1, arg2, arg3): sinon.SinonStub { + function stub(arg1: any, arg2: any, arg3: any): sinon.SinonStub { const stub = sinon.stub(arg1, arg2, arg3); restoreStubs.push(stub); return stub; diff --git a/src/vs/workbench/parts/snippets/electron-browser/TMSnippets.ts b/src/vs/workbench/parts/snippets/electron-browser/TMSnippets.ts deleted file mode 100644 index 65e7fd1eba1..00000000000 --- a/src/vs/workbench/parts/snippets/electron-browser/TMSnippets.ts +++ /dev/null @@ -1,199 +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 nls from 'vs/nls'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { parse } from 'vs/base/common/json'; -import { join } from 'path'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { readFile } from 'vs/base/node/pfs'; -import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; -import { ISnippetsService, ISnippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; -import { LanguageIdentifier } from 'vs/editor/common/modes'; -import { SnippetParser, Placeholder, Variable, Text } from 'vs/editor/contrib/snippet/browser/snippetParser'; -import { EditorSnippetVariableResolver } from 'vs/editor/contrib/snippet/browser/snippetVariables'; - -interface ISnippetsExtensionPoint { - language: string; - path: string; -} - -let snippetsExtensionPoint = ExtensionsRegistry.registerExtensionPoint('snippets', [languagesExtPoint], { - description: nls.localize('vscode.extension.contributes.snippets', 'Contributes snippets.'), - type: 'array', - defaultSnippets: [{ body: [{ language: '', path: '' }] }], - items: { - type: 'object', - defaultSnippets: [{ body: { language: '${1:id}', path: './snippets/${2:id}.json.' } }], - properties: { - language: { - description: nls.localize('vscode.extension.contributes.snippets-language', 'Language identifier for which this snippet is contributed to.'), - type: 'string' - }, - path: { - description: nls.localize('vscode.extension.contributes.snippets-path', 'Path of the snippets file. The path is relative to the extension folder and typically starts with \'./snippets/\'.'), - type: 'string' - } - } - } -}); - -export class MainProcessTextMateSnippet implements IWorkbenchContribution { - - constructor( - @IModeService private _modeService: IModeService, - @ISnippetsService private _snippetService: ISnippetsService - ) { - snippetsExtensionPoint.setHandler((extensions) => { - for (let i = 0; i < extensions.length; i++) { - let tmSnippets = extensions[i].value; - for (let j = 0; j < tmSnippets.length; j++) { - this._withSnippetContribution(extensions[i].description.name, extensions[i].description.extensionFolderPath, tmSnippets[j], extensions[i].collector); - } - } - }); - } - - getId() { - return 'tmSnippetExtension'; - } - - private _withSnippetContribution(extensionName: string, extensionFolderPath: string, snippet: ISnippetsExtensionPoint, collector: ExtensionMessageCollector): void { - if (!snippet.language || (typeof snippet.language !== 'string') || !this._modeService.isRegisteredMode(snippet.language)) { - collector.error(nls.localize('invalid.language', "Unknown language in `contributes.{0}.language`. Provided value: {1}", snippetsExtensionPoint.name, String(snippet.language))); - return; - } - if (!snippet.path || (typeof snippet.path !== 'string')) { - collector.error(nls.localize('invalid.path.0', "Expected string in `contributes.{0}.path`. Provided value: {1}", snippetsExtensionPoint.name, String(snippet.path))); - return; - } - let normalizedAbsolutePath = join(extensionFolderPath, snippet.path); - - if (normalizedAbsolutePath.indexOf(extensionFolderPath) !== 0) { - collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", snippetsExtensionPoint.name, normalizedAbsolutePath, extensionFolderPath)); - } - - let modeId = snippet.language; - let languageIdentifier = this._modeService.getLanguageIdentifier(modeId); - if (languageIdentifier) { - readAndRegisterSnippets(this._snippetService, languageIdentifier, normalizedAbsolutePath, extensionName, collector); - } - } -} - -export function readAndRegisterSnippets( - snippetService: ISnippetsService, languageIdentifier: LanguageIdentifier, filePath: string, - extensionName?: string, collector?: ExtensionMessageCollector -): TPromise { - - return readFile(filePath).then(fileContents => { - let snippets = parseSnippetFile(fileContents.toString(), extensionName, collector); - snippetService.registerSnippets(languageIdentifier.id, snippets, filePath); - }, err => { - if (err && err.code === 'ENOENT') { - snippetService.registerSnippets(languageIdentifier.id, [], filePath); - } else { - throw err; - } - }); -} - -function parseSnippetFile(snippetFileContent: string, extensionName?: string, collector?: ExtensionMessageCollector): ISnippet[] { - let snippetsObj = parse(snippetFileContent); - if (!snippetsObj || typeof snippetsObj !== 'object') { - return []; - } - - let topLevelProperties = Object.keys(snippetsObj); - let result: ISnippet[] = []; - - let processSnippet = (snippet: any, name: string) => { - let prefix = snippet['prefix']; - let body = snippet['body']; - - if (Array.isArray(body)) { - body = body.join('\n'); - } - - if (typeof prefix !== 'string' || typeof body !== 'string') { - return; - } - - snippet = { - name, - extensionName, - prefix, - description: snippet['description'] || name, - codeSnippet: body - }; - - const didRewrite = _rewriteBogousVariables(snippet); - if (didRewrite && collector) { - collector.warn(nls.localize( - 'badVariableUse', - "The \"{0}\"-snippet very likely confuses snippet-variables and snippet-placeholders. See https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax for more details.", - name - )); - } - - result.push(snippet); - }; - - topLevelProperties.forEach(topLevelProperty => { - let scopeOrTemplate = snippetsObj[topLevelProperty]; - if (scopeOrTemplate['body'] && scopeOrTemplate['prefix']) { - processSnippet(scopeOrTemplate, topLevelProperty); - } else { - let snippetNames = Object.keys(scopeOrTemplate); - snippetNames.forEach(name => { - processSnippet(scopeOrTemplate[name], name); - }); - } - }); - return result; -} - -export function _rewriteBogousVariables(snippet: ISnippet): boolean { - const textmateSnippet = new SnippetParser().parse(snippet.codeSnippet, false); - - let placeholders = new Map(); - let placeholderMax = 0; - for (const placeholder of textmateSnippet.placeholders) { - placeholderMax = Math.max(placeholderMax, placeholder.index); - } - - let didChange = false; - let stack = [...textmateSnippet.children]; - - while (stack.length > 0) { - let marker = stack.shift(); - - if ( - marker instanceof Variable - && marker.children.length === 0 - && !EditorSnippetVariableResolver.VariableNames[marker.name] - ) { - // a 'variable' without a default value and not being one of our supported - // variables is automatically turing into a placeholder. This is to restore - // a bug we had before. So `${foo}` becomes `${N:foo}` - const index = placeholders.has(marker.name) ? placeholders.get(marker.name) : ++placeholderMax; - placeholders.set(marker.name, index); - - const synthetic = new Placeholder(index).appendChild(new Text(marker.name)); - textmateSnippet.replace(marker, [synthetic]); - didChange = true; - - } else { - // recurse - stack.push(...marker.children); - } - } - - snippet.codeSnippet = textmateSnippet.toTextmateString(); - return didChange; -} diff --git a/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts b/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts index 7443d483fb6..37bd918e9d4 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.ts @@ -12,12 +12,12 @@ import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/ import { IModeService } from 'vs/editor/common/services/modeService'; import { LanguageId } from 'vs/editor/common/modes'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { ISnippetsService, ISnippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; +import { ISnippetsService, Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; interface ISnippetPick extends IPickOpenEntry { - snippet: ISnippet; + snippet: Snippet; } class Args { @@ -52,6 +52,7 @@ class Args { } @editorAction +// @ts-ignore @editorAction uses the class class InsertSnippetAction extends EditorAction { constructor() { @@ -75,16 +76,16 @@ class InsertSnippetAction extends EditorAction { const { lineNumber, column } = editor.getPosition(); let { snippet, name, langId } = Args.fromUser(arg); - return new TPromise((resolve, reject) => { + return new TPromise(async (resolve, reject) => { if (snippet) { - return resolve({ - codeSnippet: snippet, - description: undefined, - name: undefined, - extensionName: undefined, - prefix: undefined - }); + return resolve(new Snippet( + undefined, + undefined, + undefined, + snippet, + undefined + )); } let languageId: LanguageId; @@ -105,7 +106,7 @@ class InsertSnippetAction extends EditorAction { if (name) { // take selected snippet - snippetService.visitSnippets(languageId, snippet => { + (await snippetService.getSnippets(languageId)).every(snippet => { if (snippet.name !== name) { return true; } @@ -114,15 +115,23 @@ class InsertSnippetAction extends EditorAction { }); } else { // let user pick a snippet + const snippets = (await snippetService.getSnippets(languageId)).sort(Snippet.compare); const picks: ISnippetPick[] = []; - snippetService.visitSnippets(languageId, snippet => { - picks.push({ + let prevSnippet: Snippet; + for (const snippet of snippets) { + const pick: ISnippetPick = { label: snippet.prefix, detail: snippet.description, snippet - }); - return true; - }); + }; + if (!snippet.isFromExtension && !prevSnippet) { + pick.separator = { label: nls.localize('sep.userSnippet', "User Snippets") }; + } else if (snippet.isFromExtension && (!prevSnippet || !prevSnippet.isFromExtension)) { + pick.separator = { label: nls.localize('sep.extSnippet', "Extension Snippets") }; + } + picks.push(pick); + prevSnippet = snippet; + } return quickOpenService.pick(picks, { matchOnDetail: true }).then(pick => resolve(pick && pick.snippet), reject); } }).then(snippet => { diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts b/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts index e2e6cb6a263..b262f72df95 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts @@ -3,11 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; - -import 'vs/workbench/parts/snippets/electron-browser/snippetsService'; -import 'vs/workbench/parts/snippets/electron-browser/insertSnippet'; -import 'vs/workbench/parts/snippets/electron-browser/tabCompletion'; - import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { fileExists, writeFile } from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -21,13 +16,125 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as errors from 'vs/base/common/errors'; import * as JSONContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import * as nls from 'vs/nls'; -import * as snippetsTracker from './snippetsTracker'; -import * as tmSnippets from './TMSnippets'; -import * as winjs from 'vs/base/common/winjs.base'; -import * as workbenchContributions from 'vs/workbench/common/contributions'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { LanguageId } from 'vs/editor/common/modes'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { SnippetParser, Variable, Placeholder, Text } from 'vs/editor/contrib/snippet/browser/snippetParser'; +import { EditorSnippetVariableResolver } from 'vs/editor/contrib/snippet/browser/snippetVariables'; -namespace OpenSnippetsAction { +export const ISnippetsService = createDecorator('snippetService'); +export interface ISnippetsService { + + _serviceBrand: any; + + getSnippets(languageId: LanguageId): Promise; + + getSnippetsSync(languageId: LanguageId): Snippet[]; +} + + +export class Snippet { + + private _codeSnippet: string; + private _isBogous: boolean; + + constructor( + readonly name: string, + readonly prefix: string, + readonly description: string, + readonly body: string, + readonly source: string, + readonly isFromExtension?: boolean, + ) { + // + } + + get codeSnippet(): string { + this._ensureCodeSnippet(); + return this._codeSnippet; + } + + get isBogous(): boolean { + this._ensureCodeSnippet(); + return this._isBogous; + } + + private _ensureCodeSnippet() { + if (!this._codeSnippet) { + const rewrite = Snippet._rewriteBogousVariables(this.body); + if (typeof rewrite === 'string') { + this._codeSnippet = rewrite; + this._isBogous = true; + } else { + this._codeSnippet = this.body; + this._isBogous = false; + } + } + } + + static compare(a: Snippet, b: Snippet): number { + if (a.isFromExtension !== b.isFromExtension) { + if (a.isFromExtension) { + return 1; + } else { + return -1; + } + } else if (a.name > b.name) { + return 1; + } else if (a.name < b.name) { + return -1; + } else { + return 0; + } + } + + static _rewriteBogousVariables(template: string): false | string { + const textmateSnippet = new SnippetParser().parse(template, false); + + let placeholders = new Map(); + let placeholderMax = 0; + for (const placeholder of textmateSnippet.placeholders) { + placeholderMax = Math.max(placeholderMax, placeholder.index); + } + + let didChange = false; + let stack = [...textmateSnippet.children]; + + while (stack.length > 0) { + let marker = stack.shift(); + + if ( + marker instanceof Variable + && marker.children.length === 0 + && !EditorSnippetVariableResolver.VariableNames[marker.name] + ) { + // a 'variable' without a default value and not being one of our supported + // variables is automatically turned into a placeholder. This is to restore + // a bug we had before. So `${foo}` becomes `${N:foo}` + const index = placeholders.has(marker.name) ? placeholders.get(marker.name) : ++placeholderMax; + placeholders.set(marker.name, index); + + const synthetic = new Placeholder(index).appendChild(new Text(marker.name)); + textmateSnippet.replace(marker, [synthetic]); + didChange = true; + + } else { + // recurse + stack.push(...marker.children); + } + } + + if (!didChange) { + return false; + } else { + return textmateSnippet.toTextmateString(); + } + } +} + + +{ const id = 'workbench.action.openSnippets'; CommandsRegistry.registerCommand(id, accessor => { @@ -37,7 +144,7 @@ namespace OpenSnippetsAction { const environmentService = accessor.get(IEnvironmentService); const windowsService = accessor.get(IWindowsService); - function openFile(filePath: string): winjs.TPromise { + function openFile(filePath: string): TPromise { return windowsService.openWindow([filePath], { forceReuseWindow: true }); } @@ -86,7 +193,7 @@ namespace OpenSnippetsAction { }); }); } - return winjs.TPromise.as(null); + return TPromise.as(null); }); }); @@ -136,11 +243,3 @@ const schema: IJSONSchema = { Registry .as(JSONContributionRegistry.Extensions.JSONContribution) .registerSchema(schemaId, schema); - -Registry - .as(workbenchContributions.Extensions.Workbench) - .registerWorkbenchContribution(snippetsTracker.SnippetsTracker); - -Registry - .as(workbenchContributions.Extensions.Workbench) - .registerWorkbenchContribution(tmSnippets.MainProcessTextMateSnippet); diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippetsFile.ts b/src/vs/workbench/parts/snippets/electron-browser/snippetsFile.ts new file mode 100644 index 00000000000..3ee4e82d60b --- /dev/null +++ b/src/vs/workbench/parts/snippets/electron-browser/snippetsFile.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { readFile } from 'vs/base/node/pfs'; +import { parse as jsonParse } from 'vs/base/common/json'; +import { forEach } from 'vs/base/common/collections'; +import { Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; + +interface JsonSerializedSnippet { + body: string; + prefix: string | string[]; + description: string; +} + +function isJsonSerilziedSnippet(thing: any): thing is JsonSerializedSnippet { + return Boolean((thing).body) && Boolean((thing).prefix); +} + +interface JsonSerializedSnippets { + [name: string]: JsonSerializedSnippet | { [name: string]: JsonSerializedSnippet }; +} + +export class SnippetFile { + + private constructor( + readonly filepath: string, + readonly data: Snippet[] + ) { + // + } + + static fromFile(filepath: string, source: string, isFromExtension?: boolean): Promise { + return Promise.resolve(readFile(filepath)).then(value => { + const data = jsonParse(value.toString()); + const snippets: Snippet[] = []; + if (typeof data === 'object') { + forEach(data, entry => { + const { key: name, value: scopeOrTemplate } = entry; + if (isJsonSerilziedSnippet(scopeOrTemplate)) { + SnippetFile._parseSnippet(name, scopeOrTemplate, source, isFromExtension, snippets); + } else { + forEach(scopeOrTemplate, entry => { + const { key: name, value: template } = entry; + SnippetFile._parseSnippet(name, template, source, isFromExtension, snippets); + }); + } + }); + } + return new SnippetFile(filepath, snippets); + }); + } + + private static _parseSnippet(name: string, snippet: JsonSerializedSnippet, source: string, isFromExtension: boolean, bucket: Snippet[]): void { + + let { prefix, body, description } = snippet; + + if (Array.isArray(body)) { + body = body.join('\n'); + } + + if (typeof prefix !== 'string' || typeof body !== 'string') { + return; + } + + bucket.push(new Snippet( + name, + prefix, + description, + body, + source, + isFromExtension + )); + } +} diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts b/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts index 0af3c024910..8f062847599 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/snippetsService.ts @@ -7,75 +7,257 @@ import { localize } from 'vs/nls'; import { IModel } from 'vs/editor/common/editorCommon'; import { ISuggestSupport, ISuggestResult, ISuggestion, LanguageId, SuggestionType, SnippetType } from 'vs/editor/common/modes'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { setSnippetSuggestSupport } from 'vs/editor/contrib/suggest/browser/suggest'; import { IModeService } from 'vs/editor/common/services/modeService'; import { Position } from 'vs/editor/common/core/position'; import { overlap, compare, startsWith } from 'vs/base/common/strings'; import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { join } from 'path'; +import { mkdirp } from 'vs/base/node/pfs'; +import { watch } from 'fs'; +import { SnippetFile } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile'; +import { Snippet, ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { ExtensionsRegistry, IExtensionPointUser } from 'vs/platform/extensions/common/extensionsRegistry'; +import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; +import { MarkdownString } from 'vs/base/common/htmlContent'; -export const ISnippetsService = createDecorator('snippetService'); +namespace schema { -export interface ISnippetsService { + export interface ISnippetsExtensionPoint { + language: string; + path: string; + } - _serviceBrand: any; + export function isValidSnippet(extension: IExtensionPointUser, snippet: ISnippetsExtensionPoint, modeService: IModeService): boolean { + if (!snippet.language || (typeof snippet.language !== 'string') || !modeService.isRegisteredMode(snippet.language)) { + extension.collector.error(localize( + 'invalid.language', + "Unknown language in `contributes.{0}.language`. Provided value: {1}", + extension.description.name, String(snippet.language) + )); + return false; - registerSnippets(languageId: LanguageId, snippets: ISnippet[], owner: string): void; + } else if (!snippet.path || (typeof snippet.path !== 'string')) { + extension.collector.error(localize( + 'invalid.path.0', + "Expected string in `contributes.{0}.path`. Provided value: {1}", + extension.description.name, String(snippet.path) + )); + return false; - visitSnippets(languageId: LanguageId, accept: (snippet: ISnippet) => boolean): void; + } else { + const normalizedAbsolutePath = join(extension.description.extensionFolderPath, snippet.path); + if (normalizedAbsolutePath.indexOf(extension.description.extensionFolderPath) !== 0) { + extension.collector.error(localize( + 'invalid.path.1', + "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", + extension.description.name, normalizedAbsolutePath, extension.description.extensionFolderPath + )); + return false; + } - getSnippets(languageId: LanguageId): ISnippet[]; + snippet.path = normalizedAbsolutePath; + return true; + } + } + + export const snippetsContribution: IJSONSchema = { + description: localize('vscode.extension.contributes.snippets', 'Contributes snippets.'), + type: 'array', + defaultSnippets: [{ body: [{ language: '', path: '' }] }], + items: { + type: 'object', + defaultSnippets: [{ body: { language: '${1:id}', path: './snippets/${2:id}.json.' } }], + properties: { + language: { + description: localize('vscode.extension.contributes.snippets-language', 'Language identifier for which this snippet is contributed to.'), + type: 'string' + }, + path: { + description: localize('vscode.extension.contributes.snippets-path', 'Path of the snippets file. The path is relative to the extension folder and typically starts with \'./snippets/\'.'), + type: 'string' + } + } + } + }; } -export interface ISnippet { - name: string; - prefix: string; - description: string; - codeSnippet: string; - extensionName?: string; -} +class SnippetsService implements ISnippetsService { -export class SnippetsService implements ISnippetsService { + readonly _serviceBrand: any; - _serviceBrand: any; - - private readonly _snippets = new Map>(); + private readonly _pendingExtensionSnippets = new Map, string][]>(); + private readonly _extensionSnippets = new Map(); + private readonly _userSnippets = new Map(); + private readonly _userSnippetsFolder: string; + private readonly _wait: Promise; + private readonly _disposables: IDisposable[] = []; constructor( - @IModeService modeService: IModeService + @IModeService private readonly _modeService: IModeService, + @IEnvironmentService private readonly _environmentService: IEnvironmentService, + @IExtensionService extensionService: IExtensionService, ) { - setSnippetSuggestSupport(new SnippetSuggestProvider(modeService, this)); + this._wait = Promise.resolve(extensionService.onReady()); + this._userSnippetsFolder = join(_environmentService.appSettingsHome, 'snippets'); + this._prepUserSnippetsWatching(); + this._prepExtensionSnippets(); + + setSnippetSuggestSupport(new SnippetSuggestProvider(this._modeService, this)); } - registerSnippets(languageId: LanguageId, snippets: ISnippet[], fileName: string): void { - if (!this._snippets.has(languageId)) { - this._snippets.set(languageId, new Map()); + dispose(): void { + dispose(this._disposables); + } + + getSnippets(languageId: LanguageId): Promise { + let result: Snippet[] = []; + return this._wait.then(() => { + return this._getOrLoadUserSnippets(languageId, result); + }).then(() => { + return this._getOrLoadExtensionSnippets(languageId, result); + }).then(() => { + return result; + }); + } + + getSnippetsSync(languageId: LanguageId): Snippet[] { + // just kick off snippet loading for this language such + // that subsequent calls to this method return more + // correct results + this.getSnippets(languageId).catch(undefined); + + // collect and return what we already have + const userSnippets = this._userSnippets.get(languageId); + const extensionSnippets = this._extensionSnippets.get(languageId); + + if (userSnippets && extensionSnippets) { + return userSnippets.concat(extensionSnippets); + } else if (!userSnippets) { + return extensionSnippets; + } else if (!extensionSnippets) { + return userSnippets; + } else { + return undefined; } - this._snippets.get(languageId).set(fileName, snippets); } - visitSnippets(languageId: LanguageId, accept: (snippet: ISnippet) => boolean): void { - const modeSnippets = this._snippets.get(languageId); - if (modeSnippets) { - modeSnippets.forEach(snippets => { - let result = snippets.every(accept); - if (!result) { - return; + // --- extension snippet logic --- + + private _prepExtensionSnippets(): void { + ExtensionsRegistry.registerExtensionPoint('snippets', [languagesExtPoint], schema.snippetsContribution).setHandler(extensions => { + for (const extension of extensions) { + for (const contribution of extension.value) { + if (schema.isValidSnippet(extension, contribution, this._modeService)) { + const { id } = this._modeService.getLanguageIdentifier(contribution.language); + const array = this._pendingExtensionSnippets.get(id); + if (!array) { + this._pendingExtensionSnippets.set(id, [[extension, contribution.path]]); + } else { + array.push([extension, contribution.path]); + } + } + } + } + }); + } + + private _getOrLoadExtensionSnippets(languageId: LanguageId, bucket: Snippet[]): Promise { + + if (this._extensionSnippets.has(languageId)) { + bucket.push(...this._extensionSnippets.get(languageId)); + return undefined; + + } else if (this._pendingExtensionSnippets.has(languageId)) { + const pending = this._pendingExtensionSnippets.get(languageId); + this._pendingExtensionSnippets.delete(languageId); + + const snippets = []; + this._extensionSnippets.set(languageId, snippets); + + return Promise.all(pending.map(([extension, filepath]) => { + return SnippetFile.fromFile(filepath, extension.description.displayName || extension.description.name, true).then(file => { + + // collect + snippets.push(...file.data); + bucket.push(...file.data); + + // warn about bad tabstop/variable usage + if (this._environmentService.isExtensionDevelopment && file.data.some(snippet => snippet.isBogous)) { + extension.collector.warn(localize( + 'badVariableUse', + "One or more snippets from the extension '{0}' very likely confuse snippet-variables and snippet-placeholders (see https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax for more details)", + extension.description.name + )); + } + + }, err => { + // generic error + extension.collector.warn(localize( + 'badFile', + "The snippet file \"{0}\" could not be read.", + filepath + )); + }); + })).then(() => { + + }); + + } else { + return undefined; + } + } + + // --- user snippet logic --- + + private _getOrLoadUserSnippets(languageId: LanguageId, bucket: Snippet[]): Promise { + let snippets = this._userSnippets.get(languageId); + if (snippets) { + // has data + bucket.push(...snippets); + return undefined; + + } else if (snippets === undefined) { + // not yet loaded + return SnippetFile.fromFile(this._getUserSnippetFilepath(languageId), localize('source.snippet', "User Snippet")).then(file => { + this._userSnippets.set(languageId, file.data); + }, err => { + this._userSnippets.set(languageId, null); + }); + + } else { + // previous failure + return undefined; + } + } + + private _getUserSnippetFilepath(languageId: LanguageId): string { + const { language } = this._modeService.getLanguageIdentifier(languageId); + const filepath = join(this._userSnippetsFolder, `${language}.json`); + return filepath; + } + + private _prepUserSnippetsWatching(): void { + // Install a FS watcher on the snippet directory and when an + // event occurs delete any cached snippet information + mkdirp(this._userSnippetsFolder).then(() => { + const watcher = watch(this._userSnippetsFolder); + this._disposables.push({ dispose: () => watcher.close() }); + watcher.on('change', (type, filename) => { + if (typeof filename === 'string') { + const language = filename.replace(/\.json$/, '').toLowerCase(); + const languageId = this._modeService.getLanguageIdentifier(language); + if (languageId) { + this._userSnippets.delete(languageId.id); + } } }); - } - } - - getSnippets(languageId: LanguageId): ISnippet[] { - const modeSnippets = this._snippets.get(languageId); - const ret: ISnippet[] = []; - if (modeSnippets) { - modeSnippets.forEach(snippets => { - ret.push(...snippets); - }); - } - return ret; + }); } } @@ -87,35 +269,33 @@ export interface ISimpleModel { export class SnippetSuggestion implements ISuggestion { - private static _userSnippet = localize('source.snippet', "User Snippet"); - label: string; detail: string; insertText: string; - documentation: string; + documentation: MarkdownString; overwriteBefore: number; sortText: string; noAutoAccept: boolean; type: SuggestionType; snippetType: SnippetType; - constructor( - readonly snippet: ISnippet, + readonly snippet: Snippet, overwriteBefore: number ) { this.label = snippet.prefix; - this.detail = localize('detail.snippet', "{0} ({1})", snippet.description, snippet.extensionName || SnippetSuggestion._userSnippet); - this.insertText = snippet.codeSnippet; + this.detail = localize('detail.snippet', "{0} ({1})", snippet.description, snippet.source); + this.insertText = snippet.body; this.overwriteBefore = overwriteBefore; - this.sortText = `${snippet.prefix}-${snippet.extensionName || ''}`; + this.sortText = `${snippet.isFromExtension ? 'z' : 'a'}-${snippet.prefix}`; this.noAutoAccept = true; this.type = 'snippet'; this.snippetType = 'textmate'; } resolve(): this { - this.documentation = new SnippetParser().text(this.snippet.codeSnippet); + this.documentation = new MarkdownString().appendCodeblock('', new SnippetParser().text(this.snippet.codeSnippet)); + this.insertText = this.snippet.codeSnippet; return this; } @@ -134,49 +314,51 @@ export class SnippetSuggestProvider implements ISuggestSupport { // } - provideCompletionItems(model: IModel, position: Position): ISuggestResult { + provideCompletionItems(model: IModel, position: Position): Promise { const languageId = this._getLanguageIdAtPosition(model, position); - const snippets = this._snippets.getSnippets(languageId); - const suggestions: SnippetSuggestion[] = []; + return this._snippets.getSnippets(languageId).then(snippets => { - const lowWordUntil = model.getWordUntilPosition(position).word.toLowerCase(); - const lowLineUntil = model.getLineContent(position.lineNumber).substr(Math.max(0, position.column - 100), position.column - 1).toLowerCase(); + const suggestions: SnippetSuggestion[] = []; - for (const snippet of snippets) { + const lowWordUntil = model.getWordUntilPosition(position).word.toLowerCase(); + const lowLineUntil = model.getLineContent(position.lineNumber).substr(Math.max(0, position.column - 100), position.column - 1).toLowerCase(); - const lowPrefix = snippet.prefix.toLowerCase(); - let overwriteBefore = 0; - let accetSnippet = true; + for (const snippet of snippets) { - if (lowWordUntil.length > 0 && startsWith(lowPrefix, lowWordUntil)) { - // cheap match on the (none-empty) current word - overwriteBefore = lowWordUntil.length; - accetSnippet = true; + const lowPrefix = snippet.prefix.toLowerCase(); + let overwriteBefore = 0; + let accetSnippet = true; - } else if (lowLineUntil.length > 0 && lowLineUntil.match(/[^\s]$/)) { - // compute overlap between snippet and (none-empty) line on text - overwriteBefore = overlap(lowLineUntil, snippet.prefix.toLowerCase()); - accetSnippet = overwriteBefore > 0 && !model.getWordAtPosition(new Position(position.lineNumber, position.column - overwriteBefore)); + if (lowWordUntil.length > 0 && startsWith(lowPrefix, lowWordUntil)) { + // cheap match on the (none-empty) current word + overwriteBefore = lowWordUntil.length; + accetSnippet = true; + + } else if (lowLineUntil.length > 0 && lowLineUntil.match(/[^\s]$/)) { + // compute overlap between snippet and (none-empty) line on text + overwriteBefore = overlap(lowLineUntil, snippet.prefix.toLowerCase()); + accetSnippet = overwriteBefore > 0 && !model.getWordAtPosition(new Position(position.lineNumber, position.column - overwriteBefore)); + } + + if (accetSnippet) { + suggestions.push(new SnippetSuggestion(snippet, overwriteBefore)); + } } - if (accetSnippet) { - suggestions.push(new SnippetSuggestion(snippet, overwriteBefore)); + // dismbiguate suggestions with same labels + let lastItem: SnippetSuggestion; + for (const item of suggestions.sort(SnippetSuggestion.compareByLabel)) { + if (lastItem && lastItem.label === item.label) { + // use the disambiguateLabel instead of the actual label + lastItem.label = localize('snippetSuggest.longLabel', "{0}, {1}", lastItem.label, lastItem.snippet.name); + item.label = localize('snippetSuggest.longLabel', "{0}, {1}", item.label, item.snippet.name); + } + lastItem = item; } - } - // dismbiguate suggestions with same labels - let lastItem: SnippetSuggestion; - for (const item of suggestions.sort(SnippetSuggestion.compareByLabel)) { - if (lastItem && lastItem.label === item.label) { - // use the disambiguateLabel instead of the actual label - lastItem.label = localize('snippetSuggest.longLabel', "{0}, {1}", lastItem.label, lastItem.snippet.name); - item.label = localize('snippetSuggest.longLabel', "{0}, {1}", item.label, item.snippet.name); - } - lastItem = item; - } - - return { suggestions }; + return { suggestions }; + }); } resolveCompletionItem?(model: IModel, position: Position, item: ISuggestion): ISuggestion { diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippetsTracker.ts b/src/vs/workbench/parts/snippets/electron-browser/snippetsTracker.ts deleted file mode 100644 index 2ecbc3150fb..00000000000 --- a/src/vs/workbench/parts/snippets/electron-browser/snippetsTracker.ts +++ /dev/null @@ -1,68 +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 { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { join } from 'path'; -import { mkdirp, fileExists } from 'vs/base/node/pfs'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { readAndRegisterSnippets } from './TMSnippets'; -import { ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { watch } from 'fs'; -import { IModeService } from 'vs/editor/common/services/modeService'; - -export class SnippetsTracker implements IWorkbenchContribution { - - private readonly _snippetFolder: string; - private readonly _toDispose: IDisposable[]; - - constructor( - @IModeService modeService: IModeService, - @ISnippetsService snippetService: ISnippetsService, - @IEnvironmentService environmentService: IEnvironmentService, - @IExtensionService extensionService: IExtensionService - ) { - this._snippetFolder = join(environmentService.appSettingsHome, 'snippets'); - this._toDispose = []; - - // Whenever a mode is being created check if a snippet file exists - // and iff so read all snippets from it. - this._toDispose.push(modeService.onDidCreateMode(mode => { - const snippetPath = join(this._snippetFolder, `${mode.getId()}.json`); - fileExists(snippetPath) - .then(exists => exists && readAndRegisterSnippets(snippetService, mode.getLanguageIdentifier(), snippetPath)) - .done(undefined, onUnexpectedError); - })); - - // Install a FS watcher on the snippet directory and when an - // event occurs update the snippets for that one snippet. - mkdirp(this._snippetFolder).then(() => { - const watcher = watch(this._snippetFolder); - this._toDispose.push({ dispose: () => watcher.close() }); - watcher.on('change', (type, filename) => { - if (typeof filename !== 'string') { - return; - } - extensionService.onReady().then(() => { - const langName = filename.replace(/\.json$/, '').toLowerCase(); - const langId = modeService.getLanguageIdentifier(langName); - return langId && readAndRegisterSnippets(snippetService, langId, join(this._snippetFolder, filename)); - }, onUnexpectedError); - }); - }); - } - - getId(): string { - return 'vs.snippets.snippetsTracker'; - } - - dispose(): void { - dispose(this._toDispose); - } -} diff --git a/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts b/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts index 71a2e2fda5a..620afaa6156 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/tabCompletion.ts @@ -7,18 +7,21 @@ import { localize } from 'vs/nls'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { RawContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey, IContextKeyService, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ISnippetsService, getNonWhitespacePrefix, ISnippet, SnippetSuggestion } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; +import { ISnippetsService, Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; +import { getNonWhitespacePrefix, SnippetSuggestion } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; import { Registry } from 'vs/platform/registry/common/platform'; import { endsWith } from 'vs/base/common/strings'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as editorCommon from 'vs/editor/common/editorCommon'; +import { Range } from 'vs/editor/common/core/range'; import { CommonEditorRegistry, commonEditorContribution, EditorCommand } from 'vs/editor/common/editorCommonExtensions'; import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2'; import { showSimpleSuggestions } from 'vs/editor/contrib/suggest/browser/suggest'; import { IConfigurationRegistry, Extensions as ConfigExt } from 'vs/platform/configuration/common/configurationRegistry'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @commonEditorContribution export class TabCompletionController implements editorCommon.IEditorContribution { @@ -30,46 +33,24 @@ export class TabCompletionController implements editorCommon.IEditorContribution return editor.getContribution(TabCompletionController.ID); } - private readonly _editor: editorCommon.ICommonCodeEditor; - private readonly _snippetController: SnippetController2; - private readonly _dispoables: IDisposable[] = []; - private readonly _snippets: ISnippet[] = []; + private _hasSnippets: IContextKey; + private _activeSnippets: Snippet[] = []; + private _selectionListener: IDisposable; + private _configListener: IDisposable; constructor( - editor: editorCommon.ICommonCodeEditor, + private readonly _editor: editorCommon.ICommonCodeEditor, + @ISnippetsService private readonly _snippetService: ISnippetsService, + @IConfigurationService private readonly _configurationService: IConfigurationService, @IContextKeyService contextKeyService: IContextKeyService, - @ISnippetsService snippetService: ISnippetsService ) { - this._editor = editor; - this._snippetController = SnippetController2.get(editor); - - const hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService); - this._dispoables.push(editor.onDidChangeCursorSelection(e => { - - this._snippets.length = 0; - let selectFn: (snippet: ISnippet) => boolean; - - if (e.selection.isEmpty()) { - // empty selection -> real text (no whitespace) left of cursor - const prefix = getNonWhitespacePrefix(editor.getModel(), editor.getPosition()); - selectFn = prefix && (snippet => endsWith(prefix, snippet.prefix)); - - } else { - // actual selection -> snippet must be a full match - const selected = editor.getModel().getValueInRange(e.selection); - selectFn = snippet => selected === snippet.prefix; + this._hasSnippets = TabCompletionController.ContextKey.bindTo(contextKeyService); + this._configListener = this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.tabCompletion')) { + this._update(); } - - if (selectFn) { - snippetService.visitSnippets(editor.getModel().getLanguageIdentifier().id, s => { - if (selectFn(s)) { - this._snippets.push(s); - } - return true; - }); - } - hasSnippets.set(this._snippets.length > 0); - })); + }); + this._update(); } getId(): string { @@ -77,19 +58,76 @@ export class TabCompletionController implements editorCommon.IEditorContribution } dispose(): void { - dispose(this._dispoables); + dispose(this._configListener); + dispose(this._selectionListener); + } + + private _update(): void { + const enabled = this._configurationService.getValue('editor.tabCompletion'); + if (!enabled) { + dispose(this._selectionListener); + } else { + this._selectionListener = this._editor.onDidChangeCursorSelection(e => this._updateSnippets()); + if (this._editor.getModel()) { + this._updateSnippets(); + } + } + } + + private _updateSnippets(): void { + + // reset first + this._activeSnippets = []; + + // lots of dance for getting the + const selection = this._editor.getSelection(); + const model = this._editor.getModel(); + model.tokenizeIfCheap(selection.positionLineNumber); + const id = model.getLanguageIdAtPosition(selection.positionLineNumber, selection.positionColumn); + const snippets = this._snippetService.getSnippetsSync(id); + + if (!snippets) { + // nothing for this language + this._hasSnippets.set(false); + return; + } + + if (Range.isEmpty(selection)) { + // empty selection -> real text (no whitespace) left of cursor + const prefix = getNonWhitespacePrefix(model, selection.getPosition()); + if (prefix) { + for (const snippet of snippets) { + if (endsWith(prefix, snippet.prefix)) { + this._activeSnippets.push(snippet); + } + } + } + + } else if (!Range.spansMultipleLines(selection) && model.getValueLengthInRange(selection) <= 100) { + // actual selection -> snippet must be a full match + const selected = model.getValueInRange(selection); + if (selected) { + for (const snippet of snippets) { + if (selected === snippet.prefix) { + this._activeSnippets.push(snippet); + } + } + } + } + + this._hasSnippets.set(this._activeSnippets.length > 0); } performSnippetCompletions(): void { - if (this._snippets.length === 1) { + if (this._activeSnippets.length === 1) { // one -> just insert - const [snippet] = this._snippets; - this._snippetController.insert(snippet.codeSnippet, snippet.prefix.length, 0); + const [snippet] = this._activeSnippets; + SnippetController2.get(this._editor).insert(snippet.codeSnippet, snippet.prefix.length, 0); - } else if (this._snippets.length > 1) { + } else if (this._activeSnippets.length > 1) { // two or more -> show IntelliSense box - showSimpleSuggestions(this._editor, this._snippets.map(snippet => new SnippetSuggestion(snippet, snippet.prefix.length))); + showSimpleSuggestions(this._editor, this._activeSnippets.map(snippet => new SnippetSuggestion(snippet, snippet.prefix.length))); } } } @@ -105,8 +143,7 @@ CommonEditorRegistry.registerEditorCommand(new TabCompletionCommand({ kbExpr: ContextKeyExpr.and( EditorContextKeys.textFocus, EditorContextKeys.tabDoesNotMoveFocus, - SnippetController2.InSnippetMode.toNegated(), - ContextKeyExpr.has('config.editor.tabCompletion') + SnippetController2.InSnippetMode.toNegated() ), primary: KeyCode.Tab } diff --git a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts index c25a99ad46a..ab171d24f38 100644 --- a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts +++ b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsRewrite.test.ts @@ -6,20 +6,19 @@ 'use strict'; import * as assert from 'assert'; -import { _rewriteBogousVariables } from 'vs/workbench/parts/snippets/electron-browser/TMSnippets'; +import { Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; -suite('TMSnippets', function () { +suite('SnippetRewrite', function () { - function assertRewrite(input: string, expected: string): void { - let snippet = { codeSnippet: input, description: undefined, extensionName: undefined, name: undefined, prefix: undefined }; - _rewriteBogousVariables(snippet); - assert.equal(snippet.codeSnippet, expected); + function assertRewrite(input: string, expected: string | boolean): void { + const actual = Snippet._rewriteBogousVariables(input); + assert.equal(actual, expected); } test('bogous variable rewrite', function () { - assertRewrite('foo', 'foo'); - assertRewrite('hello $1 world$0', 'hello $1 world$0'); + assertRewrite('foo', false); + assertRewrite('hello $1 world$0', false); assertRewrite('$foo and $foo', '${1:foo} and ${1:foo}'); assertRewrite('$1 and $SELECTION and $foo', '$1 and ${SELECTION} and ${2:foo}'); @@ -42,6 +41,13 @@ suite('TMSnippets', function () { }); test('Snippet choices: unable to escape comma and pipe, #31521', function () { - assertRewrite('console.log(${1|not\\, not, five, 5, 1 23|});', 'console.log(${1|not\\, not, five, 5, 1 23|});'); + assertRewrite('console.log(${1|not\\, not, five, 5, 1 23|});', false); + }); + + test('lazy bogous variable rewrite', function () { + const snippet = new Snippet('foo', 'prefix', 'desc', 'This is ${bogous} because it is a ${var}', 'source'); + assert.equal(snippet.body, 'This is ${bogous} because it is a ${var}'); + assert.equal(snippet.codeSnippet, 'This is ${1:bogous} because it is a ${2:var}'); + assert.equal(snippet.isBogous, true); }); }); diff --git a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts index e179467e64e..6093d376ea2 100644 --- a/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts +++ b/src/vs/workbench/parts/snippets/test/electron-browser/snippetsService.test.ts @@ -6,11 +6,24 @@ 'use strict'; import * as assert from 'assert'; -import { SnippetsService, ISnippet, SnippetSuggestProvider } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; +import { SnippetSuggestProvider } from 'vs/workbench/parts/snippets/electron-browser/snippetsService'; import { Position } from 'vs/editor/common/core/position'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { Model } from 'vs/editor/common/model/model'; +import { ISnippetsService, Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; + +class SimpleSnippetService implements ISnippetsService { + _serviceBrand: any; + constructor(readonly snippets: Snippet[]) { + } + getSnippets() { + return Promise.resolve(this.getSnippetsSync()); + } + getSnippetsSync(): Snippet[] { + return this.snippets; + } +} suite('SnippetsService', function () { @@ -22,34 +35,35 @@ suite('SnippetsService', function () { }); let modeService: ModeServiceImpl; - let snippetService: SnippetsService; + let snippetService: ISnippetsService; setup(function () { modeService = new ModeServiceImpl(); - snippetService = new SnippetsService(modeService); - - snippetService.registerSnippets(modeService.getLanguageIdentifier('fooLang').id, [{ - prefix: 'bar', - codeSnippet: 'barCodeSnippet', - name: 'barTest', - description: '' - }, { - prefix: 'bazz', - codeSnippet: 'bazzCodeSnippet', - name: 'bazzTest', - description: '' - }], 'fooFile.json'); + snippetService = new SimpleSnippetService([new Snippet( + 'barTest', + 'bar', + '', + 'barCodeSnippet', + '' + ), new Snippet( + 'bazzTest', + 'bazz', + '', + 'bazzCodeSnippet', + '' + )]); }); + test('snippet completions - simple', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); const model = Model.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang')); - const result = provider.provideCompletionItems(model, new Position(1, 1)); - - assert.equal(result.incomplete, undefined); - assert.equal(result.suggestions.length, 2); + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { + assert.equal(result.incomplete, undefined); + assert.equal(result.suggestions.length, 2); + }); }); test('snippet completions - with prefix', function () { @@ -57,56 +71,91 @@ suite('SnippetsService', function () { const provider = new SnippetSuggestProvider(modeService, snippetService); const model = Model.createFromString('bar', undefined, modeService.getLanguageIdentifier('fooLang')); - const result = provider.provideCompletionItems(model, new Position(1, 4)); - - assert.equal(result.incomplete, undefined); - assert.equal(result.suggestions.length, 1); - assert.equal(result.suggestions[0].label, 'bar'); - assert.equal(result.suggestions[0].insertText, 'barCodeSnippet'); + return provider.provideCompletionItems(model, new Position(1, 4)).then(result => { + assert.equal(result.incomplete, undefined); + assert.equal(result.suggestions.length, 1); + assert.equal(result.suggestions[0].label, 'bar'); + assert.equal(result.suggestions[0].insertText, 'barCodeSnippet'); + }); }); test('Cannot use "[{ - prefix: ' { + assert.equal(result.suggestions.length, 1); + model.dispose(); - model = Model.createFromString('\t { + assert.equal(result.suggestions.length, 1); + model.dispose(); - model = Model.createFromString('a { + + assert.equal(result.suggestions.length, 0); + model.dispose(); + }); }); test('No user snippets in suggestions, when inside the code, #30508', function () { - snippetService.registerSnippets(modeService.getLanguageIdentifier('fooLang').id, [{ - prefix: 'foo', - codeSnippet: '$0', - name: '', - description: '' - }], 'fooFile.json'); + snippetService = new SimpleSnippetService([new Snippet( + '', + 'foo', + '', + '$0', + '' + )]); const provider = new SnippetSuggestProvider(modeService, snippetService); let model = Model.createFromString('\n\t\n>/head>', undefined, modeService.getLanguageIdentifier('fooLang')); - let result = provider.provideCompletionItems(model, new Position(1, 1)); - assert.equal(result.suggestions.length, 1); + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { + assert.equal(result.suggestions.length, 1); + return provider.provideCompletionItems(model, new Position(2, 2)); + }).then(result => { + assert.equal(result.suggestions.length, 1); + }); + }); - result = provider.provideCompletionItems(model, new Position(2, 2)); - assert.equal(result.suggestions.length, 1); + test('SnippetSuggest - ensure extension snippets come last ', function () { + snippetService = new SimpleSnippetService([new Snippet( + 'second', + 'second', + '', + 'second', + '', + true + ), new Snippet( + 'first', + 'first', + '', + 'first', + '', + false + )]); + + const provider = new SnippetSuggestProvider(modeService, snippetService); + + let model = Model.createFromString('', undefined, modeService.getLanguageIdentifier('fooLang')); + return provider.provideCompletionItems(model, new Position(1, 1)).then(result => { + assert.equal(result.suggestions.length, 2); + let [first, second] = result.suggestions; + assert.equal(first.label, 'first'); + assert.equal(second.label, 'second'); + }); }); }); diff --git a/src/vs/workbench/parts/surveys/electron-browser/languageSurveys.contribution.ts b/src/vs/workbench/parts/surveys/electron-browser/languageSurveys.contribution.ts index 483374be65f..3fa92e9391e 100644 --- a/src/vs/workbench/parts/surveys/electron-browser/languageSurveys.contribution.ts +++ b/src/vs/workbench/parts/surveys/electron-browser/languageSurveys.contribution.ts @@ -88,6 +88,7 @@ class LanguageSurvey { const message = nls.localize('helpUs', "Help us improve our support for {0}", data.languageId); const takeSurveyAction = new Action('takeSurvey', nls.localize('takeShortSurvey', "Take Short Survey"), '', true, () => { + // __GDPR__TODO__ Need to move away from dynamic event names as those cannot be registered statically telemetryService.publicLog(`${data.surveyId}.survey/takeShortSurvey`); return telemetryService.getTelemetryInfo().then(info => { window.open(`${data.surveyUrl}?o=${encodeURIComponent(process.platform)}&v=${encodeURIComponent(pkg.version)}&m=${encodeURIComponent(info.machineId)}`); @@ -97,12 +98,14 @@ class LanguageSurvey { }); const remindMeLaterAction = new Action('later', nls.localize('remindLater', "Remind Me later"), '', true, () => { + // __GDPR__TODO__ Need to move away from dynamic event names as those cannot be registered statically telemetryService.publicLog(`${data.surveyId}.survey/remindMeLater`); storageService.store(SESSION_COUNT_KEY, sessionCount - 3, StorageScope.GLOBAL); return TPromise.as(null); }); const neverAgainAction = new Action('never', nls.localize('neverAgain', "Don't Show Again"), '', true, () => { + // __GDPR__TODO__ Need to move away from dynamic event names as those cannot be registered statically telemetryService.publicLog(`${data.surveyId}.survey/dontShowAgain`); storageService.store(IS_CANDIDATE_KEY, false, StorageScope.GLOBAL); storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL); @@ -110,6 +113,7 @@ class LanguageSurvey { }); const actions = [neverAgainAction, remindMeLaterAction, takeSurveyAction]; + // __GDPR__TODO__ Need to move away from dynamic event names as those cannot be registered statically telemetryService.publicLog(`${data.surveyId}.survey/userAsked`); messageService.show(Severity.Info, { message, actions }); } @@ -118,6 +122,7 @@ class LanguageSurvey { class LanguageSurveysContribution implements IWorkbenchContribution { + // @ts-ignore unused property private surveys: LanguageSurvey[]; constructor( diff --git a/src/vs/workbench/parts/tasks/browser/quickOpen.ts b/src/vs/workbench/parts/tasks/browser/quickOpen.ts index 2f64e812655..141fde0334b 100644 --- a/src/vs/workbench/parts/tasks/browser/quickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/quickOpen.ts @@ -4,15 +4,15 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import nls = require('vs/nls'); -import Filters = require('vs/base/common/filters'); +import * as nls from 'vs/nls'; +import * as Filters from 'vs/base/common/filters'; import { TPromise } from 'vs/base/common/winjs.base'; import { Action, IAction } from 'vs/base/common/actions'; import { IStringDictionary } from 'vs/base/common/collections'; -import Quickopen = require('vs/workbench/browser/quickopen'); -import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen'); -import Model = require('vs/base/parts/quickopen/browser/quickOpenModel'); +import * as Quickopen from 'vs/workbench/browser/quickopen'; +import * as QuickOpen from 'vs/base/parts/quickopen/common/quickOpen'; +import * as Model from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Task, CustomTask, ContributedTask } from 'vs/workbench/parts/tasks/common/tasks'; @@ -21,7 +21,7 @@ import { ActionBarContributor, ContributableActionProvider } from 'vs/workbench/ export class TaskEntry extends Model.QuickOpenEntry { - constructor(protected taskService: ITaskService, protected quickOpenService: IQuickOpenService, protected _task: CustomTask | ContributedTask, highlights: Model.IHighlight[] = []) { + constructor(protected quickOpenService: IQuickOpenService, protected taskService: ITaskService, protected _task: CustomTask | ContributedTask, highlights: Model.IHighlight[] = []) { super(highlights); } @@ -29,6 +29,17 @@ export class TaskEntry extends Model.QuickOpenEntry { return this.task._label; } + public getDescription(): string { + if (!this.taskService.needsFolderQualification()) { + return null; + } + let workspaceFolder = Task.getWorkspaceFolder(this.task); + if (!workspaceFolder) { + return null; + } + return `${workspaceFolder.name}`; + } + public getAriaLabel(): string { return nls.localize('entryAriaLabel', "{0}, tasks", this.getLabel()); } @@ -87,7 +98,12 @@ export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler { let configured: CustomTask[] = []; let detected: ContributedTask[] = []; let taskMap: IStringDictionary = Object.create(null); - tasks.forEach(task => taskMap[Task.getKey(task)] = task); + tasks.forEach(task => { + let key = Task.getRecentlyUsedKey(task); + if (key) { + taskMap[key] = task; + } + }); recentlyUsedTasks.keys().forEach(key => { let task = taskMap[key]; if (task) { @@ -95,7 +111,8 @@ export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler { } }); for (let task of tasks) { - if (!recentlyUsedTasks.has(Task.getKey(task))) { + let key = Task.getRecentlyUsedKey(task); + if (!key || !recentlyUsedTasks.has(key)) { if (CustomTask.is(task)) { configured.push(task); } else { @@ -103,12 +120,13 @@ export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler { } } } + const sorter = this.taskService.createSorter(); let hasRecentlyUsed: boolean = recent.length > 0; this.fillEntries(entries, input, recent, nls.localize('recentlyUsed', 'recently used tasks')); - configured = configured.sort((a, b) => a._label.localeCompare(b._label)); + configured = configured.sort((a, b) => sorter.compare(a, b)); let hasConfigured = configured.length > 0; this.fillEntries(entries, input, configured, nls.localize('configured', 'configured tasks'), hasRecentlyUsed); - detected = detected.sort((a, b) => a._label.localeCompare(b._label)); + detected = detected.sort((a, b) => sorter.compare(a, b)); this.fillEntries(entries, input, detected, nls.localize('detected', 'detected tasks'), hasRecentlyUsed || hasConfigured); return new Model.QuickOpenModel(entries, new ContributableActionProvider()); }); @@ -146,7 +164,7 @@ class CustomizeTaskAction extends Action { private static ID = 'workbench.action.tasks.customizeTask'; private static LABEL = nls.localize('customizeTask', "Configure Task"); - constructor(private taskService: ITaskService, private quickOpenService: IQuickOpenService, private task: CustomTask | ContributedTask) { + constructor(private taskService: ITaskService, private quickOpenService: IQuickOpenService) { super(CustomizeTaskAction.ID, CustomizeTaskAction.LABEL); this.updateClass(); } @@ -155,23 +173,36 @@ class CustomizeTaskAction extends Action { this.class = 'quick-open-task-configure'; } - public run(context: any): TPromise { - if (ContributedTask.is(this.task)) { - return this.taskService.customize(this.task, undefined, true).then(() => { + public run(element: any): TPromise { + let task = this.getTask(element); + if (ContributedTask.is(task)) { + return this.taskService.customize(task, undefined, true).then(() => { this.quickOpenService.close(); }); } else { - return this.taskService.openConfig(this.task).then(() => { + return this.taskService.openConfig(task).then(() => { this.quickOpenService.close(); }); } } + + private getTask(element: any): CustomTask | ContributedTask { + if (element instanceof TaskEntry) { + return element.task; + } else if (element instanceof TaskGroupEntry) { + return (element.getEntry() as TaskEntry).task; + } + return undefined; + } } export class QuickOpenActionContributor extends ActionBarContributor { - constructor( @ITaskService private taskService: ITaskService, @IQuickOpenService private quickOpenService: IQuickOpenService) { + private action: CustomizeTaskAction; + + constructor( @ITaskService taskService: ITaskService, @IQuickOpenService quickOpenService: IQuickOpenService) { super(); + this.action = new CustomizeTaskAction(taskService, quickOpenService); } public hasActions(context: any): boolean { @@ -184,7 +215,7 @@ export class QuickOpenActionContributor extends ActionBarContributor { let actions: Action[] = []; let task = this.getTask(context); if (task && ContributedTask.is(task) || CustomTask.is(task)) { - actions.push(new CustomizeTaskAction(this.taskService, this.quickOpenService, task)); + actions.push(this.action); } return actions; } diff --git a/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts b/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts index 46d3c023200..cc997ea08ad 100644 --- a/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/taskQuickOpen.ts @@ -14,12 +14,11 @@ import { CustomTask, ContributedTask } from 'vs/workbench/parts/tasks/common/tas import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; - import * as base from './quickOpen'; class TaskEntry extends base.TaskEntry { - constructor(taskService: ITaskService, quickOpenService: IQuickOpenService, task: CustomTask | ContributedTask, highlights: Model.IHighlight[] = []) { - super(taskService, quickOpenService, task, highlights); + constructor(quickOpenService: IQuickOpenService, taskService: ITaskService, task: CustomTask | ContributedTask, highlights: Model.IHighlight[] = []) { + super(quickOpenService, taskService, task, highlights); } public run(mode: QuickOpen.Mode, context: Model.IContext): boolean { @@ -32,12 +31,15 @@ class TaskEntry extends base.TaskEntry { } export class QuickOpenHandler extends base.QuickOpenHandler { + + public static readonly ID = 'workbench.picker.tasks'; + private activationPromise: TPromise; constructor( @IQuickOpenService quickOpenService: IQuickOpenService, - @ITaskService taskService: ITaskService, - @IExtensionService extensionService: IExtensionService + @IExtensionService extensionService: IExtensionService, + @ITaskService taskService: ITaskService ) { super(quickOpenService, taskService); this.activationPromise = extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'); @@ -54,7 +56,7 @@ export class QuickOpenHandler extends base.QuickOpenHandler { } protected createEntry(task: CustomTask | ContributedTask, highlights: Model.IHighlight[]): base.TaskEntry { - return new TaskEntry(this.taskService, this.quickOpenService, task, highlights); + return new TaskEntry(this.quickOpenService, this.taskService, task, highlights); } public getEmptyLabel(searchString: string): string { diff --git a/src/vs/workbench/parts/tasks/common/problemCollectors.ts b/src/vs/workbench/parts/tasks/common/problemCollectors.ts index e886d8ef1a9..f3f4621ab7e 100644 --- a/src/vs/workbench/parts/tasks/common/problemCollectors.ts +++ b/src/vs/workbench/parts/tasks/common/problemCollectors.ts @@ -284,6 +284,11 @@ export class AbstractProblemCollector extends EventEmitter implements IDisposabl } return result; } + + protected cleanMarkerCaches(): void { + this.markers.clear(); + this.deliveredMarkers.clear(); + } } export enum ProblemHandlingStrategy { @@ -292,17 +297,15 @@ export enum ProblemHandlingStrategy { export class StartStopProblemCollector extends AbstractProblemCollector implements IProblemMatcher { private owners: string[]; - private strategy: ProblemHandlingStrategy; private currentOwner: string; private currentResource: string; - constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, strategy: ProblemHandlingStrategy = ProblemHandlingStrategy.Clean) { + constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, _strategy: ProblemHandlingStrategy = ProblemHandlingStrategy.Clean) { super(problemMatchers, markerService, modelService); let ownerSet: { [key: string]: boolean; } = Object.create(null); problemMatchers.forEach(description => ownerSet[description.owner] = true); this.owners = Object.keys(ownerSet); - this.strategy = strategy; this.owners.forEach((owner) => { this.recordResourcesToClean(owner); }); @@ -410,6 +413,7 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement if (matches) { result = true; this.emit(ProblemCollectorEvents.WatchingBeginDetected, {}); + this.cleanMarkerCaches(); this.resetCurrentResource(); let owner = beginMatcher.problemMatcher.owner; let file = matches[beginMatcher.pattern.file]; @@ -435,6 +439,7 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement let owner = endMatcher.problemMatcher.owner; this.resetCurrentResource(); this.cleanMarkers(owner); + this.cleanMarkerCaches(); } } return result; diff --git a/src/vs/workbench/parts/tasks/common/taskDefinitionRegistry.ts b/src/vs/workbench/parts/tasks/common/taskDefinitionRegistry.ts index f4ec7371520..77406c82d73 100644 --- a/src/vs/workbench/parts/tasks/common/taskDefinitionRegistry.ts +++ b/src/vs/workbench/parts/tasks/common/taskDefinitionRegistry.ts @@ -47,7 +47,7 @@ namespace Configuration { properties?: IJSONSchemaMap; } - export function from(value: TaskDefinition, messageCollector: ExtensionMessageCollector): Tasks.TaskDefinition { + export function from(value: TaskDefinition, extensionId: string, messageCollector: ExtensionMessageCollector): Tasks.TaskDefinition { if (!value) { return undefined; } @@ -64,7 +64,7 @@ namespace Configuration { } } } - return { taskType, required: required.length >= 0 ? required : undefined, properties: value.properties ? Objects.deepClone(value.properties) : undefined }; + return { extensionId, taskType, required: required.length >= 0 ? required : undefined, properties: value.properties ? Objects.deepClone(value.properties) : undefined }; } } @@ -93,15 +93,15 @@ class TaskDefinitionRegistryImpl implements ITaskDefinitionRegistry { this.readyPromise = new TPromise((resolve, reject) => { taskDefinitionsExtPoint.setHandler((extensions) => { try { - extensions.forEach(extension => { + for (let extension of extensions) { let taskTypes = extension.value; for (let taskType of taskTypes) { - let type = Configuration.from(taskType, extension.collector); + let type = Configuration.from(taskType, extension.description.id, extension.collector); if (type) { this.taskTypes[type.taskType] = type; } } - }); + } } catch (error) { } resolve(undefined); diff --git a/src/vs/workbench/parts/tasks/common/taskService.ts b/src/vs/workbench/parts/tasks/common/taskService.ts index 7598b170398..fbff0809463 100644 --- a/src/vs/workbench/parts/tasks/common/taskService.ts +++ b/src/vs/workbench/parts/tasks/common/taskService.ts @@ -9,7 +9,9 @@ import { Action } from 'vs/base/common/actions'; import { IEventEmitter } from 'vs/base/common/eventEmitter'; import { LinkedMap } from 'vs/base/common/map'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Task, ContributedTask, CustomTask, TaskSet } from 'vs/workbench/parts/tasks/common/tasks'; + +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { Task, ContributedTask, CustomTask, TaskSet, TaskSorter } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskSummary, TaskEvent, TaskType, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem'; export { ITaskSummary, Task, TaskEvent, TaskType, TaskTerminateResponse }; @@ -44,22 +46,24 @@ export interface ITaskService extends IEventEmitter { rebuild(): TPromise; clean(): TPromise; runTest(): TPromise; - run(task: string | Task, options?: RunOptions): TPromise; + run(task: Task, options?: RunOptions): TPromise; inTerminal(): boolean; isActive(): TPromise; getActiveTasks(): TPromise; - restart(task: string | Task): void; - terminate(task: string | Task): TPromise; + restart(task: Task): void; + terminate(task: Task): TPromise; terminateAll(): TPromise; tasks(): TPromise; /** * @param identifier The task's name, label or defined identifier. */ - getTask(identifier: string): TPromise; + getTask(workspaceFolder: IWorkspaceFolder | string, identifier: string): TPromise; getTasksForGroup(group: string): TPromise; getRecentlyUsedTasks(): LinkedMap; + createSorter(): TaskSorter; - canCustomize(): boolean; + needsFolderQualification(); + canCustomize(task: ContributedTask | CustomTask): boolean; customize(task: ContributedTask | CustomTask, properties?: {}, openConfig?: boolean): TPromise; openConfig(task: CustomTask): TPromise; diff --git a/src/vs/workbench/parts/tasks/common/taskSystem.ts b/src/vs/workbench/parts/tasks/common/taskSystem.ts index 98a11040d6a..e36ec0e4160 100644 --- a/src/vs/workbench/parts/tasks/common/taskSystem.ts +++ b/src/vs/workbench/parts/tasks/common/taskSystem.ts @@ -8,6 +8,9 @@ import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; import { TerminateResponse } from 'vs/base/common/processes'; import { IEventEmitter } from 'vs/base/common/eventEmitter'; + +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; + import { Task } from './tasks'; export enum TaskErrors { @@ -33,6 +36,16 @@ export class TaskError { } } +/* __GDPR__FRAGMENT__ + "TelemetryEvent" : { + "trigger" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "runner": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "taskKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "command": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "success": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "exitCode": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ export interface TelemetryEvent { // How the task got trigger. Is either shortcut or command trigger: string; @@ -101,7 +114,7 @@ export interface TaskEvent { } export interface ITaskResolver { - resolve(identifier: string): Task; + resolve(workspaceFolder: IWorkspaceFolder, identifier: string): Task; } export interface TaskTerminateResponse extends TerminateResponse { @@ -114,7 +127,7 @@ export interface ITaskSystem extends IEventEmitter { isActiveSync(): boolean; getActiveTasks(): Task[]; canAutoTerminate(): boolean; - terminate(id: string): TPromise; + terminate(task: Task): TPromise; terminateAll(): TPromise; revealTask(task: Task): boolean; } \ No newline at end of file diff --git a/src/vs/workbench/parts/tasks/common/taskTemplates.ts b/src/vs/workbench/parts/tasks/common/taskTemplates.ts index 6165c13bc0a..df05e9c58f0 100644 --- a/src/vs/workbench/parts/tasks/common/taskTemplates.ts +++ b/src/vs/workbench/parts/tasks/common/taskTemplates.ts @@ -27,7 +27,7 @@ const dotnetBuild: TaskEntry = { '\t"version": "2.0.0",', '\t"tasks": [', '\t\t{', - '\t\t\t"taskName": "build",', + '\t\t\t"label": "build",', '\t\t\t"command": "dotnet build",', '\t\t\t"type": "shell",', '\t\t\t"group": "build",', @@ -53,8 +53,8 @@ const msbuild: TaskEntry = { '\t"version": "2.0.0",', '\t"tasks": [', '\t\t{', - '\t\t\t"taskName": "build",', - '\t\t\t"type": "process",', + '\t\t\t"label": "build",', + '\t\t\t"type": "shell",', '\t\t\t"command": "msbuild",', '\t\t\t"args": [', '\t\t\t\t// Ask msbuild to generate full paths for file names.', @@ -86,7 +86,7 @@ const command: TaskEntry = { '\t"version": "2.0.0",', '\t"tasks": [', '\t\t{', - '\t\t\t"taskName": "echo",', + '\t\t\t"label": "echo",', '\t\t\t"type": "shell",', '\t\t\t"command": "echo Hello"', '\t\t}', @@ -108,7 +108,7 @@ const maven: TaskEntry = { '\t"version": "2.0.0",', '\t"tasks": [', '\t\t{', - '\t\t\t"taskName": "verify",', + '\t\t\t"label": "verify",', '\t\t\t"type": "shell",', '\t\t\t"command": "mvn -B verify",', '\t\t\t"group": "build"', diff --git a/src/vs/workbench/parts/tasks/common/tasks.ts b/src/vs/workbench/parts/tasks/common/tasks.ts index fd9b28ce2d5..5b0ca37df20 100644 --- a/src/vs/workbench/parts/tasks/common/tasks.ts +++ b/src/vs/workbench/parts/tasks/common/tasks.ts @@ -4,11 +4,14 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import URI from 'vs/base/common/uri'; import * as Types from 'vs/base/common/types'; import { IJSONSchemaMap } from 'vs/base/common/jsonSchema'; +import * as Objects from 'vs/base/common/objects'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ProblemMatcher } from 'vs/platform/markers/common/problemMatcher'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export interface ShellConfiguration { /** @@ -215,43 +218,66 @@ export namespace TaskGroup { export type TaskGroup = 'clean' | 'build' | 'rebuild' | 'test'; +export enum TaskScope { + Global = 1, + Workspace = 2, + Folder = 3 +} + export namespace TaskSourceKind { export const Workspace: 'workspace' = 'workspace'; export const Extension: 'extension' = 'extension'; - export const Composite: 'composite' = 'composite'; + export const InMemory: 'inMemory' = 'inMemory'; } export interface TaskSourceConfigElement { + workspaceFolder: IWorkspaceFolder; file: string; index: number; element: any; } export interface WorkspaceTaskSource { - kind: 'workspace'; - label: string; - config: TaskSourceConfigElement; - customizes?: TaskIdentifier; + readonly kind: 'workspace'; + readonly label: string; + readonly config: TaskSourceConfigElement; + readonly customizes?: TaskIdentifier; } export interface ExtensionTaskSource { - kind: 'extension'; - label: string; - extension: string; + readonly kind: 'extension'; + readonly label: string; + readonly extension: string; + readonly scope: TaskScope; + readonly workspaceFolder: IWorkspaceFolder | undefined; } -export interface CompositeTaskSource { - kind: 'composite'; - label: string; +export interface ExtensionTaskSourceTransfer { + __workspaceFolder: URI; } -export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | CompositeTaskSource; +export interface InMemoryTaskSource { + readonly kind: 'inMemory'; + readonly label: string; +} + +export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | InMemoryTaskSource; export interface TaskIdentifier { _key: string; type: string; } +export interface TaskDependency { + workspaceFolder: IWorkspaceFolder; + task: string; +} + +export enum GroupType { + default = 'default', + user = 'user' +} + export interface ConfigurationProperties { /** @@ -270,9 +296,9 @@ export interface ConfigurationProperties { group?: string; /** - * Whether this task is a primary task in the task group. + * The group type */ - isDefaultGroupEntry?: boolean; + groupType?: GroupType; /** * The presentation options @@ -292,7 +318,7 @@ export interface ConfigurationProperties { /** * The other tasks this task depends on. */ - dependsOn?: string[]; + dependsOn?: TaskDependency[]; /** * The problem watchers to use for this task @@ -382,33 +408,86 @@ export namespace ContributedTask { } } -export interface CompositeTask extends CommonTask, ConfigurationProperties { +export interface InMemoryTask extends CommonTask, ConfigurationProperties { /** * Indicated the source of the task (e.g tasks.json or extension) */ - _source: CompositeTaskSource; + _source: InMemoryTaskSource; - type: 'composite'; + type: 'inMemory'; identifier: string; } -export namespace CompositeTask { - export function is(value: any): value is CompositeTask { - let candidate = value as CompositeTask; - return candidate && candidate._source && candidate._source.kind === TaskSourceKind.Composite; +export namespace InMemoryTask { + export function is(value: any): value is InMemoryTask { + let candidate = value as InMemoryTask; + return candidate && candidate._source && candidate._source.kind === TaskSourceKind.InMemory; } } -export type Task = CustomTask | ContributedTask | CompositeTask; +export type Task = CustomTask | ContributedTask | InMemoryTask; export namespace Task { - export function getKey(task: Task): string { - if (CustomTask.is(task) || CompositeTask.is(task)) { - return task.identifier; - } else { - return task.defines._key; + export function getRecentlyUsedKey(task: Task): string | undefined { + interface CustomKey { + type: string; + folder: string; + id: string; } + interface ContributedKey { + type: string; + scope: number; + folder?: string; + id: string; + } + if (InMemoryTask.is(task)) { + return undefined; + } + if (CustomTask.is(task)) { + let workspaceFolder = task._source.config.workspaceFolder; + if (!workspaceFolder) { + return undefined; + } + let key: CustomKey = { type: 'custom', folder: workspaceFolder.uri.toString(), id: task.identifier }; + return JSON.stringify(key); + } + if (ContributedTask.is(task)) { + let key: ContributedKey = { type: 'contributed', scope: task._source.scope, id: task._id }; + if (task._source.scope === TaskScope.Folder && task._source.workspaceFolder) { + key.folder = task._source.workspaceFolder.uri.toString(); + } + return JSON.stringify(key); + } + return undefined; + } + + export function getMapKey(task: Task): string { + if (CustomTask.is(task)) { + let workspaceFolder = task._source.config.workspaceFolder; + return workspaceFolder ? `${workspaceFolder.uri.toString()}|${task._id}` : task._id; + } else if (ContributedTask.is(task)) { + let workspaceFolder = task._source.workspaceFolder; + return workspaceFolder + ? `${task._source.scope.toString()}|${workspaceFolder.uri.toString()}|${task._id}` + : `${task._source.scope.toString()}|${task._id}`; + } else { + return task._id; + } + } + + export function getWorkspaceFolder(task: Task): IWorkspaceFolder | undefined { + if (CustomTask.is(task)) { + return task._source.config.workspaceFolder; + } else if (ContributedTask.is(task)) { + return task._source.workspaceFolder; + } else { + return undefined; + } + } + + export function clone(task: Task): Task { + return Objects.assign({}, task); } export function getTelemetryKind(task: Task): string { @@ -420,12 +499,25 @@ export namespace Task { } else { return 'workspace'; } - } else if (CompositeTask.is(task)) { + } else if (InMemoryTask.is(task)) { return 'composite'; } else { return 'unknown'; } } + + export function matches(task: Task, alias: string): boolean { + return alias === task._label || alias === task.identifier; + } + + export function getQualifiedLabel(task: Task): string { + let workspaceFolder = getWorkspaceFolder(task); + if (workspaceFolder) { + return `${task._label} (${workspaceFolder.name})`; + } else { + return task._label; + } + } } @@ -449,7 +541,41 @@ export interface TaskSet { } export interface TaskDefinition { + extensionId: string; taskType: string; required: string[]; properties: IJSONSchemaMap; +} + +export class TaskSorter { + + private _order: Map = new Map(); + + constructor(workspaceFolders: IWorkspaceFolder[]) { + for (let i = 0; i < workspaceFolders.length; i++) { + this._order.set(workspaceFolders[i].uri.toString(), i); + } + } + + public compare(a: Task, b: Task): number { + let aw = Task.getWorkspaceFolder(a); + let bw = Task.getWorkspaceFolder(b); + if (aw && bw) { + let ai = this._order.get(aw.uri.toString()); + ai = ai === void 0 ? 0 : ai + 1; + let bi = this._order.get(bw.uri.toString()); + bi = bi === void 0 ? 0 : bi + 1; + if (ai === bi) { + return a._label.localeCompare(b._label); + } else { + return ai - bi; + } + } else if (!aw && bw) { + return -1; + } else if (aw && !bw) { + return +1; + } else { + return 0; + } + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts b/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts index 51b794a250a..484af6701b0 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/jsonSchemaCommon.ts @@ -175,6 +175,7 @@ const schema: IJSONSchema = { }, taskRunnerConfiguration: { type: 'object', + required: [], properties: { command: { type: 'string', diff --git a/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts b/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts index 7577edc410f..37fc4bb43dd 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/jsonSchema_v2.ts @@ -145,8 +145,13 @@ const group: IJSONSchema = { const taskType: IJSONSchema = { type: 'string', enum: ['shell', 'process'], - default: 'process', - description: nls.localize('JsonSchema.tasks.type', 'Defines whether the task is run as a process or as a command inside a shell. Default is process.') + default: 'shell', + description: nls.localize('JsonSchema.tasks.type', 'Defines whether the task is run as a process or as a command inside a shell.') +}; + +const label: IJSONSchema = { + type: 'string', + description: nls.localize('JsonSchema.tasks.label', "The task's user interface label") }; const version: IJSONSchema = { @@ -224,6 +229,8 @@ taskDefinitions.push(customize); let definitions = Objects.deepClone(commonSchema.definitions); let taskDescription: IJSONSchema = definitions.taskDescription; +taskDescription.required = ['label']; +taskDescription.properties.label = Objects.deepClone(label); taskDescription.properties.isShellCommand = Objects.deepClone(shellCommand); taskDescription.properties.dependsOn = dependsOn; taskDescription.properties.identifier = Objects.deepClone(identifier); @@ -231,6 +238,16 @@ taskDescription.properties.type = Objects.deepClone(taskType); taskDescription.properties.presentation = Objects.deepClone(presentation); taskDescription.properties.terminal = terminal; taskDescription.properties.group = Objects.deepClone(group); +taskDescription.properties.taskName.deprecationMessage = nls.localize( + 'JsonSchema.tasks.taskName.deprecated', + 'The task\'s name property is deprecated. Use the label property instead.' +); +taskDescription.default = { + label: 'My Task', + type: 'shell', + command: 'echo Hello', + problemMatcher: [] +}; definitions.showOutputType.deprecationMessage = nls.localize( 'JsonSchema.tasks.showOputput.deprecated', 'The property showOutput is deprecated. Use the reveal property inside the presentation property instead. See also the 1.14 release notes.' diff --git a/src/vs/workbench/parts/tasks/electron-browser/media/task.contribution.css b/src/vs/workbench/parts/tasks/electron-browser/media/task.contribution.css index b0acde0d340..05c596a162b 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/media/task.contribution.css +++ b/src/vs/workbench/parts/tasks/electron-browser/media/task.contribution.css @@ -32,8 +32,7 @@ vertical-align: top; } -.task-statusbar-item-progress { - width: 6px; +.task-statusbar-item-building { height: 18px; padding: 0px 2px 0px 2px; display: inline-block; @@ -44,7 +43,6 @@ .task-statusbar-item-label { display: inline-block; cursor: pointer; - padding: 0 5px 0 0; } .task-statusbar-item-label > .task-statusbar-item-label-counter { diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index d5253749134..b487239dcc2 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -5,10 +5,10 @@ 'use strict'; import 'vs/css!./media/task.contribution'; -import 'vs/workbench/parts/tasks/browser/taskQuickOpen'; import * as nls from 'vs/nls'; +import { QuickOpenHandler } from 'vs/workbench/parts/tasks/browser/taskQuickOpen'; import { TPromise } from 'vs/base/common/winjs.base'; import Severity from 'vs/base/common/severity'; import * as Objects from 'vs/base/common/objects'; @@ -30,14 +30,13 @@ import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { Registry } from 'vs/platform/registry/common/platform'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { SyncActionDescriptor, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IEditor } from 'vs/platform/editor/common/editor'; -import { IMessageService } from 'vs/platform/message/common/message'; +import { IMessageService, IChoiceService } from 'vs/platform/message/common/message'; import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IFileService } from 'vs/platform/files/common/files'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -48,26 +47,21 @@ import { IProgressService2, IProgressOptions, ProgressLocation } from 'vs/platfo import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IWindowService } from 'vs/platform/windows/common/windows'; - -import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; - import jsonContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry'; import { IStatusbarItem, IStatusbarRegistry, Extensions as StatusbarExtensions, StatusbarItemDescriptor, StatusbarAlignment } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; -import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; +import { IQuickOpenService, IPickOpenEntry, IPickOpenAction, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import Constants from 'vs/workbench/parts/markers/common/constants'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IConfigurationEditingService, ConfigurationTarget, IConfigurationValue } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IOutputService, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannel } from 'vs/workbench/parts/output/common/output'; @@ -75,8 +69,8 @@ import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal'; -import { ITaskSystem, ITaskResolver, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskSystemEvents, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem'; -import { Task, CustomTask, ConfiguringTask, ContributedTask, CompositeTask, TaskSet, TaskGroup, ExecutionEngine, JsonSchemaVersion, TaskSourceKind, TaskIdentifier } from 'vs/workbench/parts/tasks/common/tasks'; +import { ITaskSystem, ITaskResolver, ITaskSummary, TaskExecuteKind, TaskError, TaskErrors, TaskSystemEvents, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem'; +import { Task, CustomTask, ConfiguringTask, ContributedTask, InMemoryTask, TaskSet, TaskGroup, GroupType, ExecutionEngine, JsonSchemaVersion, TaskSourceKind, TaskIdentifier, TaskSorter } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskService, TaskServiceEvents, ITaskProvider, TaskEvent, RunOptions, CustomizationProperties } from 'vs/workbench/parts/tasks/common/taskService'; import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates'; @@ -86,8 +80,6 @@ import { TerminalTaskSystem } from './terminalTaskSystem'; import { ProcessRunnerDetector } from 'vs/workbench/parts/tasks/node/processRunnerDetector'; import { QuickOpenActionContributor } from '../browser/quickOpen'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; - import { Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -96,152 +88,9 @@ import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; let $ = Builder.$; let tasksCategory = nls.localize('tasksCategory', "Tasks"); -abstract class OpenTaskConfigurationAction extends Action { - - constructor(id: string, label: string, - private taskService: ITaskService, - private configurationService: IConfigurationService, - private editorService: IWorkbenchEditorService, private fileService: IFileService, - private contextService: IWorkspaceContextService, private outputService: IOutputService, - private messageService: IMessageService, private quickOpenService: IQuickOpenService, - private environmentService: IEnvironmentService, - private configurationResolverService: IConfigurationResolverService, - private extensionService: IExtensionService, - private telemetryService: ITelemetryService) { - - super(id, label); - } - - public run(event?: any): TPromise { - if (!this.contextService.hasWorkspace()) { - this.messageService.show(Severity.Info, nls.localize('ConfigureTaskRunnerAction.noWorkspace', 'Tasks are only available on a workspace folder.')); - return TPromise.as(undefined); - } - let sideBySide = !!(event && (event.ctrlKey || event.metaKey)); - let configFileCreated = false; - return this.fileService.resolveFile(this.contextService.toResource('.vscode/tasks.json')).then((success) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) - - return success; - }, (err: any) => { - return this.quickOpenService.pick(taskTemplates, { placeHolder: nls.localize('ConfigureTaskRunnerAction.quickPick.template', 'Select a Task Runner') }).then(selection => { - if (!selection) { - return undefined; - } - let contentPromise: TPromise; - if (selection.autoDetect) { - const outputChannel = this.outputService.getChannel(TaskService.OutputChannelId); - outputChannel.show(true); - outputChannel.append(nls.localize('ConfigureTaskRunnerAction.autoDetecting', 'Auto detecting tasks for {0}', selection.id) + '\n'); - let detector = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService); - contentPromise = detector.detect(false, selection.id).then((value) => { - let config = value.config; - if (value.stderr && value.stderr.length > 0) { - value.stderr.forEach((line) => { - outputChannel.append(line + '\n'); - }); - if (config && (!config.tasks || config.tasks.length === 0)) { - this.messageService.show(Severity.Warning, nls.localize('ConfigureTaskRunnerAction.autoDetect', 'Auto detecting the task system failed. Using default template. Consult the task output for details.')); - return selection.content; - } else { - this.messageService.show(Severity.Warning, nls.localize('ConfigureTaskRunnerAction.autoDetectError', 'Auto detecting the task system produced errors. Consult the task output for details.')); - } - } - if (config) { - if (value.stdout && value.stdout.length > 0) { - value.stdout.forEach(line => outputChannel.append(line + '\n')); - } - let content = JSON.stringify(config, null, '\t'); - content = [ - '{', - '\t// See https://go.microsoft.com/fwlink/?LinkId=733558', - '\t// for the documentation about the tasks.json format', - ].join('\n') + content.substr(1); - return content; - } else { - return selection.content; - } - }); - } else { - contentPromise = TPromise.as(selection.content); - } - return contentPromise.then(content => { - let editorConfig = this.configurationService.getConfiguration(); - if (editorConfig.editor.insertSpaces) { - content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); - } - configFileCreated = true; - return this.fileService.createFile(this.contextService.toResource('.vscode/tasks.json'), content).then((result) => { - this.telemetryService.publicLog(TaskService.TemplateTelemetryEventName, { - templateId: selection.id, - autoDetect: selection.autoDetect - }); - return result; - }); // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) - }); - /* 2.0 version - let content = selection.content; - let editorConfig = this.configurationService.getConfiguration(); - if (editorConfig.editor.insertSpaces) { - content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); - } - configFileCreated = true; - return this.fileService.createFile(this.contextService.toResource('.vscode/tasks.json'), content); - */ - }); - }).then((stat) => { - if (!stat) { - return undefined; - } - // // (2) Open editor with configuration file - return this.editorService.openEditor({ - resource: stat.resource, - options: { - forceOpen: true, - pinned: configFileCreated // pin only if config file is created #8727 - } - }, sideBySide); - }, (error) => { - throw new Error(nls.localize('ConfigureTaskRunnerAction.failed', "Unable to create the 'tasks.json' file inside the '.vscode' folder. Consult the task output for details.")); - }); - } -} - -class ConfigureTaskRunnerAction extends OpenTaskConfigurationAction { - public static ID = 'workbench.action.tasks.configureTaskRunner'; - public static TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task Runner"); - - constructor(id: string, label: string, - @ITaskService taskService: ITaskService, @IConfigurationService configurationService: IConfigurationService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, - @IWorkspaceContextService contextService: IWorkspaceContextService, @IOutputService outputService: IOutputService, - @IMessageService messageService: IMessageService, @IQuickOpenService quickOpenService: IQuickOpenService, - @IEnvironmentService environmentService: IEnvironmentService, - @IConfigurationResolverService configurationResolverService: IConfigurationResolverService, - @IExtensionService extensionService: IExtensionService, - @ITelemetryService telemetryService: ITelemetryService) { - super(id, label, taskService, configurationService, editorService, fileService, contextService, - outputService, messageService, quickOpenService, environmentService, configurationResolverService, - extensionService, telemetryService); - } -} - -class ConfigureBuildTaskAction extends OpenTaskConfigurationAction { - public static ID = 'workbench.action.tasks.configureBuildTask'; - public static TEXT = nls.localize('ConfigureBuildTaskAction.label', "Configure Build Task"); - - constructor(id: string, label: string, - @ITaskService taskService: ITaskService, @IConfigurationService configurationService: IConfigurationService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, - @IWorkspaceContextService contextService: IWorkspaceContextService, @IOutputService outputService: IOutputService, - @IMessageService messageService: IMessageService, @IQuickOpenService quickOpenService: IQuickOpenService, - @IEnvironmentService environmentService: IEnvironmentService, - @IConfigurationResolverService configurationResolverService: IConfigurationResolverService, - @IExtensionService extensionService: IExtensionService, - @ITelemetryService telemetryService: ITelemetryService) { - super(id, label, taskService, configurationService, editorService, fileService, contextService, - outputService, messageService, quickOpenService, environmentService, configurationResolverService, - extensionService, telemetryService); - } +namespace ConfigureTaskAction { + export const ID = 'workbench.action.tasks.configureTaskRunner'; + export const TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task"); } class CloseMessageAction extends Action { @@ -262,31 +111,13 @@ class CloseMessageAction extends Action { } } -class ViewTerminalAction extends Action { - - public static ID = 'workbench.action.build.viewTerminal'; - public static TEXT = nls.localize('ShowTerminalAction.label', 'View Terminal'); - - constructor( @ITerminalService private terminalService: ITerminalService) { - super(ViewTerminalAction.ID, ViewTerminalAction.TEXT); - } - - public run(): TPromise { - this.terminalService.showPanel(); - return TPromise.as(undefined); - } -} - class BuildStatusBarItem extends Themable implements IStatusbarItem { - private intervalToken: any; private activeCount: number; - private static progressChars: string = '|/-\\'; private icons: HTMLElement[]; constructor( @IPanelService private panelService: IPanelService, @IMarkerService private markerService: IMarkerService, - @IOutputService private outputService: IOutputService, @ITaskService private taskService: ITaskService, @IPartService private partService: IPartService, @IThemeService themeService: IThemeService, @@ -301,14 +132,14 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { } private registerListeners(): void { - this.toUnbind.push(this.contextService.onDidChangeWorkspaceRoots(() => this.updateStyles())); + this.toUnbind.push(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); } protected updateStyles(): void { super.updateStyles(); this.icons.forEach(icon => { - icon.style.backgroundColor = this.getColor(this.contextService.hasWorkspace() ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND); + icon.style.backgroundColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND); }); } @@ -316,7 +147,6 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { let callOnDispose: IDisposable[] = []; const element = document.createElement('div'); - const progress = document.createElement('div'); const label = document.createElement('a'); const errorIcon = document.createElement('div'); const warningIcon = document.createElement('div'); @@ -324,14 +154,10 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { const error = document.createElement('div'); const warning = document.createElement('div'); const info = document.createElement('div'); + const building = document.createElement('div'); Dom.addClass(element, 'task-statusbar-item'); - Dom.addClass(progress, 'task-statusbar-item-progress'); - element.appendChild(progress); - progress.innerHTML = BuildStatusBarItem.progressChars[0]; - $(progress).hide(); - Dom.addClass(label, 'task-statusbar-item-label'); element.appendChild(label); element.title = nls.localize('problems', "Problems"); @@ -364,6 +190,12 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { label.appendChild(info); $(info).hide(); + Dom.addClass(building, 'task-statusbar-item-building'); + element.appendChild(building); + building.innerHTML = nls.localize('building', 'Building...'); + $(building).hide(); + + callOnDispose.push(Dom.addDisposableListener(label, 'click', (e: MouseEvent) => { const panel = this.panelService.getActivePanel(); if (panel && panel.getId() === Constants.MARKERS_PANEL_ID) { @@ -403,17 +235,7 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { } this.activeCount++; if (this.activeCount === 1) { - let index = 1; - let chars = BuildStatusBarItem.progressChars; - progress.innerHTML = chars[0]; - this.intervalToken = setInterval(() => { - progress.innerHTML = chars[index]; - index++; - if (index >= chars.length) { - index = 0; - } - }, 50); - $(progress).show(); + $(building).show(); } })); @@ -426,11 +248,7 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { if (this.activeCount > 0) { this.activeCount--; if (this.activeCount === 0) { - $(progress).hide(); - if (this.intervalToken) { - clearInterval(this.intervalToken); - this.intervalToken = null; - } + $(building).hide(); } } })); @@ -440,11 +258,7 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { return; } if (this.activeCount !== 0) { - $(progress).hide(); - if (this.intervalToken) { - clearInterval(this.intervalToken); - this.intervalToken = null; - } + $(building).hide(); this.activeCount = 0; } })); @@ -477,13 +291,8 @@ class BuildStatusBarItem extends Themable implements IStatusbarItem { class TaskStatusBarItem extends Themable implements IStatusbarItem { constructor( - @IPanelService private panelService: IPanelService, - @IMarkerService private markerService: IMarkerService, - @IOutputService private outputService: IOutputService, @ITaskService private taskService: ITaskService, - @IPartService private partService: IPartService, @IThemeService themeService: IThemeService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, ) { super(themeService); } @@ -539,40 +348,6 @@ class TaskStatusBarItem extends Themable implements IStatusbarItem { } } -interface TaskServiceEventData { - error?: any; -} - -class NullTaskSystem extends EventEmitter implements ITaskSystem { - public run(task: Task): ITaskExecuteResult { - return { - kind: TaskExecuteKind.Started, - promise: TPromise.as({}) - }; - } - public revealTask(task: Task): boolean { - return false; - } - public isActive(): TPromise { - return TPromise.as(false); - } - public isActiveSync(): boolean { - return false; - } - public getActiveTasks(): Task[] { - return []; - } - public canAutoTerminate(): boolean { - return true; - } - public terminate(task: string | Task): TPromise { - return TPromise.as({ success: true, task: undefined }); - } - public terminateAll(): TPromise { - return TPromise.as([]); - } -} - class ProblemReporter implements TaskConfig.IProblemReporter { private _validationStatus: ValidationStatus; @@ -618,7 +393,12 @@ interface WorkspaceTaskResult { hasErrors: boolean; } -interface WorkspaceConfigurationResult { +interface WorkspaceFolderTaskResult extends WorkspaceTaskResult { + workspaceFolder: IWorkspaceFolder; +} + +interface WorkspaceFolderConfigurationResult { + workspaceFolder: IWorkspaceFolder; config: TaskConfig.ExternalTaskRunnerConfiguration; hasErrors: boolean; } @@ -627,11 +407,55 @@ interface TaskCustomizationTelementryEvent { properties: string[]; } +class TaskMap { + private _store: Map = new Map(); + + constructor() { + } + + public forEach(callback: (value: Task[], folder: string) => void): void { + this._store.forEach(callback); + } + + public get(workspaceFolder: IWorkspaceFolder | string): Task[] { + let result: Task[] = Types.isString(workspaceFolder) ? this._store.get(workspaceFolder) : this._store.get(workspaceFolder.uri.toString()); + if (!result) { + result = []; + Types.isString(workspaceFolder) ? this._store.set(workspaceFolder, result) : this._store.set(workspaceFolder.uri.toString(), result); + } + return result; + } + + public has(workspaceFolder: IWorkspaceFolder): boolean { + return this._store.has(workspaceFolder.uri.toString()); + } + + public add(workspaceFolder: IWorkspaceFolder | string, ...task: Task[]): void { + let values = Types.isString(workspaceFolder) ? this._store.get(workspaceFolder) : this._store.get(workspaceFolder.uri.toString()); + if (!values) { + values = []; + Types.isString(workspaceFolder) ? this._store.set(workspaceFolder, values) : this._store.set(workspaceFolder.uri.toString(), values); + } + values.push(...task); + } + + public all(): Task[] { + let result: Task[] = []; + this._store.forEach((values) => result.push(...values)); + return result; + } +} + +interface TaskQuickPickEntry extends IPickOpenEntry { + task: Task; +} + class TaskService extends EventEmitter implements ITaskService { // private static autoDetectTelemetryName: string = 'taskServer.autoDetect'; private static RecentlyUsedTasks_Key = 'workbench.tasks.recentlyUsedTasks'; private static RanTaskBefore_Key = 'workbench.tasks.ranTaskBefore'; + private static IgnoreTask010DonotShowAgain_key = 'workbench.tasks.ignoreTask010Shown'; private static CustomizationTelemetryEventName: string = 'taskService.customize'; public static TemplateTelemetryEventName: string = 'taskService.template'; @@ -641,12 +465,11 @@ class TaskService extends EventEmitter implements ITaskService { public static OutputChannelId: string = 'tasks'; public static OutputChannelLabel: string = nls.localize('tasks', "Tasks"); - private modeService: IModeService; private configurationService: IConfigurationService; - private configurationEditingService: IConfigurationEditingService; private markerService: IMarkerService; private outputService: IOutputService; private messageService: IMessageService; + private choiceService: IChoiceService; private fileService: IFileService; private telemetryService: ITelemetryService; private editorService: IWorkbenchEditorService; @@ -657,9 +480,14 @@ class TaskService extends EventEmitter implements ITaskService { private quickOpenService: IQuickOpenService; private _configHasErrors: boolean; + private __schemaVersion: JsonSchemaVersion; + private __executionEngine: ExecutionEngine; + private __workspaceFolders: IWorkspaceFolder[]; + private __ignoredWorkspaceFolders: IWorkspaceFolder[]; + private __showIgnoreMessage: boolean; private _providers: Map; - private _workspaceTasksPromise: TPromise; + private _workspaceTasksPromise: TPromise>; private _taskSystem: ITaskSystem; private _taskSystemListeners: IDisposable[]; @@ -667,19 +495,18 @@ class TaskService extends EventEmitter implements ITaskService { private _outputChannel: IOutputChannel; - constructor( @IModeService modeService: IModeService, @IConfigurationService configurationService: IConfigurationService, - @IConfigurationEditingService configurationEditingService: IConfigurationEditingService, + constructor( + @IConfigurationService configurationService: IConfigurationService, @IMarkerService markerService: IMarkerService, @IOutputService outputService: IOutputService, - @IMessageService messageService: IMessageService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IMessageService messageService: IMessageService, @IChoiceService choiceService: IChoiceService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, @IWorkspaceContextService contextService: IWorkspaceContextService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService: ITextFileService, @ILifecycleService lifecycleService: ILifecycleService, @IModelService modelService: IModelService, @IExtensionService extensionService: IExtensionService, @IQuickOpenService quickOpenService: IQuickOpenService, - @IEnvironmentService private environmentService: IEnvironmentService, @IConfigurationResolverService private configurationResolverService: IConfigurationResolverService, @ITerminalService private terminalService: ITerminalService, - @IWorkbenchEditorService private workbenchEditorService: IWorkbenchEditorService, @IStorageService private storageService: IStorageService, @IProgressService2 private progressService: IProgressService2, @IOpenerService private openerService: IOpenerService, @@ -687,12 +514,11 @@ class TaskService extends EventEmitter implements ITaskService { ) { super(); - this.modeService = modeService; this.configurationService = configurationService; - this.configurationEditingService = configurationEditingService; this.markerService = markerService; this.outputService = outputService; this.messageService = messageService; + this.choiceService = choiceService; this.editorService = editorService; this.fileService = fileService; this.contextService = contextService; @@ -704,37 +530,41 @@ class TaskService extends EventEmitter implements ITaskService { this._configHasErrors = false; this._workspaceTasksPromise = undefined; + this._taskSystem = undefined; this._taskSystemListeners = []; this._outputChannel = this.outputService.getChannel(TaskService.OutputChannelId); this._providers = new Map(); - this.configurationService.onDidUpdateConfiguration(() => { + this.configurationService.onDidChangeConfiguration(() => { if (!this._taskSystem && !this._workspaceTasksPromise) { return; } + if (!this._taskSystem || this._taskSystem instanceof TerminalTaskSystem) { + this._outputChannel.clear(); + } + let folderSetup = this.computeWorkspaceFolderSetup(); + if (this.executionEngine !== folderSetup[2]) { + if (this._taskSystem && this._taskSystem.getActiveTasks().length > 0) { + this.messageService.show( + Severity.Info, + { + message: nls.localize( + 'TaskSystem.noHotSwap', + 'Changing the task execution engine with an active task running requires to reload the Window' + ), + actions: [ + new ReloadWindowAction(ReloadWindowAction.ID, ReloadWindowAction.LABEL, this._windowServive), + new CloseMessageAction() + ] + } + ); + return; + } else { + this.disposeTaskSystemListeners(); + this._taskSystem = undefined; + } + } + this.updateSetup(folderSetup); this.updateWorkspaceTasks(); - if (!this._taskSystem) { - return; - } - let currentExecutionEngine = this._taskSystem instanceof TerminalTaskSystem - ? ExecutionEngine.Terminal - : this._taskSystem instanceof ProcessTaskSystem - ? ExecutionEngine.Process - : ExecutionEngine._default; - if (currentExecutionEngine !== this.getExecutionEngine()) { - this.messageService.show( - Severity.Info, - { - message: nls.localize( - 'TaskSystem.noHotSwap', - 'Changing the task execution engine requires to reload the Window' - ), - actions: [ - new ReloadWindowAction(ReloadWindowAction.ID, ReloadWindowAction.LABEL, this._windowServive), - new CloseMessageAction() - ] - } - ); - } }); lifecycleService.onWillShutdown(event => event.veto(this.beforeShutdown())); this.registerCommands(); @@ -781,6 +611,10 @@ class TaskService extends EventEmitter implements ITaskService { this.runTestCommand(); }); + CommandsRegistry.registerCommand('workbench.action.tasks.configureTaskRunner', () => { + this.runConfigureTasks(); + }); + CommandsRegistry.registerCommand('workbench.action.tasks.configureDefaultBuildTask', () => { this.runConfigureDefaultBuildTask(); }); @@ -794,6 +628,65 @@ class TaskService extends EventEmitter implements ITaskService { }); } + private get workspaceFolders(): IWorkspaceFolder[] { + if (!this.__workspaceFolders) { + this.updateSetup(); + } + return this.__workspaceFolders; + } + + private get ignoredWorkspaceFolders(): IWorkspaceFolder[] { + if (!this.__ignoredWorkspaceFolders) { + this.updateSetup(); + } + return this.__ignoredWorkspaceFolders; + } + + private get executionEngine(): ExecutionEngine { + if (this.__executionEngine === void 0) { + this.updateSetup(); + } + return this.__executionEngine; + } + + private get schemaVersion(): JsonSchemaVersion { + if (this.__schemaVersion === void 0) { + this.updateSetup(); + } + return this.__schemaVersion; + } + + private get showIgnoreMessage(): boolean { + if (this.__showIgnoreMessage === void 0) { + this.__showIgnoreMessage = !this.storageService.getBoolean(TaskService.IgnoreTask010DonotShowAgain_key, StorageScope.WORKSPACE, false); + } + return this.__showIgnoreMessage; + } + + private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion]): void { + if (!setup) { + setup = this.computeWorkspaceFolderSetup(); + } + this.__workspaceFolders = setup[0]; + if (this.__ignoredWorkspaceFolders) { + if (this.__ignoredWorkspaceFolders.length !== setup[1].length) { + this.__showIgnoreMessage = undefined; + } else { + let set: Set = new Set(); + this.__ignoredWorkspaceFolders.forEach(folder => set.add(folder.uri.toString())); + for (let folder of setup[1]) { + if (!set.has(folder.uri.toString())) { + this.__showIgnoreMessage = undefined; + break; + } + } + } + } + this.__ignoredWorkspaceFolders = setup[1]; + this.__executionEngine = setup[2]; + this.__schemaVersion = setup[3]; + } + private showOutput(): void { this._outputChannel.show(true); } @@ -813,22 +706,32 @@ class TaskService extends EventEmitter implements ITaskService { return this._providers.delete(handle); } - public getTask(identifier: string): TPromise { - return this.getTaskSets().then((sets) => { - let resolver = this.createResolver(sets); - return resolver.resolve(identifier); + public getTask(folder: IWorkspaceFolder | string, alias: string): TPromise { + let name = Types.isString(folder) ? folder : folder.name; + if (this.ignoredWorkspaceFolders.some(ignored => ignored.name === name)) { + return TPromise.wrapError(new Error(nls.localize('TaskServer.folderIgnored', 'The folder {0} is ignored since it uses task version 0.1.0', name))); + } + return this.getGroupedTasks().then((map) => { + let values = map.get(folder); + if (!values) { + return undefined; + } + for (let task of values) { + if (Task.matches(task, alias)) { + return task; + } + } + return undefined; }); } public tasks(): TPromise { - return this.getTaskSets().then((sets) => { - let result: Task[] = []; - for (let set of sets) { - result.push(...set.tasks); - } - return result; - }); - }; + return this.getGroupedTasks().then(result => result.all()); + } + + public createSorter(): TaskSorter { + return new TaskSorter(this.contextService.getWorkspace() ? this.contextService.getWorkspace().folders : []); + } public isActive(): TPromise { if (!this._taskSystem) { @@ -881,10 +784,10 @@ class TaskService extends EventEmitter implements ITaskService { } public build(): TPromise { - return this.getTaskSets().then((values) => { - let runnable = this.createRunnableTask(values, TaskGroup.Build); + return this.getGroupedTasks().then((tasks) => { + let runnable = this.createRunnableTask(tasks, TaskGroup.Build); if (!runnable || !runnable.task) { - if (this.getJsonSchemaVersion() === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { throw new TaskError(Severity.Info, nls.localize('TaskService.noBuildTask1', 'No build task defined. Mark a task with \'isBuildCommand\' in the tasks.json file.'), TaskErrors.NoBuildTask); } else { throw new TaskError(Severity.Info, nls.localize('TaskService.noBuildTask2', 'No build task defined. Mark a task with as a \'build\' group in the tasks.json file.'), TaskErrors.NoBuildTask); @@ -906,10 +809,10 @@ class TaskService extends EventEmitter implements ITaskService { } public runTest(): TPromise { - return this.getTaskSets().then((values) => { - let runnable = this.createRunnableTask(values, TaskGroup.Test); + return this.getGroupedTasks().then((tasks) => { + let runnable = this.createRunnableTask(tasks, TaskGroup.Test); if (!runnable || !runnable.task) { - if (this.getJsonSchemaVersion() === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { throw new TaskError(Severity.Info, nls.localize('TaskService.noTestTask1', 'No test task defined. Mark a task with \'isTestCommand\' in the tasks.json file.'), TaskErrors.NoTestTask); } else { throw new TaskError(Severity.Info, nls.localize('TaskService.noTestTask2', 'No test task defined. Mark a task with as a \'test\' group in the tasks.json file.'), TaskErrors.NoTestTask); @@ -922,23 +825,14 @@ class TaskService extends EventEmitter implements ITaskService { }); } - public run(task: string | Task, options?: RunOptions): TPromise { - return this.getTaskSets().then((values) => { - let resolver = this.createResolver(values); - let requested: string; - let toExecute: Task; - if (Types.isString(task)) { - requested = task; - toExecute = resolver.resolve(task); + public run(task: Task, options?: RunOptions): TPromise { + return this.getGroupedTasks().then((grouped) => { + if (!task) { + throw new TaskError(Severity.Info, nls.localize('TaskServer.noTask', 'Requested task {0} to execute not found.', task.name), TaskErrors.TaskNotFound); } else { - requested = task.name; - toExecute = task; - } - if (!toExecute) { - throw new TaskError(Severity.Info, nls.localize('TaskServer.noTask', 'Requested task {0} to execute not found.', requested), TaskErrors.TaskNotFound); - } else { - if (options && options.attachProblemMatcher && this.shouldAttachProblemMatcher(toExecute) && !CompositeTask.is(toExecute)) { - return this.attachProblemMatcher(toExecute).then((toExecute) => { + let resolver = this.createResolver(grouped); + if (options && options.attachProblemMatcher && this.shouldAttachProblemMatcher(task) && !InMemoryTask.is(task)) { + return this.attachProblemMatcher(task).then((toExecute) => { if (toExecute) { return this.executeTask(toExecute, resolver); } else { @@ -946,7 +840,7 @@ class TaskService extends EventEmitter implements ITaskService { } }); } - return this.executeTask(toExecute, resolver); + return this.executeTask(task, resolver); } }).then(value => value, (error) => { this.handleError(error); @@ -955,7 +849,7 @@ class TaskService extends EventEmitter implements ITaskService { } private shouldAttachProblemMatcher(task: Task): boolean { - if (!this.canCustomize()) { + if (!this.canCustomize(task)) { return false; } if (task.group !== void 0 && task.group !== TaskGroup.Build) { @@ -998,7 +892,7 @@ class TaskService extends EventEmitter implements ITaskService { } if (entries.length > 0) { entries = entries.sort((a, b) => a.label.localeCompare(b.label)); - entries[0].separator = { border: true }; + entries[0].separator = { border: true, label: nls.localize('TaskService.associate', 'associate') }; entries.unshift( { label: nls.localize('TaskService.attachProblemMatcher.continueWithout', 'Continue without scanning the task output'), matcher: undefined }, { label: nls.localize('TaskService.attachProblemMatcher.never', 'Never scan the task output'), matcher: undefined, never: true }, @@ -1016,7 +910,7 @@ class TaskService extends EventEmitter implements ITaskService { this.customize(task, { problemMatcher: [] }, true); return task; } else if (selected.matcher) { - let newTask = Objects.deepClone(task); + let newTask = Task.clone(task); let matcherReference = `$${selected.matcher.name}`; newTask.problemMatchers = [matcherReference]; this.customize(task, { problemMatcher: [matcherReference] }, true); @@ -1033,25 +927,42 @@ class TaskService extends EventEmitter implements ITaskService { } public getTasksForGroup(group: string): TPromise { - return this.getTaskSets().then((values) => { + return this.getGroupedTasks().then((groups) => { let result: Task[] = []; - for (let value of values) { - for (let task of value.tasks) { + groups.forEach((tasks) => { + for (let task of tasks) { if (task.group === group) { result.push(task); } } - } + }); return result; }); } - public canCustomize(): boolean { - return this.getJsonSchemaVersion() === JsonSchemaVersion.V2_0_0; + public needsFolderQualification(): boolean { + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; + } + + public canCustomize(task: Task): boolean { + if (this.schemaVersion !== JsonSchemaVersion.V2_0_0) { + return false; + } + if (CustomTask.is(task)) { + return true; + } + if (ContributedTask.is(task)) { + return !!Task.getWorkspaceFolder(task); + } + return false; } public customize(task: ContributedTask | CustomTask, properties?: CustomizationProperties, openConfig?: boolean): TPromise { - let configuration = this.getConfiguration(); + let workspaceFolder = Task.getWorkspaceFolder(task); + if (!workspaceFolder) { + return TPromise.as(undefined); + } + let configuration = this.getConfiguration(workspaceFolder); if (configuration.hasParseErrors) { this.messageService.show(Severity.Warning, nls.localize('customizeParseErrors', 'The current task configuration has errors. Please fix the errors first before customizing a task.')); return TPromise.as(undefined); @@ -1105,36 +1016,29 @@ class TaskService extends EventEmitter implements ITaskService { if (editorConfig.editor.insertSpaces) { content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); } - promise = this.fileService.createFile(this.contextService.toResource('.vscode/tasks.json'), content).then(() => { }); // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + promise = this.fileService.createFile(workspaceFolder.toResource('.vscode/tasks.json'), content).then(() => { }); } else { - let value: IConfigurationValue = { key: undefined, value: undefined }; // We have a global task configuration if (index === -1) { if (properties.problemMatcher !== void 0) { fileConfig.problemMatcher = properties.problemMatcher; - value.key = 'tasks.problemMatchers'; - value.value = fileConfig.problemMatcher; - promise = this.configurationEditingService.writeConfiguration(ConfigurationTarget.WORKSPACE, value); + promise = this.writeConfiguration(workspaceFolder, 'tasks.problemMatchers', fileConfig.problemMatcher); } else if (properties.group !== void 0) { fileConfig.group = properties.group; - value.key = 'tasks.group'; - value.value = fileConfig.group; - promise = this.configurationEditingService.writeConfiguration(ConfigurationTarget.WORKSPACE, value); + promise = this.writeConfiguration(workspaceFolder, 'tasks.group', fileConfig.group); } } else { if (!Array.isArray(fileConfig.tasks)) { fileConfig.tasks = []; } - value.key = 'tasks.tasks'; - value.value = fileConfig.tasks; if (index === void 0) { fileConfig.tasks.push(toCustomize); } else { fileConfig.tasks[index] = toCustomize; } - promise = this.configurationEditingService.writeConfiguration(ConfigurationTarget.WORKSPACE, value); + promise = this.writeConfiguration(workspaceFolder, 'tasks.tasks', fileConfig.tasks); } - }; + } if (!promise) { return TPromise.as(undefined); } @@ -1142,9 +1046,14 @@ class TaskService extends EventEmitter implements ITaskService { let event: TaskCustomizationTelementryEvent = { properties: properties ? Object.getOwnPropertyNames(properties) : [] }; + /* __GDPR__ + "taskService.customize" : { + "properties" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(TaskService.CustomizationTelemetryEventName, event); if (openConfig) { - let resource = this.contextService.toResource('.vscode/tasks.json'); // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + let resource = workspaceFolder.toResource('.vscode/tasks.json'); this.editorService.openEditor({ resource: resource, options: { @@ -1156,8 +1065,18 @@ class TaskService extends EventEmitter implements ITaskService { }); } + private writeConfiguration(workspaceFolder: IWorkspaceFolder, key: string, value: any): TPromise { + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + return this.configurationService.updateValue(key, value, { resource: workspaceFolder.uri }, ConfigurationTarget.WORKSPACE); + } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + return this.configurationService.updateValue(key, value, { resource: workspaceFolder.uri }, ConfigurationTarget.WORKSPACE_FOLDER); + } else { + return undefined; + } + } + public openConfig(task: CustomTask): TPromise { - let resource = this.contextService.toResource(task._source.config.file); + let resource = Task.getWorkspaceFolder(task).toResource(task._source.config.file); return this.editorService.openEditor({ resource: resource, options: { @@ -1167,18 +1086,30 @@ class TaskService extends EventEmitter implements ITaskService { }, false).then(() => undefined); } - private createRunnableTask(sets: TaskSet[], group: TaskGroup): { task: Task; resolver: ITaskResolver } { - let idMap: IStringDictionary = Object.create(null); - let labelMap: IStringDictionary = Object.create(null); - let identifierMap: IStringDictionary = Object.create(null); + private createRunnableTask(tasks: TaskMap, group: TaskGroup): { task: Task; resolver: ITaskResolver } { + interface ResolverData { + id: Map; + label: Map; + identifier: Map; + } + let resolverData: Map = new Map(); let workspaceTasks: Task[] = []; let extensionTasks: Task[] = []; - sets.forEach((set) => { - set.tasks.forEach((task) => { - idMap[task._id] = task; - labelMap[task._label] = task; - identifierMap[task.identifier] = task; + tasks.forEach((tasks, folder) => { + let data = resolverData.get(folder); + if (!data) { + data = { + id: new Map(), + label: new Map(), + identifier: new Map() + }; + resolverData.set(folder, data); + } + for (let task of tasks) { + data.id.set(task._id, task); + data.label.set(task._label, task); + data.identifier.set(task.identifier, task); if (group && task.group === group) { if (task._source.kind === TaskSourceKind.Workspace) { workspaceTasks.push(task); @@ -1186,11 +1117,15 @@ class TaskService extends EventEmitter implements ITaskService { extensionTasks.push(task); } } - }); + } }); let resolver: ITaskResolver = { - resolve: (id: string) => { - return idMap[id] || labelMap[id] || identifierMap[id]; + resolve: (workspaceFolder: IWorkspaceFolder, alias: string) => { + let data = resolverData.get(workspaceFolder.uri.toString()); + if (!data) { + return undefined; + } + return data.id.get(alias) || data.label.get(alias) || data.identifier.get(alias); } }; if (workspaceTasks.length > 0) { @@ -1209,32 +1144,44 @@ class TaskService extends EventEmitter implements ITaskService { return { task: extensionTasks[0], resolver }; } else { let id: string = UUID.generateUuid(); - let task: CompositeTask = { + let task: InMemoryTask = { _id: id, - _source: { kind: TaskSourceKind.Composite, label: 'composite' }, + _source: { kind: TaskSourceKind.InMemory, label: 'inMemory' }, _label: id, - type: 'composite', + type: 'inMemory', name: id, identifier: id, - dependsOn: extensionTasks.map(task => task._id) + dependsOn: extensionTasks.map((task) => { return { workspaceFolder: Task.getWorkspaceFolder(task), task: task._id }; }) }; return { task, resolver }; } } - private createResolver(sets: TaskSet[]): ITaskResolver { - let labelMap: IStringDictionary = Object.create(null); - let identifierMap: IStringDictionary = Object.create(null); + private createResolver(grouped: TaskMap): ITaskResolver { + interface ResolverData { + label: Map; + identifier: Map; + } - sets.forEach((set) => { - set.tasks.forEach((task) => { - labelMap[task._label] = task; - identifierMap[task.identifier] = task; - }); + let resolverData: Map = new Map(); + grouped.forEach((tasks, folder) => { + let data = resolverData.get(folder); + if (!data) { + data = { label: new Map(), identifier: new Map() }; + resolverData.set(folder, data); + } + for (let task of tasks) { + data.label.set(task._label, task); + data.identifier.set(task.identifier, task); + } }); return { - resolve: (id: string) => { - return labelMap[id] || identifierMap[id]; + resolve: (workspaceFolder: IWorkspaceFolder, alias: string) => { + let data = resolverData.get(workspaceFolder.uri.toString()); + if (!data) { + return undefined; + } + return data.label.get(alias) || data.identifier.get(alias); } }; } @@ -1246,14 +1193,17 @@ class TaskService extends EventEmitter implements ITaskService { return ProblemMatcherRegistry.onReady().then(() => { return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved let executeResult = this.getTaskSystem().run(task, resolver); - this.getRecentlyUsedTasks().set(Task.getKey(task), Task.getKey(task), Touch.First); + let key = Task.getRecentlyUsedKey(task); + if (key) { + this.getRecentlyUsedTasks().set(key, key, Touch.First); + } if (executeResult.kind === TaskExecuteKind.Active) { let active = executeResult.active; if (active.same) { if (active.background) { - this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame.background', 'The task \'{0}\' is already active and in background mode. To terminate it use `Terminate Task...` from the Tasks menu.', task._label)); + this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame.background', 'The task \'{0}\' is already active and in background mode. To terminate it use `Terminate Task...` from the Tasks menu.', Task.getQualifiedLabel(task))); } else { - this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame.noBackground', 'The task \'{0}\' is already active. To terminate it use `Terminate Task...` from the Tasks menu.', task._label)); + this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame.noBackground', 'The task \'{0}\' is already active. To terminate it use `Terminate Task...` from the Tasks menu.', Task.getQualifiedLabel(task))); } } else { throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is already a task running. Terminate it first before executing another task.'), TaskErrors.RunningTask); @@ -1264,12 +1214,11 @@ class TaskService extends EventEmitter implements ITaskService { }); } - public restart(task: string | Task): void { + public restart(task: Task): void { if (!this._taskSystem) { return; } - const id: string = Types.isString(task) ? task : task._id; - this._taskSystem.terminate(id).then((response) => { + this._taskSystem.terminate(task).then((response) => { if (response.success) { this.emit(TaskServiceEvents.Terminated, {}); this.run(task); @@ -1280,12 +1229,11 @@ class TaskService extends EventEmitter implements ITaskService { }); } - public terminate(task: string | Task): TPromise { + public terminate(task: Task): TPromise { if (!this._taskSystem) { return TPromise.as({ success: true, task: undefined }); } - const id: string = Types.isString(task) ? task : task._id; - return this._taskSystem.terminate(id); + return this._taskSystem.terminate(task); } public terminateAll(): TPromise { @@ -1299,18 +1247,16 @@ class TaskService extends EventEmitter implements ITaskService { if (this._taskSystem) { return this._taskSystem; } - let engine = this.getExecutionEngine(); - if (engine === ExecutionEngine.Terminal) { + if (this.executionEngine === ExecutionEngine.Terminal) { this._taskSystem = new TerminalTaskSystem( this.terminalService, this.outputService, this.markerService, this.modelService, this.configurationResolverService, this.telemetryService, - this.workbenchEditorService, this.contextService, - TaskService.OutputChannelId + this.contextService, TaskService.OutputChannelId ); } else { let system = new ProcessTaskSystem( this.markerService, this.modelService, this.telemetryService, this.outputService, - this.configurationResolverService, this.contextService, TaskService.OutputChannelId, + this.configurationResolverService, TaskService.OutputChannelId, ); system.hasErrors(this._configHasErrors); this._taskSystem = system; @@ -1322,7 +1268,7 @@ class TaskService extends EventEmitter implements ITaskService { return this._taskSystem; } - private getTaskSets(): TPromise { + private getGroupedTasks(): TPromise { return this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask').then(() => { return new TPromise((resolve, reject) => { let result: TaskSet[] = []; @@ -1335,12 +1281,21 @@ class TaskService extends EventEmitter implements ITaskService { resolve(result); } }; - let error = () => { - if (--counter === 0) { - resolve(result); + let error = (error: any) => { + try { + if (Types.isString(error.message)) { + this._outputChannel.append('Error: '); + this._outputChannel.append(error.message); + this._outputChannel.append('\n'); + this._outputChannel.show(true); + } + } finally { + if (--counter === 0) { + resolve(result); + } } }; - if (this.getJsonSchemaVersion() === JsonSchemaVersion.V2_0_0 && this._providers.size > 0) { + if (this.schemaVersion === JsonSchemaVersion.V2_0_0 && this._providers.size > 0) { this._providers.forEach((provider) => { counter++; provider.provideTasks().done(done, error); @@ -1349,57 +1304,101 @@ class TaskService extends EventEmitter implements ITaskService { resolve(result); } }); - }).then((result) => { - return this.getWorkspaceTasks().then((workspaceTaskResult) => { - let workspaceTasksToDelete: Task[] = []; - let configurations = workspaceTaskResult.configurations; - let legacyTaskConfigurations = workspaceTaskResult.set ? this.getLegacyTaskConfigurations(workspaceTaskResult.set) : undefined; - if (configurations || legacyTaskConfigurations) { - for (let set of result) { - for (let i = 0; i < set.tasks.length; i++) { - let task = set.tasks[i]; - if (!ContributedTask.is(task)) { - continue; - } + }).then((contributedTaskSets) => { + let result: TaskMap = new TaskMap(); + let contributedTasks: TaskMap = new TaskMap(); + for (let set of contributedTaskSets) { + for (let task of set.tasks) { + let workspaceFolder = Task.getWorkspaceFolder(task); + if (workspaceFolder) { + contributedTasks.add(workspaceFolder, task); + } + } + } + return this.getWorkspaceTasks().then((customTasks) => { + customTasks.forEach((folderTasks, key) => { + let contributed = contributedTasks.get(key); + if (!folderTasks.set) { + if (contributed) { + result.add(key, ...contributed); + } + return; + } + + if (!contributed) { + result.add(key, ...folderTasks.set.tasks); + } else { + let configurations = folderTasks.configurations; + let legacyTaskConfigurations = folderTasks.set ? this.getLegacyTaskConfigurations(folderTasks.set) : undefined; + let customTasksToDelete: Task[] = []; + if (configurations || legacyTaskConfigurations) { + let unUsedConfigurations: Set = new Set(); if (configurations) { - let configuringTask = configurations.byIdentifier[task.defines._key]; - if (configuringTask) { - set.tasks[i] = TaskConfig.createCustomTask(task, configuringTask); + Object.keys(configurations.byIdentifier).forEach(key => unUsedConfigurations.add(key)); + } + for (let task of contributed) { + if (!ContributedTask.is(task)) { continue; } - } - if (legacyTaskConfigurations) { - let configuringTask = legacyTaskConfigurations[task.defines._key]; - if (configuringTask) { - set.tasks[i] = TaskConfig.createCustomTask(task, configuringTask); - workspaceTasksToDelete.push(configuringTask); - set.tasks[i] = configuringTask; - continue; + if (configurations) { + let configuringTask = configurations.byIdentifier[task.defines._key]; + if (configuringTask) { + unUsedConfigurations.delete(task.defines._key); + result.add(key, TaskConfig.createCustomTask(task, configuringTask)); + } else { + result.add(key, task); + } + } else if (legacyTaskConfigurations) { + let configuringTask = legacyTaskConfigurations[task.defines._key]; + if (configuringTask) { + result.add(key, TaskConfig.createCustomTask(task, configuringTask)); + customTasksToDelete.push(configuringTask); + } else { + result.add(key, task); + } + } else { + result.add(key, task); } } + if (customTasksToDelete.length > 0) { + let toDelete = customTasksToDelete.reduce>((map, task) => { + map[task._id] = true; + return map; + }, Object.create(null)); + for (let task of folderTasks.set.tasks) { + if (toDelete[task._id]) { + continue; + } + result.add(key, task); + } + } else { + result.add(key, ...folderTasks.set.tasks); + } + unUsedConfigurations.forEach((value) => { + let configuringTask = configurations.byIdentifier[value]; + this._outputChannel.append(nls.localize( + 'TaskService.noConfiguration', + 'Error: The {0} task detection didn\'t contribute a task for the following configuration:\n{1}\nThe task will be ignored.\n', + configuringTask.configures.type, + JSON.stringify(configuringTask._source.config.element, undefined, 4) + )); + this.showOutput(); + }); + } else { + result.add(key, ...folderTasks.set.tasks); + result.add(key, ...contributed); } } - } - if (workspaceTaskResult.set) { - if (workspaceTasksToDelete.length > 0) { - let tasks = workspaceTaskResult.set.tasks; - let newSet: TaskSet = { - extension: workspaceTaskResult.set.extension, - tasks: [] - }; - let toDelete = workspaceTasksToDelete.reduce>((map, task) => { - map[task._id] = true; - return map; - }, Object.create(null)); - newSet.tasks = tasks.filter(task => !toDelete[task._id]); - result.push(newSet); - } else { - result.push(workspaceTaskResult.set); - } - } + }); return result; }, () => { // If we can't read the tasks.json file provide at least the contributed tasks + let result: TaskMap = new TaskMap(); + for (let set of contributedTaskSets) { + for (let task of set.tasks) { + result.add(Task.getWorkspaceFolder(task), task); + } + } return result; }); }); @@ -1431,7 +1430,7 @@ class TaskService extends EventEmitter implements ITaskService { return result; } - private getWorkspaceTasks(): TPromise { + private getWorkspaceTasks(): TPromise> { if (this._workspaceTasksPromise) { return this._workspaceTasksPromise; } @@ -1441,113 +1440,163 @@ class TaskService extends EventEmitter implements ITaskService { private updateWorkspaceTasks(): void { this._workspaceTasksPromise = this.computeWorkspaceTasks().then(value => { - this._configHasErrors = value.hasErrors; - if (this._taskSystem instanceof ProcessTaskSystem) { - this._taskSystem.hasErrors(this._configHasErrors); + if (this.executionEngine === ExecutionEngine.Process && this._taskSystem instanceof ProcessTaskSystem) { + // We can only have a process engine if we have one folder. + value.forEach((value) => { + this._configHasErrors = value.hasErrors; + (this._taskSystem as ProcessTaskSystem).hasErrors(this._configHasErrors); + }); } return value; }); } - private computeWorkspaceTasks(): TPromise { - let configPromise: TPromise; - { - let { config, hasParseErrors } = this.getConfiguration(); - if (hasParseErrors) { - return TPromise.as({ set: undefined, hasErrors: true, configurations: undefined }); + private computeWorkspaceTasks(): TPromise> { + if (this.workspaceFolders.length === 0) { + return TPromise.as(new Map()); + } else { + let promises: TPromise[] = []; + for (let folder of this.workspaceFolders) { + promises.push(this.computeWorkspaceFolderTasks(folder).then((value) => value, () => undefined)); } - let engine = ExecutionEngine._default; - if (config) { - engine = TaskConfig.ExecutionEngine.from(config); - if (engine === ExecutionEngine.Process) { - if (this.hasDetectorSupport(config)) { - configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService, config).detect(true).then((value): WorkspaceConfigurationResult => { - let hasErrors = this.printStderr(value.stderr); - let detectedConfig = value.config; - if (!detectedConfig) { - return { config, hasErrors }; - } - let result: TaskConfig.ExternalTaskRunnerConfiguration = Objects.clone(config); - let configuredTasks: IStringDictionary = Object.create(null); - if (!result.tasks) { - if (detectedConfig.tasks) { - result.tasks = detectedConfig.tasks; - } - } else { - result.tasks.forEach(task => configuredTasks[task.taskName] = task); - detectedConfig.tasks.forEach((task) => { - if (!configuredTasks[task.taskName]) { - result.tasks.push(task); - } - }); - } - return { config: result, hasErrors }; - }); - } else { - configPromise = TPromise.as({ config, hasErrors: false }); + return TPromise.join(promises).then((values) => { + let result = new Map(); + for (let value of values) { + if (value) { + result.set(value.workspaceFolder.uri.toString(), value); } - } else { - configPromise = TPromise.as({ config, hasErrors: false }); } + return result; + }); + } + } + + private computeWorkspaceFolderTasks(workspaceFolder: IWorkspaceFolder): TPromise { + return (this.executionEngine === ExecutionEngine.Process + ? this.computeLegacyConfiguration(workspaceFolder) + : this.computeConfiguration(workspaceFolder)). + then((workspaceFolderConfiguration) => { + if (!workspaceFolderConfiguration || !workspaceFolderConfiguration.config || workspaceFolderConfiguration.hasErrors) { + return TPromise.as({ workspaceFolder, set: undefined, configurations: undefined, hasErrors: workspaceFolderConfiguration ? workspaceFolderConfiguration.hasErrors : false }); + } + return ProblemMatcherRegistry.onReady().then((): WorkspaceFolderTaskResult => { + let problemReporter = new ProblemReporter(this._outputChannel); + let parseResult = TaskConfig.parse(workspaceFolder, workspaceFolderConfiguration.config, problemReporter); + let hasErrors = false; + if (!parseResult.validationStatus.isOK()) { + hasErrors = true; + this.showOutput(); + } + if (problemReporter.status.isFatal()) { + problemReporter.fatal(nls.localize('TaskSystem.configurationErrors', 'Error: the provided task configuration has validation errors and can\'t not be used. Please correct the errors first.')); + return { workspaceFolder, set: undefined, configurations: undefined, hasErrors }; + } + let customizedTasks: { byIdentifier: IStringDictionary; }; + if (parseResult.configured && parseResult.configured.length > 0) { + customizedTasks = { + byIdentifier: Object.create(null) + }; + for (let task of parseResult.configured) { + customizedTasks.byIdentifier[task.configures._key] = task; + } + } + return { workspaceFolder, set: { tasks: parseResult.custom }, configurations: customizedTasks, hasErrors }; + }); + }); + } + + private computeConfiguration(workspaceFolder: IWorkspaceFolder): TPromise { + let { config, hasParseErrors } = this.getConfiguration(workspaceFolder); + return TPromise.as({ workspaceFolder, config, hasErrors: hasParseErrors }); + } + + private computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): TPromise { + let { config, hasParseErrors } = this.getConfiguration(workspaceFolder); + if (hasParseErrors) { + return TPromise.as({ workspaceFolder: workspaceFolder, hasErrors: true, config: undefined }); + } + if (config) { + if (this.hasDetectorSupport(config)) { + return new ProcessRunnerDetector(workspaceFolder, this.fileService, this.contextService, this.configurationResolverService, config).detect(true).then((value): WorkspaceFolderConfigurationResult => { + let hasErrors = this.printStderr(value.stderr); + let detectedConfig = value.config; + if (!detectedConfig) { + return { workspaceFolder, config, hasErrors }; + } + let result: TaskConfig.ExternalTaskRunnerConfiguration = Objects.clone(config); + let configuredTasks: IStringDictionary = Object.create(null); + if (!result.tasks) { + if (detectedConfig.tasks) { + result.tasks = detectedConfig.tasks; + } + } else { + result.tasks.forEach(task => configuredTasks[task.taskName] = task); + detectedConfig.tasks.forEach((task) => { + if (!configuredTasks[task.taskName]) { + result.tasks.push(task); + } + }); + } + return { workspaceFolder, config: result, hasErrors }; + }); } else { - if (engine === ExecutionEngine.Terminal) { - configPromise = TPromise.as({ config, hasErrors: false }); + return TPromise.as({ workspaceFolder, config, hasErrors: false }); + } + } else { + return new ProcessRunnerDetector(workspaceFolder, this.fileService, this.contextService, this.configurationResolverService).detect(true).then((value) => { + let hasErrors = this.printStderr(value.stderr); + return { workspaceFolder, config: value.config, hasErrors }; + }); + } + } + + private computeWorkspaceFolderSetup(): [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion] { + let workspaceFolders: IWorkspaceFolder[] = []; + let ignoredWorkspaceFolders: IWorkspaceFolder[] = []; + let executionEngine = ExecutionEngine.Terminal; + let schemaVersion = JsonSchemaVersion.V2_0_0; + + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + let workspaceFolder: IWorkspaceFolder = this.contextService.getWorkspace().folders[0]; + workspaceFolders.push(workspaceFolder); + executionEngine = this.computeExecutionEngine(workspaceFolder); + schemaVersion = this.computeJsonSchemaVersion(workspaceFolder); + } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + for (let workspaceFolder of this.contextService.getWorkspace().folders) { + if (schemaVersion === this.computeJsonSchemaVersion(workspaceFolder)) { + workspaceFolders.push(workspaceFolder); } else { - configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService).detect(true).then((value) => { - let hasErrors = this.printStderr(value.stderr); - return { config: value.config, hasErrors }; - }); + ignoredWorkspaceFolders.push(workspaceFolder); + this._outputChannel.append(nls.localize( + 'taskService.ignoreingFolder', + 'Ignoring task configurations for workspace folder {0}. Multi folder workspace task support requires that all folders use task version 2.0.0\n', + workspaceFolder.uri.fsPath)); } } } - return configPromise.then((resolved) => { - return ProblemMatcherRegistry.onReady().then((): WorkspaceTaskResult => { - if (!resolved || !resolved.config) { - return { set: undefined, configurations: undefined, hasErrors: resolved !== void 0 ? resolved.hasErrors : false }; - } - let problemReporter = new ProblemReporter(this._outputChannel); - let parseResult = TaskConfig.parse(resolved.config, problemReporter); - let hasErrors = false; - if (!parseResult.validationStatus.isOK()) { - hasErrors = true; - this.showOutput(); - } - if (problemReporter.status.isFatal()) { - problemReporter.fatal(nls.localize('TaskSystem.configurationErrors', 'Error: the provided task configuration has validation errors and can\'t not be used. Please correct the errors first.')); - return { set: undefined, configurations: undefined, hasErrors }; - } - let customizedTasks: { byIdentifier: IStringDictionary; }; - if (parseResult.configured && parseResult.configured.length > 0) { - customizedTasks = { - byIdentifier: Object.create(null) - }; - for (let task of parseResult.configured) { - customizedTasks.byIdentifier[task.configures._key] = task; - } - } - return { set: { tasks: parseResult.custom }, configurations: customizedTasks, hasErrors }; - }); - }); + return [workspaceFolders, ignoredWorkspaceFolders, executionEngine, schemaVersion]; } - private getExecutionEngine(): ExecutionEngine { - let { config } = this.getConfiguration(); + private computeExecutionEngine(workspaceFolder: IWorkspaceFolder): ExecutionEngine { + let { config } = this.getConfiguration(workspaceFolder); if (!config) { return ExecutionEngine._default; } return TaskConfig.ExecutionEngine.from(config); } - private getJsonSchemaVersion(): JsonSchemaVersion { - let { config } = this.getConfiguration(); + private computeJsonSchemaVersion(workspaceFolder: IWorkspaceFolder): JsonSchemaVersion { + let { config } = this.getConfiguration(workspaceFolder); if (!config) { return JsonSchemaVersion.V2_0_0; } return TaskConfig.JsonSchemaVersion.from(config); } - private getConfiguration(): { config: TaskConfig.ExternalTaskRunnerConfiguration; hasParseErrors: boolean } { - let result = this.contextService.hasWorkspace() ? this.configurationService.getConfiguration('tasks', { resource: this.contextService.getLegacyWorkspace().resource }) : undefined; + private getConfiguration(workspaceFolder: IWorkspaceFolder): { config: TaskConfig.ExternalTaskRunnerConfiguration; hasParseErrors: boolean } { + let result = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY + ? this.configurationService.getConfiguration('tasks', { resource: workspaceFolder.uri }) + : undefined; if (!result) { return { config: undefined, hasParseErrors: false }; } @@ -1585,28 +1634,32 @@ class TaskService extends EventEmitter implements ITaskService { if (this._taskSystem) { return this._taskSystem instanceof TerminalTaskSystem; } - return this.getExecutionEngine() === ExecutionEngine.Terminal; + return this.executionEngine === ExecutionEngine.Terminal; } private hasDetectorSupport(config: TaskConfig.ExternalTaskRunnerConfiguration): boolean { - if (!config.command || !this.contextService.hasWorkspace()) { + if (!config.command || this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { return false; } return ProcessRunnerDetector.supports(config.command); } public configureAction(): Action { - return new ConfigureTaskRunnerAction(ConfigureTaskRunnerAction.ID, ConfigureTaskRunnerAction.TEXT, this, - this.configurationService, this.editorService, this.fileService, this.contextService, - this.outputService, this.messageService, this.quickOpenService, this.environmentService, this.configurationResolverService, - this.extensionService, this.telemetryService); + let run = () => { this.runConfigureTasks(); return TPromise.as(undefined); }; + return new class extends Action { + constructor() { + super(ConfigureTaskAction.ID, ConfigureTaskAction.TEXT, undefined, true, run); + } + }; } private configureBuildTask(): Action { - return new ConfigureBuildTaskAction(ConfigureBuildTaskAction.ID, ConfigureBuildTaskAction.TEXT, this, - this.configurationService, this.editorService, this.fileService, this.contextService, - this.outputService, this.messageService, this.quickOpenService, this.environmentService, this.configurationResolverService, - this.extensionService, this.telemetryService); + let run = () => { this.runConfigureTasks(); return TPromise.as(undefined); }; + return new class extends Action { + constructor() { + super(ConfigureTaskAction.ID, ConfigureTaskAction.TEXT, undefined, true, run); + } + }; } public beforeShutdown(): boolean | TPromise { @@ -1622,7 +1675,7 @@ class TaskService extends EventEmitter implements ITaskService { if (this._taskSystem instanceof TerminalTaskSystem) { return false; } - if (this._taskSystem.canAutoTerminate() || this.messageService.confirm({ + if (this._taskSystem.canAutoTerminate() || this.messageService.confirmSync({ message: nls.localize('TaskSystem.runningTask', 'There is a task running. Do you want to terminate it?'), primaryButton: nls.localize({ key: 'TaskSystem.terminateTask', comment: ['&& denotes a mnemonic'] }, "&&Terminate Task"), type: 'question' @@ -1644,7 +1697,7 @@ class TaskService extends EventEmitter implements ITaskService { this.disposeTaskSystemListeners(); return false; // no veto } else if (code && code === TerminateResponseCode.ProcessNotFound) { - return !this.messageService.confirm({ + return !this.messageService.confirmSync({ message: nls.localize('TaskSystem.noProcess', 'The launched task doesn\'t exist anymore. If the task spawned background processes exiting VS Code might result in orphaned processes. To avoid this start the last background process with a wait flag.'), primaryButton: nls.localize({ key: 'TaskSystem.exitAnyways', comment: ['&& denotes a mnemonic'] }, "&&Exit Anyways"), type: 'info' @@ -1700,48 +1753,73 @@ class TaskService extends EventEmitter implements ITaskService { } private canRunCommand(): boolean { - if (!this.contextService.hasWorkspace()) { + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.messageService.show(Severity.Info, nls.localize('TaskService.noWorkspace', 'Tasks are only available on a workspace folder.')); return false; } return true; } - private showQuickPick(tasks: Task[], placeHolder: string, group: boolean = false, sort: boolean = false): TPromise { + private createTaskQuickPickEntries(tasks: Task[], group: boolean = false, sort: boolean = false): TaskQuickPickEntry[] { if (tasks === void 0 || tasks === null || tasks.length === 0) { - return TPromise.as(undefined); + return []; } - interface TaskQickPickEntry extends IPickOpenEntry { - task: Task; - } - function TaskQickPickEntry(task: Task): TaskQickPickEntry { - return { label: task._label, task }; - } - function fillEntries(entries: TaskQickPickEntry[], tasks: Task[], groupLabel: string, withBorder: boolean = false): void { - let first = true; - for (let task of tasks) { - if (first) { - first = false; - let entry = TaskQickPickEntry(task); - entry.separator = { label: groupLabel, border: withBorder }; - entries.push(entry); - } else { - entries.push(TaskQickPickEntry(task)); + const TaskQuickPickEntry = (task: Task): TaskQuickPickEntry => { + let description: string; + if (this.needsFolderQualification()) { + let workspaceFolder = Task.getWorkspaceFolder(task); + if (workspaceFolder) { + description = workspaceFolder.name; } } + return { label: task._label, description, task }; + }; + let taskService = this; + let action = new class extends Action implements IPickOpenAction { + constructor() { + super('configureAction', 'Configure Task', 'quick-open-task-configure', true); + } + public run(item: IPickOpenItem): TPromise { + let task: Task = item.getPayload(); + taskService.quickOpenService.close(); + if (ContributedTask.is(task)) { + taskService.customize(task, undefined, true); + } else if (CustomTask.is(task)) { + taskService.openConfig(task); + } + return TPromise.as(false); + } + }; + function fillEntries(entries: TaskQuickPickEntry[], tasks: Task[], groupLabel: string, withBorder: boolean = false): void { + let first = true; + for (let task of tasks) { + let entry: TaskQuickPickEntry = TaskQuickPickEntry(task); + if (first) { + first = false; + entry.separator = { label: groupLabel, border: withBorder }; + } + entry.action = action; + entry.payload = task; + entries.push(entry); + } } - let entries: TaskQickPickEntry[]; + let entries: TaskQuickPickEntry[]; if (group) { entries = []; if (tasks.length === 1) { - entries.push(TaskQickPickEntry(tasks[0])); + entries.push(TaskQuickPickEntry(tasks[0])); } else { let recentlyUsedTasks = this.getRecentlyUsedTasks(); let recent: Task[] = []; let configured: Task[] = []; let detected: Task[] = []; let taskMap: IStringDictionary = Object.create(null); - tasks.forEach(task => taskMap[Task.getKey(task)] = task); + tasks.forEach(task => { + let key = Task.getRecentlyUsedKey(task); + if (key) { + taskMap[key] = task; + } + }); recentlyUsedTasks.keys().forEach(key => { let task = taskMap[key]; if (task) { @@ -1749,7 +1827,8 @@ class TaskService extends EventEmitter implements ITaskService { } }); for (let task of tasks) { - if (!recentlyUsedTasks.has(Task.getKey(task))) { + let key = Task.getRecentlyUsedKey(task); + if (!key || !recentlyUsedTasks.has(key)) { if (task._source.kind === TaskSourceKind.Workspace) { configured.push(task); } else { @@ -1757,21 +1836,62 @@ class TaskService extends EventEmitter implements ITaskService { } } } + const sorter = this.createSorter(); let hasRecentlyUsed: boolean = recent.length > 0; fillEntries(entries, recent, nls.localize('recentlyUsed', 'recently used tasks')); - configured = configured.sort((a, b) => a._label.localeCompare(b._label)); + configured = configured.sort((a, b) => sorter.compare(a, b)); let hasConfigured = configured.length > 0; fillEntries(entries, configured, nls.localize('configured', 'configured tasks'), hasRecentlyUsed); - detected = detected.sort((a, b) => a._label.localeCompare(b._label)); + detected = detected.sort((a, b) => sorter.compare(a, b)); fillEntries(entries, detected, nls.localize('detected', 'detected tasks'), hasRecentlyUsed || hasConfigured); } } else { - entries = tasks.map(task => { return { label: task._label, task }; }); if (sort) { - entries = entries.sort((a, b) => a.task._label.localeCompare(b.task._label)); + const sorter = this.createSorter(); + tasks = tasks.sort((a, b) => sorter.compare(a, b)); + } + entries = tasks.map(task => TaskQuickPickEntry(task)); + } + return entries; + } + + private showQuickPick(tasks: TPromise | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false): TPromise { + let _createEntries = (): TPromise => { + if (Array.isArray(tasks)) { + return TPromise.as(this.createTaskQuickPickEntries(tasks, group, sort)); + } else { + return tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort)); + } + }; + return this.quickOpenService.pick(_createEntries().then((entries) => { + if (entries.length === 0 && defaultEntry) { + entries.push(defaultEntry); + } + return entries; + }), { placeHolder, autoFocus: { autoFocusFirstEntry: true } }).then(entry => entry ? entry.task : undefined); + } + + private showIgnoredFoldersMessage(): TPromise { + if (this.ignoredWorkspaceFolders.length === 0 || !this.showIgnoreMessage) { + return TPromise.as(undefined); + } + let message: string = nls.localize('TaskService.ignoredFolder', 'The following workspace folders are ignored since they use task version 0.1.0: '); + for (let i = 0; i < this.ignoredWorkspaceFolders.length; i++) { + message = message + this.ignoredWorkspaceFolders[i].name; + if (i < this.ignoredWorkspaceFolders.length - 1) { + message = message + ', '; } } - return this.quickOpenService.pick(entries, { placeHolder, autoFocus: { autoFocusFirstEntry: true } }).then(entry => entry ? entry.task : undefined); + + let notAgain = nls.localize('TaskService.notAgain', 'Don\'t Show Again'); + let ok = nls.localize('TaskService.ok', 'OK'); + return this.choiceService.choose(Severity.Info, message, [notAgain, ok], 0).then((choice) => { + if (choice === 0) { + this.storageService.store(TaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE); + } + this.__showIgnoreMessage = false; + return undefined; + }, () => undefined); } private runTaskCommand(accessor: ServicesAccessor, arg: any): void { @@ -1779,25 +1899,68 @@ class TaskService extends EventEmitter implements ITaskService { return; } if (Types.isString(arg)) { - this.getTask(arg).then((task) => { - if (task) { - this.run(task); - } else { - this.quickOpenService.show('task '); + this.getGroupedTasks().then((grouped) => { + let resolver = this.createResolver(grouped); + let folders = this.contextService.getWorkspace().folders; + for (let folder of folders) { + let task = resolver.resolve(folder, arg); + if (task) { + this.run(task); + return; + } } + this.doRunTaskCommand(grouped.all()); }, () => { - this.quickOpenService.show('task '); + this.doRunTaskCommand(); }); } else { - this.quickOpenService.show('task '); + this.doRunTaskCommand(); } } + private doRunTaskCommand(tasks?: Task[]): void { + this.showIgnoredFoldersMessage().then(() => { + this.showQuickPick(tasks ? tasks : this.tasks(), + nls.localize('TaskService.pickRunTask', 'Select the task to run'), + { + label: nls.localize('TaslService.noEntryToRun', 'No task to run found. Configure Tasks...'), + task: null + }, + true). + then((task) => { + if (task === void 0) { + return; + } + if (task === null) { + this.runConfigureTasks(); + } else { + this.run(task, { attachProblemMatcher: true }); + } + }); + }); + } + + private splitPerGroupType(tasks: Task[]): { none: Task[], defaults: Task[], users: Task[] } { + let none: Task[] = []; + let defaults: Task[] = []; + let users: Task[] = []; + for (let task of tasks) { + if (task.groupType === GroupType.default) { + defaults.push(task); + } else if (task.groupType === GroupType.user) { + users.push(task); + } else { + none.push(task); + } + } + return { none, defaults, users }; + } + private runBuildCommand(): void { if (!this.canRunCommand()) { return; } - if (this.getJsonSchemaVersion() === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { this.build(); return; } @@ -1806,31 +1969,32 @@ class TaskService extends EventEmitter implements ITaskService { title: nls.localize('TaskService.fetchingBuildTasks', 'Fetching build tasks...') }; let promise = this.getTasksForGroup(TaskGroup.Build).then((tasks) => { - if (tasks.length === 0) { - this.messageService.show( - Severity.Info, + if (tasks.length > 0) { + let { defaults, users } = this.splitPerGroupType(tasks); + if (defaults.length === 1) { + this.run(defaults[0]); + return; + } else if (defaults.length + users.length > 0) { + tasks = defaults.concat(users); + } + } + this.showIgnoredFoldersMessage().then(() => { + this.showQuickPick(tasks, + nls.localize('TaskService.pickBuildTask', 'Select the build task to run'), { - message: nls.localize('TaskService.noBuildTaskTerminal', 'No Build Task found. Press \'Configure Build Task\' to define one.'), - actions: [this.configureBuildTask(), new CloseMessageAction()] - } - ); - return; - } - let primaries: Task[] = []; - for (let task of tasks) { - // We only have build tasks here - if (task.isDefaultGroupEntry) { - primaries.push(task); - } - } - if (primaries.length === 1) { - this.run(primaries[0]); - return; - } - this.showQuickPick(tasks, nls.localize('TaskService.pickBuildTask', 'Select the build task to run'), true).then((task) => { - if (task) { - this.run(task, { attachProblemMatcher: true }); - } + label: nls.localize('TaskService.noBuildTask', 'No build task to run found. Configure Tasks...'), + task: null + }, + true).then((task) => { + if (task === void 0) { + return; + } + if (task === null) { + this.runConfigureTasks(); + return; + } + this.run(task, { attachProblemMatcher: true }); + }); }); }); this.progressService.withProgress(options, () => promise); @@ -1840,7 +2004,7 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (this.getJsonSchemaVersion() === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { this.runTest(); return; } @@ -1849,31 +2013,32 @@ class TaskService extends EventEmitter implements ITaskService { title: nls.localize('TaskService.fetchingTestTasks', 'Fetching test tasks...') }; let promise = this.getTasksForGroup(TaskGroup.Test).then((tasks) => { - if (tasks.length === 0) { - this.messageService.show( - Severity.Info, + if (tasks.length > 0) { + let { defaults, users } = this.splitPerGroupType(tasks); + if (defaults.length === 1) { + this.run(defaults[0]); + return; + } else if (defaults.length + users.length > 0) { + tasks = defaults.concat(users); + } + } + this.showIgnoredFoldersMessage().then(() => { + this.showQuickPick(tasks, + nls.localize('TaskService.pickTestTask', 'Select the test task to run'), { - message: nls.localize('TaskService.noTestTaskTerminal', 'No Test Task found. Press \'Configure Task Runner\' to define one.'), - actions: [this.configureAction(), new CloseMessageAction()] + label: nls.localize('TaskService.noTestTaskTerminal', 'No test task to run found. Configure Tasks...'), + task: null + }, true + ).then((task) => { + if (task === void 0) { + return; + } + if (task === null) { + this.runConfigureTasks(); + return; } - ); - return; - } - let primaries: Task[] = []; - for (let task of tasks) { - // We only have test task here. - if (task.isDefaultGroupEntry) { - primaries.push(task); - } - } - if (primaries.length === 1) { - this.run(primaries[0]); - return; - } - this.showQuickPick(tasks, nls.localize('TaskService.pickTestTask', 'Select the test task to run'), true).then((task) => { - if (task) { this.run(task); - } + }); }); }); this.progressService.withProgress(options, () => promise); @@ -1884,16 +2049,18 @@ class TaskService extends EventEmitter implements ITaskService { return; } if (this.inTerminal()) { - this.getActiveTasks().then((activeTasks) => { - if (activeTasks.length === 0) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskRunning', 'No task is currently running.')); + this.showQuickPick(this.getActiveTasks(), + nls.localize('TaskService.tastToTerminate', 'Select task to terminate'), + { + label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'), + task: null + }, + false, true + ).then(task => { + if (task === void 0 || task === null) { return; } - this.showQuickPick(activeTasks, nls.localize('TaskService.tastToTerminate', 'Select task to terminate'), false, true).then(task => { - if (task) { - this.terminate(task); - } - }); + this.terminate(task); }); } else { this.isActive().then((active) => { @@ -1920,16 +2087,18 @@ class TaskService extends EventEmitter implements ITaskService { return; } if (this.inTerminal()) { - this.getActiveTasks().then((activeTasks) => { - if (activeTasks.length === 0) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskToRestart', 'No task to restart.')); + this.showQuickPick(this.getActiveTasks(), + nls.localize('TaskService.tastToRestart', 'Select the task to restart'), + { + label: nls.localize('TaskService.noTaskToRestart', 'No task to restart'), + task: null + }, + false, true + ).then(task => { + if (task === void 0 || task === null) { return; } - this.showQuickPick(activeTasks, nls.localize('TaskService.tastToRestart', 'Select the task to restart'), false, true).then(task => { - if (task) { - this.restart(task); - } - }); + this.restart(task); }); } else { this.getActiveTasks().then((activeTasks) => { @@ -1942,38 +2111,172 @@ class TaskService extends EventEmitter implements ITaskService { } } + private runConfigureTasks(): void { + if (!this.canRunCommand()) { + return undefined; + } + let taskPromise: TPromise; + if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { + taskPromise = this.getGroupedTasks(); + } else { + taskPromise = TPromise.as(new TaskMap()); + } + + let openTaskFile = (workspaceFolder: IWorkspaceFolder): void => { + let resource = workspaceFolder.toResource('.vscode/tasks.json'); + let configFileCreated = false; + this.fileService.resolveFile(resource).then((stat) => stat, () => undefined).then((stat) => { + if (stat) { + return stat.resource; + } + return this.quickOpenService.pick(taskTemplates, { placeHolder: nls.localize('TaskService.template', 'Select a Task Template') }).then((selection) => { + if (!selection) { + return undefined; + } + let content = selection.content; + let editorConfig = this.configurationService.getConfiguration(); + if (editorConfig.editor.insertSpaces) { + content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); + } + configFileCreated = true; + return this.fileService.createFile(resource, content).then((result): URI => { + this.telemetryService.publicLog(TaskService.TemplateTelemetryEventName, { + templateId: selection.id, + autoDetect: selection.autoDetect + }); + return result.resource; + }); + }); + }).then((resource) => { + if (!resource) { + return; + } + this.editorService.openEditor({ + resource: resource, + options: { + forceOpen: true, + pinned: configFileCreated // pin only if config file is created #8727 + } + }, false); + }); + }; + + let configureTask = (task: Task): void => { + if (ContributedTask.is(task)) { + this.customize(task, undefined, true); + } else if (CustomTask.is(task)) { + this.openConfig(task); + } + }; + + function isTaskEntry(value: IPickOpenEntry): value is IPickOpenEntry & { task: Task } { + let candidate: IPickOpenEntry & { task: Task } = value as any; + return candidate && !!candidate.task; + } + + let stats = this.contextService.getWorkspace().folders.map>((folder) => { + return this.fileService.resolveFile(folder.toResource('.vscode/tasks.json')).then(stat => stat, () => undefined); + }); + + let createLabel = nls.localize('TaskService.createJsonFile', 'Create tasks.json file from template'); + let openLabel = nls.localize('TaskService.openJsonFile', 'Open tasks.json file'); + let entries = TPromise.join(stats).then((stats) => { + return taskPromise.then((taskMap) => { + type EntryType = (IPickOpenEntry & { task: Task; }) | (IPickOpenEntry & { folder: IWorkspaceFolder; }); + let entries: EntryType[] = []; + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + let tasks = taskMap.all(); + if (tasks.length > 0) { + tasks = tasks.sort((a, b) => a._label.localeCompare(b._label)); + entries = tasks.map(task => { return { label: task._label, task }; }); + } else { + let label = stats[0] !== void 0 ? openLabel : createLabel; + entries.push({ label, folder: this.contextService.getWorkspace().folders[0] }); + } + } else { + let folders = this.contextService.getWorkspace().folders; + let index = 0; + for (let folder of folders) { + let tasks = taskMap.get(folder); + if (tasks.length > 0) { + tasks = tasks.slice().sort((a, b) => a._label.localeCompare(b._label)); + for (let i = 0; i < tasks.length; i++) { + let entry: EntryType = { label: tasks[i]._label, task: tasks[i], description: folder.name }; + if (i === 0) { + entry.separator = { label: folder.name, border: index > 0 }; + } + entries.push(entry); + } + } else { + let label = stats[index] !== void 0 ? openLabel : createLabel; + let entry: EntryType = { label, folder: folder }; + entry.separator = { label: folder.name, border: index > 0 }; + entries.push(entry); + } + index++; + } + } + return entries; + }); + }); + + this.quickOpenService.pick(entries, + { placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure'), autoFocus: { autoFocusFirstEntry: true } }). + then((selection) => { + if (!selection) { + return; + } + if (isTaskEntry(selection)) { + configureTask(selection.task); + } else { + openTaskFile(selection.folder); + } + }); + } + private runConfigureDefaultBuildTask(): void { if (!this.canRunCommand()) { return; } - if (this.getJsonSchemaVersion() === JsonSchemaVersion.V2_0_0) { + if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { - this.configureBuildTask().run(); + this.runConfigureTasks(); return; } let defaultTask: Task; + let defaultEntry: TaskQuickPickEntry; for (let task of tasks) { - if (task.group === TaskGroup.Build && task.isDefaultGroupEntry) { + if (task.group === TaskGroup.Build && task.groupType === GroupType.default) { defaultTask = task; break; } } if (defaultTask) { - this.messageService.show(Severity.Info, nls.localize('TaskService.defaultBuildTaskExists', '{0} is already marked as the default build task.', defaultTask._label)); - return; + tasks = []; + defaultEntry = { + label: nls.localize('TaskService.defaultBuildTaskExists', '{0} is already marked as the default build task', Task.getQualifiedLabel(defaultTask)), + task: defaultTask + }; } - this.showQuickPick(tasks, nls.localize('TaskService.pickDefaultBuildTask', 'Select the task to be used as the default build task'), true).then((task) => { - if (!task) { - return; - } - if (!CompositeTask.is(task)) { - this.customize(task, { group: { kind: 'build', isDefault: true } }, true); - } + this.showIgnoredFoldersMessage().then(() => { + this.showQuickPick(tasks, + nls.localize('TaskService.pickDefaultBuildTask', 'Select the task to be used as the default build task'), defaultEntry, true). + then((task) => { + if (task === void 0) { + return; + } + if (task === defaultTask && CustomTask.is(task)) { + this.openConfig(task); + } + if (!InMemoryTask.is(task)) { + this.customize(task, { group: { kind: 'build', isDefault: true } }, true); + } + }); }); })); } else { - this.configureBuildTask().run(); + this.runConfigureTasks(); } } @@ -1981,33 +2284,35 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (this.getJsonSchemaVersion() === JsonSchemaVersion.V2_0_0) { + if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { - this.configureAction().run(); + this.runConfigureTasks(); } let defaultTask: Task; for (let task of tasks) { - if (task.group === TaskGroup.Test && task.isDefaultGroupEntry) { + if (task.group === TaskGroup.Test && task.groupType === GroupType.default) { defaultTask = task; break; } } if (defaultTask) { - this.messageService.show(Severity.Info, nls.localize('TaskService.defaultTestTaskExists', '{0} is already marked as the default test task.', defaultTask._label)); + this.messageService.show(Severity.Info, nls.localize('TaskService.defaultTestTaskExists', '{0} is already marked as the default test task.', Task.getQualifiedLabel(defaultTask))); return; } - this.showQuickPick(tasks, nls.localize('TaskService.pickDefaultTestTask', 'Select the task to be used as the default test task'), true).then((task) => { - if (!task) { - return; - } - if (!CompositeTask.is(task)) { - this.customize(task, { group: { kind: 'test', isDefault: true } }, true); - } + this.showIgnoredFoldersMessage().then(() => { + this.showQuickPick(tasks, nls.localize('TaskService.pickDefaultTestTask', 'Select the task to be used as the default test task'), undefined, true).then((task) => { + if (!task) { + return; + } + if (!InMemoryTask.is(task)) { + this.customize(task, { group: { kind: 'test', isDefault: true } }, true); + } + }); }); })); } else { - this.configureAction().run(); + this.runConfigureTasks(); } } @@ -2015,33 +2320,23 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (!this._taskSystem) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskIsRunning', 'No task is running.')); - return; - } - this.getActiveTasks().then((tasks) => { - if (tasks.length === 0) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskIsRunning', 'No task is running.')); - } else if (tasks.length === 1) { - if (this._taskSystem) { - this._taskSystem.revealTask(tasks[0]); - } - } else { - this.showQuickPick(tasks, nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), false, true).then((task) => { - if (!task || !this._taskSystem) { - return; - } - this._taskSystem.revealTask(task); - }); + this.showQuickPick(this.getActiveTasks(), + nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), + { + label: nls.localize('TaskService.noTaskIsRunning', 'No task is running'), + task: null + }, + false, true + ).then((task) => { + if (task === void 0 || task === null) { + return; } + this._taskSystem.revealTask(task); }); } } - -let workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureTaskRunnerAction, ConfigureTaskRunnerAction.ID, ConfigureTaskRunnerAction.TEXT), 'Tasks: Configure Task Runner', tasksCategory); - +MenuRegistry.addCommand({ id: ConfigureTaskAction.ID, title: { value: ConfigureTaskAction.TEXT, original: 'Configure Task' }, category: { value: tasksCategory, original: 'Tasks' } }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.showLog', title: { value: nls.localize('ShowLogAction.label', "Show Task Log"), original: 'Show Task Log' }, category: { value: tasksCategory, original: 'Tasks' } }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.runTask', title: { value: nls.localize('RunTaskAction.label', "Run Task"), original: 'Run Task' }, category: { value: tasksCategory, original: 'Tasks' } }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.restartTask', title: { value: nls.localize('RestartTaskAction.label', "Restart Running Task"), original: 'Restart Running Task' }, category: { value: tasksCategory, original: 'Tasks' } }); @@ -2063,8 +2358,8 @@ const tasksPickerContextKey = 'inTasksPicker'; quickOpenRegistry.registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/tasks/browser/taskQuickOpen', - 'QuickOpenHandler', + QuickOpenHandler, + QuickOpenHandler.ID, 'task ', tasksPickerContextKey, nls.localize('quickOpen.task', "Run Task") diff --git a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts index 2e299721025..a713b785fb9 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts @@ -10,7 +10,6 @@ import path = require('path'); import * as nls from 'vs/nls'; import * as Objects from 'vs/base/common/objects'; import * as Types from 'vs/base/common/types'; -import { CharCode } from 'vs/base/common/charCode'; import * as Platform from 'vs/base/common/platform'; import * as Async from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -20,16 +19,14 @@ import Severity from 'vs/base/common/severity'; import { EventEmitter } from 'vs/base/common/eventEmitter'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as TPath from 'vs/base/common/paths'; -// import URI from 'vs/base/common/uri'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ProblemMatcher, ProblemMatcherRegistry /*, ProblemPattern, getResource */ } from 'vs/platform/markers/common/problemMatcher'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ITerminalService, ITerminalInstance, IShellLaunchConfig } from 'vs/workbench/parts/terminal/common/terminal'; import { IOutputService, IOutputChannel } from 'vs/workbench/parts/output/common/output'; @@ -40,58 +37,6 @@ import { TelemetryEvent, Triggers, TaskSystemEvents, TaskEvent, TaskType, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem'; -class TerminalDecoder { - // See https://en.wikipedia.org/wiki/ANSI_escape_code & http://stackoverflow.com/questions/25189651/how-to-remove-ansi-control-chars-vt100-from-a-java-string & - // https://www.npmjs.com/package/strip-ansi - private static ANSI_CONTROL_SEQUENCE: RegExp = /\x1b[[()#;?]*(?:\d{1,4}(?:;\d{0,4})*)?[0-9A-ORZcf-nqry=><]/g; - private static OPERATING_SYSTEM_COMMAND_SEQUENCE: RegExp = /\x1b[\]](?:.*)(?:\x07|\x1b\\)/g; - - private remaining: string; - - public write(data: string): string[] { - let result: string[] = []; - data = data.replace(TerminalDecoder.ANSI_CONTROL_SEQUENCE, ''); - data = data.replace(TerminalDecoder.OPERATING_SYSTEM_COMMAND_SEQUENCE, ''); - let value = this.remaining - ? this.remaining + data - : data; - - if (value.length < 1) { - return result; - } - let start = 0; - let ch: number; - while (start < value.length && ((ch = value.charCodeAt(start)) === CharCode.CarriageReturn || ch === CharCode.LineFeed)) { - start++; - } - let idx = start; - while (idx < value.length) { - ch = value.charCodeAt(idx); - if (ch === CharCode.CarriageReturn || ch === CharCode.LineFeed) { - result.push(value.substring(start, idx)); - idx++; - while (idx < value.length && ((ch = value.charCodeAt(idx)) === CharCode.CarriageReturn || ch === CharCode.LineFeed)) { - idx++; - } - start = idx; - } else { - idx++; - } - } - this.remaining = start < value.length ? value.substr(start) : undefined; - return result; - } - - public end(): string { - return this.remaining; - } -} - -interface PrimaryTerminal { - terminal: ITerminalInstance; - busy: boolean; -} - interface TerminalData { terminal: ITerminalInstance; lastTask: string; @@ -117,7 +62,6 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { private markerService: IMarkerService, private modelService: IModelService, private configurationResolverService: IConfigurationResolverService, private telemetryService: ITelemetryService, - private workbenchEditorService: IWorkbenchEditorService, private contextService: IWorkspaceContextService, outputChannelId: string) { super(); @@ -138,7 +82,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { } public run(task: Task, resolver: ITaskResolver, trigger: string = Triggers.command): ITaskExecuteResult { - let terminalData = this.activeTasks[task._id]; + let terminalData = this.activeTasks[Task.getMapKey(task)]; if (terminalData && terminalData.promise) { let reveal = RevealKind.Always; let focus = false; @@ -170,7 +114,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { public revealTask(task: Task): boolean { - let terminalData = this.activeTasks[task._id]; + let terminalData = this.activeTasks[Task.getMapKey(task)]; if (!terminalData) { return false; } @@ -197,11 +141,11 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { return Object.keys(this.activeTasks).map(key => this.activeTasks[key].task); } - public terminate(id: string): TPromise { - let activeTerminal = this.activeTasks[id]; + public terminate(task: Task): TPromise { + let activeTerminal = this.activeTasks[Task.getMapKey(task)]; if (!activeTerminal) { return TPromise.as({ success: false, task: undefined }); - }; + } return new TPromise((resolve, reject) => { let terminal = activeTerminal.terminal; const onExit = terminal.onExit(() => { @@ -246,15 +190,19 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { private executeTask(startedTasks: IStringDictionary>, task: Task, resolver: ITaskResolver, trigger: string): TPromise { let promises: TPromise[] = []; if (task.dependsOn) { - task.dependsOn.forEach((identifier) => { - let task = resolver.resolve(identifier); + task.dependsOn.forEach((dependency) => { + let task = resolver.resolve(dependency.workspaceFolder, dependency.task); if (task) { - let promise = startedTasks[task._id]; + let key = Task.getMapKey(task); + let promise = startedTasks[key]; if (!promise) { promise = this.executeTask(startedTasks, task, resolver, trigger); - startedTasks[task._id] = promise; + startedTasks[key] = promise; } promises.push(promise); + } else { + this.log(nls.localize('dependencyFailed', 'Couldn\'t resolve dependent task \'{0}\' in workspace folder \'{1}\'', dependency.task, dependency.workspaceFolder.name)); + this.showOutput(); } }); } @@ -286,7 +234,7 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { let promise: TPromise = undefined; if (task.isBackground) { promise = new TPromise((resolve, reject) => { - const problemMatchers = this.resolveMatchers(task.problemMatchers); + const problemMatchers = this.resolveMatchers(task, task.problemMatchers); let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService); let toUnbind: IDisposable[] = []; let event: TaskEvent = { taskId: task._id, taskName: task.name, type: TaskType.Watching, group: task.group, __task: task }; @@ -300,39 +248,33 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { this.emit(TaskSystemEvents.Inactive, event); })); watchingProblemMatcher.aboutToStart(); - let delayer: Async.Delayer = null; - let decoder = new TerminalDecoder(); + let delayer: Async.Delayer = undefined; [terminal, executedCommand] = this.createTerminal(task); const registeredLinkMatchers = this.registerLinkMatchers(terminal, problemMatchers); - const onData = terminal.onData((data: string) => { - decoder.write(data).forEach(line => { - watchingProblemMatcher.processLine(line); - if (delayer === null) { - delayer = new Async.Delayer(3000); - } - delayer.trigger(() => { - watchingProblemMatcher.forceDelivery(); - delayer = null; - }); + const onData = terminal.onLineData((line) => { + watchingProblemMatcher.processLine(line); + if (!delayer) { + delayer = new Async.Delayer(3000); + } + delayer.trigger(() => { + watchingProblemMatcher.forceDelivery(); + delayer = undefined; }); }); const onExit = terminal.onExit((exitCode) => { onData.dispose(); onExit.dispose(); - delete this.activeTasks[task._id]; + let key = Task.getMapKey(task); + delete this.activeTasks[key]; this.emit(TaskSystemEvents.Changed); switch (task.command.presentation.panel) { case PanelKind.Dedicated: - this.sameTaskTerminals[task._id] = terminal.id.toString(); + this.sameTaskTerminals[key] = terminal.id.toString(); break; case PanelKind.Shared: - this.idleTaskTerminals.set(task._id, terminal.id.toString(), Touch.First); + this.idleTaskTerminals.set(key, terminal.id.toString(), Touch.First); break; } - let remaining = decoder.end(); - if (remaining) { - watchingProblemMatcher.processLine(remaining); - } watchingProblemMatcher.dispose(); registeredLinkMatchers.forEach(handle => terminal.deregisterLinkMatcher(handle)); toUnbind = dispose(toUnbind); @@ -354,32 +296,26 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { [terminal, executedCommand] = this.createTerminal(task); let event: TaskEvent = { taskId: task._id, taskName: task.name, type: TaskType.SingleRun, group: task.group, __task: task }; this.emit(TaskSystemEvents.Active, event); - let decoder = new TerminalDecoder(); - let problemMatchers = this.resolveMatchers(task.problemMatchers); + let problemMatchers = this.resolveMatchers(task, task.problemMatchers); let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService); const registeredLinkMatchers = this.registerLinkMatchers(terminal, problemMatchers); - const onData = terminal.onData((data: string) => { - decoder.write(data).forEach((line) => { - startStopProblemMatcher.processLine(line); - }); + const onData = terminal.onLineData((line) => { + startStopProblemMatcher.processLine(line); }); const onExit = terminal.onExit((exitCode) => { onData.dispose(); onExit.dispose(); - delete this.activeTasks[task._id]; + let key = Task.getMapKey(task); + delete this.activeTasks[key]; this.emit(TaskSystemEvents.Changed); switch (task.command.presentation.panel) { case PanelKind.Dedicated: - this.sameTaskTerminals[task._id] = terminal.id.toString(); + this.sameTaskTerminals[key] = terminal.id.toString(); break; case PanelKind.Shared: - this.idleTaskTerminals.set(task._id, terminal.id.toString(), Touch.First); + this.idleTaskTerminals.set(key, terminal.id.toString(), Touch.First); break; } - let remaining = decoder.end(); - if (remaining) { - startStopProblemMatcher.processLine(remaining); - } startStopProblemMatcher.done(); startStopProblemMatcher.dispose(); registeredLinkMatchers.forEach(handle => terminal.deregisterLinkMatcher(handle)); @@ -392,11 +328,14 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { }); }); } + if (!terminal) { + return TPromise.wrapError(new Error(`Failed to create terminal for task ${task._label}`)); + } this.terminalService.setActiveInstance(terminal); if (task.command.presentation.reveal === RevealKind.Always || (task.command.presentation.reveal === RevealKind.Silent && task.problemMatchers.length === 0)) { this.terminalService.showPanel(task.command.presentation.focus); } - this.activeTasks[task._id] = { terminal, task, promise }; + this.activeTasks[Task.getMapKey(task)] = { terminal, task, promise }; this.emit(TaskSystemEvents.Changed); return promise.then((summary) => { try { @@ -408,6 +347,13 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { success: true, exitCode: summary.exitCode }; + /* __GDPR__ + "taskService" : { + "${include}": [ + "${TelemetryEvent}" + ] + } + */ this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent); } catch (error) { } @@ -421,6 +367,13 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { command: this.getSanitizedCommand(executedCommand), success: false }; + /* __GDPR__ + "taskService" : { + "${include}": [ + "${TelemetryEvent}" + ] + } + */ this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent); } catch (error) { } @@ -429,13 +382,15 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { } private createTerminal(task: CustomTask | ContributedTask): [ITerminalInstance, string] { - let options = this.resolveOptions(task.command.options); + let options = this.resolveOptions(task, task.command.options); let { command, args } = this.resolveCommandAndArgs(task); - let terminalName = nls.localize('TerminalTaskSystem.terminalName', 'Task - {0}', task.name); + let workspaceFolder = Task.getWorkspaceFolder(task); + let needsFolderQualification = workspaceFolder && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; + let terminalName = nls.localize('TerminalTaskSystem.terminalName', 'Task - {0}', needsFolderQualification ? Task.getQualifiedLabel(task) : task.name); let waitOnExit: boolean | string = false; if (task.command.presentation.reveal !== RevealKind.Never || !task.isBackground) { waitOnExit = nls.localize('reuseTerminal', 'Terminal will be reused by tasks, press any key to close it.'); - }; + } let shellLaunchConfig: IShellLaunchConfig = undefined; let isShellCommand = task.command.runtime === RuntimeType.Shell; if (isShellCommand) { @@ -490,7 +445,11 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { shellArgs.push(commandLine); shellLaunchConfig.args = windowsShellArgs ? shellArgs.join(' ') : shellArgs; if (task.command.presentation.echo) { - shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${commandLine} <\x1b[0m\n`; + if (needsFolderQualification) { + shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${commandLine} <\x1b[0m\n`; + } else { + shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${commandLine} <\x1b[0m\n`; + } } } else { let cwd = options && options.cwd ? options.cwd : process.cwd(); @@ -513,34 +472,32 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { } return args.join(' '); }; - shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; + if (needsFolderQualification) { + shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; + } else { + shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; + } } } if (options.cwd) { shellLaunchConfig.cwd = options.cwd; } if (options.env) { - let env: IStringDictionary = Object.create(null); - Object.keys(process.env).forEach((key) => { - env[key] = process.env[key]; - }); - Object.keys(options.env).forEach((key) => { - env[key] = options.env[key]; - }); - shellLaunchConfig.env = env; + shellLaunchConfig.env = options.env; } let prefersSameTerminal = task.command.presentation.panel === PanelKind.Dedicated; let allowsSharedTerminal = task.command.presentation.panel === PanelKind.Shared; + let taskKey = Task.getMapKey(task); let terminalToReuse: TerminalData; if (prefersSameTerminal) { - let terminalId = this.sameTaskTerminals[task._id]; + let terminalId = this.sameTaskTerminals[taskKey]; if (terminalId) { terminalToReuse = this.terminals[terminalId]; - delete this.sameTaskTerminals[task._id]; + delete this.sameTaskTerminals[taskKey]; } } else if (allowsSharedTerminal) { - let terminalId = this.idleTaskTerminals.remove(task._id) || this.idleTaskTerminals.shift(); + let terminalId = this.idleTaskTerminals.remove(taskKey) || this.idleTaskTerminals.shift(); if (terminalId) { terminalToReuse = this.terminals[terminalId]; } @@ -551,24 +508,24 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { } const result = this.terminalService.createInstance(shellLaunchConfig); - const key = result.id.toString(); + const terminalKey = result.id.toString(); result.onDisposed((terminal) => { - let terminalData = this.terminals[key]; + let terminalData = this.terminals[terminalKey]; if (terminalData) { - delete this.terminals[key]; + delete this.terminals[terminalKey]; delete this.sameTaskTerminals[terminalData.lastTask]; this.idleTaskTerminals.delete(terminalData.lastTask); } }); - this.terminals[key] = { terminal: result, lastTask: task._id }; + this.terminals[terminalKey] = { terminal: result, lastTask: taskKey }; return [result, command]; } private resolveCommandAndArgs(task: CustomTask | ContributedTask): { command: string, args: string[] } { // First we need to use the command args: let args: string[] = task.command.args ? task.command.args.slice() : []; - args = this.resolveVariables(args); - let command: string = this.resolveVariable(task.command.name); + args = this.resolveVariables(task, args); + let command: string = this.resolveVariable(task, task.command.name); return { command, args }; } @@ -611,11 +568,11 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { return command; } - private resolveVariables(value: string[]): string[] { - return value.map(s => this.resolveVariable(s)); + private resolveVariables(task: CustomTask | ContributedTask, value: string[]): string[] { + return value.map(s => this.resolveVariable(task, s)); } - private resolveMatchers(values: (string | ProblemMatcher)[]): ProblemMatcher[] { + private resolveMatchers(task: CustomTask | ContributedTask, values: (string | ProblemMatcher)[]): ProblemMatcher[] { if (values === void 0 || values === null || values.length === 0) { return []; } @@ -639,31 +596,31 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { result.push(matcher); } else { let copy = Objects.clone(matcher); - copy.filePrefix = this.resolveVariable(copy.filePrefix); + copy.filePrefix = this.resolveVariable(task, copy.filePrefix); result.push(copy); } }); return result; } - private resolveVariable(value: string): string { - // TODO@Dirk adopt new configuration resolver service https://github.com/Microsoft/vscode/issues/31365 - return this.configurationResolverService.resolve(this.contextService.getLegacyWorkspace().resource, value); + private resolveVariable(task: CustomTask | ContributedTask, value: string): string { + // TODO@Dirk Task.getWorkspaceFolder should return a WorkspaceFolder that is defined in workspace.ts + return this.configurationResolverService.resolve(Task.getWorkspaceFolder(task), value); } - private resolveOptions(options: CommandOptions): CommandOptions { + private resolveOptions(task: CustomTask | ContributedTask, options: CommandOptions): CommandOptions { if (options === void 0 || options === null) { - return { cwd: this.resolveVariable('${cwd}') }; + return { cwd: this.resolveVariable(task, '${workspaceFolder}') }; } let result: CommandOptions = Types.isString(options.cwd) - ? { cwd: this.resolveVariable(options.cwd) } - : { cwd: this.resolveVariable('${cwd}') }; + ? { cwd: this.resolveVariable(task, options.cwd) } + : { cwd: this.resolveVariable(task, '${workspaceFolder}') }; if (options.env) { result.env = Object.create(null); Object.keys(options.env).forEach((key) => { let value: any = options.env[key]; if (Types.isString(value)) { - result.env[key] = this.resolveVariable(value); + result.env[key] = this.resolveVariable(task, value); } else { result.env[key] = value.toString(); } diff --git a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts index bbc05d0d7d4..8d54a4baca4 100644 --- a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts +++ b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts @@ -18,7 +18,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as Tasks from '../common/tasks'; import * as TaskConfig from './taskConfiguration'; @@ -145,18 +145,20 @@ export class ProcessRunnerDetector { private contextService: IWorkspaceContextService; private configurationResolverService: IConfigurationResolverService; private taskConfiguration: TaskConfig.ExternalTaskRunnerConfiguration; + private _workspaceRoot: IWorkspaceFolder; private _stderr: string[]; private _stdout: string[]; private _cwd: string; - constructor(fileService: IFileService, contextService: IWorkspaceContextService, configurationResolverService: IConfigurationResolverService, config: TaskConfig.ExternalTaskRunnerConfiguration = null) { + constructor(workspaceFolder: IWorkspaceFolder, fileService: IFileService, contextService: IWorkspaceContextService, configurationResolverService: IConfigurationResolverService, config: TaskConfig.ExternalTaskRunnerConfiguration = null) { this.fileService = fileService; this.contextService = contextService; this.configurationResolverService = configurationResolverService; this.taskConfiguration = config; + this._workspaceRoot = workspaceFolder; this._stderr = []; this._stdout = []; - this._cwd = this.contextService.hasWorkspace() ? Paths.normalize(this.contextService.getLegacyWorkspace().resource.fsPath, true) : ''; + this._cwd = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? Paths.normalize(this._workspaceRoot.uri.fsPath, true) : ''; } public get stderr(): string[] { @@ -171,21 +173,20 @@ export class ProcessRunnerDetector { if (this.taskConfiguration && this.taskConfiguration.command && ProcessRunnerDetector.supports(this.taskConfiguration.command)) { let config = ProcessRunnerDetector.detectorConfig(this.taskConfiguration.command); let args = (this.taskConfiguration.args || []).concat(config.arg); - let options: CommandOptions = this.taskConfiguration.options ? this.resolveCommandOptions(this.taskConfiguration.options) : { cwd: this._cwd }; + let options: CommandOptions = this.taskConfiguration.options ? this.resolveCommandOptions(this._workspaceRoot, this.taskConfiguration.options) : { cwd: this._cwd }; let isShellCommand = !!this.taskConfiguration.isShellCommand; - // TODO@Dirk adopt new configuration resolver service https://github.com/Microsoft/vscode/issues/31365 return this.runDetection( - new LineProcess(this.taskConfiguration.command, this.configurationResolverService.resolve(this.contextService.getLegacyWorkspace().resource, args), isShellCommand, options), + new LineProcess(this.taskConfiguration.command, this.configurationResolverService.resolve(this._workspaceRoot, args), isShellCommand, options), this.taskConfiguration.command, isShellCommand, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); } else { if (detectSpecific) { let detectorPromise: TPromise; if ('gulp' === detectSpecific) { - detectorPromise = this.tryDetectGulp(list); + detectorPromise = this.tryDetectGulp(this._workspaceRoot, list); } else if ('jake' === detectSpecific) { - detectorPromise = this.tryDetectJake(list); + detectorPromise = this.tryDetectJake(this._workspaceRoot, list); } else if ('grunt' === detectSpecific) { - detectorPromise = this.tryDetectGrunt(list); + detectorPromise = this.tryDetectGrunt(this._workspaceRoot, list); } return detectorPromise.then((value) => { if (value) { @@ -195,15 +196,15 @@ export class ProcessRunnerDetector { } }); } else { - return this.tryDetectGulp(list).then((value) => { + return this.tryDetectGulp(this._workspaceRoot, list).then((value) => { if (value) { return value; } - return this.tryDetectJake(list).then((value) => { + return this.tryDetectJake(this._workspaceRoot, list).then((value) => { if (value) { return value; } - return this.tryDetectGrunt(list).then((value) => { + return this.tryDetectGrunt(this._workspaceRoot, list).then((value) => { if (value) { return value; } @@ -215,20 +216,20 @@ export class ProcessRunnerDetector { } } - private resolveCommandOptions(options: CommandOptions): CommandOptions { + private resolveCommandOptions(workspaceFolder: IWorkspaceFolder, options: CommandOptions): CommandOptions { // TODO@Dirk adopt new configuration resolver service https://github.com/Microsoft/vscode/issues/31365 let result = Objects.clone(options); if (result.cwd) { - result.cwd = this.configurationResolverService.resolve(this.contextService.getLegacyWorkspace().resource, result.cwd); + result.cwd = this.configurationResolverService.resolve(workspaceFolder, result.cwd); } if (result.env) { - result.env = this.configurationResolverService.resolve(this.contextService.getLegacyWorkspace().resource, result.env); + result.env = this.configurationResolverService.resolve(workspaceFolder, result.env); } return result; } - private tryDetectGulp(list: boolean): TPromise { - return this.fileService.resolveFile(this.contextService.toResource('gulpfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + private tryDetectGulp(workspaceFolder: IWorkspaceFolder, list: boolean): TPromise { + return this.fileService.resolveFile(workspaceFolder.toResource('gulpfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) let config = ProcessRunnerDetector.detectorConfig('gulp'); let process = new LineProcess('gulp', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'gulp', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); @@ -237,8 +238,8 @@ export class ProcessRunnerDetector { }); } - private tryDetectGrunt(list: boolean): TPromise { - return this.fileService.resolveFile(this.contextService.toResource('Gruntfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + private tryDetectGrunt(workspaceFolder: IWorkspaceFolder, list: boolean): TPromise { + return this.fileService.resolveFile(workspaceFolder.toResource('Gruntfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) let config = ProcessRunnerDetector.detectorConfig('grunt'); let process = new LineProcess('grunt', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'grunt', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); @@ -247,16 +248,16 @@ export class ProcessRunnerDetector { }); } - private tryDetectJake(list: boolean): TPromise { + private tryDetectJake(workspaceFolder: IWorkspaceFolder, list: boolean): TPromise { let run = () => { let config = ProcessRunnerDetector.detectorConfig('jake'); let process = new LineProcess('jake', [config.arg], true, { cwd: this._cwd }); return this.runDetection(process, 'jake', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); }; - return this.fileService.resolveFile(this.contextService.toResource('Jakefile')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(workspaceFolder.toResource('Jakefile')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) return run(); }, (err: any) => { - return this.fileService.resolveFile(this.contextService.toResource('Jakefile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(workspaceFolder.toResource('Jakefile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) return run(); }, (err: any) => { return null; diff --git a/src/vs/workbench/parts/tasks/node/processTaskSystem.ts b/src/vs/workbench/parts/tasks/node/processTaskSystem.ts index b15509838dc..6018a076566 100644 --- a/src/vs/workbench/parts/tasks/node/processTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/node/processTaskSystem.ts @@ -24,7 +24,6 @@ import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ProblemMatcher, ProblemMatcherRegistry } from 'vs/platform/markers/common/problemMatcher'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEvents } from 'vs/workbench/parts/tasks/common/problemCollectors'; import { @@ -44,7 +43,6 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { private outputService: IOutputService; private telemetryService: ITelemetryService; private configurationResolverService: IConfigurationResolverService; - private contextService: IWorkspaceContextService; private outputChannel: IOutputChannel; @@ -54,12 +52,11 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { private activeTaskPromise: TPromise; constructor(markerService: IMarkerService, modelService: IModelService, telemetryService: ITelemetryService, - outputService: IOutputService, configurationResolverService: IConfigurationResolverService, contextService: IWorkspaceContextService, outputChannelId: string) { + outputService: IOutputService, configurationResolverService: IConfigurationResolverService, outputChannelId: string) { super(); this.markerService = markerService; this.modelService = modelService; this.outputService = outputService; - this.contextService = contextService; this.telemetryService = telemetryService; this.configurationResolverService = configurationResolverService; @@ -112,8 +109,8 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { return true; } - public terminate(_id: string): TPromise { - if (!this.activeTask || this.activeTask._id !== _id) { + public terminate(task: Task): TPromise { + if (!this.activeTask || Task.getMapKey(this.activeTask) !== Task.getMapKey(task)) { return TPromise.as({ success: false, task: undefined }); } return this.terminateAll()[0]; @@ -146,16 +143,37 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { try { let result = this.doExecuteTask(task, telemetryEvent); result.promise = result.promise.then((success) => { + /* __GDPR__ + "taskService" : { + "${include}": [ + "${TelemetryEvent}" + ] + } + */ this.telemetryService.publicLog(ProcessTaskSystem.TelemetryEventName, telemetryEvent); return success; }, (err: any) => { telemetryEvent.success = false; + /* __GDPR__ + "taskService" : { + "${include}": [ + "${TelemetryEvent}" + ] + } + */ this.telemetryService.publicLog(ProcessTaskSystem.TelemetryEventName, telemetryEvent); return TPromise.wrapError(err); }); return result; } catch (err) { telemetryEvent.success = false; + /* __GDPR__ + "taskService" : { + "${include}": [ + "${TelemetryEvent}" + ] + } + */ this.telemetryService.publicLog(ProcessTaskSystem.TelemetryEventName, telemetryEvent); if (err instanceof TaskError) { throw err; @@ -181,9 +199,9 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { } let args: string[] = commandConfig.args ? commandConfig.args.slice() : []; - args = this.resolveVariables(args); - let command: string = this.resolveVariable(commandConfig.name); - this.childProcess = new LineProcess(command, args, commandConfig.runtime === RuntimeType.Shell, this.resolveOptions(commandConfig.options)); + args = this.resolveVariables(task, args); + let command: string = this.resolveVariable(task, commandConfig.name); + this.childProcess = new LineProcess(command, args, commandConfig.runtime === RuntimeType.Shell, this.resolveOptions(task, commandConfig.options)); telemetryEvent.command = this.childProcess.getSanitizedCommand(); // we have no problem matchers defined. So show the output log let reveal = task.command.presentation.reveal; @@ -196,7 +214,7 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { this.log(`running command${prompt} ${command} ${args.join(' ')}`); } if (task.isBackground) { - let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService); + let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task, task.problemMatchers), this.markerService, this.modelService); let toUnbind: IDisposable[] = []; let event: TaskEvent = { taskId: task._id, taskName: task.name, type: TaskType.Watching, group: task.group }; let eventCounter: number = 0; @@ -259,7 +277,7 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { } else { let event: TaskEvent = { taskId: task._id, taskName: task.name, type: TaskType.SingleRun, group: task.group }; this.emit(TaskSystemEvents.Active, event); - let startStopProblemMatcher = new StartStopProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService); + let startStopProblemMatcher = new StartStopProblemCollector(this.resolveMatchers(task, task.problemMatchers), this.markerService, this.modelService); this.activeTask = task; this.activeTaskPromise = this.childProcess.start().then((success): ITaskSummary => { this.childProcessEnded(); @@ -329,14 +347,14 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { return false; } - private resolveOptions(options: CommandOptions): CommandOptions { - let result: CommandOptions = { cwd: this.resolveVariable(options.cwd) }; + private resolveOptions(task: CustomTask, options: CommandOptions): CommandOptions { + let result: CommandOptions = { cwd: this.resolveVariable(task, options.cwd) }; if (options.env) { result.env = Object.create(null); Object.keys(options.env).forEach((key) => { let value: any = options.env[key]; if (Types.isString(value)) { - result.env[key] = this.resolveVariable(value); + result.env[key] = this.resolveVariable(task, value); } else { result.env[key] = value.toString(); } @@ -345,11 +363,11 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { return result; } - private resolveVariables(value: string[]): string[] { - return value.map(s => this.resolveVariable(s)); + private resolveVariables(task: CustomTask, value: string[]): string[] { + return value.map(s => this.resolveVariable(task, s)); } - private resolveMatchers(values: (string | ProblemMatcher)[]): ProblemMatcher[] { + private resolveMatchers(task: CustomTask, values: (string | ProblemMatcher)[]): ProblemMatcher[] { if (values === void 0 || values === null || values.length === 0) { return []; } @@ -373,16 +391,15 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { result.push(matcher); } else { let copy = Objects.clone(matcher); - copy.filePrefix = this.resolveVariable(copy.filePrefix); + copy.filePrefix = this.resolveVariable(task, copy.filePrefix); result.push(copy); } }); return result; } - private resolveVariable(value: string): string { - // TODO@Dirk adopt new configuration resolver service https://github.com/Microsoft/vscode/issues/31365 - return this.configurationResolverService.resolve(this.contextService.getLegacyWorkspace().resource, value); + private resolveVariable(task: CustomTask, value: string): string { + return this.configurationResolverService.resolve(Task.getWorkspaceFolder(task), value); } public log(value: string): void { diff --git a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts index 513e890116a..eaf473e96d8 100644 --- a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts +++ b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts @@ -14,12 +14,14 @@ import * as Platform from 'vs/base/common/platform'; import * as Types from 'vs/base/common/types'; import * as UUID from 'vs/base/common/uuid'; -import { ValidationStatus, IProblemReporter as IProblemReporterBase, NullProblemReporter as NullProblemReporterBase } from 'vs/base/common/parsers'; +import { ValidationStatus, IProblemReporter as IProblemReporterBase } from 'vs/base/common/parsers'; import { NamedProblemMatcher, ProblemMatcher, ProblemMatcherParser, Config as ProblemMatcherConfig, isNamedProblemMatcher, ProblemMatcherRegistry } from 'vs/platform/markers/common/problemMatcher'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; + import * as Tasks from '../common/tasks'; import { TaskDefinitionRegistry } from '../common/taskDefinitionRegistry'; @@ -561,6 +563,7 @@ function _freeze(this: void, target: T, properties: MetaData[]): Read } interface ParseContext { + workspaceFolder: IWorkspaceFolder; problemReporter: IProblemReporter; namedProblemMatchers: IStringDictionary; uuidMap: UUIDMap; @@ -616,7 +619,7 @@ namespace ShellConfiguration { namespace CommandOptions { const properties: MetaData[] = [{ property: 'cwd' }, { property: 'env' }, { property: 'shell', type: ShellConfiguration }]; - const defaults: CommandOptions = { cwd: '${workspaceRoot}' }; + const defaults: CommandOptions = { cwd: '${workspaceFolder}' }; export function from(this: void, options: CommandOptions, context: ParseContext): Tasks.CommandOptions { let result: Tasks.CommandOptions = {}; @@ -1023,13 +1026,13 @@ const source: Tasks.TaskSource = { }; namespace GroupKind { - export function from(this: void, external: string | GroupKind): [string, boolean] { + export function from(this: void, external: string | GroupKind): [string, Tasks.GroupType] { if (external === void 0) { return undefined; } if (Types.isString(external)) { if (Tasks.TaskGroup.is(external)) { - return [external, false]; + return [external, Tasks.GroupType.user]; } else { return undefined; } @@ -1040,7 +1043,7 @@ namespace GroupKind { let group: string = external.kind; let isDefault: boolean = !!external.isDefault; - return [group, isDefault]; + return [group, isDefault ? Tasks.GroupType.default : Tasks.GroupType.user]; } } @@ -1076,20 +1079,20 @@ namespace ConfigurationProperties { if (external.group !== void 0) { if (Types.isString(external.group) && Tasks.TaskGroup.is(external.group)) { result.group = external.group; - result.isDefaultGroupEntry = false; + result.groupType = Tasks.GroupType.user; } else { let values = GroupKind.from(external.group); if (values) { result.group = values[0]; - result.isDefaultGroupEntry = values[1]; + result.groupType = values[1]; } } } if (external.dependsOn !== void 0) { if (Types.isString(external.dependsOn)) { - result.dependsOn = [external.dependsOn]; + result.dependsOn = [{ workspaceFolder: context.workspaceFolder, task: external.dependsOn }]; } else if (Types.isStringArray(external.dependsOn)) { - result.dependsOn = external.dependsOn.slice(); + result.dependsOn = external.dependsOn.map((task) => { return { workspaceFolder: context.workspaceFolder, task: task }; }); } } if (includePresentation && (external.presentation !== void 0 || (external as LegacyCommandProperties).terminal !== void 0)) { @@ -1151,15 +1154,46 @@ namespace ConfiguringTask { identifier = { type }; - Object.keys(typeDeclaration.properties).forEach((property) => { + let properties = typeDeclaration.properties; + let required: Set = new Set(); + if (Array.isArray(typeDeclaration.required)) { + typeDeclaration.required.forEach(element => Types.isString(element) ? required.add(element) : required); + } + for (let property of Object.keys(properties)) { let value = external[property]; if (value !== void 0 && value !== null) { identifier[property] = value; + } else if (required.has(property)) { + let schema = properties[property]; + if (schema.default !== void 0) { + identifier[property] = Objects.deepClone(schema.default); + } else { + switch (schema.type) { + case 'boolean': + identifier[property] = false; + break; + case 'number': + case 'integer': + identifier[property] = 0; + break; + case 'string': + identifier[property] = ''; + break; + default: + let message = nls.localize( + 'ConfigurationParser.missingRequiredProperty', + 'Error: the task configuration \'{0}\' missed the required property \'{1}\'. The task configuration will be ignored.', JSON.stringify(external, undefined, 0), property + ); + context.problemReporter.error(message); + return undefined; + } + } } - }); + } } let taskIdentifier = TaskIdentifier.from(identifier); let configElement: Tasks.TaskSourceConfigElement = { + workspaceFolder: context.workspaceFolder, file: '.vscode\\tasks.json', index, element: external @@ -1167,7 +1201,7 @@ namespace ConfiguringTask { let result: Tasks.ConfiguringTask = { type: type, configures: taskIdentifier, - _id: taskIdentifier._key, + _id: `${typeDeclaration.extensionId}.${taskIdentifier._key}`, _source: Objects.assign({}, source, { config: configElement }), _label: undefined }; @@ -1212,6 +1246,9 @@ namespace CustomTask { return undefined; } let taskName = external.taskName; + if (Types.isString(external.label) && context.schemaVersion === Tasks.JsonSchemaVersion.V2_0_0) { + taskName = external.label; + } if (!taskName) { context.problemReporter.error(nls.localize('ConfigurationParser.noTaskName', 'Error: tasks must provide a taskName property. The task will be ignored.\n{0}\n', JSON.stringify(external, null, 4))); return undefined; @@ -1220,7 +1257,7 @@ namespace CustomTask { let result: Tasks.CustomTask = { type: 'custom', _id: context.uuidMap.getUUID(taskName), - _source: Objects.assign({}, source, { config: { index, element: external, file: '.vscode\\tasks.json' } }), + _source: Objects.assign({}, source, { config: { index, element: external, file: '.vscode\\tasks.json', workspaceFolder: context.workspaceFolder } }), _label: taskName, name: taskName, identifier: taskName, @@ -1278,8 +1315,8 @@ namespace CustomTask { if (task.problemMatchers === void 0) { task.problemMatchers = EMPTY_ARRAY; } - if (task.group !== void 0 && task.isDefaultGroupEntry === void 0) { - task.isDefaultGroupEntry = false; + if (task.group !== void 0 && task.groupType === void 0) { + task.groupType = Tasks.GroupType.user; } } @@ -1296,7 +1333,7 @@ namespace CustomTask { let resultConfigProps: Tasks.ConfigurationProperties = result; assignProperty(resultConfigProps, configuredProps, 'group'); - assignProperty(resultConfigProps, configuredProps, 'isDefaultGroupEntry'); + assignProperty(resultConfigProps, configuredProps, 'groupType'); assignProperty(resultConfigProps, configuredProps, 'isBackground'); assignProperty(resultConfigProps, configuredProps, 'dependsOn'); assignProperty(resultConfigProps, configuredProps, 'problemMatchers'); @@ -1306,7 +1343,7 @@ namespace CustomTask { let contributedConfigProps: Tasks.ConfigurationProperties = contributedTask; fillProperty(resultConfigProps, contributedConfigProps, 'group'); - fillProperty(resultConfigProps, contributedConfigProps, 'isDefaultGroupEntry'); + fillProperty(resultConfigProps, contributedConfigProps, 'groupType'); fillProperty(resultConfigProps, contributedConfigProps, 'isBackground'); fillProperty(resultConfigProps, contributedConfigProps, 'dependsOn'); fillProperty(resultConfigProps, contributedConfigProps, 'problemMatchers'); @@ -1348,11 +1385,11 @@ namespace TaskParser { CustomTask.fillGlobals(customTask, globals); CustomTask.fillDefaults(customTask, context); if (context.engine === Tasks.ExecutionEngine.Terminal && customTask.command && customTask.command.name && customTask.command.runtime === Tasks.RuntimeType.Shell && customTask.command.args && customTask.command.args.length > 0) { - if (hasUnescapedSpaces(customTask.command.name) || customTask.command.args.some(hasUnescapedSpaces)) { + if (customTask.command.args.some(hasUnescapedSpaces)) { context.problemReporter.warn( nls.localize( 'taskConfiguration.shellArgs', - 'Warning: the task \'{0}\' is a shell command and either the command name or one of its arguments has unescaped spaces. To ensure correct command line quoting please merge args into the command.', + 'Warning: the task \'{0}\' is a shell command and one of its arguments might have unescaped spaces. To ensure correct command line quoting please merge args into the command.', customTask.name ) ); @@ -1399,10 +1436,10 @@ namespace TaskParser { } if (defaultBuildTask.rank > -1 && defaultBuildTask.rank < 2) { defaultBuildTask.task.group = Tasks.TaskGroup.Build; - defaultBuildTask.task.isDefaultGroupEntry = false; + defaultBuildTask.task.groupType = Tasks.GroupType.user; } else if (defaultTestTask.rank > -1 && defaultTestTask.rank < 2) { defaultTestTask.task.group = Tasks.TaskGroup.Test; - defaultTestTask.task.isDefaultGroupEntry = false; + defaultTestTask.task.groupType = Tasks.GroupType.user; } return result; @@ -1438,25 +1475,20 @@ namespace TaskParser { } function hasUnescapedSpaces(this: void, value: string): boolean { - if (Platform.isWindows) { - if (value.length >= 2 && value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') { - return false; - } - return value.indexOf(' ') !== -1; - } else { - if (value.length >= 2 && ((value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') || (value.charAt(0) === '\'' && value.charAt(value.length - 1) === '\''))) { - return false; - } - for (let i = 0; i < value.length; i++) { - let ch = value.charAt(i); - if (ch === ' ') { - if (i === 0 || value.charAt(i - 1) !== '\\') { - return true; - } - } - } + let escapeChar = Platform.isWindows ? '`' : '\\'; + + if (value.length >= 2 && ((value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') || (value.charAt(0) === '\'' && value.charAt(value.length - 1) === '\''))) { return false; } + for (let i = 0; i < value.length; i++) { + let ch = value.charAt(i); + if (ch === ' ') { + if (i === 0 || value.charAt(i - 1) !== escapeChar) { + return true; + } + } + } + return false; } export function quickParse(this: void, externals: (CustomTask | ConfiguringTask)[], context: ParseContext): (Tasks.CustomTask | Tasks.ConfiguringTask)[] { @@ -1611,10 +1643,6 @@ export interface IProblemReporter extends IProblemReporterBase { clearOutput(): void; } -class NullProblemReporter extends NullProblemReporterBase implements IProblemReporter { - clearOutput(): void { }; -} - class UUIDMap { private last: IStringDictionary; @@ -1678,10 +1706,12 @@ class UUIDMap { class ConfigurationParser { + private workspaceFolder: IWorkspaceFolder; private problemReporter: IProblemReporter; private uuidMap: UUIDMap; - constructor(problemReporter: IProblemReporter, uuidMap: UUIDMap) { + constructor(workspaceFolder: IWorkspaceFolder, problemReporter: IProblemReporter, uuidMap: UUIDMap) { + this.workspaceFolder = workspaceFolder; this.problemReporter = problemReporter; this.uuidMap = uuidMap; } @@ -1689,10 +1719,8 @@ class ConfigurationParser { public run(fileConfig: ExternalTaskRunnerConfiguration): ParseResult { let engine = ExecutionEngine.from(fileConfig); let schemaVersion = JsonSchemaVersion.from(fileConfig); - if (engine === Tasks.ExecutionEngine.Terminal) { - this.problemReporter.clearOutput(); - } let context: ParseContext = { + workspaceFolder: this.workspaceFolder, problemReporter: this.problemReporter, uuidMap: this.uuidMap, namedProblemMatchers: undefined, @@ -1751,7 +1779,7 @@ class ConfigurationParser { let isBackground = fileConfig.isBackground ? !!fileConfig.isBackground : fileConfig.isWatching ? !!fileConfig.isWatching : undefined; let task: Tasks.CustomTask = { _id: context.uuidMap.getUUID(globals.command.name), - _source: Objects.assign({}, source, { config: { index: -1, element: fileConfig } }), + _source: Objects.assign({}, source, { config: { index: -1, element: fileConfig, workspaceFolder: context.workspaceFolder } }), _label: globals.command.name, type: 'custom', name: globals.command.name, @@ -1769,7 +1797,7 @@ class ConfigurationParser { let value = GroupKind.from(fileConfig.group); if (value) { task.group = value[0]; - task.isDefaultGroupEntry = value[1]; + task.groupType = value[1]; } else if (fileConfig.group === 'none') { task.group = undefined; } @@ -1783,11 +1811,16 @@ class ConfigurationParser { } } -let uuidMap: UUIDMap = new UUIDMap(); -export function parse(configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult { +let uuidMaps: Map = new Map(); +export function parse(workspaceFolder: IWorkspaceFolder, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult { + let uuidMap = uuidMaps.get(workspaceFolder.uri.toString()); + if (!uuidMap) { + uuidMap = new UUIDMap(); + uuidMaps.set(workspaceFolder.uri.toString(), uuidMap); + } try { uuidMap.start(); - return (new ConfigurationParser(logger, uuidMap)).run(configuration); + return (new ConfigurationParser(workspaceFolder, logger, uuidMap)).run(configuration); } finally { uuidMap.finish(); } @@ -1801,35 +1834,6 @@ export function getTaskIdentifier(value: TaskIdentifier): Tasks.TaskIdentifier { return TaskIdentifier.from(value); } -export function findTaskIndex(fileConfig: ExternalTaskRunnerConfiguration, task: Tasks.Task): number { - if (!fileConfig || !fileConfig.tasks) { - return undefined; - } - if (fileConfig.tasks.length === 0) { - return -1; - } - let localMap = new UUIDMap(uuidMap); - let context: ParseContext = { - problemReporter: this.problemReporter, - uuidMap: localMap, - namedProblemMatchers: undefined, - engine: ExecutionEngine.from(fileConfig), - schemaVersion: JsonSchemaVersion.from(fileConfig) - }; - try { - localMap.start(); - let tasks = TaskParser.quickParse(fileConfig.tasks, context); - for (let i = 0; i < tasks.length; i++) { - if (task._id === tasks[i]._id) { - return i; - } - } - return -1; - } finally { - localMap.finish(); - } -} - /* class VersionConverter { constructor(private problemReporter: IProblemReporter) { diff --git a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts index c89319b81dd..e8506aca7e9 100644 --- a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts +++ b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import URI from 'vs/base/common/uri'; import * as assert from 'assert'; import Severity from 'vs/base/common/severity'; import * as UUID from 'vs/base/common/uuid'; @@ -11,10 +12,17 @@ import * as UUID from 'vs/base/common/uuid'; import * as Platform from 'vs/base/common/platform'; import { ValidationStatus } from 'vs/base/common/parsers'; import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'vs/platform/markers/common/problemMatcher'; +import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as Tasks from 'vs/workbench/parts/tasks/common/tasks'; import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/parts/tasks/node/taskConfiguration'; +const workspaceFolder: IWorkspaceFolder = new WorkspaceFolder({ + uri: URI.file('/workspace/folderOne'), + name: 'folderOne', + index: 0 +}); + class ProblemReporter implements IProblemReporter { private _validationStatus: ValidationStatus = new ValidationStatus(); @@ -121,7 +129,7 @@ class CommandConfigurationBuilder { runtime: Tasks.RuntimeType.Process, args: [], options: { - cwd: '${workspaceRoot}' + cwd: '${workspaceFolder}' }, presentation: this.presentationBuilder.result, suppressTaskName: false @@ -177,7 +185,7 @@ class CustomTaskBuilder { this.commandBuilder = new CommandConfigurationBuilder(this, command); this.result = { _id: name, - _source: { kind: Tasks.TaskSourceKind.Workspace, label: 'workspace', config: { element: undefined, index: -1, file: '.vscode/tasks.json' } }, + _source: { kind: Tasks.TaskSourceKind.Workspace, label: 'workspace', config: { workspaceFolder: workspaceFolder, element: undefined, index: -1, file: '.vscode/tasks.json' } }, _label: name, type: 'custom', identifier: name, @@ -196,12 +204,12 @@ class CustomTaskBuilder { public group(value: Tasks.TaskGroup): CustomTaskBuilder { this.result.group = value; - this.result.isDefaultGroupEntry = false; + this.result.groupType = Tasks.GroupType.user; return this; } - public isPrimary(value: boolean): CustomTaskBuilder { - this.result.isDefaultGroupEntry = value; + public groupType(value: Tasks.GroupType): CustomTaskBuilder { + this.result.groupType = value; return this; } @@ -242,7 +250,7 @@ class ProblemMatcherBuilder { applyTo: ApplyToKind.allDocuments, severity: undefined, fileLocation: FileLocationKind.Relative, - filePrefix: '${cwd}', + filePrefix: '${workspaceFolder}', pattern: undefined }; } @@ -347,7 +355,7 @@ class PatternBuilder { function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, resolved: number) { let reporter = new ProblemReporter(); - let result = parse(external, reporter); + let result = parse(workspaceFolder, external, reporter); assert.ok(!reporter.receivedMessage); assert.strictEqual(result.custom.length, 1); let task = result.custom[0]; @@ -358,7 +366,7 @@ function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, re function testConfiguration(external: ExternalTaskRunnerConfiguration, builder: ConfiguationBuilder): void { builder.done(); let reporter = new ProblemReporter(); - let result = parse(external, reporter); + let result = parse(workspaceFolder, external, reporter); if (reporter.receivedMessage) { assert.ok(false, reporter.lastMessage); } @@ -450,14 +458,14 @@ function assertConfiguration(result: ParseResult, expected: Tasks.Task[]): void function assertTask(actual: Tasks.Task, expected: Tasks.Task) { assert.ok(actual._id); assert.strictEqual(actual.name, expected.name, 'name'); - if (!Tasks.CompositeTask.is(actual) && !Tasks.CompositeTask.is(expected)) { + if (!Tasks.InMemoryTask.is(actual) && !Tasks.InMemoryTask.is(expected)) { assertCommandConfiguration(actual.command, expected.command); } assert.strictEqual(actual.isBackground, expected.isBackground, 'isBackground'); assert.strictEqual(typeof actual.problemMatchers, typeof expected.problemMatchers); assert.strictEqual(actual.promptOnClose, expected.promptOnClose, 'promptOnClose'); assert.strictEqual(actual.group, expected.group, 'group'); - assert.strictEqual(actual.isDefaultGroupEntry, expected.isDefaultGroupEntry, 'isPrimaryGroupEntry'); + assert.strictEqual(actual.groupType, expected.groupType, 'groupType'); if (actual.problemMatchers && expected.problemMatchers) { assert.strictEqual(actual.problemMatchers.length, expected.problemMatchers.length); for (let i = 0; i < actual.problemMatchers.length; i++) { @@ -725,7 +733,7 @@ suite('Tasks version 0.1.0', () => { task('tsc', 'tsc'). group(Tasks.TaskGroup.Build). command().suppressTaskName(true). - options({ cwd: '${workspaceRoot}', env: { key: 'value' } }); + options({ cwd: '${workspaceFolder}', env: { key: 'value' } }); testConfiguration( { version: '0.1.0', @@ -1510,7 +1518,7 @@ suite('Tasks version 2.0.0', () => { let builder = new ConfiguationBuilder(); builder.task('dir', 'dir'). group(Tasks.TaskGroup.Build). - isPrimary(true). + groupType(Tasks.GroupType.default). command().suppressTaskName(true). runtime(Tasks.RuntimeType.Shell). presentation().echo(true); @@ -1570,7 +1578,7 @@ suite('Tasks version 2.0.0', () => { let builder = new ConfiguationBuilder(); builder.task('dir', 'dir'). group(Tasks.TaskGroup.Build). - isPrimary(true). + groupType(Tasks.GroupType.default). command().suppressTaskName(true). runtime(Tasks.RuntimeType.Shell). presentation().echo(true); @@ -1588,7 +1596,7 @@ suite('Bugs / regression tests', () => { windows: { command: 'powershell', options: { - cwd: '${workspaceRoot}' + cwd: '${workspaceFolder}' }, tasks: [ { @@ -1611,7 +1619,7 @@ suite('Bugs / regression tests', () => { osx: { command: '/bin/bash', options: { - cwd: '${workspaceRoot}' + cwd: '${workspaceFolder}' }, tasks: [ { @@ -1632,14 +1640,14 @@ suite('Bugs / regression tests', () => { builder.task('composeForDebug', 'powershell'). command().suppressTaskName(true). args(['-ExecutionPolicy', 'RemoteSigned', '.\\dockerTask.ps1', '-ComposeForDebug', '-Environment', 'debug']). - options({ cwd: '${workspaceRoot}' }). + options({ cwd: '${workspaceFolder}' }). presentation().echo(true).reveal(Tasks.RevealKind.Always); testConfiguration(external, builder); } else if (Platform.isMacintosh) { builder.task('composeForDebug', '/bin/bash'). command().suppressTaskName(true). args(['-c', './dockerTask.sh composeForDebug debug']). - options({ cwd: '${workspaceRoot}' }). + options({ cwd: '${workspaceFolder}' }). presentation().reveal(Tasks.RevealKind.Always); testConfiguration(external, builder); } diff --git a/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts b/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts index 635abfe36da..5ae1d3e6fb0 100644 --- a/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts +++ b/src/vs/workbench/parts/terminal/browser/terminalQuickOpen.ts @@ -5,15 +5,15 @@ 'use strict'; import nls = require('vs/nls'); -import strings = require('vs/base/common/strings'); -import scorer = require('vs/base/common/scorer'); import { TPromise } from 'vs/base/common/winjs.base'; import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen'; import { QuickOpenModel, QuickOpenEntry } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal'; -import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; +import { stripWildcards } from 'vs/base/common/strings'; +import { matchesFuzzy } from 'vs/base/common/filters'; +import { ICommandService } from 'vs/platform/commands/common/commands'; export class TerminalEntry extends QuickOpenEntry { @@ -49,7 +49,7 @@ export class CreateTerminal extends QuickOpenEntry { constructor( private label: string, - private terminalService: ITerminalService + private commandService: ICommandService ) { super(); } @@ -64,11 +64,7 @@ export class CreateTerminal extends QuickOpenEntry { public run(mode: Mode, context: IEntryRunContext): boolean { if (mode === Mode.OPEN) { - setTimeout(() => { - const newTerminal = this.terminalService.createInstance(); - this.terminalService.setActiveInstance(newTerminal); - this.terminalService.showPanel(true); - }, 0); + setTimeout(() => this.commandService.executeCommand('workbench.action.terminal.new'), 0); return true; } @@ -78,31 +74,33 @@ export class CreateTerminal extends QuickOpenEntry { export class TerminalPickerHandler extends QuickOpenHandler { + public static readonly ID = 'workbench.picker.terminals'; + constructor( @ITerminalService private terminalService: ITerminalService, - @IPanelService private panelService: IPanelService + @ICommandService private commandService: ICommandService, ) { super(); } public getResults(searchValue: string): TPromise { searchValue = searchValue.trim(); - const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase(); + const normalizedSearchValueLowercase = stripWildcards(searchValue).toLowerCase(); const terminalEntries: QuickOpenEntry[] = this.getTerminals(); - terminalEntries.push(new CreateTerminal(nls.localize("'workbench.action.terminal.newplus", "$(plus) Create New Integrated Terminal"), this.terminalService)); + terminalEntries.push(new CreateTerminal(nls.localize("'workbench.action.terminal.newplus", "$(plus) Create New Integrated Terminal"), this.commandService)); const entries = terminalEntries.filter(e => { if (!searchValue) { return true; } - if (!scorer.matches(e.getLabel(), normalizedSearchValueLowercase)) { + const highlights = matchesFuzzy(normalizedSearchValueLowercase, e.getLabel(), true); + if (!highlights) { return false; } - const { labelHighlights, descriptionHighlights } = QuickOpenEntry.highlight(e, searchValue); - e.setHighlights(labelHighlights, descriptionHighlights); + e.setHighlights(highlights); return true; }); diff --git a/src/vs/workbench/parts/terminal/browser/terminalWidgetManager.ts b/src/vs/workbench/parts/terminal/browser/terminalWidgetManager.ts index 279eff5b528..4a1fb003d5e 100644 --- a/src/vs/workbench/parts/terminal/browser/terminalWidgetManager.ts +++ b/src/vs/workbench/parts/terminal/browser/terminalWidgetManager.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITerminalConfigHelper } from 'vs/workbench/parts/terminal/common/terminal'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; export class TerminalWidgetManager { @@ -14,7 +13,6 @@ export class TerminalWidgetManager { private _messageListeners: IDisposable[] = []; constructor( - private _configHelper: ITerminalConfigHelper, terminalWrapper: HTMLElement ) { this._container = document.createElement('div'); @@ -90,4 +88,4 @@ class MessageWidget { this._container.removeChild(this.domNode); } } -} +} \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index dd368fc809c..68add6effcc 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -63,7 +63,7 @@ export interface ITerminalConfiguration { cursorBlinking: boolean; cursorStyle: string; fontFamily: string; - fontLigatures: boolean; + // fontLigatures: boolean; fontSize: number; lineHeight: number; setLocaleVariables: boolean; @@ -91,10 +91,10 @@ export interface ITerminalConfigHelper { export interface ITerminalFont { fontFamily: string; - fontSize: string; + fontSize: number; lineHeight: number; - charWidth: number; - charHeight: number; + charWidth?: number; + charHeight?: number; } export interface IShellLaunchConfig { @@ -232,7 +232,7 @@ export interface ITerminalInstance { * added to the DOM. * @return The ID of the new matcher, this can be used to deregister. */ - registerLinkMatcher(regex: RegExp, handler: (url: string) => void, matchIndex?: number, validationCallback?: (uri: string, element: HTMLElement, callback: (isValid: boolean) => void) => void): number; + registerLinkMatcher(regex: RegExp, handler: (url: string) => void, matchIndex?: number, validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void): number; /** * Deregisters a link matcher if it has been registered. @@ -354,9 +354,23 @@ export interface ITerminalInstance { * * @param listener The listener function which takes the processes' data stream (including * ANSI escape sequences). + * + * @deprecated onLineData will replace this. */ onData(listener: (data: string) => void): IDisposable; + /** + * Attach a listener to listen for new lines added to this terminal instance. + * + * @param listener The listener function which takes new line strings added to the terminal, + * excluding ANSI escape sequences. The line event will fire when an LF character is added to + * the terminal (ie. the line is not wrapped). Note that this means that the line data will + * not fire for the last line, until either the line is ended with a LF character of the process + * is exited. The lineData string will contain the fully wrapped line, not containing any LF/CR + * characters. + */ + onLineData(listener: (lineData: string) => void): IDisposable; + /** * Attach a listener that fires when the terminal's pty process exits. * diff --git a/src/vs/workbench/parts/terminal/common/terminalService.ts b/src/vs/workbench/parts/terminal/common/terminalService.ts index 305ac98c424..55e392cb988 100644 --- a/src/vs/workbench/parts/terminal/common/terminalService.ts +++ b/src/vs/workbench/parts/terminal/common/terminalService.ts @@ -43,7 +43,7 @@ export abstract class TerminalService implements ITerminalService { constructor( @IContextKeyService private _contextKeyService: IContextKeyService, - @IConfigurationService private _configurationService: IConfigurationService, + @IConfigurationService protected _configurationService: IConfigurationService, @IPanelService protected _panelService: IPanelService, @IPartService private _partService: IPartService, @ILifecycleService lifecycleService: ILifecycleService @@ -59,7 +59,11 @@ export abstract class TerminalService implements ITerminalService { this._onInstanceTitleChanged = new Emitter(); this._onInstancesChanged = new Emitter(); - this._configurationService.onDidUpdateConfiguration(() => this.updateConfig()); + this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('terminal.integrated')) { + this.updateConfig(); + } + }); lifecycleService.onWillShutdown(event => event.veto(this._onWillShutdown())); this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService); this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); @@ -185,13 +189,17 @@ export abstract class TerminalService implements ITerminalService { if (!panel || panel.getId() !== TERMINAL_PANEL_ID) { return this._panelService.openPanel(TERMINAL_PANEL_ID, focus).then(() => { if (focus) { - this.getActiveInstance().focus(true); + // Do the focus call asynchronously as going through the + // command palette will force editor focus + setTimeout(() => this.getActiveInstance().focus(true), 0); } complete(void 0); }); } else { if (focus) { - this.getActiveInstance().focus(true); + // Do the focus call asynchronously as going through the + // command palette will force editor focus + setTimeout(() => this.getActiveInstance().focus(true), 0); } complete(void 0); } diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css b/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css index 8fc3d445adc..5ce4d42203a 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css @@ -11,7 +11,6 @@ background-color: transparent!important; user-select: initial; position: relative; - overflow: hidden; } .monaco-workbench .panel.integrated-terminal .terminal-outer-container { @@ -42,11 +41,17 @@ } .monaco-workbench .panel.integrated-terminal .xterm-viewport { - /* Align the viewport to the bottom of the panel, just like the terminal */ + margin-right: -20px; +} + +.monaco-workbench .panel.integrated-terminal canvas { + /* Align the viewport and canvases to the bottom of the panel */ position: absolute; right: -20px; bottom: 0; left: 0; + /* Disable upstream's style */ + top: auto; } .monaco-workbench .panel.integrated-terminal { @@ -67,6 +72,40 @@ text-decoration: underline; } +.monaco-workbench .panel.integrated-terminal .xterm { + position: absolute; + bottom: 0; + left: 0; + user-select: none; +} + +.monaco-workbench .panel.integrated-terminal .xterm:focus { + /* Hide outline when focus jumps from xterm to the text area */ + outline: none; +} + +.hc-black .monaco-workbench .panel.integrated-terminal .xterm.focus::before, +.hc-black .monaco-workbench .panel.integrated-terminal .xterm:focus::before { + display: block; + content: ""; + border: 2px solid #f38518; + position: absolute; + left: -5px; + top: 0; + right: -5px; + bottom: 0; +} + +.monaco-workbench .panel.integrated-terminal .xterm .xterm-helpers { + position: absolute; + top: 0; +} + +.monaco-workbench .panel.integrated-terminal .xterm .xterm-helper-textarea:focus { + /* Override the general vscode style applies `opacity:1!important` to textareas */ + opacity: 0 !important; +} + /* Terminal actions */ /* Light theme */ @@ -76,8 +115,8 @@ .vs-dark .monaco-workbench .terminal-action.kill, .hc-black .monaco-workbench .terminal-action.kill { background: url('kill-inverse.svg') center center no-repeat; } .vs-dark .monaco-workbench .terminal-action.new, .hc-black .monaco-workbench .terminal-action.new { background: url('new-inverse.svg') center center no-repeat; } -.vs-dark .monaco-workbench.mac .panel.integrated-terminal .xterm-rows, -.hc-black .monaco-workbench.mac .panel.integrated-terminal .xterm-rows { +.vs-dark .monaco-workbench.mac .panel.integrated-terminal .terminal:not(.enable-mouse-events), +.hc-black .monaco-workbench.mac .panel.integrated-terminal .terminal:not(.enable-mouse-events) { cursor: -webkit-image-set(url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAL0lEQVQoz2NgCD3x//9/BhBYBWdhgFVAiVW4JBFKGIa4AqD0//9D3pt4I4tAdAMAHTQ/j5Zom30AAAAASUVORK5CYII=') 1x, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAz0lEQVRIx2NgYGBY/R8I/vx5eelX3n82IJ9FxGf6tksvf/8FiTMQAcAGQMDvSwu09abffY8QYSAScNk45G198eX//yev73/4///701eh//kZSARckrNBRvz//+8+6ZohwCzjGNjdgQxkAg7B9WADeBjIBqtJCbhRA0YNoIkBSNmaPEMoNmA0FkYNoFKhapJ6FGyAH3nauaSmPfwI0v/3OukVi0CIZ+F25KrtYcx/CTIy0e+rC7R1Z4KMICVTQQ14feVXIbR695u14+Ir4gwAAD49E54wc1kWAAAAAElFTkSuQmCC') 2x) 5 8, text; } diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/widgets.css b/src/vs/workbench/parts/terminal/electron-browser/media/widgets.css index c804bbdf4a7..8461ec4f274 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/widgets.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/widgets.css @@ -17,4 +17,7 @@ line-height: 19px; padding: 4px 5px; animation: fadein 100ms linear; + white-space: nowrap; + /* Must be drawn on the top of the terminal's canvases */ + z-index: 20; } \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css index ad0175361b7..31206060c2b 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css @@ -2,172 +2,87 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +/** + * Copyright (c) 2014 The xterm.js authors. All rights reserved. + * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) + * https://github.com/chjj/term.js + * @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: + * + * 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. + * + * Originally forked from (with the author's permission): + * Fabrice Bellard's javascript vt100 for jslinux: + * http://bellard.org/jslinux/ + * Copyright (c) 2011 Fabrice Bellard + * The original design remains. The terminal itself + * has been extended to include xterm CSI codes, among + * other features. + */ -.monaco-workbench .panel.integrated-terminal .xterm { +/** + * Default styles for xterm.js + */ + +.xterm { + font-family: courier-new, courier, monospace; + font-feature-settings: "liga" 0; position: relative; - height: 100%; user-select: none; + -ms-user-select: none; + -webkit-user-select: none; } -.monaco-workbench .panel.integrated-terminal .xterm:focus { - /* Hide outline when focus jumps from xterm to the text area */ +.xterm.focus, +.xterm:focus { outline: none; } -.hc-black .monaco-workbench .panel.integrated-terminal .xterm.focus::before, -.hc-black .monaco-workbench .panel.integrated-terminal .xterm:focus::before { - display: block; - content: ""; - border: 2px solid #f38518; - position: absolute; - left: -5px; - top: 0; - right: -5px; - bottom: 0; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-helpers { +.xterm .xterm-helpers { position: absolute; top: 0; + /** + * The z-index of the helpers must be higher than the canvases in order for + * IMEs to appear on top. + */ + z-index: 10; } -.monaco-workbench .panel.integrated-terminal .xterm .xterm-helper-textarea { - position: absolute; +.xterm .xterm-helper-textarea { /* * HACK: to fix IE's blinking cursor * Move textarea out of the screen to the far left, so that the cursor is not visible. */ + position: absolute; + opacity: 0; left: -9999em; top: 0; - opacity: 0; width: 0; height: 0; z-index: -10; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-helper-textarea:focus { - /* Override the general vscode style applies `opacity:1!important` to textareas */ - opacity: 0 !important; -} - -.monaco-workbench .panel.integrated-terminal .xterm a { - color: inherit; - cursor: inherit; - text-decoration: none; -} - -.monaco-workbench .panel.integrated-terminal .xterm:not(.focus):not(:focus) .terminal-cursor { - background-color: transparent; - outline-width: 1px; - outline-style: solid; - outline-offset: -1px; -} - -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-blink-on:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus .terminal-cursor, -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-blink-on:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar):focus .terminal-cursor { - background-color: transparent; - color: inherit; -} - -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-bar .terminal-cursor, -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-underline .terminal-cursor { - position: relative; -} -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-bar .terminal-cursor::before, -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-underline .terminal-cursor::before { - content: ""; - display: block; - position: absolute; -} -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-bar .terminal-cursor::before { - top: 0; - bottom: 0; - left: 0; - width: 1px; -} -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-underline .terminal-cursor::before { - bottom: 0; - left: 0; - right: 0; - height: 1px; -} -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-bar.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before, -.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-underline.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before { - background-color: transparent !important; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-viewport { - overflow-y: scroll; -} - -.terminal .xterm-wide-char, -.terminal .xterm-normal-char { - display: inline-block; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-rows { - position: absolute; - left: 0; - bottom: 0; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-rows > div { - /* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */ + /** Prevent wrapping so the IME appears against the textarea at the correct position */ white-space: nowrap; + overflow: hidden; + resize: none; } -.monaco-workbench .panel.integrated-terminal .xterm .xterm-scroll-area { - visibility: hidden; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-char-measure-element { - display: inline-block; - visibility: hidden; - position: absolute; - left: -9999em; -} - -.monaco-workbench .panel.integrated-terminal .xterm.enable-mouse-events { - /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ - cursor: default; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-selection { - position: absolute; - left: 0; - bottom: 0; - z-index: 1; - opacity: 0.3; - pointer-events: none; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-selection div { - position: absolute; -} -/* TODO: Remove in favor of theme keys, see #28397*/ -.monaco-workbench .panel.integrated-terminal .xterm .xterm-selection div { background-color: #000; } -.vs-dark .monaco-workbench .panel.integrated-terminal .xterm .xterm-selection div { background-color: #FFF; } -.hc-black .monaco-workbench .panel.integrated-terminal .xterm .xterm-selection div { background-color: #FFF; } - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bold { - font-weight: bold; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-underline { - text-decoration: underline; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-blink { - text-decoration: blink; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-hidden { - visibility: hidden; -} - -/* Composition view */ - -.terminal .composition-view { +.xterm .composition-view { + /* TODO: Composition position got messed up somewhere */ background: #000; color: #FFF; display: none; @@ -176,1928 +91,38 @@ z-index: 1; } -.terminal .composition-view.active { +.xterm .composition-view.active { display: block; } -/* Terminal colors 16-255 */ - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-16 { - color: #000000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-16 { - background-color: #000000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-17 { - color: #00005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-17 { - background-color: #00005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-18 { - color: #000087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-18 { - background-color: #000087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-19 { - color: #0000af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-19 { - background-color: #0000af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-20 { - color: #0000d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-20 { - background-color: #0000d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-21 { - color: #0000ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-21 { - background-color: #0000ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-22 { - color: #005f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-22 { - background-color: #005f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-23 { - color: #005f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-23 { - background-color: #005f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-24 { - color: #005f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-24 { - background-color: #005f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-25 { - color: #005faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-25 { - background-color: #005faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-26 { - color: #005fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-26 { - background-color: #005fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-27 { - color: #005fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-27 { - background-color: #005fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-28 { - color: #008700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-28 { - background-color: #008700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-29 { - color: #00875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-29 { - background-color: #00875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-30 { - color: #008787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-30 { - background-color: #008787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-31 { - color: #0087af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-31 { - background-color: #0087af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-32 { - color: #0087d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-32 { - background-color: #0087d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-33 { - color: #0087ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-33 { - background-color: #0087ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-34 { - color: #00af00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-34 { - background-color: #00af00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-35 { - color: #00af5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-35 { - background-color: #00af5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-36 { - color: #00af87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-36 { - background-color: #00af87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-37 { - color: #00afaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-37 { - background-color: #00afaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-38 { - color: #00afd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-38 { - background-color: #00afd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-39 { - color: #00afff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-39 { - background-color: #00afff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-40 { - color: #00d700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-40 { - background-color: #00d700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-41 { - color: #00d75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-41 { - background-color: #00d75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-42 { - color: #00d787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-42 { - background-color: #00d787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-43 { - color: #00d7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-43 { - background-color: #00d7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-44 { - color: #00d7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-44 { - background-color: #00d7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-45 { - color: #00d7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-45 { - background-color: #00d7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-46 { - color: #00ff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-46 { - background-color: #00ff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-47 { - color: #00ff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-47 { - background-color: #00ff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-48 { - color: #00ff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-48 { - background-color: #00ff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-49 { - color: #00ffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-49 { - background-color: #00ffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-50 { - color: #00ffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-50 { - background-color: #00ffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-51 { - color: #00ffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-51 { - background-color: #00ffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-52 { - color: #5f0000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-52 { - background-color: #5f0000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-53 { - color: #5f005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-53 { - background-color: #5f005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-54 { - color: #5f0087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-54 { - background-color: #5f0087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-55 { - color: #5f00af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-55 { - background-color: #5f00af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-56 { - color: #5f00d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-56 { - background-color: #5f00d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-57 { - color: #5f00ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-57 { - background-color: #5f00ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-58 { - color: #5f5f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-58 { - background-color: #5f5f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-59 { - color: #5f5f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-59 { - background-color: #5f5f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-60 { - color: #5f5f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-60 { - background-color: #5f5f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-61 { - color: #5f5faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-61 { - background-color: #5f5faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-62 { - color: #5f5fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-62 { - background-color: #5f5fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-63 { - color: #5f5fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-63 { - background-color: #5f5fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-64 { - color: #5f8700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-64 { - background-color: #5f8700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-65 { - color: #5f875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-65 { - background-color: #5f875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-66 { - color: #5f8787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-66 { - background-color: #5f8787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-67 { - color: #5f87af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-67 { - background-color: #5f87af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-68 { - color: #5f87d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-68 { - background-color: #5f87d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-69 { - color: #5f87ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-69 { - background-color: #5f87ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-70 { - color: #5faf00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-70 { - background-color: #5faf00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-71 { - color: #5faf5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-71 { - background-color: #5faf5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-72 { - color: #5faf87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-72 { - background-color: #5faf87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-73 { - color: #5fafaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-73 { - background-color: #5fafaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-74 { - color: #5fafd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-74 { - background-color: #5fafd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-75 { - color: #5fafff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-75 { - background-color: #5fafff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-76 { - color: #5fd700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-76 { - background-color: #5fd700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-77 { - color: #5fd75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-77 { - background-color: #5fd75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-78 { - color: #5fd787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-78 { - background-color: #5fd787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-79 { - color: #5fd7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-79 { - background-color: #5fd7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-80 { - color: #5fd7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-80 { - background-color: #5fd7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-81 { - color: #5fd7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-81 { - background-color: #5fd7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-82 { - color: #5fff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-82 { - background-color: #5fff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-83 { - color: #5fff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-83 { - background-color: #5fff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-84 { - color: #5fff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-84 { - background-color: #5fff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-85 { - color: #5fffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-85 { - background-color: #5fffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-86 { - color: #5fffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-86 { - background-color: #5fffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-87 { - color: #5fffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-87 { - background-color: #5fffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-88 { - color: #870000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-88 { - background-color: #870000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-89 { - color: #87005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-89 { - background-color: #87005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-90 { - color: #870087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-90 { - background-color: #870087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-91 { - color: #8700af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-91 { - background-color: #8700af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-92 { - color: #8700d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-92 { - background-color: #8700d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-93 { - color: #8700ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-93 { - background-color: #8700ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-94 { - color: #875f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-94 { - background-color: #875f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-95 { - color: #875f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-95 { - background-color: #875f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-96 { - color: #875f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-96 { - background-color: #875f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-97 { - color: #875faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-97 { - background-color: #875faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-98 { - color: #875fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-98 { - background-color: #875fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-99 { - color: #875fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-99 { - background-color: #875fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-100 { - color: #878700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-100 { - background-color: #878700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-101 { - color: #87875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-101 { - background-color: #87875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-102 { - color: #878787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-102 { - background-color: #878787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-103 { - color: #8787af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-103 { - background-color: #8787af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-104 { - color: #8787d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-104 { - background-color: #8787d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-105 { - color: #8787ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-105 { - background-color: #8787ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-106 { - color: #87af00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-106 { - background-color: #87af00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-107 { - color: #87af5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-107 { - background-color: #87af5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-108 { - color: #87af87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-108 { - background-color: #87af87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-109 { - color: #87afaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-109 { - background-color: #87afaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-110 { - color: #87afd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-110 { - background-color: #87afd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-111 { - color: #87afff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-111 { - background-color: #87afff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-112 { - color: #87d700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-112 { - background-color: #87d700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-113 { - color: #87d75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-113 { - background-color: #87d75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-114 { - color: #87d787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-114 { - background-color: #87d787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-115 { - color: #87d7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-115 { - background-color: #87d7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-116 { - color: #87d7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-116 { - background-color: #87d7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-117 { - color: #87d7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-117 { - background-color: #87d7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-118 { - color: #87ff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-118 { - background-color: #87ff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-119 { - color: #87ff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-119 { - background-color: #87ff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-120 { - color: #87ff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-120 { - background-color: #87ff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-121 { - color: #87ffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-121 { - background-color: #87ffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-122 { - color: #87ffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-122 { - background-color: #87ffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-123 { - color: #87ffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-123 { - background-color: #87ffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-124 { - color: #af0000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-124 { - background-color: #af0000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-125 { - color: #af005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-125 { - background-color: #af005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-126 { - color: #af0087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-126 { - background-color: #af0087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-127 { - color: #af00af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-127 { - background-color: #af00af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-128 { - color: #af00d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-128 { - background-color: #af00d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-129 { - color: #af00ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-129 { - background-color: #af00ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-130 { - color: #af5f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-130 { - background-color: #af5f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-131 { - color: #af5f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-131 { - background-color: #af5f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-132 { - color: #af5f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-132 { - background-color: #af5f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-133 { - color: #af5faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-133 { - background-color: #af5faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-134 { - color: #af5fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-134 { - background-color: #af5fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-135 { - color: #af5fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-135 { - background-color: #af5fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-136 { - color: #af8700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-136 { - background-color: #af8700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-137 { - color: #af875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-137 { - background-color: #af875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-138 { - color: #af8787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-138 { - background-color: #af8787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-139 { - color: #af87af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-139 { - background-color: #af87af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-140 { - color: #af87d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-140 { - background-color: #af87d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-141 { - color: #af87ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-141 { - background-color: #af87ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-142 { - color: #afaf00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-142 { - background-color: #afaf00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-143 { - color: #afaf5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-143 { - background-color: #afaf5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-144 { - color: #afaf87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-144 { - background-color: #afaf87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-145 { - color: #afafaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-145 { - background-color: #afafaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-146 { - color: #afafd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-146 { - background-color: #afafd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-147 { - color: #afafff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-147 { - background-color: #afafff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-148 { - color: #afd700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-148 { - background-color: #afd700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-149 { - color: #afd75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-149 { - background-color: #afd75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-150 { - color: #afd787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-150 { - background-color: #afd787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-151 { - color: #afd7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-151 { - background-color: #afd7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-152 { - color: #afd7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-152 { - background-color: #afd7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-153 { - color: #afd7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-153 { - background-color: #afd7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-154 { - color: #afff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-154 { - background-color: #afff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-155 { - color: #afff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-155 { - background-color: #afff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-156 { - color: #afff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-156 { - background-color: #afff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-157 { - color: #afffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-157 { - background-color: #afffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-158 { - color: #afffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-158 { - background-color: #afffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-159 { - color: #afffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-159 { - background-color: #afffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-160 { - color: #d70000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-160 { - background-color: #d70000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-161 { - color: #d7005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-161 { - background-color: #d7005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-162 { - color: #d70087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-162 { - background-color: #d70087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-163 { - color: #d700af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-163 { - background-color: #d700af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-164 { - color: #d700d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-164 { - background-color: #d700d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-165 { - color: #d700ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-165 { - background-color: #d700ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-166 { - color: #d75f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-166 { - background-color: #d75f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-167 { - color: #d75f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-167 { - background-color: #d75f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-168 { - color: #d75f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-168 { - background-color: #d75f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-169 { - color: #d75faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-169 { - background-color: #d75faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-170 { - color: #d75fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-170 { - background-color: #d75fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-171 { - color: #d75fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-171 { - background-color: #d75fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-172 { - color: #d78700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-172 { - background-color: #d78700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-173 { - color: #d7875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-173 { - background-color: #d7875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-174 { - color: #d78787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-174 { - background-color: #d78787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-175 { - color: #d787af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-175 { - background-color: #d787af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-176 { - color: #d787d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-176 { - background-color: #d787d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-177 { - color: #d787ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-177 { - background-color: #d787ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-178 { - color: #d7af00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-178 { - background-color: #d7af00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-179 { - color: #d7af5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-179 { - background-color: #d7af5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-180 { - color: #d7af87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-180 { - background-color: #d7af87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-181 { - color: #d7afaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-181 { - background-color: #d7afaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-182 { - color: #d7afd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-182 { - background-color: #d7afd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-183 { - color: #d7afff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-183 { - background-color: #d7afff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-184 { - color: #d7d700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-184 { - background-color: #d7d700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-185 { - color: #d7d75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-185 { - background-color: #d7d75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-186 { - color: #d7d787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-186 { - background-color: #d7d787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-187 { - color: #d7d7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-187 { - background-color: #d7d7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-188 { - color: #d7d7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-188 { - background-color: #d7d7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-189 { - color: #d7d7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-189 { - background-color: #d7d7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-190 { - color: #d7ff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-190 { - background-color: #d7ff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-191 { - color: #d7ff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-191 { - background-color: #d7ff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-192 { - color: #d7ff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-192 { - background-color: #d7ff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-193 { - color: #d7ffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-193 { - background-color: #d7ffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-194 { - color: #d7ffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-194 { - background-color: #d7ffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-195 { - color: #d7ffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-195 { - background-color: #d7ffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-196 { - color: #ff0000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-196 { - background-color: #ff0000; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-197 { - color: #ff005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-197 { - background-color: #ff005f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-198 { - color: #ff0087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-198 { - background-color: #ff0087; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-199 { - color: #ff00af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-199 { - background-color: #ff00af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-200 { - color: #ff00d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-200 { - background-color: #ff00d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-201 { - color: #ff00ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-201 { - background-color: #ff00ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-202 { - color: #ff5f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-202 { - background-color: #ff5f00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-203 { - color: #ff5f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-203 { - background-color: #ff5f5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-204 { - color: #ff5f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-204 { - background-color: #ff5f87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-205 { - color: #ff5faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-205 { - background-color: #ff5faf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-206 { - color: #ff5fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-206 { - background-color: #ff5fd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-207 { - color: #ff5fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-207 { - background-color: #ff5fff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-208 { - color: #ff8700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-208 { - background-color: #ff8700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-209 { - color: #ff875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-209 { - background-color: #ff875f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-210 { - color: #ff8787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-210 { - background-color: #ff8787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-211 { - color: #ff87af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-211 { - background-color: #ff87af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-212 { - color: #ff87d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-212 { - background-color: #ff87d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-213 { - color: #ff87ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-213 { - background-color: #ff87ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-214 { - color: #ffaf00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-214 { - background-color: #ffaf00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-215 { - color: #ffaf5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-215 { - background-color: #ffaf5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-216 { - color: #ffaf87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-216 { - background-color: #ffaf87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-217 { - color: #ffafaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-217 { - background-color: #ffafaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-218 { - color: #ffafd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-218 { - background-color: #ffafd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-219 { - color: #ffafff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-219 { - background-color: #ffafff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-220 { - color: #ffd700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-220 { - background-color: #ffd700; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-221 { - color: #ffd75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-221 { - background-color: #ffd75f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-222 { - color: #ffd787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-222 { - background-color: #ffd787; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-223 { - color: #ffd7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-223 { - background-color: #ffd7af; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-224 { - color: #ffd7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-224 { - background-color: #ffd7d7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-225 { - color: #ffd7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-225 { - background-color: #ffd7ff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-226 { - color: #ffff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-226 { - background-color: #ffff00; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-227 { - color: #ffff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-227 { - background-color: #ffff5f; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-228 { - color: #ffff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-228 { - background-color: #ffff87; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-229 { - color: #ffffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-229 { - background-color: #ffffaf; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-230 { - color: #ffffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-230 { - background-color: #ffffd7; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-231 { - color: #ffffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-231 { - background-color: #ffffff; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-232 { - color: #080808; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-232 { - background-color: #080808; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-233 { - color: #121212; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-233 { - background-color: #121212; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-234 { - color: #1c1c1c; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-234 { - background-color: #1c1c1c; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-235 { - color: #262626; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-235 { - background-color: #262626; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-236 { - color: #303030; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-236 { - background-color: #303030; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-237 { - color: #3a3a3a; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-237 { - background-color: #3a3a3a; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-238 { - color: #444444; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-238 { - background-color: #444444; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-239 { - color: #4e4e4e; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-239 { - background-color: #4e4e4e; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-240 { - color: #585858; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-240 { - background-color: #585858; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-241 { - color: #626262; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-241 { - background-color: #626262; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-242 { - color: #6c6c6c; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-242 { - background-color: #6c6c6c; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-243 { - color: #767676; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-243 { - background-color: #767676; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-244 { - color: #808080; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-244 { - background-color: #808080; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-245 { - color: #8a8a8a; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-245 { - background-color: #8a8a8a; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-246 { - color: #949494; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-246 { - background-color: #949494; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-247 { - color: #9e9e9e; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-247 { - background-color: #9e9e9e; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-248 { - color: #a8a8a8; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-248 { - background-color: #a8a8a8; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-249 { - color: #b2b2b2; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-249 { - background-color: #b2b2b2; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-250 { - color: #bcbcbc; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-250 { - background-color: #bcbcbc; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-251 { - color: #c6c6c6; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-251 { - background-color: #c6c6c6; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-252 { - color: #d0d0d0; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-252 { - background-color: #d0d0d0; -} - -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-253 { - color: #dadada; +.xterm .xterm-viewport { + /* On OS X this is required in order for the scroll bar to appear fully opaque */ + background-color: #000; + overflow-y: scroll; } -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-253 { - background-color: #dadada; +.xterm canvas { + position: absolute; + left: 0; + top: 0; } -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-254 { - color: #e4e4e4; +.xterm .xterm-scroll-area { + visibility: hidden; } -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-254 { - background-color: #e4e4e4; +.xterm .xterm-char-measure-element { + display: inline-block; + visibility: hidden; + position: absolute; + left: -9999em; } -.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-255 { - color: #eeeeee; +.xterm.enable-mouse-events { + /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ + cursor: default; } -.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-255 { - background-color: #eeeeee; +.xterm:not(.enable-mouse-events) { + cursor: text; } diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index 916ac9d275f..0d7bb112081 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -11,13 +11,14 @@ import * as debugActions from 'vs/workbench/parts/debug/browser/debugActions'; import * as nls from 'vs/nls'; import * as panel from 'vs/workbench/browser/panel'; import * as platform from 'vs/base/common/platform'; +import * as terminalCommands from 'vs/workbench/parts/terminal/electron-browser/terminalCommands'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, TERMINAL_DEFAULT_RIGHT_CLICK_COPY_PASTE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TerminalCursorStyle } from 'vs/workbench/parts/terminal/common/terminal'; -import { TERMINAL_DEFAULT_SHELL_LINUX, TERMINAL_DEFAULT_SHELL_OSX, TERMINAL_DEFAULT_SHELL_WINDOWS } from 'vs/workbench/parts/terminal/electron-browser/terminal'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { TERMINAL_DEFAULT_SHELL_UNIX_LIKE, TERMINAL_DEFAULT_SHELL_WINDOWS } from 'vs/workbench/parts/terminal/electron-browser/terminal'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, FocusTerminalAtIndexAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; +import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; @@ -29,10 +30,13 @@ import { OpenNextRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditor import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { registerColors } from './terminalColorRegistry'; import { NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction } from 'vs/workbench/electron-browser/actions'; -import { QUICKOPEN_ACTION_ID, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; +import { QUICKOPEN_ACTION_ID, getQuickNavigateHandler, QUICKOPEN_FOCUS_SECONDARY_ACTION_ID } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { TogglePanelAction } from 'vs/workbench/browser/parts/panel/panelActions'; +import { TerminalPanel } from 'vs/workbench/parts/terminal/electron-browser/terminalPanel'; +import { TerminalPickerHandler } from 'vs/workbench/parts/terminal/browser/terminalQuickOpen'; const quickOpenRegistry = (Registry.as(QuickOpenExtensions.Quickopen)); @@ -40,8 +44,8 @@ const inTerminalsPicker = 'inTerminalPicker'; quickOpenRegistry.registerQuickOpenHandler( new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/terminal/browser/terminalQuickOpen', - 'TerminalPickerHandler', + TerminalPickerHandler, + TerminalPickerHandler.ID, TERMINAL_PICKER_PREFIX, inTerminalsPicker, nls.localize('quickOpen.terminal', "Show All Opened Terminals") @@ -50,15 +54,15 @@ quickOpenRegistry.registerQuickOpenHandler( const quickOpenNavigateNextInTerminalPickerId = 'workbench.action.quickOpenNavigateNextInTerminalPicker'; CommandsRegistry.registerCommand( - quickOpenNavigateNextInTerminalPickerId, { handler: getQuickNavigateHandler(quickOpenNavigateNextInTerminalPickerId, true) }); + { id: quickOpenNavigateNextInTerminalPickerId, handler: getQuickNavigateHandler(quickOpenNavigateNextInTerminalPickerId, true) }); const quickOpenNavigatePreviousInTerminalPickerId = 'workbench.action.quickOpenNavigatePreviousInTerminalPicker'; CommandsRegistry.registerCommand( - quickOpenNavigatePreviousInTerminalPickerId, { handler: getQuickNavigateHandler(quickOpenNavigatePreviousInTerminalPickerId, false) }); + { id: quickOpenNavigatePreviousInTerminalPickerId, handler: getQuickNavigateHandler(quickOpenNavigatePreviousInTerminalPickerId, false) }); const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenTermAction, QuickOpenTermAction.ID, QuickOpenTermAction.LABEL), 'Quick Open Terminal'); +registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenTermAction, QuickOpenTermAction.ID, QuickOpenTermAction.LABEL), 'Terminal: Switch Active Terminal', nls.localize('terminal', "Terminal")); const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionTermContributor); @@ -72,7 +76,7 @@ configurationRegistry.registerConfiguration({ 'terminal.integrated.shell.linux': { 'description': nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux."), 'type': 'string', - 'default': TERMINAL_DEFAULT_SHELL_LINUX + 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE }, 'terminal.integrated.shellArgs.linux': { 'description': nls.localize('terminal.integrated.shellArgs.linux', "The command line arguments to use when on the Linux terminal."), @@ -85,7 +89,7 @@ configurationRegistry.registerConfiguration({ 'terminal.integrated.shell.osx': { 'description': nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on OS X."), 'type': 'string', - 'default': TERMINAL_DEFAULT_SHELL_OSX + 'default': TERMINAL_DEFAULT_SHELL_UNIX_LIKE }, 'terminal.integrated.shellArgs.osx': { 'description': nls.localize('terminal.integrated.shellArgs.osx', "The command line arguments to use when on the OS X terminal."), @@ -120,11 +124,12 @@ configurationRegistry.registerConfiguration({ 'description': nls.localize('terminal.integrated.fontFamily', "Controls the font family of the terminal, this defaults to editor.fontFamily's value."), 'type': 'string' }, - 'terminal.integrated.fontLigatures': { - 'description': nls.localize('terminal.integrated.fontLigatures', "Controls whether font ligatures are enabled in the terminal."), - 'type': 'boolean', - 'default': false - }, + // TODO: Support font ligatures + // 'terminal.integrated.fontLigatures': { + // 'description': nls.localize('terminal.integrated.fontLigatures', "Controls whether font ligatures are enabled in the terminal."), + // 'type': 'boolean', + // 'default': false + // }, 'terminal.integrated.fontSize': { 'description': nls.localize('terminal.integrated.fontSize', "Controls the font size in pixels of the terminal."), 'type': 'number', @@ -133,11 +138,11 @@ configurationRegistry.registerConfiguration({ 'terminal.integrated.lineHeight': { 'description': nls.localize('terminal.integrated.lineHeight', "Controls the line height of the terminal, this number is multipled by the terminal font size to get the actual line-height in pixels."), 'type': 'number', - 'default': 1.2 + 'default': 1 }, 'terminal.integrated.enableBold': { 'type': 'boolean', - 'description': nls.localize('terminal.integrated.enableBold', "Whether to enable bold text within the terminal, this requires support from the terminal shell."), + 'description': nls.localize('terminal.integrated.enableBold', "Whether to enable bold text within the terminal, note that this requires support from the terminal shell."), 'default': true }, 'terminal.integrated.cursorBlinking': { @@ -180,6 +185,7 @@ configurationRegistry.registerConfiguration({ ToggleTabFocusModeAction.ID, FocusActiveGroupAction.ID, QUICKOPEN_ACTION_ID, + QUICKOPEN_FOCUS_SECONDARY_ACTION_ID, ShowAllCommandsAction.ID, CreateNewTerminalAction.ID, CopyTerminalSelectionAction.ID, @@ -187,15 +193,22 @@ configurationRegistry.registerConfiguration({ FocusActiveTerminalAction.ID, FocusPreviousTerminalAction.ID, FocusNextTerminalAction.ID, - FocusTerminalAtIndexAction.getId(1), - FocusTerminalAtIndexAction.getId(2), - FocusTerminalAtIndexAction.getId(3), - FocusTerminalAtIndexAction.getId(4), - FocusTerminalAtIndexAction.getId(5), - FocusTerminalAtIndexAction.getId(6), - FocusTerminalAtIndexAction.getId(7), - FocusTerminalAtIndexAction.getId(8), - FocusTerminalAtIndexAction.getId(9), + 'workbench.action.tasks.build', + 'workbench.action.tasks.restartTask', + 'workbench.action.tasks.runTask', + 'workbench.action.tasks.showLog', + 'workbench.action.tasks.showTasks', + 'workbench.action.tasks.terminate', + 'workbench.action.tasks.test', + 'workbench.action.terminal.focusAtIndex1', + 'workbench.action.terminal.focusAtIndex2', + 'workbench.action.terminal.focusAtIndex3', + 'workbench.action.terminal.focusAtIndex4', + 'workbench.action.terminal.focusAtIndex5', + 'workbench.action.terminal.focusAtIndex6', + 'workbench.action.terminal.focusAtIndex7', + 'workbench.action.terminal.focusAtIndex8', + 'workbench.action.terminal.focusAtIndex9', TerminalPasteAction.ID, RunSelectedTextInTerminalAction.ID, RunActiveFileInTerminalAction.ID, @@ -229,6 +242,7 @@ configurationRegistry.registerConfiguration({ NavigateLeftAction.ID, DeleteWordLeftTerminalAction.ID, DeleteWordRightTerminalAction.ID, + TogglePanelAction.ID, 'workbench.action.quickOpenView' ].sort() }, @@ -253,8 +267,7 @@ configurationRegistry.registerConfiguration({ registerSingleton(ITerminalService, TerminalService); (Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( - 'vs/workbench/parts/terminal/electron-browser/terminalPanel', - 'TerminalPanel', + TerminalPanel, TERMINAL_PANEL_ID, nls.localize('terminal', "Terminal"), 'terminal', @@ -277,9 +290,6 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewTermina actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusActiveTerminalAction, FocusActiveTerminalAction.ID, FocusActiveTerminalAction.LABEL), 'Terminal: Focus Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTerminalAction, FocusNextTerminalAction.ID, FocusNextTerminalAction.LABEL), 'Terminal: Focus Next Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); -for (let i = 1; i < 10; i++) { - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalAtIndexAction, FocusTerminalAtIndexAction.getId(i), FocusTerminalAtIndexAction.getLabel(i)), 'Terminal: Focus Terminal ' + i, category); -} actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }, @@ -340,21 +350,24 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFin }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Find Widget', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(HideTerminalFindWidgetAction, HideTerminalFindWidgetAction.ID, HideTerminalFindWidgetAction.LABEL, { primary: KeyCode.Escape, - secondary: [KeyCode.Shift | KeyCode.Escape] + secondary: [KeyMod.Shift | KeyCode.Escape] }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Hide Find Widget', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextFindTermTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction.ID, ShowNextFindTermTerminalFindWidgetAction.LABEL, { primary: KeyMod.Alt | KeyCode.DownArrow -}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Find History Show Next', category); +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Show Next Find Term', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction.ID, ShowPreviousFindTermTerminalFindWidgetAction.LABEL, { primary: KeyMod.Alt | KeyCode.UpArrow -}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Find History Show Previous', category); +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Show Previous Find Term', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordLeftTerminalAction, DeleteWordLeftTerminalAction.ID, DeleteWordLeftTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Backspace, mac: { primary: KeyMod.Alt | KeyCode.Backspace } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Before Cursor', category); +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Left', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordRightTerminalAction, DeleteWordRightTerminalAction.ID, DeleteWordRightTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Delete, mac: { primary: KeyMod.Alt | KeyCode.Delete } -}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word After Cursor', category); +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Right', category); + +terminalCommands.setup(); + registerColors(); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.ts index 4601182e9a7..b73b020260e 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.ts @@ -4,13 +4,20 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as cp from 'child_process'; import * as os from 'os'; import * as platform from 'vs/base/common/platform'; import * as processes from 'vs/base/node/processes'; +import { readFile, fileExists } from 'vs/base/node/pfs'; -export const TERMINAL_DEFAULT_SHELL_LINUX = !platform.isWindows ? (process.env.SHELL || 'sh') : 'sh'; -export const TERMINAL_DEFAULT_SHELL_OSX = !platform.isWindows ? (process.env.SHELL || 'sh') : 'sh'; +let unixLikeTerminal = 'sh'; +if (!platform.isWindows && process.env.SHELL) { + unixLikeTerminal = process.env.SHELL; + // Some systems have $SHELL set to /bin/false which breaks the terminal + if (unixLikeTerminal === '/bin/false') { + unixLikeTerminal = '/bin/bash'; + } +} +export const TERMINAL_DEFAULT_SHELL_UNIX_LIKE = unixLikeTerminal; const isAtLeastWindows10 = platform.isWindows && parseFloat(os.release()) >= 10; const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); @@ -18,6 +25,19 @@ const powerShellPath = `${process.env.windir}\\${is32ProcessOn64Windows ? 'Sysna export const TERMINAL_DEFAULT_SHELL_WINDOWS = isAtLeastWindows10 ? powerShellPath : processes.getWindowsShell(); -export interface ITerminalProcessFactory { - create(env: { [key: string]: string }): cp.ChildProcess; +if (platform.isLinux) { + const file = '/etc/os-release'; + fileExists(file).then(exists => { + if (!exists) { + return; + } + readFile(file).then(b => { + const contents = b.toString(); + if (contents.indexOf('NAME=Fedora') >= 0) { + isFedora = true; + } + }); + }); } + +export let isFedora = false; \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index aa12f72876a..3db89bc5d53 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -8,7 +8,7 @@ import * as os from 'os'; import { Action, IAction } from 'vs/base/common/actions'; import { EndOfLinePreference } from 'vs/editor/common/editorCommon'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; -import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; +import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal'; import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { TPromise } from 'vs/base/common/winjs.base'; import { TogglePanelAction } from 'vs/workbench/browser/panel'; @@ -21,6 +21,9 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { ActionBarContributor } from 'vs/workbench/browser/actions'; import { TerminalEntry } from 'vs/workbench/parts/terminal/browser/terminalQuickOpen'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export const TERMINAL_PICKER_PREFIX = 'term '; @@ -200,19 +203,39 @@ export class CreateNewTerminalAction extends Action { constructor( id: string, label: string, - @ITerminalService private terminalService: ITerminalService + @ITerminalService private terminalService: ITerminalService, + @ICommandService private commandService: ICommandService, + @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService ) { super(id, label); this.class = 'terminal-action new'; } public run(event?: any): TPromise { - const instance = this.terminalService.createInstance(undefined, true); - if (!instance) { - return TPromise.as(void 0); + const folders = this.workspaceContextService.getWorkspace().folders; + + let instancePromise: TPromise; + if (folders.length <= 1) { + // Allow terminal service to handle the path when there is only a + // single root + instancePromise = TPromise.as(this.terminalService.createInstance(undefined, true)); + } else { + instancePromise = this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND).then(workspace => { + if (!workspace) { + // Don't create the instance if the workspace picker was canceled + return null; + } + return this.terminalService.createInstance({ cwd: workspace.uri.fsPath }, true); + }); } - this.terminalService.setActiveInstance(instance); - return this.terminalService.showPanel(true); + + return instancePromise.then(instance => { + if (!instance) { + return TPromise.as(void 0); + } + this.terminalService.setActiveInstance(instance); + return this.terminalService.showPanel(true); + }); } } @@ -256,34 +279,6 @@ export class FocusNextTerminalAction extends Action { } } -export class FocusTerminalAtIndexAction extends Action { - private static ID_PREFIX = 'workbench.action.terminal.focusAtIndex'; - - constructor( - id: string, label: string, - @ITerminalService private terminalService: ITerminalService - ) { - super(id, label); - } - - public run(event?: any): TPromise { - this.terminalService.setActiveInstanceByIndex(this.getTerminalNumber() - 1); - return this.terminalService.showPanel(true); - } - - public static getId(n: number): string { - return FocusTerminalAtIndexAction.ID_PREFIX + n; - } - - public static getLabel(n: number): string { - return nls.localize('workbench.action.terminal.focusAtIndex', 'Focus Terminal {0}', n); - } - - private getTerminalNumber(): number { - return parseInt(this.id.substr(FocusTerminalAtIndexAction.ID_PREFIX.length)); - } -} - export class FocusPreviousTerminalAction extends Action { public static ID = 'workbench.action.terminal.focusPrevious'; @@ -734,8 +729,6 @@ export class ShowPreviousFindTermTerminalFindWidgetAction extends Action { export class QuickOpenActionTermContributor extends ActionBarContributor { constructor( - @ITerminalService private terminalService: ITerminalService, - @IQuickOpenService private quickOpenService: IQuickOpenService, @IInstantiationService private instantiationService: IInstantiationService ) { super(); @@ -758,7 +751,7 @@ export class QuickOpenActionTermContributor extends ActionBarContributor { export class QuickOpenTermAction extends Action { public static ID = 'workbench.action.quickOpenTerm'; - public static LABEL = nls.localize('quickOpenTerm', "Terminal: Switch Active Terminal"); + public static LABEL = nls.localize('quickOpenTerm', "Switch Active Terminal"); constructor( id: string, @@ -779,8 +772,7 @@ export class RenameTerminalQuickOpenAction extends RenameTerminalAction { id: string, label: string, private terminal: TerminalEntry, @IQuickOpenService quickOpenService: IQuickOpenService, - @ITerminalService terminalService: ITerminalService, - @IInstantiationService private instantiationService: IInstantiationService + @ITerminalService terminalService: ITerminalService ) { super(id, label, quickOpenService, terminalService); this.class = 'quick-open-terminal-configure'; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.ts index a9b56906ec4..d80978e1489 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.ts @@ -21,13 +21,11 @@ export const TERMINAL_FOREGROUND_COLOR = registerColor('terminal.foreground', { }, nls.localize('terminal.foreground', 'The foreground color of the terminal.')); export const TERMINAL_CURSOR_FOREGROUND_COLOR = registerColor('terminalCursor.foreground', null, nls.localize('terminalCursor.foreground', 'The foreground color of the terminal cursor.')); export const TERMINAL_CURSOR_BACKGROUND_COLOR = registerColor('terminalCursor.background', null, nls.localize('terminalCursor.background', 'The background color of the terminal cursor. Allows customizing the color of a character overlapped by a block cursor.')); - -// TODO: Reinstate, see #28397 -// export const TERMINAL_SELECTION_BACKGROUND_COLOR = registerColor('terminal.selectionBackground', { -// light: '#000', -// dark: '#FFF', -// hc: '#FFF' -// }, nls.localize('terminal.selectionBackground', 'The selection background color of the terminal.')); +export const TERMINAL_SELECTION_BACKGROUND_COLOR = registerColor('terminal.selectionBackground', { + light: '#00000040', + dark: '#FFFFFF40', + hc: '#FFFFFF80' +}, nls.localize('terminal.selectionBackground', 'The selection background color of the terminal.')); const ansiColorMap = { 'terminal.ansiBlack': { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalCommands.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalCommands.ts new file mode 100644 index 00000000000..828588d03b1 --- /dev/null +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalCommands.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal'; + +export function setup(): void { + registerOpenTerminalAtIndexCommands(); +} + +function registerOpenTerminalAtIndexCommands(): void { + for (let i = 0; i < 9; i++) { + const terminalIndex = i; + const visibleIndex = i + 1; + + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: `workbench.action.terminal.focusAtIndex${visibleIndex}`, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: void 0, + primary: null, + handler: accessor => { + const terminalService = accessor.get(ITerminalService); + terminalService.setActiveInstanceByIndex(terminalIndex); + return terminalService.showPanel(true); + } + }); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts index 78c27b2f88e..3724726111a 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts @@ -14,6 +14,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ITerminalConfiguration, ITerminalConfigHelper, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY } from 'vs/workbench/parts/terminal/common/terminal'; import { TPromise } from 'vs/base/common/winjs.base'; import Severity from 'vs/base/common/severity'; +import { isFedora } from 'vs/workbench/parts/terminal/electron-browser/terminal'; interface IEditorConfiguration { editor: IEditorOptions; @@ -25,7 +26,10 @@ interface IFullTerminalConfiguration { }; } -const DEFAULT_LINE_HEIGHT = 1.2; +const DEFAULT_LINE_HEIGHT = 1.0; + +const MINIMUM_FONT_SIZE = 6; +const MAXIMUM_FONT_SIZE = 25; /** * Encapsulates terminal configuration logic, the primary purpose of this file is so that platform @@ -38,7 +42,6 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { private _lastFontMeasurement: ITerminalFont; public constructor( - private _platform: platform.Platform, @IConfigurationService private _configurationService: IConfigurationService, @IWorkspaceConfigurationService private _workspaceConfigurationService: IWorkspaceConfigurationService, @IChoiceService private _choiceService: IChoiceService, @@ -55,11 +58,12 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { this._charMeasureElement = document.createElement('div'); this.panelContainer.appendChild(this._charMeasureElement); } + // TODO: This should leverage CharMeasure const style = this._charMeasureElement.style; style.display = 'block'; style.fontFamily = fontFamily; style.fontSize = fontSize + 'px'; - style.lineHeight = lineHeight.toString(10); + style.lineHeight = 'normal'; this._charMeasureElement.innerText = 'X'; const rect = this._charMeasureElement.getBoundingClientRect(); style.display = 'none'; @@ -71,10 +75,10 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { this._lastFontMeasurement = { fontFamily, - fontSize: fontSize + 'px', + fontSize, lineHeight, charWidth: rect.width, - charHeight: rect.height + charHeight: Math.ceil(rect.height) }; return this._lastFontMeasurement; } @@ -83,19 +87,29 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { * Gets the font information based on the terminal.integrated.fontFamily * terminal.integrated.fontSize, terminal.integrated.lineHeight configuration properties */ - public getFont(): ITerminalFont { + public getFont(excludeDimensions?: boolean): ITerminalFont { const config = this._configurationService.getConfiguration(); const editorConfig = (config).editor; const terminalConfig = this.config; - const fontFamily = terminalConfig.fontFamily || editorConfig.fontFamily; - let fontSize = this._toInteger(terminalConfig.fontSize, 0); - if (fontSize <= 0) { - fontSize = EDITOR_FONT_DEFAULTS.fontSize; + let fontFamily = terminalConfig.fontFamily || editorConfig.fontFamily; + + // Work around bad font on Fedora + if (!terminalConfig.fontFamily) { + if (isFedora) { + fontFamily = '\'DejaVu Sans Mono\''; + } } - let lineHeight = terminalConfig.lineHeight <= 0 ? DEFAULT_LINE_HEIGHT : terminalConfig.lineHeight; - if (!lineHeight) { - lineHeight = DEFAULT_LINE_HEIGHT; + + let fontSize = this._toInteger(terminalConfig.fontSize, MINIMUM_FONT_SIZE, MAXIMUM_FONT_SIZE, EDITOR_FONT_DEFAULTS.fontSize); + const lineHeight = terminalConfig.lineHeight ? Math.max(terminalConfig.lineHeight, 1) : DEFAULT_LINE_HEIGHT; + + if (excludeDimensions) { + return { + fontFamily, + fontSize, + lineHeight + }; } return this._measureFont(fontFamily, fontSize, lineHeight); @@ -108,8 +122,8 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig): void { // Check whether there is a workspace setting const platformKey = platform.isWindows ? 'windows' : platform.isMacintosh ? 'osx' : 'linux'; - const shellConfigValue = this._workspaceConfigurationService.lookup(`terminal.integrated.shell.${platformKey}`); - const shellArgsConfigValue = this._workspaceConfigurationService.lookup(`terminal.integrated.shellArgs.${platformKey}`); + const shellConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shell.${platformKey}`); + const shellArgsConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shellArgs.${platformKey}`); // Check if workspace setting exists and whether it's whitelisted let isWorkspaceShellAllowed = false; @@ -165,14 +179,17 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { } } - private _toInteger(source: any, minimum?: number): number { + private _toInteger(source: any, minimum: number, maximum: number, fallback: number): number { let r = parseInt(source, 10); if (isNaN(r)) { - r = 0; + return fallback; } if (typeof minimum === 'number') { r = Math.max(minimum, r); } + if (typeof maximum === 'number') { + r = Math.min(maximum, r); + } return r; } } \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalFindWidget.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalFindWidget.ts index 7ffa860ab6a..43202651a4d 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalFindWidget.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalFindWidget.ts @@ -30,7 +30,7 @@ export class TerminalFindWidget extends SimpleFindWidget { instance.findNext(val); } } - }; + } public hide() { super.hide(); diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index eeef27cdff5..46cc64e1c2f 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -21,36 +21,28 @@ import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IStringDictionary } from 'vs/base/common/collections'; import { ITerminalInstance, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, IShellLaunchConfig } from 'vs/workbench/parts/terminal/common/terminal'; -import { ITerminalProcessFactory } from 'vs/workbench/parts/terminal/electron-browser/terminal'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { TabFocus } from 'vs/editor/common/config/commonEditorConfig'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browser/terminalLinkHandler'; import { TerminalWidgetManager } from 'vs/workbench/parts/terminal/browser/terminalWidgetManager'; -import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService'; import { scrollbarSliderBackground, scrollbarSliderHoverBackground, scrollbarSliderActiveBackground } from 'vs/platform/theme/common/colorRegistry'; import { TPromise } from 'vs/base/common/winjs.base'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import pkg from 'vs/platform/node/package'; +import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/parts/terminal/electron-browser/terminalColorRegistry'; +import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; // Enable search functionality in xterm.js instance XTermTerminal.loadAddon('search'); - -class StandardTerminalProcessFactory implements ITerminalProcessFactory { - public create(env: { [key: string]: string }): cp.ChildProcess { - return cp.fork('./terminalProcess', [], { - env, - cwd: Uri.parse(path.dirname(require.toUrl('./terminalProcess'))).fsPath - }); - } -} +// Enable the winpty compatibility addon which will simulate wraparound mode +XTermTerminal.loadAddon('winptyCompat'); enum ProcessState { // The process has not been initialized yet. @@ -74,7 +66,6 @@ enum ProcessState { export class TerminalInstance implements ITerminalInstance { private static readonly EOL_REGEX = /\r?\n/g; - private static _terminalProcessFactory: ITerminalProcessFactory = new StandardTerminalProcessFactory(); private static _lastKnownDimensions: Dimension = null; private static _idCounter = 1; @@ -105,6 +96,7 @@ export class TerminalInstance implements ITerminalInstance { private _preLaunchInputQueue: string; private _initialCwd: string; private _windowsShellHelper: WindowsShellHelper; + private _onLineDataListeners: ((lineData: string) => void)[]; private _widgetManager: TerminalWidgetManager; private _linkHandler: TerminalLinkHandler; @@ -128,15 +120,15 @@ export class TerminalInstance implements ITerminalInstance { @IKeybindingService private _keybindingService: IKeybindingService, @IMessageService private _messageService: IMessageService, @IPanelService private _panelService: IPanelService, - @IWorkspaceContextService private _contextService: IWorkspaceContextService, - @IWorkbenchEditorService private _editorService: IWorkbenchEditorService, @IInstantiationService private _instantiationService: IInstantiationService, @IClipboardService private _clipboardService: IClipboardService, - @IHistoryService private _historyService: IHistoryService + @IHistoryService private _historyService: IHistoryService, + @IThemeService private _themeService: IThemeService ) { this._instanceDisposables = []; this._processDisposables = []; this._skipTerminalCommands = []; + this._onLineDataListeners = []; this._isExiting = false; this._hadFocusOnExit = false; this._processState = ProcessState.UNINITIALIZED; @@ -163,7 +155,7 @@ export class TerminalInstance implements ITerminalInstance { if (platform.isWindows) { this._processReady.then(() => { if (!this._isDisposed) { - this._windowsShellHelper = new WindowsShellHelper(this._processId, this._shellLaunchConfig.executable, this, this._xterm); + this._windowsShellHelper = new WindowsShellHelper(this._processId, this, this._xterm); } }); } @@ -202,8 +194,20 @@ export class TerminalInstance implements ITerminalInstance { return null; } const font = this._configHelper.getFont(); - this._cols = Math.max(Math.floor(dimension.width / font.charWidth), 1); - this._rows = Math.max(Math.floor(dimension.height / font.charHeight), 1); + + // Because xterm.js converts from CSS pixels to actual pixels through + // the use of canvas, window.devicePixelRatio needs to be used here in + // order to be precise. font.charWidth/charHeight alone as insufficient + // when window.devicePixelRatio changes. + const scaledWidthAvailable = dimension.width * window.devicePixelRatio; + const scaledCharWidth = Math.floor(font.charWidth * window.devicePixelRatio); + this._cols = Math.max(Math.floor(scaledWidthAvailable / scaledCharWidth), 1); + + const scaledHeightAvailable = dimension.height * window.devicePixelRatio; + const scaledCharHeight = Math.ceil(font.charHeight * window.devicePixelRatio); + const scaledLineHeight = Math.floor(scaledCharHeight * font.lineHeight); + this._rows = Math.max(Math.floor(scaledHeightAvailable / scaledLineHeight), 1); + return dimension.width; } @@ -245,12 +249,20 @@ export class TerminalInstance implements ITerminalInstance { * Create xterm.js instance and attach data listeners. */ protected _createXterm(): void { + const font = this._configHelper.getFont(true); this._xterm = new XTermTerminal({ - scrollback: this._configHelper.config.scrollback + scrollback: this._configHelper.config.scrollback, + theme: this._getXtermTheme(), + fontFamily: font.fontFamily, + fontSize: font.fontSize, + lineHeight: font.lineHeight, + enableBold: this._configHelper.config.enableBold }); if (this._shellLaunchConfig.initialText) { this._xterm.writeln(this._shellLaunchConfig.initialText); } + this._xterm.winptyCompatInit(); + this._xterm.on('lineFeed', () => this._onLineFeed()); this._process.on('message', (message) => this._sendPtyDataToXterm(message)); this._xterm.on('data', (data) => { if (this._processId) { @@ -268,6 +280,7 @@ export class TerminalInstance implements ITerminalInstance { }); this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, platform.platform, this._initialCwd); this._linkHandler.registerLocalLinkHandler(); + this._instanceDisposables.push(this._themeService.onThemeChange(theme => this._updateTheme(theme))); } public attachToElement(container: HTMLElement): void { @@ -280,6 +293,9 @@ export class TerminalInstance implements ITerminalInstance { dom.addClass(this._wrapperElement, 'terminal-wrapper'); this._xtermElement = document.createElement('div'); + // Attach the xterm object to the DOM, exposing it to the smoke tests + (this._wrapperElement).xterm = this._xterm; + this._xterm.open(this._xtermElement); this._xterm.attachCustomKeyEventHandler((event: KeyboardEvent) => { // Disable all input if the terminal is exiting @@ -346,7 +362,7 @@ export class TerminalInstance implements ITerminalInstance { })); this._wrapperElement.appendChild(this._xtermElement); - this._widgetManager = new TerminalWidgetManager(this._configHelper, this._wrapperElement); + this._widgetManager = new TerminalWidgetManager(this._wrapperElement); this._linkHandler.setWidgetManager(this._widgetManager); this._container.appendChild(this._wrapperElement); @@ -364,7 +380,7 @@ export class TerminalInstance implements ITerminalInstance { } } - public registerLinkMatcher(regex: RegExp, handler: (url: string) => void, matchIndex?: number, validationCallback?: (uri: string, element: HTMLElement, callback: (isValid: boolean) => void) => void): number { + public registerLinkMatcher(regex: RegExp, handler: (url: string) => void, matchIndex?: number, validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void): number { return this._linkHandler.registerCustomLinkHandler(regex, handler, matchIndex, validationCallback); } @@ -373,7 +389,7 @@ export class TerminalInstance implements ITerminalInstance { } public hasSelection(): boolean { - return this._xterm.hasSelection(); + return this._xterm && this._xterm.hasSelection(); } public copySelection(): void { @@ -407,10 +423,8 @@ export class TerminalInstance implements ITerminalInstance { } public notifyFindWidgetFocusChanged(isFocused: boolean): void { - // In order to support escape to close the find widget when the terminal - // is focused terminalFocus needs to be true when either the terminal or - // the find widget are focused. - this._terminalFocusContextKey.set(isFocused || document.activeElement === this._xterm.textarea); + const terminalFocused = !isFocused && (document.activeElement === this._xterm.textarea || document.activeElement === this._xterm.element); + this._terminalFocusContextKey.set(terminalFocused); } public dispose(): void { @@ -428,6 +442,8 @@ export class TerminalInstance implements ITerminalInstance { this._wrapperElement = null; } if (this._xterm) { + const buffer = (this._xterm.buffer); + this._sendLineData(buffer, buffer.ybase + buffer.y); this._xterm.destroy(); this._xterm = null; } @@ -489,11 +505,21 @@ export class TerminalInstance implements ITerminalInstance { // background since scrollTop changes take no effect but the terminal's position does // change since the number of visible rows decreases. this._xterm.emit('scroll', this._xterm.buffer.ydisp); + if (this._container) { + // Force a layout when the instance becomes invisible. This is particularly important + // for ensuring that terminals that are created in the background by an extension will + // correctly get correct character measurements in order to render to the screen (see + // #34554). + const computedStyle = window.getComputedStyle(this._container); + const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10); + const height = parseInt(computedStyle.getPropertyValue('height').replace('px', ''), 10); + this.layout(new Dimension(width, height)); + } } } public scrollDownLine(): void { - this._xterm.scrollDisp(1); + this._xterm.scrollLines(1); } public scrollDownPage(): void { @@ -505,7 +531,7 @@ export class TerminalInstance implements ITerminalInstance { } public scrollUpLine(): void { - this._xterm.scrollDisp(-1); + this._xterm.scrollLines(-1); } public scrollUpPage(): void { @@ -559,24 +585,15 @@ export class TerminalInstance implements ITerminalInstance { if (!this._shellLaunchConfig.executable) { this._configHelper.mergeDefaultShellPathAndArgs(this._shellLaunchConfig); } - this._initialCwd = this._getCwd(this._shellLaunchConfig, this._historyService.getLastActiveWorkspaceRoot()); - let envFromConfig: IStringDictionary; - if (platform.isWindows) { - envFromConfig = { ...process.env }; - for (let configKey in this._configHelper.config.env['windows']) { - let actualKey = configKey; - for (let envKey in envFromConfig) { - if (configKey.toLowerCase() === envKey.toLowerCase()) { - actualKey = envKey; - break; - } - } - envFromConfig[actualKey] = this._configHelper.config.env['windows'][configKey]; - } - } else { - const platformKey = platform.isMacintosh ? 'osx' : 'linux'; - envFromConfig = { ...process.env, ...this._configHelper.config.env[platformKey] }; - } + this._initialCwd = this._getCwd(this._shellLaunchConfig, this._historyService.getLastActiveWorkspaceRoot('file')); + + // Merge process env with the env from config + const envFromConfig = { ...process.env }; + const envSettingKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux'); + TerminalInstance.mergeEnvironments(envFromConfig, this._configHelper.config.env[envSettingKey]); + + // Continue env initialization, merging in the env from the launch + // config and adding keys that are needed to create the process const env = TerminalInstance.createTerminalEnv(envFromConfig, this._shellLaunchConfig, this._initialCwd, locale, this._cols, this._rows); this._process = cp.fork(Uri.parse(require.toUrl('bootstrap')).fsPath, ['--type=terminal'], { env, @@ -742,10 +759,49 @@ export class TerminalInstance implements ITerminalInstance { this._shellLaunchConfig = shell; } + public static mergeEnvironments(parent: IStringDictionary, other: IStringDictionary) { + if (!other) { + return; + } + + // On Windows apply the new values ignoring case, while still retaining + // the case of the original key. + if (platform.isWindows) { + for (let configKey in other) { + let actualKey = configKey; + for (let envKey in parent) { + if (configKey.toLowerCase() === envKey.toLowerCase()) { + actualKey = envKey; + break; + } + } + const value = other[configKey]; + TerminalInstance._mergeEnvironmentValue(parent, actualKey, value); + } + } else { + Object.keys(other).forEach((key) => { + const value = other[key]; + TerminalInstance._mergeEnvironmentValue(parent, key, value); + }); + } + } + + private static _mergeEnvironmentValue(env: IStringDictionary, key: string, value: string | null) { + if (typeof value === 'string') { + env[key] = value; + } else { + delete env[key]; + } + } + // TODO: This should be private/protected // TODO: locale should not be optional public static createTerminalEnv(parentEnv: IStringDictionary, shell: IShellLaunchConfig, cwd: string, locale?: string, cols?: number, rows?: number): IStringDictionary { - const env = shell.env ? shell.env : TerminalInstance._cloneEnv(parentEnv); + const env = { ...parentEnv }; + if (shell.env) { + TerminalInstance.mergeEnvironments(env, shell.env); + } + env['PTYPID'] = process.pid.toString(); env['PTYSHELL'] = shell.executable; env['TERM_PROGRAM'] = 'vscode'; @@ -783,6 +839,37 @@ export class TerminalInstance implements ITerminalInstance { }; } + public onLineData(listener: (lineData: string) => void): lifecycle.IDisposable { + this._onLineDataListeners.push(listener); + return { + dispose: () => { + const i = this._onLineDataListeners.indexOf(listener); + if (i >= 0) { + this._onLineDataListeners.splice(i, 1); + } + } + }; + } + + private _onLineFeed(): void { + if (this._onLineDataListeners.length === 0) { + return; + } + const buffer = (this._xterm.buffer); + const newLine = buffer.lines.get(buffer.ybase + buffer.y); + if (!newLine.isWrapped) { + this._sendLineData(buffer, buffer.ybase + buffer.y - 1); + } + } + + private _sendLineData(buffer: any, lineIndex: number): void { + let lineData = buffer.translateBufferLineToString(lineIndex, true); + while (lineIndex >= 0 && buffer.lines.get(lineIndex--).isWrapped) { + lineData = buffer.translateBufferLineToString(lineIndex, true) + lineData; + } + this._onLineDataListeners.forEach(listener => listener(lineData)); + } + public onExit(listener: (exitCode: number) => void): lifecycle.IDisposable { if (this._process) { this._process.on('exit', listener); @@ -804,14 +891,6 @@ export class TerminalInstance implements ITerminalInstance { return cwd; } - private static _cloneEnv(env: IStringDictionary): IStringDictionary { - const newEnv: IStringDictionary = Object.create(null); - Object.keys(env).forEach((key) => { - newEnv[key] = env[key]; - }); - return newEnv; - } - private static _getLangEnvVariable(locale?: string) { const parts = locale ? locale.split('-') : []; const n = parts.length; @@ -826,6 +905,7 @@ export class TerminalInstance implements ITerminalInstance { de: 'DE', en: 'US', es: 'ES', + fi: 'FI', fr: 'FR', it: 'IT', ja: 'JP', @@ -880,10 +960,31 @@ export class TerminalInstance implements ITerminalInstance { if (!terminalWidth) { return; } + if (this._xterm) { + const font = this._configHelper.getFont(); + + // Only apply these settings when the terminal is visible so that + // the characters are measured correctly. + if (this._isVisible) { + if (this._xterm.getOption('lineHeight') !== font.lineHeight) { + this._xterm.setOption('lineHeight', font.lineHeight); + } + if (this._xterm.getOption('fontSize') !== font.fontSize) { + this._xterm.setOption('fontSize', font.fontSize); + } + if (this._xterm.getOption('fontFamily') !== font.fontFamily) { + this._xterm.setOption('fontFamily', font.fontFamily); + } + if (this._xterm.getOption('enableBold') !== this._configHelper.config.enableBold) { + this._xterm.setOption('enableBold', this._configHelper.config.enableBold); + } + } + this._xterm.resize(this._cols, this._rows); this._xterm.element.style.width = terminalWidth + 'px'; } + this._processReady.then(() => { if (this._process && this._process.connected) { // The child process could aready be terminated @@ -903,10 +1004,6 @@ export class TerminalInstance implements ITerminalInstance { }); } - public static setTerminalProcessFactory(factory: ITerminalProcessFactory): void { - this._terminalProcessFactory = factory; - } - public setTitle(title: string, eventFromProcess: boolean): void { if (!title) { return; @@ -931,6 +1028,46 @@ export class TerminalInstance implements ITerminalInstance { this._onTitleChanged.fire(title); } } + + private _getXtermTheme(theme?: ITheme): any { + if (!theme) { + theme = this._themeService.getTheme(); + } + + const foregroundColor = theme.getColor(TERMINAL_FOREGROUND_COLOR); + const backgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || theme.getColor(PANEL_BACKGROUND); + const cursorColor = theme.getColor(TERMINAL_CURSOR_FOREGROUND_COLOR) || foregroundColor; + const cursorAccentColor = theme.getColor(TERMINAL_CURSOR_BACKGROUND_COLOR) || backgroundColor; + const selectionColor = theme.getColor(TERMINAL_SELECTION_BACKGROUND_COLOR); + + return { + background: backgroundColor ? backgroundColor.toString() : null, + foreground: foregroundColor ? foregroundColor.toString() : null, + cursor: cursorColor ? cursorColor.toString() : null, + cursorAccent: cursorAccentColor ? cursorAccentColor.toString() : null, + selection: selectionColor ? selectionColor.toString() : null, + black: theme.getColor(ansiColorIdentifiers[0]).toString(), + red: theme.getColor(ansiColorIdentifiers[1]).toString(), + green: theme.getColor(ansiColorIdentifiers[2]).toString(), + yellow: theme.getColor(ansiColorIdentifiers[3]).toString(), + blue: theme.getColor(ansiColorIdentifiers[4]).toString(), + magenta: theme.getColor(ansiColorIdentifiers[5]).toString(), + cyan: theme.getColor(ansiColorIdentifiers[6]).toString(), + white: theme.getColor(ansiColorIdentifiers[7]).toString(), + brightBlack: theme.getColor(ansiColorIdentifiers[8]).toString(), + brightRed: theme.getColor(ansiColorIdentifiers[9]).toString(), + brightGreen: theme.getColor(ansiColorIdentifiers[10]).toString(), + brightYellow: theme.getColor(ansiColorIdentifiers[11]).toString(), + brightBlue: theme.getColor(ansiColorIdentifiers[12]).toString(), + brightMagenta: theme.getColor(ansiColorIdentifiers[13]).toString(), + brightCyan: theme.getColor(ansiColorIdentifiers[14]).toString(), + brightWhite: theme.getColor(ansiColorIdentifiers[15]).toString() + }; + } + + private _updateTheme(theme?: ITheme): void { + this._xterm.setOption('theme', this._getXtermTheme(theme)); + } } registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { @@ -941,7 +1078,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { collector.addRule(` .monaco-workbench .panel.integrated-terminal .xterm.focus .xterm-viewport, .monaco-workbench .panel.integrated-terminal .xterm:focus .xterm-viewport, - .monaco-workbench .panel.integrated-terminal .xterm:hover .xterm-viewport { background-color: ${scrollbarSliderBackgroundColor}; }` + .monaco-workbench .panel.integrated-terminal .xterm:hover .xterm-viewport { background-color: ${scrollbarSliderBackgroundColor} !important; }` ); } diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts index 071f434f0fa..22634f79026 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts @@ -3,27 +3,25 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import * as path from 'path'; import * as platform from 'vs/base/common/platform'; import * as pfs from 'vs/base/node/pfs'; import Uri from 'vs/base/common/uri'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { TerminalWidgetManager } from 'vs/workbench/parts/terminal/browser/terminalWidgetManager'; import { TPromise } from 'vs/base/common/winjs.base'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal'; const pathPrefix = '(\\.\\.?|\\~)'; const pathSeparatorClause = '\\/'; // '":; are allowed in paths but they are often separators so ignore them // Also disallow \\ to prevent a catastropic backtracking case #24798 const excludedPathCharactersClause = '[^\\0\\s!$`&*()\\[\\]+\'":;\\\\]'; -const escapedExcludedPathCharactersClause = '(\\\\s|\\\\!|\\\\$|\\\\`|\\\\&|\\\\*|(|)|\\+)'; /** A regex that matches paths in the form /foo, ~/foo, ./foo, ../foo, foo/bar */ -const unixLocalLinkClause = '((' + pathPrefix + '|(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'; +const unixLocalLinkClause = '((' + pathPrefix + '|(' + excludedPathCharactersClause + ')+)?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + ')+)+)'; const winDrivePrefix = '[a-zA-Z]:'; const winPathPrefix = '(' + winDrivePrefix + '|\\.\\.?|\\~)'; @@ -43,7 +41,7 @@ const lineAndColumnClause = [ // Changing any regex may effect this value, hence changes this as well if required. const winLineAndColumnMatchIndex = 12; -const unixLineAndColumnMatchIndex = 15; +const unixLineAndColumnMatchIndex = 23; // Each line and column clause have 6 groups (ie no. of expressions in round brackets) const lineAndColumnClauseGroupCount = 6; @@ -54,7 +52,7 @@ const CUSTOM_LINK_PRIORITY = -1; const LOCAL_LINK_PRIORITY = -2; export type XtermLinkMatcherHandler = (event: MouseEvent, uri: string) => boolean | void; -export type XtermLinkMatcherValidationCallback = (uri: string, element: HTMLElement, callback: (isValid: boolean) => void) => void; +export type XtermLinkMatcherValidationCallback = (uri: string, callback: (isValid: boolean) => void) => void; export class TerminalLinkHandler { private _hoverDisposables: IDisposable[] = []; @@ -68,8 +66,8 @@ export class TerminalLinkHandler { private _platform: platform.Platform, private _initialCwd: string, @IOpenerService private _openerService: IOpenerService, - @IWorkbenchEditorService private _editorService: IWorkbenchEditorService, - @IConfigurationService private _configurationService: IConfigurationService + @IConfigurationService private _configurationService: IConfigurationService, + @ITerminalService private _terminalService: ITerminalService ) { const baseLocalLinkClause = _platform === platform.Platform.Windows ? winLocalLinkClause : unixLocalLinkClause; // Append line and column number regex @@ -79,8 +77,8 @@ export class TerminalLinkHandler { this._handleHypertextLink(uri); })); - this._xterm.setHypertextValidationCallback((uri: string, element: HTMLElement, callback: (isValid: boolean) => void) => { - this._validateWebLink(uri, element, callback); + this._xterm.setHypertextValidationCallback((uri: string, callback: (isValid: boolean) => void) => { + this._validateWebLink(uri, callback); }); } @@ -89,17 +87,11 @@ export class TerminalLinkHandler { } public registerCustomLinkHandler(regex: RegExp, handler: (uri: string) => void, matchIndex?: number, validationCallback?: XtermLinkMatcherValidationCallback): number { - const wrappedValidationCallback = (uri: string, element: HTMLElement, callback) => { - this._addTooltipEventListeners(element); - if (validationCallback) { - validationCallback(uri, element, callback); - } else { - callback(true); - } - }; return this._xterm.registerLinkMatcher(regex, this._wrapLinkHandler(handler), { matchIndex, - validationCallback: wrappedValidationCallback, + validationCallback: (uri: string, callback: (isValid: boolean) => void) => validationCallback(uri, callback), + tooltipCallback: (e: MouseEvent, u) => this._widgetManager.showMessage(e.offsetX, e.offsetY, this._getLinkHoverString()), + leaveCallback: () => this._widgetManager.closeMessage(), priority: CUSTOM_LINK_PRIORITY }); } @@ -110,7 +102,9 @@ export class TerminalLinkHandler { }); return this._xterm.registerLinkMatcher(this._localLinkRegex, wrappedHandler, { - validationCallback: (link: string, element: HTMLElement, callback: (isValid: boolean) => void) => this._validateLocalLink(link, element, callback), + validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateLocalLink(uri, callback), + tooltipCallback: (e: MouseEvent, u) => this._widgetManager.showMessage(e.offsetX, e.offsetY, this._getLinkHoverString()), + leaveCallback: () => this._widgetManager.closeMessage(), priority: LOCAL_LINK_PRIORITY }); } @@ -126,6 +120,9 @@ export class TerminalLinkHandler { event.preventDefault(); // Require correct modifier on click if (!this._isLinkActivationModifierDown(event)) { + // If the modifier is not pressed, the terminal should be + // focused if it's not already + this._terminalService.getActiveInstance().focus(true); return false; } return handler(uri); @@ -156,17 +153,11 @@ export class TerminalLinkHandler { }); } - private _validateLocalLink(link: string, element: HTMLElement, callback: (isValid: boolean) => void): void { - this._resolvePath(link).then(resolvedLink => { - if (resolvedLink) { - this._addTooltipEventListeners(element); - } - callback(!!resolvedLink); - }); + private _validateLocalLink(link: string, callback: (isValid: boolean) => void): void { + this._resolvePath(link).then(resolvedLink => callback(!!resolvedLink)); } - private _validateWebLink(link: string, element: HTMLElement, callback: (isValid: boolean) => void): void { - this._addTooltipEventListeners(element); + private _validateWebLink(link: string, callback: (isValid: boolean) => void): void { callback(true); } @@ -194,30 +185,6 @@ export class TerminalLinkHandler { return nls.localize('terminalLinkHandler.followLinkCtrl', 'Ctrl + click to follow link'); } - private _addTooltipEventListeners(element: HTMLElement): void { - let timeout: number = null; - let isMessageShowing = false; - this._hoverDisposables.push(dom.addDisposableListener(element, dom.EventType.MOUSE_OVER, e => { - element.classList.toggle('active', this._isLinkActivationModifierDown(e)); - this._mouseMoveDisposable = dom.addDisposableListener(element, dom.EventType.MOUSE_MOVE, e => { - element.classList.toggle('active', this._isLinkActivationModifierDown(e)); - }); - timeout = setTimeout(() => { - this._widgetManager.showMessage(element.offsetLeft, element.offsetTop, this._getLinkHoverString()); - isMessageShowing = true; - }, 500); - })); - this._hoverDisposables.push(dom.addDisposableListener(element, dom.EventType.MOUSE_OUT, () => { - element.classList.remove('active'); - if (this._mouseMoveDisposable) { - this._mouseMoveDisposable.dispose(); - } - clearTimeout(timeout); - this._widgetManager.closeMessage(); - isMessageShowing = false; - })); - } - protected _preprocessPath(link: string): string { if (this._platform === platform.Platform.Windows) { // Resolve ~ -> %HOMEDRIVE%\%HOMEPATH% @@ -329,4 +296,4 @@ export class TerminalLinkHandler { export interface LineColumnInfo { lineNumber?: string; columnNumber?: string; -}; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index c7a9ef3805a..2dd16ba5775 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -12,20 +12,20 @@ import { Action, IAction } from 'vs/base/common/actions'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ITerminalService, ITerminalFont, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; +import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { TerminalFindWidget } from './terminalFindWidget'; -import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR } from './terminalColorRegistry'; -import { ColorIdentifier, editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; -import { KillTerminalAction, CreateNewTerminalAction, SwitchTerminalInstanceAction, SwitchTerminalInstanceActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; +import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { KillTerminalAction, SwitchTerminalInstanceAction, SwitchTerminalInstanceActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Panel } from 'vs/workbench/browser/panel'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; +import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; +import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/parts/terminal/electron-browser/terminalColorRegistry'; export class TerminalPanel extends Panel { @@ -33,7 +33,6 @@ export class TerminalPanel extends Panel { private _copyContextMenuAction: IAction; private _contextMenuActions: IAction[]; private _cancelContextMenu: boolean = false; - private _font: ITerminalFont; private _fontStyleElement: HTMLElement; private _parentDomElement: HTMLElement; private _terminalContainer: HTMLElement; @@ -43,7 +42,6 @@ export class TerminalPanel extends Panel { constructor( @IConfigurationService private _configurationService: IConfigurationService, @IContextMenuService private _contextMenuService: IContextMenuService, - @IContextViewService private _contextViewService: IContextViewService, @IInstantiationService private _instantiationService: IInstantiationService, @ITerminalService private _terminalService: ITerminalService, @IThemeService protected themeService: IThemeService, @@ -74,7 +72,11 @@ export class TerminalPanel extends Panel { this._terminalService.setContainers(this.getContainer().getHTMLElement(), this._terminalContainer); this._register(this.themeService.onThemeChange(theme => this._updateTheme(theme))); - this._register(this._configurationService.onDidUpdateConfiguration(() => this._updateFont())); + this._register(this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('terminal.integrated') || e.affectsConfiguration('editor.fontFamily')) { + this._updateFont(); + } + })); this._updateFont(); this._updateTheme(); @@ -99,11 +101,16 @@ export class TerminalPanel extends Panel { this._updateTheme(); } else { return super.setVisible(visible).then(() => { - const instance = this._terminalService.createInstance(); - if (instance) { - this._updateFont(); - this._updateTheme(); - } + // Allow time for the panel to display if it is being shown + // for the first time. If there is not wait here the initial + // dimensions of the pty could be wrong. + setTimeout(() => { + const instance = this._terminalService.createInstance(); + if (instance) { + this._updateFont(); + this._updateTheme(); + } + }, 0); return TPromise.as(void 0); }); } @@ -129,7 +136,7 @@ export class TerminalPanel extends Panel { if (!this._contextMenuActions) { this._copyContextMenuAction = this._instantiationService.createInstance(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, nls.localize('copy', "Copy")); this._contextMenuActions = [ - this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, nls.localize('createNewTerminal', "New Terminal")), + this._instantiationService.createInstance(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.PANEL_LABEL), new Separator(), this._copyContextMenuAction, this._instantiationService.createInstance(TerminalPasteAction, TerminalPasteAction.ID, nls.localize('paste', "Paste")), @@ -273,44 +280,10 @@ export class TerminalPanel extends Panel { } let css = ''; - ansiColorIdentifiers.forEach((colorId: ColorIdentifier, index: number) => { - if (colorId) { // should not happen, all indices should have a color defined. - let color = theme.getColor(colorId); - css += `.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-${index} { color: ${color}; }` + - `.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-${index} { background-color: ${color}; }`; - } - }); - const bgColor = theme.getColor(TERMINAL_BACKGROUND_COLOR); - if (bgColor) { - css += `.monaco-workbench .panel.integrated-terminal .terminal-outer-container { background-color: ${bgColor}; }`; - } - const fgColor = theme.getColor(TERMINAL_FOREGROUND_COLOR); - if (fgColor) { - css += `.monaco-workbench .panel.integrated-terminal .xterm { color: ${fgColor}; }`; - } - const cursorFgColor = theme.getColor(TERMINAL_CURSOR_FOREGROUND_COLOR) || fgColor; - if (cursorFgColor) { - css += `.monaco-workbench .panel.integrated-terminal .xterm:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus .terminal-cursor,` + - `.monaco-workbench .panel.integrated-terminal .xterm:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar):focus .terminal-cursor { background-color: ${cursorFgColor} }` + - `.monaco-workbench .panel.integrated-terminal .xterm:not(.focus):not(:focus) .terminal-cursor { outline-color: ${cursorFgColor}; }` + - `.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-bar .terminal-cursor::before,` + - `.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-underline .terminal-cursor::before { background-color: ${cursorFgColor}; }` + - `.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-bar.focus.xterm-cursor-blink .terminal-cursor::before,` + - `.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-underline.focus.xterm-cursor-blink .terminal-cursor::before { background-color: ${cursorFgColor}; }`; - } + const backgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || theme.getColor(PANEL_BACKGROUND); + this._terminalContainer.style.backgroundColor = backgroundColor ? backgroundColor.toString() : ''; - const cursorBgColor = theme.getColor(TERMINAL_CURSOR_BACKGROUND_COLOR) || bgColor || theme.getColor(PANEL_BACKGROUND); - if (cursorBgColor) { - css += `.monaco-workbench .panel.integrated-terminal .xterm:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus .terminal-cursor,` + - `.monaco-workbench .panel.integrated-terminal .xterm:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar):focus .terminal-cursor { color: ${cursorBgColor} }`; - } - - // TODO: Reinstate, see #28397 - // const selectionColor = theme.getColor(TERMINAL_SELECTION_BACKGROUND_COLOR); - // if (selectionColor) { - // css += `.monaco-workbench .panel.integrated-terminal .xterm .xterm-selection div { background-color: ${selectionColor}; }`; - // } // Borrow the editor's hover background for now let hoverBackground = theme.getColor(editorHoverBackground); if (hoverBackground) { @@ -333,28 +306,11 @@ export class TerminalPanel extends Panel { if (this._terminalService.terminalInstances.length === 0) { return; } - let newFont = this._terminalService.configHelper.getFont(); - dom.toggleClass(this._parentDomElement, 'enable-ligatures', this._terminalService.configHelper.config.fontLigatures); - dom.toggleClass(this._parentDomElement, 'disable-bold', !this._terminalService.configHelper.config.enableBold); - if (!this._font || this._fontsDiffer(this._font, newFont)) { - this._fontStyleElement.innerHTML = '.monaco-workbench .panel.integrated-terminal .xterm {' + - `font-family: ${newFont.fontFamily};` + - `font-size: ${newFont.fontSize};` + - `line-height: ${newFont.lineHeight};` + - '}'; - this._font = newFont; - } + // TODO: Can we support ligatures? + // dom.toggleClass(this._parentDomElement, 'enable-ligatures', this._terminalService.configHelper.config.fontLigatures); this.layout(new Dimension(this._parentDomElement.offsetWidth, this._parentDomElement.offsetHeight)); } - private _fontsDiffer(a: ITerminalFont, b: ITerminalFont): boolean { - return a.charHeight !== b.charHeight || - a.charWidth !== b.charWidth || - a.fontFamily !== b.fontFamily || - a.fontSize !== b.fontSize || - a.lineHeight !== b.lineHeight; - } - /** * Adds quotes to a path if it contains whitespaces */ diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts index 3eed7c6397c..d498d16a71f 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts @@ -6,30 +6,27 @@ import * as nls from 'vs/nls'; import * as pfs from 'vs/base/node/pfs'; import * as platform from 'vs/base/common/platform'; -import product from 'vs/platform/node/product'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IQuickOpenService, IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen'; import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; import { TerminalService as AbstractTerminalService } from 'vs/workbench/parts/terminal/common/terminalService'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IChoiceService } from 'vs/platform/message/common/message'; +import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { TERMINAL_DEFAULT_SHELL_WINDOWS } from 'vs/workbench/parts/terminal/electron-browser/terminal'; import { TerminalPanel } from 'vs/workbench/parts/terminal/electron-browser/terminalPanel'; -import { IWindowService } from 'vs/platform/windows/common/windows'; export class TerminalService extends AbstractTerminalService implements ITerminalService { private _configHelper: TerminalConfigHelper; - public get configHelper(): ITerminalConfigHelper { return this._configHelper; }; + public get configHelper(): ITerminalConfigHelper { return this._configHelper; } constructor( @IContextKeyService _contextKeyService: IContextKeyService, @@ -38,15 +35,14 @@ export class TerminalService extends AbstractTerminalService implements ITermina @IPartService _partService: IPartService, @ILifecycleService _lifecycleService: ILifecycleService, @IInstantiationService private _instantiationService: IInstantiationService, - @IWindowService private _windowService: IWindowService, @IQuickOpenService private _quickOpenService: IQuickOpenService, - @IConfigurationEditingService private _configurationEditingService: IConfigurationEditingService, @IChoiceService private _choiceService: IChoiceService, - @IStorageService private _storageService: IStorageService + @IStorageService private _storageService: IStorageService, + @IMessageService private _messageService: IMessageService ) { super(_contextKeyService, _configurationService, _panelService, _partService, _lifecycleService); - this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, platform.platform); + this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper); } public createInstance(shell: IShellLaunchConfig = {}, wasNewTerminalAction?: boolean): ITerminalInstance { @@ -163,8 +159,7 @@ export class TerminalService extends AbstractTerminalService implements ITermina return null; } const shell = value.description; - const configChange = { key: 'terminal.integrated.shell.windows', value: shell }; - return this._configurationEditingService.writeConfiguration(ConfigurationTarget.USER, configChange).then(() => shell); + return this._configurationService.updateValue('terminal.integrated.shell.windows', shell, ConfigurationTarget.USER).then(() => shell); }); }); } @@ -218,22 +213,17 @@ export class TerminalService extends AbstractTerminalService implements ITermina } protected _showTerminalCloseConfirmation(): boolean { - const cancelId = 1; let message; if (this.terminalInstances.length === 1) { message = nls.localize('terminalService.terminalCloseConfirmationSingular', "There is an active terminal session, do you want to kill it?"); } else { message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.terminalInstances.length); } - const opts: Electron.ShowMessageBoxOptions = { - title: product.nameLong, + + return !this._messageService.confirmSync({ message, type: 'warning', - buttons: [nls.localize('yes', "Yes"), nls.localize('cancel', "Cancel")], - noLink: true, - cancelId - }; - return this._windowService.showMessageBox(opts) === cancelId; + }); } public setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void { diff --git a/src/vs/workbench/parts/terminal/electron-browser/windowsShellHelper.ts b/src/vs/workbench/parts/terminal/electron-browser/windowsShellHelper.ts index 1fbb6bb2cd8..da9a2b515ea 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/windowsShellHelper.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/windowsShellHelper.ts @@ -14,14 +14,13 @@ const SHELL_EXECUTABLES = ['cmd.exe', 'powershell.exe', 'bash.exe']; let windowsProcessTree; export class WindowsShellHelper { - private _childProcessIdStack: number[]; private _onCheckShell: Emitter>; private _isDisposed: boolean; private _currentRequest: TPromise; + private _newLineFeed: boolean; public constructor( private _rootProcessId: number, - private _rootShellExecutable: string, private _terminalInstance: ITerminalInstance, private _xterm: XTermTerminal ) { @@ -33,7 +32,6 @@ export class WindowsShellHelper { windowsProcessTree = require.__$__nodeRequire('windows-process-tree'); } - this._childProcessIdStack = [this._rootProcessId]; this._isDisposed = false; this._onCheckShell = new Emitter>(); // The debounce is necessary to prevent multiple processes from spawning when @@ -44,7 +42,19 @@ export class WindowsShellHelper { }, 50); }); - this._xterm.on('lineFeed', () => this._onCheckShell.fire()); + // We want to fire a new check for the shell on a lineFeed, but only + // when parsing has finished which is indicated by the cursormove event. + // If this is done on every lineFeed, parsing ends up taking + // significantly longer due to resetting timers. Note that this is + // private API. + this._xterm.on('lineFeed', () => this._newLineFeed = true); + this._xterm.on('cursormove', () => { + if (this._newLineFeed) { + this._onCheckShell.fire(); + } + }); + + // Fire a new check for the shell when any key is pressed. this._xterm.on('keypress', () => this._onCheckShell.fire()); } diff --git a/src/vs/workbench/parts/terminal/node/terminalProcess.ts b/src/vs/workbench/parts/terminal/node/terminalProcess.ts index 74fa1cad116..1f06c0d80e8 100644 --- a/src/vs/workbench/parts/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/parts/terminal/node/terminalProcess.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as cp from 'child_process'; import * as os from 'os'; import * as path from 'path'; import * as pty from 'node-pty'; @@ -56,17 +55,8 @@ function queueProcessExit() { clearTimeout(closeTimeout); } closeTimeout = setTimeout(function () { - if (process.platform === 'win32') { - // Forcefully kill the entire process tree under the shell process - // on Windows as ptyProcess.kill can leave some lingering processes. - // See https://github.com/Microsoft/vscode/issues/26807 - cp.execFile('taskkill.exe', ['/T', '/F', '/PID', ptyProcess.pid.toString()]).on('close', () => { - process.exit(exitCode); - }); - } else { - ptyProcess.kill(); - process.exit(exitCode); - } + ptyProcess.kill(); + process.exit(exitCode); }, 250); } @@ -90,7 +80,9 @@ process.on('message', function (message) { if (message.event === 'input') { ptyProcess.write(message.data); } else if (message.event === 'resize') { - ptyProcess.resize(message.cols, message.rows); + // Ensure that cols and rows are always >= 1, this prevents a native + // exception in winpty. + ptyProcess.resize(Math.max(message.cols, 1), Math.max(message.rows, 1)); } else if (message.event === 'shutdown') { queueProcessExit(); } diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalColorRegistry.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalColorRegistry.test.ts index 8a0820c4ac7..fa5448c879a 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalColorRegistry.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalColorRegistry.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import { Extensions as ThemeingExtensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry'; +import { Extensions as ThemeingExtensions, IColorRegistry, ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { ansiColorIdentifiers, registerColors } from 'vs/workbench/parts/terminal/electron-browser/terminalColorRegistry'; import { ITheme, ThemeType } from 'vs/platform/theme/common/themeService'; @@ -20,7 +20,7 @@ function getMockTheme(type: ThemeType): ITheme { selector: '', label: '', type: type, - getColor: (colorId) => themingRegistry.resolveDefaultColor(colorId, theme), + getColor: (colorId: ColorIdentifier): Color => themingRegistry.resolveDefaultColor(colorId, theme), defines: () => true }; return theme; diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts index b370e03061b..3dfbf80c376 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts @@ -6,24 +6,24 @@ 'use strict'; import * as assert from 'assert'; -import { IConfigurationService, getConfigurationValue, IConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; -import { Platform } from 'vs/base/common/platform'; +import { IConfigurationService, getConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { TPromise } from 'vs/base/common/winjs.base'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; - +import { isFedora } from 'vs/workbench/parts/terminal/electron-browser/terminal'; class MockConfigurationService implements IConfigurationService { public _serviceBrand: any; public serviceId = IConfigurationService; public constructor(private configuration: any = {}) { } - public reloadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: void 0, folder: void 0 }; } - public keys() { return { default: [], user: [], workspace: [], folder: [] }; } - public values() { return {}; } + public inspect(key: string, overrides?: IConfigurationOverrides): any { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: void 0, workspaceFolder: void 0 }; } + public keys() { return { default: [] as string[], user: [] as string[], workspace: [] as string[], workspaceFolder: [] as string[] }; } public getConfiguration(): any { return this.configuration; } + public getValue(key: string, overrides?: IConfigurationOverrides): T { return getConfigurationValue(this.getConfiguration(), key); } + public updateValue(): TPromise { return null; } public getConfigurationData(): any { return null; } - public onDidUpdateConfiguration() { return { dispose() { } }; } + public onDidChangeConfiguration() { return { dispose() { } }; } + public reloadConfiguration(): TPromise { return null; } } suite('Workbench - TerminalConfigHelper', () => { @@ -47,7 +47,7 @@ suite('Workbench - TerminalConfigHelper', () => { } } }); - configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); + configHelper = new TerminalConfigHelper(configurationService, null, null, null); configHelper.panelContainer = fixture; assert.equal(configHelper.getFont().fontFamily, 'bar', 'terminal.integrated.fontFamily should be selected over editor.fontFamily'); @@ -61,9 +61,13 @@ suite('Workbench - TerminalConfigHelper', () => { } } }); - configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); + configHelper = new TerminalConfigHelper(configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontFamily, 'foo', 'editor.fontFamily should be the fallback when terminal.integrated.fontFamily not set'); + if (isFedora) { + assert.equal(configHelper.getFont().fontFamily, '\'DejaVu Sans Mono\'', 'Fedora should have its font overridden when terminal.integrated.fontFamily not set'); + } else { + assert.equal(configHelper.getFont().fontFamily, 'foo', 'editor.fontFamily should be the fallback when terminal.integrated.fontFamily not set'); + } }); test('TerminalConfigHelper - getFont fontSize', function () { @@ -73,23 +77,22 @@ suite('Workbench - TerminalConfigHelper', () => { configurationService = new MockConfigurationService({ editor: { fontFamily: 'foo', - fontSize: 1 + fontSize: 9 }, terminal: { integrated: { fontFamily: 'bar', - fontSize: 2 + fontSize: 10 } } }); - configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); + configHelper = new TerminalConfigHelper(configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontSize, '2px', 'terminal.integrated.fontSize should be selected over editor.fontSize'); + assert.equal(configHelper.getFont().fontSize, 10, 'terminal.integrated.fontSize should be selected over editor.fontSize'); configurationService = new MockConfigurationService({ editor: { - fontFamily: 'foo', - fontSize: 0 + fontFamily: 'foo' }, terminal: { integrated: { @@ -98,25 +101,24 @@ suite('Workbench - TerminalConfigHelper', () => { } } }); - configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); + configHelper = new TerminalConfigHelper(configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontSize, `${EDITOR_FONT_DEFAULTS.fontSize}px`, 'The default editor font size should be used when editor.fontSize is 0 and terminal.integrated.fontSize not set'); + assert.equal(configHelper.getFont().fontSize, 6, 'The minimum terminal font size should be used when terminal.integrated.fontSize less than it'); configurationService = new MockConfigurationService({ editor: { fontFamily: 'foo', - fontSize: 0 }, terminal: { integrated: { fontFamily: 0, - fontSize: -10 + fontSize: null } } }); - configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); + configHelper = new TerminalConfigHelper(configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontSize, `${EDITOR_FONT_DEFAULTS.fontSize}px`, 'The default editor font size should be used when editor.fontSize is < 0 and terminal.integrated.fontSize not set'); + assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize, 'The default editor font size should be used when terminal.integrated.fontSize is not set'); }); test('TerminalConfigHelper - getFont lineHeight', function () { @@ -135,7 +137,7 @@ suite('Workbench - TerminalConfigHelper', () => { } } }); - configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); + configHelper = new TerminalConfigHelper(configurationService, null, null, null); configHelper.panelContainer = fixture; assert.equal(configHelper.getFont().lineHeight, 2, 'terminal.integrated.lineHeight should be selected over editor.lineHeight'); @@ -151,8 +153,8 @@ suite('Workbench - TerminalConfigHelper', () => { } } }); - configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); + configHelper = new TerminalConfigHelper(configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().lineHeight, 1.2, 'editor.lineHeight should be 1.2 when terminal.integrated.lineHeight not set'); + assert.equal(configHelper.getFont().lineHeight, 1, 'editor.lineHeight should be 1 when terminal.integrated.lineHeight not set'); }); }); \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalInstance.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalInstance.test.ts index d50abe08810..608a9e5f8bc 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalInstance.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalInstance.test.ts @@ -7,6 +7,7 @@ import * as assert from 'assert'; import * as os from 'os'; +import * as platform from 'vs/base/common/platform'; import Uri from 'vs/base/common/uri'; import { IMessageService } from 'vs/platform/message/common/message'; import { IStringDictionary } from 'vs/base/common/collections'; @@ -39,14 +40,14 @@ suite('Workbench - TerminalInstance', () => { instantiationService.stub(IHistoryService, new TestHistoryService()); }); - test('TerminalInstance - createTerminalEnv', function () { + test('createTerminalEnv', function () { const shell1 = { executable: '/bin/foosh', args: ['-bar', 'baz'] }; - const parentEnv1: IStringDictionary = { + const parentEnv1: IStringDictionary = { ok: true - }; + } as any; const env1 = TerminalInstance.createTerminalEnv(parentEnv1, shell1, '/foo', 'en-au'); assert.ok(env1['ok'], 'Parent environment is copied'); assert.deepStrictEqual(parentEnv1, { ok: true }, 'Parent environment is unchanged'); @@ -58,11 +59,11 @@ suite('Workbench - TerminalInstance', () => { assert.equal(env1['PTYCWD'], '/foo', 'PTYCWD is equal to requested cwd'); assert.equal(env1['LANG'], 'en_AU.UTF-8', 'LANG is equal to the requested locale with UTF-8'); - const shell2 = { + const shell2: IShellLaunchConfig = { executable: '/bin/foosh', args: [] }; - const parentEnv2: IStringDictionary = { + const parentEnv2: IStringDictionary = { LANG: 'en_US.UTF-8' }; const env2 = TerminalInstance.createTerminalEnv(parentEnv2, shell2, '/foo', 'en-au'); @@ -77,6 +78,69 @@ suite('Workbench - TerminalInstance', () => { assert.equal(env4['LANG'], 'en_US.UTF-8', 'LANG is equal to the parent environment\'s LANG'); }); + suite('mergeEnvironments', () => { + test('should add keys', () => { + const parent = { + a: 'b' + }; + const other = { + c: 'd' + }; + TerminalInstance.mergeEnvironments(parent, other); + assert.deepEqual(parent, { + a: 'b', + c: 'd' + }); + }); + + test('should add keys ignoring case on Windows', () => { + if (!platform.isWindows) { + return; + } + const parent = { + a: 'b' + }; + const other = { + A: 'c' + }; + TerminalInstance.mergeEnvironments(parent, other); + assert.deepEqual(parent, { + a: 'c' + }); + }); + + test('null values should delete keys from the parent env', () => { + const parent = { + a: 'b', + c: 'd' + }; + const other: IStringDictionary = { + a: null + }; + TerminalInstance.mergeEnvironments(parent, other); + assert.deepEqual(parent, { + c: 'd' + }); + }); + + test('null values should delete keys from the parent env ignoring case on Windows', () => { + if (!platform.isWindows) { + return; + } + const parent = { + a: 'b', + c: 'd' + }; + const other: IStringDictionary = { + A: null + }; + TerminalInstance.mergeEnvironments(parent, other); + assert.deepEqual(parent, { + c: 'd' + }); + }); + }); + suite('_getCwd', () => { let instance: TestTerminalInstance; let instantiationService: TestInstantiationService; diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts index c71031b2552..a16322808aa 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalLinkHandler.test.ts @@ -134,10 +134,10 @@ suite('Workbench - TerminalLinkHandler', () => { const supportedLinkFormats: LinkFormatInfo[] = [ { urlFormat: '{0}' }, - { urlFormat: '{0} on line {1}', line: '5' }, - { urlFormat: '{0} on line {1}, column {2}', line: '5', column: '3' }, - { urlFormat: '{0}:line {1}', line: '5' }, - { urlFormat: '{0}:line {1}, column {2}', line: '5', column: '3' }, + // { urlFormat: '{0} on line {1}', line: '5' }, + // { urlFormat: '{0} on line {1}, column {2}', line: '5', column: '3' }, + // { urlFormat: '{0}:line {1}', line: '5' }, + // { urlFormat: '{0}:line {1}, column {2}', line: '5', column: '3' }, { urlFormat: '{0}({1})', line: '5' }, { urlFormat: '{0} ({1})', line: '5' }, { urlFormat: '{0}({1},{2})', line: '5', column: '3' }, @@ -152,6 +152,7 @@ suite('Workbench - TerminalLinkHandler', () => { linkUrls.forEach(linkUrl => { supportedLinkFormats.forEach(linkFormatInfo => { + // console.log('linkFormatInfo: ', linkFormatInfo); testLink( strings.format(linkFormatInfo.urlFormat, linkUrl, linkFormatInfo.line, linkFormatInfo.column), linkUrl, @@ -170,7 +171,7 @@ suite('Workbench - TerminalLinkHandler', () => { test('Windows', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, 'C:\\base', null, null, null); - let stub = sinon.stub(path, 'join', function (arg1, arg2) { + let stub = sinon.stub(path, 'join', function (arg1: string, arg2: string) { return arg1 + '\\' + arg2; }); assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\./src/file1'); @@ -183,7 +184,7 @@ suite('Workbench - TerminalLinkHandler', () => { test('Linux', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, '/base', null, null, null); - let stub = sinon.stub(path, 'join', function (arg1, arg2) { + let stub = sinon.stub(path, 'join', function (arg1: string, arg2: string) { return arg1 + '/' + arg2; }); diff --git a/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts b/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts index 2b83cfd4c32..937068e685d 100644 --- a/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts +++ b/src/vs/workbench/parts/themes/electron-browser/themes.contribution.ts @@ -13,18 +13,18 @@ import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/parts/extensions/common/extensions'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { Delayer } from 'vs/base/common/async'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IColorRegistry, Extensions as ColorRegistryExtensions } from 'vs/platform/theme/common/colorRegistry'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Color } from 'vs/base/common/color'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export class SelectColorThemeAction extends Action { @@ -35,6 +35,7 @@ export class SelectColorThemeAction extends Action { id: string, label: string, @IQuickOpenService private quickOpenService: IQuickOpenService, + // @ts-ignore unused injected service @IMessageService private messageService: IMessageService, @IWorkbenchThemeService private themeService: IWorkbenchThemeService, @IExtensionGalleryService private extensionGalleryService: IExtensionGalleryService, @@ -60,7 +61,7 @@ export class SelectColorThemeAction extends Action { } let target = null; if (applyTheme) { - let confValue = this.configurationService.lookup(COLOR_THEME_SETTING); + let confValue = this.configurationService.inspect(COLOR_THEME_SETTING); target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; } @@ -126,7 +127,7 @@ class SelectIconThemeAction extends Action { } let target = null; if (applyTheme) { - let confValue = this.configurationService.lookup(ICON_THEME_SETTING); + let confValue = this.configurationService.inspect(ICON_THEME_SETTING); target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; } this.themeService.setFileIconTheme(theme && theme.id, target).done(null, diff --git a/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts b/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts index 8e68052288c..86ba85f8e0b 100644 --- a/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts +++ b/src/vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution.ts @@ -17,6 +17,7 @@ import { IPreferencesService } from 'vs/workbench/parts/preferences/common/prefe import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -28,6 +29,7 @@ class UnsupportedWorkspaceSettingsContribution implements IWorkbenchContribution constructor( @ILifecycleService lifecycleService: ILifecycleService, + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @IWorkspaceConfigurationService private workspaceConfigurationService: IWorkspaceConfigurationService, @IPreferencesService private preferencesService: IPreferencesService, @IMessageService private messageService: IMessageService, @@ -35,7 +37,8 @@ class UnsupportedWorkspaceSettingsContribution implements IWorkbenchContribution @IStorageService private storageService: IStorageService ) { lifecycleService.onShutdown(this.dispose, this); - this.toDispose.push(this.workspaceConfigurationService.onDidUpdateConfiguration(e => this.checkWorkspaceSettings())); + this.toDispose.push(this.workspaceConfigurationService.onDidChangeConfiguration(e => this.checkWorkspaceSettings())); + this.toDispose.push(workspaceContextService.onDidChangeWorkspaceFolders(e => this.checkWorkspaceSettings())); } getId(): string { @@ -70,12 +73,18 @@ class UnsupportedWorkspaceSettingsContribution implements IWorkbenchContribution const message = nls.localize('unsupportedWorkspaceSettings', 'This Workspace contains settings that can only be set in User Settings. ({0})', unsupportedKeys.join(', ')); const openWorkspaceSettings = new Action('unsupportedWorkspaceSettings.openWorkspaceSettings', nls.localize('openWorkspaceSettings', 'Open Workspace Settings'), '', true, () => { + /* __GDPR__ + "workspace.settings.unsupported.review" : {} + */ this.telemetryService.publicLog('workspace.settings.unsupported.review'); this.rememberWarningWasShown(); return this.preferencesService.openWorkspaceSettings(); }); const openDocumentation = new Action('unsupportedWorkspaceSettings.openDocumentation', nls.localize('openDocumentation', 'Learn More'), '', true, () => { + /* __GDPR__ + "workspace.settings.unsupported.documentation" : {} + */ this.telemetryService.publicLog('workspace.settings.unsupported.documentation'); this.rememberWarningWasShown(); window.open('https://go.microsoft.com/fwlink/?linkid=839878'); // Don't change link. @@ -83,6 +92,9 @@ class UnsupportedWorkspaceSettingsContribution implements IWorkbenchContribution }); const close = new Action('unsupportedWorkspaceSettings.Ignore', nls.localize('ignore', 'Ignore'), '', true, () => { + /* __GDPR__ + "workspace.settings.unsupported.ignore" : {} + */ this.telemetryService.publicLog('workspace.settings.unsupported.ignore'); this.rememberWarningWasShown(); return TPromise.as(true); @@ -90,6 +102,9 @@ class UnsupportedWorkspaceSettingsContribution implements IWorkbenchContribution const actions = [openWorkspaceSettings, openDocumentation, close]; this.messageService.show(Severity.Warning, { message, actions }); + /* __GDPR__ + "workspace.settings.unsupported.warning" : {} + */ this.telemetryService.publicLog('workspace.settings.unsupported.warning'); } } diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts index 80924f706cb..7138a6e6e92 100644 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts @@ -24,6 +24,9 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMode } from 'vs/editor/common/modes'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { addGAParameters } from 'vs/platform/telemetry/node/telemetryNodeUtils'; function renderBody(body: string): string { return ` @@ -47,6 +50,7 @@ export class ReleaseNotesEditor extends WebviewEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, + @IEnvironmentService private environmentService: IEnvironmentService, @IThemeService protected themeService: IThemeService, @IOpenerService private openerService: IOpenerService, @IModeService private modeService: IModeService, @@ -102,7 +106,11 @@ export class ReleaseNotesEditor extends WebviewEditor { this.onThemeChange(this.themeService.getTheme()); this._webview.contents = [body]; - this._webview.onDidClickLink(link => this.openerService.open(link), null, this.contentDisposables); + this._webview.onDidClickLink(link => { + addGAParameters(this.telemetryService, this.environmentService, link, 'ReleaseNotes') + .then(updated => this.openerService.open(updated)) + .then(null, onUnexpectedError); + }, null, this.contentDisposables); this._webview.onDidScroll(event => { this.scrollYPercentage = event.scrollYPercentage; }, null, this.contentDisposables); diff --git a/src/vs/workbench/parts/update/electron-browser/update.contribution.ts b/src/vs/workbench/parts/update/electron-browser/update.contribution.ts index 50a2dc0bc60..55cbb08c38f 100644 --- a/src/vs/workbench/parts/update/electron-browser/update.contribution.ts +++ b/src/vs/workbench/parts/update/electron-browser/update.contribution.ts @@ -11,14 +11,13 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { ReleaseNotesEditor } from 'vs/workbench/parts/update/electron-browser/releaseNotesEditor'; import { ReleaseNotesInput } from 'vs/workbench/parts/update/electron-browser/releaseNotesInput'; -import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IGlobalActivityRegistry, GlobalActivityExtensions } from 'vs/workbench/browser/activity'; -import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; +import { IGlobalActivityRegistry, GlobalActivityExtensions } from 'vs/workbench/common/activity'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution } from './update'; +import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(ProductContribution); @@ -33,10 +32,9 @@ Registry.as(GlobalActivityExtensions) // Editor const editorDescriptor = new EditorDescriptor( + ReleaseNotesEditor, ReleaseNotesEditor.ID, - nls.localize('release notes', "Release notes"), - 'vs/workbench/parts/update/electron-browser/releaseNotesEditor', - 'ReleaseNotesEditor' + nls.localize('release notes', "Release notes") ); Registry.as(EditorExtensions.Editors) diff --git a/src/vs/workbench/parts/update/electron-browser/update.ts b/src/vs/workbench/parts/update/electron-browser/update.ts index 0cef04feea5..6643e018c5c 100644 --- a/src/vs/workbench/parts/update/electron-browser/update.ts +++ b/src/vs/workbench/parts/update/electron-browser/update.ts @@ -17,10 +17,10 @@ import pkg from 'vs/platform/node/package'; import product from 'vs/platform/node/product'; import URI from 'vs/base/common/uri'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IActivityBarService, NumberBadge } from 'vs/workbench/services/activity/common/activityBarService'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ReleaseNotesInput } from 'vs/workbench/parts/update/electron-browser/releaseNotesInput'; -import { IGlobalActivity } from 'vs/workbench/browser/activity'; +import { IGlobalActivity } from 'vs/workbench/common/activity'; import { IRequestService } from 'vs/platform/request/node/request'; import { asText } from 'vs/base/node/request'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -32,6 +32,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { IUpdateService, State as UpdateState } from 'vs/platform/update/common/update'; import * as semver from 'semver'; import { OS, isLinux, isWindows } from 'vs/base/common/platform'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; class ApplyUpdateAction extends Action { constructor( @IUpdateService private updateService: IUpdateService) { @@ -127,7 +128,6 @@ export abstract class AbstractShowReleaseNotesAction extends Action { constructor( id: string, label: string, - private returnValue: boolean, private version: string, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IInstantiationService private instantiationService: IInstantiationService @@ -155,12 +155,11 @@ export abstract class AbstractShowReleaseNotesAction extends Action { export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { constructor( - returnValue: boolean, version: string, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IInstantiationService instantiationService: IInstantiationService ) { - super('update.showReleaseNotes', nls.localize('releaseNotes', "Release Notes"), returnValue, version, editorService, instantiationService); + super('update.showReleaseNotes', nls.localize('releaseNotes', "Release Notes"), version, editorService, instantiationService); } } @@ -175,13 +174,13 @@ export class ShowCurrentReleaseNotesAction extends AbstractShowReleaseNotesActio @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IInstantiationService instantiationService: IInstantiationService ) { - super(id, label, true, pkg.version, editorService, instantiationService); + super(id, label, pkg.version, editorService, instantiationService); } } export class DownloadAction extends Action { - constructor(private url: string, @IUpdateService private updateService: IUpdateService) { + constructor( @IUpdateService private updateService: IUpdateService) { super('update.download', nls.localize('downloadNow', "Download Now"), null, true); } @@ -267,8 +266,13 @@ export class Win3264BitContribution implements IWorkbenchContribution { @IStorageService storageService: IStorageService, @IInstantiationService instantiationService: IInstantiationService, @IMessageService messageService: IMessageService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IEnvironmentService environmentService: IEnvironmentService ) { + if (environmentService.disableUpdates) { + return; + } + const neverShowAgain = new NeverShowAgain(Win3264BitContribution.KEY, storageService); if (!neverShowAgain.shouldShow()) { @@ -295,7 +299,7 @@ class CommandAction extends Action { constructor( commandId: string, label: string, - @ICommandService private commandService: ICommandService + @ICommandService commandService: ICommandService ) { super(`command-action:${commandId}`, label, undefined, true, () => commandService.executeCommand(commandId)); } @@ -323,7 +327,7 @@ export class UpdateContribution implements IGlobalActivity { @IMessageService private messageService: IMessageService, @IUpdateService private updateService: IUpdateService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IActivityBarService private activityBarService: IActivityBarService + @IActivityService private activityService: IActivityService ) { const onUpdateAvailable = isLinux ? mapEvent(updateService.onUpdateAvailable, e => e.version) @@ -363,7 +367,7 @@ export class UpdateContribution implements IGlobalActivity { if (isUpdateAvailable) { const badge = new NumberBadge(1, () => nls.localize('updateIsReady', "New {0} update available.", product.nameShort)); - this.badgeDisposable = this.activityBarService.showGlobalActivity(this.id, badge); + this.badgeDisposable = this.activityService.showActivity(this.id, badge); } } @@ -388,10 +392,10 @@ export class UpdateContribution implements IGlobalActivity { } private showUpdateNotification(version: string): void { - const releaseNotesAction = this.instantiationService.createInstance(ShowReleaseNotesAction, false, version); + const releaseNotesAction = this.instantiationService.createInstance(ShowReleaseNotesAction, version); if (isLinux) { - const downloadAction = this.instantiationService.createInstance(DownloadAction, version); + const downloadAction = this.instantiationService.createInstance(DownloadAction); this.messageService.show(severity.Info, { message: nls.localize('thereIsUpdateAvailable', "There is an available update."), diff --git a/src/vs/workbench/parts/views/browser/views.ts b/src/vs/workbench/parts/views/browser/views.ts deleted file mode 100644 index 4d2505bfa90..00000000000 --- a/src/vs/workbench/parts/views/browser/views.ts +++ /dev/null @@ -1,786 +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 nls from 'vs/nls'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IThemable, attachStyler } from 'vs/platform/theme/common/styler'; -import * as errors from 'vs/base/common/errors'; -import * as DOM from 'vs/base/browser/dom'; -import { $, Dimension, Builder } from 'vs/base/browser/builder'; -import { Scope } from 'vs/workbench/common/memento'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IAction, IActionRunner } from 'vs/base/common/actions'; -import { IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { prepareActions } from 'vs/workbench/browser/actions'; -import { Viewlet, ViewletRegistry, Extensions } from 'vs/workbench/browser/viewlet'; -import { ITree } from 'vs/base/parts/tree/browser/tree'; -import { DelayedDragHandler } from 'vs/base/browser/dnd'; -import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { AbstractCollapsibleView, CollapsibleState, IView as IBaseView, SplitView, ViewSizing } from 'vs/base/browser/ui/splitview/splitview'; -import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/parts/views/browser/viewsRegistry'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND } from 'vs/workbench/common/theme'; -import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; - -export interface IViewOptions { - - id: string; - - name: string; - - actionRunner: IActionRunner; - - collapsed: boolean; - -} - -export interface IViewConstructorSignature { - - new(initialSize: number, options: IViewOptions, ...services: { _serviceBrand: any; }[]): IView; - -} - -export interface IView extends IBaseView, IThemable { - - id: string; - - name: string; - - getHeaderElement(): HTMLElement; - - create(): TPromise; - - setVisible(visible: boolean): TPromise; - - isVisible(): boolean; - - getActions(): IAction[]; - - getSecondaryActions(): IAction[]; - - getActionItem(action: IAction): IActionItem; - - getActionsContext(): any; - - showHeader(): boolean; - - hideHeader(): boolean; - - focusBody(): void; - - isExpanded(): boolean; - - expand(): void; - - collapse(): void; - - getOptimalWidth(): number; - - shutdown(): void; -} - -export interface ICollapsibleViewOptions extends IViewOptions { - - ariaHeaderLabel?: string; - - sizing: ViewSizing; - - initialBodySize?: number; - -} - -export abstract class CollapsibleView extends AbstractCollapsibleView implements IView { - - readonly id: string; - readonly name: string; - - protected treeContainer: HTMLElement; - protected tree: ITree; - protected toDispose: IDisposable[]; - protected toolBar: ToolBar; - protected actionRunner: IActionRunner; - protected isDisposed: boolean; - - private _isVisible: boolean; - - private dragHandler: DelayedDragHandler; - - constructor( - initialSize: number, - options: ICollapsibleViewOptions, - protected keybindingService: IKeybindingService, - protected contextMenuService: IContextMenuService - ) { - super(initialSize, { - ariaHeaderLabel: options.ariaHeaderLabel, - sizing: options.sizing, - bodySize: options.initialBodySize ? options.initialBodySize : 4 * 22, - initialState: options.collapsed ? CollapsibleState.COLLAPSED : CollapsibleState.EXPANDED, - }); - - this.id = options.id; - this.name = options.name; - this.actionRunner = options.actionRunner; - this.toDispose = []; - } - - protected changeState(state: CollapsibleState): void { - this.updateTreeVisibility(this.tree, state === CollapsibleState.EXPANDED); - - super.changeState(state); - } - - get draggableLabel(): string { return this.name; } - - public create(): TPromise { - return TPromise.as(null); - } - - getHeaderElement(): HTMLElement { - return this.header; - } - - public renderHeader(container: HTMLElement): void { - - // Tool bar - this.toolBar = new ToolBar($('div.actions').appendTo(container).getHTMLElement(), this.contextMenuService, { - orientation: ActionsOrientation.HORIZONTAL, - actionItemProvider: (action) => this.getActionItem(action), - ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.name), - getKeyBinding: (action) => this.keybindingService.lookupKeybinding(action.id) - }); - this.toolBar.actionRunner = this.actionRunner; - this.updateActions(); - - // Expand on drag over - this.dragHandler = new DelayedDragHandler(container, () => { - if (!this.isExpanded()) { - this.expand(); - } - }); - } - - protected updateActions(): void { - this.toolBar.setActions(prepareActions(this.getActions()), prepareActions(this.getSecondaryActions()))(); - this.toolBar.context = this.getActionsContext(); - } - - protected renderViewTree(container: HTMLElement): HTMLElement { - const treeContainer = document.createElement('div'); - container.appendChild(treeContainer); - - return treeContainer; - } - - public getViewer(): ITree { - return this.tree; - } - - public isVisible(): boolean { - return this._isVisible; - } - - public setVisible(visible: boolean): TPromise { - if (this._isVisible !== visible) { - this._isVisible = visible; - this.updateTreeVisibility(this.tree, visible && this.state === CollapsibleState.EXPANDED); - } - - return TPromise.as(null); - } - - public focusBody(): void { - this.focusTree(); - } - - protected reveal(element: any, relativeTop?: number): TPromise { - if (!this.tree) { - return TPromise.as(null); // return early if viewlet has not yet been created - } - - return this.tree.reveal(element, relativeTop); - } - - public layoutBody(size: number): void { - if (this.tree) { - this.treeContainer.style.height = size + 'px'; - this.tree.layout(size); - } - } - - public getActions(): IAction[] { - return []; - } - - public getSecondaryActions(): IAction[] { - return []; - } - - public getActionItem(action: IAction): IActionItem { - return null; - } - - public getActionsContext(): any { - return undefined; - } - - public shutdown(): void { - // Subclass to implement - } - - public getOptimalWidth(): number { - return 0; - } - - public dispose(): void { - this.isDisposed = true; - this.treeContainer = null; - - if (this.tree) { - this.tree.dispose(); - } - - if (this.dragHandler) { - this.dragHandler.dispose(); - } - - this.toDispose = dispose(this.toDispose); - - if (this.toolBar) { - this.toolBar.dispose(); - } - - super.dispose(); - } - - private updateTreeVisibility(tree: ITree, isVisible: boolean): void { - if (!tree) { - return; - } - - if (isVisible) { - $(tree.getHTMLElement()).show(); - } else { - $(tree.getHTMLElement()).hide(); // make sure the tree goes out of the tabindex world by hiding it - } - - if (isVisible) { - tree.onVisible(); - } else { - tree.onHidden(); - } - } - - private focusTree(): void { - if (!this.tree) { - return; // return early if viewlet has not yet been created - } - - // Make sure the current selected element is revealed - const selection = this.tree.getSelection(); - if (selection.length > 0) { - this.reveal(selection[0], 0.5).done(null, errors.onUnexpectedError); - } - - // Pass Focus to Viewer - this.tree.DOMFocus(); - } -} - -export interface IViewletViewOptions extends IViewOptions { - - viewletSettings: object; - -} - -export interface IViewState { - - collapsed: boolean; - - size: number | undefined; - - isHidden: boolean; - - order: number; - -} - -export class ViewsViewlet extends Viewlet { - - protected viewletContainer: HTMLElement; - protected lastFocusedView: IView; - - private splitView: SplitView; - private viewHeaderContextMenuListeners: IDisposable[] = []; - protected dimension: Dimension; - private viewletSettings: object; - - private readonly viewsContextKeys: Set = new Set(); - protected viewsStates: Map = new Map(); - private areExtensionsReady: boolean = false; - - constructor( - id: string, - private location: ViewLocation, - private showHeaderInTitleWhenSingleView: boolean, - @ITelemetryService telemetryService: ITelemetryService, - @IStorageService protected storageService: IStorageService, - @IInstantiationService protected instantiationService: IInstantiationService, - @IThemeService themeService: IThemeService, - @IWorkspaceContextService protected contextService: IWorkspaceContextService, - @IContextKeyService protected contextKeyService: IContextKeyService, - @IContextMenuService protected contextMenuService: IContextMenuService, - @IExtensionService extensionService: IExtensionService - ) { - super(id, telemetryService, themeService); - - this.viewletSettings = this.getMemento(storageService, Scope.WORKSPACE); - - this._register(ViewsRegistry.onViewsRegistered(this.onViewsRegistered, this)); - this._register(ViewsRegistry.onViewsDeregistered(this.onViewsDeregistered, this)); - this._register(contextKeyService.onDidChangeContext(keys => this.onContextChanged(keys))); - - extensionService.onReady().then(() => { - this.areExtensionsReady = true; - this.onViewsUpdated(); - }); - } - - public create(parent: Builder): TPromise { - super.create(parent); - - this.viewletContainer = DOM.append(parent.getHTMLElement(), DOM.$('')); - this.splitView = this._register(new SplitView(this.viewletContainer, { canChangeOrderByDragAndDrop: true })); - this.attachSplitViewStyler(this.splitView); - this._register(this.splitView.onFocus((view: IView) => this.lastFocusedView = view)); - this._register(this.splitView.onDidOrderChange(() => { - const views = this.splitView.getViews(); - for (let order = 0; order < views.length; order++) { - this.viewsStates.get(views[order].id).order = order; - } - })); - - return this.onViewsRegistered(ViewsRegistry.getViews(this.location)) - .then(() => { - this.lastFocusedView = this.splitView.getViews()[0]; - this.focus(); - }); - } - - public getTitle(): string { - let title = Registry.as(Extensions.Viewlets).getViewlet(this.getId()).name; - if (this.showHeaderInTitleArea() && this.splitView.getViews()[0]) { - title += ': ' + this.splitView.getViews()[0].name; - } - return title; - } - - public getActions(): IAction[] { - if (this.showHeaderInTitleArea() && this.splitView.getViews()[0]) { - return this.splitView.getViews()[0].getActions(); - } - return []; - } - - public getSecondaryActions(): IAction[] { - if (this.showHeaderInTitleArea() && this.splitView.getViews()[0]) { - return this.splitView.getViews()[0].getSecondaryActions(); - } - return []; - } - - public getContextMenuActions(): IAction[] { - return this.getViewDescriptorsFromRegistry(true) - .filter(viewDescriptor => viewDescriptor.canToggleVisibility && this.contextKeyService.contextMatchesRules(viewDescriptor.when)) - .map(viewDescriptor => ({ - id: `${viewDescriptor.id}.toggleVisibility`, - label: viewDescriptor.name, - checked: this.isCurrentlyVisible(viewDescriptor), - enabled: true, - run: () => this.toggleViewVisibility(viewDescriptor.id) - })); - } - - public setVisible(visible: boolean): TPromise { - return super.setVisible(visible) - .then(() => TPromise.join(this.splitView.getViews().filter(view => view.isVisible() !== visible) - .map((view) => view.setVisible(visible)))) - .then(() => void 0); - } - - public focus(): void { - super.focus(); - - if (this.lastFocusedView) { - this.lastFocusedView.focus(); - } else if (this.views.length > 0) { - this.views[0].focus(); - } - } - - public layout(dimension: Dimension): void { - this.dimension = dimension; - this.layoutViews(); - } - - public getOptimalWidth(): number { - const additionalMargin = 16; - const optimalWidth = Math.max(...this.splitView.getViews().map(view => view.getOptimalWidth() || 0)); - return optimalWidth + additionalMargin; - } - - public shutdown(): void { - this.splitView.getViews().forEach((view) => view.shutdown()); - super.shutdown(); - } - - private layoutViews(): void { - if (this.splitView) { - this.splitView.layout(this.dimension.height); - for (const view of this.splitView.getViews()) { - let viewState = this.updateViewStateSize(view); - this.viewsStates.set(view.id, viewState); - } - } - } - - private toggleViewVisibility(id: string): void { - const view = this.getView(id); - let viewState = this.viewsStates.get(id); - if (view) { - viewState = viewState || this.createViewState(view); - viewState.isHidden = true; - } else { - viewState = viewState || { collapsed: true, size: void 0, isHidden: false, order: void 0 }; - viewState.isHidden = false; - } - this.viewsStates.set(id, viewState); - this.updateViews(); - } - - private onViewsRegistered(views: IViewDescriptor[]): TPromise { - this.viewsContextKeys.clear(); - for (const viewDescriptor of this.getViewDescriptorsFromRegistry()) { - if (viewDescriptor.when) { - for (const key of viewDescriptor.when.keys()) { - this.viewsContextKeys.add(key); - } - } - } - - return this.updateViews(); - } - - private onViewsDeregistered(views: IViewDescriptor[]): TPromise { - return this.updateViews(views); - } - - private onContextChanged(keys: string[]): void { - if (!keys) { - return; - } - - let hasToUpdate: boolean = false; - for (const key of keys) { - if (this.viewsContextKeys.has(key)) { - hasToUpdate = true; - break; - } - } - - if (hasToUpdate) { - this.updateViews(); - } - } - - protected updateViews(unregisteredViews: IViewDescriptor[] = []): TPromise { - if (this.splitView) { - - const registeredViews = this.getViewDescriptorsFromRegistry(); - const [visible, toAdd, toRemove] = registeredViews.reduce<[IViewDescriptor[], IViewDescriptor[], IViewDescriptor[]]>((result, viewDescriptor) => { - const isCurrentlyVisible = this.isCurrentlyVisible(viewDescriptor); - const canBeVisible = this.canBeVisible(viewDescriptor); - - if (canBeVisible) { - result[0].push(viewDescriptor); - } - - if (!isCurrentlyVisible && canBeVisible) { - result[1].push(viewDescriptor); - } - - if (isCurrentlyVisible && !canBeVisible) { - result[2].push(viewDescriptor); - } - - return result; - - }, [[], [], unregisteredViews]); - - const toCreate: IView[] = []; - - if (toAdd.length || toRemove.length) { - for (const view of this.splitView.getViews()) { - let viewState = this.viewsStates.get(view.id); - if (!viewState || typeof viewState.size === 'undefined' || view.size !== viewState.size || !view.isExpanded() !== viewState.collapsed) { - viewState = this.updateViewStateSize(view); - this.viewsStates.set(view.id, viewState); - } - } - if (toRemove.length) { - for (const viewDescriptor of toRemove) { - let view = this.getView(viewDescriptor.id); - this.splitView.removeView(view); - if (this.lastFocusedView === view) { - this.lastFocusedView = null; - } - } - } - - for (const viewDescriptor of toAdd) { - let viewState = this.viewsStates.get(viewDescriptor.id); - let index = visible.indexOf(viewDescriptor); - const view = this.createView(viewDescriptor, - viewState ? viewState.size : this.getDefaultViewSize(), - { - id: viewDescriptor.id, - name: viewDescriptor.name, - actionRunner: this.getActionRunner(), - collapsed: viewState ? viewState.collapsed : void 0, - viewletSettings: this.viewletSettings - }); - toCreate.push(view); - - this.attachViewStyler(view); - this.splitView.addView(view, viewState && viewState.size ? Math.max(viewState.size, 1) : viewDescriptor.size, index); - } - - return TPromise.join(toCreate.map(view => view.create())) - .then(() => this.onViewsUpdated()) - .then(() => toCreate); - } - } - return TPromise.as([]); - } - - protected getDefaultViewSize(): number | undefined { - return undefined; - } - - private attachViewStyler(widget: IThemable, options?: { noContrastBorder?: boolean }): IDisposable { - return attachStyler(this.themeService, { - headerForeground: SIDE_BAR_SECTION_HEADER_FOREGROUND, - headerBackground: SIDE_BAR_SECTION_HEADER_BACKGROUND, - headerHighContrastBorder: (options && options.noContrastBorder) ? null : contrastBorder - }, widget); - } - - private attachSplitViewStyler(widget: IThemable): IDisposable { - return attachStyler(this.themeService, { - dropBackground: SIDE_BAR_DRAG_AND_DROP_BACKGROUND - }, widget); - } - - private isCurrentlyVisible(viewDescriptor: IViewDescriptor): boolean { - return !!this.getView(viewDescriptor.id); - } - - private canBeVisible(viewDescriptor: IViewDescriptor): boolean { - const viewstate = this.viewsStates.get(viewDescriptor.id); - if (viewDescriptor.canToggleVisibility && viewstate && viewstate.isHidden) { - return false; - } - return this.contextKeyService.contextMatchesRules(viewDescriptor.when); - } - - private onViewsUpdated(): TPromise { - if (!this.splitView) { - return TPromise.as(null); - } - - if (this.showHeaderInTitleArea()) { - if (this.splitView.getViews()[0]) { - this.splitView.getViews()[0].hideHeader(); - if (!this.splitView.getViews()[0].isExpanded()) { - this.splitView.getViews()[0].expand(); - } - } - } else { - for (const view of this.splitView.getViews()) { - view.showHeader(); - } - } - - // Update title area since the title actions have changed. - this.updateTitleArea(); - - this.viewHeaderContextMenuListeners = dispose(this.viewHeaderContextMenuListeners); - for (const viewDescriptor of this.getViewDescriptorsFromRegistry()) { - const view = this.getView(viewDescriptor.id); - if (view) { - this.viewHeaderContextMenuListeners.push(DOM.addDisposableListener(view.getHeaderElement(), DOM.EventType.CONTEXT_MENU, e => { - e.stopPropagation(); - e.preventDefault(); - if (viewDescriptor.canToggleVisibility) { - this.onContextMenu(new StandardMouseEvent(e), view); - } - })); - } - } - - if (this.dimension) { - this.layoutViews(); - } - - return this.setVisible(this.isVisible()); - } - - private onContextMenu(event: StandardMouseEvent, view: IView): void { - event.stopPropagation(); - event.preventDefault(); - - let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; - this.contextMenuService.showContextMenu({ - getAnchor: () => anchor, - getActions: () => TPromise.as([{ - id: `${view.id}.removeView`, - label: nls.localize('hideView', "Hide from Side Bar"), - enabled: true, - run: () => this.toggleViewVisibility(view.id) - }]), - }); - } - - protected showHeaderInTitleArea(): boolean { - if (!this.showHeaderInTitleWhenSingleView) { - return false; - } - if (this.splitView.getViews().length > 1) { - return false; - } - if (ViewLocation.getContributedViewLocation(this.location.id) && !this.areExtensionsReady) { - // Checks in cache so that view do not jump. See #29609 - let visibleViewsCount = 0; - const viewDecriptors = this.getViewDescriptorsFromRegistry(); - this.viewsStates.forEach((viewState, id) => { - const viewDescriptor = viewDecriptors.filter(viewDescriptor => viewDescriptor.id === id)[0]; - const isHidden = viewState.isHidden || (viewDescriptor && !this.contextKeyService.contextMatchesRules(viewDescriptor.when)); - if (!isHidden) { - visibleViewsCount++; - } - }); - return visibleViewsCount === 1; - } - return true; - } - - protected getViewDescriptorsFromRegistry(defaultOrder: boolean = false): IViewDescriptor[] { - return ViewsRegistry.getViews(this.location) - .sort((a, b) => { - const viewStateA = this.viewsStates.get(a.id); - const viewStateB = this.viewsStates.get(b.id); - const orderA = !defaultOrder && viewStateA ? viewStateA.order : a.order; - const orderB = !defaultOrder && viewStateB ? viewStateB.order : b.order; - - if (orderB === void 0 || orderB === null) { - return -1; - } - if (orderA === void 0 || orderA === null) { - return 1; - } - - return orderA - orderB; - }); - } - - protected createView(viewDescriptor: IViewDescriptor, initialSize: number, options: IViewletViewOptions): IView { - return this.instantiationService.createInstance(viewDescriptor.ctor, initialSize, options); - } - - protected get views(): IView[] { - return this.splitView ? this.splitView.getViews() : []; - } - - protected getView(id: string): IView { - return this.splitView.getViews().filter(view => view.id === id)[0]; - } - - private updateViewStateSize(view: IView): IViewState { - const currentState = this.viewsStates.get(view.id); - const newViewState = this.createViewState(view); - return currentState ? { ...currentState, collapsed: newViewState.collapsed, size: newViewState.size } : newViewState; - } - - protected createViewState(view: IView): IViewState { - const collapsed = !view.isExpanded(); - const size = collapsed && view instanceof CollapsibleView ? view.previousSize : view.size; - return { - collapsed, - size: size && size > 0 ? size : void 0, - isHidden: false, - order: this.splitView.getViews().indexOf(view) - }; - } -} - -export class PersistentViewsViewlet extends ViewsViewlet { - - constructor( - id: string, - location: ViewLocation, - private viewletStateStorageId: string, - showHeaderInTitleWhenSingleView: boolean, - @ITelemetryService telemetryService: ITelemetryService, - @IStorageService storageService: IStorageService, - @IInstantiationService instantiationService: IInstantiationService, - @IThemeService themeService: IThemeService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IContextKeyService contextKeyService: IContextKeyService, - @IContextMenuService contextMenuService: IContextMenuService, - @IExtensionService extensionService: IExtensionService - ) { - super(id, location, showHeaderInTitleWhenSingleView, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService); - this.loadViewsStates(); - } - - shutdown(): void { - this.saveViewsStates(); - super.shutdown(); - } - - private saveViewsStates(): void { - const viewsStates = {}; - const registeredViewDescriptors = this.getViewDescriptorsFromRegistry(); - this.viewsStates.forEach((viewState, id) => { - const view = this.getView(id); - if (view) { - viewState = this.createViewState(view); - viewsStates[id] = { size: viewState.size, collapsed: viewState.collapsed, isHidden: viewState.isHidden, order: viewState.order }; - } else { - const viewDescriptor = registeredViewDescriptors.filter(v => v.id === id)[0]; - if (viewDescriptor) { - viewsStates[id] = viewState; - } - } - }); - - this.storageService.store(this.viewletStateStorageId, JSON.stringify(viewsStates), this.contextService.hasWorkspace() ? StorageScope.WORKSPACE : StorageScope.GLOBAL); - } - - private loadViewsStates(): void { - const viewsStates = JSON.parse(this.storageService.get(this.viewletStateStorageId, this.contextService.hasWorkspace() ? StorageScope.WORKSPACE : StorageScope.GLOBAL, '{}')); - Object.keys(viewsStates).forEach(id => this.viewsStates.set(id, viewsStates[id])); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index 8d108a933d7..71c6932203c 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -12,15 +12,14 @@ import { isMacintosh } from 'vs/base/common/platform'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { OpenRecentAction } from 'vs/workbench/electron-browser/actions'; -import { GlobalNewUntitledFileAction, OpenFileAction } from 'vs/workbench/parts/files/browser/fileActions'; -import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { GlobalNewUntitledFileAction } from 'vs/workbench/parts/files/browser/fileActions'; +import { OpenFolderAction, OpenFileFolderAction, OpenFileAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; import { Parts, IPartService } from 'vs/workbench/services/part/common/partService'; import { StartAction } from 'vs/workbench/parts/debug/browser/debugActions'; @@ -100,39 +99,52 @@ const folderEntries = [ ]; const UNBOUND = nls.localize('watermark.unboundCommand', "unbound"); +const WORKBENCH_TIPS_ENABLED_KEY = 'workbench.tips.enabled'; export class WatermarkContribution implements IWorkbenchContribution { private toDispose: IDisposable[] = []; private watermark: Builder; private enabled: boolean; + private workbenchState: WorkbenchState; constructor( @ILifecycleService lifecycleService: ILifecycleService, @IPartService private partService: IPartService, @IKeybindingService private keybindingService: IKeybindingService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @ITelemetryService private telemetryService: ITelemetryService, @IConfigurationService private configurationService: IConfigurationService ) { + this.workbenchState = contextService.getWorkbenchState(); + lifecycleService.onShutdown(this.dispose, this); - this.partService.joinCreation().then(() => { - this.enabled = this.configurationService.lookup('workbench.tips.enabled').value; + lifecycleService.when(LifecyclePhase.Running).then(() => { + this.enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); if (this.enabled) { this.create(); } }); - this.configurationService.onDidUpdateConfiguration(e => { - const enabled = this.configurationService.lookup('workbench.tips.enabled').value; - if (enabled !== this.enabled) { - this.enabled = enabled; - if (this.enabled) { - this.create(); - } else { - this.destroy(); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) { + const enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); + if (enabled !== this.enabled) { + this.enabled = enabled; + if (this.enabled) { + this.create(); + } else { + this.destroy(); + } } } - }); + })); + this.toDispose.push(this.contextService.onDidChangeWorkbenchState(e => { + const previousWorkbenchState = this.workbenchState; + this.workbenchState = this.contextService.getWorkbenchState(); + + if (this.enabled && this.workbenchState !== previousWorkbenchState) { + this.recreate(); + } + })); } public getId() { @@ -147,7 +159,7 @@ export class WatermarkContribution implements IWorkbenchContribution { .div({ 'class': 'watermark' }); const box = $(this.watermark) .div({ 'class': 'watermark-box' }); - const folder = this.contextService.hasWorkspace(); + const folder = this.workbenchState !== WorkbenchState.EMPTY; const selected = folder ? folderEntries : noFolderEntries .filter(entry => !('mac' in entry) || entry.mac === isMacintosh); const update = () => { @@ -189,6 +201,11 @@ export class WatermarkContribution implements IWorkbenchContribution { } } + private recreate(): void { + this.destroy(); + this.create(); + } + public dispose(): void { this.toDispose = dispose(this.toDispose); } diff --git a/src/vs/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.ts b/src/vs/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.ts index cdb9eb088b0..04541aa4295 100644 --- a/src/vs/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.ts +++ b/src/vs/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.ts @@ -11,50 +11,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import * as platform from 'vs/base/common/platform'; import product from 'vs/platform/node/product'; -abstract class AbstractGettingStarted implements IWorkbenchContribution { - protected static hideWelcomeSettingskey = 'workbench.hide.welcome'; - - protected welcomePageURL: string; - protected appName: string; - - constructor( - @IStorageService private storageService: IStorageService, - @IEnvironmentService environmentService: IEnvironmentService, - @ITelemetryService private telemetryService: ITelemetryService - ) { - this.appName = product.nameLong; - - if (product.welcomePage && !environmentService.isExtensionDevelopment /* do not open a browser when we run an extension */) { - this.welcomePageURL = product.welcomePage; - this.handleWelcome(); - } - } - - protected handleWelcome(): void { - let firstStartup = !this.storageService.get(AbstractGettingStarted.hideWelcomeSettingskey); - - if (firstStartup && this.welcomePageURL) { - this.telemetryService.getTelemetryInfo().then(info => { - let url = this.getUrl(info); - this.openExternal(url); - this.storageService.store(AbstractGettingStarted.hideWelcomeSettingskey, true); - }); - } - } - - private getUrl(telemetryInfo: ITelemetryInfo): string { - return `${this.welcomePageURL}&&from=${this.appName}&&id=${telemetryInfo.machineId}`; - } - - protected openExternal(url: string) { - throw new Error('implement me'); - } - - getId(): string { - return 'vs.gettingstarted'; - } -} - export class GettingStarted implements IWorkbenchContribution { private static hideWelcomeSettingskey = 'workbench.hide.welcome'; diff --git a/src/vs/workbench/parts/welcome/gettingStarted/test/common/gettingStarted.test.ts b/src/vs/workbench/parts/welcome/gettingStarted/test/common/gettingStarted.test.ts index 4a232cc0717..7427ca510f2 100644 --- a/src/vs/workbench/parts/welcome/gettingStarted/test/common/gettingStarted.test.ts +++ b/src/vs/workbench/parts/welcome/gettingStarted/test/common/gettingStarted.test.ts @@ -5,7 +5,6 @@ 'use strict'; -// import * as assert from 'assert'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -19,7 +18,7 @@ suite('Workbench - GettingStarted', () => { suiteSetup(() => { instantiation = new TestInstantiationService(); - instantiation.stub(IWorkspaceContextService, { + instantiation.stub(IWorkspaceContextService, { getConfiguration: () => { return { env: { @@ -29,7 +28,7 @@ suite('Workbench - GettingStarted', () => { }; } }); - instantiation.stub(IStorageService, { + instantiation.stub(IStorageService, { get: () => hideWelcomeSettingsValue, store: (value) => hideWelcomeSettingsValue = value }); diff --git a/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts b/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts index 3b11cb151e2..31585553567 100644 --- a/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts @@ -15,7 +15,7 @@ import { Parts, IPartService } from 'vs/workbench/services/part/common/partServi import { TPromise } from 'vs/base/common/winjs.base'; import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.ts b/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.ts index 72b48874dc1..e62ff02dd82 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.ts @@ -15,7 +15,7 @@ export default () => `

${escape(localize('welcomePage.vscode', "Visual Studio Code"))}

-

${escape(localize('welcomePage.editingEvolved', "Editing evolved"))}

+

${escape(localize({ key: 'welcomePage.editingEvolved', comment: ['Shown as subtitle on the Welcome page.'] }, "Editing evolved"))}

@@ -69,7 +69,6 @@ export default () => `
  • -
diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts index 94897a64575..f6ab21bbef8 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution.ts @@ -8,10 +8,10 @@ import { localize } from 'vs/nls'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { WelcomePageContribution, WelcomePageAction, WelcomeInputFactory } from 'vs/workbench/parts/welcome/page/electron-browser/welcomePage'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; +import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ @@ -39,4 +39,4 @@ Registry.as(WorkbenchExtensions.Workbench) Registry.as(ActionExtensions.WorkbenchActions) .registerWorkbenchAction(new SyncActionDescriptor(WelcomePageAction, WelcomePageAction.ID, WelcomePageAction.LABEL), 'Help: Welcome', localize('help', "Help")); -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(WelcomeInputFactory.ID, WelcomeInputFactory); +Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputFactory(WelcomeInputFactory.ID, WelcomeInputFactory); diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.css b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.css index a87de4ff421..1d6504a5cbd 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.css +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.css @@ -144,6 +144,7 @@ text-align: left; cursor: pointer; white-space: nowrap; + font-family: inherit; } .monaco-workbench > .part.editor > .content .welcomePage .commands li button > span { diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts index 94b2ba73526..83fc57833bc 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts @@ -10,7 +10,6 @@ import * as path from 'path'; import * as arrays from 'vs/base/common/arrays'; import { WalkThroughInput } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughInput'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Position } from 'vs/platform/editor/common/editor'; @@ -18,8 +17,7 @@ import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { TPromise } from 'vs/base/common/winjs.base'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -31,10 +29,9 @@ import { IMessageService, Severity, CloseAction } from 'vs/platform/message/comm import { getInstalledExtensions, IExtensionStatus, onExtensionChanged, isKeymapExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsUtils'; import { IExtensionEnablementService, IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { used } from 'vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page'; -import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; +import { ILifecycleService, StartupKind, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { tildify } from 'vs/base/common/labels'; -import { isLinux } from 'vs/base/common/platform'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, foreground, descriptionForeground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { getExtraColor } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughUtils'; @@ -52,7 +49,6 @@ const telemetryFrom = 'welcomePage'; export class WelcomePageContribution implements IWorkbenchContribution { constructor( - @IPartService partService: IPartService, @IInstantiationService instantiationService: IInstantiationService, @IConfigurationService configurationService: IConfigurationService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @@ -65,7 +61,7 @@ export class WelcomePageContribution implements IWorkbenchContribution { if (enabled && lifecycleService.startupKind !== StartupKind.ReloadedWindow) { TPromise.join([ backupFileService.hasBackups(), - partService.joinCreation() + lifecycleService.when(LifecyclePhase.Running) ]).then(([hasBackups]) => { const activeInput = editorService.getActiveEditorInput(); if (!activeInput && !hasBackups) { @@ -83,9 +79,9 @@ export class WelcomePageContribution implements IWorkbenchContribution { } function isWelcomePageEnabled(configurationService: IConfigurationService) { - const startupEditor = configurationService.lookup(configurationKey); + const startupEditor = configurationService.inspect(configurationKey); if (!startupEditor.user && !startupEditor.workspace) { - const welcomeEnabled = configurationService.lookup(oldConfigurationKey); + const welcomeEnabled = configurationService.inspect(oldConfigurationKey); if (welcomeEnabled.value !== undefined && welcomeEnabled.value !== null) { return welcomeEnabled.value; } @@ -124,8 +120,8 @@ interface ExtensionSuggestion { const extensionPacks: ExtensionSuggestion[] = [ { name: localize('welcomePage.javaScript', "JavaScript"), id: 'dbaeumer.vscode-eslint' }, { name: localize('welcomePage.typeScript', "TypeScript"), id: 'eg2.tslint' }, - { name: localize('welcomePage.python', "Python"), id: 'donjayamanne.python' }, - // { name: localize('welcomePage.go', "Go"), id: 'lukehoban.go' }, + // { name: localize('welcomePage.python', "Python"), id: 'donjayamanne.python' }, + { name: localize('welcomePage.go', "Go"), id: 'lukehoban.go' }, { name: localize('welcomePage.php', "PHP"), id: 'felixfbecker.php-pack' }, { name: localize('welcomePage.azure', "Azure"), title: localize('welcomePage.showAzureExtensions', "Show Azure extensions"), id: 'workbench.extensions.action.showAzureExtensions', isCommand: true }, { name: localize('welcomePage.docker', "Docker"), id: 'PeterJausovec.vscode-docker' }, @@ -148,6 +144,32 @@ interface Strings { extensionNotFound: string; } +/* __GDPR__ + "installExtension" : { + "${include}": [ + "${WelcomePageInstall-1}" + ] + } +*/ +/* __GDPR__ + "installedExtension" : { + "${include}": [ + "${WelcomePageInstalled-1}", + "${WelcomePageInstalled-2}", + "${WelcomePageInstalled-3}", + "${WelcomePageInstalled-4}", + "${WelcomePageInstalled-5}", + "${WelcomePageInstalled-6}" + ] + } +*/ +/* __GDPR__ + "detailsExtension" : { + "${include}": [ + "${WelcomePageDetails-1}" + ] + } +*/ const extensionPackStrings: Strings = { installEvent: 'installExtension', installedEvent: 'installedExtension', @@ -159,6 +181,32 @@ const extensionPackStrings: Strings = { extensionNotFound: localize('welcomePage.extensionPackNotFound', "Support for {0} with id {1} could not be found."), }; +/* __GDPR__ + "installKeymap" : { + "${include}": [ + "${WelcomePageInstall-1}" + ] + } +*/ +/* __GDPR__ + "installedKeymap" : { + "${include}": [ + "${WelcomePageInstalled-1}", + "${WelcomePageInstalled-2}", + "${WelcomePageInstalled-3}", + "${WelcomePageInstalled-4}", + "${WelcomePageInstalled-5}", + "${WelcomePageInstalled-6}" + ] + } +*/ +/* __GDPR__ + "detailsKeymap" : { + "${include}": [ + "${WelcomePageDetails-1}" + ] + } +*/ const keymapStrings: Strings = { installEvent: 'installKeymap', installedEvent: 'installedKeymap', @@ -185,7 +233,6 @@ class WelcomePage { @IWindowsService private windowsService: IWindowsService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, @IEnvironmentService private environmentService: IEnvironmentService, @IMessageService private messageService: IMessageService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, @@ -194,7 +241,9 @@ class WelcomePage { @IExtensionTipsService private tipsService: IExtensionTipsService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @ILifecycleService lifecycleService: ILifecycleService, + // @ts-ignore unused injected service @IThemeService private themeService: IThemeService, + // @ts-ignore unused injected service @IExperimentService private experimentService: IExperimentService, @ITelemetryService private telemetryService: ITelemetryService ) { @@ -227,22 +276,12 @@ class WelcomePage { showOnStartup.setAttribute('checked', 'checked'); } showOnStartup.addEventListener('click', e => { - this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: configurationKey, value: showOnStartup.checked ? 'welcomePage' : 'newUntitledFile' }); + this.configurationService.updateValue(configurationKey, showOnStartup.checked ? 'welcomePage' : 'newUntitledFile', ConfigurationTarget.USER); }); recentlyOpened.then(({ workspaces }) => { - const context = this.contextService.getWorkspace(); - workspaces = workspaces.filter(workspace => { - if (this.contextService.hasMultiFolderWorkspace() && typeof workspace !== 'string' && context.id === workspace.id) { - return false; // do not show current workspace - } - - if (this.contextService.hasFolderWorkspace() && isSingleFolderWorkspaceIdentifier(workspace) && this.pathEquals(context.roots[0].fsPath, workspace)) { - return false; // do not show current workspace (single folder case) - } - - return true; - }); + // Filter out the current workspace + workspaces = workspaces.filter(workspace => !this.contextService.isCurrentWorkspace(workspace)); if (!workspaces.length) { const recent = container.querySelector('.welcomePage') as HTMLElement; recent.classList.add('emptyRecent'); @@ -281,6 +320,12 @@ class WelcomePage { a.setAttribute('aria-label', localize('welcomePage.openFolderWithPath', "Open folder {0} with path {1}", name, tildifiedParentFolder)); a.href = 'javascript:void(0)'; a.addEventListener('click', e => { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: 'openRecentFolder', from: telemetryFrom @@ -313,14 +358,8 @@ class WelcomePage { this.updateInstalledExtensions(container, installedExtensions); break; } - }; + } })); - - if (this.experimentService.getExperiments().deployToAzureQuickLink) { - container.querySelector('.showInterfaceOverview').remove(); - } else { - container.querySelector('.deployToAzure').remove(); - } } private addExtensionList(container: HTMLElement, listSelector: string, suggestions: ExtensionSuggestion[], strings: Strings) { @@ -359,23 +398,27 @@ class WelcomePage { } } - private pathEquals(path1: string, path2: string): boolean { - if (!isLinux) { - path1 = path1.toLowerCase(); - path2 = path2.toLowerCase(); - } - - return path1 === path2; - } - private installExtension(extensionSuggestion: ExtensionSuggestion, strings: Strings): void { + /* __GDPR__FRAGMENT__ + "WelcomePageInstall-1" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(strings.installEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, }); this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => { - const installedExtension = arrays.first(extensions, extension => extension.identifier === extensionSuggestion.id); + const installedExtension = arrays.first(extensions, extension => extension.identifier.id === extensionSuggestion.id); if (installedExtension && installedExtension.globallyEnabled) { + /* __GDPR__FRAGMENT__ + "WelcomePageInstalled-1" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, @@ -384,16 +427,16 @@ class WelcomePage { this.messageService.show(Severity.Info, strings.alreadyInstalled.replace('{0}', extensionSuggestion.name)); return; } - const foundAndInstalled = installedExtension ? TPromise.as(true) : this.extensionGalleryService.query({ names: [extensionSuggestion.id] }) + const foundAndInstalled = installedExtension ? TPromise.as(true) : this.extensionGalleryService.query({ names: [extensionSuggestion.id], source: telemetryFrom }) .then(result => { const [extension] = result.firstPage; if (!extension) { return false; } - return this.extensionManagementService.installFromGallery(extension, false) + return this.extensionManagementService.installFromGallery(extension) .then(() => { // TODO: Do this as part of the install to avoid multiple events. - return this.extensionEnablementService.setEnablement(extensionSuggestion.id, false); + return this.extensionEnablementService.setEnablement({ id: extensionSuggestion.id }, false); }).then(() => { return true; }); @@ -416,8 +459,15 @@ class WelcomePage { return foundAndInstalled.then(found => { messageDelay.cancel(); if (found) { - return this.extensionEnablementService.setEnablement(extensionSuggestion.id, true) + return this.extensionEnablementService.setEnablement({ id: extensionSuggestion.id }, true) .then(() => { + /* __GDPR__FRAGMENT__ + "WelcomePageInstalled-2" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, @@ -426,6 +476,13 @@ class WelcomePage { return this.windowService.reloadWindow(); }); } else { + /* __GDPR__FRAGMENT__ + "WelcomePageInstalled-3" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, @@ -436,6 +493,14 @@ class WelcomePage { } }); }).then(null, err => { + /* __GDPR__FRAGMENT__ + "WelcomePageInstalled-4" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "error": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, @@ -447,6 +512,12 @@ class WelcomePage { return TPromise.as(true); }), new Action('details', localize('details', "Details"), null, true, () => { + /* __GDPR__FRAGMENT__ + "WelcomePageDetails-1" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(strings.detailsEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, @@ -457,6 +528,13 @@ class WelcomePage { return TPromise.as(false); }), new Action('cancel', localize('cancel', "Cancel"), null, true, () => { + /* __GDPR__FRAGMENT__ + "WelcomePageInstalled-5" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, @@ -467,6 +545,14 @@ class WelcomePage { ] }); }).then(null, err => { + /* __GDPR__FRAGMENT__ + "WelcomePageInstalled-6" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "outcome": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "error": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ this.telemetryService.publicLog(strings.installedEvent, { from: telemetryFrom, extensionId: extensionSuggestion.id, diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/vs_code_editor_walkthrough.md b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/vs_code_editor_walkthrough.md index 1edc236faf6..fbd56ebf869 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/vs_code_editor_walkthrough.md +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/editor/vs_code_editor_walkthrough.md @@ -4,12 +4,14 @@ The core editor in VS Code is packed with features. This page highlights a numb * [Multi-cursor Editing](#multi-cursor-editing) - block selection, select all occurrences, add additional cursors and more * [IntelliSense](#intellisense) - get code assistance and parameter suggestions for your code and external modules. * [Line Actions](#line-actions) - quickly move lines around to re-order your code. -* [Rename Refactoring](#rename-refactoring) - Quickly rename symbols across your code base. +* [Rename Refactoring](#rename-refactoring) - quickly rename symbols across your code base. +* [Refactoring via Extraction](#refactoring-via-extraction) - quickly extract common code into a separate function or constant. * [Formatting](#formatting) - keep your code looking great with inbuilt document & selection formatting. * [Code Folding](#code-folding) - focus on the most relevant parts of your code by folding other areas. * [Errors and Warnings](#errors-and-warnings) - see errors and warning as you type. * [Snippets](#snippets) - spend less time typing with snippets. * [Emmet](#emmet) - integrated Emmet support takes HTML and CSS editing to the next level. +* [JavaScript Type Checking](#javascript-type-checking) - perform type checking on your JavaScript file using TypeScript with zero configuration. @@ -27,7 +29,7 @@ That is the tip of the iceberg for multi-cursor editing have a look at the `sele #p3 {background-color: #0000ff;} /* blue */ ``` -> **CSS Tip:** you may have noticed in the example above for CSS we also provide color swatches inline, additionally if you hover over an element such as `#p1` we will show how this is represented in HTML. A simple example of some language specific editor features. +> **CSS Tip:** you may have noticed in the example above for CSS we also provide color swatches inline, additionally if you hover over an element such as `#p1` we will show how this is represented in HTML. These swatches also act as color pickers that allow you to easily change a color value. A simple example of some language specific editor features. ### IntelliSense @@ -85,6 +87,21 @@ function Book(title, author) { > **JSDoc Tip:** The example above also showcased another way to get IntelliSense hints by using `JSDoc` comments. You can try this out by invoking the `Book` function and seeing the enhanced context in the IntelliSense Experience for the function as well as parameters. +### Refactoring via Extraction +Sometimes you want factor already written code into a separate function or constant to use it later again. Select the lines you want to factor out and press kb(editor.action.quickFix) or click the little light bulb and choose one of the respective `Extract to...` options. Try it by selecting the code inside the `if`-clause on line 3 or any other common code you want to factor out. + +```js +function findFirstEvenNumber(arr) { + for (let i = 0; i < arr.length; i++) { + if (typeof arr[i] === 'number' && arr[i] % 2 === 0) { + return arr[i]; + } + } + return null; +} +``` + + ### Formatting Keeping your code looking great is hard without a good formatter. Luckily it's easy to format content either the entire document with kb(editor.action.formatDocument) or formatting can be applied to the current selection with kb(editor.action.formatSelection). Both of these options are also available through the right click context menu. @@ -154,6 +171,19 @@ ul>li.item$*5 +### JavaScript Type Checking +Sometimes type checking your JavaScript code can help you spot mistakes you might have not caught otherwise. You can run the TypeScript type checker against your existing JavaScript code by simply adding a `// @ts-check` comment to the top of your file. + +```js +// @ts-nocheck + +let easy = true; +easy = 42; +``` + +>**Tip:** You can also enable the checks workspace or application wide by adding `"javascript.implicitProjectConfig.checkJs": true` to your workspace or user settings and explicitly ignoring files or lines using `// @ts-nocheck` and `// @ts-ignore`. Check out the docs on [JavaScript in VS Code](https://code.visualstudio.com/docs/languages/javascript) to learn more. + + ## Thanks! Well if you have got this far then you will have touched on some of the editing features in Visual Studio Code. But don't stop now :) We have lots of additional [documentation](https://code.visualstudio.com/docs), [introductory videos](https://code.visualstudio.com/docs/getstarted/introvideos) and [tips and tricks](https://go.microsoft.com/fwlink/?linkid=852118) for the product that will help you learn how to use it. And while you are here, here are a few additional things you can try: - Open the Integrated Terminal by pressing kb(workbench.action.terminal.toggleTerminal) then see what's possible by [reviewing the terminal documentation](https://code.visualstudio.com/docs/editor/integrated-terminal) diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThrough.contribution.ts b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThrough.contribution.ts index 6ee4f984bf8..3c296f9ee5e 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThrough.contribution.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThrough.contribution.ts @@ -11,21 +11,22 @@ import { WalkThroughArrowUpAction, WalkThroughArrowDownAction, WalkThroughPageUp import { WalkThroughContentProvider, WalkThroughSnippetContentProvider } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider'; import { EditorWalkThroughAction, EditorWalkThroughInputFactory } from 'vs/workbench/parts/welcome/walkThrough/electron-browser/editor/editorWalkThrough'; import { Registry } from 'vs/platform/registry/common/platform'; -import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; +import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { KeyCode } from 'vs/base/common/keyCodes'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } from 'vs/workbench/browser/editor'; Registry.as(EditorExtensions.Editors) - .registerEditor(new EditorDescriptor(WalkThroughPart.ID, + .registerEditor(new EditorDescriptor( + WalkThroughPart, + WalkThroughPart.ID, localize('walkThrough.editor.label', "Interactive Playground"), - 'vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart', - 'WalkThroughPart'), + ), [new SyncDescriptor(WalkThroughInput)]); Registry.as(Extensions.WorkbenchActions) @@ -33,7 +34,7 @@ Registry.as(Extensions.WorkbenchActions) new SyncActionDescriptor(EditorWalkThroughAction, EditorWalkThroughAction.ID, EditorWalkThroughAction.LABEL), 'Help: Interactive Playground', localize('help', "Help")); -Registry.as(EditorExtensions.Editors).registerEditorInputFactory(EditorWalkThroughInputFactory.ID, EditorWalkThroughInputFactory); +Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(EditorWalkThroughInputFactory.ID, EditorWalkThroughInputFactory); Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(WalkThroughContentProvider); diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css index 305fece6c6b..225f1c5415f 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css @@ -114,7 +114,7 @@ white-space: pre; } -.file-icons-enabled .show-file-icons .vs_code_editor_walkthrough\.md-name-file-icon.md-ext-file-icon.markdown-lang-file-icon.file-icon::before { +.file-icons-enabled .show-file-icons .vs_code_editor_walkthrough\.md-name-file-icon.md-ext-file-icon.ext-file-icon.markdown-lang-file-icon.file-icon::before { content: ' '; background-image: url('../../code-icon.svg'); } diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts index 65d4be0580d..2eb59c0b93d 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts @@ -19,8 +19,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { WalkThroughInput } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughInput'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { marked } from 'vs/base/common/marked/marked'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IFileService } from 'vs/platform/files/common/files'; import { IModelService } from 'vs/editor/common/services/modelService'; import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -34,7 +32,6 @@ import { once } from 'vs/base/common/event'; import { isObject } from 'vs/base/common/types'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; -import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; @@ -99,15 +96,12 @@ export class WalkThroughPart extends BaseEditor { @IInstantiationService private instantiationService: IInstantiationService, @IThemeService protected themeService: IThemeService, @IOpenerService private openerService: IOpenerService, - @IFileService private fileService: IFileService, @IModelService protected modelService: IModelService, @IKeybindingService private keybindingService: IKeybindingService, @IStorageService private storageService: IStorageService, @IContextKeyService private contextKeyService: IContextKeyService, @IConfigurationService private configurationService: IConfigurationService, - @IModeService private modeService: IModeService, - @IMessageService private messageService: IMessageService, - @IPartService private partService: IPartService + @IMessageService private messageService: IMessageService ) { super(WalkThroughPart.ID, telemetryService, themeService); this.editorFocus = WALK_THROUGH_FOCUS.bindTo(this.contextKeyService); @@ -178,6 +172,13 @@ export class WalkThroughPart extends BaseEditor { let baseElement = window.document.getElementsByTagName('base')[0] || window.location; if (baseElement && node.href.indexOf(baseElement.href) >= 0 && node.hash) { let scrollTarget = this.content.querySelector(node.hash); + /* __GDPR__ + "revealInDocument" : { + "hash" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "broken": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('revealInDocument', { hash: node.hash, broken: !scrollTarget, @@ -209,6 +210,12 @@ export class WalkThroughPart extends BaseEditor { private open(uri: URI) { if (uri.scheme === 'http' || uri.scheme === 'https') { + /* __GDPR__ + "openExternal" : { + "uri" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('openExternal', { uri: uri.toString(true), from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined @@ -272,7 +279,7 @@ export class WalkThroughPart extends BaseEditor { } private getArrowScrollHeight() { - let fontSize = this.configurationService.lookup('editor.fontSize').value; + let fontSize = this.configurationService.getValue('editor.fontSize'); if (typeof fontSize !== 'number' || fontSize < 1) { fontSize = 12; } @@ -341,6 +348,12 @@ export class WalkThroughPart extends BaseEditor { const div = innerContent.querySelector(`#${id.replace(/\./g, '\\.')}`) as HTMLElement; const options = this.getEditorOptions(snippet.textEditorModel.getModeId()); + /* __GDPR__FRAGMENT__ + "EditorTelemetryData" : { + "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ const telemetryData = { target: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, snippet: i @@ -382,13 +395,20 @@ export class WalkThroughPart extends BaseEditor { } })); - this.contentDisposables.push(this.configurationService.onDidUpdateConfiguration(() => { + this.contentDisposables.push(this.configurationService.onDidChangeConfiguration(() => { if (snippet.textEditorModel) { editor.updateOptions(this.getEditorOptions(snippet.textEditorModel.getModeId())); } })); this.contentDisposables.push(once(editor.onMouseDown)(() => { + /* __GDPR__ + "walkThroughSnippetInteraction" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'mouseDown', @@ -396,6 +416,13 @@ export class WalkThroughPart extends BaseEditor { }); })); this.contentDisposables.push(once(editor.onKeyDown)(() => { + /* __GDPR__ + "walkThroughSnippetInteraction" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'keyDown', @@ -403,6 +430,13 @@ export class WalkThroughPart extends BaseEditor { }); })); this.contentDisposables.push(once(editor.onDidChangeModelContent)(() => { + /* __GDPR__ + "walkThroughSnippetInteraction" : { + "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'changeModelContent', @@ -412,7 +446,11 @@ export class WalkThroughPart extends BaseEditor { }); this.updateSizeClasses(); this.multiCursorModifier(); - this.contentDisposables.push(this.configurationService.onDidUpdateConfiguration(() => this.multiCursorModifier())); + this.contentDisposables.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.multiCursorModifier')) { + this.multiCursorModifier(); + } + })); if (input.onReady) { input.onReady(innerContent); } @@ -470,8 +508,8 @@ export class WalkThroughPart extends BaseEditor { private multiCursorModifier() { const labels = UILabelProvider.modifierLabels[OS]; - const setting = this.configurationService.lookup('editor.multiCursorModifier'); - const modifier = labels[setting.value === 'ctrlCmd' ? (OS === OperatingSystem.Macintosh ? 'metaKey' : 'ctrlKey') : 'altKey']; + const value = this.configurationService.getValue('editor.multiCursorModifier'); + const modifier = labels[value === 'ctrlCmd' ? (OS === OperatingSystem.Macintosh ? 'metaKey' : 'ctrlKey') : 'altKey']; const keys = this.content.querySelectorAll('.multi-cursor-modifier'); Array.prototype.forEach.call(keys, (key: Element) => { while (key.firstChild) { diff --git a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts index f99257555b6..a534a77b13b 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughInput.ts @@ -15,6 +15,7 @@ import { marked } from 'vs/base/common/marked/marked'; import { Schemas } from 'vs/base/common/network'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export class WalkThroughModel extends EditorModel { @@ -63,7 +64,8 @@ export class WalkThroughInput extends EditorInput { private options: WalkThroughInputOptions, @ITelemetryService private telemetryService: ITelemetryService, @ILifecycleService lifecycleService: ILifecycleService, - @ITextModelService private textModelResolverService: ITextModelService + @ITextModelService private textModelResolverService: ITextModelService, + @IHashService private hashService: IHashService ) { super(); this.disposables.push(lifecycleService.onShutdown(e => this.disposeTelemetry(e))); @@ -92,7 +94,13 @@ export class WalkThroughInput extends EditorInput { getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); descriptor['target'] = this.getTelemetryFrom(); - descriptor['resource'] = telemetryURIDescriptor(this.options.resource); + descriptor['resource'] = telemetryURIDescriptor(this.options.resource, path => this.hashService.createSHA1(path)); + /* __GDPR__FRAGMENT__ + "EditorTelemetryDescriptor" : { + "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "resource": { "${inline}": [ "${URIDescriptor}" ] } + } + */ return descriptor; } @@ -165,6 +173,11 @@ export class WalkThroughInput extends EditorInput { private resolveTelemetry() { if (!this.resolveTime) { this.resolveTime = Date.now(); + /* __GDPR__ + "resolvingInput" : { + "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('resolvingInput', { target: this.getTelemetryFrom(), }); @@ -173,6 +186,15 @@ export class WalkThroughInput extends EditorInput { private disposeTelemetry(reason?: ShutdownReason) { if (this.resolveTime) { + /* __GDPR__ + "disposingInput" : { + "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "timeSpent": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "reason": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "maxTopScroll": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "maxBottomScroll": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('disposingInput', { target: this.getTelemetryFrom(), timeSpent: (Date.now() - this.resolveTime) / 60, diff --git a/src/vs/workbench/services/activity/browser/activityService.ts b/src/vs/workbench/services/activity/browser/activityService.ts new file mode 100644 index 00000000000..4f328baa8ae --- /dev/null +++ b/src/vs/workbench/services/activity/browser/activityService.ts @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart'; +import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart'; +import { IActivityService, IBadge } from 'vs/workbench/services/activity/common/activity'; +import { IDisposable } from 'vs/base/common/lifecycle'; + +export class ActivityService implements IActivityService { + + public _serviceBrand: any; + + constructor( + private activitybarPart: ActivitybarPart, + private panelPart: PanelPart, + @IPanelService private panelService: IPanelService + ) { } + + public showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string): IDisposable { + if (this.panelService.getPanels().filter(p => p.id === compositeOrActionId).length) { + return this.panelPart.showActivity(compositeOrActionId, badge, clazz); + } + + return this.activitybarPart.showActivity(compositeOrActionId, badge, clazz); + } +} diff --git a/src/vs/workbench/services/activity/common/activityBarService.ts b/src/vs/workbench/services/activity/common/activity.ts similarity index 63% rename from src/vs/workbench/services/activity/common/activityBarService.ts rename to src/vs/workbench/services/activity/common/activity.ts index 5c5b18a2105..e2f5286ba2e 100644 --- a/src/vs/workbench/services/activity/common/activityBarService.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -58,38 +58,13 @@ export class IconBadge extends BaseBadge { export class ProgressBadge extends BaseBadge { } -export const IActivityBarService = createDecorator('activityBarService'); +export const IActivityService = createDecorator('activityService'); -export interface IActivityBarService { +export interface IActivityService { _serviceBrand: any; /** - * Show activity in the activitybar for the given global activity. + * Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action. */ - showGlobalActivity(globalActivityId: string, badge: IBadge): IDisposable; - - /** - * Show activity in the activitybar for the given viewlet. - */ - showActivity(viewletId: string, badge: IBadge, clazz?: string): IDisposable; - - /** - * Unpins a viewlet from the activitybar. - */ - unpin(viewletId: string): void; - - /** - * Pin a viewlet inside the activity bar. - */ - pin(viewletId: string): void; - - /** - * Find out if a viewlet is pinned in the activity bar. - */ - isPinned(viewletId: string): boolean; - - /** - * Reorder viewlet ordering by moving a viewlet to the location of another viewlet. - */ - move(viewletId: string, toViewletId: string): void; + showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string): IDisposable; } diff --git a/src/vs/workbench/services/backup/node/backupFileService.ts b/src/vs/workbench/services/backup/node/backupFileService.ts index fc8c8efbdd0..af5ca6bda2b 100644 --- a/src/vs/workbench/services/backup/node/backupFileService.ts +++ b/src/vs/workbench/services/backup/node/backupFileService.ts @@ -7,7 +7,6 @@ import * as path from 'path'; import * as crypto from 'crypto'; -import * as platform from 'vs/base/common/platform'; import pfs = require('vs/base/node/pfs'); import Uri from 'vs/base/common/uri'; import { ResourceQueue } from 'vs/base/common/async'; @@ -88,20 +87,29 @@ export class BackupFilesModel implements IBackupFilesModel { export class BackupFileService implements IBackupFileService { + private static readonly META_MARKER = '\n'; + public _serviceBrand: any; - private static readonly META_MARKER = '\n'; + private backupWorkspacePath: string; private isShuttingDown: boolean; private ready: TPromise; - private ioOperationQueues: ResourceQueue; // queue IO operations to ensure write order + private ioOperationQueues: ResourceQueue; // queue IO operations to ensure write order constructor( - private backupWorkspacePath: string, + backupWorkspacePath: string, @IFileService private fileService: IFileService ) { this.isShuttingDown = false; - this.ioOperationQueues = new ResourceQueue(); + this.ioOperationQueues = new ResourceQueue(); + + this.initialize(backupWorkspacePath); + } + + public initialize(backupWorkspacePath: string): void { + this.backupWorkspacePath = backupWorkspacePath; + this.ready = this.init(); } @@ -137,16 +145,6 @@ export class BackupFileService implements IBackupFileService { return backupResource; } - // Otherwise: on Windows and Mac pre v1.11 we used to store backups in lowercase format - // Therefor we also want to check if we have backups of this old format hanging around - // TODO@Ben migration - if (platform.isWindows || platform.isMacintosh) { - const legacyBackupResource = this.getBackupResource(resource, true /* legacyMacWindowsFormat */); - if (model.has(legacyBackupResource)) { - return legacyBackupResource; - } - } - return void 0; }); } @@ -184,21 +182,6 @@ export class BackupFileService implements IBackupFileService { return this.ioOperationQueues.queueFor(backupResource).queue(() => { return pfs.del(backupResource.fsPath).then(() => model.remove(backupResource)); - }).then(() => { - - // On Windows and Mac pre v1.11 we used to store backups in lowercase format - // Therefor we also want to check if we have backups of this old format laying around - // TODO@Ben migration - if (platform.isWindows || platform.isMacintosh) { - const legacyBackupResource = this.getBackupResource(resource, true /* legacyMacWindowsFormat */); - if (model.has(legacyBackupResource)) { - return this.ioOperationQueues.queueFor(legacyBackupResource).queue(() => { - return pfs.del(legacyBackupResource.fsPath).then(() => model.remove(legacyBackupResource)); - }); - } - } - - return TPromise.as(void 0); }); }); } @@ -235,17 +218,15 @@ export class BackupFileService implements IBackupFileService { return textSource.lines.slice(1).join(textSource.EOL); // The first line of a backup text file is the file name } - protected getBackupResource(resource: Uri, legacyMacWindowsFormat?: boolean): Uri { + protected getBackupResource(resource: Uri): Uri { if (!this.backupEnabled) { return null; } - return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, this.hashPath(resource, legacyMacWindowsFormat))); + return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, this.hashPath(resource))); } - private hashPath(resource: Uri, legacyMacWindowsFormat?: boolean): string { - const caseAwarePath = legacyMacWindowsFormat ? resource.fsPath.toLowerCase() : resource.fsPath; - - return crypto.createHash('md5').update(caseAwarePath).digest('hex'); + private hashPath(resource: Uri): string { + return crypto.createHash('md5').update(resource.fsPath).digest('hex'); } } diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts index ca9d721d6b2..28db9272fcf 100644 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts @@ -16,25 +16,12 @@ import pfs = require('vs/base/node/pfs'); import Uri from 'vs/base/common/uri'; import { BackupFileService, BackupFilesModel } from 'vs/workbench/services/backup/node/backupFileService'; import { FileService } from 'vs/workbench/services/files/node/fileService'; -import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; import { RawTextSource } from 'vs/editor/common/model/textSource'; -import { TestContextService } from 'vs/workbench/test/workbenchTestServices'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -class TestEnvironmentService extends EnvironmentService { - - constructor(private _backupHome: string, private _backupWorkspacesPath: string) { - super(parseArgs(process.argv), process.execPath); - } - - get backupHome(): string { return this._backupHome; } - - get backupWorkspacesPath(): string { return this._backupWorkspacesPath; } -} - -const parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); +const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice'); const backupHome = path.join(parentDir, 'Backups'); const workspacesJsonPath = path.join(backupHome, 'workspaces.json'); @@ -44,19 +31,18 @@ const fooFile = Uri.file(platform.isWindows ? 'c:\\Foo' : '/Foo'); const barFile = Uri.file(platform.isWindows ? 'c:\\Bar' : '/Bar'); const untitledFile = Uri.from({ scheme: 'untitled', path: 'Untitled-1' }); const fooBackupPath = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(fooFile.fsPath).digest('hex')); -const fooBackupPathLegacy = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(fooFile.fsPath.toLowerCase()).digest('hex')); const barBackupPath = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(barFile.fsPath).digest('hex')); const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', crypto.createHash('md5').update(untitledFile.fsPath).digest('hex')); class TestBackupFileService extends BackupFileService { constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) { - const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, [workspace])), new TestConfigurationService(), { disableWatcher: true }); + const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, toWorkspaceFolders([{ path: workspace.fsPath }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }); super(workspaceBackupPath, fileService); } - public getBackupResource(resource: Uri, legacyMacWindowsFormat?: boolean): Uri { - return super.getBackupResource(resource, legacyMacWindowsFormat); + public getBackupResource(resource: Uri): Uri { + return super.getBackupResource(resource); } } @@ -115,47 +101,6 @@ suite('BackupFileService', () => { }); }); }); - - test('should return whether a backup resource exists - legacy support (read old lowercase format as fallback)', done => { - if (platform.isLinux) { - done(); - return; // only on mac and windows - } - - pfs.mkdirp(path.dirname(fooBackupPath)).then(() => { - fs.writeFileSync(fooBackupPathLegacy, 'foo'); - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - service.loadBackupResource(fooFile).then(resource => { - assert.ok(resource); - assert.equal(path.basename(resource.fsPath), path.basename(fooBackupPathLegacy)); - return service.hasBackups().then(hasBackups => { - assert.ok(hasBackups); - done(); - }); - }); - }); - }); - - test('should return whether a backup resource exists - legacy support #2 (both cases present, return case sensitive backup)', done => { - if (platform.isLinux) { - done(); - return; // only on mac and windows - } - - pfs.mkdirp(path.dirname(fooBackupPath)).then(() => { - fs.writeFileSync(fooBackupPath, 'foo'); - fs.writeFileSync(fooBackupPathLegacy, 'foo'); - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - service.loadBackupResource(fooFile).then(resource => { - assert.ok(resource); - assert.equal(path.basename(resource.fsPath), path.basename(fooBackupPath)); - return service.hasBackups().then(hasBackups => { - assert.ok(hasBackups); - done(); - }); - }); - }); - }); }); suite('backupResource', () => { @@ -200,27 +145,6 @@ suite('BackupFileService', () => { }); }); }); - - test('text file - legacy support (dicard lowercase backup file if present)', done => { - if (platform.isLinux) { - done(); - return; // only on mac and windows - } - - pfs.mkdirp(path.dirname(fooBackupPath)).then(() => { - fs.writeFileSync(fooBackupPathLegacy, 'foo'); - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - service.backupResource(fooFile, 'test').then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2); - service.discardResourceBackup(fooFile).then(() => { - assert.equal(fs.existsSync(fooBackupPath), false); - assert.equal(fs.existsSync(fooBackupPathLegacy), false); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0); - done(); - }); - }); - }); - }); }); suite('discardAllWorkspaceBackups', () => { diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index c38ff73b6d6..d6f6475490b 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -13,15 +13,20 @@ export const WORKSPACE_CONFIG_DEFAULT_PATH = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_ export const IWorkspaceConfigurationService = createDecorator('configurationService'); export interface IWorkspaceConfigurationService extends IConfigurationService { - /** * Returns untrusted configuration keys for the current workspace. */ getUnsupportedWorkspaceKeys(): string[]; - } -export const WORKSPACE_STANDALONE_CONFIGURATIONS = { - 'tasks': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/tasks.json`, - 'launch': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json` -}; \ No newline at end of file +export const defaultSettingsSchemaId = 'vscode://schemas/settings/default'; +export const userSettingsSchemaId = 'vscode://schemas/settings/user'; +export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace'; +export const folderSettingsSchemaId = 'vscode://schemas/settings/folder'; + +export const TASKS_CONFIGURATION_KEY = 'tasks'; +export const LAUNCH_CONFIGURATION_KEY = 'launch'; + +export const WORKSPACE_STANDALONE_CONFIGURATIONS = Object.create(null); +WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/tasks.json`; +WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY] = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json`; \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/common/configurationEditing.ts b/src/vs/workbench/services/configuration/common/configurationEditing.ts deleted file mode 100644 index 5cd14ca3229..00000000000 --- a/src/vs/workbench/services/configuration/common/configurationEditing.ts +++ /dev/null @@ -1,104 +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 { TPromise } from 'vs/base/common/winjs.base'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; - -export const IConfigurationEditingService = createDecorator('configurationEditingService'); - -export enum ConfigurationEditingErrorCode { - - /** - * Error when trying to write a configuration key that is not registered. - */ - ERROR_UNKNOWN_KEY, - - /** - * Error when trying to write an invalid folder configuration key to folder settings. - */ - ERROR_INVALID_FOLDER_CONFIGURATION, - - /** - * Error when trying to write to user target but not supported for provided key. - */ - ERROR_INVALID_USER_TARGET, - - /** - * Error when trying to write a configuration key to folder target - */ - ERROR_INVALID_FOLDER_TARGET, - - /** - * Error when trying to write to the workspace configuration without having a workspace opened. - */ - ERROR_NO_WORKSPACE_OPENED, - - /** - * Error when trying to write and save to the configuration file while it is dirty in the editor. - */ - ERROR_CONFIGURATION_FILE_DIRTY, - - /** - * Error when trying to write to a configuration file that contains JSON errors. - */ - ERROR_INVALID_CONFIGURATION -} - -export class ConfigurationEditingError extends Error { - constructor(message: string, public code: ConfigurationEditingErrorCode) { - super(message); - } -} - -export enum ConfigurationTarget { - - /** - * Targets the user configuration file for writing. - */ - USER, - - /** - * Targets the workspace configuration file for writing. This only works if a workspace is opened. - */ - WORKSPACE, - - /** - * Targets the folder configuration file for writing. This only works if a workspace is opened. - */ - FOLDER -} - -export interface IConfigurationValue { - key: string; - value: any; -} - -export interface IConfigurationEditingOptions { - /** - * If `true`, do not saves the configuration. Default is `false`. - */ - donotSave?: boolean; - /** - * If `true`, do not notifies the error to user by showing the message box. Default is `false`. - */ - donotNotifyError?: boolean; - /** - * Scope of configuration to be written into. - */ - scopes?: IConfigurationOverrides; -} - -export interface IConfigurationEditingService { - - _serviceBrand: ServiceIdentifier; - - /** - * Allows to write the configuration value to either the user or workspace configuration file and save it if asked to save. - * The returned promise will be in error state in any of the error cases from [ConfigurationEditingErrorCode](#ConfigurationEditingErrorCode) - */ - writeConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options?: IConfigurationEditingOptions): TPromise; -} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/common/configurationExtensionPoint.ts b/src/vs/workbench/services/configuration/common/configurationExtensionPoint.ts new file mode 100644 index 00000000000..5525cc06c01 --- /dev/null +++ b/src/vs/workbench/services/configuration/common/configurationExtensionPoint.ts @@ -0,0 +1,211 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import * as objects from 'vs/base/common/objects'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { ExtensionsRegistry, IExtensionPointUser } from 'vs/platform/extensions/common/extensionsRegistry'; +import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { workspaceSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; + +const configurationRegistry = Registry.as(Extensions.Configuration); + +const configurationEntrySchema: IJSONSchema = { + type: 'object', + defaultSnippets: [{ body: { title: '', properties: {} } }], + properties: { + title: { + description: nls.localize('vscode.extension.contributes.configuration.title', 'A summary of the settings. This label will be used in the settings file as separating comment.'), + type: 'string' + }, + properties: { + description: nls.localize('vscode.extension.contributes.configuration.properties', 'Description of the configuration properties.'), + type: 'object', + additionalProperties: { + anyOf: [ + { $ref: 'http://json-schema.org/draft-04/schema#' }, + { + type: 'object', + properties: { + isExecutable: { + type: 'boolean' + }, + scope: { + type: 'string', + enum: ['window', 'resource'], + default: 'window', + enumDescriptions: [ + nls.localize('scope.window.description', "Window specific configuration, which can be configured in the User or Workspace settings."), + nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the User, Workspace or Folder settings.") + ], + description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `window` and `resource`.") + } + } + } + ] + } + } + } +}; + + +// BEGIN VSCode extension point `configuration` +const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configuration', [], { + description: nls.localize('vscode.extension.contributes.configuration', 'Contributes configuration settings.'), + oneOf: [ + configurationEntrySchema, + { + type: 'array', + items: configurationEntrySchema + } + ] +}); +configurationExtPoint.setHandler(extensions => { + const configurations: IConfigurationNode[] = []; + + function handleConfiguration(node: IConfigurationNode, id: string, extension: IExtensionPointUser) { + let configuration = objects.clone(node); + + if (configuration.title && (typeof configuration.title !== 'string')) { + extension.collector.error(nls.localize('invalid.title', "'configuration.title' must be a string")); + } + + validateProperties(configuration, extension); + + configuration.id = id; + configurations.push(configuration); + } + + for (let extension of extensions) { + const value = extension.value; + const id = extension.description.id; + if (!Array.isArray(value)) { + handleConfiguration(value, id, extension); + } else { + value.forEach(v => handleConfiguration(v, id, extension)); + } + } + configurationRegistry.registerConfigurations(configurations, false); +}); +// END VSCode extension point `configuration` + +// BEGIN VSCode extension point `configurationDefaults` +const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configurationDefaults', [], { + description: nls.localize('vscode.extension.contributes.defaultConfiguration', 'Contributes default editor configuration settings by language.'), + type: 'object', + defaultSnippets: [{ body: {} }], + patternProperties: { + '\\[.*\\]$': { + type: 'object', + default: {}, + $ref: editorConfigurationSchemaId, + } + } +}); +defaultConfigurationExtPoint.setHandler(extensions => { + const defaultConfigurations: IDefaultConfigurationExtension[] = extensions.map(extension => { + const id = extension.description.id; + const name = extension.description.name; + const defaults = objects.clone(extension.value); + return { + id, name, defaults + }; + }); + configurationRegistry.registerDefaultConfigurations(defaultConfigurations); +}); +// END VSCode extension point `configurationDefaults` + +function validateProperties(configuration: IConfigurationNode, extension: IExtensionPointUser): void { + let properties = configuration.properties; + if (properties) { + if (typeof properties !== 'object') { + extension.collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object")); + configuration.properties = {}; + } + for (let key in properties) { + const message = validateProperty(key); + const propertyConfiguration = configuration.properties[key]; + propertyConfiguration.scope = propertyConfiguration.scope && propertyConfiguration.scope.toString() === 'resource' ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW; + propertyConfiguration.notMultiRootAdopted = !(extension.description.isBuiltin || (Array.isArray(extension.description.keywords) && extension.description.keywords.indexOf('multi-root ready') !== -1)); + if (message) { + extension.collector.warn(message); + delete properties[key]; + } + } + } + let subNodes = configuration.allOf; + if (subNodes) { + extension.collector.error(nls.localize('invalid.allOf', "'configuration.allOf' is deprecated and should no longer be used. Instead, pass multiple configuration sections as an array to the 'configuration' contribution point.")); + for (let node of subNodes) { + validateProperties(node, extension); + } + } +} + +const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); +jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', { + default: { + folders: [ + { + path: '' + } + ], + settings: { + } + }, + required: ['folders'], + properties: { + 'folders': { + minItems: 0, + uniqueItems: true, + description: nls.localize('workspaceConfig.folders.description', "List of folders to be loaded in the workspace."), + items: { + type: 'object', + default: { path: '' }, + oneOf: [{ + properties: { + path: { + type: 'string', + description: nls.localize('workspaceConfig.path.description', "A file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file.") + }, + name: { + type: 'string', + description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") + } + }, + required: ['path'] + }, { + properties: { + uri: { + type: 'string', + description: nls.localize('workspaceConfig.uri.description', "URI of the folder") + }, + name: { + type: 'string', + description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") + } + }, + required: ['uri'] + }] + } + }, + 'settings': { + type: 'object', + default: {}, + description: nls.localize('workspaceConfig.settings.description', "Workspace settings"), + $ref: workspaceSettingsSchemaId + }, + 'extensions': { + type: 'object', + default: {}, + description: nls.localize('workspaceConfig.extensions.description', "Workspace extensions"), + $ref: 'vscode://schemas/extensions' + } + }, + additionalProperties: false, + errorMessage: nls.localize('unknownWorkspaceProperty', "Unknown workspace configuration property") +}); \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index dd7f73103ed..be16b2d69c6 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -4,69 +4,74 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { clone } from 'vs/base/common/objects'; -import { CustomConfigurationModel, toValuesTree } from 'vs/platform/configuration/common/model'; -import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { clone, equals } from 'vs/base/common/objects'; +import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { StrictResourceMap } from 'vs/base/common/map'; +import URI from 'vs/base/common/uri'; +import { distinct } from 'vs/base/common/arrays'; -export class WorkspaceConfigurationModel extends CustomConfigurationModel { +export class WorkspaceConfigurationModel extends CustomConfigurationModel { - private _raw: T; + private _raw: any; private _folders: IStoredWorkspaceFolder[]; - private _worksapaceSettings: ConfigurationModel; - private _tasksConfiguration: ConfigurationModel; - private _launchConfiguration: ConfigurationModel; - private _workspaceConfiguration: ConfigurationModel; + private _worksapaceSettings: WorkspaceSettingsModel; public update(content: string): void { super.update(content); - this._worksapaceSettings = new ConfigurationModel(this._worksapaceSettings.contents, this._worksapaceSettings.keys, this.overrides); - this._workspaceConfiguration = this.consolidate(); + this._folders = (this._raw['folders'] || []) as IStoredWorkspaceFolder[]; + this._worksapaceSettings = new WorkspaceSettingsModel(this._raw['settings'] || {}); } get folders(): IStoredWorkspaceFolder[] { return this._folders; } - get workspaceConfiguration(): ConfigurationModel { - return this._workspaceConfiguration; + get workspaceConfiguration(): ConfigurationModel { + return this._worksapaceSettings || new WorkspaceSettingsModel({}); } - protected processRaw(raw: T): void { + get workspaceSettingsModel(): WorkspaceSettingsModel { + return this._worksapaceSettings || new WorkspaceSettingsModel({}); + } + + protected processRaw(raw: any): void { this._raw = raw; - - this._folders = (this._raw['folders'] || []) as IStoredWorkspaceFolder[]; - this._worksapaceSettings = this.parseConfigurationModel('settings'); - this._tasksConfiguration = this.parseConfigurationModel('tasks'); - this._launchConfiguration = this.parseConfigurationModel('launch'); - super.processRaw(raw); } - private parseConfigurationModel(section: string): ConfigurationModel { - const rawSection = this._raw[section] || {}; - const contents = toValuesTree(rawSection, message => console.error(`Conflict in section '${section}' of workspace configuration file ${message}`)); - return new ConfigurationModel(contents, Object.keys(rawSection)); + +} + +export class WorkspaceSettingsModel extends ConfigurationModel { + + private _raw: any; + private _unsupportedKeys: string[]; + + constructor(raw: any) { + super(); + this._raw = raw; + this.update(); } - private consolidate(): ConfigurationModel { - const keys: string[] = [...this._worksapaceSettings.keys, - ...this._tasksConfiguration.keys.map(key => `tasks.${key}`), - ...this._launchConfiguration.keys.map(key => `launch.${key}`)]; + public get unsupportedKeys(): string[] { + return this._unsupportedKeys || []; + } - const mergedContents = new ConfigurationModel({}, keys) - .merge(this._worksapaceSettings) - .merge(this._tasksConfiguration) - .merge(this._launchConfiguration); - - return new ConfigurationModel(mergedContents.contents, keys, mergedContents.overrides); + update(): void { + const { unsupportedKeys, contents } = processWorkspaceSettings(this._raw); + this._unsupportedKeys = unsupportedKeys; + this._contents = toValuesTree(contents, message => console.error(`Conflict in workspace settings file: ${message}`)); + this._keys = Object.keys(contents); } } -export class ScopedConfigurationModel extends CustomConfigurationModel { +export class ScopedConfigurationModel extends CustomConfigurationModel { constructor(content: string, name: string, public readonly scope: string) { super(null, name); @@ -82,24 +87,38 @@ export class ScopedConfigurationModel extends CustomConfigurationModel { } -export class FolderSettingsModel extends CustomConfigurationModel { +function processWorkspaceSettings(content: any): { unsupportedKeys: string[], contents: any } { + const isNotExecutable = (key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): boolean => { + const propertySchema = configurationProperties[key]; + if (!propertySchema) { + return true; // Unknown propertis are ignored from checks + } + return !propertySchema.isExecutable; + }; - private _raw: T; + const unsupportedKeys = []; + const contents = {}; + const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + for (let key in content) { + if (isNotExecutable(key, configurationProperties)) { + contents[key] = content[key]; + } else { + unsupportedKeys.push(key); + } + } + return { contents, unsupportedKeys }; +} + +export class FolderSettingsModel extends CustomConfigurationModel { + + private _raw: any; private _unsupportedKeys: string[]; - protected processRaw(raw: T): void { + protected processRaw(raw: any): void { this._raw = raw; - const processedRaw = {}; - this._unsupportedKeys = []; - const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); - for (let key in raw) { - if (this.isNotExecutable(key, configurationProperties)) { - processedRaw[key] = raw[key]; - } else { - this._unsupportedKeys.push(key); - } - } - return super.processRaw(processedRaw); + const { unsupportedKeys, contents } = processWorkspaceSettings(raw); + this._unsupportedKeys = unsupportedKeys; + return super.processRaw(contents); } public reprocess(): void { @@ -110,24 +129,16 @@ export class FolderSettingsModel extends CustomConfigurationModel { return this._unsupportedKeys || []; } - private isNotExecutable(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): boolean { - const propertySchema = configurationProperties[key]; - if (!propertySchema) { - return true; // Unknown propertis are ignored from checks - } - return !propertySchema.isExecutable; - } - - public createWorkspaceConfigurationModel(): ConfigurationModel { + public createWorkspaceConfigurationModel(): ConfigurationModel { return this.createScopedConfigurationModel(ConfigurationScope.WINDOW); } - public createFolderScopedConfigurationModel(): ConfigurationModel { + public createFolderScopedConfigurationModel(): ConfigurationModel { return this.createScopedConfigurationModel(ConfigurationScope.RESOURCE); } - private createScopedConfigurationModel(scope: ConfigurationScope): ConfigurationModel { - const workspaceRaw = {}; + private createScopedConfigurationModel(scope: ConfigurationScope): ConfigurationModel { + const workspaceRaw = {}; const configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties(); for (let key in this._raw) { if (this.getScope(key, configurationProperties) === scope) { @@ -145,15 +156,15 @@ export class FolderSettingsModel extends CustomConfigurationModel { } } -export class FolderConfigurationModel extends CustomConfigurationModel { +export class FolderConfigurationModel extends CustomConfigurationModel { - constructor(public readonly workspaceSettingsConfig: FolderSettingsModel, private scopedConfigs: ScopedConfigurationModel[], private scope: ConfigurationScope) { + constructor(public readonly workspaceSettingsConfig: FolderSettingsModel, private scopedConfigs: ScopedConfigurationModel[], private scope: ConfigurationScope) { super(); this.consolidate(); } private consolidate(): void { - this._contents = {}; + this._contents = {}; this._overrides = []; this.doMerge(this, ConfigurationScope.WINDOW === this.scope ? this.workspaceSettingsConfig : this.workspaceSettingsConfig.createFolderScopedConfigurationModel()); @@ -178,4 +189,185 @@ export class FolderConfigurationModel extends CustomConfigurationModel { this.workspaceSettingsConfig.reprocess(); this.consolidate(); } +} + +export class Configuration extends BaseConfiguration { + + constructor( + defaults: ConfigurationModel, + user: ConfigurationModel, + workspaceConfiguration: ConfigurationModel, + protected folders: StrictResourceMap, + memoryConfiguration: ConfigurationModel, + memoryConfigurationByResource: StrictResourceMap, + private readonly _workspace: Workspace) { + super(defaults, user, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource); + } + + getSection(section: string = '', overrides: IConfigurationOverrides = {}): C { + return super.getSection(section, overrides, this._workspace); + } + + getValue(key: string, overrides: IConfigurationOverrides = {}): any { + return super.getValue(key, overrides, this._workspace); + } + + lookup(key: string, overrides: IConfigurationOverrides = {}): { + default: C, + user: C, + workspace: C, + workspaceFolder: C + memory?: C + value: C, + } { + return super.lookup(key, overrides, this._workspace); + } + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + return super.keys(this._workspace); + } + + updateDefaultConfiguration(defaults: ConfigurationModel): void { + this._defaults = defaults; + this.merge(); + } + + updateUserConfiguration(user: ConfigurationModel): ConfigurationChangeEvent { + const { added, updated, removed } = compare(this._user, user); + let changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); + + this._user = user; + this.merge(); + + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key))); + } + return new ConfigurationChangeEvent().change(changedKeys); + } + + updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): ConfigurationChangeEvent { + const { added, updated, removed } = compare(this._workspaceConfiguration, workspaceConfiguration); + let changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); + + this._workspaceConfiguration = workspaceConfiguration; + this.merge(); + + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key))); + } + return new ConfigurationChangeEvent().change(changedKeys); + } + + updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel): ConfigurationChangeEvent { + const currentFolderConfiguration = this.folders.get(resource); + + if (currentFolderConfiguration) { + const { added, updated, removed } = compare(currentFolderConfiguration, configuration); + let changedKeys = [...added, ...updated, ...removed]; + if (changedKeys.length) { + const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace); + + this.folders.set(resource, configuration); + this.mergeFolder(resource); + + changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key, { resource }), this.getValue(key, { resource }))); + } + return new ConfigurationChangeEvent().change(changedKeys, resource); + } + + this.folders.set(resource, configuration); + this.mergeFolder(resource); + return new ConfigurationChangeEvent().change(configuration.keys, resource); + } + + deleteFolderConfiguration(folder: URI): ConfigurationChangeEvent { + if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.toString() === folder.toString()) { + // Do not remove workspace configuration + return new ConfigurationChangeEvent(); + } + + const keys = this.folders.get(folder).keys; + this.folders.delete(folder); + this._foldersConsolidatedConfigurations.delete(folder); + return new ConfigurationChangeEvent().change(keys, folder); + } + + getFolderConfigurationModel(folder: URI): FolderConfigurationModel { + return this.folders.get(folder); + } + + compare(other: Configuration): string[] { + let from = other.allKeys(); + let to = this.allKeys(); + + const added = to.filter(key => from.indexOf(key) === -1); + const removed = from.filter(key => to.indexOf(key) === -1); + const updated = []; + + for (const key of from) { + const value1 = this.getValue(key); + const value2 = other.getValue(key); + if (!equals(value1, value2)) { + updated.push(key); + } + } + + return [...added, ...removed, ...updated]; + } + + allKeys(): string[] { + let keys = this.keys(); + let all = [...keys.default, ...keys.user, ...keys.workspace]; + for (const resource of this.folders.keys()) { + all.push(...this.folders.get(resource).keys); + } + return distinct(all); + } +} + +export class WorkspaceConfigurationChangeEvent implements IConfigurationChangeEvent { + + constructor(private configurationChangeEvent: IConfigurationChangeEvent, private workspace: Workspace) { } + + get changedConfiguration(): IConfigurationModel { + return this.configurationChangeEvent.changedConfiguration; + } + + get changedConfigurationByResource(): StrictResourceMap { + return this.configurationChangeEvent.changedConfigurationByResource; + } + + get affectedKeys(): string[] { + return this.configurationChangeEvent.affectedKeys; + } + + get source(): ConfigurationTarget { + return this.configurationChangeEvent.source; + } + + get sourceConfig(): any { + return this.configurationChangeEvent.sourceConfig; + } + + affectsConfiguration(config: string, resource?: URI): boolean { + if (this.configurationChangeEvent.affectsConfiguration(config, resource)) { + return true; + } + + if (resource && this.workspace) { + let workspaceFolder = this.workspace.getFolder(resource); + if (workspaceFolder) { + return this.configurationChangeEvent.affectsConfiguration(config, workspaceFolder.uri); + } + } + + return false; + } } \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index 0f45a64cd69..3692195001f 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -2,38 +2,28 @@ * 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 URI from 'vs/base/common/uri'; import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter } from 'vs/base/common/event'; -import { StrictResourceMap } from 'vs/base/common/map'; -import { equals, coalesce } from 'vs/base/common/arrays'; -import * as objects from 'vs/base/common/objects'; +import { readFile } from 'vs/base/node/pfs'; import * as errors from 'vs/base/common/errors'; import * as collections from 'vs/base/common/collections'; -import { Disposable, toDisposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { readFile, stat } from 'vs/base/node/pfs'; -import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import * as extfs from 'vs/base/node/extfs'; -import { IWorkspaceContextService, IWorkspace, Workspace, ILegacyWorkspace, LegacyWorkspace } from 'vs/platform/workspace/common/workspace'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { CustomConfigurationModel } from 'vs/platform/configuration/common/model'; -import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels'; -import { IConfigurationServiceEvent, ConfigurationSource, IConfigurationKeys, IConfigurationValue, ConfigurationModel, IConfigurationOverrides, Configuration as BaseConfiguration, IConfigurationValues, IConfigurationData } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH } from 'vs/workbench/services/configuration/common/configuration'; -import { ConfigurationService as GlobalConfigurationService } from 'vs/platform/configuration/node/configurationService'; -import * as nls from 'vs/nls'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; -import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope, schemaId } from 'vs/platform/configuration/common/configurationRegistry'; -import { createHash } from 'crypto'; -import { getWorkspaceLabel, IWorkspacesService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { CustomConfigurationModel, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; +import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, WorkspaceSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels'; +import { WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; +import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { IStoredWorkspace, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import * as extfs from 'vs/base/node/extfs'; +import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; + +// node.hs helper functions interface IStat { resource: URI; @@ -46,602 +36,108 @@ interface IContent { value: string; } -interface IWorkspaceConfiguration { - workspace: T; - consolidated: any; +function resolveContents(resources: URI[]): TPromise { + const contents: IContent[] = []; + + return TPromise.join(resources.map(resource => { + return resolveContent(resource).then(content => { + contents.push(content); + }); + })).then(() => contents); } -type IWorkspaceFoldersConfiguration = { [rootFolder: string]: { folders: string[]; } }; - -const configurationRegistry = Registry.as(Extensions.Configuration); - -// BEGIN VSCode extension point `configuration` -const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configuration', [], { - description: nls.localize('vscode.extension.contributes.configuration', 'Contributes configuration settings.'), - type: 'object', - defaultSnippets: [{ body: { title: '', properties: {} } }], - properties: { - title: { - description: nls.localize('vscode.extension.contributes.configuration.title', 'A summary of the settings. This label will be used in the settings file as separating comment.'), - type: 'string' - }, - properties: { - description: nls.localize('vscode.extension.contributes.configuration.properties', 'Description of the configuration properties.'), - type: 'object', - additionalProperties: { - anyOf: [ - { $ref: 'http://json-schema.org/draft-04/schema#' }, - { - type: 'object', - properties: { - isExecutable: { - type: 'boolean' - }, - scope: { - type: 'string', - enum: ['window', 'resource'], - default: 'window', - enumDescriptions: [ - nls.localize('scope.window.description', "Window specific configuration, which can be configured in the User or Workspace settings."), - nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the User, Workspace or Folder settings.") - ], - description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `window` and `resource`.") - } - } - } - ] - } - } - } -}); -configurationExtPoint.setHandler(extensions => { - const configurations: IConfigurationNode[] = []; - - - for (let i = 0; i < extensions.length; i++) { - const configuration = objects.clone(extensions[i].value); - const collector = extensions[i].collector; - - if (configuration.type && configuration.type !== 'object') { - collector.warn(nls.localize('invalid.type', "if set, 'configuration.type' must be set to 'object")); - } else { - configuration.type = 'object'; - } - - if (configuration.title && (typeof configuration.title !== 'string')) { - collector.error(nls.localize('invalid.title', "'configuration.title' must be a string")); - } - - validateProperties(configuration, collector); - - configuration.id = extensions[i].description.id; - configurations.push(configuration); - } - - configurationRegistry.registerConfigurations(configurations, false); -}); -// END VSCode extension point `configuration` - -// BEGIN VSCode extension point `configurationDefaults` -const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint('configurationDefaults', [], { - description: nls.localize('vscode.extension.contributes.defaultConfiguration', 'Contributes default editor configuration settings by language.'), - type: 'object', - defaultSnippets: [{ body: {} }], - patternProperties: { - '\\[.*\\]$': { - type: 'object', - default: {}, - $ref: editorConfigurationSchemaId, - } - } -}); -defaultConfigurationExtPoint.setHandler(extensions => { - const defaultConfigurations: IDefaultConfigurationExtension[] = extensions.map(extension => { - const id = extension.description.id; - const name = extension.description.name; - const defaults = objects.clone(extension.value); - return { - id, name, defaults - }; - }); - configurationRegistry.registerDefaultConfigurations(defaultConfigurations); -}); -// END VSCode extension point `configurationDefaults` - -function validateProperties(configuration: IConfigurationNode, collector: ExtensionMessageCollector): void { - let properties = configuration.properties; - if (properties) { - if (typeof properties !== 'object') { - collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object")); - configuration.properties = {}; - } - for (let key in properties) { - const message = validateProperty(key); - const propertyConfiguration = configuration.properties[key]; - propertyConfiguration.scope = propertyConfiguration.scope && propertyConfiguration.scope.toString() === 'resource' ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW; - if (message) { - collector.warn(message); - delete properties[key]; - } - } - } - let subNodes = configuration.allOf; - if (subNodes) { - for (let node of subNodes) { - validateProperties(node, collector); - } - } +function resolveContent(resource: URI): TPromise { + return readFile(resource.fsPath).then(contents => ({ resource, value: contents.toString() })); } -export class WorkspaceService extends Disposable implements IWorkspaceConfigurationService, IWorkspaceContextService { - - public _serviceBrand: any; - - protected workspace: Workspace = null; - protected legacyWorkspace: LegacyWorkspace = null; - protected _configuration: Configuration; - - protected readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; - - protected readonly _onDidChangeWorkspaceRoots: Emitter = this._register(new Emitter()); - public readonly onDidChangeWorkspaceRoots: Event = this._onDidChangeWorkspaceRoots.event; - - protected readonly _onDidChangeWorkspaceName: Emitter = this._register(new Emitter()); - public readonly onDidChangeWorkspaceName: Event = this._onDidChangeWorkspaceName.event; - - constructor() { - super(); - this._configuration = new Configuration(new BaseConfiguration(new ConfigurationModel(), new ConfigurationModel()), new ConfigurationModel(), new StrictResourceMap>(), this.workspace); - } - - public getLegacyWorkspace(): ILegacyWorkspace { - return this.legacyWorkspace; - } - - public getWorkspace(): IWorkspace { - return this.workspace; - } - - public hasWorkspace(): boolean { - return !!this.workspace; - } - - public hasFolderWorkspace(): boolean { - return this.workspace && !this.workspace.configuration; - } - - public hasMultiFolderWorkspace(): boolean { - return this.workspace && !!this.workspace.configuration; - } - - public getRoot(resource: URI): URI { - return this.workspace ? this.workspace.getRoot(resource) : null; - } - - private get workspaceUri(): URI { - return this.workspace ? this.workspace.roots[0] : null; - } - - public isInsideWorkspace(resource: URI): boolean { - return !!this.getRoot(resource); - } - - public toResource(workspaceRelativePath: string): URI { - return this.workspace ? this.legacyWorkspace.toResource(workspaceRelativePath) : null; - } - - public initialize(trigger: boolean = true): TPromise { - this.resetCaches(); - return this.updateConfiguration() - .then(() => { - if (trigger) { - this.triggerConfigurationChange(); +function resolveStat(resource: URI): TPromise { + return new TPromise((c, e) => { + extfs.readdir(resource.fsPath, (error, children) => { + if (error) { + if ((error).code === 'ENOTDIR') { + c({ resource }); + } else { + e(error); } - }); - } - - public reloadConfiguration(section?: string): TPromise { - return TPromise.as(this.getConfiguration(section)); - } - - public getConfigurationData(): IConfigurationData { - return this._configuration.toData(); - } - - public getConfiguration(section?: string, overrides?: IConfigurationOverrides): C { - return this._configuration.getValue(section, overrides); - } - - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { - return this._configuration.lookup(key, overrides); - } - - public keys(overrides?: IConfigurationOverrides): IConfigurationKeys { - return this._configuration.keys(overrides); - } - - public values(): IConfigurationValues { - return this._configuration.values(); - } - - public getUnsupportedWorkspaceKeys(): string[] { - return []; - } - - public isInWorkspaceContext(): boolean { - return false; - } - - protected triggerConfigurationChange(): void { - this._onDidUpdateConfiguration.fire({ source: ConfigurationSource.Workspace, sourceConfig: void 0 }); - } - - public handleWorkspaceFileEvents(event: FileChangesEvent): void { - // implemented by sub classes - } - - protected resetCaches(): void { - // implemented by sub classes - } - - protected updateConfiguration(): TPromise { - // implemented by sub classes - return TPromise.as(false); - } -} - -export class EmptyWorkspaceServiceImpl extends WorkspaceService { - - private baseConfigurationService: GlobalConfigurationService; - - constructor(environmentService: IEnvironmentService) { - super(); - this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService)); - this._register(this.baseConfigurationService.onDidUpdateConfiguration(e => this.onBaseConfigurationChanged(e))); - this.resetCaches(); - } - - public reloadConfiguration(section?: string): TPromise { - const current = this._configuration; - return this.baseConfigurationService.reloadConfiguration() - .then(() => this.initialize(false)) // Reinitialize to ensure we are hitting the disk - .then(() => { - // Check and trigger - if (!this._configuration.equals(current)) { - this.triggerConfigurationChange(); - } - return super.reloadConfiguration(section); - }); - } - - private onBaseConfigurationChanged({ source, sourceConfig }: IConfigurationServiceEvent): void { - if (this._configuration.updateBaseConfiguration(this.baseConfigurationService.configuration())) { - this._onDidUpdateConfiguration.fire({ source, sourceConfig }); - } - } - - protected resetCaches(): void { - this._configuration = new Configuration(this.baseConfigurationService.configuration(), new ConfigurationModel(), new StrictResourceMap>(), null); - } - - protected triggerConfigurationChange(): void { - this._onDidUpdateConfiguration.fire({ source: ConfigurationSource.User, sourceConfig: this._configuration.user.contents }); - } -} - -export class WorkspaceServiceImpl extends WorkspaceService { - - public _serviceBrand: any; - - private workspaceConfigPath: URI; - private folderPath: URI; - private baseConfigurationService: GlobalConfigurationService; - private workspaceConfiguration: WorkspaceConfiguration; - private cachedFolderConfigs: StrictResourceMap>; - - constructor(private workspaceIdentifier: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier, private environmentService: IEnvironmentService, private workspacesService: IWorkspacesService, private workspaceSettingsRootFolder: string = WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME) { - super(); - - if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier)) { - this.folderPath = URI.file(workspaceIdentifier); - } else { - this.workspaceConfigPath = URI.file(workspaceIdentifier.configPath); - } - - this.workspaceConfiguration = this._register(new WorkspaceConfiguration()); - this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService)); - } - - public getUnsupportedWorkspaceKeys(): string[] { - return this.hasFolderWorkspace() ? this._configuration.getFolderConfigurationModel(this.workspace.roots[0]).workspaceSettingsConfig.unsupportedKeys : []; - } - - public initialize(trigger: boolean = true): TPromise { - if (!this.workspace) { - return this.initializeWorkspace() - .then(() => super.initialize(trigger)); - } - - if (this.hasMultiFolderWorkspace()) { - return this.workspaceConfiguration.load(this.workspaceConfigPath) - .then(() => super.initialize(trigger)); - } - - return super.initialize(trigger); - } - - public reloadConfiguration(section?: string): TPromise { - const current = this._configuration; - return this.baseConfigurationService.reloadConfiguration() - .then(() => this.initialize(false)) // Reinitialize to ensure we are hitting the disk - .then(() => { - // Check and trigger - if (!this._configuration.equals(current)) { - this.triggerConfigurationChange(); - } - return super.reloadConfiguration(section); - }); - } - - public handleWorkspaceFileEvents(event: FileChangesEvent): void { - TPromise.join(this.workspace.roots.map(folder => this.cachedFolderConfigs.get(folder).handleWorkspaceFileEvents(event))) // handle file event for each folder - .then(folderConfigurations => - folderConfigurations.map((configuration, index) => ({ configuration, folder: this.workspace.roots[index] })) - .filter(folderConfiguration => !!folderConfiguration.configuration) // Filter folders which are not impacted by events - .map(folderConfiguration => this.updateFolderConfiguration(folderConfiguration.folder, folderConfiguration.configuration, true)) // Update the configuration of impacted folders - .reduce((result, value) => result || value, false)) // Check if the effective configuration of folder is changed - .then(changed => changed ? this.triggerConfigurationChange() : void 0); // Trigger event if changed - } - - protected resetCaches(): void { - this.cachedFolderConfigs = new StrictResourceMap>(); - this._configuration = new Configuration(this.baseConfigurationService.configuration(), new ConfigurationModel(), new StrictResourceMap>(), this.workspace); - this.initCachesForFolders(this.workspace.roots); - } - - private initializeWorkspace(): TPromise { - return (this.workspaceConfigPath ? this.initializeMulitFolderWorkspace() : this.initializeSingleFolderWorkspace()) - .then(() => { - this._register(this.baseConfigurationService.onDidUpdateConfiguration(e => this.onBaseConfigurationChanged(e))); - }); - } - - // TODO@Sandeep use again once we can change workspace without window reload - // private onWorkspaceChange(configPath: URI): TPromise { - // let workspaceName = this.workspace.name; - // this.workspaceConfigPath = configPath; - - // // Reset the workspace if current workspace is single folder - // if (this.hasFolderWorkspace()) { - // this.folderPath = null; - // this.workspace = null; - // } - - // // Update workspace configuration path with new path - // else { - // this.workspace.configuration = configPath; - // this.workspace.name = getWorkspaceLabel({ id: this.workspace.id, configPath: this.workspace.configuration.fsPath }, this.environmentService); - // } - - // return this.initialize().then(() => { - // if (workspaceName !== this.workspace.name) { - // this._onDidChangeWorkspaceName.fire(); - // } - // }); - // } - - private initializeMulitFolderWorkspace(): TPromise { - this.registerWorkspaceConfigSchema(); - return this.workspaceConfiguration.load(this.workspaceConfigPath) - .then(() => { - const workspaceConfigurationModel = this.workspaceConfiguration.workspaceConfigurationModel; - const workspaceFolders = this.parseWorkspaceFolders(workspaceConfigurationModel.folders); - if (!workspaceFolders.length) { - return TPromise.wrapError(new Error('Invalid workspace configuraton file ' + this.workspaceConfigPath)); - } - const workspaceId = (this.workspaceIdentifier as IWorkspaceIdentifier).id; - const workspaceName = getWorkspaceLabel({ id: workspaceId, configPath: this.workspaceConfigPath.fsPath }, this.environmentService); - this.workspace = new Workspace(workspaceId, workspaceName, workspaceFolders, this.workspaceConfigPath); - this.legacyWorkspace = new LegacyWorkspace(this.workspace.roots[0]); - this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => this.onWorkspaceConfigurationChanged())); - return null; - }); - } - - private parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[]): URI[] { - return coalesce(configuredFolders.map(configuredFolder => { - const path = configuredFolder.path; - if (!path) { - return void 0; - } - - if (paths.isAbsolute(path)) { - return URI.file(path); - } - - return URI.file(paths.join(paths.dirname(this.workspaceConfigPath.fsPath), path)); - })); - } - - private registerWorkspaceConfigSchema(): void { - const contributionRegistry = Registry.as(JSONExtensions.JSONContribution); - if (!contributionRegistry.getSchemaContributions().schemas['vscode://schemas/workspaceConfig']) { - contributionRegistry.registerSchema('vscode://schemas/workspaceConfig', { - default: { - folders: [ - { - path: '' - } - ], - settings: { - } - }, - required: ['folders'], - properties: { - 'folders': { - minItems: 1, - uniqueItems: true, - description: nls.localize('workspaceConfig.folders.description', "List of folders to be loaded in the workspace. Must be a file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file."), - items: { - type: 'object', - default: { path: '' }, - properties: { - path: { - type: 'string', - description: nls.localize('workspaceConfig.folder.description', "A file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file.") - } - } - } - }, - 'settings': { - type: 'object', - default: {}, - description: nls.localize('workspaceConfig.settings.description', "Workspace settings"), - $ref: schemaId - } - } - }); - } - } - - private initializeSingleFolderWorkspace(): TPromise { - return stat(this.folderPath.fsPath) - .then(workspaceStat => { - const ctime = isLinux ? workspaceStat.ino : workspaceStat.birthtime.getTime(); // On Linux, birthtime is ctime, so we cannot use it! We use the ino instead! - const id = createHash('md5').update(this.folderPath.fsPath).update(ctime ? String(ctime) : '').digest('hex'); - const folder = URI.file(this.folderPath.fsPath); - this.workspace = new Workspace(id, paths.basename(this.folderPath.fsPath), [folder], null); - this.legacyWorkspace = new LegacyWorkspace(folder, ctime); - return TPromise.as(null); - }); - } - - private initCachesForFolders(folders: URI[]): void { - for (const folder of folders) { - this.cachedFolderConfigs.set(folder, this._register(new FolderConfiguration(folder, this.workspaceSettingsRootFolder, this.hasMultiFolderWorkspace() ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW))); - this.updateFolderConfiguration(folder, new FolderConfigurationModel(new FolderSettingsModel(null), [], ConfigurationScope.RESOURCE), false); - } - } - - protected updateConfiguration(folders: URI[] = this.workspace.roots): TPromise { - return TPromise.join([...folders.map(folder => this.cachedFolderConfigs.get(folder).loadConfiguration() - .then(configuration => this.updateFolderConfiguration(folder, configuration, true)))]) - .then(changed => changed.reduce((result, value) => result || value, false)) - .then(changed => this.updateWorkspaceConfiguration(true) || changed); - } - - private onBaseConfigurationChanged({ source, sourceConfig }: IConfigurationServiceEvent): void { - if (source === ConfigurationSource.Default) { - this.workspace.roots.forEach(folder => this._configuration.getFolderConfigurationModel(folder).update()); - } - if (this._configuration.updateBaseConfiguration(this.baseConfigurationService.configuration())) { - this._onDidUpdateConfiguration.fire({ source, sourceConfig }); - } - } - - private onWorkspaceConfigurationChanged(): void { - let configuredFolders = this.parseWorkspaceFolders(this.workspaceConfiguration.workspaceConfigurationModel.folders); - const foldersChanged = !equals(this.workspace.roots, configuredFolders, (r1, r2) => r1.fsPath === r2.fsPath); - if (foldersChanged) { // TODO@Sandeep be smarter here about detecting changes - this.workspace.roots = configuredFolders; - this.onFoldersChanged() - .then(configurationChanged => { - this._onDidChangeWorkspaceRoots.fire(); - if (configurationChanged) { - this.triggerConfigurationChange(); - } + } else { + c({ + resource, + isDirectory: true, + children: children.map(child => { return { resource: URI.file(paths.join(resource.fsPath, child)) }; }) }); - } else { - const configurationChanged = this.updateWorkspaceConfiguration(true); - if (configurationChanged) { - this.triggerConfigurationChange(); } - } - } - - private onFoldersChanged(): TPromise { - let configurationChangedOnRemoval = false; - - // Remove the configurations of deleted folders - for (const key of this.cachedFolderConfigs.keys()) { - if (!this.workspace.roots.filter(folder => folder.toString() === key.toString())[0]) { - this.cachedFolderConfigs.delete(key); - if (this._configuration.deleteFolderConfiguration(key)) { - configurationChangedOnRemoval = true; - } - } - } - - // Initialize the newly added folders - const toInitialize = this.workspace.roots.filter(folder => !this.cachedFolderConfigs.has(folder)); - if (toInitialize.length) { - this.initCachesForFolders(toInitialize); - return this.updateConfiguration(toInitialize) - .then(changed => configurationChangedOnRemoval || changed); - } else if (configurationChangedOnRemoval) { - this.updateWorkspaceConfiguration(false); - return TPromise.as(true); - } - return TPromise.as(false); - } - - private updateFolderConfiguration(folder: URI, folderConfiguration: FolderConfigurationModel, compare: boolean): boolean { - let configurationChanged = this._configuration.updateFolderConfiguration(folder, folderConfiguration, compare); - if (this.hasFolderWorkspace()) { - // Workspace configuration changed - configurationChanged = this.updateWorkspaceConfiguration(compare) || configurationChanged; - } - return configurationChanged; - } - - private updateWorkspaceConfiguration(compare: boolean): boolean { - const workspaceConfiguration = this.hasMultiFolderWorkspace() ? this.workspaceConfiguration.workspaceConfigurationModel.workspaceConfiguration : this._configuration.getFolderConfigurationModel(this.workspace.roots[0]); - return this._configuration.updateWorkspaceConfiguration(workspaceConfiguration, compare); - } - - protected triggerConfigurationChange(): void { - this._onDidUpdateConfiguration.fire({ source: ConfigurationSource.Workspace, sourceConfig: this._configuration.getFolderConfigurationModel(this.workspace.roots[0]).contents }); - } + }); + }); } -class WorkspaceConfiguration extends Disposable { +export class WorkspaceConfiguration extends Disposable { private _workspaceConfigPath: URI; - private _workspaceConfigurationWatcher: ConfigWatcher>; + private _workspaceConfigurationWatcher: ConfigWatcher; private _workspaceConfigurationWatcherDisposables: IDisposable[] = []; private _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; - load(workspaceConfigPath: URI): TPromise { if (this._workspaceConfigPath && this._workspaceConfigPath.fsPath === workspaceConfigPath.fsPath) { - return this._reload(); + return this.reload(); } this._workspaceConfigPath = workspaceConfigPath; - this._workspaceConfigurationWatcherDisposables = dispose(this._workspaceConfigurationWatcherDisposables); + this.stopListeningToWatcher(); return new TPromise((c, e) => { this._workspaceConfigurationWatcher = new ConfigWatcher(this._workspaceConfigPath.fsPath, { - changeBufferDelay: 300, onError: error => errors.onUnexpectedError(error), defaultConfig: new WorkspaceConfigurationModel(null, this._workspaceConfigPath.fsPath), parse: (content: string, parseErrors: any[]) => { + changeBufferDelay: 300, + onError: error => errors.onUnexpectedError(error), + defaultConfig: new WorkspaceConfigurationModel(JSON.stringify({ folders: [] } as IStoredWorkspace, null, '\t'), this._workspaceConfigPath.fsPath), + parse: (content: string, parseErrors: any[]) => { const workspaceConfigurationModel = new WorkspaceConfigurationModel(content, this._workspaceConfigPath.fsPath); parseErrors = [...workspaceConfigurationModel.errors]; return workspaceConfigurationModel; }, initCallback: () => c(null) }); - this._workspaceConfigurationWatcherDisposables.push(toDisposable(() => this._workspaceConfigurationWatcher.dispose())); - this._workspaceConfigurationWatcher.onDidUpdateConfiguration(() => this._onDidUpdateConfiguration.fire(), this, this._workspaceConfigurationWatcherDisposables); + this.listenToWatcher(); }); } - get workspaceConfigurationModel(): WorkspaceConfigurationModel { + private get workspaceConfigurationModel(): WorkspaceConfigurationModel { return this._workspaceConfigurationWatcher ? this._workspaceConfigurationWatcher.getConfig() : new WorkspaceConfigurationModel(); } - private _reload(): TPromise { - return new TPromise(c => this._workspaceConfigurationWatcher.reload(() => c(null))); + reload(): TPromise { + this.stopListeningToWatcher(); + return new TPromise(c => this._workspaceConfigurationWatcher.reload(() => { + this.listenToWatcher(); + c(null); + })); + } + + getFolders(): IStoredWorkspaceFolder[] { + return this.workspaceConfigurationModel.folders; + } + + setFolders(folders: IStoredWorkspaceFolder[], jsonEditingService: JSONEditingService): TPromise { + return jsonEditingService.write(this._workspaceConfigPath, { key: 'folders', value: folders }, true) + .then(() => this.reload()); + } + + getConfiguration(): ConfigurationModel { + return this.workspaceConfigurationModel.workspaceConfiguration; + } + + getWorkspaceSettings(): WorkspaceSettingsModel { + return this.workspaceConfigurationModel.workspaceSettingsModel; + } + + private listenToWatcher() { + this._workspaceConfigurationWatcherDisposables.push(this._workspaceConfigurationWatcher); + this._workspaceConfigurationWatcher.onDidUpdateConfiguration(() => this._onDidUpdateConfiguration.fire(), this, this._workspaceConfigurationWatcherDisposables); + } + + private stopListeningToWatcher() { + this._workspaceConfigurationWatcherDisposables = dispose(this._workspaceConfigurationWatcherDisposables); } dispose(): void { @@ -650,15 +146,15 @@ class WorkspaceConfiguration extends Disposable { } } -class FolderConfiguration extends Disposable { +export class FolderConfiguration extends Disposable { private static RELOAD_CONFIGURATION_DELAY = 50; - private bulkFetchFromWorkspacePromise: TPromise; - private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise> }; + private bulkFetchFromWorkspacePromise: TPromise; + private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise }; private reloadConfigurationScheduler: RunOnceScheduler; - private reloadConfigurationEventEmitter: Emitter> = new Emitter>(); + private reloadConfigurationEventEmitter: Emitter = new Emitter(); constructor(private folder: URI, private configFolderRelativePath: string, private scope: ConfigurationScope) { super(); @@ -667,17 +163,17 @@ class FolderConfiguration extends Disposable { this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.loadConfiguration().then(configuration => this.reloadConfigurationEventEmitter.fire(configuration), errors.onUnexpectedError), FolderConfiguration.RELOAD_CONFIGURATION_DELAY)); } - loadConfiguration(): TPromise> { + loadConfiguration(): TPromise { // Load workspace locals return this.loadWorkspaceConfigFiles().then(workspaceConfigFiles => { // Consolidate (support *.json files in the workspace settings folder) - const workspaceSettingsConfig = >workspaceConfigFiles[WORKSPACE_CONFIG_DEFAULT_PATH] || new FolderSettingsModel(null); - const otherConfigModels = Object.keys(workspaceConfigFiles).filter(key => key !== WORKSPACE_CONFIG_DEFAULT_PATH).map(key => >workspaceConfigFiles[key]); - return new FolderConfigurationModel(workspaceSettingsConfig, otherConfigModels, this.scope); + const workspaceSettingsConfig = workspaceConfigFiles[WORKSPACE_CONFIG_DEFAULT_PATH] || new FolderSettingsModel(null); + const otherConfigModels = Object.keys(workspaceConfigFiles).filter(key => key !== WORKSPACE_CONFIG_DEFAULT_PATH).map(key => workspaceConfigFiles[key]); + return new FolderConfigurationModel(workspaceSettingsConfig, otherConfigModels, this.scope); }); } - private loadWorkspaceConfigFiles(): TPromise<{ [relativeWorkspacePath: string]: ConfigurationModel }> { + private loadWorkspaceConfigFiles(): TPromise<{ [relativeWorkspacePath: string]: ConfigurationModel }> { // once: when invoked for the first time we fetch json files that contribute settings if (!this.bulkFetchFromWorkspacePromise) { this.bulkFetchFromWorkspacePromise = resolveStat(this.toResource(this.configFolderRelativePath)).then(stat => { @@ -704,7 +200,7 @@ class FolderConfiguration extends Disposable { return this.bulkFetchFromWorkspacePromise.then(() => TPromise.join(this.workspaceFilePathToConfiguration)); } - public handleWorkspaceFileEvents(event: FileChangesEvent): TPromise> { + public handleWorkspaceFileEvents(event: FileChangesEvent): TPromise { const events = event.changes; let affectedByChanges = false; @@ -762,22 +258,22 @@ class FolderConfiguration extends Disposable { }); } - private createConfigModel(content: IContent): ConfigurationModel { + private createConfigModel(content: IContent): ConfigurationModel { const path = this.toFolderRelativePath(content.resource); if (path === WORKSPACE_CONFIG_DEFAULT_PATH) { - return new FolderSettingsModel(content.value, content.resource.toString()); + return new FolderSettingsModel(content.value, content.resource.toString()); } else { const matches = /\/([^\.]*)*\.json/.exec(path); if (matches && matches[1]) { - return new ScopedConfigurationModel(content.value, content.resource.toString(), matches[1]); + return new ScopedConfigurationModel(content.value, content.resource.toString(), matches[1]); } } - return new CustomConfigurationModel(null); + return new CustomConfigurationModel(null); } private isWorkspaceConfigurationFile(folderRelativePath: string): boolean { - return [WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS.launch, WORKSPACE_STANDALONE_CONFIGURATIONS.tasks].some(p => p === folderRelativePath); + return [WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY], WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY]].some(p => p === folderRelativePath); } private toResource(folderRelativePath: string): URI { @@ -803,114 +299,4 @@ class FolderConfiguration extends Disposable { return false; } -} - -// node.hs helper functions - -function resolveContents(resources: URI[]): TPromise { - const contents: IContent[] = []; - - return TPromise.join(resources.map(resource => { - return resolveContent(resource).then(content => { - contents.push(content); - }); - })).then(() => contents); -} - -function resolveContent(resource: URI): TPromise { - return readFile(resource.fsPath).then(contents => ({ resource, value: contents.toString() })); -} - -function resolveStat(resource: URI): TPromise { - return new TPromise((c, e) => { - extfs.readdir(resource.fsPath, (error, children) => { - if (error) { - if ((error).code === 'ENOTDIR') { - c({ resource }); - } else { - e(error); - } - } else { - c({ - resource, - isDirectory: true, - children: children.map(child => { return { resource: URI.file(paths.join(resource.fsPath, child)) }; }) - }); - } - }); - }); -} - -export class Configuration extends BaseConfiguration { - - constructor(private _baseConfiguration: BaseConfiguration, workspaceConfiguration: ConfigurationModel, protected folders: StrictResourceMap>, workspace: Workspace) { - super(_baseConfiguration.defaults, _baseConfiguration.user, workspaceConfiguration, folders, workspace); - } - - updateBaseConfiguration(baseConfiguration: BaseConfiguration): boolean { - const current = new Configuration(this._baseConfiguration, this._workspaceConfiguration, this.folders, this._workspace); - - this._baseConfiguration = baseConfiguration; - this._defaults = this._baseConfiguration.defaults; - this._user = this._baseConfiguration.user; - this.merge(); - - return !this.equals(current); - } - - updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel, compare: boolean = true): boolean { - const current = new Configuration(this._baseConfiguration, this._workspaceConfiguration, this.folders, this._workspace); - - this._workspaceConfiguration = workspaceConfiguration; - this.merge(); - - return compare && !this.equals(current); - } - - updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel, compare: boolean): boolean { - const current = this.getValue(null, { resource }); - - this.folders.set(resource, configuration); - this.mergeFolder(resource); - - return compare && !objects.equals(current, this.getValue(null, { resource })); - } - - deleteFolderConfiguration(folder: URI): boolean { - if (this._workspace && this._workspace.roots.length > 0 && this._workspace.roots[0].fsPath === folder.fsPath) { - // Do not remove workspace configuration - return false; - } - - const changed = this.folders.get(folder).keys.length > 0; - this.folders.delete(folder); - this._foldersConsolidatedConfigurations.delete(folder); - return changed; - } - - getFolderConfigurationModel(folder: URI): FolderConfigurationModel { - return >this.folders.get(folder); - } - - equals(other: any): boolean { - if (!other || !(other instanceof Configuration)) { - return false; - } - - if (!objects.equals(this.getValue(), other.getValue())) { - return false; - } - - if (this._foldersConsolidatedConfigurations.size !== other._foldersConsolidatedConfigurations.size) { - return false; - } - - for (const resource of this._foldersConsolidatedConfigurations.keys()) { - if (!objects.equals(this.getValue(null, { resource }), other.getValue(null, { resource }))) { - return false; - } - } - - return true; - } -} +} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index e4568ab9394..1deacb7b526 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -7,7 +7,6 @@ import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; -import * as paths from 'vs/base/common/paths'; import URI from 'vs/base/common/uri'; import * as json from 'vs/base/common/json'; import * as encoding from 'vs/base/node/encoding'; @@ -21,35 +20,100 @@ import { EditOperation } from 'vs/editor/common/core/editOperation'; import { Registry } from 'vs/platform/registry/common/platform'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IConfigurationService, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; -import { keyFromOverrideIdentifier } from 'vs/platform/configuration/common/model'; -import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; +import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; -import { IConfigurationEditingService, ConfigurationEditingErrorCode, ConfigurationEditingError, ConfigurationTarget, IConfigurationValue, IConfigurationEditingOptions } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { OVERRIDE_PROPERTY_PATTERN, IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IChoiceService, IMessageService, Severity } from 'vs/platform/message/common/message'; import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -interface IConfigurationEditOperation extends IConfigurationValue { - jsonPath: json.JSONPath; - resource: URI; - isWorkspaceStandalone?: boolean; +export enum ConfigurationEditingErrorCode { + + /** + * Error when trying to write a configuration key that is not registered. + */ + ERROR_UNKNOWN_KEY, + + /** + * Error when trying to write an invalid folder configuration key to folder settings. + */ + ERROR_INVALID_FOLDER_CONFIGURATION, + + /** + * Error when trying to write to user target but not supported for provided key. + */ + ERROR_INVALID_USER_TARGET, + + /** + * Error when trying to write to user target but not supported for provided key. + */ + ERROR_INVALID_WORKSPACE_TARGET, + + /** + * Error when trying to write a configuration key to folder target + */ + ERROR_INVALID_FOLDER_TARGET, + + /** + * Error when trying to write to the workspace configuration without having a workspace opened. + */ + ERROR_NO_WORKSPACE_OPENED, + + /** + * Error when trying to write and save to the configuration file while it is dirty in the editor. + */ + ERROR_CONFIGURATION_FILE_DIRTY, + + /** + * Error when trying to write to a configuration file that contains JSON errors. + */ + ERROR_INVALID_CONFIGURATION } -interface IValidationResult { - error?: ConfigurationEditingErrorCode; - exists?: boolean; +export class ConfigurationEditingError extends Error { + constructor(message: string, public code: ConfigurationEditingErrorCode) { + super(message); + } +} + +export interface IConfigurationValue { + key: string; + value: any; +} + +export interface IConfigurationEditingOptions { + /** + * If `true`, do not saves the configuration. Default is `false`. + */ + donotSave?: boolean; + /** + * If `true`, do not notifies the error to user by showing the message box. Default is `false`. + */ + donotNotifyError?: boolean; + /** + * Scope of configuration to be written into. + */ + scopes?: IConfigurationOverrides; +} + +interface IConfigurationEditOperation extends IConfigurationValue { + target: ConfigurationTarget; + jsonPath: json.JSONPath; + resource: URI; + workspaceStandAloneConfigurationKey?: string; + } interface ConfigurationEditingOptions extends IConfigurationEditingOptions { force?: boolean; } -export class ConfigurationEditingService implements IConfigurationEditingService { +export class ConfigurationEditingService { public _serviceBrand: any; @@ -64,28 +128,28 @@ export class ConfigurationEditingService implements IConfigurationEditingService @ITextFileService private textFileService: ITextFileService, @IChoiceService private choiceService: IChoiceService, @IMessageService private messageService: IMessageService, - @ICommandService private commandService: ICommandService + @ICommandService private commandService: ICommandService, + @IWorkbenchEditorService private editorService: IWorkbenchEditorService ) { this.queue = new Queue(); } writeConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options: IConfigurationEditingOptions = {}): TPromise { - return this.queue.queue(() => this.doWriteConfiguration(target, value, options) // queue up writes to prevent race conditions + const operation = this.getConfigurationEditOperation(target, value, options.scopes || {}); + return this.queue.queue(() => this.doWriteConfiguration(operation, options) // queue up writes to prevent race conditions .then(() => null, error => { if (!options.donotNotifyError) { - this.onError(error, target, value, options.scopes); + this.onError(error, operation, options.scopes); } return TPromise.wrapError(error); })); } - private doWriteConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options: ConfigurationEditingOptions): TPromise { - const operation = this.getConfigurationEditOperation(target, value, options.scopes || {}); - + private doWriteConfiguration(operation: IConfigurationEditOperation, options: ConfigurationEditingOptions): TPromise { const checkDirtyConfiguration = !(options.force || options.donotSave); const saveConfiguration = options.force || !options.donotSave; - return this.resolveAndValidate(target, operation, checkDirtyConfiguration, options.scopes || {}) + return this.resolveAndValidate(operation.target, operation, checkDirtyConfiguration, options.scopes || {}) .then(reference => this.writeToBuffer(reference.object.textEditorModel, operation, saveConfiguration) .then(() => reference.dispose())); } @@ -93,9 +157,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService private writeToBuffer(model: editorCommon.IModel, operation: IConfigurationEditOperation, save: boolean): TPromise { const edit = this.getEdits(model, operation)[0]; if (this.applyEditsToBuffer(edit, model) && save) { - return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }) - // Reload the configuration so that we make sure all parties are updated - .then(() => this.configurationService.reloadConfiguration()); + return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ }); } return TPromise.as(null); } @@ -113,45 +175,97 @@ export class ConfigurationEditingService implements IConfigurationEditingService return false; } - private onError(error: ConfigurationEditingError, target: ConfigurationTarget, value: IConfigurationValue, scopes: IConfigurationOverrides): void { + private onError(error: ConfigurationEditingError, operation: IConfigurationEditOperation, scopes: IConfigurationOverrides): void { switch (error.code) { case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: - this.onInvalidConfigurationError(error, target); + this.onInvalidConfigurationError(error, operation); break; case ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY: - this.onConfigurationFileDirtyError(error, target, value, scopes); + this.onConfigurationFileDirtyError(error, operation, scopes); break; default: this.messageService.show(Severity.Error, error.message); } } - private onInvalidConfigurationError(error: ConfigurationEditingError, target: ConfigurationTarget): void { - this.choiceService.choose(Severity.Error, error.message, [nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 1) - .then(option => { - switch (option) { - case 0: - this.openSettings(target); - } - }); + private onInvalidConfigurationError(error: ConfigurationEditingError, operation: IConfigurationEditOperation, ): void { + const openStandAloneConfigurationActionLabel = operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY ? nls.localize('openTasksConfiguration', "Open Tasks Configuration") + : operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY ? nls.localize('openLaunchConfiguration', "Open Launch Configuration") + : null; + if (openStandAloneConfigurationActionLabel) { + this.choiceService.choose(Severity.Error, error.message, [openStandAloneConfigurationActionLabel, nls.localize('close', "Close")], 1) + .then(option => { + switch (option) { + case 0: + this.openFile(operation.resource); + break; + } + }); + } else { + this.choiceService.choose(Severity.Error, error.message, [nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 1) + .then(option => { + switch (option) { + case 0: + this.openSettings(operation); + break; + } + }); + } } - private onConfigurationFileDirtyError(error: ConfigurationEditingError, target: ConfigurationTarget, value: IConfigurationValue, scopes: IConfigurationOverrides): void { - this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save Settings and Retry"), nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 2) - .then(option => { - switch (option) { - case 0: - this.writeConfiguration(target, value, { force: true, scopes }); - break; - case 1: - this.openSettings(target); - break; - } - }); + private onConfigurationFileDirtyError(error: ConfigurationEditingError, operation: IConfigurationEditOperation, scopes: IConfigurationOverrides): void { + const openStandAloneConfigurationActionLabel = operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY ? nls.localize('openTasksConfiguration', "Open Tasks Configuration") + : operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY ? nls.localize('openLaunchConfiguration', "Open Launch Configuration") + : null; + if (openStandAloneConfigurationActionLabel) { + this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), openStandAloneConfigurationActionLabel, nls.localize('close', "Close")], 2) + .then(option => { + switch (option) { + case 0: + const key = operation.key ? `${operation.workspaceStandAloneConfigurationKey}.${operation.key}` : operation.workspaceStandAloneConfigurationKey; + this.writeConfiguration(operation.target, { key, value: operation.value }, { force: true, scopes }); + break; + case 1: + this.openFile(operation.resource); + break; + } + }); + } else { + this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 2) + .then(option => { + switch (option) { + case 0: + this.writeConfiguration(operation.target, { key: operation.key, value: operation.value }, { force: true, scopes }); + break; + case 1: + this.openSettings(operation); + break; + } + }); + } } - private openSettings(target: ConfigurationTarget): void { - this.commandService.executeCommand(ConfigurationTarget.USER === target ? 'workbench.action.openGlobalSettings' : 'workbench.action.openWorkspaceSettings'); + private openSettings(operation: IConfigurationEditOperation): void { + switch (operation.target) { + case ConfigurationTarget.USER: + this.commandService.executeCommand('workbench.action.openGlobalSettings'); + break; + case ConfigurationTarget.WORKSPACE: + this.commandService.executeCommand('workbench.action.openWorkspaceSettings'); + break; + case ConfigurationTarget.WORKSPACE_FOLDER: + if (operation.resource) { + const workspaceFolder = this.contextService.getWorkspaceFolder(operation.resource); + if (workspaceFolder) { + this.commandService.executeCommand('_workbench.action.openFolderSettings', workspaceFolder); + } + } + break; + } + } + + private openFile(resource: URI): void { + this.editorService.openEditor({ resource }); } private wrapError(code: ConfigurationEditingErrorCode, target: ConfigurationTarget, operation: IConfigurationEditOperation): TPromise { @@ -167,24 +281,47 @@ export class ConfigurationEditingService implements IConfigurationEditingService case ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY: return nls.localize('errorUnknownKey', "Unable to write to {0} because {1} is not a registered configuration.", this.stringifyTarget(target), operation.key); case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION: return nls.localize('errorInvalidFolderConfiguration', "Unable to write to Folder Settings because {0} does not support the folder resource scope.", operation.key); case ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET: return nls.localize('errorInvalidUserTarget', "Unable to write to User Settings because {0} does not support for global scope.", operation.key); + case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET: return nls.localize('errorInvalidWorkspaceTarget', "Unable to write to Workspace Settings because {0} does not support for workspace scope in a multi folder workspace.", operation.key); case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET: return nls.localize('errorInvalidFolderTarget', "Unable to write to Folder Settings because no resource is provided."); case ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED: return nls.localize('errorNoWorkspaceOpened', "Unable to write to {0} because no workspace is opened. Please open a workspace first and try again.", this.stringifyTarget(target)); // User issues case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: { - if (target === ConfigurationTarget.USER) { - return nls.localize('errorInvalidConfiguration', "Unable to write into settings. Please open **User Settings** to correct errors/warnings in the file and try again."); + if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) { + return nls.localize('errorInvalidTaskConfiguration', "Unable to write into tasks file. Please open **Tasks** file to correct errors/warnings in it and try again."); } - - return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into settings. Please open **Workspace Settings** to correct errors/warnings in the file and try again."); - }; + if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) { + return nls.localize('errorInvalidLaunchConfiguration', "Unable to write into launch file. Please open **Launch** file to correct errors/warnings in it and try again."); + } + switch (target) { + case ConfigurationTarget.USER: + return nls.localize('errorInvalidConfiguration', "Unable to write into user settings. Please open **User Settings** file to correct errors/warnings in it and try again."); + case ConfigurationTarget.WORKSPACE: + return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open **Workspace Settings** file to correct errors/warnings in the file and try again."); + case ConfigurationTarget.WORKSPACE_FOLDER: + const workspaceFolderName = this.contextService.getWorkspaceFolder(operation.resource).name; + return nls.localize('errorInvalidConfigurationFolder', "Unable to write into folder settings. Please open **Folder Settings** file under **{0}** folder to correct errors/warnings in it and try again.", workspaceFolderName); + } + return ''; + } case ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY: { - if (target === ConfigurationTarget.USER) { - return nls.localize('errorConfigurationFileDirty', "Unable to write into settings because the file is dirty. Please save the **User Settings** file and try again."); + if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) { + return nls.localize('errorTasksConfigurationFileDirty', "Unable to write into tasks file because the file is dirty. Please save the **Tasks Configuration** file and try again."); } - - return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into settings because the file is dirty. Please save the **Workspace Settings** file and try again."); - }; + if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) { + return nls.localize('errorLaunchConfigurationFileDirty', "Unable to write into launch file because the file is dirty. Please save the **Launch Configuration** file and try again."); + } + switch (target) { + case ConfigurationTarget.USER: + return nls.localize('errorConfigurationFileDirty', "Unable to write into user settings because the file is dirty. Please save the **User Settings** file and try again."); + case ConfigurationTarget.WORKSPACE: + return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file is dirty. Please save the **Workspace Settings** file and try again."); + case ConfigurationTarget.WORKSPACE_FOLDER: + const workspaceFolderName = this.contextService.getWorkspaceFolder(operation.resource).name; + return nls.localize('errorConfigurationFileDirtyFolder', "Unable to write into folder settings because the file is dirty. Please save the **Folder Settings** file under **{0}** folder and try again.", workspaceFolderName); + } + return ''; + } } } @@ -194,9 +331,10 @@ export class ConfigurationEditingService implements IConfigurationEditingService return nls.localize('userTarget', "User Settings"); case ConfigurationTarget.WORKSPACE: return nls.localize('workspaceTarget', "Workspace Settings"); - case ConfigurationTarget.FOLDER: + case ConfigurationTarget.WORKSPACE_FOLDER: return nls.localize('folderTarget', "Folder Settings"); } + return ''; } private getEdits(model: editorCommon.IModel, edit: IConfigurationEditOperation): Edit[] { @@ -228,7 +366,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService private hasParseErrors(model: editorCommon.IModel, operation: IConfigurationEditOperation): boolean { // If we write to a workspace standalone file and replace the entire contents (no key provided) // we can return here because any parse errors can safely be ignored since all contents are replaced - if (operation.isWorkspaceStandalone && !operation.key) { + if (operation.workspaceStandAloneConfigurationKey && !operation.key) { return false; } const parseErrors: json.ParseError[] = []; @@ -239,31 +377,40 @@ export class ConfigurationEditingService implements IConfigurationEditingService private resolveAndValidate(target: ConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean, overrides: IConfigurationOverrides): TPromise> { // Any key must be a known setting from the registry (unless this is a standalone config) - if (!operation.isWorkspaceStandalone) { + if (!operation.workspaceStandAloneConfigurationKey) { const validKeys = this.configurationService.keys().default; if (validKeys.indexOf(operation.key) < 0 && !OVERRIDE_PROPERTY_PATTERN.test(operation.key)) { return this.wrapError(ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY, target, operation); } } - // Target cannot be user if is standalone - if (operation.isWorkspaceStandalone && target === ConfigurationTarget.USER) { - return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation); + if (operation.workspaceStandAloneConfigurationKey) { + // Global tasks and launches are not supported + if (target === ConfigurationTarget.USER) { + return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation); + } + + // Workspace tasks and launches are not supported + if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === ConfigurationTarget.WORKSPACE) { + return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET, target, operation); + } } // Target cannot be workspace or folder if no workspace opened - if ((target === ConfigurationTarget.WORKSPACE || target === ConfigurationTarget.FOLDER) && !this.contextService.hasWorkspace()) { + if ((target === ConfigurationTarget.WORKSPACE || target === ConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { return this.wrapError(ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED, target, operation); } - if (target === ConfigurationTarget.FOLDER) { + if (target === ConfigurationTarget.WORKSPACE_FOLDER) { if (!operation.resource) { return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation); } - const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); - if (configurationProperties[operation.key].scope !== ConfigurationScope.RESOURCE) { - return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION, target, operation); + if (!operation.workspaceStandAloneConfigurationKey) { + const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); + if (configurationProperties[operation.key].scope !== ConfigurationScope.RESOURCE) { + return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION, target, operation); + } } } @@ -296,15 +443,15 @@ export class ConfigurationEditingService implements IConfigurationEditingService // Check for prefix if (config.key === key) { - const jsonPath = workspace && workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath ? [key] : []; - return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource, isWorkspaceStandalone: true }; + const jsonPath = workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath ? [key] : []; + return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource, workspaceStandAloneConfigurationKey: key, target }; } // Check for prefix. const keyPrefix = `${key}.`; if (config.key.indexOf(keyPrefix) === 0) { - const jsonPath = workspace && workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath ? [key, config.key.substr(keyPrefix.length)] : [config.key.substr(keyPrefix.length)]; - return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource, isWorkspaceStandalone: true }; + const jsonPath = workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath ? [key, config.key.substr(keyPrefix.length)] : [config.key.substr(keyPrefix.length)]; + return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource, workspaceStandAloneConfigurationKey: key, target }; } } } @@ -312,14 +459,14 @@ export class ConfigurationEditingService implements IConfigurationEditingService let key = config.key; let jsonPath = overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier), key] : [key]; if (target === ConfigurationTarget.USER) { - return { key, jsonPath, value: config.value, resource: URI.file(this.environmentService.appSettingsPath) }; + return { key, jsonPath, value: config.value, resource: URI.file(this.environmentService.appSettingsPath), target }; } const resource = this.getConfigurationFileResource(target, WORKSPACE_CONFIG_DEFAULT_PATH, overrides.resource); - if (workspace && workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath) { + if (workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath) { jsonPath = ['settings', ...jsonPath]; } - return { key, jsonPath, value: config.value, resource }; + return { key, jsonPath, value: config.value, resource, target }; } private getConfigurationFileResource(target: ConfigurationTarget, relativePath: string, resource: URI): URI { @@ -327,27 +474,29 @@ export class ConfigurationEditingService implements IConfigurationEditingService return URI.file(this.environmentService.appSettingsPath); } - const workspace = this.contextService.getWorkspace(); + const workbenchState = this.contextService.getWorkbenchState(); + if (workbenchState !== WorkbenchState.EMPTY) { - if (workspace) { + const workspace = this.contextService.getWorkspace(); if (target === ConfigurationTarget.WORKSPACE) { - return this.contextService.hasMultiFolderWorkspace() ? workspace.configuration : this.toResource(relativePath, workspace.roots[0]); + if (workbenchState === WorkbenchState.WORKSPACE) { + return workspace.configuration; + } + if (workbenchState === WorkbenchState.FOLDER) { + return workspace.folders[0].toResource(relativePath); + } } - if (target === ConfigurationTarget.FOLDER && this.contextService.hasMultiFolderWorkspace()) { + if (target === ConfigurationTarget.WORKSPACE_FOLDER) { if (resource) { - const root = this.contextService.getRoot(resource); - if (root) { - return this.toResource(relativePath, root); + const folder = this.contextService.getWorkspaceFolder(resource); + if (folder) { + return folder.toResource(relativePath); } } } } return null; } - - private toResource(relativePath: string, root: URI): URI { - return URI.file(paths.join(root.fsPath, relativePath)); - } } diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts new file mode 100644 index 00000000000..11cd1329ab5 --- /dev/null +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -0,0 +1,753 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; +import * as paths from 'vs/base/common/paths'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { dirname } from 'path'; +import * as assert from 'vs/base/common/assert'; +import Event, { Emitter } from 'vs/base/common/event'; +import { StrictResourceMap } from 'vs/base/common/map'; +import { equals } from 'vs/base/common/objects'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Queue } from 'vs/base/common/async'; +import { stat, writeFile } from 'vs/base/node/pfs'; +import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; +import { FileChangesEvent } from 'vs/platform/files/common/files'; +import { isLinux } from 'vs/base/common/platform'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration'; +import { FolderConfigurationModel, Configuration, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; +import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { ConfigurationService as GlobalConfigurationService } from 'vs/platform/configuration/node/configurationService'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IConfigurationNode, IConfigurationRegistry, Extensions, ConfigurationScope, settingsSchema, resourceSettingsSchema } from 'vs/platform/configuration/common/configurationRegistry'; +import { createHash } from 'crypto'; +import { getWorkspaceLabel, IWorkspacesService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import product from 'vs/platform/node/product'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; +import { WorkspaceConfiguration, FolderConfiguration } from 'vs/workbench/services/configuration/node/configuration'; +import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; +import { Schemas } from 'vs/base/common/network'; +import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; +import { distinct } from 'vs/base/common/arrays'; + +export class WorkspaceService extends Disposable implements IWorkspaceConfigurationService, IWorkspaceContextService { + + public _serviceBrand: any; + + private workspace: Workspace; + private _configuration: Configuration; + private baseConfigurationService: GlobalConfigurationService; + private workspaceConfiguration: WorkspaceConfiguration; + private cachedFolderConfigs: StrictResourceMap; + + private workspaceEditingQueue: Queue; + + protected readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; + + protected readonly _onDidChangeWorkspaceFolders: Emitter = this._register(new Emitter()); + public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; + + protected readonly _onDidChangeWorkspaceName: Emitter = this._register(new Emitter()); + public readonly onDidChangeWorkspaceName: Event = this._onDidChangeWorkspaceName.event; + + protected readonly _onDidChangeWorkbenchState: Emitter = this._register(new Emitter()); + public readonly onDidChangeWorkbenchState: Event = this._onDidChangeWorkbenchState.event; + + private configurationEditingService: ConfigurationEditingService; + private jsonEditingService: JSONEditingService; + + // @ts-ignore unused injected service + constructor(private environmentService: IEnvironmentService, private workspacesService: IWorkspacesService, private workspaceSettingsRootFolder: string = WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME) { + super(); + + this.workspaceConfiguration = this._register(new WorkspaceConfiguration()); + this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => this.onWorkspaceConfigurationChanged())); + + this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService)); + this._register(this.baseConfigurationService.onDidChangeConfiguration(e => this.onBaseConfigurationChanged(e))); + this._register(Registry.as(Extensions.Configuration).onDidRegisterConfiguration(e => this.registerConfigurationSchemas())); + + this.workspaceEditingQueue = new Queue(); + } + + // Workspace Context Service Impl + + public getWorkspace(): Workspace { + return this.workspace; + } + + public getWorkbenchState(): WorkbenchState { + // Workspace has configuration file + if (this.workspace.configuration) { + return WorkbenchState.WORKSPACE; + } + + // Folder has single root + if (this.workspace.folders.length === 1) { + return WorkbenchState.FOLDER; + } + + // Empty + return WorkbenchState.EMPTY; + } + + public getWorkspaceFolder(resource: URI): IWorkspaceFolder { + return this.workspace.getFolder(resource); + } + + public addFolders(foldersToAdd: IWorkspaceFolderCreationData[]): TPromise { + assert.ok(this.jsonEditingService, 'Workbench is not initialized yet'); + return this.workspaceEditingQueue.queue(() => this.doAddFolders(foldersToAdd)); + } + + public removeFolders(foldersToRemove: URI[]): TPromise { + assert.ok(this.jsonEditingService, 'Workbench is not initialized yet'); + return this.workspaceEditingQueue.queue(() => this.doRemoveFolders(foldersToRemove)); + } + + public isInsideWorkspace(resource: URI): boolean { + return !!this.getWorkspaceFolder(resource); + } + + public isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean { + switch (this.getWorkbenchState()) { + case WorkbenchState.FOLDER: + return isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && this.pathEquals(this.workspace.folders[0].uri.fsPath, workspaceIdentifier); + case WorkbenchState.WORKSPACE: + return isWorkspaceIdentifier(workspaceIdentifier) && this.workspace.id === workspaceIdentifier.id; + } + return false; + } + + private doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[]): TPromise { + if (this.getWorkbenchState() !== WorkbenchState.WORKSPACE) { + return TPromise.as(void 0); // we need a workspace to begin with + } + + const currentWorkspaceFolders = this.getWorkspace().folders; + const currentWorkspaceFolderUris = currentWorkspaceFolders.map(folder => folder.uri); + const currentStoredFolders = currentWorkspaceFolders.map(folder => folder.raw); + + const storedFoldersToAdd: IStoredWorkspaceFolder[] = []; + + const workspaceConfigFolder = dirname(this.getWorkspace().configuration.fsPath); + + foldersToAdd.forEach(folderToAdd => { + if (this.contains(currentWorkspaceFolderUris, folderToAdd.uri)) { + return; // already existing + } + + let storedFolder: IStoredWorkspaceFolder; + + // File resource: use "path" property + if (folderToAdd.uri.scheme === Schemas.file) { + storedFolder = { + path: massageFolderPathForWorkspace(folderToAdd.uri.fsPath, workspaceConfigFolder, currentStoredFolders) + }; + } + + // Any other resource: use "uri" property + else { + storedFolder = { + uri: folderToAdd.uri.toString(true) + }; + } + + if (folderToAdd.name) { + storedFolder.name = folderToAdd.name; + } + + storedFoldersToAdd.push(storedFolder); + }); + + if (storedFoldersToAdd.length > 0) { + return this.setFolders([...currentStoredFolders, ...storedFoldersToAdd]); + } + + return TPromise.as(void 0); + } + + private doRemoveFolders(foldersToRemove: URI[]): TPromise { + if (this.getWorkbenchState() !== WorkbenchState.WORKSPACE) { + return TPromise.as(void 0); // we need a workspace to begin with + } + + const currentWorkspaceFolders = this.getWorkspace().folders; + const currentStoredFolders = currentWorkspaceFolders.map(folder => folder.raw); + + const newStoredFolders: IStoredWorkspaceFolder[] = currentStoredFolders.filter((folder, index) => { + if (!isStoredWorkspaceFolder(folder)) { + return true; // keep entries which are unrelated + } + + return !this.contains(foldersToRemove, currentWorkspaceFolders[index].uri); // keep entries which are unrelated + }); + + if (newStoredFolders.length !== currentStoredFolders.length) { + return this.setFolders(newStoredFolders); + } + + return TPromise.as(void 0); + } + + private setFolders(folders: IStoredWorkspaceFolder[]): TPromise { + return this.workspaceConfiguration.setFolders(folders, this.jsonEditingService) + .then(() => this.onWorkspaceConfigurationChanged()); + } + + private contains(resources: URI[], toCheck: URI): boolean { + return resources.some(resource => { + if (isLinux) { + return resource.toString() === toCheck.toString(); + } + + return resource.toString().toLowerCase() === toCheck.toString().toLowerCase(); + }); + } + + // Workspace Configuration Service Impl + + getConfigurationData(): IConfigurationData { + return this._configuration.toData(); + } + + getConfiguration(): T; + getConfiguration(section: string): T; + getConfiguration(overrides: IConfigurationOverrides): T; + getConfiguration(section: string, overrides: IConfigurationOverrides): T; + getConfiguration(arg1?: any, arg2?: any): any { + const section = typeof arg1 === 'string' ? arg1 : void 0; + const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0; + return this._configuration.getSection(section, overrides); + } + + getValue(key: string, overrides?: IConfigurationOverrides): T { + return this._configuration.getValue(key, overrides); + } + + updateValue(key: string, value: any): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise; + updateValue(key: string, value: any, target: ConfigurationTarget): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise; + updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget, donotNotifyError: boolean): TPromise; + updateValue(key: string, value: any, arg3?: any, arg4?: any, donotNotifyError?: any): TPromise { + assert.ok(this.configurationEditingService, 'Workbench is not initialized yet'); + const overrides = isConfigurationOverrides(arg3) ? arg3 : void 0; + const target = this.deriveConfigurationTarget(key, value, overrides, overrides ? arg4 : arg3); + return target ? this.writeConfigurationValue(key, value, target, overrides, donotNotifyError) + : TPromise.as(null); + } + + reloadConfiguration(folder?: IWorkspaceFolder, key?: string): TPromise { + if (folder) { + return this.reloadWorkspaceFolderConfiguration(folder, key); + } + return this.reloadUserConfiguration() + .then(() => this.reloadWorkspaceConfiguration()) + .then(() => this.loadConfiguration()); + } + + inspect(key: string, overrides?: IConfigurationOverrides): { + default: T, + user: T, + workspace: T, + workspaceFolder: T, + memory?: T, + value: T + } { + return this._configuration.lookup(key); + } + + keys(): { + default: string[]; + user: string[]; + workspace: string[]; + workspaceFolder: string[]; + } { + return this._configuration.keys(); + } + + getUnsupportedWorkspaceKeys(): string[] { + const unsupportedWorkspaceKeys = [...this.workspaceConfiguration.getWorkspaceSettings().unsupportedKeys]; + for (const folder of this.workspace.folders) { + unsupportedWorkspaceKeys.push(...this._configuration.getFolderConfigurationModel(folder.uri).workspaceSettingsConfig.unsupportedKeys); + } + return distinct(unsupportedWorkspaceKeys); + } + + initialize(arg: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWindowConfiguration): TPromise { + return this.createWorkspace(arg) + .then(workspace => this.updateWorkspaceAndInitializeConfiguration(workspace)); + } + + setInstantiationService(instantiationService: IInstantiationService): void { + this.configurationEditingService = instantiationService.createInstance(ConfigurationEditingService); + this.jsonEditingService = instantiationService.createInstance(JSONEditingService); + } + + handleWorkspaceFileEvents(event: FileChangesEvent): TPromise { + switch (this.getWorkbenchState()) { + case WorkbenchState.FOLDER: + return this.onSingleFolderFileChanges(event); + case WorkbenchState.WORKSPACE: + return this.onWorkspaceFileChanges(event); + } + return TPromise.as(void 0); + } + + private createWorkspace(arg: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWindowConfiguration): TPromise { + if (isWorkspaceIdentifier(arg)) { + return this.createMulitFolderWorkspace(arg); + } + + if (isSingleFolderWorkspaceIdentifier(arg)) { + return this.createSingleFolderWorkspace(arg); + } + + return this.createEmptyWorkspace(arg); + } + + private createMulitFolderWorkspace(workspaceIdentifier: IWorkspaceIdentifier): TPromise { + const workspaceConfigPath = URI.file(workspaceIdentifier.configPath); + return this.workspaceConfiguration.load(workspaceConfigPath) + .then(() => { + const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), URI.file(paths.dirname(workspaceConfigPath.fsPath))); + const workspaceId = workspaceIdentifier.id; + const workspaceName = getWorkspaceLabel({ id: workspaceId, configPath: workspaceConfigPath.fsPath }, this.environmentService); + return new Workspace(workspaceId, workspaceName, workspaceFolders, workspaceConfigPath); + }); + } + + private createSingleFolderWorkspace(singleFolderWorkspaceIdentifier: ISingleFolderWorkspaceIdentifier): TPromise { + const folderPath = URI.file(singleFolderWorkspaceIdentifier); + return stat(folderPath.fsPath) + .then(workspaceStat => { + const ctime = isLinux ? workspaceStat.ino : workspaceStat.birthtime.getTime(); // On Linux, birthtime is ctime, so we cannot use it! We use the ino instead! + const id = createHash('md5').update(folderPath.fsPath).update(ctime ? String(ctime) : '').digest('hex'); + const folder = URI.file(folderPath.fsPath); + return new Workspace(id, paths.basename(folderPath.fsPath), toWorkspaceFolders([{ path: folder.fsPath }]), null, ctime); + }); + } + + private createEmptyWorkspace(configuration: IWindowConfiguration): TPromise { + let id = configuration.backupPath ? URI.from({ path: paths.basename(configuration.backupPath), scheme: 'empty' }).toString() : ''; + return TPromise.as(new Workspace(id)); + } + + private updateWorkspaceAndInitializeConfiguration(workspace: Workspace): TPromise { + let folderChanges: IWorkspaceFoldersChangeEvent; + if (this.workspace) { + const currentState = this.getWorkbenchState(); + const currentWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0; + const currentFolders = this.workspace.folders; + + this.workspace.update(workspace); + + const newState = this.getWorkbenchState(); + if (newState !== currentState) { + this._onDidChangeWorkbenchState.fire(newState); + } + + const newWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0; + if (newWorkspacePath !== currentWorkspacePath || newState !== currentState) { + this._onDidChangeWorkspaceName.fire(); + } + + folderChanges = this.compareFolders(currentFolders, this.workspace.folders); + + } else { + this.workspace = workspace; + } + + return this.initializeConfiguration().then(() => { + // Trigger folders change after configuration initialization so that configuration is up to date. + if (folderChanges && (folderChanges.added.length || folderChanges.removed.length || folderChanges.changed.length)) { + this._onDidChangeWorkspaceFolders.fire(folderChanges); + } + }); + } + + private compareFolders(currentFolders: IWorkspaceFolder[], newFolders: IWorkspaceFolder[]): IWorkspaceFoldersChangeEvent { + const result = { added: [], removed: [], changed: [] }; + result.added = newFolders.filter(newFolder => !currentFolders.some(currentFolder => newFolder.uri.toString() === currentFolder.uri.toString())); + for (let currentIndex = 0; currentIndex < currentFolders.length; currentIndex++) { + let currentFolder = currentFolders[currentIndex]; + let newIndex = 0; + for (newIndex = 0; newIndex < newFolders.length && currentFolder.uri.toString() !== newFolders[newIndex].uri.toString(); newIndex++) { } + if (newIndex < newFolders.length) { + if (currentIndex !== newIndex || currentFolder.name !== newFolders[newIndex].name) { + result.changed.push(currentFolder); + } + } else { + result.removed.push(currentFolder); + } + } + return result; + } + + private initializeConfiguration(): TPromise { + this.registerConfigurationSchemas(); + return this.loadConfiguration(); + } + + private reloadUserConfiguration(key?: string): TPromise { + return this.baseConfigurationService.reloadConfiguration(); + } + + private reloadWorkspaceConfiguration(key?: string): TPromise { + const workbenchState = this.getWorkbenchState(); + if (workbenchState === WorkbenchState.FOLDER) { + return this.onWorkspaceFolderConfigurationChanged(this.workspace.folders[0], key); + } + if (workbenchState === WorkbenchState.WORKSPACE) { + return this.workspaceConfiguration.reload().then(() => this.onWorkspaceConfigurationChanged()); + } + return TPromise.as(null); + } + + private reloadWorkspaceFolderConfiguration(folder: IWorkspaceFolder, key?: string): TPromise { + return this.onWorkspaceFolderConfigurationChanged(folder, key); + } + + private loadConfiguration(): TPromise { + // reset caches + this.cachedFolderConfigs = new StrictResourceMap(); + + const folders = this.workspace.folders; + return this.loadFolderConfigurations(folders) + .then((folderConfigurations) => { + + let workspaceConfiguration = this.getWorkspaceConfigurationModel(folderConfigurations); + const folderConfigurationModels = new StrictResourceMap(); + folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration)); + + const currentConfiguration = this._configuration; + this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: Sandy Avoid passing null + + if (currentConfiguration) { + const changedKeys = this._configuration.compare(currentConfiguration); + this.triggerConfigurationChange(new ConfigurationChangeEvent().change(changedKeys), ConfigurationTarget.WORKSPACE); + } else { + this._onDidChangeConfiguration.fire(new AllKeysConfigurationChangeEvent(this._configuration.allKeys(), ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE))); + } + }); + } + + private getWorkspaceConfigurationModel(folderConfigurations: FolderConfigurationModel[]): ConfigurationModel { + switch (this.getWorkbenchState()) { + case WorkbenchState.FOLDER: + return folderConfigurations[0]; + case WorkbenchState.WORKSPACE: + return this.workspaceConfiguration.getConfiguration(); + default: + return new ConfigurationModel(); + } + } + + private registerConfigurationSchemas(): void { + if (this.workspace) { + const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); + jsonRegistry.registerSchema(defaultSettingsSchemaId, settingsSchema); + jsonRegistry.registerSchema(userSettingsSchemaId, settingsSchema); + + if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) { + jsonRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); + jsonRegistry.registerSchema(folderSettingsSchemaId, resourceSettingsSchema); + } else { + jsonRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); + jsonRegistry.registerSchema(folderSettingsSchemaId, settingsSchema); + } + } + } + + private onBaseConfigurationChanged(e: IConfigurationChangeEvent): void { + if (this.workspace && this._configuration) { + if (e.source === ConfigurationTarget.DEFAULT) { + this.workspaceConfiguration.getWorkspaceSettings().update(); + this.workspace.folders.forEach(folder => this._configuration.getFolderConfigurationModel(folder.uri).update()); + this._configuration.updateDefaultConfiguration(this.baseConfigurationService.configuration.defaults); + this.triggerConfigurationChange(new ConfigurationChangeEvent().change(e.affectedKeys), e.source); + } else { + let keys = this._configuration.updateUserConfiguration(this.baseConfigurationService.configuration.user); + this.triggerConfigurationChange(keys, e.source); + } + } + } + + private onWorkspaceConfigurationChanged(): TPromise { + if (this.workspace && this.workspace.configuration && this._configuration) { + const workspaceConfigurationChangeEvent = this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.getConfiguration()); + let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), URI.file(paths.dirname(this.workspace.configuration.fsPath))); + const changes = this.compareFolders(this.workspace.folders, configuredFolders); + if (changes.added.length || changes.removed.length || changes.changed.length) { + this.workspace.folders = configuredFolders; + return this.onFoldersChanged() + .then(foldersConfigurationChangeEvent => { + this.triggerConfigurationChange(foldersConfigurationChangeEvent.change(workspaceConfigurationChangeEvent), ConfigurationTarget.WORKSPACE_FOLDER); + this._onDidChangeWorkspaceFolders.fire(changes); + }); + } else { + this.triggerConfigurationChange(workspaceConfigurationChangeEvent, ConfigurationTarget.WORKSPACE); + } + } + return TPromise.as(null); + } + + private onWorkspaceFileChanges(event: FileChangesEvent): TPromise { + return TPromise.join(this.workspace.folders.map(folder => + // handle file event for each folder + this.cachedFolderConfigs.get(folder.uri).handleWorkspaceFileEvents(event) + // Update folder configuration if handled + .then(folderConfiguration => folderConfiguration ? this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration) : new ConfigurationChangeEvent())) + ).then(changeEvents => { + const consolidateChangeEvent = changeEvents.reduce((consolidated, e) => consolidated.change(e), new ConfigurationChangeEvent()); + this.triggerConfigurationChange(consolidateChangeEvent, ConfigurationTarget.WORKSPACE_FOLDER); + }); + } + + private onSingleFolderFileChanges(event: FileChangesEvent): TPromise { + const folder = this.workspace.folders[0]; + return this.cachedFolderConfigs.get(folder.uri).handleWorkspaceFileEvents(event) + .then(folderConfiguration => { + if (folderConfiguration) { + // File change handled + this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration); + const workspaceChangedKeys = this._configuration.updateWorkspaceConfiguration(folderConfiguration); + this.triggerConfigurationChange(workspaceChangedKeys, ConfigurationTarget.WORKSPACE); + } + }); + } + + private onWorkspaceFolderConfigurationChanged(folder: IWorkspaceFolder, key?: string): TPromise { + this.disposeFolderConfiguration(folder); + return this.loadFolderConfigurations([folder]) + .then(([folderConfiguration]) => { + const folderChangedKeys = this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration); + if (this.getWorkbenchState() === WorkbenchState.FOLDER) { + const workspaceChangedKeys = this._configuration.updateWorkspaceConfiguration(folderConfiguration); + this.triggerConfigurationChange(workspaceChangedKeys, ConfigurationTarget.WORKSPACE); + } else { + this.triggerConfigurationChange(folderChangedKeys, ConfigurationTarget.WORKSPACE_FOLDER); + } + }); + } + + private onFoldersChanged(): TPromise { + let changeEvent = new ConfigurationChangeEvent(); + + // Remove the configurations of deleted folders + for (const key of this.cachedFolderConfigs.keys()) { + if (!this.workspace.folders.filter(folder => folder.uri.toString() === key.toString())[0]) { + this.cachedFolderConfigs.delete(key); + changeEvent = changeEvent.change(this._configuration.deleteFolderConfiguration(key)); + } + } + + const toInitialize = this.workspace.folders.filter(folder => !this.cachedFolderConfigs.has(folder.uri)); + if (toInitialize.length) { + return this.loadFolderConfigurations(toInitialize) + .then(folderConfigurations => { + folderConfigurations.forEach((folderConfiguration, index) => { + changeEvent = changeEvent.change(this._configuration.updateFolderConfiguration(toInitialize[index].uri, folderConfiguration)); + }); + return changeEvent; + }); + } + return TPromise.as(changeEvent); + } + + private loadFolderConfigurations(folders: IWorkspaceFolder[]): TPromise { + return TPromise.join([...folders.map(folder => { + const folderConfiguration = new FolderConfiguration(folder.uri, this.workspaceSettingsRootFolder, this.getWorkbenchState() === WorkbenchState.WORKSPACE ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW); + this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); + return folderConfiguration.loadConfiguration(); + })]); + } + + private writeConfigurationValue(key: string, value: any, target: ConfigurationTarget, overrides: IConfigurationOverrides, donotNotifyError: boolean): TPromise { + if (target === ConfigurationTarget.DEFAULT) { + return TPromise.wrapError(new Error('Invalid configuration target')); + } + + if (target === ConfigurationTarget.MEMORY) { + this._configuration.updateValue(key, value, overrides); + this.triggerConfigurationChange(new ConfigurationChangeEvent().change(overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier)] : [key], overrides.resource), target); + return TPromise.as(null); + } + + return this.configurationEditingService.writeConfiguration(target, { key, value }, { scopes: overrides, donotNotifyError }) + .then(() => { + switch (target) { + case ConfigurationTarget.USER: + return this.reloadUserConfiguration(); + case ConfigurationTarget.WORKSPACE: + return this.reloadWorkspaceConfiguration(); + case ConfigurationTarget.WORKSPACE_FOLDER: + const workspaceFolder = overrides && overrides.resource ? this.workspace.getFolder(overrides.resource) : null; + if (workspaceFolder) { + return this.reloadWorkspaceFolderConfiguration(this.workspace.getFolder(overrides.resource), key); + } + } + return null; + }); + } + + private deriveConfigurationTarget(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): ConfigurationTarget { + if (target) { + return target; + } + + if (value === void 0) { + // Ignore. But expected is to remove the value from all targets + return void 0; + } + + const inspect = this.inspect(key, overrides); + if (equals(value, inspect.value)) { + // No change. So ignore. + return void 0; + } + + if (inspect.workspaceFolder !== void 0) { + return ConfigurationTarget.WORKSPACE_FOLDER; + } + + if (inspect.workspace !== void 0) { + return ConfigurationTarget.WORKSPACE; + } + + return ConfigurationTarget.USER; + } + + private triggerConfigurationChange(configurationEvent: ConfigurationChangeEvent, target: ConfigurationTarget): void { + if (configurationEvent.affectedKeys.length) { + configurationEvent.telemetryData(target, this.getTargetConfiguration(target)); + this._onDidChangeConfiguration.fire(new WorkspaceConfigurationChangeEvent(configurationEvent, this.workspace)); + } + } + + private getTargetConfiguration(target: ConfigurationTarget): any { + switch (target) { + case ConfigurationTarget.DEFAULT: + return this._configuration.defaults.contents; + case ConfigurationTarget.USER: + return this._configuration.user.contents; + case ConfigurationTarget.WORKSPACE: + return this._configuration.workspace.contents; + } + return {}; + } + + private pathEquals(path1: string, path2: string): boolean { + if (!isLinux) { + path1 = path1.toLowerCase(); + path2 = path2.toLowerCase(); + } + + return path1 === path2; + } + + private disposeFolderConfiguration(folder: IWorkspaceFolder): void { + const folderConfiguration = this.cachedFolderConfigs.get(folder.uri); + if (folderConfiguration) { + folderConfiguration.dispose(); + } + } +} + +interface IExportedConfigurationNode { + name: string; + description: string; + default: any; + type: string | string[]; + enum?: any[]; + enumDescriptions?: string[]; +} + +interface IConfigurationExport { + settings: IExportedConfigurationNode[]; + buildTime: number; + commit: string; + buildNumber: number; +} + +export class DefaultConfigurationExportHelper { + + constructor( + @IEnvironmentService environmentService: IEnvironmentService, + @IExtensionService private extensionService: IExtensionService, + @ICommandService private commandService: ICommandService) { + if (environmentService.args['export-default-configuration']) { + this.writeConfigModelAndQuit(environmentService.args['export-default-configuration']); + } + } + + private writeConfigModelAndQuit(targetPath: string): TPromise { + return this.extensionService.onReady() + .then(() => this.writeConfigModel(targetPath)) + .then(() => this.commandService.executeCommand('workbench.action.quit')) + .then(() => { }); + } + + private writeConfigModel(targetPath: string): TPromise { + const config = this.getConfigModel(); + + const resultString = JSON.stringify(config, undefined, ' '); + return writeFile(targetPath, resultString); + } + + private getConfigModel(): IConfigurationExport { + const configurations = Registry.as(Extensions.Configuration).getConfigurations().slice(); + const settings: IExportedConfigurationNode[] = []; + const processConfig = (config: IConfigurationNode) => { + if (config.properties) { + for (let name in config.properties) { + const prop = config.properties[name]; + const propDetails: IExportedConfigurationNode = { + name, + description: prop.description, + default: prop.default, + type: prop.type + }; + + if (prop.enum) { + propDetails.enum = prop.enum; + } + + if (prop.enumDescriptions) { + propDetails.enumDescriptions = prop.enumDescriptions; + } + + settings.push(propDetails); + } + } + + if (config.allOf) { + config.allOf.forEach(processConfig); + } + }; + + configurations.forEach(processConfig); + + const result: IConfigurationExport = { + settings: settings.sort((a, b) => a.name.localeCompare(b.name)), + buildTime: Date.now(), + commit: product.commit, + buildNumber: product.settingsSearchBuildId + }; + + return result; + } +} diff --git a/src/vs/workbench/services/configuration/node/jsonEditingService.ts b/src/vs/workbench/services/configuration/node/jsonEditingService.ts index da7afec3203..c2786248c14 100644 --- a/src/vs/workbench/services/configuration/node/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/node/jsonEditingService.ts @@ -42,7 +42,8 @@ export class JSONEditingService implements IJSONEditingService { private doWriteConfiguration(resource: URI, value: IJSONValue, save: boolean): TPromise { return this.resolveAndValidate(resource, save) - .then(reference => this.writeToBuffer(reference.object.textEditorModel, value)); + .then(reference => this.writeToBuffer(reference.object.textEditorModel, value) + .then(() => reference.dispose())); } private writeToBuffer(model: editorCommon.IModel, value: IJSONValue): TPromise { @@ -125,10 +126,10 @@ export class JSONEditingService implements IJSONEditingService { // User issues case JSONEditingErrorCode.ERROR_INVALID_FILE: { return nls.localize('errorInvalidFile', "Unable to write into the file. Please open the file to correct errors/warnings in the file and try again."); - }; + } case JSONEditingErrorCode.ERROR_FILE_DIRTY: { return nls.localize('errorFileDirty', "Unable to write into the file because the file is dirty. Please save the file and try again."); - }; + } } } } \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts index a6755918258..781260d8502 100644 --- a/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts +++ b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts @@ -5,8 +5,13 @@ 'use strict'; import * as assert from 'assert'; -import { FolderConfigurationModel, ScopedConfigurationModel, FolderSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels'; +import { join } from 'vs/base/common/paths'; +import { FolderConfigurationModel, ScopedConfigurationModel, FolderSettingsModel, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import URI from 'vs/base/common/uri'; +import { ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; suite('ConfigurationService - Model', () => { @@ -17,7 +22,7 @@ suite('ConfigurationService - Model', () => { const testObject = new FolderConfigurationModel(settingsConfig, [], ConfigurationScope.WINDOW); - assert.equal(testObject.getContentsFor('task'), undefined); + assert.equal(testObject.getSectionContents('task'), undefined); }); test('Test consolidate (settings and tasks)', () => { @@ -94,4 +99,99 @@ suite('ConfigurationService - Model', () => { assert.deepEqual(new FolderConfigurationModel(settingsConfig, [launchConfig, tasksConfig], ConfigurationScope.WINDOW).contents, expected); assert.deepEqual(new FolderConfigurationModel(settingsConfig, [tasksConfig, launchConfig], ConfigurationScope.WINDOW).contents, expected); }); +}); + +suite('WorkspaceConfigurationChangeEvent', () => { + + test('changeEvent affecting workspace folders', () => { + let configurationChangeEvent = new ConfigurationChangeEvent(); + configurationChangeEvent.change(['window.title']); + configurationChangeEvent.change(['window.zoomLevel'], URI.file('folder1')); + configurationChangeEvent.change(['workbench.editor.enablePreview'], URI.file('folder2')); + configurationChangeEvent.change(['window.restoreFullscreen'], URI.file('folder1')); + configurationChangeEvent.change(['window.restoreWindows'], URI.file('folder2')); + configurationChangeEvent.telemetryData(ConfigurationTarget.WORKSPACE, {}); + + let testObject = new WorkspaceConfigurationChangeEvent(configurationChangeEvent, new Workspace('id', 'name', + [new WorkspaceFolder({ index: 0, name: '1', uri: URI.file('folder1') }), + new WorkspaceFolder({ index: 1, name: '2', uri: URI.file('folder2') }), + new WorkspaceFolder({ index: 2, name: '3', uri: URI.file('folder3') })])); + + assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']); + assert.equal(testObject.source, ConfigurationTarget.WORKSPACE); + + assert.ok(testObject.affectsConfiguration('window.zoomLevel')); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('folder1'))); + assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('window.zoomLevel', URI.file(join('folder3', 'file3')))); + + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen')); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('window.restoreFullscreen', URI.file(join('folder3', 'file3')))); + + assert.ok(testObject.affectsConfiguration('window.restoreWindows')); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file('file2'))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('window.restoreWindows', URI.file(join('folder3', 'file3')))); + + assert.ok(testObject.affectsConfiguration('window.title')); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('folder1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file(join('folder2', 'file2')))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('folder3'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window.title', URI.file('file3'))); + + assert.ok(testObject.affectsConfiguration('window')); + assert.ok(testObject.affectsConfiguration('window', URI.file('folder1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file(join('folder1', 'file1')))); + assert.ok(testObject.affectsConfiguration('window', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('window', URI.file(join('folder2', 'file2')))); + assert.ok(testObject.affectsConfiguration('window', URI.file('folder3'))); + assert.ok(testObject.affectsConfiguration('window', URI.file(join('folder3', 'file3')))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file1'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file2'))); + assert.ok(testObject.affectsConfiguration('window', URI.file('file3'))); + + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview')); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('folder3'))); + + assert.ok(testObject.affectsConfiguration('workbench.editor')); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('workbench.editor', URI.file('folder3'))); + + assert.ok(testObject.affectsConfiguration('workbench')); + assert.ok(testObject.affectsConfiguration('workbench', URI.file('folder2'))); + assert.ok(testObject.affectsConfiguration('workbench', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('workbench', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('workbench', URI.file('folder3'))); + + assert.ok(!testObject.affectsConfiguration('files')); + assert.ok(!testObject.affectsConfiguration('files', URI.file('folder1'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file(join('folder1', 'file1')))); + assert.ok(!testObject.affectsConfiguration('files', URI.file('folder2'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file(join('folder2', 'file2')))); + assert.ok(!testObject.affectsConfiguration('files', URI.file('folder3'))); + assert.ok(!testObject.affectsConfiguration('files', URI.file(join('folder3', 'file3')))); + }); + }); \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/test/node/configuration.test.ts b/src/vs/workbench/services/configuration/test/node/configuration.test.ts deleted file mode 100644 index 1ee691bae5f..00000000000 --- a/src/vs/workbench/services/configuration/test/node/configuration.test.ts +++ /dev/null @@ -1,454 +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 assert = require('assert'); -import os = require('os'); -import path = require('path'); -import fs = require('fs'); -import * as sinon from 'sinon'; -import URI from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; -import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; -import extfs = require('vs/base/node/extfs'); -import uuid = require('vs/base/common/uuid'); -import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { WorkspaceServiceImpl, WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; -import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; - -class SettingsTestEnvironmentService extends EnvironmentService { - - constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome) { - super(args, _execPath); - } - - get appSettingsPath(): string { return this.customAppSettingsHome; } -} - -suite('WorkspaceConfigurationService - Node', () => { - - function createWorkspace(callback: (workspaceDir: string, globalSettingsFile: string, cleanUp: (callback: () => void) => void) => void): void { - const id = uuid.generateUuid(); - const parentDir = path.join(os.tmpdir(), 'vsctests', id); - const workspaceDir = path.join(parentDir, 'workspaceconfig', id); - const workspaceSettingsDir = path.join(workspaceDir, '.vscode'); - const globalSettingsFile = path.join(workspaceDir, 'config.json'); - - extfs.mkdirp(workspaceSettingsDir, 493, (error) => { - callback(workspaceDir, globalSettingsFile, (callback) => extfs.del(parentDir, os.tmpdir(), () => { }, callback)); - }); - } - - function createService(workspaceDir: string, globalSettingsFile: string): TPromise { - const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); - const service = new WorkspaceServiceImpl(workspaceDir, environmentService, null); - - return service.initialize().then(() => service); - } - - test('defaults', (done: () => void) => { - interface ITestSetting { - workspace: { - service: { - testSetting: string; - } - }; - } - - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test_workspace', - 'type': 'object', - 'properties': { - 'workspace.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - const config = service.getConfiguration(); - assert.equal(config.workspace.service.testSetting, 'isSet'); - - service.dispose(); - - cleanUp(done); - }); - }); - }); - - test('globals', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); - - service.reloadConfiguration().then(() => { - const config = service.getConfiguration<{ testworkbench: { editor: { tabs: boolean } } }>(); - assert.equal(config.testworkbench.editor.tabs, true); - - service.dispose(); - - cleanUp(done); - }); - }); - }); - }); - - test('reload configuration emits events', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); - - return service.initialize().then(() => { - service.onDidUpdateConfiguration(event => { - const config = service.getConfiguration<{ testworkbench: { editor: { tabs: boolean } } }>(); - assert.equal(config.testworkbench.editor.tabs, false); - - service.dispose(); - - cleanUp(done); - }); - - fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": false }'); - - // this has to trigger the event since the config changes - service.reloadConfiguration().done(); - }); - - }); - }); - }); - - test('globals override defaults', (done: () => void) => { - interface ITestSetting { - workspace: { - service: { - testSetting: string; - } - }; - } - - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test_workspace', - 'type': 'object', - 'properties': { - 'workspace.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - fs.writeFileSync(globalSettingsFile, '{ "workspace.service.testSetting": "isChanged" }'); - - service.reloadConfiguration().then(() => { - const config = service.getConfiguration(); - assert.equal(config.workspace.service.testSetting, 'isChanged'); - - service.dispose(); - - cleanUp(done); - }); - }); - }); - }); - - test('workspace settings', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "testworkbench.editor.icons": true }'); - - service.reloadConfiguration().then(() => { - const config = service.getConfiguration<{ testworkbench: { editor: { icons: boolean } } }>(); - assert.equal(config.testworkbench.editor.icons, true); - - service.dispose(); - - cleanUp(done); - }); - }); - }); - }); - - test('workspace settings override user settings', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.icons": false, "testworkbench.other.setting": true }'); - fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "testworkbench.editor.icons": true }'); - - service.reloadConfiguration().then(() => { - const config = service.getConfiguration<{ testworkbench: { editor: { icons: boolean }, other: { setting: string } } }>(); - assert.equal(config.testworkbench.editor.icons, true); - assert.equal(config.testworkbench.other.setting, true); - - service.dispose(); - - cleanUp(done); - }); - }); - }); - }); - - test('workspace change triggers event', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - service.onDidUpdateConfiguration(event => { - const config = service.getConfiguration<{ testworkbench: { editor: { icons: boolean } } }>(); - assert.equal(config.testworkbench.editor.icons, true); - assert.equal(service.getConfiguration().testworkbench.editor.icons, true); - - service.dispose(); - - cleanUp(done); - }); - - const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); - fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": true }'); - - const event = new FileChangesEvent([{ resource: URI.file(settingsFile), type: FileChangeType.ADDED }]); - service.handleWorkspaceFileEvents(event); - }); - }); - }); - - test('workspace reload should triggers event if content changed', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); - fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": true }'); - - const target = sinon.stub(); - service.onDidUpdateConfiguration(event => target()); - - fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": false }'); - - service.reloadConfiguration().done(() => { - assert.ok(target.calledOnce); - service.dispose(); - - cleanUp(done); - }); - }); - }); - }); - - test('workspace reload should not trigger event if nothing changed', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); - fs.writeFileSync(settingsFile, '{ "testworkbench.editor.icons": true }'); - - service.reloadConfiguration().done(() => { - const target = sinon.stub(); - service.onDidUpdateConfiguration(event => target()); - - service.reloadConfiguration().done(() => { - assert.ok(!target.called); - service.dispose(); - - cleanUp(done); - }); - }); - }); - }); - }); - - test('workspace reload should not trigger event if there is no model', (done: () => void) => { - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - const target = sinon.stub(); - service.onDidUpdateConfiguration(event => target()); - service.reloadConfiguration().done(() => { - assert.ok(!target.called); - service.dispose(); - cleanUp(done); - }); - }); - }); - }); - - - test('lookup', (done: () => void) => { - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test', - 'type': 'object', - 'properties': { - 'workspaceLookup.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - let res = service.lookup('something.missing'); - assert.ok(!res.default); - assert.ok(!res.user); - assert.ok(!res.workspace); - assert.ok(!res.value); - - res = service.lookup('workspaceLookup.service.testSetting'); - assert.equal(res.default, 'isSet'); - assert.equal(res.value, 'isSet'); - assert.ok(!res.user); - assert.ok(!res.workspace); - - fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); - - return service.reloadConfiguration().then(() => { - res = service.lookup('workspaceLookup.service.testSetting'); - assert.equal(res.default, 'isSet'); - assert.equal(res.user, true); - assert.equal(res.value, true); - assert.ok(!res.workspace); - - const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); - fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); - - return service.reloadConfiguration().then(() => { - res = service.lookup('workspaceLookup.service.testSetting'); - assert.equal(res.default, 'isSet'); - assert.equal(res.user, true); - assert.equal(res.workspace, 55); - assert.equal(res.value, 55); - - service.dispose(); - - cleanUp(done); - }); - - }); - - }); - }); - }); - - test('keys', (done: () => void) => { - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test', - 'type': 'object', - 'properties': { - 'workspaceLookup.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - - function contains(array: string[], key: string): boolean { - return array.indexOf(key) >= 0; - } - - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - let keys = service.keys(); - - assert.ok(!contains(keys.default, 'something.missing')); - assert.ok(!contains(keys.user, 'something.missing')); - assert.ok(!contains(keys.workspace, 'something.missing')); - - assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); - assert.ok(!contains(keys.user, 'workspaceLookup.service.testSetting')); - assert.ok(!contains(keys.workspace, 'workspaceLookup.service.testSetting')); - - fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); - - return service.reloadConfiguration().then(() => { - keys = service.keys(); - - assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); - assert.ok(contains(keys.user, 'workspaceLookup.service.testSetting')); - assert.ok(!contains(keys.workspace, 'workspaceLookup.service.testSetting')); - - const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); - fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); - - return service.reloadConfiguration().then(() => { - keys = service.keys(); - - assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); - assert.ok(contains(keys.user, 'workspaceLookup.service.testSetting')); - assert.ok(contains(keys.workspace, 'workspaceLookup.service.testSetting')); - - const settingsFile = path.join(workspaceDir, '.vscode', 'tasks.json'); - fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.taskTestSetting": 55 }'); - - return service.reloadConfiguration().then(() => { - keys = service.keys(); - - assert.ok(!contains(keys.default, 'tasks.workspaceLookup.service.taskTestSetting')); - assert.ok(!contains(keys.user, 'tasks.workspaceLookup.service.taskTestSetting')); - assert.ok(contains(keys.workspace, 'tasks.workspaceLookup.service.taskTestSetting')); - - service.dispose(); - - cleanUp(done); - }); - }); - }); - }); - }); - }); - - test('values', (done: () => void) => { - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test', - 'type': 'object', - 'properties': { - 'workspaceLookup.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { - return createService(workspaceDir, globalSettingsFile).then(service => { - let values = service.values(); - let value = values['workspaceLookup.service.testSetting']; - - assert.ok(value); - assert.equal(value.default, 'isSet'); - - fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); - - return service.reloadConfiguration().then(() => { - values = service.values(); - value = values['workspaceLookup.service.testSetting']; - - assert.ok(value); - assert.equal(value.user, true); - - const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); - fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); - - return service.reloadConfiguration().then(() => { - values = service.values(); - value = values['workspaceLookup.service.testSetting']; - - assert.ok(value); - assert.equal(value.user, true); - assert.equal(value.workspace, 55); - - done(); - }); - }); - }); - }); - }); -}); \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts index b5c9099cde4..9966a0a9fa5 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts @@ -18,37 +18,27 @@ import { parseArgs } from 'vs/platform/environment/node/argv'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import extfs = require('vs/base/node/extfs'); -import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService } from 'vs/workbench/test/workbenchTestServices'; +import { TestTextFileService, TestTextResourceConfigurationService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; import uuid = require('vs/base/common/uuid'); import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { WorkspaceService, EmptyWorkspaceServiceImpl, WorkspaceServiceImpl } from 'vs/workbench/services/configuration/node/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { FileService } from 'vs/workbench/services/files/node/fileService'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; -import { ConfigurationTarget, ConfigurationEditingError, ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/node/configurationEditingService'; import { IFileService } from 'vs/platform/files/common/files'; import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; -import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; +import { IChoiceService } from 'vs/platform/message/common/message'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; class SettingsTestEnvironmentService extends EnvironmentService { - constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome) { + constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome: string) { super(args, _execPath); } @@ -59,11 +49,10 @@ suite('ConfigurationEditingService', () => { let instantiationService: TestInstantiationService; let testObject: ConfigurationEditingService; - let parentDir; - let workspaceDir; - let globalSettingsFile; + let parentDir: string; + let workspaceDir: string; + let globalSettingsFile: string; let workspaceSettingsDir; - let choiceService; suiteSetup(() => { const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -113,34 +102,19 @@ suite('ConfigurationEditingService', () => { // Clear services if they are already created clearServices(); - instantiationService = new TestInstantiationService(); + instantiationService = workbenchInstantiationService(); const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); instantiationService.stub(IEnvironmentService, environmentService); const workspacesService = instantiationService.stub(IWorkspacesService, {}); - const workspaceService = noWorkspace ? new EmptyWorkspaceServiceImpl(environmentService) : new WorkspaceServiceImpl(workspaceDir, environmentService, workspacesService); + const workspaceService = new WorkspaceService(environmentService, workspacesService); instantiationService.stub(IWorkspaceContextService, workspaceService); - instantiationService.stub(IConfigurationService, workspaceService); - instantiationService.stub(ILifecycleService, new TestLifecycleService()); - instantiationService.stub(IEditorGroupService, new TestEditorGroupService()); - instantiationService.stub(ITelemetryService, NullTelemetryService); - instantiationService.stub(IModeService, ModeServiceImpl); - instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl)); - instantiationService.stub(IFileService, new FileService(workspaceService, new TestConfigurationService(), { disableWatcher: true })); - instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); - instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); - instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); - instantiationService.stub(IBackupFileService, new TestBackupFileService()); - choiceService = instantiationService.stub(IChoiceService, { - choose: (severity, message, options, cancelId): TPromise => { - return TPromise.as(cancelId); - } + return workspaceService.initialize(noWorkspace ? {} : workspaceDir).then(() => { + instantiationService.stub(IConfigurationService, workspaceService); + instantiationService.stub(IFileService, new FileService(workspaceService, new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true })); + instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); + instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); + testObject = instantiationService.createInstance(ConfigurationEditingService); }); - instantiationService.stub(IMessageService, { - show: (severity, message, options, cancelId): void => { } - }); - - testObject = instantiationService.createInstance(ConfigurationEditingService); - return workspaceService.initialize(); } teardown(() => { @@ -225,7 +199,6 @@ suite('ConfigurationEditingService', () => { const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); const parsed = json.parse(contents); assert.equal(parsed['configurationEditing.service.testSetting'], 'value'); - assert.equal(instantiationService.get(IConfigurationService).lookup('configurationEditing.service.testSetting').value, 'value'); }); }); @@ -237,10 +210,6 @@ suite('ConfigurationEditingService', () => { const parsed = json.parse(contents); assert.equal(parsed['configurationEditing.service.testSetting'], 'value'); assert.equal(parsed['my.super.setting'], 'my.super.value'); - - const configurationService = instantiationService.get(IConfigurationService); - assert.equal(configurationService.lookup('configurationEditing.service.testSetting').value, 'value'); - assert.equal(configurationService.lookup('my.super.setting').value, 'my.super.value'); }); }); @@ -251,8 +220,6 @@ suite('ConfigurationEditingService', () => { const contents = fs.readFileSync(target).toString('utf8'); const parsed = json.parse(contents); assert.equal(parsed['service.testSetting'], 'value'); - const configurationService = instantiationService.get(IConfigurationService); - assert.equal(configurationService.lookup('tasks.service.testSetting').value, 'value'); }); }); @@ -265,10 +232,6 @@ suite('ConfigurationEditingService', () => { const parsed = json.parse(contents); assert.equal(parsed['service.testSetting'], 'value'); assert.equal(parsed['my.super.setting'], 'my.super.value'); - - const configurationService = instantiationService.get(IConfigurationService); - assert.equal(configurationService.lookup('launch.service.testSetting').value, 'value'); - assert.equal(configurationService.lookup('launch.my.super.setting').value, 'my.super.value'); }); }); diff --git a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts new file mode 100644 index 00000000000..444f2793249 --- /dev/null +++ b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts @@ -0,0 +1,686 @@ +/*--------------------------------------------------------------------------------------------- + * 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 sinon from 'sinon'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; +import { parseArgs } from 'vs/platform/environment/node/argv'; +import extfs = require('vs/base/node/extfs'); +import uuid = require('vs/base/common/uuid'); +import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; +import { ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/node/configurationEditingService'; +import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; +import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { workbenchInstantiationService, TestTextResourceConfigurationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices'; +import { FileService } from 'vs/workbench/services/files/node/fileService'; +import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; +import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; +import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; + +class SettingsTestEnvironmentService extends EnvironmentService { + + constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome) { + super(args, _execPath); + } + + get appSettingsPath(): string { return this.customAppSettingsHome; } +} + +function setUpFolderWorkspace(folderName: string): TPromise<{ parentDir: string, folderDir: string }> { + const id = uuid.generateUuid(); + const parentDir = path.join(os.tmpdir(), 'vsctests', id); + return setUpFolder(folderName, parentDir).then(folderDir => ({ parentDir, folderDir })); +} + +function setUpFolder(folderName: string, parentDir: string): TPromise { + const folderDir = path.join(parentDir, folderName); + const workspaceSettingsDir = path.join(folderDir, '.vscode'); + return new TPromise((c, e) => { + extfs.mkdirp(workspaceSettingsDir, 493, (error) => { + if (error) { + e(error); + return null; + } + c(folderDir); + }); + }); +} + +function setUpWorkspace(folders: string[]): TPromise<{ parentDir: string, configPath: string }> { + + const id = uuid.generateUuid(); + const parentDir = path.join(os.tmpdir(), 'vsctests', id); + + return createDir(parentDir) + .then(() => { + const configPath = path.join(parentDir, 'vsctests.code-workspace'); + const workspace = { folders: folders.map(path => ({ path })) }; + fs.writeFileSync(configPath, JSON.stringify(workspace, null, '\t')); + + return TPromise.join(folders.map(folder => setUpFolder(folder, parentDir))) + .then(() => ({ parentDir, configPath })); + }); + +} + +function createDir(dir: string): TPromise { + return new TPromise((c, e) => { + extfs.mkdirp(dir, 493, (error) => { + if (error) { + e(error); + return null; + } + c(null); + }); + }); +} + +suite('WorkspaceContextService - Folder', () => { + + let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceResource: string, workspaceContextService: IWorkspaceContextService; + + setup(() => { + return setUpFolderWorkspace(workspaceName) + .then(({ parentDir, folderDir }) => { + parentResource = parentDir; + workspaceResource = folderDir; + const globalSettingsFile = path.join(parentDir, 'settings.json'); + const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); + workspaceContextService = new WorkspaceService(environmentService, null); + return (workspaceContextService).initialize(folderDir); + }); + }); + + teardown(done => { + if (workspaceContextService) { + (workspaceContextService).dispose(); + } + if (parentResource) { + extfs.del(parentResource, os.tmpdir(), () => { }, done); + } + }); + + test('getWorkspace()', () => { + const actual = workspaceContextService.getWorkspace(); + + assert.equal(actual.folders.length, 1); + assert.equal(actual.folders[0].uri.fsPath, URI.file(workspaceResource).fsPath); + assert.equal(actual.folders[0].name, workspaceName); + assert.equal(actual.folders[0].index, 0); + assert.ok(!actual.configuration); + }); + + test('getWorkbenchState()', () => { + const actual = workspaceContextService.getWorkbenchState(); + + assert.equal(actual, WorkbenchState.FOLDER); + }); + + test('getWorkspaceFolder()', () => { + const actual = workspaceContextService.getWorkspaceFolder(URI.file(path.join(workspaceResource, 'a'))); + + assert.equal(actual, workspaceContextService.getWorkspace().folders[0]); + }); + + test('isCurrentWorkspace() => true', () => { + assert.ok(workspaceContextService.isCurrentWorkspace(workspaceResource)); + }); + + test('isCurrentWorkspace() => false', () => { + assert.ok(!workspaceContextService.isCurrentWorkspace(workspaceResource + 'abc')); + }); +}); + +suite('WorkspaceContextService - Workspace', () => { + + let parentResource: string, testObject: WorkspaceService; + + setup(() => { + return setUpWorkspace(['a', 'b']) + .then(({ parentDir, configPath }) => { + + parentResource = parentDir; + + const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); + const workspaceService = new WorkspaceService(environmentService, null); + + const instantiationService = workbenchInstantiationService(); + instantiationService.stub(IWorkspaceContextService, workspaceService); + instantiationService.stub(IConfigurationService, workspaceService); + instantiationService.stub(IEnvironmentService, environmentService); + + return workspaceService.initialize({ id: configPath, configPath }).then(() => { + + instantiationService.stub(IFileService, new FileService(workspaceService, new TestTextResourceConfigurationService(), workspaceService, { disableWatcher: true })); + instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); + instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); + workspaceService.setInstantiationService(instantiationService); + + testObject = workspaceService; + }); + }); + }); + + teardown(done => { + if (testObject) { + (testObject).dispose(); + } + if (parentResource) { + extfs.del(parentResource, os.tmpdir(), () => { }, done); + } + }); + + test('workspace folders', () => { + const actual = testObject.getWorkspace().folders; + + assert.equal(actual.length, 2); + assert.equal(path.basename(actual[0].uri.fsPath), 'a'); + assert.equal(path.basename(actual[1].uri.fsPath), 'b'); + }); + + test('add folders', () => { + const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath); + return testObject.addFolders([{ uri: URI.file(path.join(workspaceDir, 'd')) }, { uri: URI.file(path.join(workspaceDir, 'c')) }]) + .then(() => { + const actual = testObject.getWorkspace().folders; + + assert.equal(actual.length, 4); + assert.equal(path.basename(actual[0].uri.fsPath), 'a'); + assert.equal(path.basename(actual[1].uri.fsPath), 'b'); + assert.equal(path.basename(actual[2].uri.fsPath), 'd'); + assert.equal(path.basename(actual[3].uri.fsPath), 'c'); + }); + }); + + test('add folders (with name)', () => { + const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath); + return testObject.addFolders([{ uri: URI.file(path.join(workspaceDir, 'd')), name: 'DDD' }, { uri: URI.file(path.join(workspaceDir, 'c')), name: 'CCC' }]) + .then(() => { + const actual = testObject.getWorkspace().folders; + + assert.equal(actual.length, 4); + assert.equal(path.basename(actual[0].uri.fsPath), 'a'); + assert.equal(path.basename(actual[1].uri.fsPath), 'b'); + assert.equal(path.basename(actual[2].uri.fsPath), 'd'); + assert.equal(path.basename(actual[3].uri.fsPath), 'c'); + assert.equal(actual[2].name, 'DDD'); + assert.equal(actual[3].name, 'CCC'); + }); + }); + + test('add folders triggers change event', () => { + const target = sinon.spy(); + testObject.onDidChangeWorkspaceFolders(target); + const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath); + const addedFolders = [{ uri: URI.file(path.join(workspaceDir, 'd')) }, { uri: URI.file(path.join(workspaceDir, 'c')) }]; + return testObject.addFolders(addedFolders) + .then(() => { + assert.ok(target.calledOnce); + const actual = target.args[0][0]; + assert.deepEqual(actual.added.map(r => r.uri.toString()), addedFolders.map(a => a.uri.toString())); + assert.deepEqual(actual.removed, []); + assert.deepEqual(actual.changed, []); + }); + }); + + test('remove folders', () => { + return testObject.removeFolders([testObject.getWorkspace().folders[0].uri]) + .then(() => { + const actual = testObject.getWorkspace().folders; + assert.equal(actual.length, 1); + assert.equal(path.basename(actual[0].uri.fsPath), 'b'); + }); + }); + + test('remove folders triggers change event', () => { + const target = sinon.spy(); + testObject.onDidChangeWorkspaceFolders(target); + const removedFolder = testObject.getWorkspace().folders[0]; + return testObject.removeFolders([removedFolder.uri]) + .then(() => { + assert.ok(target.calledOnce); + const actual = target.args[0][0]; + assert.deepEqual(actual.added, []); + assert.deepEqual(actual.removed.map(r => r.uri.toString()), [removedFolder.uri.toString()]); + assert.deepEqual(actual.changed.map(c => c.uri.toString()), [testObject.getWorkspace().folders[0].uri.toString()]); + }); + }); + + test('reorder folders trigger change event', () => { + const target = sinon.spy(); + testObject.onDidChangeWorkspaceFolders(target); + const workspace = { folders: [{ path: testObject.getWorkspace().folders[1].uri.fsPath }, { path: testObject.getWorkspace().folders[0].uri.fsPath }] }; + fs.writeFileSync(testObject.getWorkspace().configuration.fsPath, JSON.stringify(workspace, null, '\t')); + return testObject.reloadConfiguration() + .then(() => { + assert.ok(target.calledOnce); + const actual = target.args[0][0]; + assert.deepEqual(actual.added, []); + assert.deepEqual(actual.removed, []); + assert.deepEqual(actual.changed.map(c => c.uri.toString()), testObject.getWorkspace().folders.map(f => f.uri.toString()).reverse()); + }); + }); + + test('rename folders trigger change event', () => { + const target = sinon.spy(); + testObject.onDidChangeWorkspaceFolders(target); + const workspace = { folders: [{ path: testObject.getWorkspace().folders[0].uri.fsPath, name: '1' }, { path: testObject.getWorkspace().folders[1].uri.fsPath }] }; + fs.writeFileSync(testObject.getWorkspace().configuration.fsPath, JSON.stringify(workspace, null, '\t')); + return testObject.reloadConfiguration() + .then(() => { + assert.ok(target.calledOnce); + const actual = target.args[0][0]; + assert.deepEqual(actual.added, []); + assert.deepEqual(actual.removed, []); + assert.deepEqual(actual.changed.map(c => c.uri.toString()), [testObject.getWorkspace().folders[0].uri.toString()]); + }); + }); + +}); + +suite('WorkspaceConfigurationService - Folder', () => { + + let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceDir: string, testObject: IConfigurationService, globalSettingsFile: string; + + suiteSetup(() => { + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.folder.testSetting': { + 'type': 'string', + 'default': 'isSet' + }, + } + }); + }); + + setup(() => { + return setUpFolderWorkspace(workspaceName) + .then(({ parentDir, folderDir }) => { + + parentResource = parentDir; + workspaceDir = folderDir; + globalSettingsFile = path.join(parentDir, 'settings.json'); + + const instantiationService = workbenchInstantiationService(); + const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); + const workspaceService = new WorkspaceService(environmentService, null); + instantiationService.stub(IWorkspaceContextService, workspaceService); + instantiationService.stub(IConfigurationService, workspaceService); + instantiationService.stub(IEnvironmentService, environmentService); + + return workspaceService.initialize(folderDir).then(() => { + instantiationService.stub(IFileService, new FileService(workspaceService, new TestTextResourceConfigurationService(), workspaceService, { disableWatcher: true })); + instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); + instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); + workspaceService.setInstantiationService(instantiationService); + testObject = workspaceService; + }); + }); + }); + + teardown(done => { + if (testObject) { + (testObject).dispose(); + } + if (parentResource) { + extfs.del(parentResource, os.tmpdir(), () => { }, done); + } + }); + + test('defaults', () => { + assert.deepEqual(testObject.getValue('configurationService'), { 'folder': { 'testSetting': 'isSet' } }); + }); + + test('globals override defaults', () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }'); + return testObject.reloadConfiguration() + .then(() => assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'userValue')); + }); + + test('globals', () => { + fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); + return testObject.reloadConfiguration() + .then(() => assert.equal(testObject.getValue('testworkbench.editor.tabs'), true)); + }); + + test('workspace settings', () => { + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "testworkbench.editor.icons": true }'); + return testObject.reloadConfiguration() + .then(() => assert.equal(testObject.getValue('testworkbench.editor.icons'), true)); + }); + + test('workspace settings override user settings', () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }'); + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }'); + return testObject.reloadConfiguration() + .then(() => assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue')); + }); + + test('workspace change triggers event', () => { + const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); + fs.writeFileSync(settingsFile, '{ "configurationService.folder.testSetting": "workspaceValue" }'); + const event = new FileChangesEvent([{ resource: URI.file(settingsFile), type: FileChangeType.ADDED }]); + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return (testObject).handleWorkspaceFileEvents(event) + .then(() => { + assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue'); + assert.ok(target.called); + }); + }); + + test('reload configuration emits events after global configuraiton changes', () => { + fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.reloadConfiguration().then(() => assert.ok(target.called)); + }); + + test('reload configuration emits events after workspace configuraiton changes', () => { + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }'); + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.reloadConfiguration().then(() => assert.ok(target.called)); + }); + + test('reload configuration should not emit event if no changes', () => { + fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }'); + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }'); + return testObject.reloadConfiguration() + .then(() => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(() => { target(); }); + return testObject.reloadConfiguration() + .then(() => assert.ok(!target.called)); + }); + }); + + test('inspect', () => { + let actual = testObject.inspect('something.missing'); + assert.equal(actual.default, void 0); + assert.equal(actual.user, void 0); + assert.equal(actual.workspace, void 0); + assert.equal(actual.workspaceFolder, void 0); + assert.equal(actual.value, void 0); + + actual = testObject.inspect('configurationService.folder.testSetting'); + assert.equal(actual.default, 'isSet'); + assert.equal(actual.user, void 0); + assert.equal(actual.workspace, void 0); + assert.equal(actual.workspaceFolder, void 0); + assert.equal(actual.value, 'isSet'); + + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }'); + return testObject.reloadConfiguration() + .then(() => { + actual = testObject.inspect('configurationService.folder.testSetting'); + assert.equal(actual.default, 'isSet'); + assert.equal(actual.user, 'userValue'); + assert.equal(actual.workspace, void 0); + assert.equal(actual.workspaceFolder, void 0); + assert.equal(actual.value, 'userValue'); + + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }'); + + return testObject.reloadConfiguration() + .then(() => { + actual = testObject.inspect('configurationService.folder.testSetting'); + assert.equal(actual.default, 'isSet'); + assert.equal(actual.user, 'userValue'); + assert.equal(actual.workspace, 'workspaceValue'); + assert.equal(actual.workspaceFolder, void 0); + assert.equal(actual.value, 'workspaceValue'); + }); + }); + }); + + test('keys', () => { + let actual = testObject.keys(); + assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1); + assert.deepEqual(actual.user, []); + assert.deepEqual(actual.workspace, []); + assert.deepEqual(actual.workspaceFolder, []); + + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }'); + return testObject.reloadConfiguration() + .then(() => { + actual = testObject.keys(); + assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1); + assert.deepEqual(actual.user, ['configurationService.folder.testSetting']); + assert.deepEqual(actual.workspace, []); + assert.deepEqual(actual.workspaceFolder, []); + + fs.writeFileSync(path.join(workspaceDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }'); + + return testObject.reloadConfiguration() + .then(() => { + actual = testObject.keys(); + assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1); + assert.deepEqual(actual.user, ['configurationService.folder.testSetting']); + assert.deepEqual(actual.workspace, ['configurationService.folder.testSetting']); + assert.deepEqual(actual.workspaceFolder, []); + }); + }); + }); + + test('update user configuration', () => { + return testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.USER) + .then(() => assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'value')); + }); + + test('update workspace configuration', () => { + return testObject.updateValue('tasks.service.testSetting', 'value', ConfigurationTarget.WORKSPACE) + .then(() => assert.equal(testObject.getValue('tasks.service.testSetting'), 'value')); + }); + + test('update tasks configuration', () => { + return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, ConfigurationTarget.WORKSPACE) + .then(() => assert.deepEqual(testObject.getValue('tasks'), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] })); + }); + + test('update user configuration should trigger change event before promise is resolve', () => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.USER) + .then(() => assert.ok(target.called)); + }); + + test('update workspace configuration should trigger change event before promise is resolve', () => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.WORKSPACE) + .then(() => assert.ok(target.called)); + }); + + test('update task configuration should trigger change event before promise is resolve', () => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, ConfigurationTarget.WORKSPACE) + .then(() => assert.ok(target.called)); + }); + + test('initialize with different folder triggers configuration event if there are changes', () => { + return setUpFolderWorkspace(`testWorkspace${uuid.generateUuid()}`) + .then(({ folderDir }) => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + + fs.writeFileSync(path.join(folderDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue2" }'); + return (testObject).initialize(folderDir) + .then(() => { + assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue2'); + assert.ok(target.called); + }); + }); + }); + + test('initialize with different folder triggers configuration event if there are no changes', () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "workspaceValue2" }'); + return testObject.reloadConfiguration() + .then(() => setUpFolderWorkspace(`testWorkspace${uuid.generateUuid()}`)) + .then(({ folderDir }) => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(() => target()); + fs.writeFileSync(path.join(folderDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue2" }'); + return (testObject).initialize(folderDir) + .then(() => { + assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue2'); + assert.ok(!target.called); + }); + }); + }); +}); + +suite('WorkspaceConfigurationService - Update (Multiroot)', () => { + + let parentResource: string, workspaceContextService: IWorkspaceContextService, jsonEditingServce: IJSONEditingService, testObject: IConfigurationService; + + suiteSetup(() => { + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.workspace.testSetting': { + 'type': 'string', + 'default': 'isSet' + }, + 'configurationService.workspace.testResourceSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.RESOURCE + } + } + }); + }); + + setup(() => { + return setUpWorkspace(['1', '2']) + .then(({ parentDir, configPath }) => { + + parentResource = parentDir; + + const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); + const workspaceService = new WorkspaceService(environmentService, null); + + const instantiationService = workbenchInstantiationService(); + instantiationService.stub(IWorkspaceContextService, workspaceService); + instantiationService.stub(IConfigurationService, workspaceService); + instantiationService.stub(IEnvironmentService, environmentService); + + return workspaceService.initialize({ id: configPath, configPath }).then(() => { + + instantiationService.stub(IFileService, new FileService(workspaceService, new TestTextResourceConfigurationService(), workspaceService, { disableWatcher: true })); + instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); + instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); + workspaceService.setInstantiationService(instantiationService); + + workspaceContextService = workspaceService; + jsonEditingServce = instantiationService.createInstance(JSONEditingService); + testObject = workspaceService; + }); + }); + }); + + teardown(done => { + if (testObject) { + (testObject).dispose(); + } + if (parentResource) { + extfs.del(parentResource, os.tmpdir(), () => { }, done); + } + }); + + test('update user configuration', () => { + return testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER) + .then(() => assert.equal(testObject.getValue('configurationService.workspace.testSetting'), 'userValue')); + }); + + test('update user configuration should trigger change event before promise is resolve', () => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER) + .then(() => assert.ok(target.called)); + }); + + test('update workspace configuration', () => { + return testObject.updateValue('configurationService.workspace.testSetting', 'workspaceValue', ConfigurationTarget.WORKSPACE) + .then(() => assert.equal(testObject.getValue('configurationService.workspace.testSetting'), 'workspaceValue')); + }); + + test('update workspace configuration should trigger change event before promise is resolve', () => { + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.updateValue('configurationService.workspace.testSetting', 'workspaceValue', ConfigurationTarget.WORKSPACE) + .then(() => assert.ok(target.called)); + }); + + test('update workspace folder configuration', () => { + const workspace = workspaceContextService.getWorkspace(); + return testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER) + .then(() => assert.equal(testObject.getValue('configurationService.workspace.testResourceSetting', { resource: workspace.folders[0].uri }), 'workspaceFolderValue')); + }); + + test('update workspace folder configuration should trigger change event before promise is resolve', () => { + const workspace = workspaceContextService.getWorkspace(); + const target = sinon.spy(); + testObject.onDidChangeConfiguration(target); + return testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER) + .then(() => assert.ok(target.called)); + }); + + test('update tasks configuration in a folder', () => { + const workspace = workspaceContextService.getWorkspace(); + return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER) + .then(() => assert.deepEqual(testObject.getValue('tasks', { resource: workspace.folders[0].uri }), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] })); + }); + + test('update tasks configuration in a workspace is not supported', () => { + const workspace = workspaceContextService.getWorkspace(); + return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true) + .then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET)); + }); + + test('update launch configuration in a workspace is not supported', () => { + const workspace = workspaceContextService.getWorkspace(); + return testObject.updateValue('launch', { 'version': '1.0.0', configurations: [{ 'name': 'myLaunch' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true) + .then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET)); + }); + + test('task configurations are not read from workspace', () => { + return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration, { key: 'tasks', value: { 'version': '1.0' } }, true) + .then(() => testObject.reloadConfiguration()) + .then(() => { + const actual = testObject.inspect('tasks.version'); + assert.equal(actual.workspace, void 0); + }); + }); + + test('launch configurations are not read from workspace', () => { + return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration, { key: 'launch', value: { 'version': '1.0' } }, true) + .then(() => testObject.reloadConfiguration()) + .then(() => { + const actual = testObject.inspect('launch.version'); + assert.equal(actual.workspace, void 0); + }); + }); +}); diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index a4d5f33a9ff..e2dc0febf79 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import uri from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { IStringDictionary } from 'vs/base/common/collections'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export const IConfigurationResolverService = createDecorator('configurationResolverService'); @@ -14,9 +14,9 @@ export interface IConfigurationResolverService { _serviceBrand: any; // TODO@Isidor improve this API - resolve(root: uri, value: string): string; - resolve(root: uri, value: string[]): string[]; - resolve(root: uri, value: IStringDictionary): IStringDictionary; - resolveAny(root: uri, value: T): T; + resolve(root: IWorkspaceFolder, value: string): string; + resolve(root: IWorkspaceFolder, value: string[]): string[]; + resolve(root: IWorkspaceFolder, value: IStringDictionary): IStringDictionary; + resolveAny(root: IWorkspaceFolder, value: T): T; resolveInteractiveVariables(configuration: any, interactiveVariablesMap: { [key: string]: string }): TPromise; } diff --git a/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts index e65a6cd14a4..80a59f403e7 100644 --- a/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import uri from 'vs/base/common/uri'; import * as paths from 'vs/base/common/paths'; import * as types from 'vs/base/common/types'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -14,13 +13,14 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { toResource } from 'vs/workbench/common/editor'; export class ConfigurationResolverService implements IConfigurationResolverService { _serviceBrand: any; private _execPath: string; - private _workspaceRoot: string; + private _lastWorkspaceFolder: IWorkspaceFolder; constructor( envVariables: { [key: string]: string }, @@ -40,14 +40,26 @@ export class ConfigurationResolverService implements IConfigurationResolverServi } private get cwd(): string { - return this.workspaceRoot; + if (this.workspaceRoot) { + return this.workspaceRoot; + } else { + return process.cwd(); + } } private get workspaceRoot(): string { - return this._workspaceRoot; + return this._lastWorkspaceFolder ? this._lastWorkspaceFolder.uri.fsPath : undefined; + } + + private get workspaceFolder(): string { + return this.workspaceRoot; } private get workspaceRootFolderName(): string { + return this.workspaceFolderBasename; + } + + private get workspaceFolderBasename(): string { return this.workspaceRoot ? paths.basename(this.workspaceRoot) : ''; } @@ -101,37 +113,43 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return paths.normalize(fileResource.fsPath, true); } - public resolve(root: uri, value: string): string; - public resolve(root: uri, value: string[]): string[]; - public resolve(root: uri, value: IStringDictionary): IStringDictionary; - public resolve(root: uri, value: any): any { - this._workspaceRoot = root.fsPath.toString(); - if (types.isString(value)) { - return this.resolveString(root, value); - } else if (types.isArray(value)) { - return this.resolveArray(root, value); - } else if (types.isObject(value)) { - return this.resolveLiteral(root, value); + public resolve(root: IWorkspaceFolder, value: string): string; + public resolve(root: IWorkspaceFolder, value: string[]): string[]; + public resolve(root: IWorkspaceFolder, value: IStringDictionary): IStringDictionary; + public resolve(root: IWorkspaceFolder, value: any): any { + try { + this._lastWorkspaceFolder = root; + if (types.isString(value)) { + return this.resolveString(root, value); + } else if (types.isArray(value)) { + return this.resolveArray(root, value); + } else if (types.isObject(value)) { + return this.resolveLiteral(root, value); + } + return value; + } finally { + this._lastWorkspaceFolder = undefined; } - - return value; } - public resolveAny(root: uri, value: T): T; - public resolveAny(root: uri, value: any): any { - this._workspaceRoot = root.fsPath.toString(); - if (types.isString(value)) { - return this.resolveString(root, value); - } else if (types.isArray(value)) { - return this.resolveAnyArray(root, value); - } else if (types.isObject(value)) { - return this.resolveAnyLiteral(root, value); + public resolveAny(root: IWorkspaceFolder, value: T): T; + public resolveAny(root: IWorkspaceFolder, value: any): any { + try { + this._lastWorkspaceFolder = root; + if (types.isString(value)) { + return this.resolveString(root, value); + } else if (types.isArray(value)) { + return this.resolveAnyArray(root, value); + } else if (types.isObject(value)) { + return this.resolveAnyLiteral(root, value); + } + return value; + } finally { + this._lastWorkspaceFolder = undefined; } - - return value; } - private resolveString(root: uri, value: string): string { + private resolveString(root: IWorkspaceFolder, value: string): string { let regexp = /\$\{(.*?)\}/g; const originalValue = value; const resolvedString = value.replace(regexp, (match: string, name: string) => { @@ -146,9 +164,9 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return this.resolveConfigVariable(root, resolvedString, originalValue); } - private resolveConfigVariable(root: uri, value: string, originalValue: string): string { + private resolveConfigVariable(root: IWorkspaceFolder, value: string, originalValue: string): string { const replacer = (match: string, name: string) => { - let config = this.configurationService.getConfiguration(); + let config = this.configurationService.getConfiguration({ resource: root.uri }); let newValue: any; try { const keys: string[] = name.split('.'); @@ -177,7 +195,7 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return value.replace(/\$\{config:(.+?)\}/g, replacer); } - private resolveLiteral(root: uri, values: IStringDictionary | string[]>): IStringDictionary | string[]> { + private resolveLiteral(root: IWorkspaceFolder, values: IStringDictionary | string[]>): IStringDictionary | string[]> { let result: IStringDictionary | string[]> = Object.create(null); Object.keys(values).forEach(key => { let value = values[key]; @@ -186,8 +204,8 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return result; } - private resolveAnyLiteral(root: uri, values: T): T; - private resolveAnyLiteral(root: uri, values: any): any { + private resolveAnyLiteral(root: IWorkspaceFolder, values: T): T; + private resolveAnyLiteral(root: IWorkspaceFolder, values: any): any { let result: IStringDictionary | string[]> = Object.create(null); Object.keys(values).forEach(key => { let value = values[key]; @@ -196,12 +214,12 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return result; } - private resolveArray(root: uri, value: string[]): string[] { + private resolveArray(root: IWorkspaceFolder, value: string[]): string[] { return value.map(s => this.resolveString(root, s)); } - private resolveAnyArray(root: uri, value: T[]): T[]; - private resolveAnyArray(root: uri, value: any[]): any[] { + private resolveAnyArray(root: IWorkspaceFolder, value: T[]): T[]; + private resolveAnyArray(root: IWorkspaceFolder, value: any[]): any[] { return value.map(s => this.resolveAny(root, s)); } diff --git a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts index 12fc724a449..a7ad4e84a3f 100644 --- a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts @@ -7,10 +7,11 @@ import assert = require('assert'); import uri from 'vs/base/common/uri'; import platform = require('vs/base/common/platform'); import { TPromise } from 'vs/base/common/winjs.base'; -import { IConfigurationService, getConfigurationValue, IConfigurationOverrides, IConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, getConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/node/configurationResolverService'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { TestEnvironmentService, TestEditorService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -19,13 +20,18 @@ suite('Configuration Resolver Service', () => { let envVariables: { [key: string]: string } = { key1: 'Value for Key1', key2: 'Value for Key2' }; let mockCommandService: MockCommandService; let editorService: TestEditorService; - let workspaceUri: uri; + let workspace: IWorkspaceFolder; setup(() => { mockCommandService = new MockCommandService(); editorService = new TestEditorService(); - workspaceUri = uri.parse('file:///VSCode/workspaceLocation'); + workspace = { + uri: uri.parse('file:///VSCode/workspaceLocation'), + name: 'hey', + index: 0, + toResource: () => null + }; configurationResolverService = new ConfigurationResolverService(envVariables, editorService, TestEnvironmentService, new TestConfigurationService(), mockCommandService); }); @@ -36,41 +42,41 @@ suite('Configuration Resolver Service', () => { test('substitute one', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} xyz'), 'abc \\VSCode\\workspaceLocation xyz'); + assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc \\VSCode\\workspaceLocation xyz'); } else { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} xyz'), 'abc /VSCode/workspaceLocation xyz'); + assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc /VSCode/workspaceLocation xyz'); } }); test('workspace root folder name', () => { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz'); + assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz'); }); test('current selected line number', () => { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`); + assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`); }); test('substitute many', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation'); + assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation'); } else { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation'); + assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation'); } }); test('substitute one env variable', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} ${env:key1} xyz'), 'abc \\VSCode\\workspaceLocation Value for Key1 xyz'); + assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc \\VSCode\\workspaceLocation Value for Key1 xyz'); } else { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, 'abc ${workspaceRoot} ${env:key1} xyz'), 'abc /VSCode/workspaceLocation Value for Key1 xyz'); + assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc /VSCode/workspaceLocation Value for Key1 xyz'); } }); test('substitute many env variable', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for Key1 - Value for Key2'); + assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for Key1 - Value for Key2'); } else { - assert.strictEqual(configurationResolverService.resolve(workspaceUri, '${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation Value for Key1 - Value for Key2'); + assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation Value for Key1 - Value for Key2'); } }); @@ -88,7 +94,7 @@ suite('Configuration Resolver Service', () => { }); let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz'); }); test('substitute many configuration variables', () => { @@ -105,14 +111,14 @@ suite('Configuration Resolver Service', () => { }); let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo bar xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo bar xyz'); }); test('substitute nested configuration variables', () => { let configurationService: IConfigurationService; configurationService = new MockConfigurationService({ editor: { - fontFamily: 'foo ${workspaceRoot} ${config:terminal.integrated.fontFamily}' + fontFamily: 'foo ${workspaceFolder} ${config:terminal.integrated.fontFamily}' }, terminal: { integrated: { @@ -123,9 +129,9 @@ suite('Configuration Resolver Service', () => { let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); if (platform.isWindows) { - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz'); } else { - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz'); } }); @@ -133,7 +139,7 @@ suite('Configuration Resolver Service', () => { let configurationService: IConfigurationService; configurationService = new MockConfigurationService({ editor: { - fontFamily: 'foo ${workspaceRoot} ${config:terminal.integrated.fontFamily} ${config:editor.fontFamily}' + fontFamily: 'foo ${workspaceFolder} ${config:terminal.integrated.fontFamily} ${config:editor.fontFamily}' }, terminal: { integrated: { @@ -144,9 +150,9 @@ suite('Configuration Resolver Service', () => { let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); if (platform.isWindows) { - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo \\VSCode\\workspaceLocation bar bar xyz'); } else { - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo /VSCode/workspaceLocation bar bar xyz'); } }); @@ -165,9 +171,9 @@ suite('Configuration Resolver Service', () => { let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); if (platform.isWindows) { - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${workspaceRoot} ${env:key1} xyz'), 'abc foo \\VSCode\\workspaceLocation Value for Key1 xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${workspaceFolder} ${env:key1} xyz'), 'abc foo \\VSCode\\workspaceLocation Value for Key1 xyz'); } else { - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${workspaceRoot} ${env:key1} xyz'), 'abc foo /VSCode/workspaceLocation Value for Key1 xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${workspaceFolder} ${env:key1} xyz'), 'abc foo /VSCode/workspaceLocation Value for Key1 xyz'); } }); @@ -186,9 +192,9 @@ suite('Configuration Resolver Service', () => { let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); if (platform.isWindows) { - assert.strictEqual(service.resolve(workspaceUri, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), 'foo bar \\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for Key1 - Value for Key2'); + assert.strictEqual(service.resolve(workspace, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), 'foo bar \\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for Key1 - Value for Key2'); } else { - assert.strictEqual(service.resolve(workspaceUri, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceRoot} - ${workspaceRoot} ${env:key1} - ${env:key2}'), 'foo bar /VSCode/workspaceLocation - /VSCode/workspaceLocation Value for Key1 - Value for Key2'); + assert.strictEqual(service.resolve(workspace, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), 'foo bar /VSCode/workspaceLocation - /VSCode/workspaceLocation Value for Key1 - Value for Key2'); } }); @@ -219,7 +225,7 @@ suite('Configuration Resolver Service', () => { }); let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz'); }); test('configuration should not evaluate Javascript', () => { @@ -231,7 +237,7 @@ suite('Configuration Resolver Service', () => { }); let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor[\'abc\'.substr(0)]} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor[\'abc\'.substr(0)]} xyz'), 'abc xyz'); }); test('uses empty string as fallback', () => { @@ -241,10 +247,10 @@ suite('Configuration Resolver Service', () => { }); let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.abc} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.abc.def} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:panel} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:panel.abc} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.abc} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.abc.def} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:panel} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:panel.abc} xyz'), 'abc xyz'); }); test('is restricted to own properties', () => { @@ -254,8 +260,8 @@ suite('Configuration Resolver Service', () => { }); let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.__proto__} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.toString} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.__proto__} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.toString} xyz'), 'abc xyz'); }); test('configuration variables with invalid accessor', () => { @@ -267,9 +273,9 @@ suite('Configuration Resolver Service', () => { }); let service = new ConfigurationResolverService(envVariables, new TestEditorService(), TestEnvironmentService, configurationService, mockCommandService); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:} xyz'), 'abc ${config:} xyz'); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor..fontFamily} xyz'), 'abc xyz'); - assert.strictEqual(service.resolve(workspaceUri, 'abc ${config:editor.none.none2} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:} xyz'), 'abc ${config:} xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor..fontFamily} xyz'), 'abc xyz'); + assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.none.none2} xyz'), 'abc xyz'); }); test('interactive variable simple', () => { @@ -342,13 +348,14 @@ class MockConfigurationService implements IConfigurationService { public _serviceBrand: any; public serviceId = IConfigurationService; public constructor(private configuration: any = {}) { } - public reloadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); } - public lookup(key: string, overrides?: IConfigurationOverrides): IConfigurationValue { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspace: void 0, folder: void 0 }; } - public keys() { return { default: [], user: [], workspace: [], folder: [] }; } - public values() { return {}; } + public inspect(key: string, overrides?: IConfigurationOverrides): any { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key), workspaceFolder: void 0, folder: void 0 }; } + public keys() { return { default: [], user: [], workspace: [], workspaceFolder: [] }; } public getConfiguration(): any { return this.configuration; } + public getValue(key: string): any { return getConfigurationValue(this.getConfiguration(), key); } + public updateValue(): TPromise { return null; } public getConfigurationData(): any { return null; } - public onDidUpdateConfiguration() { return { dispose() { } }; } + public onDidChangeConfiguration() { return { dispose() { } }; } + public reloadConfiguration() { return null; } } class MockCommandService implements ICommandService { @@ -357,8 +364,7 @@ class MockCommandService implements ICommandService { public callCount = 0; onWillExecuteCommand = () => ({ dispose: () => { } }); - - public executeCommand(commandId: string, ...args: any[]): TPromise { + public executeCommand(commandId: string, ...args: any[]): TPromise { this.callCount++; return TPromise.as(commandId); } diff --git a/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts index 9bc00e11185..d6e303791af 100644 --- a/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextview/electron-browser/contextmenuService.ts @@ -47,7 +47,7 @@ export class ContextMenuService implements IContextMenuService { y = elementPosition.top + elementPosition.height; } else { const pos = <{ x: number; y: number; }>anchor; - x = pos.x; + x = pos.x + 1; /* prevent first item from being selected automatically under mouse */ y = pos.y; } @@ -55,7 +55,7 @@ export class ContextMenuService implements IContextMenuService { x *= zoom; y *= zoom; - menu.popup(remote.getCurrentWindow(), Math.floor(x), Math.floor(y)); + menu.popup(remote.getCurrentWindow(), { x: Math.floor(x), y: Math.floor(y), positioningItem: delegate.autoSelectFirstItem ? 0 : void 0 }); if (delegate.onHide) { delegate.onHide(undefined); } @@ -78,7 +78,7 @@ export class ContextMenuService implements IContextMenuService { menu.append(submenu); } else { - const options: Electron.MenuItemOptions = { + const options: Electron.MenuItemConstructorOptions = { label: unmnemonicLabel(e.label), checked: !!e.checked || !!e.radio, type: !!e.checked ? 'checkbox' : !!e.radio ? 'radio' : void 0, @@ -111,6 +111,12 @@ export class ContextMenuService implements IContextMenuService { } private runAction(actionRunner: IActionRunner, actionToRun: IAction, delegate: IContextMenuDelegate, event: IEvent): void { + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: actionToRun.id, from: 'contextMenu' }); const context = delegate.getActionsContext ? delegate.getActionsContext(event) : event; diff --git a/src/vs/workbench/services/crashReporter/common/crashReporterService.ts b/src/vs/workbench/services/crashReporter/common/crashReporterService.ts deleted file mode 100644 index 4ee9d234d9d..00000000000 --- a/src/vs/workbench/services/crashReporter/common/crashReporterService.ts +++ /dev/null @@ -1,43 +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 nls = require('vs/nls'); -import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -export const ICrashReporterService = createDecorator('crashReporterService'); - -export const TELEMETRY_SECTION_ID = 'telemetry'; - -export interface ICrashReporterConfig { - enableCrashReporter: boolean; -} - -const configurationRegistry = Registry.as(Extensions.Configuration); -configurationRegistry.registerConfiguration({ - 'id': TELEMETRY_SECTION_ID, - 'order': 110, - title: nls.localize('telemetryConfigurationTitle', "Telemetry"), - 'type': 'object', - 'properties': { - 'telemetry.enableCrashReporter': { - 'type': 'boolean', - 'description': nls.localize('telemetry.enableCrashReporting', "Enable crash reports to be sent to Microsoft.\nThis option requires restart to take effect."), - 'default': true - } - } -}); - -export interface ICrashReporterService { - _serviceBrand: any; - getChildProcessStartOptions(processName: string): Electron.CrashReporterStartOptions; -} - -export const NullCrashReporterService: ICrashReporterService = { - _serviceBrand: undefined, - getChildProcessStartOptions(processName: string) { return undefined; } -}; \ No newline at end of file diff --git a/src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts b/src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts index 096c578d77f..d04c2c33c50 100644 --- a/src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts +++ b/src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import nls = require('vs/nls'); import { onUnexpectedError } from 'vs/base/common/errors'; import { assign, clone } from 'vs/base/common/objects'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -13,8 +14,43 @@ import { crashReporter } from 'electron'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; import * as os from 'os'; -import { ICrashReporterService, TELEMETRY_SECTION_ID, ICrashReporterConfig } from 'vs/workbench/services/crashReporter/common/crashReporterService'; import { isWindows, isMacintosh, isLinux } from 'vs/base/common/platform'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; + +export const ICrashReporterService = createDecorator('crashReporterService'); + +export const TELEMETRY_SECTION_ID = 'telemetry'; + +export interface ICrashReporterConfig { + enableCrashReporter: boolean; +} + +const configurationRegistry = Registry.as(Extensions.Configuration); +configurationRegistry.registerConfiguration({ + 'id': TELEMETRY_SECTION_ID, + 'order': 110, + title: nls.localize('telemetryConfigurationTitle', "Telemetry"), + 'type': 'object', + 'properties': { + 'telemetry.enableCrashReporter': { + 'type': 'boolean', + 'description': nls.localize('telemetry.enableCrashReporting', "Enable crash reports to be sent to Microsoft.\nThis option requires restart to take effect."), + 'default': true + } + } +}); + +export interface ICrashReporterService { + _serviceBrand: any; + getChildProcessStartOptions(processName: string): Electron.CrashReporterStartOptions; // TODO +} + +export const NullCrashReporterService: ICrashReporterService = { + _serviceBrand: undefined, + getChildProcessStartOptions(processName: string) { return undefined; } +}; export class CrashReporterService implements ICrashReporterService { diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts new file mode 100644 index 00000000000..1ce66c0408d --- /dev/null +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import URI from 'vs/base/common/uri'; +import Event from 'vs/base/common/event'; +import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; +import { IDisposable } from 'vs/base/common/lifecycle'; + +export const IDecorationsService = createDecorator('IFileDecorationsService'); + +export interface IDecorationData { + readonly weight?: number; + readonly color?: ColorIdentifier; + readonly letter?: string; + readonly tooltip?: string; + readonly bubble?: boolean; + readonly source?: string; +} + +export interface IDecoration { + readonly tooltip: string; + readonly labelClassName: string; + readonly badgeClassName: string; + update(source?: string, data?: IDecorationData): IDecoration; +} + +export interface IDecorationsProvider { + readonly label: string; + readonly onDidChange: Event; + provideDecorations(uri: URI): IDecorationData | Thenable; +} + +export interface IResourceDecorationChangeEvent { + affectsResource(uri: URI): boolean; +} + +export interface IDecorationsService { + + readonly _serviceBrand: any; + + readonly onDidChangeDecorations: Event; + + registerDecorationsProvider(provider: IDecorationsProvider): IDisposable; + + getDecoration(uri: URI, includeChildren: boolean, overwrite?: IDecorationData): IDecoration; +} diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts new file mode 100644 index 00000000000..242a1b9c5c3 --- /dev/null +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -0,0 +1,420 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; +import Event, { Emitter, debounceEvent, anyEvent } from 'vs/base/common/event'; +import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; +import { TernarySearchTree } from 'vs/base/common/map'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { isThenable } from 'vs/base/common/async'; +import { LinkedList } from 'vs/base/common/linkedList'; +import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; +import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; +import { IdGenerator } from 'vs/base/common/idGenerator'; +import { IIterator } from 'vs/base/common/iterator'; +import { isFalsyOrWhitespace } from 'vs/base/common/strings'; +import { localize } from 'vs/nls'; + +class DecorationRule { + + static keyOf(data: IDecorationData | IDecorationData[]): string { + if (Array.isArray(data)) { + return data.map(DecorationRule.keyOf).join(','); + } else { + const { color, letter } = data; + return `${color}/${letter}`; + } + } + + private static readonly _classNames = new IdGenerator('monaco-decorations-style-'); + + readonly data: IDecorationData | IDecorationData[]; + readonly itemColorClassName: string; + readonly itemBadgeClassName: string; + readonly bubbleBadgeClassName: string; + + constructor(data: IDecorationData | IDecorationData[]) { + this.data = data; + this.itemColorClassName = DecorationRule._classNames.nextId(); + this.itemBadgeClassName = DecorationRule._classNames.nextId(); + this.bubbleBadgeClassName = DecorationRule._classNames.nextId(); + } + + appendCSSRules(element: HTMLStyleElement, theme: ITheme): void { + if (!Array.isArray(this.data)) { + this._appendForOne(this.data, element, theme); + } else { + this._appendForMany(this.data, element, theme); + } + } + + private _appendForOne(data: IDecorationData, element: HTMLStyleElement, theme: ITheme): void { + const { color, letter } = data; + // label + createCSSRule(`.${this.itemColorClassName}`, `color: ${theme.getColor(color) || 'inherit'};`, element); + // letter + if (letter) { + createCSSRule(`.${this.itemBadgeClassName}::after`, `content: "${letter}"; color: ${theme.getColor(color) || 'inherit'};`, element); + } + } + + private _appendForMany(data: IDecorationData[], element: HTMLStyleElement, theme: ITheme): void { + // label + const { color } = data[0]; + createCSSRule(`.${this.itemColorClassName}`, `color: ${theme.getColor(color) || 'inherit'};`, element); + + // badge + const letters = data.filter(d => !isFalsyOrWhitespace(d.letter)).map(d => d.letter); + if (letters.length) { + createCSSRule(`.${this.itemBadgeClassName}::after`, `content: "${letters.join(', ')}"; color: ${theme.getColor(color) || 'inherit'};`, element); + } + + // bubble badge + createCSSRule( + `.${this.bubbleBadgeClassName}::after`, + `content: "\uf052"; color: ${theme.getColor(color) || 'inherit'}; font-family: octicons; font-size: 14px; padding-right: 14px; opacity: 0.4;`, + element + ); + } + + removeCSSRules(element: HTMLStyleElement): void { + removeCSSRulesContainingSelector(this.itemColorClassName, element); + removeCSSRulesContainingSelector(this.itemBadgeClassName, element); + removeCSSRulesContainingSelector(this.bubbleBadgeClassName, element); + } + + isUnused(): boolean { + return !document.querySelector(`.${this.itemColorClassName}`) + && !document.querySelector(`.${this.itemBadgeClassName}`) + && !document.querySelector(`.${this.bubbleBadgeClassName}`); + } +} + +class DecorationStyles { + + private readonly _disposables: IDisposable[]; + private readonly _styleElement = createStyleSheet(); + private readonly _decorationRules = new Map(); + + constructor( + private _themeService: IThemeService, + ) { + this._disposables = [this._themeService.onThemeChange(this._onThemeChange, this)]; + } + + dispose(): void { + dispose(this._disposables); + this._styleElement.parentElement.removeChild(this._styleElement); + } + + asDecoration(data: IDecorationData[], onlyChildren: boolean): IDecoration { + + // sort by weight + data.sort((a, b) => b.weight - a.weight); + + let key = DecorationRule.keyOf(data); + let rule = this._decorationRules.get(key); + + if (!rule) { + // new css rule + rule = new DecorationRule(data); + this._decorationRules.set(key, rule); + rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); + } + + let labelClassName = rule.itemColorClassName; + let badgeClassName = rule.itemBadgeClassName; + let tooltip = data.filter(d => !isFalsyOrWhitespace(d.tooltip)).map(d => d.tooltip).join(' • '); + + if (onlyChildren) { + // show items from its children only + badgeClassName = rule.bubbleBadgeClassName; + tooltip = localize('bubbleTitle', "contains emphasized items"); + } + + return { + labelClassName, + badgeClassName, + tooltip, + update: (source, insert) => { + let newData = data.slice(); + if (!source) { + // add -> just append + newData.push(insert); + + } else { + // remove/replace -> require a walk + for (let i = 0; i < newData.length; i++) { + if (newData[i].source === source) { + if (!insert) { + // remove + newData.splice(i, 1); + i--; + } else { + // replace + newData[i] = insert; + } + } + } + } + return this.asDecoration(newData, onlyChildren); + } + }; + } + + private _onThemeChange(): void { + this._decorationRules.forEach(rule => { + rule.removeCSSRules(this._styleElement); + rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); + }); + } + + cleanUp(iter: IIterator): void { + // remove every rule for which no more + // decoration (data) is kept. this isn't cheap + let usedDecorations = new Set(); + for (let e = iter.next(); !e.done; e = iter.next()) { + e.value.data.forEach((value, key) => { + if (!isThenable(value) && value) { + usedDecorations.add(DecorationRule.keyOf(value)); + } + }); + } + this._decorationRules.forEach((value, index) => { + const { data } = value; + if (value.isUnused()) { + let remove: boolean; + if (Array.isArray(data)) { + remove = data.some(data => !usedDecorations.has(DecorationRule.keyOf(data))); + } else if (!usedDecorations.has(DecorationRule.keyOf(data))) { + remove = true; + } + if (remove) { + value.removeCSSRules(this._styleElement); + this._decorationRules.delete(index); + } + } + }); + } +} + +class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { + + private readonly _data = TernarySearchTree.forPaths(); + + affectsResource(uri: URI): boolean { + return this._data.get(uri.toString()) || this._data.findSuperstr(uri.toString()) !== undefined; + } + + static debouncer(last: FileDecorationChangeEvent, current: URI | URI[]) { + if (!last) { + last = new FileDecorationChangeEvent(); + } + if (Array.isArray(current)) { + // many + for (const uri of current) { + last._data.set(uri.toString(), true); + } + } else { + // one + last._data.set(current.toString(), true); + } + + return last; + } +} + +class DecorationProviderWrapper { + + readonly data = TernarySearchTree.forPaths | IDecorationData>(); + private readonly _dispoable: IDisposable; + + constructor( + private readonly _provider: IDecorationsProvider, + private readonly _uriEmitter: Emitter, + private readonly _flushEmitter: Emitter + ) { + this._dispoable = this._provider.onDidChange(uris => { + if (!uris) { + // flush event -> drop all data, can affect everything + this.data.clear(); + this._flushEmitter.fire({ affectsResource() { return true; } }); + + } else { + // selective changes -> drop for resource, fetch again, send event + for (const uri of uris) { + this.data.delete(uri.toString()); + this._fetchData(uri); + } + } + }); + } + + dispose(): void { + this._dispoable.dispose(); + this.data.clear(); + } + + knowsAbout(uri: URI): boolean { + return Boolean(this.data.get(uri.toString())) || Boolean(this.data.findSuperstr(uri.toString())); + } + + getOrRetrieve(uri: URI, includeChildren: boolean, callback: (data: IDecorationData, isChild: boolean) => void): void { + const key = uri.toString(); + let item = this.data.get(key); + + if (isThenable(item)) { + // pending -> still waiting + return; + } + + if (item === undefined) { + // unknown -> trigger request + item = this._fetchData(uri); + } + + if (item) { + // found something + callback(item, false); + } + + if (includeChildren) { + // (resolved) children + const childTree = this.data.findSuperstr(key); + if (childTree) { + childTree.forEach(value => { + if (value && !isThenable(value)) { + callback(value, true); + } + }); + } + } + } + + private _fetchData(uri: URI): IDecorationData { + + const dataOrThenable = this._provider.provideDecorations(uri); + if (!isThenable(dataOrThenable)) { + // sync -> we have a result now + return this._keepItem(uri, dataOrThenable); + + } else { + // async -> we have a result soon + const request = Promise.resolve(dataOrThenable) + .then(data => this._keepItem(uri, data)) + .catch(_ => this.data.delete(uri.toString())); + + this.data.set(uri.toString(), request); + return undefined; + } + } + + private _keepItem(uri: URI, data: IDecorationData): IDecorationData { + let deco = data ? data : null; + this.data.set(uri.toString(), deco); + this._uriEmitter.fire(uri); + return deco; + } +} + +export class FileDecorationsService implements IDecorationsService { + + _serviceBrand: any; + + private readonly _data = new LinkedList(); + private readonly _onDidChangeDecorationsDelayed = new Emitter(); + private readonly _onDidChangeDecorations = new Emitter(); + private readonly _decorationStyles: DecorationStyles; + private readonly _disposables: IDisposable[]; + + readonly onDidChangeDecorations: Event = anyEvent( + this._onDidChangeDecorations.event, + debounceEvent( + this._onDidChangeDecorationsDelayed.event, + FileDecorationChangeEvent.debouncer + ) + ); + + constructor( + @IThemeService themeService: IThemeService, + cleanUpCount: number = 17 + ) { + this._decorationStyles = new DecorationStyles(themeService); + + // every so many events we check if there are + // css styles that we don't need anymore + let count = 0; + let reg = this.onDidChangeDecorations(() => { + if (++count % cleanUpCount === 0) { + this._decorationStyles.cleanUp(this._data.iterator()); + } + }); + + this._disposables = [ + reg, + this._decorationStyles + ]; + } + + dispose(): void { + dispose(this._disposables); + } + + registerDecorationsProvider(provider: IDecorationsProvider): IDisposable { + + const wrapper = new DecorationProviderWrapper( + provider, + this._onDidChangeDecorationsDelayed, + this._onDidChangeDecorations + ); + const remove = this._data.push(wrapper); + + this._onDidChangeDecorations.fire({ + // everything might have changed + affectsResource() { return true; } + }); + + return { + dispose: () => { + // fire event that says 'yes' for any resource + // known to this provider. then dispose and remove it. + remove(); + this._onDidChangeDecorations.fire({ affectsResource: uri => wrapper.knowsAbout(uri) }); + wrapper.dispose(); + } + }; + } + + getDecoration(uri: URI, includeChildren: boolean, overwrite?: IDecorationData): IDecoration { + let data: IDecorationData[] = []; + let containsChildren: boolean; + for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { + next.value.getOrRetrieve(uri, includeChildren, (deco, isChild) => { + if (!isChild || deco.bubble) { + data.push(deco); + containsChildren = isChild || containsChildren; + } + }); + } + + if (data.length === 0) { + // nothing, maybe overwrite data + if (overwrite) { + return this._decorationStyles.asDecoration([overwrite], containsChildren); + } else { + return undefined; + } + } else { + // result, maybe overwrite + let result = this._decorationStyles.asDecoration(data, containsChildren); + if (overwrite) { + return result.update(overwrite.source, overwrite); + } else { + return result; + } + } + } +} diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts new file mode 100644 index 00000000000..9c0a15d8bb3 --- /dev/null +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -0,0 +1,171 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; +import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; +import URI from 'vs/base/common/uri'; +import Event, { toPromise } from 'vs/base/common/event'; +import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; + +suite('DecorationsService', function () { + + let service: FileDecorationsService; + + setup(function () { + if (service) { + service.dispose(); + } + service = new FileDecorationsService(new TestThemeService()); + }); + + test('Async provider, async/evented result', function () { + + let uri = URI.parse('foo:bar'); + let callCounter = 0; + + service.registerDecorationsProvider(new class implements IDecorationsProvider { + readonly label: string = 'Test'; + readonly onDidChange: Event = Event.None; + provideDecorations(uri: URI) { + callCounter += 1; + return new Promise(resolve => { + setTimeout(() => resolve({ + color: 'someBlue', + tooltip: 'T' + })); + }); + } + }); + + // trigger -> async + assert.equal(service.getDecoration(uri, false), undefined); + assert.equal(callCounter, 1); + + // event when result is computed + return toPromise(service.onDidChangeDecorations).then(e => { + assert.equal(e.affectsResource(uri), true); + + // sync result + assert.deepEqual(service.getDecoration(uri, false).tooltip, 'T'); + assert.equal(callCounter, 1); + }); + }); + + test('Sync provider, sync result', function () { + + let uri = URI.parse('foo:bar'); + let callCounter = 0; + + service.registerDecorationsProvider(new class implements IDecorationsProvider { + readonly label: string = 'Test'; + readonly onDidChange: Event = Event.None; + provideDecorations(uri: URI) { + callCounter += 1; + return { color: 'someBlue', tooltip: 'Z' }; + } + }); + + // trigger -> sync + assert.deepEqual(service.getDecoration(uri, false).tooltip, 'Z'); + assert.equal(callCounter, 1); + }); + + test('Clear decorations on provider dispose', function () { + let uri = URI.parse('foo:bar'); + let callCounter = 0; + + let reg = service.registerDecorationsProvider(new class implements IDecorationsProvider { + readonly label: string = 'Test'; + readonly onDidChange: Event = Event.None; + provideDecorations(uri: URI) { + callCounter += 1; + return { color: 'someBlue', tooltip: 'J' }; + } + }); + + // trigger -> sync + assert.deepEqual(service.getDecoration(uri, false).tooltip, 'J'); + assert.equal(callCounter, 1); + + // un-register -> ensure good event + let didSeeEvent = false; + service.onDidChangeDecorations(e => { + assert.equal(e.affectsResource(uri), true); + assert.deepEqual(service.getDecoration(uri, false), undefined); + assert.equal(callCounter, 1); + didSeeEvent = true; + }); + reg.dispose(); + assert.equal(didSeeEvent, true); + }); + + test('No default bubbling', function () { + + let reg = service.registerDecorationsProvider({ + label: 'Test', + onDidChange: Event.None, + provideDecorations(uri: URI) { + return uri.path.match(/\.txt/) + ? { tooltip: '.txt', weight: 17 } + : undefined; + } + }); + + let childUri = URI.parse('file:///some/path/some/file.txt'); + + let deco = service.getDecoration(childUri, false); + assert.equal(deco.tooltip, '.txt'); + + deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); + assert.equal(deco, undefined); + reg.dispose(); + + // bubble + reg = service.registerDecorationsProvider({ + label: 'Test', + onDidChange: Event.None, + provideDecorations(uri: URI) { + return uri.path.match(/\.txt/) + ? { tooltip: '.txt.bubble', weight: 71, bubble: true } + : undefined; + } + }); + + deco = service.getDecoration(childUri, false); + assert.equal(deco.tooltip, '.txt.bubble'); + + deco = service.getDecoration(childUri.with({ path: 'some/path/' }), true); + assert.equal(typeof deco.tooltip, 'string'); + }); + + test('Overwrite data', function () { + + let someUri = URI.parse('file:///some/path/some/file.txt'); + let deco = service.getDecoration(someUri, false); + assert.equal(deco, undefined); + + deco = service.getDecoration(someUri, false, { tooltip: 'Overwrite' }); + assert.equal(deco.tooltip, 'Overwrite'); + + let reg = service.registerDecorationsProvider({ + label: 'Test', + onDidChange: Event.None, + provideDecorations(uri: URI) { + return { tooltip: 'FromMe', source: 'foo' }; + } + }); + + deco = service.getDecoration(someUri, false); + assert.equal(deco.tooltip, 'FromMe'); + + deco = service.getDecoration(someUri, false, { source: 'foo', tooltip: 'O' }); + assert.equal(deco.tooltip, 'O'); + + reg.dispose(); + }); +}); diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts deleted file mode 100644 index f2ac5bbf146..00000000000 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ /dev/null @@ -1,362 +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 { TPromise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; -import network = require('vs/base/common/network'); -import { Registry } from 'vs/platform/registry/common/platform'; -import { basename, dirname } from 'vs/base/common/paths'; -import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorInput, EditorOptions, TextEditorOptions, IEditorRegistry, Extensions, SideBySideEditorInput, IFileEditorInput, IFileInputFactory } from 'vs/workbench/common/editor'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; -import { IUntitledEditorService, UNTITLED_SCHEMA } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IEditor, IResourceInput, IResourceDiffInput, IResourceSideBySideInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import nls = require('vs/nls'); -import { getPathLabel } from 'vs/base/common/labels'; -import { ResourceMap } from 'vs/base/common/map'; -import { once } from 'vs/base/common/event'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; - -export interface IEditorPart { - openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, sideBySide?: boolean): TPromise; - openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, position?: Position): TPromise; - openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions | ITextEditorOptions }[]): TPromise; - replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions | ITextEditorOptions }[], position?: Position): TPromise; - closeEditor(position: Position, input: IEditorInput): TPromise; - closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise; - closeAllEditors(except?: Position): TPromise; - getActiveEditor(): BaseEditor; - getVisibleEditors(): IEditor[]; - getActiveEditorInput(): IEditorInput; -} - -type ICachedEditorInput = ResourceEditorInput | IFileEditorInput; - -export class WorkbenchEditorService implements IWorkbenchEditorService { - - public _serviceBrand: any; - - private static CACHE: ResourceMap = new ResourceMap(); - - private editorPart: IEditorPart | IWorkbenchEditorService; - private fileInputFactory: IFileInputFactory; - - constructor( - editorPart: IEditorPart | IWorkbenchEditorService, - @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IInstantiationService private instantiationService: IInstantiationService, - @IEnvironmentService private environmentService: IEnvironmentService - ) { - this.editorPart = editorPart; - this.fileInputFactory = Registry.as(Extensions.Editors).getFileInputFactory(); - } - - public getActiveEditor(): IEditor { - return this.editorPart.getActiveEditor(); - } - - public getActiveEditorInput(): IEditorInput { - return this.editorPart.getActiveEditorInput(); - } - - public getVisibleEditors(): IEditor[] { - return this.editorPart.getVisibleEditors(); - } - - public isVisible(input: IEditorInput, includeSideBySide: boolean): boolean { - if (!input) { - return false; - } - - return this.getVisibleEditors().some(editor => { - if (!editor.input) { - return false; - } - - if (input.matches(editor.input)) { - return true; - } - - if (includeSideBySide && editor.input instanceof SideBySideEditorInput) { - const sideBySideInput = editor.input; - return input.matches(sideBySideInput.master) || input.matches(sideBySideInput.details); - } - - return false; - }); - } - - public openEditor(input: IEditorInput, options?: IEditorOptions, sideBySide?: boolean): TPromise; - public openEditor(input: IEditorInput, options?: IEditorOptions, position?: Position): TPromise; - public openEditor(input: IResourceInputType, position?: Position): TPromise; - public openEditor(input: IResourceInputType, sideBySide?: boolean): TPromise; - public openEditor(input: any, arg2?: any, arg3?: any): TPromise { - if (!input) { - return TPromise.as(null); - } - - // Workbench Input Support - if (input instanceof EditorInput) { - return this.doOpenEditor(input, this.toOptions(arg2), arg3); - } - - // Support opening foreign resources (such as a http link that points outside of the workbench) - const resourceInput = input; - if (resourceInput.resource instanceof URI) { - const schema = resourceInput.resource.scheme; - if (schema === network.Schemas.http || schema === network.Schemas.https) { - window.open(resourceInput.resource.toString(true)); - - return TPromise.as(null); - } - } - - // Untyped Text Editor Support (required for code that uses this service below workbench level) - const textInput = input; - const typedInput = this.createInput(textInput); - if (typedInput) { - return this.doOpenEditor(typedInput, TextEditorOptions.from(textInput), arg2); - } - - return TPromise.as(null); - } - - private toOptions(options?: IEditorOptions | EditorOptions): EditorOptions { - if (!options || options instanceof EditorOptions) { - return options as EditorOptions; - } - - const textOptions: ITextEditorOptions = options; - if (!!textOptions.selection) { - return TextEditorOptions.create(options); - } - - return EditorOptions.create(options); - } - - /** - * Allow subclasses to implement their own behavior for opening editor (see below). - */ - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { - return this.editorPart.openEditor(input, options, arg3); - } - - public openEditors(editors: { input: IResourceInputType, position: Position }[]): TPromise; - public openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions }[]): TPromise; - public openEditors(editors: any[]): TPromise { - const inputs = editors.map(editor => this.createInput(editor.input)); - const typedInputs: { input: IEditorInput, position: Position, options?: EditorOptions }[] = inputs.map((input, index) => { - const options = editors[index].input instanceof EditorInput ? this.toOptions(editors[index].options) : TextEditorOptions.from(editors[index].input); - - return { - input, - options, - position: editors[index].position - }; - }); - - return this.editorPart.openEditors(typedInputs); - } - - public replaceEditors(editors: { toReplace: IResourceInputType, replaceWith: IResourceInputType }[], position?: Position): TPromise; - public replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions }[], position?: Position): TPromise; - public replaceEditors(editors: any[], position?: Position): TPromise { - const toReplaceInputs = editors.map(editor => this.createInput(editor.toReplace)); - const replaceWithInputs = editors.map(editor => this.createInput(editor.replaceWith)); - const typedReplacements: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: EditorOptions }[] = editors.map((editor, index) => { - const options = editor.toReplace instanceof EditorInput ? this.toOptions(editor.options) : TextEditorOptions.from(editor.replaceWith); - - return { - toReplace: toReplaceInputs[index], - replaceWith: replaceWithInputs[index], - options - }; - }); - - return this.editorPart.replaceEditors(typedReplacements, position); - } - - public closeEditor(position: Position, input: IEditorInput): TPromise { - return this.doCloseEditor(position, input); - } - - protected doCloseEditor(position: Position, input: IEditorInput): TPromise { - return this.editorPart.closeEditor(position, input); - } - - public closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise { - return this.editorPart.closeEditors(position, filter); - } - - public closeAllEditors(except?: Position): TPromise { - return this.editorPart.closeAllEditors(except); - } - - public createInput(input: IEditorInput): EditorInput; - public createInput(input: IResourceInputType): EditorInput; - public createInput(input: any): IEditorInput { - - // Workbench Input Support - if (input instanceof EditorInput) { - return input; - } - - // Side by Side Support - const resourceSideBySideInput = input; - if (resourceSideBySideInput.masterResource && resourceSideBySideInput.detailResource) { - const masterInput = this.createInput({ resource: resourceSideBySideInput.masterResource }); - const detailInput = this.createInput({ resource: resourceSideBySideInput.detailResource }); - - return new SideBySideEditorInput(resourceSideBySideInput.label || masterInput.getName(), typeof resourceSideBySideInput.description === 'string' ? resourceSideBySideInput.description : masterInput.getDescription(), detailInput, masterInput); - } - - // Diff Editor Support - const resourceDiffInput = input; - if (resourceDiffInput.leftResource && resourceDiffInput.rightResource) { - const leftInput = this.createInput({ resource: resourceDiffInput.leftResource }); - const rightInput = this.createInput({ resource: resourceDiffInput.rightResource }); - const label = resourceDiffInput.label || this.toDiffLabel(resourceDiffInput.leftResource, resourceDiffInput.rightResource, this.workspaceContextService, this.environmentService); - - return new DiffEditorInput(label, resourceDiffInput.description, leftInput, rightInput); - } - - // Untitled file support - const untitledInput = input; - if (!untitledInput.resource || typeof untitledInput.filePath === 'string' || (untitledInput.resource instanceof URI && untitledInput.resource.scheme === UNTITLED_SCHEMA)) { - return this.untitledEditorService.createOrGet(untitledInput.filePath ? URI.file(untitledInput.filePath) : untitledInput.resource, untitledInput.language, untitledInput.contents, untitledInput.encoding); - } - - const resourceInput = input; - - // Files support - if (resourceInput.resource instanceof URI && resourceInput.resource.scheme === network.Schemas.file) { - return this.createOrGet(resourceInput.resource, this.instantiationService, resourceInput.label, resourceInput.description, resourceInput.encoding); - } - - // Any other resource - else if (resourceInput.resource instanceof URI) { - const label = resourceInput.label || basename(resourceInput.resource.fsPath); - let description: string; - if (typeof resourceInput.description === 'string') { - description = resourceInput.description; - } else if (resourceInput.resource.scheme === network.Schemas.file) { - description = dirname(resourceInput.resource.fsPath); - } - - return this.createOrGet(resourceInput.resource, this.instantiationService, label, description); - } - - return null; - } - - private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string, description: string, encoding?: string): ICachedEditorInput { - if (WorkbenchEditorService.CACHE.has(resource)) { - const input = WorkbenchEditorService.CACHE.get(resource); - if (input instanceof ResourceEditorInput) { - input.setName(label); - input.setDescription(description); - } else { - input.setPreferredEncoding(encoding); - } - - return input; - } - - let input: ICachedEditorInput; - if (resource.scheme === network.Schemas.file) { - input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); - } else { - input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); - } - - WorkbenchEditorService.CACHE.set(resource, input); - once(input.onDispose)(() => { - WorkbenchEditorService.CACHE.delete(resource); - }); - - return input; - } - - private toDiffLabel(res1: URI, res2: URI, context: IWorkspaceContextService, environment: IEnvironmentService): string { - const leftName = getPathLabel(res1.fsPath, context, environment); - const rightName = getPathLabel(res2.fsPath, context, environment); - - return nls.localize('compareLabels', "{0} ↔ {1}", leftName, rightName); - } -} - -export interface IEditorOpenHandler { - (input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - (input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; -} - -export interface IEditorCloseHandler { - (position: Position, input: IEditorInput): TPromise; -} - -/** - * Subclass of workbench editor service that delegates all calls to the provided editor service. Subclasses can choose to override the behavior - * of openEditor() and closeEditor() by providing a handler. - * - * This gives clients a chance to override the behavior of openEditor() and closeEditor(). - */ -export class DelegatingWorkbenchEditorService extends WorkbenchEditorService { - private editorOpenHandler: IEditorOpenHandler; - private editorCloseHandler: IEditorCloseHandler; - - constructor( - @IUntitledEditorService untitledEditorService: IUntitledEditorService, - @IInstantiationService instantiationService: IInstantiationService, - @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IEnvironmentService environmentService: IEnvironmentService - ) { - super( - editorService, - untitledEditorService, - workspaceContextService, - instantiationService, - environmentService - ); - } - - public setEditorOpenHandler(handler: IEditorOpenHandler): void { - this.editorOpenHandler = handler; - } - - public setEditorCloseHandler(handler: IEditorCloseHandler): void { - this.editorCloseHandler = handler; - } - - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; - protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { - const handleOpen = this.editorOpenHandler ? this.editorOpenHandler(input, options, arg3) : TPromise.as(void 0); - - return handleOpen.then(editor => { - if (editor) { - return TPromise.as(editor); - } - - return super.doOpenEditor(input, options, arg3); - }); - } - - protected doCloseEditor(position: Position, input: IEditorInput): TPromise { - const handleClose = this.editorCloseHandler ? this.editorCloseHandler(position, input) : TPromise.as(void 0); - - return handleClose.then(() => { - return super.doCloseEditor(position, input); - }); - } -} \ No newline at end of file diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 05f2ae36cc2..8100a8cd551 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -6,8 +6,23 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService, IEditor, IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IResourceInput, IResourceDiffInput, IResourceSideBySideInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; +import URI from 'vs/base/common/uri'; +import network = require('vs/base/common/network'); +import { Registry } from 'vs/platform/registry/common/platform'; +import { basename, dirname } from 'vs/base/common/paths'; +import { EditorInput, EditorOptions, TextEditorOptions, Extensions as EditorExtensions, SideBySideEditorInput, IFileEditorInput, IFileInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; +import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { IUntitledEditorService, UNTITLED_SCHEMA } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import nls = require('vs/nls'); +import { getPathLabel } from 'vs/base/common/labels'; +import { ResourceMap } from 'vs/base/common/map'; +import { once } from 'vs/base/common/event'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IFileService } from 'vs/platform/files/common/files'; export const IWorkbenchEditorService = createDecorator('editorService'); @@ -91,4 +106,344 @@ export interface IWorkbenchEditorService extends IEditorService { * Allows to resolve an untyped input to a workbench typed instanceof editor input */ createInput(input: IResourceInputType): IEditorInput; -} \ No newline at end of file +} + +export interface IEditorPart { + openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, sideBySide?: boolean): TPromise; + openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, position?: Position): TPromise; + openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions | ITextEditorOptions }[]): TPromise; + replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions | ITextEditorOptions }[], position?: Position): TPromise; + closeEditor(position: Position, input: IEditorInput): TPromise; + closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise; + closeAllEditors(except?: Position): TPromise; + getActiveEditor(): IEditor; + getVisibleEditors(): IEditor[]; + getActiveEditorInput(): IEditorInput; +} + +type ICachedEditorInput = ResourceEditorInput | IFileEditorInput; + +export class WorkbenchEditorService implements IWorkbenchEditorService { + + public _serviceBrand: any; + + private static CACHE: ResourceMap = new ResourceMap(); + + private editorPart: IEditorPart | IWorkbenchEditorService; + private fileInputFactory: IFileInputFactory; + + constructor( + editorPart: IEditorPart | IWorkbenchEditorService, + @IUntitledEditorService private untitledEditorService: IUntitledEditorService, + @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, + @IInstantiationService private instantiationService: IInstantiationService, + @IEnvironmentService private environmentService: IEnvironmentService, + @IFileService private fileService: IFileService + ) { + this.editorPart = editorPart; + this.fileInputFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileInputFactory(); + } + + public getActiveEditor(): IEditor { + return this.editorPart.getActiveEditor(); + } + + public getActiveEditorInput(): IEditorInput { + return this.editorPart.getActiveEditorInput(); + } + + public getVisibleEditors(): IEditor[] { + return this.editorPart.getVisibleEditors(); + } + + public isVisible(input: IEditorInput, includeSideBySide: boolean): boolean { + if (!input) { + return false; + } + + return this.getVisibleEditors().some(editor => { + if (!editor.input) { + return false; + } + + if (input.matches(editor.input)) { + return true; + } + + if (includeSideBySide && editor.input instanceof SideBySideEditorInput) { + const sideBySideInput = editor.input; + return input.matches(sideBySideInput.master) || input.matches(sideBySideInput.details); + } + + return false; + }); + } + + public openEditor(input: IEditorInput, options?: IEditorOptions, sideBySide?: boolean): TPromise; + public openEditor(input: IEditorInput, options?: IEditorOptions, position?: Position): TPromise; + public openEditor(input: IResourceInputType, position?: Position): TPromise; + public openEditor(input: IResourceInputType, sideBySide?: boolean): TPromise; + public openEditor(input: any, arg2?: any, arg3?: any): TPromise { + if (!input) { + return TPromise.as(null); + } + + // Workbench Input Support + if (input instanceof EditorInput) { + return this.doOpenEditor(input, this.toOptions(arg2), arg3); + } + + // Support opening foreign resources (such as a http link that points outside of the workbench) + const resourceInput = input; + if (resourceInput.resource instanceof URI) { + const schema = resourceInput.resource.scheme; + if (schema === network.Schemas.http || schema === network.Schemas.https) { + window.open(resourceInput.resource.toString(true)); + + return TPromise.as(null); + } + } + + // Untyped Text Editor Support (required for code that uses this service below workbench level) + const textInput = input; + const typedInput = this.createInput(textInput); + if (typedInput) { + return this.doOpenEditor(typedInput, TextEditorOptions.from(textInput), arg2); + } + + return TPromise.as(null); + } + + private toOptions(options?: IEditorOptions | EditorOptions): EditorOptions { + if (!options || options instanceof EditorOptions) { + return options as EditorOptions; + } + + const textOptions: ITextEditorOptions = options; + if (!!textOptions.selection) { + return TextEditorOptions.create(options); + } + + return EditorOptions.create(options); + } + + /** + * Allow subclasses to implement their own behavior for opening editor (see below). + */ + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { + return this.editorPart.openEditor(input, options, arg3); + } + + public openEditors(editors: { input: IResourceInputType, position: Position }[]): TPromise; + public openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions }[]): TPromise; + public openEditors(editors: any[]): TPromise { + const inputs = editors.map(editor => this.createInput(editor.input)); + const typedInputs: { input: IEditorInput, position: Position, options?: EditorOptions }[] = inputs.map((input, index) => { + const options = editors[index].input instanceof EditorInput ? this.toOptions(editors[index].options) : TextEditorOptions.from(editors[index].input); + + return { + input, + options, + position: editors[index].position + }; + }); + + return this.editorPart.openEditors(typedInputs); + } + + public replaceEditors(editors: { toReplace: IResourceInputType, replaceWith: IResourceInputType }[], position?: Position): TPromise; + public replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions }[], position?: Position): TPromise; + public replaceEditors(editors: any[], position?: Position): TPromise { + const toReplaceInputs = editors.map(editor => this.createInput(editor.toReplace)); + const replaceWithInputs = editors.map(editor => this.createInput(editor.replaceWith)); + const typedReplacements: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: EditorOptions }[] = editors.map((editor, index) => { + const options = editor.toReplace instanceof EditorInput ? this.toOptions(editor.options) : TextEditorOptions.from(editor.replaceWith); + + return { + toReplace: toReplaceInputs[index], + replaceWith: replaceWithInputs[index], + options + }; + }); + + return this.editorPart.replaceEditors(typedReplacements, position); + } + + public closeEditor(position: Position, input: IEditorInput): TPromise { + return this.doCloseEditor(position, input); + } + + protected doCloseEditor(position: Position, input: IEditorInput): TPromise { + return this.editorPart.closeEditor(position, input); + } + + public closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise { + return this.editorPart.closeEditors(position, filter); + } + + public closeAllEditors(except?: Position): TPromise { + return this.editorPart.closeAllEditors(except); + } + + public createInput(input: IEditorInput): EditorInput; + public createInput(input: IResourceInputType): EditorInput; + public createInput(input: any): IEditorInput { + + // Workbench Input Support + if (input instanceof EditorInput) { + return input; + } + + // Side by Side Support + const resourceSideBySideInput = input; + if (resourceSideBySideInput.masterResource && resourceSideBySideInput.detailResource) { + const masterInput = this.createInput({ resource: resourceSideBySideInput.masterResource }); + const detailInput = this.createInput({ resource: resourceSideBySideInput.detailResource }); + + return new SideBySideEditorInput(resourceSideBySideInput.label || masterInput.getName(), typeof resourceSideBySideInput.description === 'string' ? resourceSideBySideInput.description : masterInput.getDescription(), detailInput, masterInput); + } + + // Diff Editor Support + const resourceDiffInput = input; + if (resourceDiffInput.leftResource && resourceDiffInput.rightResource) { + const leftInput = this.createInput({ resource: resourceDiffInput.leftResource }); + const rightInput = this.createInput({ resource: resourceDiffInput.rightResource }); + const label = resourceDiffInput.label || this.toDiffLabel(resourceDiffInput.leftResource, resourceDiffInput.rightResource, this.workspaceContextService, this.environmentService); + + return new DiffEditorInput(label, resourceDiffInput.description, leftInput, rightInput); + } + + // Untitled file support + const untitledInput = input; + if (!untitledInput.resource || typeof untitledInput.filePath === 'string' || (untitledInput.resource instanceof URI && untitledInput.resource.scheme === UNTITLED_SCHEMA)) { + return this.untitledEditorService.createOrGet(untitledInput.filePath ? URI.file(untitledInput.filePath) : untitledInput.resource, untitledInput.language, untitledInput.contents, untitledInput.encoding); + } + + const resourceInput = input; + + // Files support + if (resourceInput.resource instanceof URI && resourceInput.resource.scheme === network.Schemas.file) { + return this.createOrGet(resourceInput.resource, this.instantiationService, resourceInput.label, resourceInput.description, resourceInput.encoding); + } + + // Any other resource + else if (resourceInput.resource instanceof URI) { + const label = resourceInput.label || basename(resourceInput.resource.fsPath); + let description: string; + if (typeof resourceInput.description === 'string') { + description = resourceInput.description; + } else if (resourceInput.resource.scheme === network.Schemas.file) { + description = dirname(resourceInput.resource.fsPath); + } + + return this.createOrGet(resourceInput.resource, this.instantiationService, label, description); + } + + return null; + } + + private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string, description: string, encoding?: string): ICachedEditorInput { + if (WorkbenchEditorService.CACHE.has(resource)) { + const input = WorkbenchEditorService.CACHE.get(resource); + if (input instanceof ResourceEditorInput) { + input.setName(label); + input.setDescription(description); + } else { + input.setPreferredEncoding(encoding); + } + + return input; + } + + let input: ICachedEditorInput; + if (resource.scheme === network.Schemas.file || this.fileService.canHandleResource && this.fileService.canHandleResource(resource)) { + input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); + } else { + input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); + } + + WorkbenchEditorService.CACHE.set(resource, input); + once(input.onDispose)(() => { + WorkbenchEditorService.CACHE.delete(resource); + }); + + return input; + } + + private toDiffLabel(res1: URI, res2: URI, context: IWorkspaceContextService, environment: IEnvironmentService): string { + const leftName = getPathLabel(res1.fsPath, context, environment); + const rightName = getPathLabel(res2.fsPath, context, environment); + + return nls.localize('compareLabels', "{0} ↔ {1}", leftName, rightName); + } +} + +export interface IEditorOpenHandler { + (input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + (input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; +} + +export interface IEditorCloseHandler { + (position: Position, input: IEditorInput): TPromise; +} + +/** + * Subclass of workbench editor service that delegates all calls to the provided editor service. Subclasses can choose to override the behavior + * of openEditor() and closeEditor() by providing a handler. + * + * This gives clients a chance to override the behavior of openEditor() and closeEditor(). + */ +export class DelegatingWorkbenchEditorService extends WorkbenchEditorService { + private editorOpenHandler: IEditorOpenHandler; + private editorCloseHandler: IEditorCloseHandler; + + constructor( + @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @IInstantiationService instantiationService: IInstantiationService, + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IEnvironmentService environmentService: IEnvironmentService, + @IFileService fileService: IFileService + ) { + super( + editorService, + untitledEditorService, + workspaceContextService, + instantiationService, + environmentService, + fileService + ); + } + + public setEditorOpenHandler(handler: IEditorOpenHandler): void { + this.editorOpenHandler = handler; + } + + public setEditorCloseHandler(handler: IEditorCloseHandler): void { + this.editorCloseHandler = handler; + } + + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise; + protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise { + const handleOpen = this.editorOpenHandler ? this.editorOpenHandler(input, options, arg3) : TPromise.as(void 0); + + return handleOpen.then(editor => { + if (editor) { + return TPromise.as(editor); + } + + return super.doOpenEditor(input, options, arg3); + }); + } + + protected doCloseEditor(position: Position, input: IEditorInput): TPromise { + const handleClose = this.editorCloseHandler ? this.editorCloseHandler(position, input) : TPromise.as(void 0); + + return handleClose.then(() => { + return super.doCloseEditor(position, input); + }); + } +} diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index c6ce1376dc1..0e71a596420 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -8,37 +8,36 @@ import * as assert from 'assert'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; import paths = require('vs/base/common/paths'); -import { Position, Direction, IEditor } from 'vs/platform/editor/common/editor'; +import { Position, Direction, IEditor, IEditorInput } from 'vs/platform/editor/common/editor'; import URI from 'vs/base/common/uri'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorInput, EditorOptions, TextEditorOptions } from 'vs/workbench/common/editor'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; -import { DelegatingWorkbenchEditorService, WorkbenchEditorService, IEditorPart } from 'vs/workbench/services/editor/browser/editorService'; +import { DelegatingWorkbenchEditorService, WorkbenchEditorService, IEditorPart } from 'vs/workbench/services/editor/common/editorService'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; -let activeEditor: BaseEditor = { +let activeEditor: BaseEditor = { getSelection: function () { return 'test.selection'; } -}; +} as any; -let openedEditorInput; -let openedEditorOptions; -let openedEditorPosition; +let openedEditorInput: EditorInput; +let openedEditorOptions: EditorOptions; -function toResource(path) { +function toResource(path: string) { return URI.from({ scheme: 'custom', path }); } -function toFileResource(path) { - return URI.file(paths.join('C:\\', new Buffer(this.test.fullTitle()).toString('base64'), path)); +function toFileResource(self: any, path: string) { + return URI.file(paths.join('C:\\', new Buffer(self.test.fullTitle()).toString('base64'), path)); } class TestEditorPart implements IEditorPart { - private activeInput; + private activeInput: EditorInput; public getId(): string { return null; @@ -69,7 +68,6 @@ class TestEditorPart implements IEditorPart { public openEditor(input?: EditorInput, options?: EditorOptions, arg?: any): TPromise { openedEditorInput = input; openedEditorOptions = options; - openedEditorPosition = arg; return TPromise.as(activeEditor); } @@ -96,7 +94,7 @@ suite('WorkbenchEditorService', () => { test('basics', function () { let instantiationService = workbenchInstantiationService(); - let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toFileResource.call(this, '/something.js'), void 0); + let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toFileResource(this, '/something.js'), void 0); let testEditorPart = new TestEditorPart(); testEditorPart.setActiveEditorInput(activeInput); @@ -123,12 +121,12 @@ suite('WorkbenchEditorService', () => { }); // Open Untyped Input (file) - service.openEditor({ resource: toFileResource.call(this, '/index.html'), options: { selection: { startLineNumber: 1, startColumn: 1 } } }).then((editor) => { + service.openEditor({ resource: toFileResource(this, '/index.html'), options: { selection: { startLineNumber: 1, startColumn: 1 } } }).then((editor) => { assert.strictEqual(editor, activeEditor); assert(openedEditorInput instanceof FileEditorInput); let contentInput = openedEditorInput; - assert.strictEqual(contentInput.getResource().fsPath, toFileResource.call(this, '/index.html').fsPath); + assert.strictEqual(contentInput.getResource().fsPath, toFileResource(this, '/index.html').fsPath); assert(openedEditorOptions instanceof TextEditorOptions); let textEditorOptions = openedEditorOptions; @@ -136,7 +134,7 @@ suite('WorkbenchEditorService', () => { }); // Open Untyped Input (file, encoding) - service.openEditor({ resource: toFileResource.call(this, '/index.html'), encoding: 'utf16le', options: { selection: { startLineNumber: 1, startColumn: 1 } } }).then((editor) => { + service.openEditor({ resource: toFileResource(this, '/index.html'), encoding: 'utf16le', options: { selection: { startLineNumber: 1, startColumn: 1 } } }).then((editor) => { assert.strictEqual(editor, activeEditor); assert(openedEditorInput instanceof FileEditorInput); @@ -181,18 +179,18 @@ suite('WorkbenchEditorService', () => { test('caching', function () { let instantiationService = workbenchInstantiationService(); - let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toFileResource.call(this, '/something.js'), void 0); + let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toFileResource(this, '/something.js'), void 0); let testEditorPart = new TestEditorPart(); testEditorPart.setActiveEditorInput(activeInput); let service: WorkbenchEditorService = instantiationService.createInstance(WorkbenchEditorService, testEditorPart); // Cached Input (Files) - const fileResource1 = toFileResource.call(this, '/foo/bar/cache1.js'); + const fileResource1 = toFileResource(this, '/foo/bar/cache1.js'); const fileInput1 = service.createInput({ resource: fileResource1 }); assert.ok(fileInput1); - const fileResource2 = toFileResource.call(this, '/foo/bar/cache2.js'); + const fileResource2 = toFileResource(this, '/foo/bar/cache2.js'); const fileInput2 = service.createInput({ resource: fileResource2 }); assert.ok(fileInput2); @@ -234,7 +232,7 @@ suite('WorkbenchEditorService', () => { test('delegate', function (done) { let instantiationService = workbenchInstantiationService(); - let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toFileResource.call(this, '/something.js'), void 0); + let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toFileResource(this, '/something.js'), void 0); let testEditorPart = new TestEditorPart(); testEditorPart.setActiveEditorInput(activeInput); @@ -262,7 +260,7 @@ suite('WorkbenchEditorService', () => { let inp = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.parse('my://resource')); let delegate = instantiationService.createInstance(DelegatingWorkbenchEditorService); - delegate.setEditorOpenHandler((input, options?) => { + delegate.setEditorOpenHandler((input: IEditorInput, options?: EditorOptions) => { assert.strictEqual(input, inp); return TPromise.as(ed); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index cbfcf27d66b..8e82c3e4347 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -16,7 +16,7 @@ import { findFreePort } from 'vs/base/node/ports'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { ILifecycleService, ShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ChildProcess, fork } from 'child_process'; import { ipcRenderer as ipc } from 'electron'; @@ -25,16 +25,17 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { generateRandomPipeName, Protocol } from 'vs/base/parts/ipc/node/ipc.net'; import { createServer, Server, Socket } from 'net'; -import Event, { Emitter, debounceEvent, mapEvent, any } from 'vs/base/common/event'; -import { fromEventEmitter } from 'vs/base/node/event'; -import { IInitData, IWorkspaceData } from 'vs/workbench/api/node/extHost.protocol'; +import Event, { Emitter, debounceEvent, mapEvent, anyEvent, fromNodeEventEmitter } from 'vs/base/common/event'; +import { IInitData, IWorkspaceData, IConfigurationInitData } from 'vs/workbench/api/node/extHost.protocol'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { ICrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService'; +import { ICrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService'; import { IBroadcastService, IBroadcast } from 'vs/platform/broadcast/electron-browser/broadcastService'; import { isEqual } from 'vs/base/common/paths'; -import { EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, ILogEntry, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; +import { EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IRemoteConsoleLog, log, parse } from 'vs/base/node/console'; +import { getScopes } from 'vs/platform/configuration/common/configurationRegistry'; export class ExtensionHostProcessWorker { @@ -142,7 +143,8 @@ export class ExtensionHostProcessWorker { VSCODE_WINDOW_ID: String(this._windowService.getCurrentWindowId()), VSCODE_IPC_HOOK_EXTHOST: pipeName, VSCODE_HANDLES_UNCAUGHT_ERRORS: true, - ELECTRON_NO_ASAR: '1' + ELECTRON_NO_ASAR: '1', + VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || product.quality !== 'stable' || this._environmentService.verbose) }), // We only detach the extension host on windows. Linux and Mac orphan by default // and detach under Linux and Mac create another process group. @@ -167,9 +169,9 @@ export class ExtensionHostProcessWorker { type Output = { data: string, format: string[] }; this._extensionHostProcess.stdout.setEncoding('utf8'); this._extensionHostProcess.stderr.setEncoding('utf8'); - const onStdout = fromEventEmitter(this._extensionHostProcess.stdout, 'data'); - const onStderr = fromEventEmitter(this._extensionHostProcess.stderr, 'data'); - const onOutput = any( + const onStdout = fromNodeEventEmitter(this._extensionHostProcess.stdout, 'data'); + const onStderr = fromNodeEventEmitter(this._extensionHostProcess.stderr, 'data'); + const onOutput = anyEvent( mapEvent(onStdout, o => ({ data: `%c${o}`, format: [''] })), mapEvent(onStderr, o => ({ data: `%c${o}`, format: ['color: red'] })) ); @@ -183,15 +185,20 @@ export class ExtensionHostProcessWorker { // Print out extension host output onDebouncedOutput(data => { - console.group('Extension Host'); - console.log(data.data, ...data.format); - console.groupEnd(); + const inspectorUrlIndex = !this._environmentService.isBuilt && data.data && data.data.indexOf('chrome-devtools://'); + if (inspectorUrlIndex >= 0) { + console.log(`%c[Extension Host] %cdebugger inspector at ${data.data.substr(inspectorUrlIndex)}`, 'color: blue', 'color: black'); + } else { + console.group('Extension Host'); + console.log(data.data, ...data.format); + console.groupEnd(); + } }); // Support logging from extension host this._extensionHostProcess.on('message', msg => { - if (msg && (msg).type === '__$console') { - this._logExtensionHostMessage(msg); + if (msg && (msg).type === '__$console') { + this._logExtensionHostMessage(msg); } }); @@ -337,6 +344,7 @@ export class ExtensionHostProcessWorker { private _createExtHostInitData(): TPromise { return TPromise.join([this._telemetryService.getTelemetryInfo(), this._extensionService.getExtensions()]).then(([telemetryInfo, extensionDescriptions]) => { + const configurationData: IConfigurationInitData = { ...this._configurationService.getConfigurationData(), configurationScopes: [] }; const r: IInitData = { parentPid: process.pid, environment: { @@ -351,42 +359,26 @@ export class ExtensionHostProcessWorker { enableProposedApiForAll: !this._environmentService.isBuilt || (!!this._environmentService.extensionDevelopmentPath && product.nameLong.indexOf('Insiders') >= 0), enableProposedApiFor: this._environmentService.args['enable-proposed-api'] || [] }, - workspace: this._contextService.getWorkspace(), + workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace(), extensions: extensionDescriptions, - configuration: this._configurationService.getConfigurationData(), + // Send configurations scopes only in development mode. + configuration: !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment ? { ...configurationData, configurationScopes: getScopes(this._configurationService.keys().default) } : configurationData, telemetryInfo }; return r; }); } - private _logExtensionHostMessage(logEntry: ILogEntry) { - let args = []; - try { - let parsed = JSON.parse(logEntry.arguments); - args.push(...Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(logEntry.arguments); - } - - // If the first argument is a string, check for % which indicates that the message - // uses substitution for variables. In this case, we cannot just inject our colored - // [Extension Host] to the front because it breaks substitution. - let consoleArgs = []; - if (typeof args[0] === 'string' && args[0].indexOf('%') >= 0) { - consoleArgs = [`%c[Extension Host]%c ${args[0]}`, 'color: blue', 'color: black', ...args.slice(1)]; - } else { - consoleArgs = ['%c[Extension Host]', 'color: blue', ...args]; - } + private _logExtensionHostMessage(entry: IRemoteConsoleLog) { // Send to local console unless we run tests from cli if (!this._isExtensionDevTestFromCli) { - console[logEntry.severity].apply(console, consoleArgs); + log(entry, 'Extension Host'); } // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - this._windowsService.log(logEntry.severity, ...args); + this._windowsService.log(entry.severity, ...parse(entry).args); } // Broadcast to other windows if we are in development mode @@ -394,7 +386,7 @@ export class ExtensionHostProcessWorker { this._broadcastService.broadcast({ channel: EXTENSION_LOG_BROADCAST_CHANNEL, payload: { - logEntry, + logEntry: entry, debugId: this._environmentService.debugExtensionHost.debugId } }); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts index 60261ce5e0d..4204b5715a1 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts @@ -59,7 +59,12 @@ class ExtensionManifestParser extends ExtensionManifestHandler { public parse(): TPromise { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { try { - return JSON.parse(manifestContents.toString()); + const manifest = JSON.parse(manifestContents.toString()); + if (manifest.__metadata) { + manifest.uuid = manifest.__metadata.id; + } + delete manifest.__metadata; + return manifest; } catch (e) { this._log.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, getParseErrorMessage(e.message))); } @@ -196,7 +201,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { if (literal.hasOwnProperty(key)) { processEntry(literal, key); } - }; + } } } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index e1a98d415ae..8e19e2df434 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -32,6 +32,8 @@ import { ExtHostCustomersRegistry } from 'vs/workbench/api/electron-browser/extH import { IWindowService } from 'vs/platform/windows/common/windows'; import { Action } from 'vs/base/common/actions'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { mark, time } from 'vs/base/common/performance'; +import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions')); @@ -81,7 +83,8 @@ export class ExtensionService implements IExtensionService { @ITelemetryService private readonly _telemetryService: ITelemetryService, @IExtensionEnablementService private readonly _extensionEnablementService: IExtensionEnablementService, @IStorageService private readonly _storageService: IStorageService, - @IWindowService private readonly _windowService: IWindowService + @IWindowService private readonly _windowService: IWindowService, + @ILifecycleService lifecycleService: ILifecycleService ) { this._registry = null; this._barrier = new Barrier(); @@ -96,8 +99,12 @@ export class ExtensionService implements IExtensionService { this._extensionHostProcessCustomers = []; this._extensionHostProcessProxy = null; - this._startExtensionHostProcess([]); - this._scanAndHandleExtensions(); + lifecycleService.when(LifecyclePhase.Restoring).then(() => { + // delay extension host creation and extension scanning + // until after the editors/panels are restored + this._startExtensionHostProcess([]); + this._scanAndHandleExtensions(); + }); } public restartExtensionHost(): void { @@ -105,6 +112,14 @@ export class ExtensionService implements IExtensionService { this._startExtensionHostProcess(Object.keys(this._allRequestedActivateEvents)); } + public startExtensionHost(): void { + this._startExtensionHostProcess(Object.keys(this._allRequestedActivateEvents)); + } + + public stopExtensionHost(): void { + this._stopExtensionHostProcess(); + } + private _stopExtensionHostProcess(): void { this._extensionHostProcessFinishedActivateEvents = Object.create(null); this._extensionHostProcessActivationTimes = Object.create(null); @@ -230,7 +245,7 @@ export class ExtensionService implements IExtensionService { } protected _activateByEvent(activationEvent: string): TPromise { - if (this._extensionHostProcessFinishedActivateEvents[activationEvent]) { + if (this._extensionHostProcessFinishedActivateEvents[activationEvent] || !this._extensionHostProcessProxy) { return NO_OP_VOID_PROMISE; } return this._extensionHostProcessProxy.then((proxy) => { @@ -286,11 +301,21 @@ export class ExtensionService implements IExtensionService { }); ExtensionService._scanInstalledExtensions(this._environmentService, log).then((installedExtensions) => { + + // Migrate enablement service to use identifiers + this._extensionEnablementService.migrateToIdentifiers(installedExtensions); + const disabledExtensions = [ ...getGloballyDisabledExtensions(this._extensionEnablementService, this._storageService, installedExtensions), ...this._extensionEnablementService.getWorkspaceDisabledExtensions() ]; + /* __GDPR__ + "extensionsScanned" : { + "totalCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "disabledCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ this._telemetryService.publicLog('extensionsScanned', { totalCount: installedExtensions.length, disabledCount: disabledExtensions.length @@ -299,7 +324,7 @@ export class ExtensionService implements IExtensionService { if (disabledExtensions.length === 0) { return installedExtensions; } - return installedExtensions.filter(e => disabledExtensions.every(id => !areSameExtensions({ id }, e))); + return installedExtensions.filter(e => disabledExtensions.every(disabled => !areSameExtensions(disabled, e))); }).then((extensionDescriptions) => { this._registry = new ExtensionDescriptionRegistry(extensionDescriptions); @@ -310,9 +335,14 @@ export class ExtensionService implements IExtensionService { let messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); for (let i = 0, len = extensionPoints.length; i < len; i++) { - ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + const clock = time(`handleExtensionPoint:${extensionPoints[i].name}`); + try { + ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + } finally { + clock.stop(); + } } - + mark('extensionHostReady'); this._barrier.open(); }); } @@ -333,6 +363,14 @@ export class ExtensionService implements IExtensionService { if (!this._isDev && msg.extensionId) { const { type, extensionId, extensionPointId, message } = msg; + /* __GDPR__ + "extensionsMessage" : { + "type" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "extensionId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "extensionPointId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "message": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ this._telemetryService.publicLog('extensionsMessage', { type, extensionId, extensionPointId, message }); diff --git a/src/vs/workbench/services/extensions/node/lazyPromise.ts b/src/vs/workbench/services/extensions/node/lazyPromise.ts index c70b58ce0be..af99f35dc52 100644 --- a/src/vs/workbench/services/extensions/node/lazyPromise.ts +++ b/src/vs/workbench/services/extensions/node/lazyPromise.ts @@ -5,6 +5,7 @@ 'use strict'; import { TPromise, ValueCallback, ErrorCallback } from 'vs/base/common/winjs.base'; +import { onUnexpectedError } from 'vs/base/common/errors'; export class LazyPromise { @@ -75,6 +76,10 @@ export class LazyPromise { if (this._actual) { this._actualErr(err); + } else { + // If nobody's listening at this point, it is safe to assume they never will, + // since resolving this promise is always "async" + onUnexpectedError(err); } } diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index d47a6ce4076..cf46014fe39 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -11,22 +11,19 @@ import paths = require('vs/base/common/paths'); import encoding = require('vs/base/node/encoding'); import errors = require('vs/base/common/errors'); import uri from 'vs/base/common/uri'; -import { toResource } from 'vs/workbench/common/editor'; -import { FileOperation, FileOperationEvent, IFileService, IFilesConfiguration, IResolveFileOptions, IFileStat, IResolveFileResult, IContent, IStreamContent, IImportResult, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent } from 'vs/platform/files/common/files'; +import { FileOperation, FileOperationEvent, IFileService, IFilesConfiguration, IResolveFileOptions, IFileStat, IResolveFileResult, IContent, IStreamContent, IImportResult, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, ICreateFileOptions } from 'vs/platform/files/common/files'; import { FileService as NodeFileService, IFileServiceOptions, IEncodingOverride } from 'vs/workbench/services/files/node/fileService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { Action } from 'vs/base/common/actions'; -import { ResourceMap } from 'vs/base/common/map'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IMessageService, IMessageWithAction, Severity, CloseAction } from 'vs/platform/message/common/message'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import Event, { Emitter } from 'vs/base/common/event'; import { shell } from 'electron'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; export class FileService implements IFileService { @@ -39,23 +36,20 @@ export class FileService implements IFileService { private raw: IFileService; private toUnbind: IDisposable[]; - private activeOutOfWorkspaceWatchers: ResourceMap; protected _onFileChanges: Emitter; - private _onAfterOperation: Emitter; + protected _onAfterOperation: Emitter; constructor( @IConfigurationService private configurationService: IConfigurationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEnvironmentService private environmentService: IEnvironmentService, - @IEditorGroupService private editorGroupService: IEditorGroupService, @ILifecycleService private lifecycleService: ILifecycleService, @IMessageService private messageService: IMessageService, - @IStorageService private storageService: IStorageService + @IStorageService private storageService: IStorageService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { this.toUnbind = []; - this.activeOutOfWorkspaceWatchers = new ResourceMap(); this._onFileChanges = new Emitter(); this.toUnbind.push(this._onFileChanges); @@ -80,7 +74,7 @@ export class FileService implements IFileService { }; // create service - this.raw = new NodeFileService(contextService, configurationService, fileServiceConfig); + this.raw = new NodeFileService(contextService, textResourceConfigurationService, configurationService, fileServiceConfig); // Listeners this.registerListeners(); @@ -125,67 +119,33 @@ export class FileService implements IFileService { this.toUnbind.push(this.raw.onAfterOperation(e => this._onAfterOperation.fire(e))); // Config changes - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); - - // Editor changing - this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(e))); // Root changes - this.toUnbind.push(this.contextService.onDidChangeWorkspaceRoots(() => this.onDidChangeWorkspaceRoots())); + this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.onDidChangeWorkspaceFolders())); // Lifecycle this.lifecycleService.onShutdown(this.dispose, this); } - private onDidChangeWorkspaceRoots(): void { + private onDidChangeWorkspaceFolders(): void { this.updateOptions({ encodingOverride: this.getEncodingOverrides() }); } private getEncodingOverrides(): IEncodingOverride[] { const encodingOverride: IEncodingOverride[] = []; encodingOverride.push({ resource: uri.file(this.environmentService.appSettingsHome), encoding: encoding.UTF8 }); - if (this.contextService.hasWorkspace()) { - this.contextService.getWorkspace().roots.forEach(root => { - encodingOverride.push({ resource: uri.file(paths.join(root.fsPath, '.vscode')), encoding: encoding.UTF8 }); - }); - } + this.contextService.getWorkspace().folders.forEach(folder => { + encodingOverride.push({ resource: uri.file(paths.join(folder.uri.fsPath, '.vscode')), encoding: encoding.UTF8 }); + }); return encodingOverride; } - private onEditorsChanged(): void { - this.handleOutOfWorkspaceWatchers(); - } - - private handleOutOfWorkspaceWatchers(): void { - const visibleOutOfWorkspacePaths = new ResourceMap(); - this.editorService.getVisibleEditors().map(editor => { - return toResource(editor.input, { supportSideBySide: true, filter: 'file' }); - }).filter(fileResource => { - return !!fileResource && !this.contextService.isInsideWorkspace(fileResource); - }).forEach(resource => { - visibleOutOfWorkspacePaths.set(resource, resource); - }); - - // Handle no longer visible out of workspace resources - this.activeOutOfWorkspaceWatchers.forEach(resource => { - if (!visibleOutOfWorkspacePaths.get(resource)) { - this.unwatchFileChanges(resource); - this.activeOutOfWorkspaceWatchers.delete(resource); - } - }); - - // Handle newly visible out of workspace resources - visibleOutOfWorkspacePaths.forEach(resource => { - if (!this.activeOutOfWorkspaceWatchers.get(resource)) { - this.watchFileChanges(resource); - this.activeOutOfWorkspaceWatchers.set(resource, resource); - } - }); - } - - private onConfigurationChange(configuration: IFilesConfiguration): void { - this.updateOptions(configuration.files); + private onConfigurationChange(event: IConfigurationChangeEvent): void { + if (event.affectsConfiguration('files')) { + this.updateOptions(this.configurationService.getConfiguration('files')); + } } public updateOptions(options: object): void { @@ -224,8 +184,8 @@ export class FileService implements IFileService { return this.raw.copyFile(source, target, overwrite); } - public createFile(resource: uri, content?: string): TPromise { - return this.raw.createFile(resource, content); + public createFile(resource: uri, content?: string, options?: ICreateFileOptions): TPromise { + return this.raw.createFile(resource, content, options); } public createFolder(resource: uri): TPromise { @@ -297,10 +257,6 @@ export class FileService implements IFileService { public dispose(): void { this.toUnbind = dispose(this.toUnbind); - // Dispose watchers if any - this.activeOutOfWorkspaceWatchers.forEach(resource => this.unwatchFileChanges(resource)); - this.activeOutOfWorkspaceWatchers.clear(); - // Dispose service this.raw.dispose(); } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 990dfba275b..6de890c430f 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,32 +6,116 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent, ICreateFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; -import Event from 'vs/base/common/event'; -import { EventEmitter } from 'events'; -import { basename } from 'path'; +import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { isFalsyOrEmpty, distinct } from 'vs/base/common/arrays'; +import { Schemas } from 'vs/base/common/network'; +import { Progress } from 'vs/platform/progress/common/progress'; +import { decodeStream, encode, UTF8, UTF8_with_bom } from 'vs/base/node/encoding'; +import { TernarySearchTree } from 'vs/base/common/map'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IMessageService } from 'vs/platform/message/common/message'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { maxBufferLen, detectMimeAndEncodingFromBuffer } from 'vs/base/node/mime'; +import { MIME_BINARY } from 'vs/base/common/mime'; +import { localize } from 'vs/nls'; -export interface IRemoteFileSystemProvider { - onDidChange: Event; - resolve(resource: URI): TPromise; - update(resource: URI, content: string): TPromise; +function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse?: (tuple: [URI, IStat]) => boolean): TPromise { + const [resource, stat] = tuple; + const fileStat: IFileStat = { + isDirectory: false, + hasChildren: false, + resource: resource, + name: basename(resource.path), + mtime: stat.mtime, + size: stat.size, + etag: stat.mtime.toString(29) + stat.size.toString(31), + }; + + if (stat.type === FileType.File) { + // done + return TPromise.as(fileStat); + + } else { + // dir -> resolve + return provider.readdir(resource).then(entries => { + fileStat.isDirectory = true; + fileStat.hasChildren = entries.length > 0; + + if (recurse && recurse([resource, stat])) { + // resolve children if requested + return TPromise.join(entries.map(stat => toIFileStat(provider, stat, recurse))).then(children => { + fileStat.children = children; + return fileStat; + }); + } else { + return fileStat; + } + }); + } +} + +export function toDeepIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], to: URI[]): TPromise { + + const trie = TernarySearchTree.forPaths(); + trie.set(tuple[0].toString(), true); + + if (!isFalsyOrEmpty(to)) { + to.forEach(uri => trie.set(uri.toString(), true)); + } + + return toIFileStat(provider, tuple, candidate => { + return Boolean(trie.findSuperstr(candidate[0].toString()) || trie.get(candidate[0].toString())); + }); } export class RemoteFileService extends FileService { - private readonly _provider = new Map(); + private readonly _provider = new Map(); + private _supportedSchemes: string[]; - registerProvider(authority: string, provider: IRemoteFileSystemProvider): IDisposable { + constructor( + @IExtensionService private readonly _extensionService: IExtensionService, + @IStorageService private readonly _storageService: IStorageService, + @IConfigurationService configurationService: IConfigurationService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IEnvironmentService environmentService: IEnvironmentService, + @ILifecycleService lifecycleService: ILifecycleService, + @IMessageService messageService: IMessageService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, + ) { + super( + configurationService, + contextService, + environmentService, + lifecycleService, + messageService, + _storageService, + textResourceConfigurationService, + ); + + this._supportedSchemes = JSON.parse(this._storageService.get('remote_schemes', undefined, '[]')); + } + + registerProvider(authority: string, provider: IFileSystemProvider): IDisposable { if (this._provider.has(authority)) { throw new Error(); } + this._supportedSchemes.push(authority); + this._storageService.store('remote_schemes', JSON.stringify(distinct(this._supportedSchemes))); + this._provider.set(authority, provider); - const reg = provider.onDidChange(e => { + const reg = provider.onDidChange(changes => { // forward change events - this._onFileChanges.fire(new FileChangesEvent([{ resource: e, type: FileChangeType.UPDATED }])); + this._onFileChanges.fire(new FileChangesEvent(changes)); }); return { dispose: () => { @@ -41,70 +125,396 @@ export class RemoteFileService extends FileService { }; } + canHandleResource(resource: URI): boolean { + return resource.scheme === Schemas.file + || this._provider.has(resource.scheme) + // TODO@remote + || this._supportedSchemes.indexOf(resource.scheme) >= 0; + } + + // --- stat + + private _withProvider(resource: URI): TPromise { + return this._extensionService.activateByEvent('onFileSystemAccess:' + resource.scheme).then(() => { + const provider = this._provider.get(resource.scheme); + if (!provider) { + const err = new Error(); + err.name = 'ENOPRO'; + err.message = `no provider for ${resource.toString()}`; + throw err; + } + return provider; + }); + } + + existsFile(resource: URI): TPromise { + if (resource.scheme === Schemas.file) { + return super.existsFile(resource); + } else { + return this.resolveFile(resource).then(data => true, err => false); + } + } + + resolveFile(resource: URI, options?: IResolveFileOptions): TPromise { + if (resource.scheme === Schemas.file) { + return super.resolveFile(resource, options); + } else { + return this._doResolveFiles([{ resource, options }]).then(data => { + if (data.length !== 1 || !data[0].success) { + throw new Error(`ENOENT, ${resource}`); + } else { + return data[0].stat; + } + }); + } + } + + resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + + // soft-groupBy, keep order, don't rearrange/merge groups + let groups: (typeof toResolve)[] = []; + let group: typeof toResolve; + for (const request of toResolve) { + if (!group || group[0].resource.scheme !== request.resource.scheme) { + group = []; + groups.push(group); + } + group.push(request); + } + + const promises: TPromise[] = []; + for (const group of groups) { + if (group[0].resource.scheme === Schemas.file) { + promises.push(super.resolveFiles(group)); + } else { + promises.push(this._doResolveFiles(group)); + } + } + return TPromise.join(promises).then(data => { + return [].concat(...data); + }); + } + + private _doResolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + return this._withProvider(toResolve[0].resource).then(provider => { + let result: IResolveFileResult[] = []; + let promises = toResolve.map((item, idx) => { + return provider.stat(item.resource).then(stat => { + return toDeepIFileStat(provider, [item.resource, stat], item.options && item.options.resolveTo).then(fileStat => { + result[idx] = { stat: fileStat, success: true }; + }); + }, err => { + result[idx] = { stat: undefined, success: false }; + }); + }); + return TPromise.join(promises).then(() => result); + }); + } + // --- resolve resolveContent(resource: URI, options?: IResolveContentOptions): TPromise { - if (this._provider.has(resource.authority)) { - return this._doResolveContent(resource); + if (resource.scheme === Schemas.file) { + return super.resolveContent(resource, options); + } else { + return this._doResolveContent(resource, options).then(RemoteFileService._asContent); } - - return super.resolveContent(resource, options); } resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { - if (this._provider.has(resource.authority)) { - return this._doResolveContent(resource).then(RemoteFileService._asStreamContent); + if (resource.scheme === Schemas.file) { + return super.resolveStreamContent(resource, options); + } else { + return this._doResolveContent(resource, options); } - - return super.resolveStreamContent(resource, options); } - private async _doResolveContent(resource: URI): TPromise { + private _doResolveContent(resource: URI, options: IResolveContentOptions = Object.create(null)): TPromise { + return this._withProvider(resource).then(provider => { - const stat = RemoteFileService._createFakeStat(resource); - const value = await this._provider.get(resource.authority).resolve(resource); - return { ...stat, value }; + return this.resolveFile(resource).then(fileStat => { + const guessEncoding = options.autoGuessEncoding; + const count = maxBufferLen(options); + const chunks: Buffer[] = []; + + return provider.read( + resource, + 0, count, + new Progress(chunk => chunks.push(chunk)) + ).then(bytesRead => { + // send to bla + return detectMimeAndEncodingFromBuffer({ bytesRead, buffer: Buffer.concat(chunks) }, guessEncoding); + + }).then(detected => { + if (options.acceptTextOnly && detected.mimes.indexOf(MIME_BINARY) >= 0) { + return TPromise.wrapError(new FileOperationError( + localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), + FileOperationResult.FILE_IS_BINARY + )); + } + + let preferredEncoding: string; + if (options && options.encoding) { + if (detected.encoding === UTF8 && options.encoding === UTF8) { + preferredEncoding = UTF8_with_bom; // indicate the file has BOM if we are to resolve with UTF 8 + } else { + preferredEncoding = options.encoding; // give passed in encoding highest priority + } + } else if (detected.encoding) { + if (detected.encoding === UTF8) { + preferredEncoding = UTF8_with_bom; // if we detected UTF-8, it can only be because of a BOM + } else { + preferredEncoding = detected.encoding; + } + // todo@remote - encoding logic should not be kept + // hostage inside the node file service + // } else if (super.configuredEncoding(resource) === UTF8_with_bom) { + } else { + preferredEncoding = UTF8; // if we did not detect UTF 8 BOM before, this can only be UTF 8 then + } + + // const encoding = this.getEncoding(resource); + const stream = decodeStream(preferredEncoding); + + // start with what we have already read + // and have a new stream to read the rest + let offset = 0; + for (const chunk of chunks) { + stream.write(chunk); + offset += chunk.length; + } + if (offset < count) { + // we didn't read enough the first time which means + // that we are done + stream.end(); + } else { + // there is more to read + provider.read(resource, offset, -1, new Progress(chunk => stream.write(chunk))).then(() => { + stream.end(); + }, err => { + stream.emit('error', err); + stream.end(); + }); + } + + return { + encoding: preferredEncoding, + value: stream, + resource: fileStat.resource, + name: fileStat.name, + etag: fileStat.etag, + mtime: fileStat.mtime, + }; + }); + }); + }); } // --- saving + createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise { + if (resource.scheme === Schemas.file) { + return super.createFile(resource, content, options); + } else { + return this._withProvider(resource).then(provider => { + let prepare = options && !options.overwrite + ? this.existsFile(resource) + : TPromise.as(false); + + + return prepare.then(exists => { + if (exists && options && !options.overwrite) { + return TPromise.wrapError(new FileOperationError('EEXIST', FileOperationResult.FILE_MODIFIED_SINCE)); + } + return this._doUpdateContent(provider, resource, content || '', {}); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat)); + return fileStat; + }); + }); + } + } + updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { - if (this._provider.has(resource.authority)) { - return this._doUpdateContent(resource, value).then(RemoteFileService._createFakeStat); + if (resource.scheme === Schemas.file) { + return super.updateContent(resource, value, options); + } else { + return this._withProvider(resource).then(provider => { + return this._doUpdateContent(provider, resource, value, options || {}); + }); + } + } + + private _doUpdateContent(provider: IFileSystemProvider, resource: URI, content: string, options: IUpdateContentOptions): TPromise { + const encoding = this.getEncoding(resource, options.encoding); + return provider.write(resource, encode(content, encoding)).then(() => { + return this.resolveFile(resource); + }); + } + + private static _asContent(content: IStreamContent): TPromise { + return new TPromise((resolve, reject) => { + let result: IContent = { + value: '', + encoding: content.encoding, + etag: content.etag, + mtime: content.mtime, + name: content.name, + resource: content.resource + }; + content.value.on('data', chunk => result.value += chunk); + content.value.on('error', reject); + content.value.on('end', () => resolve(result)); + }); + } + + // --- delete + + del(resource: URI, useTrash?: boolean): TPromise { + if (resource.scheme === Schemas.file) { + return super.del(resource, useTrash); + } else { + return this._withProvider(resource).then(provider => { + return provider.stat(resource).then(stat => { + return stat.type === FileType.Dir ? provider.rmdir(resource) : provider.unlink(resource); + }).then(() => { + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE)); + }); + }); + } + } + + createFolder(resource: URI): TPromise { + if (resource.scheme === Schemas.file) { + return super.createFolder(resource); + } else { + return this._withProvider(resource).then(provider => { + return provider.mkdir(resource).then(stat => { + return toIFileStat(provider, [resource, stat]); + }); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat)); + return fileStat; + }); + } + } + + rename(resource: URI, newName: string): TPromise { + if (resource.scheme === Schemas.file) { + return super.rename(resource, newName); + } else { + const target = resource.with({ path: join(resource.path, '..', newName) }); + return this._doMoveWithInScheme(resource, target, false); + } + } + + moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { + if (source.scheme !== target.scheme) { + return this._doMoveAcrossScheme(source, target); + } else if (source.scheme === Schemas.file) { + return super.moveFile(source, target, overwrite); + } else { + return this._doMoveWithInScheme(source, target, overwrite); + } + } + + private _doMoveWithInScheme(source: URI, target: URI, overwrite?: boolean): TPromise { + + const prepare = overwrite + ? this.del(target).then(undefined, err => { /*ignore*/ }) + : TPromise.as(null); + + return prepare.then(() => this._withProvider(source)).then(provider => { + return provider.move(source, target).then(stat => { + return toIFileStat(provider, [target, stat]); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, fileStat)); + return fileStat; + }); + }); + } + + private _doMoveAcrossScheme(source: URI, target: URI, overwrite?: boolean): TPromise { + return this.copyFile(source, target, overwrite).then(() => { + return this.del(source); + }).then(() => { + return this.resolveFile(target); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, fileStat)); + return fileStat; + }); + } + + importFile(source: URI, targetFolder: URI): TPromise { + if (source.scheme === targetFolder.scheme && source.scheme === Schemas.file) { + return super.importFile(source, targetFolder); + } else { + const target = targetFolder.with({ path: join(targetFolder.path, basename(source.path)) }); + return this.copyFile(source, target, false).then(stat => ({ stat, isNew: false })); + } + } + + copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { + if (source.scheme === target.scheme && source.scheme === Schemas.file) { + return super.copyFile(source, target, overwrite); } - return super.updateContent(resource, value, options); + const prepare = overwrite + ? this.del(target).then(undefined, err => { /*ignore*/ }) + : TPromise.as(null); + + return prepare.then(() => { + // TODO@Joh This does only work for textfiles + // because the content turns things into a string + // and all binary data will be broken + return this.resolveContent(source).then(content => { + return this._withProvider(target).then(provider => { + return this._doUpdateContent(provider, target, content.value, { encoding: content.encoding }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.COPY, fileStat)); + return fileStat; + }); + }, err => { + if (err instanceof Error && err.name === 'ENOPRO') { + // file scheme + return super.updateContent(target, content.value, { encoding: content.encoding }); + } else { + return TPromise.wrapError(err); + } + }); + }); + }); + } - private async _doUpdateContent(resource: URI, content: string): TPromise { - await this._provider.get(resource.authority).update(resource, content); - return resource; + touchFile(resource: URI): TPromise { + if (resource.scheme === Schemas.file) { + return super.touchFile(resource); + } else { + return this._doTouchFile(resource); + } } - // --- util - - private static _createFakeStat(resource: URI): IFileStat { - - return { - resource, - name: basename(resource.path), - encoding: 'utf8', - mtime: Date.now(), - etag: Date.now().toString(16), - isDirectory: false, - hasChildren: false - }; + private _doTouchFile(resource: URI): TPromise { + return this._withProvider(resource).then(provider => { + return provider.stat(resource).then(() => { + return provider.utimes(resource, Date.now(), Date.now()); + }, err => { + return provider.write(resource, new Uint8Array(0)); + }).then(() => { + return this.resolveFile(resource); + }); + }); } - private static _asStreamContent(content: IContent): IStreamContent { - const emitter = new EventEmitter(); - const { value } = content; - const result = content; - result.value = emitter; - setTimeout(() => { - emitter.emit('data', value); - emitter.emit('end'); - }, 0); - return result; + // TODO@Joh - file watching on demand! + public watchFileChanges(resource: URI): void { + if (resource.scheme === Schemas.file) { + super.watchFileChanges(resource); + } + } + public unwatchFileChanges(resource: URI): void { + if (resource.scheme === Schemas.file) { + super.unwatchFileChanges(resource); + } } } diff --git a/src/vs/workbench/services/files/node/fileService.ts b/src/vs/workbench/services/files/node/fileService.ts index 5cf7b843c4e..48910f60660 100644 --- a/src/vs/workbench/services/files/node/fileService.ts +++ b/src/vs/workbench/services/files/node/fileService.ts @@ -11,7 +11,7 @@ import os = require('os'); import crypto = require('crypto'); import assert = require('assert'); -import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, IFilesConfiguration } from 'vs/platform/files/common/files'; +import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, IFilesConfiguration, ICreateFileOptions } from 'vs/platform/files/common/files'; import { isEqualOrParent } from 'vs/base/common/paths'; import { ResourceMap } from 'vs/base/common/map'; import arrays = require('vs/base/common/arrays'); @@ -25,7 +25,7 @@ import uri from 'vs/base/common/uri'; import nls = require('vs/nls'); import { isWindows, isLinux } from 'vs/base/common/platform'; import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import pfs = require('vs/base/node/pfs'); import encoding = require('vs/base/node/encoding'); @@ -36,6 +36,7 @@ import { FileWatcher as WindowsWatcherService } from 'vs/workbench/services/file import { toFileChangesEvent, normalize, IRawFileChange } from 'vs/workbench/services/files/node/watcher/common'; import Event, { Emitter } from 'vs/base/common/event'; import { FileWatcher as NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/watcherService'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export interface IEncodingOverride { @@ -89,17 +90,16 @@ export class FileService implements IFileService { private undeliveredRawFileChangesEvents: IRawFileChange[]; private activeWorkspaceChangeWatcher: IDisposable; - private currentWorkspaceRootsCount: number; constructor( private contextService: IWorkspaceContextService, + private textResourceConfigurationService: ITextResourceConfigurationService, private configurationService: IConfigurationService, - options: IFileServiceOptions, + options: IFileServiceOptions ) { this.toDispose = []; this.options = options || Object.create(null); this.tmpPath = this.options.tmpDir || os.tmpdir(); - this.currentWorkspaceRootsCount = contextService.hasWorkspace() ? contextService.getWorkspace().roots.length : 0; this._onFileChanges = new Emitter(); this.toDispose.push(this._onFileChanges); @@ -111,36 +111,17 @@ export class FileService implements IFileService { this.options.errorLogger = console.error; } - if (this.currentWorkspaceRootsCount > 0 && !this.options.disableWatcher) { - this.setupWorkspaceWatching(); - } - this.activeFileChangesWatchers = new ResourceMap(); this.fileChangesWatchDelayer = new ThrottledDelayer(FileService.FS_EVENT_DELAY); this.undeliveredRawFileChangesEvents = []; + this.setupWorkspaceWatching(); + this.registerListeners(); } private registerListeners(): void { - this.toDispose.push(this.contextService.onDidChangeWorkspaceRoots(() => this.onDidChangeWorkspaceRoots())); - } - - private onDidChangeWorkspaceRoots(): void { - const newRootCount = this.contextService.hasWorkspace() ? this.contextService.getWorkspace().roots.length : 0; - - let restartWorkspaceWatcher = false; - if (this.currentWorkspaceRootsCount <= 1 && newRootCount > 1) { - restartWorkspaceWatcher = true; // transition: from 1 or 0 folders to 2+ - } else if (this.currentWorkspaceRootsCount > 1 && newRootCount <= 1) { - restartWorkspaceWatcher = true; // transition: from 2+ folders to 1 or 0 - } - - if (restartWorkspaceWatcher) { - this.setupWorkspaceWatching(); - } - - this.currentWorkspaceRootsCount = newRootCount; + this.toDispose.push(this.contextService.onDidChangeWorkbenchState(() => this.setupWorkspaceWatching())); } public get onFileChanges(): Event { @@ -164,8 +145,14 @@ export class FileService implements IFileService { this.activeWorkspaceChangeWatcher.dispose(); } + // Return if not aplicable + const workbenchState = this.contextService.getWorkbenchState(); + if (workbenchState === WorkbenchState.EMPTY || this.options.disableWatcher) { + return; + } + // new watcher: use it if setting tells us so or we run in multi-root environment - if (this.options.useExperimentalFileWatcher || this.contextService.getWorkspace().roots.length > 1) { + if (this.options.useExperimentalFileWatcher || workbenchState === WorkbenchState.WORKSPACE) { this.activeWorkspaceChangeWatcher = toDisposable(this.setupNsfwWorkspaceWatching().startWatching()); } @@ -218,7 +205,7 @@ export class FileService implements IFileService { // Guard early against attempts to resolve an invalid file path if (resource.scheme !== 'file' || !resource.fsPath) { return TPromise.wrapError(new FileOperationError( - nls.localize('fileInvalidPath', "Invalid file resource ({0})", resource.toString()), + nls.localize('fileInvalidPath', "Invalid file resource ({0})", resource.toString(true)), FileOperationResult.FILE_INVALID_PATH )); } @@ -290,7 +277,7 @@ export class FileService implements IFileService { // Return if file not found if (!exists) { return TPromise.wrapError(new FileOperationError( - nls.localize('fileNotFoundError', "File not found ({0})", resource.toString()), + nls.localize('fileNotFoundError', "File not found ({0})", resource.toString(true)), FileOperationResult.FILE_NOT_FOUND )); } @@ -379,15 +366,33 @@ export class FileService implements IFileService { }); } - public createFile(resource: uri, content: string = ''): TPromise { + public createFile(resource: uri, content: string = '', options: ICreateFileOptions = Object.create(null)): TPromise { + const absolutePath = this.toAbsolutePath(resource); - // Create file - return this.updateContent(resource, content).then(result => { + let checkFilePromise: TPromise; + if (options.overwrite) { + checkFilePromise = TPromise.as(false); + } else { + checkFilePromise = pfs.exists(absolutePath); + } - // Events - this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, result)); + // Check file exists + return checkFilePromise.then(exists => { + if (exists && !options.overwrite) { + return TPromise.wrapError(new FileOperationError( + nls.localize('fileExists', "File to create already exists ({0})", resource.toString(true)), + FileOperationResult.FILE_MODIFIED_SINCE + )); + } - return result; + // Create file + return this.updateContent(resource, content).then(result => { + + // Events + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, result)); + + return result; + }); }); } @@ -638,13 +643,13 @@ export class FileService implements IFileService { } private configuredAutoGuessEncoding(resource: uri): boolean { - const config = this.configurationService.getConfiguration(void 0, { resource }) as IFilesConfiguration; + const config = this.textResourceConfigurationService.getConfiguration(resource) as IFilesConfiguration; return config && config.files && config.files.autoGuessEncoding === true; } private configuredEncoding(resource: uri): string { - const config = this.configurationService.getConfiguration(void 0, { resource }) as IFilesConfiguration; + const config = this.textResourceConfigurationService.getConfiguration(resource) as IFilesConfiguration; return config && config.files && config.files.encoding; } @@ -713,60 +718,57 @@ export class FileService implements IFileService { let watcher = this.activeFileChangesWatchers.get(resource); if (!watcher) { const fsPath = resource.fsPath; + const fsName = paths.basename(resource.fsPath); try { - watcher = fs.watch(fsPath); // will be persistent but not recursive + watcher = extfs.watch(fsPath, (eventType: string, filename: string) => { + const renamedOrDeleted = ((filename && filename !== fsName) || eventType === 'rename'); + + // The file was either deleted or renamed. Many tools apply changes to files in an + // atomic way ("Atomic Save") by first renaming the file to a temporary name and then + // renaming it back to the original name. Our watcher will detect this as a rename + // and then stops to work on Mac and Linux because the watcher is applied to the + // inode and not the name. The fix is to detect this case and trying to watch the file + // again after a certain delay. + // In addition, we send out a delete event if after a timeout we detect that the file + // does indeed not exist anymore. + if (renamedOrDeleted) { + + // Very important to dispose the watcher which now points to a stale inode + this.unwatchFileChanges(resource); + + // Wait a bit and try to install watcher again, assuming that the file was renamed quickly ("Atomic Save") + setTimeout(() => { + this.existsFile(resource).done(exists => { + + // File still exists, so reapply the watcher + if (exists) { + this.watchFileChanges(resource); + } + + // File seems to be really gone, so emit a deleted event + else { + this.onRawFileChange({ + type: FileChangeType.DELETED, + path: fsPath + }); + } + }); + }, FileService.FS_REWATCH_DELAY); + } + + // Handle raw file change + this.onRawFileChange({ + type: FileChangeType.UPDATED, + path: fsPath + }); + }); } catch (error) { return; // the path might not exist anymore, ignore this error and return } this.activeFileChangesWatchers.set(resource, watcher); - // eventType is either 'rename' or 'change' - const fsName = paths.basename(resource.fsPath); - watcher.on('change', (eventType: string, filename: string) => { - const renamedOrDeleted = ((filename && filename !== fsName) || eventType === 'rename'); - - // The file was either deleted or renamed. Many tools apply changes to files in an - // atomic way ("Atomic Save") by first renaming the file to a temporary name and then - // renaming it back to the original name. Our watcher will detect this as a rename - // and then stops to work on Mac and Linux because the watcher is applied to the - // inode and not the name. The fix is to detect this case and trying to watch the file - // again after a certain delay. - // In addition, we send out a delete event if after a timeout we detect that the file - // does indeed not exist anymore. - if (renamedOrDeleted) { - - // Very important to dispose the watcher which now points to a stale inode - this.unwatchFileChanges(resource); - - // Wait a bit and try to install watcher again, assuming that the file was renamed quickly ("Atomic Save") - setTimeout(() => { - this.existsFile(resource).done(exists => { - - // File still exists, so reapply the watcher - if (exists) { - this.watchFileChanges(resource); - } - - // File seems to be really gone, so emit a deleted event - else { - this.onRawFileChange({ - type: FileChangeType.DELETED, - path: fsPath - }); - } - }); - }, FileService.FS_REWATCH_DELAY); - } - - // Handle raw file change - this.onRawFileChange({ - type: FileChangeType.UPDATED, - path: fsPath - }); - }); - // Errors watcher.on('error', (error: string) => { this.options.errorLogger(error); @@ -917,11 +919,11 @@ export class StatResolver { clb(null, null); // return - we might not have permissions to read the folder or stat the file }, - function stat(): void { + function stat(this: any): void { fs.stat(fileResource.fsPath, this); }, - function countChildren(fsstat: fs.Stats): void { + function countChildren(this: any, fsstat: fs.Stats): void { fileStat = fsstat; if (fileStat.isDirectory()) { diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts index b3f8c608892..b8c93d184de 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts @@ -81,30 +81,33 @@ export class FileWatcher { }); // Start watching - this.updateRoots(); - this.toDispose.push(this.contextService.onDidChangeWorkspaceRoots(() => this.updateRoots())); - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.updateRoots())); + this.updateFolders(); + this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => this.updateFolders())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('files.watcherExclude')) { + this.updateFolders(); + } + })); return () => this.dispose(); } - private updateRoots() { + private updateFolders() { if (this.isDisposed) { return; } - const roots = this.contextService.getWorkspace().roots; - this.service.setRoots(roots.map(root => { + this.service.setRoots(this.contextService.getWorkspace().folders.map(folder => { // Fetch the root's watcherExclude setting and return it - const configuration = this.configurationService.getConfiguration(undefined, { - resource: root + const configuration = this.configurationService.getConfiguration({ + resource: folder.uri }); let ignored: string[] = []; if (configuration.files && configuration.files.watcherExclude) { ignored = Object.keys(configuration.files.watcherExclude).filter(k => !!configuration.files.watcherExclude[k]); } return { - basePath: root.fsPath, + basePath: folder.uri.fsPath, ignored }; })); diff --git a/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts b/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts index 3dc0a747c60..ecc68bde9c0 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/unix/chokidarWatcherService.ts @@ -63,6 +63,12 @@ export class ChokidarWatcherService implements IWatcherService { return new TPromise((c, e, p) => { chokidarWatcher.on('all', (type: string, path: string) => { + if (isMacintosh) { + // Mac: uses NFD unicode form on disk, but we want NFC + // See also https://github.com/nodejs/node/issues/2165 + path = strings.normalizeNFC(path); + } + if (path.indexOf(realBasePath) < 0) { return; // we really only care about absolute paths here in our basepath context here } diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts b/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts index 0f96d2c3b9c..7c4917dc472 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts @@ -52,7 +52,7 @@ export class FileWatcher { const service = new WatcherChannelClient(channel); // Start watching - const basePath: string = normalize(this.contextService.getWorkspace().roots[0].fsPath); + const basePath: string = normalize(this.contextService.getWorkspace().folders[0].uri.fsPath); service.watch({ basePath: basePath, ignored: this.ignored, verboseLogging: this.verboseLogging }).then(null, err => { if (!this.isDisposed && !(err instanceof Error && err.name === 'Canceled' && err.message === 'Canceled')) { return TPromise.wrapError(err); // the service lib uses the promise cancel error to indicate the process died, we do not want to bubble this up diff --git a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts b/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts index 54ba8d297fd..26295cbc4a9 100644 --- a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts @@ -26,7 +26,7 @@ export class FileWatcher { } public startWatching(): () => void { - let basePath: string = normalize(this.contextService.getWorkspace().roots[0].fsPath); + let basePath: string = normalize(this.contextService.getWorkspace().folders[0].uri.fsPath); if (basePath && basePath.indexOf('\\\\') === 0 && endsWith(basePath, sep)) { // for some weird reason, node adds a trailing slash to UNC paths diff --git a/src/vs/workbench/services/files/test/node/fileService.test.ts b/src/vs/workbench/services/files/test/node/fileService.test.ts index 681c96c8aba..428474c05b7 100644 --- a/src/vs/workbench/services/files/test/node/fileService.test.ts +++ b/src/vs/workbench/services/files/test/node/fileService.test.ts @@ -19,26 +19,26 @@ import extfs = require('vs/base/node/extfs'); import encodingLib = require('vs/base/node/encoding'); import utils = require('vs/workbench/services/files/test/node/utils'); import { onError } from 'vs/base/test/common/utils'; -import { TestContextService } from 'vs/workbench/test/workbenchTestServices'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; suite('FileService', () => { let service: FileService; - let parentDir = path.join(os.tmpdir(), 'vsctests', 'service'); + const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'fileservice'); let testDir: string; setup(function (done) { - let id = uuid.generateUuid(); + const id = uuid.generateUuid(); testDir = path.join(parentDir, id); - let sourceDir = require.toUrl('./fixtures/service'); + const sourceDir = require.toUrl('./fixtures/service'); extfs.copy(sourceDir, testDir, (error) => { if (error) { return onError(error, done); } - service = new FileService(new TestContextService(new Workspace(testDir, testDir, [uri.file(testDir)])), new TestConfigurationService(), { disableWatcher: true }); + service = new FileService(new TestContextService(new Workspace(testDir, testDir, toWorkspaceFolders([{ path: testDir }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }); done(); }); }); @@ -71,6 +71,45 @@ suite('FileService', () => { }, error => onError(error, done)); }); + test('createFile (does not overwrite by default)', function (done: () => void) { + const contents = 'Hello World'; + const resource = uri.file(path.join(testDir, 'test.txt')); + + fs.writeFileSync(resource.fsPath, ''); // create file + + service.createFile(resource, contents).done(null, error => { + assert.ok(error); + + done(); + }); + }); + + test('createFile (allows to overwrite existing)', function (done: () => void) { + let event: FileOperationEvent; + const toDispose = service.onAfterOperation(e => { + event = e; + }); + + const contents = 'Hello World'; + const resource = uri.file(path.join(testDir, 'test.txt')); + + fs.writeFileSync(resource.fsPath, ''); // create file + + service.createFile(resource, contents, { overwrite: true }).done(s => { + assert.equal(s.name, 'test.txt'); + assert.equal(fs.existsSync(s.resource.fsPath), true); + assert.equal(fs.readFileSync(s.resource.fsPath), contents); + + assert.ok(event); + assert.equal(event.resource.fsPath, resource.fsPath); + assert.equal(event.operation, FileOperation.CREATE); + assert.equal(event.target.resource.fsPath, resource.fsPath); + toDispose.dispose(); + + done(); + }, error => onError(error, done)); + }); + test('createFolder', function (done: () => void) { let event: FileOperationEvent; const toDispose = service.onAfterOperation(e => { @@ -487,7 +526,7 @@ suite('FileService', () => { service.resolveFile(uri.file(testDir), { resolveTo: [uri.file(path.join(testDir, 'deep'))] }).done(r => { assert.equal(r.children.length, 6); - let deep = utils.getByName(r, 'deep'); + const deep = utils.getByName(r, 'deep'); assert.equal(deep.children.length, 4); done(); @@ -503,7 +542,7 @@ suite('FileService', () => { assert.equal(r1.children.length, 6); - let deep = utils.getByName(r1, 'deep'); + const deep = utils.getByName(r1, 'deep'); assert.equal(deep.children.length, 4); const r2 = res[1].stat; @@ -527,7 +566,7 @@ suite('FileService', () => { }); test('updateContent', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'small.txt')); + const resource = uri.file(path.join(testDir, 'small.txt')); service.resolveContent(resource).done(c => { assert.equal(c.value, 'Small File'); @@ -543,8 +582,8 @@ suite('FileService', () => { }); test('updateContent - use encoding (UTF 16 BE)', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'small.txt')); - let encoding = 'utf16be'; + const resource = uri.file(path.join(testDir, 'small.txt')); + const encoding = 'utf16be'; service.resolveContent(resource).done(c => { c.encoding = encoding; @@ -564,8 +603,8 @@ suite('FileService', () => { }); test('updateContent - encoding preserved (UTF 16 LE)', function (done: () => void) { - let encoding = 'utf16le'; - let resource = uri.file(path.join(testDir, 'some_utf16le.css')); + const encoding = 'utf16le'; + const resource = uri.file(path.join(testDir, 'some_utf16le.css')); service.resolveContent(resource).done(c => { assert.equal(c.encoding, encoding); @@ -587,7 +626,7 @@ suite('FileService', () => { }); test('resolveContent - FILE_IS_BINARY', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'binary.txt')); + const resource = uri.file(path.join(testDir, 'binary.txt')); service.resolveContent(resource, { acceptTextOnly: true }).done(null, (e: FileOperationError) => { assert.equal(e.fileOperationResult, FileOperationResult.FILE_IS_BINARY); @@ -601,7 +640,7 @@ suite('FileService', () => { }); test('resolveContent - FILE_IS_DIRECTORY', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'deep')); + const resource = uri.file(path.join(testDir, 'deep')); service.resolveContent(resource).done(null, (e: FileOperationError) => { assert.equal(e.fileOperationResult, FileOperationResult.FILE_IS_DIRECTORY); @@ -611,7 +650,7 @@ suite('FileService', () => { }); test('resolveContent - FILE_NOT_FOUND', function (done: () => void) { - let resource = uri.file(path.join(testDir, '404.html')); + const resource = uri.file(path.join(testDir, '404.html')); service.resolveContent(resource).done(null, (e: FileOperationError) => { assert.equal(e.fileOperationResult, FileOperationResult.FILE_NOT_FOUND); @@ -621,7 +660,7 @@ suite('FileService', () => { }); test('resolveContent - FILE_NOT_MODIFIED_SINCE', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'index.html')); + const resource = uri.file(path.join(testDir, 'index.html')); service.resolveContent(resource).done(c => { return service.resolveContent(resource, { etag: c.etag }).then(null, (e: FileOperationError) => { @@ -633,7 +672,7 @@ suite('FileService', () => { }); test('resolveContent - FILE_MODIFIED_SINCE', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'index.html')); + const resource = uri.file(path.join(testDir, 'index.html')); service.resolveContent(resource).done(c => { fs.writeFileSync(resource.fsPath, 'Updates Incoming!'); @@ -647,8 +686,8 @@ suite('FileService', () => { }); test('resolveContent - encoding picked up', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'index.html')); - let encoding = 'windows1252'; + const resource = uri.file(path.join(testDir, 'index.html')); + const encoding = 'windows1252'; service.resolveContent(resource, { encoding: encoding }).done(c => { assert.equal(c.encoding, encoding); @@ -658,7 +697,7 @@ suite('FileService', () => { }); test('resolveContent - user overrides BOM', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'some_utf16le.css')); + const resource = uri.file(path.join(testDir, 'some_utf16le.css')); service.resolveContent(resource, { encoding: 'windows1252' }).done(c => { assert.equal(c.encoding, 'windows1252'); @@ -668,7 +707,7 @@ suite('FileService', () => { }); test('resolveContent - BOM removed', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'some_utf8_bom.txt')); + const resource = uri.file(path.join(testDir, 'some_utf8_bom.txt')); service.resolveContent(resource).done(c => { assert.equal(encodingLib.detectEncodingByBOMFromBuffer(new Buffer(c.value), 512), null); @@ -678,7 +717,7 @@ suite('FileService', () => { }); test('resolveContent - invalid encoding', function (done: () => void) { - let resource = uri.file(path.join(testDir, 'index.html')); + const resource = uri.file(path.join(testDir, 'index.html')); service.resolveContent(resource, { encoding: 'superduper' }).done(c => { assert.equal(c.encoding, 'utf8'); @@ -688,7 +727,7 @@ suite('FileService', () => { }); test('watchFileChanges', function (done: () => void) { - let toWatch = uri.file(path.join(testDir, 'index.html')); + const toWatch = uri.file(path.join(testDir, 'index.html')); service.watchFileChanges(toWatch); @@ -705,7 +744,7 @@ suite('FileService', () => { }); test('watchFileChanges - support atomic save', function (done: () => void) { - let toWatch = uri.file(path.join(testDir, 'index.html')); + const toWatch = uri.file(path.join(testDir, 'index.html')); service.watchFileChanges(toWatch); @@ -729,21 +768,23 @@ suite('FileService', () => { test('options - encoding', function (done: () => void) { // setup - let _id = uuid.generateUuid(); - let _testDir = path.join(parentDir, _id); - let _sourceDir = require.toUrl('./fixtures/service'); + const _id = uuid.generateUuid(); + const _testDir = path.join(parentDir, _id); + const _sourceDir = require.toUrl('./fixtures/service'); extfs.copy(_sourceDir, _testDir, () => { - let encodingOverride: IEncodingOverride[] = []; + const encodingOverride: IEncodingOverride[] = []; encodingOverride.push({ resource: uri.file(path.join(testDir, 'deep')), encoding: 'utf16le' }); - let configurationService = new TestConfigurationService(); + const configurationService = new TestConfigurationService(); configurationService.setUserConfiguration('files', { encoding: 'windows1252' }); - let _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [uri.file(_testDir)])), configurationService, { + const textResourceConfigurationService = new TestTextResourceConfigurationService(configurationService); + + const _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, toWorkspaceFolders([{ path: _testDir }]))), textResourceConfigurationService, configurationService, { encodingOverride, disableWatcher: true }); @@ -765,12 +806,12 @@ suite('FileService', () => { test('UTF 8 BOMs', function (done: () => void) { // setup - let _id = uuid.generateUuid(); - let _testDir = path.join(parentDir, _id); - let _sourceDir = require.toUrl('./fixtures/service'); - let resource = uri.file(path.join(testDir, 'index.html')); + const _id = uuid.generateUuid(); + const _testDir = path.join(parentDir, _id); + const _sourceDir = require.toUrl('./fixtures/service'); + const resource = uri.file(path.join(testDir, 'index.html')); - let _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [uri.file(_testDir)])), new TestConfigurationService(), { + const _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, toWorkspaceFolders([{ path: _testDir }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }); diff --git a/src/vs/workbench/services/files/test/node/watcher.test.ts b/src/vs/workbench/services/files/test/node/watcher.test.ts index a8c6b9ee80b..705595868cf 100644 --- a/src/vs/workbench/services/files/test/node/watcher.test.ts +++ b/src/vs/workbench/services/files/test/node/watcher.test.ts @@ -44,7 +44,7 @@ enum Path { UNIX, WINDOWS, UNC -}; +} suite('Watcher', () => { diff --git a/src/vs/workbench/services/group/common/groupService.ts b/src/vs/workbench/services/group/common/groupService.ts index 4f0ec01d264..a04e26bbd89 100644 --- a/src/vs/workbench/services/group/common/groupService.ts +++ b/src/vs/workbench/services/group/common/groupService.ts @@ -5,9 +5,9 @@ 'use strict'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, ServiceIdentifier, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Position, IEditorInput } from 'vs/platform/editor/common/editor'; -import { IEditorStacksModel, IEditorGroup } from 'vs/workbench/common/editor'; +import { IEditorStacksModel, IEditorGroup, IEditorOpeningEvent } from 'vs/workbench/common/editor'; import Event from 'vs/base/common/event'; export enum GroupArrangement { @@ -19,11 +19,12 @@ export type GroupOrientation = 'vertical' | 'horizontal'; export const IEditorGroupService = createDecorator('editorGroupService'); -export interface ITabOptions { +export interface IEditorTabOptions { showTabs?: boolean; tabCloseButton?: 'left' | 'right' | 'off'; showIcons?: boolean; previewEditors?: boolean; + labelFormat?: 'default' | 'short' | 'medium' | 'long'; } export interface IMoveOptions { @@ -44,15 +45,20 @@ export interface IEditorGroupService { */ onEditorsChanged: Event; + /** + * Emitted when an editor is opening. Allows to prevent/replace the opening via the event method. + */ + onEditorOpening: Event; + /** * Emitted when opening an editor fails. */ onEditorOpenFail: Event; /** - * Emitted when a editors are moved to another position. + * Emitted when an entire editor group is moved to another position. */ - onEditorsMoved: Event; + onEditorGroupMoved: Event; /** * Emitted when the editor group orientation was changed. @@ -62,7 +68,7 @@ export interface IEditorGroupService { /** * Emitted when tab options changed. */ - onTabOptionsChanged: Event; + onTabOptionsChanged: Event; /** * Keyboard focus the editor group at the provided position. @@ -130,5 +136,10 @@ export interface IEditorGroupService { /** * Returns tab options. */ - getTabOptions(): ITabOptions; + getTabOptions(): IEditorTabOptions; + + /** + * Invoke a function in the context of the active editor. + */ + invokeWithinEditorContext(fn: (accessor: ServicesAccessor) => T): T; } \ No newline at end of file diff --git a/src/vs/workbench/services/hash/common/hashService.ts b/src/vs/workbench/services/hash/common/hashService.ts new file mode 100644 index 00000000000..e8e2ee18d9d --- /dev/null +++ b/src/vs/workbench/services/hash/common/hashService.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'; + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IHashService = createDecorator('hashService'); + +export interface IHashService { + _serviceBrand: any; + + /** + * Produce a SHA1 hash of the provided content. + */ + createSHA1(content: string): string; +} \ No newline at end of file diff --git a/src/vs/workbench/services/hash/node/hashService.ts b/src/vs/workbench/services/hash/node/hashService.ts new file mode 100644 index 00000000000..fec0cab111f --- /dev/null +++ b/src/vs/workbench/services/hash/node/hashService.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { createHash } from 'crypto'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; + +export class HashService implements IHashService { + + _serviceBrand: any; + + public createSHA1(content: string): string { + return createHash('sha1').update(content).digest('hex'); + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 45377e011ec..04c8610f378 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -9,24 +9,24 @@ import { TPromise } from 'vs/base/common/winjs.base'; import errors = require('vs/base/common/errors'); import URI from 'vs/base/common/uri'; import { IEditor } from 'vs/editor/common/editorCommon'; -import { IEditor as IBaseEditor, IEditorInput, ITextEditorOptions, IResourceInput } from 'vs/platform/editor/common/editor'; -import { EditorInput, IEditorCloseEvent, IEditorRegistry, Extensions, toResource, IEditorGroup } from 'vs/workbench/common/editor'; +import { IEditor as IBaseEditor, IEditorInput, ITextEditorOptions, IResourceInput, ITextEditorSelection, Position as GroupPosition } from 'vs/platform/editor/common/editor'; +import { Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorGroup, IEditorInputFactoryRegistry, toResource } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { FileChangesEvent, IFileService, FileChangeType } from 'vs/platform/files/common/files'; +import { FileChangesEvent, IFileService, FileChangeType, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files'; import { Selection } from 'vs/editor/common/core/selection'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; -import { once } from 'vs/base/common/event'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { once, debounceEvent } from 'vs/base/common/event'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { getExcludes, ISearchConfiguration } from 'vs/platform/search/common/search'; -import { parse, IExpression } from 'vs/base/common/glob'; +import { IExpression } from 'vs/base/common/glob'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ResourceGlobMatcher } from 'vs/workbench/common/resources'; @@ -34,38 +34,44 @@ import { ResourceGlobMatcher } from 'vs/workbench/common/resources'; /** * Stores the selection & view state of an editor and allows to compare it to other selection states. */ -export class EditorState { +export class TextEditorState { - private static EDITOR_SELECTION_THRESHOLD = 5; // number of lines to move in editor to justify for new state + private static EDITOR_SELECTION_THRESHOLD = 10; // number of lines to move in editor to justify for new state + + private textEditorSelection: ITextEditorSelection; constructor(private _editorInput: IEditorInput, private _selection: Selection) { + this.textEditorSelection = Selection.isISelection(_selection) ? { + startLineNumber: _selection.startLineNumber, + startColumn: _selection.startColumn + } : void 0; } public get editorInput(): IEditorInput { return this._editorInput; } - public get selection(): Selection { - return this._selection; + public get selection(): ITextEditorSelection { + return this.textEditorSelection; } - public justifiesNewPushState(other: EditorState, event?: ICursorPositionChangedEvent): boolean { + public justifiesNewPushState(other: TextEditorState, event?: ICursorPositionChangedEvent): boolean { + if (event && event.source === 'api') { + return true;Ā //Ā alwaysĀ letĀ APIĀ sourceĀ winĀ (e.g.Ā "GoĀ toĀ definition"Ā shouldĀ addĀ aĀ historyĀ entry) + } + if (!this._editorInput.matches(other._editorInput)) { - return true; // push different editor inputs + return true; // different editor inputs } if (!Selection.isISelection(this._selection) || !Selection.isISelection(other._selection)) { return true; // unknown selections } - if (event && event.source === 'api') { - return true;Ā //Ā alwaysĀ letĀ APIĀ sourceĀ winĀ (e.g.Ā "GoĀ toĀ definition"Ā shouldĀ addĀ aĀ historyĀ entry) - } - - const myLineNumber = Math.min(this._selection.selectionStartLineNumber, this._selection.positionLineNumber); + const thisLineNumber = Math.min(this._selection.selectionStartLineNumber, this._selection.positionLineNumber); const otherLineNumber = Math.min(other._selection.selectionStartLineNumber, other._selection.positionLineNumber); - if (Math.abs(myLineNumber - otherLineNumber) < EditorState.EDITOR_SELECTION_THRESHOLD) { + if (Math.abs(thisLineNumber - otherLineNumber) < TextEditorState.EDITOR_SELECTION_THRESHOLD) { return false; // ignore selection changes in the range of EditorState.EDITOR_SELECTION_THRESHOLD lines } @@ -73,9 +79,14 @@ export class EditorState { } } -interface ISerializedFileHistoryEntry { - resource?: string; - resourceJSON: object; +interface ISerializedEditorHistoryEntry { + resourceJSON?: object; + editorInputJSON?: { typeId: string; deserialized: string; }; +} + +interface IEditorIdentifier { + editor: IEditorInput; + position: GroupPosition; } export abstract class BaseHistoryService { @@ -83,6 +94,7 @@ export abstract class BaseHistoryService { protected toUnbind: IDisposable[]; private activeEditorListeners: IDisposable[]; + private lastActiveEditor: IEditorIdentifier; constructor( protected editorGroupService: IEditorGroupService, @@ -96,25 +108,46 @@ export abstract class BaseHistoryService { } private onEditorsChanged(): void { + const activeEditor = this.editorService.getActiveEditor(); + if (this.lastActiveEditor && this.matchesEditor(this.lastActiveEditor, activeEditor)) { + return; // return if the active editor is still the same + } + + // Remember as last active editor (can be undefined if none opened) + this.lastActiveEditor = activeEditor ? { editor: activeEditor.input, position: activeEditor.position } : void 0; // Dispose old listeners dispose(this.activeEditorListeners); this.activeEditorListeners = []; - const activeEditor = this.editorService.getActiveEditor(); - // Propagate to history this.handleActiveEditorChange(activeEditor); // Apply listener for selection changes if this is a text editor const control = getCodeEditor(activeEditor); if (control) { - this.activeEditorListeners.push(control.onDidChangeCursorPosition(event => { + + // Debounce the event with a timeout of 0ms so that multiple calls to + // editor.setSelection() are folded into one. We do not want to record + // subsequent history navigations for such API calls. + this.activeEditorListeners.push(debounceEvent(control.onDidChangeCursorPosition, (last, event) => event, 0)((event => { this.handleEditorSelectionChangeEvent(activeEditor, event); - })); + }))); } } + private matchesEditor(identifier: IEditorIdentifier, editor?: IBaseEditor): boolean { + if (!editor) { + return false; + } + + if (identifier.position !== editor.position) { + return false; + } + + return identifier.editor.matches(editor.input); + } + protected abstract handleExcludesChange(): void; protected abstract handleEditorSelectionChangeEvent(editor?: IBaseEditor, event?: ICursorPositionChangedEvent): void; @@ -128,7 +161,7 @@ export abstract class BaseHistoryService { interface IStackEntry { input: IEditorInput | IResourceInput; - options?: ITextEditorOptions; + selection?: ITextEditorSelection; timestamp: number; } @@ -145,17 +178,16 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private static MAX_HISTORY_ITEMS = 200; private static MAX_STACK_ITEMS = 20; private static MAX_RECENTLY_CLOSED_EDITORS = 20; - private static MERGE_EVENT_CHANGES_THRESHOLD = 100; private stack: IStackEntry[]; private index: number; + private lastIndex: number; private navigatingInStack: boolean; - private currentFileEditorState: EditorState; + private currentTextEditorState: TextEditorState; private history: (IEditorInput | IResourceInput)[]; private recentlyClosedFiles: IRecentlyClosedFile[]; private loaded: boolean; - private registry: IEditorRegistry; private resourceFilter: ResourceGlobMatcher; constructor( @@ -172,23 +204,32 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic super(editorGroupService, editorService); this.index = -1; + this.lastIndex = -1; this.stack = []; this.recentlyClosedFiles = []; this.loaded = false; - this.registry = Registry.as(Extensions.Editors); - this.resourceFilter = instantiationService.createInstance(ResourceGlobMatcher, (root: URI) => this.getExcludes(root), (expression: IExpression) => parse(expression)); + this.resourceFilter = instantiationService.createInstance( + ResourceGlobMatcher, + (root: URI) => this.getExcludes(root), + (event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) || event.affectsConfiguration('search.exclude') + ); this.registerListeners(); } + private setIndex(value: number): void { + this.lastIndex = this.index; + this.index = value; + } + private getExcludes(root?: URI): IExpression { const scope = root ? { resource: root } : void 0; - return getExcludes(this.configurationService.getConfiguration(void 0, scope)); + return getExcludes(this.configurationService.getConfiguration(scope)); } private registerListeners(): void { - this.toUnbind.push(this.lifecycleService.onShutdown(reason => this.save())); + this.toUnbind.push(this.lifecycleService.onShutdown(reason => this.saveHistory())); this.toUnbind.push(this.editorGroupService.onEditorOpenFail(editor => this.remove(editor))); this.toUnbind.push(this.editorGroupService.getStacksModel().onEditorClosed(event => this.onEditorClosed(event))); this.toUnbind.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); @@ -205,12 +246,13 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic // Track closing of pinned editor to support to reopen closed editors if (event.pinned) { - const file = toResource(event.editor, { filter: 'file' }); // we only support files to reopen - if (file) { + const resource = event.editor ? event.editor.getResource() : void 0; + const supportsReopen = resource && this.fileService.canHandleResource(resource); // we only support file'ish things to reopen + if (supportsReopen) { // Remove all inputs matching and add as last recently closed this.removeFromRecentlyClosedFiles(event.editor); - this.recentlyClosedFiles.push({ resource: file, index: event.index }); + this.recentlyClosedFiles.push({ resource, index: event.index }); // Bounding if (this.recentlyClosedFiles.length > HistoryService.MAX_RECENTLY_CLOSED_EDITORS) { @@ -246,7 +288,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } private doForwardInEditors(): void { - this.index++; + this.setIndex(this.index + 1); this.navigate(); } @@ -260,8 +302,9 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic const previousEntry = this.stack[currentIndex]; if (!this.matches(currentEntry.input, previousEntry.input)) { - this.index = currentIndex; + this.setIndex(currentIndex); this.navigate(true /* across editors */); + break; } } @@ -277,8 +320,17 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } } + public last(): void { + if (this.lastIndex === -1) { + this.back(); + } else { + this.setIndex(this.lastIndex); + this.navigate(); + } + } + private doBackInEditors(): void { - this.index--; + this.setIndex(this.index - 1); this.navigate(); } @@ -292,8 +344,9 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic const previousEntry = this.stack[currentIndex]; if (!this.matches(currentEntry.input, previousEntry.input)) { - this.index = currentIndex; + this.setIndex(currentIndex); this.navigate(true /* across editors */); + break; } } @@ -303,6 +356,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic this.ensureHistoryLoaded(); this.index = -1; + this.lastIndex = -1; this.stack.splice(0); this.history = []; this.recentlyClosedFiles = []; @@ -311,11 +365,15 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private navigate(acrossEditors?: boolean): void { const entry = this.stack[this.index]; - let options = entry.options; - if (options && !acrossEditors /* ignore line/col options when going across editors */) { - options.revealIfOpened = true; - } else { - options = { revealIfOpened: true }; + const options: ITextEditorOptions = { + revealIfOpened: true // support to navigate across editor groups + }; + + // Unless we navigate across editors, support selection and + // minimize scrolling by setting revealInCenterIfOutsideViewport + if (entry.selection && !acrossEditors) { + options.selection = entry.selection; + options.revealInCenterIfOutsideViewport = true; } this.navigatingInStack = true; @@ -368,10 +426,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic // Remove this from the history unless the history input is a resource // that can easily be restored even when the input gets disposed if (historyInput instanceof EditorInput) { - const onceDispose = once(historyInput.onDispose); - onceDispose(() => { - this.removeFromHistory(input); - }); + once(historyInput.onDispose)(() => this.removeFromHistory(input)); } } @@ -415,47 +470,50 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic // treat editor changes that happen as part of stack navigation specially // we do not want to add a new stack entry as a matter of navigating the - // stack but we need to keep our currentFileEditorState up to date with + // stack but we need to keep our currentTextEditorState up to date with // the navigtion that occurs. if (this.navigatingInStack) { if (control && editor.input) { - this.currentFileEditorState = new EditorState(editor.input, control.getSelection()); + this.currentTextEditorState = new TextEditorState(editor.input, control.getSelection()); } else { - this.currentFileEditorState = null; // we navigated to a non file editor + this.currentTextEditorState = null; // we navigated to a non text editor + } + } + + // normal navigation not part of history navigation + else { + + // navigation inside text editor + if (control && editor.input) { + this.handleTextEditorEvent(editor, control, event); } - return; - } + // navigation to non-text editor + else { + this.currentTextEditorState = null; // at this time we have no active text editor view state - if (control && editor.input) { - this.handleTextEditorEvent(editor, control, event); - - return; - } - - this.currentFileEditorState = null; // at this time we have no active file editor view state - - if (editor && editor.input) { - this.handleNonTextEditorEvent(editor); + if (editor && editor.input) { + this.handleNonTextEditorEvent(editor); + } + } } } private handleTextEditorEvent(editor: IBaseEditor, editorControl: IEditor, event?: ICursorPositionChangedEvent): void { - const stateCandidate = new EditorState(editor.input, editorControl.getSelection()); - if (!this.currentFileEditorState || this.currentFileEditorState.justifiesNewPushState(stateCandidate, event)) { - this.currentFileEditorState = stateCandidate; + const stateCandidate = new TextEditorState(editor.input, editorControl.getSelection()); - let options: ITextEditorOptions; - - const selection = editorControl.getSelection(); - if (selection) { - options = { - selection: { startLineNumber: selection.startLineNumber, startColumn: selection.startColumn } - }; - } - - this.add(editor.input, options, true /* from event */); + // Add to stack if we dont have a current state or this new state justifies a push + if (!this.currentTextEditorState || this.currentTextEditorState.justifiesNewPushState(stateCandidate, event)) { + this.add(editor.input, stateCandidate.selection); } + + // Otherwise we replace the current stack entry with this one + else { + this.replace(editor.input, stateCandidate.selection); + } + + // Update our current text editor state + this.currentTextEditorState = stateCandidate; } private handleNonTextEditorEvent(editor: IBaseEditor): void { @@ -464,39 +522,43 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic return; // do not push same editor input again } - this.add(editor.input, void 0, true /* from event */); + this.add(editor.input); } - public add(input: IEditorInput, options?: ITextEditorOptions, fromEvent?: boolean): void { + public add(input: IEditorInput, selection?: ITextEditorSelection): void { if (!this.navigatingInStack) { - this.addToStack(input, options, fromEvent); + this.addOrReplaceInStack(input, selection); } } - private addToStack(input: IEditorInput, options?: ITextEditorOptions, fromEvent?: boolean): void { + private replace(input: IEditorInput, selection?: ITextEditorSelection): void { + if (!this.navigatingInStack) { + this.addOrReplaceInStack(input, selection, true /* force replace */); + } + } + + private addOrReplaceInStack(input: IEditorInput, selection?: ITextEditorSelection, forceReplace?: boolean): void { // Overwrite an entry in the stack if we have a matching input that comes // with editor options to indicate that this entry is more specific. Also // prevent entries that have the exact same options. Finally, Overwrite - // entries if it came from an event and we detect that the change came in - // very fast which indicates that it was not coming in from a user change - // but rather rapid programmatic changes. We just take the last of the changes - // to not cause too many entries on the stack. + // entries if we detect that the change came in very fast which indicates + // that it was not coming in from a user change but rather rapid programmatic + // changes. We just take the last of the changes to not cause too many entries + // on the stack. + // We can also be instructed to force replace the last entry. let replace = false; - if (this.stack[this.index]) { - const currentEntry = this.stack[this.index]; - if (this.matches(input, currentEntry.input) && (this.sameOptions(currentEntry.options, options) || (fromEvent && Date.now() - currentEntry.timestamp < HistoryService.MERGE_EVENT_CHANGES_THRESHOLD))) { - replace = true; + const currentEntry = this.stack[this.index]; + if (currentEntry) { + if (forceReplace) { + replace = true; // replace if we are forced to + } else if (this.matches(input, currentEntry.input) && this.sameSelection(currentEntry.selection, selection)) { + replace = true; // replace if the input is the same as the current one and the selection as well } } const stackInput = this.preferResourceInput(input); - const entry = { input: stackInput, options, timestamp: fromEvent ? Date.now() : void 0 }; - - // If we are not at the end of history, we remove anything after - if (this.stack.length > this.index + 1) { - this.stack = this.stack.slice(0, this.index + 1); - } + const entry = { input: stackInput, selection, timestamp: Date.now() }; // Replace at current position if (replace) { @@ -505,63 +567,58 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic // Add to stack at current position else { - this.index++; - this.stack.splice(this.index, 0, entry); + + // If we are not at the end of history, we remove anything after + if (this.stack.length > this.index + 1) { + this.stack = this.stack.slice(0, this.index + 1); + } + + this.stack.splice(this.index + 1, 0, entry); // Check for limit if (this.stack.length > HistoryService.MAX_STACK_ITEMS) { this.stack.shift(); // remove first and dispose - if (this.index > 0) { - this.index--; + if (this.lastIndex >= 0) { + this.lastIndex--; } + } else { + this.setIndex(this.index + 1); } } // Remove this from the stack unless the stack input is a resource // that can easily be restored even when the input gets disposed if (stackInput instanceof EditorInput) { - const onceDispose = once(stackInput.onDispose); - onceDispose(() => { - this.removeFromStack(input); - }); + once(stackInput.onDispose)(() => this.removeFromStack(input)); } } private preferResourceInput(input: IEditorInput): IEditorInput | IResourceInput { - const file = toResource(input, { filter: 'file' }); - if (file) { - return { resource: file }; + const resource = input ? input.getResource() : void 0; + const preferResourceInput = resource && this.fileService.canHandleResource(resource); // file'ish things prefer resources + if (preferResourceInput) { + return { resource }; } return input; } - private sameOptions(optionsA?: ITextEditorOptions, optionsB?: ITextEditorOptions): boolean { - if (!optionsA && !optionsB) { + private sameSelection(selectionA?: ITextEditorSelection, selectionB?: ITextEditorSelection): boolean { + if (!selectionA && !selectionB) { return true; } - if ((!optionsA && optionsB) || (optionsA && !optionsB)) { + if ((!selectionA && selectionB) || (selectionA && !selectionB)) { return false; } - const s1 = optionsA.selection; - const s2 = optionsB.selection; - - if (!s1 && !s2) { - return true; - } - - if ((!s1 && s2) || (s1 && !s2)) { - return false; - } - - return s1.startLineNumber === s2.startLineNumber; // we consider the history entry same if we are on the same line + return selectionA.startLineNumber === selectionB.startLineNumber; // we consider the history entry same if we are on the same line } private removeFromStack(arg1: IEditorInput | IResourceInput | FileChangesEvent): void { this.stack = this.stack.filter(e => !this.matches(arg1, e.input)); this.index = this.stack.length - 1; // reset index + this.lastIndex = -1; } private removeFromRecentlyClosedFiles(arg1: IEditorInput | IResourceInput | FileChangesEvent): void { @@ -625,9 +682,9 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } if (arg2 instanceof EditorInput) { - const file = toResource(arg2, { filter: 'file' }); + const inputResource = arg2.getResource(); - return file && file.toString() === resource.toString(); + return inputResource && this.fileService.canHandleResource(inputResource) && inputResource.toString() === resource.toString(); } const resourceInput = arg2 as IResourceInput; @@ -649,45 +706,92 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic this.loaded = true; } - private save(): void { + private saveHistory(): void { if (!this.history) { return; // nothing to save because history was not used } - const entries: ISerializedFileHistoryEntry[] = this.history.map(input => { + const registry = Registry.as(EditorExtensions.EditorInputFactories); + + const entries: ISerializedEditorHistoryEntry[] = this.history.map(input => { + + // Editor input: try via factory if (input instanceof EditorInput) { - return void 0; // only file resource inputs are serializable currently + const factory = registry.getEditorInputFactory(input.getTypeId()); + if (factory) { + const deserialized = factory.serialize(input); + if (deserialized) { + return { editorInputJSON: { typeId: input.getTypeId(), deserialized } } as ISerializedEditorHistoryEntry; + } + } } - return { resourceJSON: (input as IResourceInput).resource.toJSON() }; + // File resource: via URI.toJSON() + else { + return { resourceJSON: (input as IResourceInput).resource.toJSON() } as ISerializedEditorHistoryEntry; + } + + return void 0; }).filter(serialized => !!serialized); this.storageService.store(HistoryService.STORAGE_KEY, JSON.stringify(entries), StorageScope.WORKSPACE); } private loadHistory(): void { - let entries: ISerializedFileHistoryEntry[] = []; + let entries: ISerializedEditorHistoryEntry[] = []; const entriesRaw = this.storageService.get(HistoryService.STORAGE_KEY, StorageScope.WORKSPACE); if (entriesRaw) { - entries = JSON.parse(entriesRaw); + entries = JSON.parse(entriesRaw).filter(entry => !!entry); } + const registry = Registry.as(EditorExtensions.EditorInputFactories); + this.history = entries.map(entry => { - const serializedFileInput = entry as ISerializedFileHistoryEntry; - if (serializedFileInput.resource || serializedFileInput.resourceJSON) { - return { resource: !!serializedFileInput.resourceJSON ? URI.revive(serializedFileInput.resourceJSON) : URI.parse(serializedFileInput.resource) } as IResourceInput; + const serializedEditorHistoryEntry = entry as ISerializedEditorHistoryEntry; + + // File resource: via URI.revive() + if (serializedEditorHistoryEntry.resourceJSON) { + return { resource: URI.revive(serializedEditorHistoryEntry.resourceJSON) } as IResourceInput; + } + + // Editor input: via factory + const { editorInputJSON } = serializedEditorHistoryEntry; + if (editorInputJSON && editorInputJSON.deserialized) { + const factory = registry.getEditorInputFactory(editorInputJSON.typeId); + if (factory) { + const input = factory.deserialize(this.instantiationService, editorInputJSON.deserialized); + if (input) { + once(input.onDispose)(() => this.removeFromHistory(input)); // remove from history once disposed + } + + return input; + } } return void 0; }).filter(input => !!input); } - public getLastActiveWorkspaceRoot(): URI { - if (!this.contextService.hasWorkspace()) { + public getLastActiveWorkspaceRoot(schemeFilter?: string): URI { + + // No Folder: return early + const folders = this.contextService.getWorkspace().folders; + if (folders.length === 0) { return void 0; } + // Single Folder: return early + if (folders.length === 1) { + const resource = folders[0].uri; + if (!schemeFilter || resource.scheme === schemeFilter) { + return resource; + } + + return void 0; + } + + // Multiple folders: find the last active one const history = this.getHistory(); for (let i = 0; i < history.length; i++) { const input = history[i]; @@ -696,13 +800,44 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } const resourceInput = input as IResourceInput; - const resourceWorkspace = this.contextService.getRoot(resourceInput.resource); + if (schemeFilter && resourceInput.resource.scheme !== schemeFilter) { + continue; + } + + const resourceWorkspace = this.contextService.getWorkspaceFolder(resourceInput.resource); if (resourceWorkspace) { - return resourceWorkspace; + return resourceWorkspace.uri; } } - // fallback to first workspace - return this.contextService.getWorkspace().roots[0]; + // fallback to first workspace matching scheme filter if any + for (let i = 0; i < folders.length; i++) { + const resource = folders[i].uri; + if (!schemeFilter || resource.scheme === schemeFilter) { + return resource; + } + } + + return void 0; + } + + public getLastActiveFile(): URI { + const history = this.getHistory(); + for (let i = 0; i < history.length; i++) { + let resource: URI; + + const input = history[i]; + if (input instanceof EditorInput) { + resource = toResource(input, { filter: 'file' }); + } else { + resource = (input as IResourceInput).resource; + } + + if (resource && resource.scheme === 'file') { + return resource; + } + } + + return void 0; } } diff --git a/src/vs/workbench/services/history/common/history.ts b/src/vs/workbench/services/history/common/history.ts index f42395085de..6760ab1c091 100644 --- a/src/vs/workbench/services/history/common/history.ts +++ b/src/vs/workbench/services/history/common/history.ts @@ -5,7 +5,7 @@ 'use strict'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IEditorInput, ITextEditorOptions, IResourceInput } from 'vs/platform/editor/common/editor'; +import { IEditorInput, IResourceInput } from 'vs/platform/editor/common/editor'; import URI from 'vs/base/common/uri'; export const IHistoryService = createDecorator('historyService'); @@ -19,11 +19,6 @@ export interface IHistoryService { */ reopenLastClosedEditor(): void; - /** - * Add an entry to the navigation stack of the history. - */ - add(input: IEditorInput, options?: ITextEditorOptions): void; - /** * Navigate forwards in history. * @@ -40,6 +35,11 @@ export interface IHistoryService { */ back(acrossEditors?: boolean): void; + /** + * Navigate forward or backwards to previous entry in history. + */ + last(): void; + /** * Removes an entry from history. */ @@ -58,6 +58,13 @@ export interface IHistoryService { /** * Looking at the editor history, returns the workspace root of the last file that was * inside the workspace and part of the editor history. + * + * @param schemeFilter optional filter to restrict roots by scheme. */ - getLastActiveWorkspaceRoot(): URI; + getLastActiveWorkspaceRoot(schemeFilter?: string): URI; + + /** + * Looking at the editor history, returns the resource of the last file tht was opened. + */ + getLastActiveFile(): URI; } \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts index 29dcb5a716d..2bb8da1d890 100644 --- a/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts +++ b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts @@ -429,10 +429,6 @@ class ScanCodeKeyCodeMapper { export class MacLinuxKeyboardMapper implements IKeyboardMapper { - /** - * Is the keyboard type ISO (on Mac) - */ - private readonly _isISOKeyboard: boolean; /** * Is this the standard US keyboard layout? */ @@ -458,8 +454,7 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { */ private readonly _scanCodeToDispatch: string[] = []; - constructor(isISOKeyboard: boolean, isUSStandard: boolean, rawMappings: IMacLinuxKeyboardMapping, OS: OperatingSystem) { - this._isISOKeyboard = isISOKeyboard; + constructor(isUSStandard: boolean, rawMappings: IMacLinuxKeyboardMapping, OS: OperatingSystem) { this._isUSStandard = isUSStandard; this._OS = OS; this._codeInfo = []; @@ -1055,21 +1050,6 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { code = ScanCode.Enter; } - if (this._OS === OperatingSystem.Macintosh && this._isISOKeyboard) { - // See https://github.com/Microsoft/vscode/issues/24153 - // On OSX, on ISO keyboards, Chromium swaps the scan codes - // of IntlBackslash and Backquote. - - switch (code) { - case ScanCode.IntlBackslash: - code = ScanCode.Backquote; - break; - case ScanCode.Backquote: - code = ScanCode.IntlBackslash; - break; - } - } - const keyCode = keyboardEvent.keyCode; if ( diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts index e374bd0a2a3..562e8972512 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts @@ -8,7 +8,6 @@ import * as nls from 'vs/nls'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { ResolvedKeybinding, Keybinding } from 'vs/base/common/keyCodes'; import { OS, OperatingSystem } from 'vs/base/common/platform'; -import { toDisposable } from 'vs/base/common/lifecycle'; import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; @@ -41,7 +40,6 @@ import { onUnexpectedError } from 'vs/base/common/errors'; export class KeyboardMapperFactory { public static INSTANCE = new KeyboardMapperFactory(); - private _isISOKeyboard: boolean; private _layoutInfo: nativeKeymap.IKeyboardLayoutInfo; private _rawMapping: nativeKeymap.IKeyboardMapping; private _keyboardMapper: IKeyboardMapper; @@ -51,25 +49,21 @@ export class KeyboardMapperFactory { public onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; private constructor() { - this._isISOKeyboard = false; this._layoutInfo = null; this._rawMapping = null; this._keyboardMapper = null; this._initialized = false; } - public _onKeyboardLayoutChanged(isISOKeyboard: boolean): void { - isISOKeyboard = !!isISOKeyboard; + public _onKeyboardLayoutChanged(): void { if (this._initialized) { - this._setKeyboardData(isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); - } else { - this._isISOKeyboard = isISOKeyboard; + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } } public getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper { if (!this._initialized) { - this._setKeyboardData(this._isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } if (dispatchConfig === DispatchConfig.KeyCode) { // Forcefully set to use keyCode @@ -80,7 +74,7 @@ export class KeyboardMapperFactory { public getCurrentKeyboardLayout(): nativeKeymap.IKeyboardLayoutInfo { if (!this._initialized) { - this._setKeyboardData(this._isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } return this._layoutInfo; } @@ -106,27 +100,26 @@ export class KeyboardMapperFactory { public getRawKeyboardMapping(): nativeKeymap.IKeyboardMapping { if (!this._initialized) { - this._setKeyboardData(this._isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } return this._rawMapping; } - private _setKeyboardData(isISOKeyboard: boolean, layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void { + private _setKeyboardData(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void { this._layoutInfo = layoutInfo; - if (this._initialized && this._isISOKeyboard === isISOKeyboard && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) { + if (this._initialized && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) { // nothing to do... return; } this._initialized = true; - this._isISOKeyboard = isISOKeyboard; this._rawMapping = rawMapping; - this._keyboardMapper = KeyboardMapperFactory._createKeyboardMapper(this._isISOKeyboard, this._layoutInfo, this._rawMapping); + this._keyboardMapper = KeyboardMapperFactory._createKeyboardMapper(this._layoutInfo, this._rawMapping); this._onDidChangeKeyboardMapper.fire(); } - private static _createKeyboardMapper(isISOKeyboard: boolean, layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper { + private static _createKeyboardMapper(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper { const isUSStandard = KeyboardMapperFactory._isUSStandard(layoutInfo); if (OS === OperatingSystem.Windows) { return new WindowsKeyboardMapper(isUSStandard, rawMapping); @@ -145,7 +138,7 @@ export class KeyboardMapperFactory { } } - return new MacLinuxKeyboardMapper(isISOKeyboard, isUSStandard, rawMapping, OS); + return new MacLinuxKeyboardMapper(isUSStandard, rawMapping, OS); } private static _equals(a: nativeKeymap.IKeyboardMapping, b: nativeKeymap.IKeyboardMapping): boolean { @@ -266,16 +259,16 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { windowElement: Window, @IContextKeyService contextKeyService: IContextKeyService, @ICommandService commandService: ICommandService, - @ITelemetryService private telemetryService: ITelemetryService, + @ITelemetryService telemetryService: ITelemetryService, @IMessageService messageService: IMessageService, @IEnvironmentService environmentService: IEnvironmentService, @IStatusbarService statusBarService: IStatusbarService, @IConfigurationService configurationService: IConfigurationService ) { - super(contextKeyService, commandService, messageService, statusBarService); + super(contextKeyService, commandService, telemetryService, messageService, statusBarService); let dispatchConfig = getDispatchConfig(configurationService); - configurationService.onDidUpdateConfiguration((e) => { + configurationService.onDidChangeConfiguration((e) => { let newDispatchConfig = getDispatchConfig(configurationService); if (dispatchConfig === newDispatchConfig) { return; @@ -296,7 +289,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { this._firstTimeComputingResolver = true; this.userKeybindings = new ConfigWatcher(environmentService.appKeybindingsPath, { defaultConfig: [], onError: error => onUnexpectedError(error) }); - this.toDispose.push(toDisposable(() => this.userKeybindings.dispose())); + this.toDispose.push(this.userKeybindings); keybindingsExtPoint.setHandler((extensions) => { let commandAdded = false; @@ -325,6 +318,11 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { keybindingsTelemetry(telemetryService, this); let data = KeyboardMapperFactory.INSTANCE.getCurrentKeyboardLayout(); + /* __GDPR__ + "keyboardLayout" : { + "currentKeyboardLayout": { "${inline}": [ "${IKeyboardLayoutInfo}" ] } + } + */ telemetryService.publicLog('keyboardLayout', { currentKeyboardLayout: data }); @@ -412,7 +410,12 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { if (!isFirstTime) { let cnt = extraUserKeybindings.length; - this.telemetryService.publicLog('customKeybindingsChanged', { + /* __GDPR__ + "customKeybindingsChanged" : { + "keyCount" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this._telemetryService.publicLog('customKeybindingsChanged', { keyCount: cnt }); } diff --git a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts index aa5d104d8b7..bd0f29a1abe 100644 --- a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts @@ -19,7 +19,7 @@ const WRITE_FILE_IF_DIFFERENT = false; function createKeyboardMapper(isUSStandard: boolean, file: string, OS: OperatingSystem): TPromise { return readRawMapping(file).then((rawMappings) => { - return new MacLinuxKeyboardMapper(false, isUSStandard, rawMappings, OS); + return new MacLinuxKeyboardMapper(isUSStandard, rawMappings, OS); }); } @@ -1202,7 +1202,7 @@ suite('keyboardMapper - LINUX en_us', () => { suite('keyboardMapper', () => { test('issue #23706: Linux UK layout: Ctrl + Apostrophe also toggles terminal', () => { - let mapper = new MacLinuxKeyboardMapper(false, false, { + let mapper = new MacLinuxKeyboardMapper(false, { 'Backquote': { 'value': '`', 'withShift': '¬', @@ -1234,7 +1234,7 @@ suite('keyboardMapper', () => { }); test('issue #24064: NumLock/NumPad keys stopped working in 1.11 on Linux', () => { - let mapper = new MacLinuxKeyboardMapper(false, false, {}, OperatingSystem.Linux); + let mapper = new MacLinuxKeyboardMapper(false, {}, OperatingSystem.Linux); function assertNumpadKeyboardEvent(keyCode: KeyCode, code: string, label: string, electronAccelerator: string, userSettingsLabel: string, dispatch: string): void { assertResolveKeyboardEvent( @@ -1273,7 +1273,7 @@ suite('keyboardMapper', () => { }); test('issue #24107: Delete, Insert, Home, End, PgUp, PgDn, and arrow keys no longer work editor in 1.11', () => { - let mapper = new MacLinuxKeyboardMapper(false, false, {}, OperatingSystem.Linux); + let mapper = new MacLinuxKeyboardMapper(false, {}, OperatingSystem.Linux); function assertKeyboardEvent(keyCode: KeyCode, code: string, label: string, electronAccelerator: string, userSettingsLabel: string, dispatch: string): void { assertResolveKeyboardEvent( @@ -1322,66 +1322,6 @@ suite('keyboardMapper', () => { assertKeyboardEvent(KeyCode.DownArrow, 'NumpadEnter', 'DownArrow', 'Down', 'down', '[ArrowDown]'); assertKeyboardEvent(KeyCode.UpArrow, 'Lang3', 'UpArrow', 'Up', 'up', '[ArrowUp]'); }); - - test('issue #24153: ISO Keyboards: Backslash and IntlBackslash "swapped"', () => { - let mapper = new MacLinuxKeyboardMapper(true, false, { - 'Backquote': { - 'value': '`', - 'withShift': '~', - 'withAltGr': '`', - 'withShiftAltGr': '`' - }, - 'IntlBackslash': { - 'value': '§', - 'withShift': '°', - 'withAltGr': '§', - 'withShiftAltGr': '°' - } - }, OperatingSystem.Macintosh); - - assertResolveKeyboardEvent( - mapper, - { - ctrlKey: true, - shiftKey: false, - altKey: false, - metaKey: false, - keyCode: -1, - code: 'Backquote' - }, - { - label: '⌃§', - ariaLabel: 'Control+§', - electronAccelerator: null, - userSettingsLabel: 'ctrl+[IntlBackslash]', - isWYSIWYG: false, - isChord: false, - dispatchParts: ['ctrl+[IntlBackslash]', null], - } - ); - - assertResolveKeyboardEvent( - mapper, - { - ctrlKey: true, - shiftKey: false, - altKey: false, - metaKey: false, - keyCode: -1, - code: 'IntlBackslash' - }, - { - label: '⌃`', - ariaLabel: 'Control+`', - electronAccelerator: null, - userSettingsLabel: 'ctrl+`', - isWYSIWYG: true, - isChord: false, - dispatchParts: ['ctrl+[Backquote]', null], - } - ); - }); - }); suite('keyboardMapper - LINUX ru', () => { diff --git a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts index 135525dbbaf..242aebeffca 100644 --- a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts @@ -9,7 +9,6 @@ import assert = require('assert'); import os = require('os'); import path = require('path'); import fs = require('fs'); -import uri from 'vs/base/common/uri'; import * as json from 'vs/base/common/json'; import { OS } from 'vs/base/common/platform'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; @@ -17,8 +16,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { KeyCode, SimpleKeybinding, ChordKeybinding } from 'vs/base/common/keyCodes'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import extfs = require('vs/base/node/extfs'); -import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestContextService } from 'vs/workbench/test/workbenchTestServices'; -import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/common/workspace'; +import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestContextService, TestTextResourceConfigurationService, TestHashService } from 'vs/workbench/test/workbenchTestServices'; +import { IWorkspaceContextService, Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import uuid = require('vs/base/common/uuid'); import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { FileService } from 'vs/workbench/services/files/node/fileService'; @@ -43,6 +42,7 @@ import { KeybindingsEditingService } from 'vs/workbench/services/keybinding/comm import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; interface Modifiers { metaKey?: boolean; @@ -56,7 +56,7 @@ suite('Keybindings Editing', () => { let instantiationService: TestInstantiationService; let testObject: KeybindingsEditingService; let testDir: string; - let keybindingsFile; + let keybindingsFile: string; setup(() => { return setUpWorkspace().then(() => { @@ -68,13 +68,15 @@ suite('Keybindings Editing', () => { instantiationService.stub(IConfigurationService, ConfigurationService); instantiationService.stub(IConfigurationService, 'getConfiguration', { 'eol': '\n' }); instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', () => { }); + instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', () => { }); instantiationService.stub(IWorkspaceContextService, new TestContextService()); instantiationService.stub(ILifecycleService, new TestLifecycleService()); + instantiationService.stub(IHashService, new TestHashService()); instantiationService.stub(IEditorGroupService, new TestEditorGroupService()); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl)); - instantiationService.stub(IFileService, new FileService(new TestContextService(new Workspace(testDir, testDir, [uri.file(testDir)])), new TestConfigurationService(), { disableWatcher: true })); + instantiationService.stub(IFileService, new FileService(new TestContextService(new Workspace(testDir, testDir, toWorkspaceFolders([{ path: testDir }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true })); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); diff --git a/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts index 99e62bc0aa6..3c73d835251 100644 --- a/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts +++ b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts @@ -13,6 +13,8 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ipcRenderer as ipc } from 'electron'; import Event, { Emitter } from 'vs/base/common/event'; import { IWindowService } from 'vs/platform/windows/common/windows'; +import { mark } from 'vs/base/common/performance'; +import { Barrier } from 'vs/workbench/services/extensions/node/barrier'; export class LifecycleService implements ILifecycleService { @@ -20,12 +22,12 @@ export class LifecycleService implements ILifecycleService { public _serviceBrand: any; - private readonly _onDidChangePhase = new Emitter(); private readonly _onWillShutdown = new Emitter(); private readonly _onShutdown = new Emitter(); private readonly _startupKind: StartupKind; private _phase: LifecyclePhase = LifecyclePhase.Starting; + private _phaseWhen = new Map(); constructor( @IMessageService private _messageService: IMessageService, @@ -50,20 +52,38 @@ export class LifecycleService implements ILifecycleService { } public set phase(value: LifecyclePhase) { - if (this._phase !== value) { - this._phase = value; - this._onDidChangePhase.fire(value); + if (value < this.phase) { + throw new Error('Lifecycle cannot go backwards'); } + if (this._phase === value) { + return; + } + + this._phase = value; + mark(`LifecyclePhase/${LifecyclePhase[value]}`); + + if (this._phaseWhen.has(this._phase)) { + this._phaseWhen.get(this._phase).open(); + this._phaseWhen.delete(this._phase); + } + } + + public when(phase: LifecyclePhase): Thenable { + if (phase <= this._phase) { + return Promise.resolve(); + } + let barrier = this._phaseWhen.get(phase); + if (!barrier) { + barrier = new Barrier(); + this._phaseWhen.set(phase, barrier); + } + return barrier.wait(); } public get startupKind(): StartupKind { return this._startupKind; } - public get onDidChangePhase(): Event { - return this._onDidChangePhase.event; - } - public get onWillShutdown(): Event { return this._onWillShutdown.event; } diff --git a/src/vs/workbench/services/message/browser/messageList.ts b/src/vs/workbench/services/message/browser/messageList.ts index 154aca8ed0d..a882703c7ae 100644 --- a/src/vs/workbench/services/message/browser/messageList.ts +++ b/src/vs/workbench/services/message/browser/messageList.ts @@ -304,6 +304,12 @@ export class MessageList { DOM.EventHelper.stop(e, true); + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'message' }); (action.run() || TPromise.as(null)) @@ -347,7 +353,7 @@ export class MessageList { sevLabel.title(title); - $(messageContentElement as HTMLElement).title(title).appendTo(div); + $(messageContentElement).title(title).appendTo(div); }); }); } diff --git a/src/vs/workbench/services/message/browser/messageService.ts b/src/vs/workbench/services/message/browser/messageService.ts index f0f6af73d98..9fe4dd36645 100644 --- a/src/vs/workbench/services/message/browser/messageService.ts +++ b/src/vs/workbench/services/message/browser/messageService.ts @@ -9,9 +9,10 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import types = require('vs/base/common/types'); import { MessageList, Severity as BaseSeverity } from 'vs/workbench/services/message/browser/messageList'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IMessageService, IMessageWithAction, IConfirmation, Severity } from 'vs/platform/message/common/message'; +import { IMessageService, IMessageWithAction, IConfirmation, Severity, IConfirmationResult } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import Event from 'vs/base/common/event'; +import { TPromise } from 'vs/base/common/winjs.base'; interface IBufferedMessage { severity: Severity; @@ -135,7 +136,7 @@ export class WorkbenchMessageService implements IMessageService { } } - public confirm(confirmation: IConfirmation): boolean { + public confirmSync(confirmation: IConfirmation): boolean { let messageText = confirmation.message; if (confirmation.detail) { messageText = messageText + '\n\n' + confirmation.detail; @@ -144,6 +145,10 @@ export class WorkbenchMessageService implements IMessageService { return window.confirm(messageText); } + public confirm(confirmation: IConfirmation): TPromise { + return TPromise.as({ confirmed: this.confirmSync(confirmation) } as IConfirmationResult); + } + public dispose(): void { this.toDispose = dispose(this.toDispose); } diff --git a/src/vs/workbench/services/message/electron-browser/messageService.ts b/src/vs/workbench/services/message/electron-browser/messageService.ts index af79fbcbc64..f676f67dc54 100644 --- a/src/vs/workbench/services/message/electron-browser/messageService.ts +++ b/src/vs/workbench/services/message/electron-browser/messageService.ts @@ -9,11 +9,11 @@ import nls = require('vs/nls'); import product from 'vs/platform/node/product'; import { TPromise } from 'vs/base/common/winjs.base'; import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService'; -import { IConfirmation, Severity, IChoiceService } from 'vs/platform/message/common/message'; +import { IConfirmation, Severity, IChoiceService, IConfirmationResult } from 'vs/platform/message/common/message'; import { isLinux } from 'vs/base/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Action } from 'vs/base/common/actions'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowService, IMessageBoxResult } from 'vs/platform/windows/common/windows'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; export class MessageService extends WorkbenchMessageService implements IChoiceService { @@ -26,8 +26,26 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe super(container, telemetryService); } - public confirm(confirmation: IConfirmation): boolean { + public confirm(confirmation: IConfirmation): TPromise { + const opts = this.getConfirmOptions(confirmation); + return this.showMessageBox(opts).then(result => { + return { + confirmed: result.button === 0 ? true : false, + checkboxChecked: result.checkboxChecked + } as IConfirmationResult; + }); + } + + public confirmSync(confirmation: IConfirmation): boolean { + const opts = this.getConfirmOptions(confirmation); + + const result = this.showMessageBoxSync(opts); + + return result === 0 ? true : false; + } + + private getConfirmOptions(confirmation: IConfirmation): Electron.MessageBoxOptions { const buttons: string[] = []; if (confirmation.primaryButton) { buttons.push(confirmation.primaryButton); @@ -41,7 +59,7 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe buttons.push(nls.localize('cancelButton', "Cancel")); } - let opts: Electron.ShowMessageBoxOptions = { + let opts: Electron.MessageBoxOptions = { title: confirmation.title, message: confirmation.message, buttons, @@ -57,15 +75,18 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe opts.type = confirmation.type; } - let result = this.showMessageBox(opts); + if (confirmation.checkbox) { + opts.checkboxLabel = confirmation.checkbox.label; + opts.checkboxChecked = confirmation.checkbox.checked; + } - return result === 0 ? true : false; + return opts; } public choose(severity: Severity, message: string, options: string[], cancelId: number, modal: boolean = false): TPromise { if (modal) { const type: 'none' | 'info' | 'error' | 'question' | 'warning' = severity === Severity.Info ? 'question' : severity === Severity.Error ? 'error' : severity === Severity.Warning ? 'warning' : 'none'; - return TPromise.wrap(this.showMessageBox({ message, buttons: options, type, cancelId })); + return TPromise.wrap(this.showMessageBoxSync({ message, buttons: options, type, cancelId })); } let onCancel: () => void = null; @@ -84,7 +105,25 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe return promise; } - private showMessageBox(opts: Electron.ShowMessageBoxOptions): number { + private showMessageBox(opts: Electron.MessageBoxOptions): TPromise { + opts = this.massageMessageBoxOptions(opts); + + return this.windowService.showMessageBox(opts).then(result => { + return { + button: isLinux ? opts.buttons.length - result.button - 1 : result.button, + checkboxChecked: result.checkboxChecked + } as IMessageBoxResult; + }); + } + + private showMessageBoxSync(opts: Electron.MessageBoxOptions): number { + opts = this.massageMessageBoxOptions(opts); + + const result = this.windowService.showMessageBoxSync(opts); + return isLinux ? opts.buttons.length - result - 1 : result; + } + + private massageMessageBoxOptions(opts: Electron.MessageBoxOptions): Electron.MessageBoxOptions { opts.buttons = opts.buttons.map(button => mnemonicButtonLabel(button)); opts.buttons = isLinux ? opts.buttons.reverse() : opts.buttons; @@ -99,7 +138,6 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe opts.noLink = true; opts.title = opts.title || product.nameLong; - const result = this.windowService.showMessageBox(opts); - return isLinux ? opts.buttons.length - result - 1 : result; + return opts; } } diff --git a/src/vs/workbench/services/mode/common/workbenchModeService.ts b/src/vs/workbench/services/mode/common/workbenchModeService.ts index 7b59087af60..621e9a5f65e 100644 --- a/src/vs/workbench/services/mode/common/workbenchModeService.ts +++ b/src/vs/workbench/services/mode/common/workbenchModeService.ts @@ -9,13 +9,14 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; import mime = require('vs/base/common/mime'); -import { IFilesConfiguration } from 'vs/platform/files/common/files'; +import { IFilesConfiguration, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IExtensionPointUser, ExtensionMessageCollector, IExtensionPoint, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { ILanguageExtensionPoint, IValidLanguageExtensionPoint } from 'vs/editor/common/services/modeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; export const languagesExtPoint: IExtensionPoint = ExtensionsRegistry.registerExtensionPoint('languages', [], { description: nls.localize('vscode.extension.contributes.languages', 'Contributes language declarations.'), @@ -84,9 +85,10 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { constructor( @IExtensionService extensionService: IExtensionService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @IEnvironmentService environmentService: IEnvironmentService ) { - super(); + super(environmentService.verbose || environmentService.isExtensionDevelopment || !environmentService.isBuilt); this._configurationService = configurationService; this._extensionService = extensionService; @@ -123,7 +125,11 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { }); - this._configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this._configurationService.getConfiguration())); + this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(FILES_ASSOCIATIONS_CONFIG)) { + this.updateMime(); + } + }); this.onDidCreateMode((mode) => { this._extensionService.activateByEvent(`onLanguage:${mode.getId()}`).done(null, onUnexpectedError); @@ -132,10 +138,8 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { protected _onReady(): TPromise { if (!this._onReadyPromise) { - const configuration = this._configurationService.getConfiguration(); this._onReadyPromise = this._extensionService.onReady().then(() => { - this.onConfigurationChange(configuration); - + this.updateMime(); return true; }); } @@ -143,7 +147,8 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { return this._onReadyPromise; } - private onConfigurationChange(configuration: IFilesConfiguration): void { + private updateMime(): void { + const configuration = this._configurationService.getConfiguration(); // Clear user configured mime associations mime.clearTextMimes(true /* user configured */); diff --git a/src/vs/workbench/services/panel/common/panelService.ts b/src/vs/workbench/services/panel/common/panelService.ts index 5de4a2d9e18..13bd32dbc2a 100644 --- a/src/vs/workbench/services/panel/common/panelService.ts +++ b/src/vs/workbench/services/panel/common/panelService.ts @@ -13,7 +13,7 @@ export const IPanelService = createDecorator('panelService'); export interface IPanelIdentifier { id: string; name: string; - commandId: string; + cssClass: string; } export interface IPanelService { diff --git a/src/vs/workbench/services/part/common/partService.ts b/src/vs/workbench/services/part/common/partService.ts index 4e41c5df51c..0cdb78d9d9c 100644 --- a/src/vs/workbench/services/part/common/partService.ts +++ b/src/vs/workbench/services/part/common/partService.ts @@ -19,11 +19,13 @@ export enum Parts { export enum Position { LEFT, - RIGHT + RIGHT, + BOTTOM } export interface ILayoutOptions { toggleMaximizedPanel?: boolean; + source?: Parts; } export const IPartService = createDecorator('partService'); @@ -51,11 +53,6 @@ export interface IPartService { */ isCreated(): boolean; - /** - * Promise is complete when all parts have been created. - */ - joinCreation(): TPromise; - /** * Returns whether the given part has the keyboard focus or not. */ @@ -107,6 +104,11 @@ export interface IPartService { */ getSideBarPosition(): Position; + /** + * Gets the current panel position. Note that the panel can be hidden too. + */ + getPanelPosition(): Position; + /** * Returns the identifier of the element that contains the workbench. */ diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index aebb56b7a0c..9a94a0d8908 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -17,6 +17,8 @@ interface ProgressState { worked?: number; done?: boolean; whilePromise?: TPromise; + whileStart?: number; + whileDelay?: number; } export abstract class ScopedService { @@ -87,7 +89,15 @@ export class WorkbenchProgressService extends ScopedService implements IProgress // Replay Infinite Progress from Promise if (this.progressState.whilePromise) { - this.doShowWhile(); + let delay: number; + if (this.progressState.whileDelay > 0) { + const remainingDelay = this.progressState.whileDelay - (Date.now() - this.progressState.whileStart); + if (remainingDelay > 0) { + delay = remainingDelay; + } + } + + this.doShowWhile(delay); } // Replay Infinite Progress @@ -113,6 +123,8 @@ export class WorkbenchProgressService extends ScopedService implements IProgress this.progressState.worked = void 0; this.progressState.total = void 0; this.progressState.whilePromise = void 0; + this.progressState.whileStart = void 0; + this.progressState.whileDelay = void 0; } public show(infinite: boolean, delay?: number): IProgressRunner; @@ -218,6 +230,8 @@ export class WorkbenchProgressService extends ScopedService implements IProgress // Keep Promise in State this.progressState.whilePromise = promise; + this.progressState.whileDelay = delay || 0; + this.progressState.whileStart = Date.now(); let stop = () => { diff --git a/src/vs/workbench/services/progress/browser/progressService2.ts b/src/vs/workbench/services/progress/browser/progressService2.ts index 4ba5417b3a2..b6de990d858 100644 --- a/src/vs/workbench/services/progress/browser/progressService2.ts +++ b/src/vs/workbench/services/progress/browser/progressService2.ts @@ -7,8 +7,7 @@ import 'vs/css!./media/progressService2'; import * as dom from 'vs/base/browser/dom'; import { localize } from 'vs/nls'; -import { IActivityBarService, ProgressBadge } from 'vs/workbench/services/activity/common/activityBarService'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { IProgressService2, IProgressOptions, ProgressLocation, IProgress, IProgressStep, Progress, emptyProgress } from 'vs/platform/progress/common/progress'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; @@ -61,7 +60,6 @@ export class ProgressService2 implements IProgressService2 { private _stack: [IProgressOptions, Progress][] = []; constructor( - @IActivityBarService private _activityBar: IActivityBarService, @IViewletService private _viewletService: IViewletService ) { // @@ -151,34 +149,34 @@ export class ProgressService2 implements IProgressService2 { } // show activity bar - let activityProgress: IDisposable; - let delayHandle = setTimeout(() => { - delayHandle = undefined; - const handle = this._activityBar.showActivity( - viewletId, - new ProgressBadge(() => ''), - 'progress-badge' - ); - const startTimeVisible = Date.now(); - const minTimeVisible = 300; - activityProgress = { - dispose() { - const d = Date.now() - startTimeVisible; - if (d < minTimeVisible) { - // should at least show for Nms - setTimeout(() => handle.dispose(), minTimeVisible - d); - } else { - // shown long enough - handle.dispose(); - } - } - }; - }, 300); + // let activityProgress: IDisposable; + // let delayHandle = setTimeout(() => { + // delayHandle = undefined; + // const handle = this._activityBar.showActivity( + // viewletId, + // new ProgressBadge(() => ''), + // 'progress-badge' + // ); + // const startTimeVisible = Date.now(); + // const minTimeVisible = 300; + // activityProgress = { + // dispose() { + // const d = Date.now() - startTimeVisible; + // if (d < minTimeVisible) { + // // should at least show for Nms + // setTimeout(() => handle.dispose(), minTimeVisible - d); + // } else { + // // shown long enough + // handle.dispose(); + // } + // } + // }; + // }, 300); - always(promise, () => { - clearTimeout(delayHandle); - dispose(activityProgress); - }); + // always(promise, () => { + // clearTimeout(delayHandle); + // dispose(activityProgress); + // }); } } diff --git a/src/vs/workbench/services/progress/test/progressService.test.ts b/src/vs/workbench/services/progress/test/progressService.test.ts index 9a4a2dd281b..ef327a11f63 100644 --- a/src/vs/workbench/services/progress/test/progressService.test.ts +++ b/src/vs/workbench/services/progress/test/progressService.test.ts @@ -17,7 +17,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { Emitter } from 'vs/base/common/event'; -let activeViewlet: Viewlet = {}; +let activeViewlet: Viewlet = {} as any; class TestViewletService implements IViewletService { public _serviceBrand: any; diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 902c80182bd..461cfd58b6d 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -11,6 +11,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import Event from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Command } from 'vs/editor/common/modes'; +import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; export interface IBaselineResourceProvider { getBaselineResource(resource: URI): TPromise; @@ -24,33 +25,53 @@ export interface ISCMResourceDecorations { tooltip?: string; strikeThrough?: boolean; faded?: boolean; + + source?: string; + letter?: string; + color?: ColorIdentifier; +} + +export interface ISCMResourceSplice { + start: number; + deleteCount: number; + resources: ISCMResource[]; +} + +export interface ISCMResourceCollection { + readonly resources: ISCMResource[]; + readonly onDidSplice: Event; } export interface ISCMResource { readonly resourceGroup: ISCMResourceGroup; readonly sourceUri: URI; - readonly command?: Command; readonly decorations: ISCMResourceDecorations; + open(): TPromise; } export interface ISCMResourceGroup { readonly provider: ISCMProvider; readonly label: string; readonly id: string; - readonly resources: ISCMResource[]; + readonly resourceCollection: ISCMResourceCollection; + readonly hideWhenEmpty: boolean; } export interface ISCMProvider extends IDisposable { readonly label: string; readonly id: string; readonly contextValue: string; + readonly resources: ISCMResourceGroup[]; - readonly onDidChange: Event; + readonly onDidChangeResources: Event; + + readonly rootUri?: URI; readonly count?: number; readonly commitTemplate?: string; readonly onDidChangeCommitTemplate?: Event; readonly acceptInputCommand?: Command; readonly statusBarCommands?: Command[]; + readonly onDidChange: Event; getOriginalResource(uri: URI): TPromise; } @@ -58,6 +79,9 @@ export interface ISCMProvider extends IDisposable { export interface ISCMInput { value: string; readonly onDidChange: Event; + + placeholder: string; + readonly onDidChangePlaceholder: Event; } export interface ISCMRepository extends IDisposable { @@ -72,9 +96,8 @@ export interface ISCMService { readonly _serviceBrand: any; readonly onDidAddRepository: Event; readonly onDidRemoveRepository: Event; - readonly onDidChangeRepository: Event; readonly repositories: ISCMRepository[]; registerSCMProvider(provider: ISCMProvider): ISCMRepository; -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/scm/common/scmService.ts b/src/vs/workbench/services/scm/common/scmService.ts index 6e429c117b1..dadee567ffa 100644 --- a/src/vs/workbench/services/scm/common/scmService.ts +++ b/src/vs/workbench/services/scm/common/scmService.ts @@ -24,6 +24,20 @@ class SCMInput implements ISCMInput { private _onDidChange = new Emitter(); get onDidChange(): Event { return this._onDidChange.event; } + + private _placeholder = ''; + + get placeholder(): string { + return this._placeholder; + } + + set placeholder(placeholder: string) { + this._placeholder = placeholder; + this._onDidChangePlaceholder.fire(placeholder); + } + + private _onDidChangePlaceholder = new Emitter(); + get onDidChangePlaceholder(): Event { return this._onDidChangePlaceholder.event; } } class SCMRepository implements ISCMRepository { @@ -62,9 +76,6 @@ export class SCMService implements ISCMService { private _onDidRemoveProvider = new Emitter(); get onDidRemoveRepository(): Event { return this._onDidRemoveProvider.event; } - private _onDidChangeProvider = new Emitter(); - get onDidChangeRepository(): Event { return this._onDidChangeProvider.event; } - constructor() { } registerSCMProvider(provider: ISCMProvider): ISCMRepository { diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index f0b617d4fbf..372fab93bdf 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -14,7 +14,6 @@ import { isEqualOrParent } from 'vs/base/common/paths'; import { Readable } from 'stream'; import { TPromise } from 'vs/base/common/winjs.base'; -import scorer = require('vs/base/common/scorer'); import objects = require('vs/base/common/objects'); import arrays = require('vs/base/common/arrays'); import platform = require('vs/base/common/platform'); @@ -26,12 +25,14 @@ import { IProgress, IUncachedSearchStats } from 'vs/platform/search/common/searc import extfs = require('vs/base/node/extfs'); import flow = require('vs/base/node/flow'); import { IRawFileMatch, ISerializedSearchComplete, IRawSearch, ISearchEngine, IFolderSearch } from './search'; +import { spawnRipgrepCmd } from './ripgrepFileSearch'; enum Traversal { Node = 1, MacFind, WindowsDir, - LinuxFind + LinuxFind, + Ripgrep } interface IDirectoryEntry { @@ -47,10 +48,12 @@ interface IDirectoryTree { export class FileWalker { private config: IRawSearch; + private useRipgrep: boolean; private filePattern: string; private normalizedFilePatternLowercase: string; private includePattern: glob.ParsedExpression; private maxResults: number; + private exists: boolean; private maxFilesize: number; private isLimitHit: boolean; private resultCount: number; @@ -71,9 +74,11 @@ export class FileWalker { constructor(config: IRawSearch) { this.config = config; + this.useRipgrep = config.useRipgrep !== false; this.filePattern = config.filePattern; this.includePattern = config.includePattern && glob.parse(config.includePattern); this.maxResults = config.maxResults || null; + this.exists = config.exists; this.maxFilesize = config.maxFilesize || null; this.walkedPaths = Object.create(null); this.resultCount = 0; @@ -151,16 +156,19 @@ export class FileWalker { let traverse = this.nodeJSTraversal; if (!this.maxFilesize) { - if (platform.isMacintosh) { + if (this.useRipgrep) { + this.traversal = Traversal.Ripgrep; + traverse = this.cmdTraversal; + } else if (platform.isMacintosh) { this.traversal = Traversal.MacFind; - traverse = this.findTraversal; + traverse = this.cmdTraversal; // Disable 'dir' for now (#11181, #11179, #11183, #11182). } /* else if (platform.isWindows) { this.traversal = Traversal.WindowsDir; traverse = this.windowsDirTraversal; } */ else if (platform.isLinux) { this.traversal = Traversal.LinuxFind; - traverse = this.findTraversal; + traverse = this.cmdTraversal; } } @@ -173,15 +181,10 @@ export class FileWalker { flow.parallel(folderQueries, (folderQuery: IFolderSearch, rootFolderDone: (err: Error, result: void) => void) => { this.call(traverse, this, folderQuery, onResult, (err?: Error) => { if (err) { - if (isNodeTraversal) { - rootFolderDone(err, undefined); - } else { - // fallback - const errorMessage = toErrorMessage(err); - console.error(errorMessage); - this.errors.push(errorMessage); - this.nodeJSTraversal(folderQuery, onResult, err => rootFolderDone(err, undefined)); - } + const errorMessage = toErrorMessage(err); + console.error(errorMessage); + this.errors.push(errorMessage); + rootFolderDone(err, undefined); } else { rootFolderDone(undefined, undefined); } @@ -200,27 +203,47 @@ export class FileWalker { } } - private findTraversal(folderQuery: IFolderSearch, onResult: (result: IRawFileMatch) => void, cb: (err?: Error) => void): void { + private cmdTraversal(folderQuery: IFolderSearch, onResult: (result: IRawFileMatch) => void, cb: (err?: Error) => void): void { const rootFolder = folderQuery.folder; const isMac = platform.isMacintosh; + let cmd: childProcess.ChildProcess; + const killCmd = () => cmd && cmd.kill(); + let done = (err?: Error) => { + process.removeListener('exit', killCmd); done = () => { }; cb(err); }; let leftover = ''; let first = true; const tree = this.initDirectoryTree(); - const cmd = this.spawnFindCmd(folderQuery); - this.collectStdout(cmd, 'utf8', (err: Error, stdout?: string, last?: boolean) => { + + const useRipgrep = this.useRipgrep; + let noSiblingsClauses: boolean; + let filePatternSeen = false; + if (useRipgrep) { + const ripgrep = spawnRipgrepCmd(this.config, folderQuery, this.config.includePattern, this.folderExcludePatterns.get(folderQuery.folder).expression); + cmd = ripgrep.cmd; + noSiblingsClauses = !Object.keys(ripgrep.siblingClauses).length; + } else { + cmd = this.spawnFindCmd(folderQuery); + } + + process.on('exit', killCmd); + this.collectStdout(cmd, 'utf8', useRipgrep, (err: Error, stdout?: string, last?: boolean) => { if (err) { done(err); return; } + if (this.isLimitHit) { + done(); + return; + } // Mac: uses NFD unicode form on disk, but we want NFC const normalized = leftover + (isMac ? strings.normalizeNFC(stdout) : stdout); - const relativeFiles = normalized.split('\n./'); - if (first && normalized.length >= 2) { + const relativeFiles = normalized.split(useRipgrep ? '\n' : '\n./'); + if (!useRipgrep && first && normalized.length >= 2) { first = false; relativeFiles[0] = relativeFiles[0].trim().substr(2); } @@ -240,6 +263,41 @@ export class FileWalker { return; } + this.cmdResultCount += relativeFiles.length; + + if (useRipgrep && noSiblingsClauses) { + for (const relativePath of relativeFiles) { + if (relativePath === this.filePattern) { + filePatternSeen = true; + } + const basename = path.basename(relativePath); + this.matchFile(onResult, { base: rootFolder, relativePath, basename }); + if (this.isLimitHit) { + killCmd(); + break; + } + } + if (last || this.isLimitHit) { + if (!filePatternSeen) { + this.checkFilePatternRelativeMatch(folderQuery.folder, (match, size) => { + if (match) { + this.resultCount++; + onResult({ + base: folderQuery.folder, + relativePath: this.filePattern, + basename: path.basename(this.filePattern), + }); + } + done(); + }); + } else { + done(); + } + } + return; + } + + // TODO: Optimize siblings clauses with ripgrep here. this.addDirectoryEntries(tree, rootFolder, relativeFiles, onResult); if (last) { @@ -304,9 +362,9 @@ export class FileWalker { /** * Public for testing. */ - public readStdout(cmd: childProcess.ChildProcess, encoding: string, cb: (err: Error, stdout?: string) => void): void { + public readStdout(cmd: childProcess.ChildProcess, encoding: string, isRipgrep: boolean, cb: (err: Error, stdout?: string) => void): void { let all = ''; - this.collectStdout(cmd, encoding, (err: Error, stdout?: string, last?: boolean) => { + this.collectStdout(cmd, encoding, isRipgrep, (err: Error, stdout?: string, last?: boolean) => { if (err) { cb(err); return; @@ -319,7 +377,7 @@ export class FileWalker { }); } - private collectStdout(cmd: childProcess.ChildProcess, encoding: string, cb: (err: Error, stdout?: string, last?: boolean) => void): void { + private collectStdout(cmd: childProcess.ChildProcess, encoding: string, isRipgrep: boolean, cb: (err: Error, stdout?: string, last?: boolean) => void): void { let done = (err: Error, stdout?: string, last?: boolean) => { if (err || last) { done = () => { }; @@ -336,9 +394,13 @@ export class FileWalker { }); cmd.on('close', (code: number) => { - if (code !== 0) { - done(new Error(`find failed with error code ${code}: ${this.decodeData(stderr, encoding)}`)); + // ripgrep returns code=1 when no results are found + if (code !== 0 && (!isRipgrep || code !== 1)) { + done(new Error(`command failed with error code ${code}: ${this.decodeData(stderr, encoding)}`)); } else { + if (isRipgrep && this.exists && code === 0) { + this.isLimitHit = true; + } done(null, '', true); } }); @@ -375,8 +437,6 @@ export class FileWalker { } private addDirectoryEntries({ pathToEntries }: IDirectoryTree, base: string, relativeFiles: string[], onResult: (result: IRawFileMatch) => void) { - this.cmdResultCount += relativeFiles.length; - // Support relative paths to files from a root resource (ignores excludes) if (relativeFiles.indexOf(this.filePattern) !== -1) { const basename = path.basename(this.filePattern); @@ -429,7 +489,11 @@ export class FileWalker { self.matchFile(onResult, entry); } - }; + + if (self.isLimitHit) { + break; + } + } } matchDirectory(rootEntries); } @@ -599,7 +663,7 @@ export class FileWalker { if (this.isFilePatternMatch(candidate.relativePath) && (!this.includePattern || this.includePattern(candidate.relativePath, candidate.basename))) { this.resultCount++; - if (this.maxResults && this.resultCount > this.maxResults) { + if (this.exists || (this.maxResults && this.resultCount > this.maxResults)) { this.isLimitHit = true; } @@ -617,7 +681,7 @@ export class FileWalker { return true; // support the all-matching wildcard } - return scorer.matches(path, this.normalizedFilePatternLowercase); + return strings.fuzzyContains(path, this.normalizedFilePatternLowercase); } // No patterns means we match all @@ -682,8 +746,8 @@ class AbsoluteAndRelativeParsedExpression { private absoluteParsedExpr: glob.ParsedExpression; private relativeParsedExpr: glob.ParsedExpression; - constructor(expr: glob.IExpression, private root: string) { - this.init(expr); + constructor(public expression: glob.IExpression, private root: string) { + this.init(expression); } /** diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index f2666cecaea..55fb059c48f 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -12,9 +12,7 @@ import gracefulFs = require('graceful-fs'); gracefulFs.gracefulify(fs); import arrays = require('vs/base/common/arrays'); -import { compareByScore } from 'vs/base/common/comparers'; import objects = require('vs/base/common/objects'); -import scorer = require('vs/base/common/scorer'); import strings = require('vs/base/common/strings'); import { PPromise, TPromise } from 'vs/base/common/winjs.base'; import { FileWalker, Engine as FileSearchEngine } from 'vs/workbench/services/search/node/fileSearch'; @@ -22,8 +20,10 @@ import { MAX_FILE_SIZE } from 'vs/platform/files/common/files'; import { RipgrepEngine } from 'vs/workbench/services/search/node/ripgrepTextSearch'; import { Engine as TextSearchEngine } from 'vs/workbench/services/search/node/textSearch'; import { TextSearchWorkerProvider } from 'vs/workbench/services/search/node/textSearchWorkerProvider'; -import { IRawSearchService, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchProgressItem, ISerializedSearchComplete, ISearchEngine, IFileSearchProgressItem } from './search'; +import { IRawSearchService, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchProgressItem, ISerializedSearchComplete, ISearchEngine, IFileSearchProgressItem, ITelemetryEvent } from './search'; import { ICachedSearchStats, IProgress } from 'vs/platform/search/common/search'; +import { fuzzyContains } from 'vs/base/common/strings'; +import { compareItemsByScore, IItemAccessor, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; export class SearchService implements IRawSearchService { @@ -33,6 +33,8 @@ export class SearchService implements IRawSearchService { private textSearchWorkerProvider: TextSearchWorkerProvider; + private telemetryPipe: (event: ITelemetryEvent) => void; + public fileSearch(config: IRawSearch): PPromise { return this.doFileSearch(FileSearchEngine, config, SearchService.BATCH_SIZE); } @@ -81,6 +83,7 @@ export class SearchService implements IRawSearchService { includePattern: config.includePattern, excludePattern: config.excludePattern, filePattern: config.filePattern, + useRipgrep: false, maxFilesize: MAX_FILE_SIZE }), this.textSearchWorkerProvider); @@ -140,6 +143,12 @@ export class SearchService implements IRawSearchService { searchPromise = this.doSearch(engine, -1) .then(result => { c([result, results]); + if (this.telemetryPipe) { + this.telemetryPipe({ + eventName: 'fileSearch', + data: result.stats + }); + } }, e, progress => { if (Array.isArray(progress)) { results = progress; @@ -161,23 +170,26 @@ export class SearchService implements IRawSearchService { allResultsPromise = this.preventCancellation(allResultsPromise); } + let chained: TPromise; return new PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress>((c, e, p) => { - allResultsPromise.then(([result, results]) => { + chained = allResultsPromise.then(([result, results]) => { const scorerCache: ScorerCache = cache ? cache.scorerCache : Object.create(null); const unsortedResultTime = Date.now(); - const sortedResults = this.sortResults(config, results, scorerCache); - const sortedResultTime = Date.now(); + return this.sortResults(config, results, scorerCache) + .then(sortedResults => { + const sortedResultTime = Date.now(); - c([{ - stats: objects.assign({}, result.stats, { - unsortedResultTime, - sortedResultTime - }), - limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults - }, sortedResults]); + c([{ + stats: objects.assign({}, result.stats, { + unsortedResultTime, + sortedResultTime + }), + limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults + }, sortedResults]); + }); }, e, p); }, () => { - allResultsPromise.cancel(); + chained.cancel(); }); } @@ -198,47 +210,54 @@ export class SearchService implements IRawSearchService { const cacheLookupStartTime = Date.now(); const cached = this.getResultsFromCache(cache, config.filePattern); if (cached) { + let chained: TPromise; return new PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress>((c, e, p) => { - cached.then(([result, results, cacheStats]) => { + chained = cached.then(([result, results, cacheStats]) => { const cacheLookupResultTime = Date.now(); - const sortedResults = this.sortResults(config, results, cache.scorerCache); - const sortedResultTime = Date.now(); + return this.sortResults(config, results, cache.scorerCache) + .then(sortedResults => { + const sortedResultTime = Date.now(); - const stats: ICachedSearchStats = { - fromCache: true, - cacheLookupStartTime: cacheLookupStartTime, - cacheFilterStartTime: cacheStats.cacheFilterStartTime, - cacheLookupResultTime: cacheLookupResultTime, - cacheEntryCount: cacheStats.cacheFilterResultCount, - resultCount: results.length - }; - if (config.sortByScore) { - stats.unsortedResultTime = cacheLookupResultTime; - stats.sortedResultTime = sortedResultTime; - } - if (!cacheStats.cacheWasResolved) { - stats.joined = result.stats; - } - c([ - { - limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults, - stats: stats - }, - sortedResults - ]); + const stats: ICachedSearchStats = { + fromCache: true, + cacheLookupStartTime: cacheLookupStartTime, + cacheFilterStartTime: cacheStats.cacheFilterStartTime, + cacheLookupResultTime: cacheLookupResultTime, + cacheEntryCount: cacheStats.cacheFilterResultCount, + resultCount: results.length + }; + if (config.sortByScore) { + stats.unsortedResultTime = cacheLookupResultTime; + stats.sortedResultTime = sortedResultTime; + } + if (!cacheStats.cacheWasResolved) { + stats.joined = result.stats; + } + c([ + { + limitHit: result.limitHit || typeof config.maxResults === 'number' && results.length > config.maxResults, + stats: stats + }, + sortedResults + ]); + }); }, e, p); }, () => { - cached.cancel(); + chained.cancel(); }); } return undefined; } - private sortResults(config: IRawSearch, results: IRawFileMatch[], scorerCache: ScorerCache): IRawFileMatch[] { - const filePattern = config.filePattern; - const normalizedSearchValue = strings.stripWildcards(filePattern).toLowerCase(); - const compare = (elementA: IRawFileMatch, elementB: IRawFileMatch) => compareByScore(elementA, elementB, FileMatchAccessor, filePattern, normalizedSearchValue, scorerCache); - return arrays.top(results, compare, config.maxResults); + private sortResults(config: IRawSearch, results: IRawFileMatch[], scorerCache: ScorerCache): TPromise { + // we use the same compare function that is used later when showing the results using fuzzy scoring + // this is very important because we are also limiting the number of results by config.maxResults + // and as such we want the top items to be included in this result set if the number of items + // exceeds config.maxResults. + const query = prepareQuery(config.filePattern); + const compare = (matchA: IRawFileMatch, matchB: IRawFileMatch) => compareItemsByScore(matchA, matchB, query, true, FileMatchItemAccessor, scorerCache); + + return arrays.topAsync(results, compare, config.maxResults, 10000); } private sendProgress(results: ISerializedFileMatch[], progressCb: (batch: ISerializedFileMatch[]) => void, batchSize: number) { @@ -291,7 +310,7 @@ export class SearchService implements IRawSearchService { let entry = cachedEntries[i]; // Check if this entry is a match for the search value - if (!scorer.matches(entry.relativePath, normalizedSearchValueLowercase)) { + if (!fuzzyContains(entry.relativePath, normalizedSearchValueLowercase)) { continue; } @@ -369,6 +388,14 @@ export class SearchService implements IRawSearchService { return TPromise.as(undefined); } + public fetchTelemetry(): PPromise { + return new PPromise((c, e, p) => { + this.telemetryPipe = p; + }, () => { + this.telemetryPipe = null; + }); + } + private preventCancellation(promise: PPromise): PPromise { return new PPromise((c, e, p) => { // Allow for piled up cancellations to come through first. @@ -388,20 +415,20 @@ class Cache { public scorerCache: ScorerCache = Object.create(null); } -interface ScorerCache { - [key: string]: number; -} +const FileMatchItemAccessor = new class implements IItemAccessor { -class FileMatchAccessor { - - public static getLabel(match: IRawFileMatch): string { - return match.basename; + public getItemLabel(match: IRawFileMatch): string { + return match.basename; // e.g. myFile.txt } - public static getResourcePath(match: IRawFileMatch): string { - return match.relativePath; + public getItemDescription(match: IRawFileMatch): string { + return match.relativePath.substr(0, match.relativePath.length - match.basename.length - 1); // e.g. some/path/to/file } -} + + public getItemPath(match: IRawFileMatch): string { + return match.relativePath; // e.g. some/path/to/file/myFile.txt + } +}; interface CacheStats { cacheWasResolved: boolean; diff --git a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts new file mode 100644 index 00000000000..939edf660cc --- /dev/null +++ b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as cp from 'child_process'; +import { rgPath } from 'vscode-ripgrep'; + +import { isMacintosh as isMac } from 'vs/base/common/platform'; +import * as glob from 'vs/base/common/glob'; +import { normalizeNFD, startsWith } from 'vs/base/common/strings'; + +import { IFolderSearch, IRawSearch } from './search'; +import { foldersToIncludeGlobs, foldersToRgExcludeGlobs } from './ripgrepTextSearch'; + +export function spawnRipgrepCmd(config: IRawSearch, folderQuery: IFolderSearch, includePattern: glob.IExpression, excludePattern: glob.IExpression) { + const rgArgs = getRgArgs(config, folderQuery, includePattern, excludePattern); + return { + cmd: cp.spawn(rgPath, rgArgs.globArgs, { cwd: folderQuery.folder }), + siblingClauses: rgArgs.siblingClauses + }; +} + +function getRgArgs(config: IRawSearch, folderQuery: IFolderSearch, includePattern: glob.IExpression, excludePattern: glob.IExpression) { + const args = ['--files', '--hidden', '--case-sensitive']; + + // includePattern can't have siblingClauses + foldersToIncludeGlobs([folderQuery], includePattern, false).forEach(globArg => { + args.push('-g', anchor(isMac ? normalizeNFD(globArg) : globArg)); + }); + + let siblingClauses: glob.IExpression; + + const rgGlobs = foldersToRgExcludeGlobs([folderQuery], excludePattern, undefined, false); + rgGlobs.globArgs + .forEach(rgGlob => args.push('-g', `!${anchor(isMac ? normalizeNFD(rgGlob) : rgGlob)}`)); + siblingClauses = rgGlobs.siblingClauses; + + if (folderQuery.disregardIgnoreFiles !== false) { + // Don't use .gitignore or .ignore + args.push('--no-ignore'); + } + + // Follow symlinks + if (!config.ignoreSymlinks) { + args.push('--follow'); + } + + if (config.exists) { + args.push('--quiet'); + } + + // Folder to search + args.push('--'); + + args.push('.'); + + return { globArgs: args, siblingClauses }; +} + +function anchor(glob: string) { + return startsWith(glob, '**') || startsWith(glob, '/') ? glob : `/${glob}`; +} \ No newline at end of file diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts index 925c395bf37..6ae30eb0b4d 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts @@ -26,6 +26,7 @@ import { ISerializedFileMatch, ISerializedSearchComplete, IRawSearch, IFolderSea export class RipgrepEngine { private isDone = false; private rgProc: cp.ChildProcess; + private killRgProcFn: Function; private postProcessExclusions: glob.ParsedExpression; private ripgrepParser: RipgrepParser; @@ -33,6 +34,7 @@ export class RipgrepEngine { private resultsHandledP: TPromise = TPromise.wrap(null); constructor(private config: IRawSearch) { + this.killRgProcFn = () => this.rgProc && this.rgProc.kill(); } cancel(): void { @@ -44,6 +46,7 @@ export class RipgrepEngine { // TODO@Rob - make promise-based once the old search is gone, and I don't need them to have matching interfaces anymore search(onResult: (match: ISerializedFileMatch) => void, onMessage: (message: ISearchLog) => void, done: (error: Error, complete: ISerializedSearchComplete) => void): void { if (!this.config.folderQueries.length && !this.config.extraFiles.length) { + process.removeListener('exit', this.killRgProcFn); done(null, { limitHit: false, stats: null @@ -69,8 +72,9 @@ export class RipgrepEngine { } }); this.rgProc = cp.spawn(rgPath, rgArgs.globArgs, { cwd }); + process.once('exit', this.killRgProcFn); - this.ripgrepParser = new RipgrepParser(this.config.maxResults, cwd); + this.ripgrepParser = new RipgrepParser(this.config.maxResults, cwd, this.config.extraFiles); this.ripgrepParser.on('result', (match: ISerializedFileMatch) => { if (this.postProcessExclusions) { const handleResultP = (>this.postProcessExclusions(match.path, undefined, () => getSiblings(match.path))) @@ -87,6 +91,7 @@ export class RipgrepEngine { }); this.ripgrepParser.on('hitLimit', () => { this.cancel(); + process.removeListener('exit', this.killRgProcFn); done(null, { limitHit: true, stats: null @@ -115,6 +120,7 @@ export class RipgrepEngine { if (!this.isDone) { this.isDone = true; let displayMsg: string; + process.removeListener('exit', this.killRgProcFn); if (stderr && !gotData && (displayMsg = this.rgErrorMsgForDisplay(stderr))) { done(new Error(displayMsg), { limitHit: false, @@ -143,8 +149,10 @@ export class RipgrepEngine { return firstLine; } - if (strings.startsWith(firstLine, 'error parsing glob')) { - return firstLine; + if (strings.startsWith(firstLine, 'error parsing glob') || + strings.startsWith(firstLine, 'unsupported encoding')) { + // Uppercase first letter + return firstLine.charAt(0).toUpperCase() + firstLine.substr(1); } return undefined; @@ -162,12 +170,15 @@ export class RipgrepParser extends EventEmitter { private remainder: string; private isDone: boolean; private stringDecoder: NodeStringDecoder; + private extraSearchFiles: string[]; private numResults = 0; - constructor(private maxResults: number, private rootFolder: string) { + constructor(private maxResults: number, private rootFolder: string, extraFiles?: string[]) { super(); this.stringDecoder = new StringDecoder(); + + this.extraSearchFiles = extraFiles || []; } public cancel(): void { @@ -221,15 +232,37 @@ export class RipgrepParser extends EventEmitter { this.onResult(); } - this.fileMatch = new FileMatch(path.isAbsolute(r[1]) ? r[1] : path.join(this.rootFolder, r[1])); + this.fileMatch = this.getFileMatch(r[1]); } else { // Line is empty (or malformed) } } } + private getFileMatch(relativeOrAbsolutePath: string): FileMatch { + const absPath = path.isAbsolute(relativeOrAbsolutePath) ? + relativeOrAbsolutePath : + path.join(this.rootFolder, relativeOrAbsolutePath); + + return new FileMatch(absPath); + } + private handleMatchLine(outputLine: string, lineNum: number, text: string): void { + if (lineNum === 0) { + text = strings.stripUTF8BOM(text); + } + const lineMatch = new LineMatch(text, lineNum); + if (!this.fileMatch) { + // When searching a single file and no folderQueries, rg does not print the file line, so create it here + const singleFile = this.extraSearchFiles[0]; + if (!singleFile) { + throw new Error('Got match line for unknown file'); + } + + this.fileMatch = this.getFileMatch(singleFile); + } + this.fileMatch.addMatch(lineMatch); let lastMatchEndPos = 0; @@ -363,17 +396,17 @@ export class LineMatch implements ILineMatch { } } -interface IRgGlobResult { +export interface IRgGlobResult { globArgs: string[]; siblingClauses: glob.IExpression; } -function foldersToRgExcludeGlobs(folderQueries: IFolderSearch[], globalExclude: glob.IExpression, excludesToSkip: Set): IRgGlobResult { +export function foldersToRgExcludeGlobs(folderQueries: IFolderSearch[], globalExclude: glob.IExpression, excludesToSkip?: Set, absoluteGlobs = true): IRgGlobResult { const globArgs: string[] = []; let siblingClauses: glob.IExpression = {}; folderQueries.forEach(folderQuery => { const totalExcludePattern = objects.assign({}, folderQuery.excludePattern || {}, globalExclude || {}); - const result = globExprsToRgGlobs(totalExcludePattern, folderQuery.folder, excludesToSkip); + const result = globExprsToRgGlobs(totalExcludePattern, absoluteGlobs && folderQuery.folder, excludesToSkip); globArgs.push(...result.globArgs); if (result.siblingClauses) { siblingClauses = objects.assign(siblingClauses, result.siblingClauses); @@ -383,18 +416,18 @@ function foldersToRgExcludeGlobs(folderQueries: IFolderSearch[], globalExclude: return { globArgs, siblingClauses }; } -function foldersToIncludeGlobs(folderQueries: IFolderSearch[], globalInclude: glob.IExpression): string[] { +export function foldersToIncludeGlobs(folderQueries: IFolderSearch[], globalInclude: glob.IExpression, absoluteGlobs = true): string[] { const globArgs: string[] = []; folderQueries.forEach(folderQuery => { const totalIncludePattern = objects.assign({}, globalInclude || {}, folderQuery.includePattern || {}); - const result = globExprsToRgGlobs(totalIncludePattern, folderQuery.folder); + const result = globExprsToRgGlobs(totalIncludePattern, absoluteGlobs && folderQuery.folder); globArgs.push(...result.globArgs); }); return globArgs; } -function globExprsToRgGlobs(patterns: glob.IExpression, folder: string, excludesToSkip?: Set): IRgGlobResult { +function globExprsToRgGlobs(patterns: glob.IExpression, folder?: string, excludesToSkip?: Set): IRgGlobResult { const globArgs: string[] = []; let siblingClauses: glob.IExpression = null; Object.keys(patterns) @@ -403,8 +436,15 @@ function globExprsToRgGlobs(patterns: glob.IExpression, folder: string, excludes return; } + if (!key) { + return; + } + const value = patterns[key]; - key = getAbsoluteGlob(folder, key); + key = trimTrailingSlash(folder ? getAbsoluteGlob(folder, key) : key); + + // glob.ts requires forward slashes + key = key.replace(/\\/g, '/'); if (typeof value === 'boolean' && value) { globArgs.push(fixDriveC(key)); @@ -427,11 +467,9 @@ function globExprsToRgGlobs(patterns: glob.IExpression, folder: string, excludes * Exported for testing */ export function getAbsoluteGlob(folder: string, key: string): string { - const absolute = paths.isAbsolute(key) ? + return paths.isAbsolute(key) ? key : path.join(folder, key); - - return trimTrailingSlash(absolute); } function trimTrailingSlash(str: string): string { @@ -479,7 +517,9 @@ function getRgArgs(config: IRawSearch): IRgGlobResult { } // Follow symlinks - args.push('--follow'); + if (!config.ignoreSymlinks) { + args.push('--follow'); + } // Set default encoding if only one folder is opened if (config.folderQueries.length === 1 && config.folderQueries[0].fileEncoding && config.folderQueries[0].fileEncoding !== 'utf8') { diff --git a/src/vs/workbench/services/search/node/search.ts b/src/vs/workbench/services/search/node/search.ts index be8e891b4fc..47730641ef0 100644 --- a/src/vs/workbench/services/search/node/search.ts +++ b/src/vs/workbench/services/search/node/search.ts @@ -8,22 +8,26 @@ import { PPromise, TPromise } from 'vs/base/common/winjs.base'; import { IExpression } from 'vs/base/common/glob'; import { IProgress, ILineMatch, IPatternInfo, ISearchStats, ISearchLog } from 'vs/platform/search/common/search'; +import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; export interface IFolderSearch { folder: string; excludePattern?: IExpression; includePattern?: IExpression; fileEncoding?: string; + disregardIgnoreFiles?: boolean; } export interface IRawSearch { folderQueries: IFolderSearch[]; + ignoreSymlinks?: boolean; extraFiles?: string[]; filePattern?: string; excludePattern?: IExpression; includePattern?: IExpression; contentPattern?: IPatternInfo; maxResults?: number; + exists?: boolean; sortByScore?: boolean; cacheKey?: string; maxFilesize?: number; @@ -31,10 +35,16 @@ export interface IRawSearch { disregardIgnoreFiles?: boolean; } +export interface ITelemetryEvent { + eventName: string; + data: ITelemetryData; +} + export interface IRawSearchService { fileSearch(search: IRawSearch): PPromise; textSearch(search: IRawSearch): PPromise; clearCache(cacheKey: string): TPromise; + fetchTelemetry(): PPromise; } export interface IRawFileMatch { diff --git a/src/vs/workbench/services/search/node/searchIpc.ts b/src/vs/workbench/services/search/node/searchIpc.ts index 74f91db2ede..4e9575e0d55 100644 --- a/src/vs/workbench/services/search/node/searchIpc.ts +++ b/src/vs/workbench/services/search/node/searchIpc.ts @@ -7,12 +7,13 @@ import { PPromise, TPromise } from 'vs/base/common/winjs.base'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IRawSearchService, IRawSearch, ISerializedSearchComplete, ISerializedSearchProgressItem } from './search'; +import { IRawSearchService, IRawSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ITelemetryEvent } from './search'; export interface ISearchChannel extends IChannel { call(command: 'fileSearch', search: IRawSearch): PPromise; call(command: 'textSearch', search: IRawSearch): PPromise; call(command: 'clearCache', cacheKey: string): TPromise; + call(command: 'fetchTelemetry'): PPromise; call(command: string, arg: any): TPromise; } @@ -20,11 +21,12 @@ export class SearchChannel implements ISearchChannel { constructor(private service: IRawSearchService) { } - call(command: string, arg: any): TPromise { + call(command: string, arg?: any): TPromise { switch (command) { case 'fileSearch': return this.service.fileSearch(arg); case 'textSearch': return this.service.textSearch(arg); case 'clearCache': return this.service.clearCache(arg); + case 'fetchTelemetry': return this.service.fetchTelemetry(); } return undefined; } @@ -42,7 +44,11 @@ export class SearchChannelClient implements IRawSearchService { return this.channel.call('textSearch', search); } - public clearCache(cacheKey: string): TPromise { + clearCache(cacheKey: string): TPromise { return this.channel.call('clearCache', cacheKey); } + + fetchTelemetry(): PPromise { + return this.channel.call('fetchTelemetry'); + } } \ No newline at end of file diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index 1ff0178c591..da0865c1e95 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -7,7 +7,6 @@ import { PPromise, TPromise } from 'vs/base/common/winjs.base'; import uri from 'vs/base/common/uri'; import objects = require('vs/base/common/objects'); -import scorer = require('vs/base/common/scorer'); import strings = require('vs/base/common/strings'); import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client, IIPCOptions } from 'vs/base/parts/ipc/node/ipc.cp'; @@ -16,11 +15,14 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { IModelService } from 'vs/editor/common/services/modelService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IRawSearch, IFolderSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedFileMatch, IRawSearchService } from './search'; +import { IRawSearch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedFileMatch, IRawSearchService, ITelemetryEvent } from './search'; import { ISearchChannel, SearchChannelClient } from './searchIpc'; import { IEnvironmentService, IDebugParams } from 'vs/platform/environment/common/environment'; import { ResourceMap } from 'vs/base/common/map'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { Schemas } from 'vs/base/common/network'; export class SearchService implements ISearchService { public _serviceBrand: any; @@ -32,11 +34,14 @@ export class SearchService implements ISearchService { @IModelService private modelService: IModelService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, @IEnvironmentService environmentService: IEnvironmentService, + // @ts-ignore unused injected service @IWorkspaceContextService private contextService: IWorkspaceContextService, + @ITelemetryService private telemetryService: ITelemetryService, @IConfigurationService private configurationService: IConfigurationService ) { this.diskSearch = new DiskSearch(!environmentService.isBuilt || environmentService.verbose, /*timeout=*/undefined, environmentService.debugSearch); this.registerSearchResultProvider(this.diskSearch); + this.forwardTelemetry(); } public registerSearchResultProvider(provider: ISearchResultProvider): IDisposable { @@ -188,7 +193,7 @@ export class SearchService implements ISearchService { return false; // if we match on file pattern, we have to ignore non file resources } - if (!scorer.matches(resource.fsPath, strings.stripWildcards(query.filePattern).toLowerCase())) { + if (!strings.fuzzyContains(resource.fsPath, strings.stripWildcards(query.filePattern).toLowerCase())) { return false; } } @@ -206,6 +211,13 @@ export class SearchService implements ISearchService { public clearCache(cacheKey: string): TPromise { return this.diskSearch.clearCache(cacheKey); } + + private forwardTelemetry() { + this.diskSearch.fetchTelemetry() + .then(null, onUnexpectedError, event => { + this.telemetryService.publicLog(event.eventName, event.data); + }); + } } export class DiskSearch implements ISearchResultProvider { @@ -249,25 +261,42 @@ export class DiskSearch implements ISearchResultProvider { let request: PPromise; let rawSearch: IRawSearch = { - folderQueries: query.folderQueries ? query.folderQueries.map(q => { - return { - excludePattern: q.excludePattern, - includePattern: q.includePattern, - fileEncoding: q.fileEncoding, - folder: q.folder.fsPath - }; - }) : [], - extraFiles: query.extraFileResources ? query.extraFileResources.map(r => r.fsPath) : [], + folderQueries: [], + extraFiles: [], filePattern: query.filePattern, excludePattern: query.excludePattern, includePattern: query.includePattern, maxResults: query.maxResults, + exists: query.exists, sortByScore: query.sortByScore, cacheKey: query.cacheKey, useRipgrep: query.useRipgrep, - disregardIgnoreFiles: query.disregardIgnoreFiles + disregardIgnoreFiles: query.disregardIgnoreFiles, + ignoreSymlinks: query.ignoreSymlinks }; + if (query.folderQueries) { + for (const q of query.folderQueries) { + if (q.folder.scheme === Schemas.file) { + rawSearch.folderQueries.push({ + excludePattern: q.excludePattern, + includePattern: q.includePattern, + fileEncoding: q.fileEncoding, + disregardIgnoreFiles: q.disregardIgnoreFiles, + folder: q.folder.fsPath + }); + } + } + } + + if (query.extraFileResources) { + for (const r of query.extraFileResources) { + if (r.scheme === Schemas.file) { + rawSearch.extraFiles.push(r.fsPath); + } + } + } + if (query.type === QueryType.Text) { rawSearch.contentPattern = query.contentPattern; } @@ -327,4 +356,8 @@ export class DiskSearch implements ISearchResultProvider { public clearCache(cacheKey: string): TPromise { return this.raw.clearCache(cacheKey); } + + public fetchTelemetry(): PPromise { + return this.raw.fetchTelemetry(); + } } diff --git a/src/vs/workbench/services/search/test/node/fixtures2/36438/modules/do-not-find.txt b/src/vs/workbench/services/search/test/node/fixtures2/36438/modules/do-not-find.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/vs/workbench/services/search/test/node/fixtures2/36438/more/modules/find.txt b/src/vs/workbench/services/search/test/node/fixtures2/36438/more/modules/find.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index 75fddf759ba..ed2bc113e36 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -22,14 +22,21 @@ const ROOT_FOLDER_QUERY: IFolderSearch[] = [ TEST_ROOT_FOLDER ]; +const ROOT_FOLDER_QUERY_36438: IFolderSearch[] = [ + { folder: path.normalize(require.toUrl('./fixtures2/36438')) } +]; + const MULTIROOT_QUERIES: IFolderSearch[] = [ { folder: EXAMPLES_FIXTURES }, { folder: MORE_FIXTURES } ]; +const testTimeout = 5000; + suite('FileSearchEngine', () => { test('Files: *.js', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.js' @@ -47,7 +54,133 @@ suite('FileSearchEngine', () => { }); }); + test('Files: maxResults', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + maxResults: 1 + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error) => { + assert.ok(!error); + assert.equal(count, 1); + done(); + }); + }); + + test('Files: maxResults without Ripgrep', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + maxResults: 1, + useRipgrep: false + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error) => { + assert.ok(!error); + assert.equal(count, 1); + done(); + }); + }); + + test('Files: exists', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/file.txt': true }, + exists: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(complete.limitHit); + done(); + }); + }); + + test('Files: not exists', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/nofile.txt': true }, + exists: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(!complete.limitHit); + done(); + }); + }); + + test('Files: exists without Ripgrep', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/file.txt': true }, + exists: true, + useRipgrep: false + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(complete.limitHit); + done(); + }); + }); + + test('Files: not exists without Ripgrep', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY, + includePattern: { '**/nofile.txt': true }, + exists: true, + useRipgrep: false + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(!complete.limitHit); + done(); + }); + }); + test('Files: examples/com*', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: normalize(join('examples', 'com*'), true) @@ -66,6 +199,7 @@ suite('FileSearchEngine', () => { }); test('Files: examples (fuzzy)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'xl' @@ -84,6 +218,7 @@ suite('FileSearchEngine', () => { }); test('Files: multiroot', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: MULTIROOT_QUERIES, filePattern: 'file' @@ -101,7 +236,57 @@ suite('FileSearchEngine', () => { }); }); + test('Files: multiroot with includePattern and maxResults', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: MULTIROOT_QUERIES, + maxResults: 1, + includePattern: { + '*.txt': true, + '*.js': true + }, + useRipgrep: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 1); + done(); + }); + }); + + test('Files: multiroot with includePattern and exists', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: MULTIROOT_QUERIES, + exists: true, + includePattern: { + '*.txt': true, + '*.js': true + }, + useRipgrep: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error, complete) => { + assert.ok(!error); + assert.equal(count, 0); + assert.ok(complete.limitHit); + done(); + }); + }); + test('Files: NPE (CamelCase)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'NullPE' @@ -120,6 +305,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.*', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*' @@ -138,6 +324,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.as', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.as' @@ -156,6 +343,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* without derived', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'site.*', @@ -178,6 +366,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* exclude folder without wildcard', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -196,7 +385,46 @@ suite('FileSearchEngine', () => { }); }); + test('Files: exclude folder without wildcard #36438', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY_36438, + excludePattern: { 'modules': true } + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error) => { + assert.ok(!error); + assert.equal(count, 1); + done(); + }); + }); + + test('Files: include folder without wildcard #36438', function (done: () => void) { + this.timeout(testTimeout); + let engine = new FileSearchEngine({ + folderQueries: ROOT_FOLDER_QUERY_36438, + includePattern: { 'modules/**': true } + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error) => { + assert.ok(!error); + assert.equal(count, 1); + done(); + }); + }); + test('Files: *.* exclude folder with leading wildcard', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -216,6 +444,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* exclude folder with trailing wildcard', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -235,6 +464,7 @@ suite('FileSearchEngine', () => { }); test('Files: *.* exclude with unicode', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '*.*', @@ -254,6 +484,7 @@ suite('FileSearchEngine', () => { }); test('Files: multiroot with exclude', function (done: () => void) { + this.timeout(testTimeout); const folderQueries: IFolderSearch[] = [ { folder: EXAMPLES_FIXTURES, @@ -287,6 +518,7 @@ suite('FileSearchEngine', () => { }); test('Files: Unicode and Spaces', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: '汉语' @@ -308,6 +540,7 @@ suite('FileSearchEngine', () => { }); test('Files: no results', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: 'nofilematch' @@ -326,6 +559,7 @@ suite('FileSearchEngine', () => { }); test('Files: absolute path to file ignores excludes', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: path.normalize(path.join(require.toUrl('./fixtures'), 'site.css')), @@ -348,6 +582,7 @@ suite('FileSearchEngine', () => { }); test('Files: relative path matched once', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: path.normalize(path.join('examples', 'company.js')) @@ -369,6 +604,7 @@ suite('FileSearchEngine', () => { }); test('Files: relative path to file ignores excludes', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, filePattern: path.normalize(path.join('examples', 'company.js')), @@ -391,6 +627,7 @@ suite('FileSearchEngine', () => { }); test('Files: Include pattern, single files', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: ROOT_FOLDER_QUERY, includePattern: { @@ -414,6 +651,7 @@ suite('FileSearchEngine', () => { }); test('Files: extraFiles only', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [], extraFiles: [ @@ -440,6 +678,7 @@ suite('FileSearchEngine', () => { }); test('Files: extraFiles only (with include)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [], extraFiles: [ @@ -467,6 +706,7 @@ suite('FileSearchEngine', () => { }); test('Files: extraFiles only (with exclude)', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [], extraFiles: [ @@ -491,6 +731,7 @@ suite('FileSearchEngine', () => { }); test('Files: no dupes in nested folders', function (done: () => void) { + this.timeout(testTimeout); let engine = new FileSearchEngine({ folderQueries: [ { folder: EXAMPLES_FIXTURES }, @@ -515,6 +756,7 @@ suite('FileSearchEngine', () => { suite('FileWalker', () => { test('Find: exclude subfolder', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -525,14 +767,14 @@ suite('FileWalker', () => { const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '**/something': true } }); const cmd1 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + walker.readStdout(cmd1, 'utf8', /*isRipgrep=*/false, (err1, stdout1) => { assert.equal(err1, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '**/subfolder': true } }); const cmd2 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + walker.readStdout(cmd2, 'utf8', /*isRipgrep=*/false, (err2, stdout2) => { assert.equal(err2, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); @@ -542,6 +784,7 @@ suite('FileWalker', () => { }); test('Find: folder excludes', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -559,7 +802,7 @@ suite('FileWalker', () => { const walker = new FileWalker({ folderQueries }); const cmd1 = walker.spawnFindCmd(folderQueries[0]); - walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + walker.readStdout(cmd1, 'utf8', /*isRipgrep=*/false, (err1, stdout1) => { assert.equal(err1, null); assert(outputContains(stdout1, file0), stdout1); assert(!outputContains(stdout1, file1), stdout1); @@ -568,6 +811,7 @@ suite('FileWalker', () => { }); test('Find: exclude multiple folders', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -579,7 +823,7 @@ suite('FileWalker', () => { const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '**/something': true } }); const cmd1 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + walker.readStdout(cmd1, 'utf8', /*isRipgrep=*/false, (err1, stdout1) => { assert.equal(err1, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); @@ -587,7 +831,7 @@ suite('FileWalker', () => { const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '{**/examples,**/more}': true } }); const cmd2 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + walker.readStdout(cmd2, 'utf8', /*isRipgrep=*/false, (err2, stdout2) => { assert.equal(err2, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); @@ -598,6 +842,7 @@ suite('FileWalker', () => { }); test('Find: exclude folder path suffix', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -608,14 +853,14 @@ suite('FileWalker', () => { const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '**/examples/something': true } }); const cmd1 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + walker.readStdout(cmd1, 'utf8', /*isRipgrep=*/false, (err1, stdout1) => { assert.equal(err1, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '**/examples/subfolder': true } }); const cmd2 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + walker.readStdout(cmd2, 'utf8', /*isRipgrep=*/false, (err2, stdout2) => { assert.equal(err2, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); @@ -625,6 +870,7 @@ suite('FileWalker', () => { }); test('Find: exclude subfolder path suffix', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -635,14 +881,14 @@ suite('FileWalker', () => { const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '**/subfolder/something': true } }); const cmd1 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + walker.readStdout(cmd1, 'utf8', /*isRipgrep=*/false, (err1, stdout1) => { assert.equal(err1, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { '**/subfolder/anotherfolder': true } }); const cmd2 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + walker.readStdout(cmd2, 'utf8', /*isRipgrep=*/false, (err2, stdout2) => { assert.equal(err2, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); @@ -652,6 +898,7 @@ suite('FileWalker', () => { }); test('Find: exclude folder path', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -662,14 +909,14 @@ suite('FileWalker', () => { const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { 'examples/something': true } }); const cmd1 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + walker.readStdout(cmd1, 'utf8', /*isRipgrep=*/false, (err1, stdout1) => { assert.equal(err1, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); const walker = new FileWalker({ folderQueries: ROOT_FOLDER_QUERY, excludePattern: { 'examples/subfolder': true } }); const cmd2 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + walker.readStdout(cmd2, 'utf8', /*isRipgrep=*/false, (err2, stdout2) => { assert.equal(err2, null); assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); @@ -679,6 +926,7 @@ suite('FileWalker', () => { }); test('Find: exclude combination of paths', function (done: () => void) { + this.timeout(testTimeout); if (platform.isWindows) { done(); return; @@ -704,7 +952,7 @@ suite('FileWalker', () => { } }); const cmd1 = walker.spawnFindCmd(TEST_ROOT_FOLDER); - walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + walker.readStdout(cmd1, 'utf8', /*isRipgrep=*/false, (err1, stdout1) => { assert.equal(err1, null); for (const fileIn of filesIn) { assert.notStrictEqual(stdout1.split('\n').indexOf(fileIn), -1, stdout1); diff --git a/src/vs/workbench/services/search/test/node/searchService.test.ts b/src/vs/workbench/services/search/test/node/searchService.test.ts index 36935227c65..7fd40591eef 100644 --- a/src/vs/workbench/services/search/test/node/searchService.test.ts +++ b/src/vs/workbench/services/search/test/node/searchService.test.ts @@ -7,9 +7,10 @@ import * as assert from 'assert'; import { normalize } from 'path'; +import path = require('path'); import { IProgress, IUncachedSearchStats } from 'vs/platform/search/common/search'; -import { ISearchEngine, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchComplete } from 'vs/workbench/services/search/node/search'; +import { ISearchEngine, IRawSearch, IRawFileMatch, ISerializedFileMatch, ISerializedSearchComplete, IFolderSearch } from 'vs/workbench/services/search/node/search'; import { SearchService as RawSearchService } from 'vs/workbench/services/search/node/rawSearchService'; import { DiskSearch } from 'vs/workbench/services/search/node/searchService'; @@ -17,6 +18,12 @@ const TEST_FOLDER_QUERIES = [ { folder: normalize('/some/where') } ]; +const TEST_FIXTURES = path.normalize(require.toUrl('./fixtures')); +const MULTIROOT_QUERIES: IFolderSearch[] = [ + { folder: path.join(TEST_FIXTURES, 'examples') }, + { folder: path.join(TEST_FIXTURES, 'more') } +]; + const stats: IUncachedSearchStats = { fromCache: false, resultCount: 4, @@ -143,6 +150,43 @@ suite('SearchService', () => { }); }); + test('Multi-root with include pattern and maxResults', function () { + const service = new RawSearchService(); + + const query: IRawSearch = { + folderQueries: MULTIROOT_QUERIES, + maxResults: 1, + includePattern: { + '*.txt': true, + '*.js': true + }, + }; + + return DiskSearch.collectResults(service.fileSearch(query)) + .then(result => { + assert.strictEqual(result.results.length, 1, 'Result'); + }); + }); + + test('Multi-root with include pattern and exists', function () { + const service = new RawSearchService(); + + const query: IRawSearch = { + folderQueries: MULTIROOT_QUERIES, + exists: true, + includePattern: { + '*.txt': true, + '*.js': true + }, + }; + + return DiskSearch.collectResults(service.fileSearch(query)) + .then(result => { + assert.strictEqual(result.results.length, 0, 'Result'); + assert.ok(result.limitHit); + }); + }); + test('Sorted results', function () { const paths = ['bab', 'bbc', 'abb']; const matches: IRawFileMatch[] = paths.map(relativePath => ({ diff --git a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts index de5000fdcfe..cdc6ada67da 100644 --- a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts +++ b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts @@ -37,7 +37,7 @@ const textSearchWorkerProvider = new TextSearchWorkerProvider(); function doLegacySearchTest(config: IRawSearch, expectedResultCount: number | Function): TPromise { return new TPromise((resolve, reject) => { - let engine = new TextSearchEngine(config, new FileWalker(config), textSearchWorkerProvider); + let engine = new TextSearchEngine(config, new FileWalker({ ...config, useRipgrep: false }), textSearchWorkerProvider); let c = 0; engine.search((result) => { diff --git a/src/vs/workbench/services/telemetry/common/workspaceStats.ts b/src/vs/workbench/services/telemetry/node/workspaceStats.ts similarity index 71% rename from src/vs/workbench/services/telemetry/common/workspaceStats.ts rename to src/vs/workbench/services/telemetry/node/workspaceStats.ts index dd8965ca6bb..8c122d88bdb 100644 --- a/src/vs/workbench/services/telemetry/common/workspaceStats.ts +++ b/src/vs/workbench/services/telemetry/node/workspaceStats.ts @@ -11,7 +11,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import URI from 'vs/base/common/uri'; import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; @@ -36,7 +36,7 @@ const SecondLevelDomainWhitelist = [ 'google.com' ]; -type Tags = { [index: string]: boolean | number }; +type Tags = { [index: string]: boolean | number | string }; function stripLowLevelDomains(domain: string): string { let match = domain.match(SecondLevelDomainMatcher); @@ -144,19 +144,65 @@ export class WorkspaceStats { return arr.some(v => v.search(regEx) > -1) || undefined; } + /* __GDPR__FRAGMENT__ + "WorkspaceTags" : { + "workbench.filesToOpen" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workbench.filesToCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "workspace.id" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.roots" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.empty" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.grunt" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.gulp" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.jake" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.tsconfig" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.jsconfig" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.config.xml" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.vsc.extension" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.ASP5" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.sln" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.unity" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.npm" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.bower" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.yeoman.code.ext" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.cordova.high" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.cordova.low" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.xamarin.android" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.xamarin.ios" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.android.cpp" : { "classification": "CustomerContent", "purpose": "FeatureInsight" }, + "workspace.reactNative" : { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ private getWorkspaceTags(configuration: IWindowConfiguration): TPromise { const tags: Tags = Object.create(null); - const { filesToOpen, filesToCreate, filesToDiff } = configuration; - tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || undefined; - tags['workbench.filesToCreate'] = filesToCreate && filesToCreate.length || undefined; - tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || undefined; - + const state = this.contextService.getWorkbenchState(); const workspace = this.contextService.getWorkspace(); - tags['workspace.roots'] = workspace ? workspace.roots.length : 0; - tags['workspace.empty'] = !workspace; - const folders = workspace ? workspace.roots : this.environmentService.appQuality !== 'stable' && this.findFolders(configuration); + let workspaceId: string; + switch (state) { + case WorkbenchState.EMPTY: + workspaceId = void 0; + break; + case WorkbenchState.FOLDER: + workspaceId = crypto.createHash('sha1').update(workspace.folders[0].uri.fsPath).digest('hex'); + break; + case WorkbenchState.WORKSPACE: + workspaceId = crypto.createHash('sha1').update(workspace.configuration.fsPath).digest('hex'); + } + + tags['workspace.id'] = workspaceId; + + const { filesToOpen, filesToCreate, filesToDiff } = configuration; + tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || 0; + tags['workbench.filesToCreate'] = filesToCreate && filesToCreate.length || 0; + tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0; + + const isEmpty = state === WorkbenchState.EMPTY; + tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length; + tags['workspace.empty'] = isEmpty; + + const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.environmentService.appQuality !== 'stable' && this.findFolders(configuration); if (folders && folders.length && this.fileService) { return this.fileService.resolveFiles(folders.map(resource => ({ resource }))).then(results => { const names = ([]).concat(...results.map(result => result.success ? (result.stat.children || []) : [])).map(c => c.name); @@ -244,6 +290,13 @@ export class WorkspaceStats { public reportWorkspaceTags(configuration: IWindowConfiguration): void { this.getWorkspaceTags(configuration).then((tags) => { + /* __GDPR__ + "workspce.tags" : { + "${include}": [ + "${WorkspaceTags}" + ] + } + */ this.telemetryService.publicLog('workspce.tags', tags); }, error => onUnexpectedError(error)); } @@ -260,6 +313,11 @@ export class WorkspaceStats { const set = domains.reduce((set, list) => list.reduce((set, item) => set.add(item), set), new Set()); const list: string[] = []; set.forEach(item => list.push(item)); + /* __GDPR__ + "workspace.remotes" : { + "domains" : { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('workspace.remotes', { domains: list.sort() }); }, onUnexpectedError); } @@ -272,9 +330,21 @@ export class WorkspaceStats { content => getHashedRemotes(content.value), err => [] // ignore missing or binary file ); - })).then(hashedRemotes => this.telemetryService.publicLog('workspace.hashedRemotes', { remotes: hashedRemotes }), onUnexpectedError); + })).then(hashedRemotes => { + /* __GDPR__ + "workspace.hashedRemotes" : { + "remotes" : { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('workspace.hashedRemotes', { remotes: hashedRemotes }); + }, onUnexpectedError); } + /* __GDPR__FRAGMENT__ + "AzureTags" : { + "node" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ private reportAzureNode(workspaceUris: URI[], tags: Tags): TPromise { // TODO: should also work for `node_modules` folders several levels down const uris = workspaceUris.map(workspaceUri => { @@ -295,6 +365,12 @@ export class WorkspaceStats { }); } + + /* __GDPR__FRAGMENT__ + "AzureTags" : { + "java" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ private reportAzureJava(workspaceUris: URI[], tags: Tags): TPromise { return TPromise.join(workspaceUris.map(workspaceUri => { const path = workspaceUri.path; @@ -317,18 +393,24 @@ export class WorkspaceStats { return this.reportAzureJava(uris, tags); }).then((tags) => { if (Object.keys(tags).length) { + /* __GDPR__ + "workspace.azure" : { + "${include}": [ + "${AzureTags}" + ] + } + */ this.telemetryService.publicLog('workspace.azure', tags); } }).then(null, onUnexpectedError); } public reportCloudStats(): void { - const workspace = this.contextService.getWorkspace(); - const uris = workspace && workspace.roots; - if (uris && uris.length && this.fileService) { + const uris = this.contextService.getWorkspace().folders.map(folder => folder.uri); + if (uris.length && this.fileService) { this.reportRemoteDomains(uris); this.reportRemotes(uris); this.reportAzure(uris); } - }; + } } diff --git a/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts b/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts index 5647af87623..7bb6e7d3d8f 100644 --- a/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts +++ b/src/vs/workbench/services/telemetry/test/workspaceStats.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import * as crypto from 'crypto'; -import { getDomainsOfRemotes, getRemotes, getHashedRemotes } from 'vs/workbench/services/telemetry/common/workspaceStats'; +import { getDomainsOfRemotes, getRemotes, getHashedRemotes } from 'vs/workbench/services/telemetry/node/workspaceStats'; function hash(value: string): string { return crypto.createHash('sha1').update(value.toString()).digest('hex'); diff --git a/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts b/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts index 6b950249e3b..67d2651068e 100644 --- a/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts +++ b/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts @@ -105,6 +105,8 @@ export class TextMateService implements ITextMateService { private _themeService: IWorkbenchThemeService; private _scopeRegistry: TMScopeRegistry; private _injections: { [scopeName: string]: string[]; }; + private _injectedEmbeddedLanguages: { [scopeName: string]: IEmbeddedLanguagesMap[]; }; + private _languageToScope: Map; private _styleElement: HTMLStyleElement; @@ -123,6 +125,7 @@ export class TextMateService implements ITextMateService { this._scopeRegistry = new TMScopeRegistry(); this.onDidEncounterLanguage = this._scopeRegistry.onDidEncounterLanguage; this._injections = {}; + this._injectedEmbeddedLanguages = {}; this._languageToScope = new Map(); this._grammarRegistry = new Registry({ @@ -237,6 +240,16 @@ export class TextMateService implements ITextMateService { } injections.push(syntax.scopeName); } + + if (syntax.embeddedLanguages) { + for (let injectScope of syntax.injectTo) { + let injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[injectScope]; + if (!injectedEmbeddedLanguages) { + this._injectedEmbeddedLanguages[injectScope] = injectedEmbeddedLanguages = []; + } + injectedEmbeddedLanguages.push(syntax.embeddedLanguages); + } + } } let modeId = syntax.language; @@ -271,6 +284,15 @@ export class TextMateService implements ITextMateService { return TPromise.wrapError(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); } let embeddedLanguages = this._resolveEmbeddedLanguages(languageRegistration.embeddedLanguages); + let injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[scopeName]; + if (injectedEmbeddedLanguages) { + for (const injected of injectedEmbeddedLanguages.map(this._resolveEmbeddedLanguages.bind(this))) { + for (const scope of Object.keys(injected)) { + embeddedLanguages[scope] = injected[scope]; + } + } + } + let languageId = this._modeService.getLanguageIdentifier(modeId).id; let containsEmbeddedLanguages = (Object.keys(embeddedLanguages).length > 0); return new TPromise((c, e, p) => { diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index bdfaaa0b9ba..a01191f7cd2 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -12,7 +12,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { guessMimeTypes } from 'vs/base/common/mime'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import URI from 'vs/base/common/uri'; -import * as assert from 'vs/base/common/assert'; +// import * as assert from 'vs/base/common/assert'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import paths = require('vs/base/common/paths'); import diagnostics = require('vs/base/common/diagnostics'); @@ -31,9 +31,9 @@ import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { anonymize } from 'vs/platform/telemetry/common/telemetryUtils'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IRawTextSource } from 'vs/editor/common/model/textSource'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; /** * The text file editor model listens to changes to its underlying code editor model and saves these changes through the file service back to the disk. @@ -87,10 +87,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IBackupFileService private backupFileService: IBackupFileService, @IEnvironmentService private environmentService: IEnvironmentService, @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IHashService private hashService: IHashService ) { super(modelService, modeService); - assert.ok(resource.scheme === 'file', 'TextFileEditorModel can only handle file:// resources.'); + // TODO@remote + // assert.ok(resource.scheme === 'file', 'TextFileEditorModel can only handle file:// resources.'); this.resource = resource; this.toDispose = []; @@ -99,6 +101,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.toDispose.push(this._onDidContentChange); this.toDispose.push(this._onDidStateChange); this.preferredEncoding = preferredEncoding; + this.inOrphanMode = false; this.dirty = false; this.versionId = 0; this.lastSaveAttemptTime = 0; @@ -119,16 +122,18 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.toDispose.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); this.toDispose.push(this.textFileService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); this.toDispose.push(this.textFileService.onFilesAssociationChange(e => this.onFilesAssociationChange())); - this.toDispose.push(this.onDidStateChange(e => { - if (e === StateChange.REVERTED) { + this.toDispose.push(this.onDidStateChange(e => this.onStateChange(e))); + } - // Cancel any content change event promises as they are no longer valid. - this.contentChangeEventScheduler.cancel(); + private onStateChange(e: StateChange): void { + if (e === StateChange.REVERTED) { - // Refire state change reverted events as content change events - this._onDidContentChange.fire(StateChange.REVERTED); - } - })); + // Cancel any content change event promises as they are no longer valid. + this.contentChangeEventScheduler.cancel(); + + // Refire state change reverted events as content change events + this._onDidContentChange.fire(StateChange.REVERTED); + } } private onFileChanges(e: FileChangesEvent): void { @@ -361,10 +366,31 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private loadWithContent(content: IRawTextContent | IContent, backup?: URI): TPromise { - diag('load() - resolved content', this.resource, new Date()); + return this.doLoadWithContent(content, backup).then(model => { - // Telemetry - this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); + // Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype + if (this.isSettingsFile()) { + /* __GDPR__ + "settingsRead" : {} + */ + this.telemetryService.publicLog('settingsRead'); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data + } else { + /* __GDPR__ + "fileGet" : { + "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "path": { "classification": "CustomerContent", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: this.hashService.createSHA1(this.resource.fsPath) }); + } + + return model; + }); + } + + private doLoadWithContent(content: IRawTextContent | IContent, backup?: URI): TPromise { + diag('load() - resolved content', this.resource, new Date()); // Update our resolved disk stat model const resolvedStat: IFileStat = { @@ -449,10 +475,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.setDirty(false); } - // See https://github.com/Microsoft/vscode/issues/30189 - // This code has been extracted to a different method because it caused a memory leak - // where `value` was captured in the content change listener closure scope. - this._installChangeContentListener(); + // Model Listeners + this.installModelListeners(); return this; }, error => { @@ -465,13 +489,14 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.createTextEditorModelPromise; } - private _installChangeContentListener(): void { + private installModelListeners(): void { + // See https://github.com/Microsoft/vscode/issues/30189 // This code has been extracted to a different method because it caused a memory leak // where `value` was captured in the content change listener closure scope. - this.toDispose.push(this.textEditorModel.onDidChangeContent(() => { - this.onModelContentChanged(); - })); + + // Content Change + this.toDispose.push(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); } private doLoadBackup(backup: URI): TPromise { @@ -666,10 +691,15 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // mark the save participant as current pending save operation return this.saveSequentializer.setPending(versionId, saveParticipantPromise.then(newVersionId => { - // the model was not dirty and no save participant changed the contents, so we do not have - // to write the contents to disk, as they are already on disk. we still want to trigger - // a change on the file though so that external file watchers can be notified - if (options.force && !this.dirty && options.reason === SaveReason.EXPLICIT && versionId === newVersionId) { + // Under certain conditions a save to the model will not cause the contents to the flushed on + // disk because we can assume that the contents are already on disk. Instead, we just touch the + // file to still trigger external file watchers for example. + // The conditions are all of: + // - a forced, explicit save (Ctrl+S) + // - the model is not dirty (otherwise we know there are changed which needs to go to the file) + // - the model is not in orphan mode (because in that case we know the file does not exist on disk) + // - the model version did not change due to save participants running + if (options.force && !this.dirty && !this.inOrphanMode && options.reason === SaveReason.EXPLICIT && versionId === newVersionId) { return this.doTouch(); } @@ -696,8 +726,17 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Telemetry if (this.isSettingsFile()) { + /* __GDPR__ + "settingsWritten" : {} + */ this.telemetryService.publicLog('settingsWritten'); // Do not log write to user settings.json and .vscode folder as a filePUT event as it ruins our JSON usage data } else { + /* __GDPR__ + "filePUT" : { + "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('filePUT', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.lastResolvedDiskStat.resource.fsPath) }); } @@ -745,13 +784,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Check for workspace settings file - if (this.contextService.hasWorkspace()) { - return this.contextService.getWorkspace().roots.some(root => { - return paths.isEqualOrParent(this.resource.fsPath, path.join(root.fsPath, '.vscode')); - }); - } - - return false; + return this.contextService.getWorkspace().folders.some(folder => { + return paths.isEqualOrParent(this.resource.fsPath, path.join(folder.uri.fsPath, '.vscode')); + }); } private doTouch(): TPromise { diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 70e7a582514..c185124e868 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -17,7 +17,7 @@ import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IRevertOptions, IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; import { ConfirmResult } from 'vs/workbench/common/editor'; import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IFileService, IResolveContentOptions, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -85,8 +85,15 @@ export abstract class TextFileService implements ITextFileService { const configuration = this.configurationService.getConfiguration(); this.currentFilesAssociationConfig = configuration && configuration.files && configuration.files.associations; - this.onConfigurationChange(configuration); + this.onFilesConfigurationChange(configuration); + /* __GDPR__ + "autoSave" : { + "${include}": [ + "${IAutoSaveConfiguration}" + ] + } + */ this.telemetryService.publicLog('autoSave', this.getAutoSaveConfiguration()); this.registerListeners(); @@ -116,8 +123,12 @@ export abstract class TextFileService implements ITextFileService { this.lifecycleService.onWillShutdown(event => event.veto(this.beforeShutdown(event.reason))); this.lifecycleService.onShutdown(this.dispose, this); - // Configuration changes - this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); + // Files configuration changes + this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('files')) { + this.onFilesConfigurationChange(this.configurationService.getConfiguration()); + } + })); } private beforeShutdown(reason: ShutdownReason): boolean | TPromise { @@ -180,7 +191,7 @@ export abstract class TextFileService implements ITextFileService { let doBackup: boolean; switch (reason) { case ShutdownReason.CLOSE: - if (this.contextService.hasWorkspace() && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured } else if (windowCount > 1 || platform.isMacintosh) { doBackup = false; // do not backup if a window is closed that does not cause quitting of the application @@ -198,7 +209,7 @@ export abstract class TextFileService implements ITextFileService { break; case ShutdownReason.LOAD: - if (this.contextService.hasWorkspace() && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured } else { doBackup = false; // do not backup because we are switching contexts @@ -211,6 +222,13 @@ export abstract class TextFileService implements ITextFileService { } // Telemetry + /* __GDPR__ + "hotExit:triggered" : { + "reason" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "windowCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "fileCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('hotExit:triggered', { reason, windowCount, fileCount: dirtyToBackup.length }); // Backup @@ -302,7 +320,7 @@ export abstract class TextFileService implements ITextFileService { return this.backupFileService.discardAllWorkspaceBackups(); } - protected onConfigurationChange(configuration: IFilesConfiguration): void { + protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); const autoSaveMode = (configuration && configuration.files && configuration.files.autoSave) || AutoSaveConfiguration.OFF; @@ -407,10 +425,14 @@ export abstract class TextFileService implements ITextFileService { const filesToSave: URI[] = []; const untitledToSave: URI[] = []; toSave.forEach(s => { - if (s.scheme === Schemas.file) { - filesToSave.push(s); - } else if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && s.scheme === UNTITLED_SCHEMA) { + // TODO@remote + // if (s.scheme === Schemas.file) { + // filesToSave.push(s); + // } else + if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && s.scheme === UNTITLED_SCHEMA) { untitledToSave.push(s); + } else { + filesToSave.push(s); } }); @@ -617,12 +639,14 @@ export abstract class TextFileService implements ITextFileService { } private suggestFileName(untitledResource: URI): string { - const root = this.historyService.getLastActiveWorkspaceRoot(); - if (root) { - return URI.file(paths.join(root.fsPath, this.untitledEditorService.suggestFileName(untitledResource))).fsPath; + const untitledFileName = this.untitledEditorService.suggestFileName(untitledResource); + + const lastActiveFile = this.historyService.getLastActiveFile(); + if (lastActiveFile) { + return URI.file(paths.join(paths.dirname(lastActiveFile.fsPath), untitledFileName)).fsPath; } - return this.untitledEditorService.suggestFileName(untitledResource); + return untitledFileName; } public revert(resource: URI, options?: IRevertOptions): TPromise { @@ -712,4 +736,4 @@ export abstract class TextFileService implements ITextFileService { // Clear all caches this._models.clear(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index fc5bb023221..3a649cade6e 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -100,6 +100,13 @@ export interface IResult { success?: boolean; } +/* __GDPR__FRAGMENT__ + "IAutoSaveConfiguration" : { + "autoSaveDelay" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "autoSaveFocusChange": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "autoSaveApplicationChange": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ export interface IAutoSaveConfiguration { autoSaveDelay: number; autoSaveFocusChange: boolean; diff --git a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts index a28e830308b..d5823de480d 100644 --- a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts @@ -118,7 +118,7 @@ export class TextFileService extends AbstractTextFileService { buttons.push(save, cancel, dontSave); } - const opts: Electron.ShowMessageBoxOptions = { + const opts: Electron.MessageBoxOptions = { title: product.nameLong, message: message.join('\n'), type: 'warning', @@ -132,19 +132,17 @@ export class TextFileService extends AbstractTextFileService { opts.defaultId = 2; } - const choice = this.windowService.showMessageBox(opts); + const choice = this.windowService.showMessageBoxSync(opts); return buttons[choice].result; } public promptForPath(defaultPath?: string): string { - return this.windowService.showSaveDialog(this.getSaveDialogOptions(defaultPath ? paths.normalize(defaultPath, true) : void 0)); + return this.windowService.showSaveDialog(this.getSaveDialogOptions(defaultPath)); } private getSaveDialogOptions(defaultPath?: string): Electron.SaveDialogOptions { - const options: Electron.SaveDialogOptions = { - defaultPath: defaultPath - }; + const options: Electron.SaveDialogOptions = { defaultPath }; // Filters are only enabled on Windows where they work properly if (!isWindows) { @@ -154,7 +152,7 @@ export class TextFileService extends AbstractTextFileService { interface IFilter { name: string; extensions: string[]; } // Build the file filter by using our known languages - const ext: string = paths.extname(defaultPath); + const ext: string = defaultPath ? paths.extname(defaultPath) : void 0; let matchingFilter: IFilter; const filters: IFilter[] = this.modeService.getRegisteredLanguageNames().map(languageName => { const extensions = this.modeService.getExtensions(languageName); diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 48c32c6a912..99275a3e567 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -163,7 +163,6 @@ suite('Files - TextFileEditorModelManager', () => { let revertedCounter = 0; let savedCounter = 0; let encodingCounter = 0; - let orphanedCounter = 0; let disposeCounter = 0; let contentCounter = 0; @@ -191,12 +190,6 @@ suite('Files - TextFileEditorModelManager', () => { } }); - manager.onModelOrphanedChanged(e => { - if (e.resource.toString() === resource1.toString()) { - orphanedCounter++; - } - }); - manager.onModelContentChanged(e => { if (e.resource.toString() === resource1.toString()) { contentCounter++; @@ -232,7 +225,6 @@ suite('Files - TextFileEditorModelManager', () => { // content change event if done async TPromise.timeout(10).then(() => { assert.equal(contentCounter, 2); - assert.equal(orphanedCounter, 1); model1.dispose(); model2.dispose(); @@ -330,15 +322,15 @@ suite('Files - TextFileEditorModelManager', () => { const resource = toResource('/path/index_something.txt'); - manager.loadOrCreate(resource, { encoding: 'utf8' }).done((model: TextFileEditorModel) => { + manager.loadOrCreate(resource, { encoding: 'utf8' }).done(model => { model.textEditorModel.setValue('make dirty'); - manager.disposeModel(model); + manager.disposeModel(model as TextFileEditorModel); assert.ok(!model.isDisposed()); model.revert(true); - manager.disposeModel(model); + manager.disposeModel(model as TextFileEditorModel); assert.ok(model.isDisposed()); manager.dispose(); diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 777b42a5b71..3fe68e030d9 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -19,7 +19,7 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; import { HotExitConfiguration } from 'vs/platform/files/common/files'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/common/workspace'; class ServiceAccessor { constructor( @@ -104,7 +104,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.DONT_SAVE); - service.onConfigurationChange({ files: { hotExit: 'off' } }); + service.onFilesConfigurationChange({ files: { hotExit: 'off' } }); model.load().done(() => { model.textEditorModel.setValue('foo'); @@ -137,7 +137,7 @@ suite('Files - TextFileService', () => { const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.SAVE); - service.onConfigurationChange({ files: { hotExit: 'off' } }); + service.onFilesConfigurationChange({ files: { hotExit: 'off' } }); model.load().done(() => { model.textEditorModel.setValue('foo'); @@ -371,16 +371,16 @@ suite('Files - TextFileService', () => { }); }); - function hotExitTest(setting: string, shutdownReason: ShutdownReason, multipleWindows: boolean, workspace: true, shouldVeto: boolean, done: () => void): void { + function hotExitTest(this: any, setting: string, shutdownReason: ShutdownReason, multipleWindows: boolean, workspace: true, shouldVeto: boolean, done: () => void): void { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; // Set hot exit config - service.onConfigurationChange({ files: { hotExit: setting } }); + service.onFilesConfigurationChange({ files: { hotExit: setting } }); // Set empty workspace if required if (!workspace) { - accessor.contextService.setWorkspace(null); + accessor.contextService.setWorkspace(new Workspace('empty:1508317022751')); } // Set multiple windows if required if (multipleWindows) { diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index c7b7668b869..e81451b195a 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -35,7 +35,10 @@ class ResourceModelCollection extends ReferenceCollection this.instantiationService.createInstance(ResourceEditorModel, resource)); } @@ -99,7 +102,6 @@ export class TextModelResolverService implements ITextModelService { private resourceModelCollection: ResourceModelCollection; constructor( - @ITextFileService private textFileService: ITextFileService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, @IInstantiationService private instantiationService: IInstantiationService, @IModelService private modelService: IModelService diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts index 9ae8a6fd4ba..968623410fd 100644 --- a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -71,9 +71,9 @@ suite('Workbench - TextModelResolverService', () => { let resource = URI.from({ scheme: 'test', authority: null, path: 'thePath' }); let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); - input.resolve().then((model: ResourceEditorModel) => { + input.resolve().then(model => { assert.ok(model); - assert.equal(model.getValue(), 'Hello Test'); + assert.equal((model as ResourceEditorModel).getValue(), 'Hello Test'); let disposed = false; once(model.onDispose)(() => { diff --git a/src/vs/workbench/services/themes/common/colorThemeSchema.ts b/src/vs/workbench/services/themes/common/colorThemeSchema.ts index 5c6b7609512..4e7c779283c 100644 --- a/src/vs/workbench/services/themes/common/colorThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/colorThemeSchema.ts @@ -121,8 +121,12 @@ export const tokenColorizationSettingSchema: IJSONSchema = { foreground: { type: 'string', description: nls.localize('schema.token.foreground', 'Foreground color for the token.'), - format: 'color', - defaultSnippets: [{ body: '${1:#FF0000}' }] + format: 'color-hex', + default: '#ff0000' + }, + background: { + type: 'string', + deprecationMessage: nls.localize('schema.token.background.warning', 'Token background colors are currently not supported.') }, fontStyle: { type: 'string', diff --git a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts index 8233a577d9e..b26a44c5ab7 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts +++ b/src/vs/workbench/services/themes/common/fileIconThemeSchema.ts @@ -167,6 +167,7 @@ const schema: IJSONSchema = { }, fontColor: { type: 'string', + format: 'color-hex', description: nls.localize('schema.fontColor', 'When using a glyph font: The color to use.') }, fontSize: { @@ -208,6 +209,10 @@ const schema: IJSONSchema = { highContrast: { $ref: '#/definitions/associations', description: nls.localize('schema.highContrast', 'Optional associations for file icons in high contrast color themes.') + }, + hidesExplorerArrows: { + type: 'boolean', + description: nls.localize('schema.hidesExplorerArrows', 'Configures whether the file explorer\'s arrows should be hidden when this theme is active.') } } }; diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index f943d4229c4..f8f97e35a74 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -7,9 +7,9 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TPromise } from 'vs/base/common/winjs.base'; import Event from 'vs/base/common/event'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { Color } from 'vs/base/common/color'; import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; export const IWorkbenchThemeService = createDecorator('themeService'); @@ -20,7 +20,6 @@ export const VS_HC_THEME = 'hc-black'; export const COLOR_THEME_SETTING = 'workbench.colorTheme'; export const ICON_THEME_SETTING = 'workbench.iconTheme'; export const CUSTOM_WORKBENCH_COLORS_SETTING = 'workbench.colorCustomizations'; -export const DEPRECATED_CUSTOM_COLORS_SETTING = 'workbench.experimental.colorCustomizations'; export const CUSTOM_EDITOR_COLORS_SETTING = 'editor.tokenColorCustomizations'; export const CUSTOM_EDITOR_SCOPE_COLORS_SETTING = 'textMateRules'; @@ -48,6 +47,7 @@ export interface IFileIconTheme { readonly isLoaded: boolean; readonly hasFileIcons?: boolean; readonly hasFolderIcons?: boolean; + readonly hidesExplorerArrows?: boolean; } export interface IWorkbenchThemeService extends IThemeService { diff --git a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts index ebdb67e5e07..528d7fa234c 100644 --- a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts +++ b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts @@ -2,6 +2,7 @@ * 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 Paths = require('vs/base/common/paths'); import Json = require('vs/base/common/json'); @@ -36,25 +37,27 @@ const tokenGroupToScopesMap = { export class ColorThemeData implements IColorTheme { - constructor() { + private constructor() { } id: string; label: string; settingsId: string; description?: string; + isLoaded: boolean; + path?: string; + extensionData: ExtensionData; + get tokenColors(): ITokenColorizationRule[] { // Add the custom colors after the theme colors // so that they will override them return this.themeTokenColors.concat(this.customTokenColors); } - themeTokenColors: ITokenColorizationRule[] = []; - customTokenColors: ITokenColorizationRule[] = []; - isLoaded: boolean; - path?: string; - extensionData: ExtensionData; - colorMap: IColorMap = {}; - customColorMap: IColorMap = {}; + + private themeTokenColors: ITokenColorizationRule[] = []; + private customTokenColors: ITokenColorizationRule[] = []; + private colorMap: IColorMap = {}; + private customColorMap: IColorMap = {}; public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color { let color = this.customColorMap[colorId]; @@ -119,18 +122,36 @@ export class ColorThemeData implements IColorTheme { public ensureLoaded(themeService: WorkbenchThemeService): TPromise { if (!this.isLoaded) { - this.themeTokenColors = []; - this.colorMap = {}; if (this.path) { return _loadColorThemeFromFile(this.path, this.themeTokenColors, this.colorMap).then(_ => { this.isLoaded = true; - _sanitizeTokenColors(this); + this.sanitizeTokenColors(); }); } } return TPromise.as(null); } + /** + * Place the default settings first and add add the token-info rules + */ + private sanitizeTokenColors() { + let hasDefaultTokens = false; + let updatedTokenColors: ITokenColorizationRule[] = [updateDefaultRuleSettings({ settings: {} }, this)]; + this.tokenColors.forEach(rule => { + if (rule.scope) { + if (rule.scope === 'token.info-token') { + hasDefaultTokens = true; + } + updatedTokenColors.push(rule); + } + }); + if (!hasDefaultTokens) { + updatedTokenColors.push(...defaultThemeColors[this.type]); + } + this.themeTokenColors = updatedTokenColors; + } + toThemeFile() { if (!this.isLoaded) { return ''; @@ -171,56 +192,60 @@ export class ColorThemeData implements IColorTheme { default: return 'dark'; } } -} -export function createUnloadedTheme(id: string): ColorThemeData { - let themeData = new ColorThemeData(); - themeData.id = id; - themeData.label = ''; - themeData.settingsId = null; - themeData.isLoaded = false; - themeData.themeTokenColors = [{ settings: {} }]; - return themeData; -} + // constructors -export function fromStorageData(input: string): ColorThemeData { - try { - let data = JSON.parse(input); - let theme = new ColorThemeData(); - for (let key in data) { - switch (key) { - case 'colorMap': - let colorMapData = data[key]; - for (let id in colorMapData) { - theme.colorMap[id] = Color.fromHex(colorMapData[id]); - } - break; - case 'themeTokenColors': - case 'id': case 'label': case 'settingsId': case 'extensionData': - theme[key] = data[key]; - break; + static createUnloadedTheme(id: string): ColorThemeData { + let themeData = new ColorThemeData(); + themeData.id = id; + themeData.label = ''; + themeData.settingsId = null; + themeData.isLoaded = false; + themeData.themeTokenColors = [{ settings: {} }]; + return themeData; + } + + static fromStorageData(input: string): ColorThemeData { + try { + let data = JSON.parse(input); + let theme = new ColorThemeData(); + for (let key in data) { + switch (key) { + case 'colorMap': + let colorMapData = data[key]; + for (let id in colorMapData) { + theme.colorMap[id] = Color.fromHex(colorMapData[id]); + } + break; + case 'themeTokenColors': + case 'id': case 'label': case 'settingsId': case 'extensionData': + theme[key] = data[key]; + break; + } } + return theme; + } catch (e) { + return null; } - return theme; - } catch (e) { - return null; + } + + static fromExtensionTheme(theme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): ColorThemeData { + let baseTheme: string = theme['uiTheme'] || 'vs-dark'; + + let themeSelector = toCSSSelector(extensionData.extensionId + '-' + Paths.normalize(theme.path)); + let themeData = new ColorThemeData(); + themeData.id = `${baseTheme} ${themeSelector}`; + themeData.label = theme.label || Paths.basename(theme.path); + themeData.settingsId = theme.id || themeData.label; + themeData.description = theme.description; + themeData.path = normalizedAbsolutePath; + themeData.extensionData = extensionData; + themeData.isLoaded = false; + return themeData; } } -export function fromExtensionTheme(theme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): ColorThemeData { - let baseTheme: string = theme['uiTheme'] || 'vs-dark'; - let themeSelector = toCSSSelector(extensionData.extensionId + '-' + Paths.normalize(theme.path)); - let themeData = new ColorThemeData(); - themeData.id = `${baseTheme} ${themeSelector}`; - themeData.label = theme.label || Paths.basename(theme.path); - themeData.settingsId = theme.id || themeData.label; - themeData.description = theme.description; - themeData.path = normalizedAbsolutePath; - themeData.extensionData = extensionData; - themeData.isLoaded = false; - return themeData; -} function toCSSSelector(str: string) { str = str.replace(/[^_\-a-zA-Z0-9]/g, '-'); @@ -296,25 +321,7 @@ function _loadSyntaxTokensFromFile(themePath: string, resultRules: ITokenColoriz return TPromise.wrapError(new Error(nls.localize('error.cannotload', "Problems loading tmTheme file {0}: {1}", themePath, error.message))); }); } -/** - * Place the default settings first and add add the token-info rules - */ -function _sanitizeTokenColors(theme: ColorThemeData) { - let hasDefaultTokens = false; - let updatedTokenColors: ITokenColorizationRule[] = [updateDefaultRuleSettings({ settings: {} }, theme)]; - theme.tokenColors.forEach(rule => { - if (rule.scope) { - if (rule.scope === 'token.info-token') { - hasDefaultTokens = true; - } - updatedTokenColors.push(rule); - } - }); - if (!hasDefaultTokens) { - updatedTokenColors.push(...defaultThemeColors[theme.type]); - } - theme.themeTokenColors = updatedTokenColors; -} + function updateDefaultRuleSettings(defaultRule: ITokenColorizationRule, theme: ColorThemeData): ITokenColorizationRule { let foreground = theme.getColor(editorForeground) || theme.getDefault(editorForeground); @@ -324,7 +331,6 @@ function updateDefaultRuleSettings(defaultRule: ITokenColorizationRule, theme: C return defaultRule; } - let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { 'light': [ { scope: 'token.info-token', settings: { foreground: '#316bcd' } }, diff --git a/src/vs/workbench/services/themes/electron-browser/colorThemeStore.ts b/src/vs/workbench/services/themes/electron-browser/colorThemeStore.ts new file mode 100644 index 00000000000..34751542947 --- /dev/null +++ b/src/vs/workbench/services/themes/electron-browser/colorThemeStore.ts @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------------------------- + * 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 nls = require('vs/nls'); + +import * as types from 'vs/base/common/types'; +import * as Paths from 'path'; +import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; +import { IColorTheme, ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ColorThemeData } from 'vs/workbench/services/themes/electron-browser/colorThemeData'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; + + +let themesExtPoint = ExtensionsRegistry.registerExtensionPoint('themes', [], { + description: nls.localize('vscode.extension.contributes.themes', 'Contributes textmate color themes.'), + type: 'array', + items: { + type: 'object', + defaultSnippets: [{ body: { label: '${1:label}', id: '${2:id}', uiTheme: VS_DARK_THEME, path: './themes/${3:id}.tmTheme.' } }], + properties: { + id: { + description: nls.localize('vscode.extension.contributes.themes.id', 'Id of the icon theme as used in the user settings.'), + type: 'string' + }, + label: { + description: nls.localize('vscode.extension.contributes.themes.label', 'Label of the color theme as shown in the UI.'), + type: 'string' + }, + uiTheme: { + description: nls.localize('vscode.extension.contributes.themes.uiTheme', 'Base theme defining the colors around the editor: \'vs\' is the light color theme, \'vs-dark\' is the dark color theme. \'hc-black\' is the dark high contrast theme.'), + enum: [VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME] + }, + path: { + description: nls.localize('vscode.extension.contributes.themes.path', 'Path of the tmTheme file. The path is relative to the extension folder and is typically \'./themes/themeFile.tmTheme\'.'), + type: 'string' + } + }, + required: ['path', 'uiTheme'] + } +}); + +export class ColorThemeStore { + + private extensionsColorThemes: ColorThemeData[]; + private onDidChangeEmitter: Emitter; + + public get onDidChange(): Event { return this.onDidChangeEmitter.event; } + + constructor( @IExtensionService private extensionService: IExtensionService) { + this.extensionsColorThemes = []; + this.onDidChangeEmitter = new Emitter(); + this.initialize(); + } + + + private initialize() { + themesExtPoint.setHandler((extensions) => { + for (let ext of extensions) { + let extensionData = { + extensionId: ext.description.id, + extensionPublisher: ext.description.publisher, + extensionName: ext.description.name, + extensionIsBuiltin: ext.description.isBuiltin + }; + this.onThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); + } + this.onDidChangeEmitter.fire(this.extensionsColorThemes); + }); + } + + private onThemes(extensionFolderPath: string, extensionData: ExtensionData, themes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { + if (!Array.isArray(themes)) { + collector.error(nls.localize( + 'reqarray', + "Extension point `{0}` must be an array.", + themesExtPoint.name + )); + return; + } + themes.forEach(theme => { + if (!theme.path || !types.isString(theme.path)) { + collector.error(nls.localize( + 'reqpath', + "Expected string in `contributes.{0}.path`. Provided value: {1}", + themesExtPoint.name, + String(theme.path) + )); + return; + } + let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, theme.path)); + + if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { + collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", themesExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); + } + let themeData = ColorThemeData.fromExtensionTheme(theme, normalizedAbsolutePath, extensionData); + this.extensionsColorThemes.push(themeData); + }); + } + + public findThemeData(themeId: string, defaultId?: string): TPromise { + return this.getColorThemes().then(allThemes => { + let defaultTheme: ColorThemeData = void 0; + for (let t of allThemes) { + if (t.id === themeId) { + return t; + } + if (t.id === defaultId) { + defaultTheme = t; + } + } + return defaultTheme; + }); + } + + public findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise { + return this.getColorThemes().then(allThemes => { + let defaultTheme: ColorThemeData = void 0; + for (let t of allThemes) { + if (t.settingsId === settingsId) { + return t; + } + if (t.id === defaultId) { + defaultTheme = t; + } + } + return defaultTheme; + }); + } + + public getColorThemes(): TPromise { + return this.extensionService.onReady().then(isReady => { + return this.extensionsColorThemes; + }); + } + +} diff --git a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts new file mode 100644 index 00000000000..286627526d4 --- /dev/null +++ b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts @@ -0,0 +1,295 @@ +/*--------------------------------------------------------------------------------------------- + * 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 URI from 'vs/base/common/uri'; +import nls = require('vs/nls'); +import * as Paths from 'path'; +import Json = require('vs/base/common/json'); +import { ExtensionData, IThemeExtensionPoint, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { TPromise } from 'vs/base/common/winjs.base'; +import pfs = require('vs/base/node/pfs'); +import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; +import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; + +export class FileIconThemeData implements IFileIconTheme { + id: string; + label: string; + settingsId: string; + description?: string; + hasFileIcons?: boolean; + hasFolderIcons?: boolean; + hidesExplorerArrows?: boolean; + isLoaded: boolean; + path?: string; + extensionData: ExtensionData; + + private styleSheetContent?: string; + + private constructor() { + } + + public ensureLoaded(themeService: WorkbenchThemeService): TPromise { + if (!this.isLoaded) { + if (this.path) { + return _loadIconThemeDocument(this.path).then(iconThemeDocument => { + let result = _processIconThemeDocument(this.id, this.path, iconThemeDocument); + this.styleSheetContent = result.content; + this.hasFileIcons = result.hasFileIcons; + this.hasFolderIcons = result.hasFolderIcons; + this.hidesExplorerArrows = result.hidesExplorerArrows; + this.isLoaded = true; + return this.styleSheetContent; + }); + } + } + return TPromise.as(this.styleSheetContent); + } + + static fromExtensionTheme(iconTheme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): FileIconThemeData { + let themeData = new FileIconThemeData(); + themeData.id = extensionData.extensionId + '-' + iconTheme.id; + themeData.label = iconTheme.label || Paths.basename(iconTheme.path); + themeData.settingsId = iconTheme.id; + themeData.description = iconTheme.description; + themeData.path = normalizedAbsolutePath; + themeData.extensionData = extensionData; + themeData.isLoaded = false; + return themeData; + } + + private static _noIconTheme: FileIconThemeData = null; + + static noIconTheme(): FileIconThemeData { + let themeData = FileIconThemeData._noIconTheme; + if (!themeData) { + themeData = FileIconThemeData._noIconTheme = new FileIconThemeData(); + themeData.id = ''; + themeData.label = ''; + themeData.settingsId = null; + themeData.hasFileIcons = false; + themeData.hasFolderIcons = false; + themeData.hidesExplorerArrows = false; + themeData.isLoaded = true; + themeData.extensionData = null; + } + return themeData; + } +} + +interface IconDefinition { + iconPath: string; + fontColor: string; + fontCharacter: string; + fontSize: string; + fontId: string; +} + +interface FontDefinition { + id: string; + weight: string; + style: string; + size: string; + src: { path: string; format: string; }[]; +} + +interface IconsAssociation { + folder?: string; + file?: string; + folderExpanded?: string; + rootFolder?: string; + rootFolderExpanded?: string; + folderNames?: { [folderName: string]: string; }; + folderNamesExpanded?: { [folderName: string]: string; }; + fileExtensions?: { [extension: string]: string; }; + fileNames?: { [fileName: string]: string; }; + languageIds?: { [languageId: string]: string; }; +} + +interface IconThemeDocument extends IconsAssociation { + iconDefinitions: { [key: string]: IconDefinition }; + fonts: FontDefinition[]; + light?: IconsAssociation; + highContrast?: IconsAssociation; + hidesExplorerArrows?: boolean; +} + +function _loadIconThemeDocument(fileSetPath: string): TPromise { + return pfs.readFile(fileSetPath).then(content => { + let errors: Json.ParseError[] = []; + let contentValue = Json.parse(content.toString(), errors); + if (errors.length > 0) { + return TPromise.wrapError(new Error(nls.localize('error.cannotparseicontheme', "Problems parsing file icons file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', ')))); + } + return TPromise.as(contentValue); + }); +} + +function _processIconThemeDocument(id: string, iconThemeDocumentPath: string, iconThemeDocument: IconThemeDocument): { content: string; hasFileIcons: boolean; hasFolderIcons: boolean; hidesExplorerArrows: boolean; } { + + let result = { content: '', hasFileIcons: false, hasFolderIcons: false, hidesExplorerArrows: iconThemeDocument.hidesExplorerArrows }; + + if (!iconThemeDocument.iconDefinitions) { + return result; + } + let selectorByDefinitionId: { [def: string]: string[] } = {}; + + function resolvePath(path: string) { + const uri = URI.file(Paths.join(Paths.dirname(iconThemeDocumentPath), path)); + return uri.toString(); + } + + function collectSelectors(associations: IconsAssociation, baseThemeClassName?: string) { + function addSelector(selector: string, defId: string) { + if (defId) { + let list = selectorByDefinitionId[defId]; + if (!list) { + list = selectorByDefinitionId[defId] = []; + } + list.push(selector); + } + } + if (associations) { + let qualifier = '.show-file-icons'; + if (baseThemeClassName) { + qualifier = baseThemeClassName + ' ' + qualifier; + } + + let expanded = '.monaco-tree-row.expanded'; // workaround for #11453 + + if (associations.folder) { + addSelector(`${qualifier} .folder-icon::before`, associations.folder); + result.hasFolderIcons = true; + } + + if (associations.folderExpanded) { + addSelector(`${qualifier} ${expanded} .folder-icon::before`, associations.folderExpanded); + result.hasFolderIcons = true; + } + + let rootFolder = associations.rootFolder || associations.folder; + let rootFolderExpanded = associations.rootFolderExpanded || associations.folderExpanded; + + if (rootFolder) { + addSelector(`${qualifier} .rootfolder-icon::before`, rootFolder); + result.hasFolderIcons = true; + } + + if (rootFolderExpanded) { + addSelector(`${qualifier} ${expanded} .rootfolder-icon::before`, rootFolderExpanded); + result.hasFolderIcons = true; + } + + if (associations.file) { + addSelector(`${qualifier} .file-icon::before`, associations.file); + result.hasFileIcons = true; + } + + let folderNames = associations.folderNames; + if (folderNames) { + for (let folderName in folderNames) { + addSelector(`${qualifier} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNames[folderName]); + result.hasFolderIcons = true; + } + } + let folderNamesExpanded = associations.folderNamesExpanded; + if (folderNamesExpanded) { + for (let folderName in folderNamesExpanded) { + addSelector(`${qualifier} ${expanded} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNamesExpanded[folderName]); + result.hasFolderIcons = true; + } + } + + let languageIds = associations.languageIds; + if (languageIds) { + for (let languageId in languageIds) { + addSelector(`${qualifier} .${escapeCSS(languageId)}-lang-file-icon.file-icon::before`, languageIds[languageId]); + result.hasFileIcons = true; + } + } + let fileExtensions = associations.fileExtensions; + if (fileExtensions) { + for (let fileExtension in fileExtensions) { + let selectors: string[] = []; + let segments = fileExtension.toLowerCase().split('.'); + if (segments.length) { + for (let i = 0; i < segments.length; i++) { + selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); + } + selectors.push('.ext-file-icon'); // extra segment to increase file-ext score + } + addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileExtensions[fileExtension]); + result.hasFileIcons = true; + } + } + let fileNames = associations.fileNames; + if (fileNames) { + for (let fileName in fileNames) { + let selectors: string[] = []; + fileName = fileName.toLowerCase(); + selectors.push(`.${escapeCSS(fileName)}-name-file-icon`); + let segments = fileName.split('.'); + if (segments.length) { + for (let i = 1; i < segments.length; i++) { + selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); + } + selectors.push('.ext-file-icon'); // extra segment to increase file-ext score + } + addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileNames[fileName]); + result.hasFileIcons = true; + } + } + } + } + collectSelectors(iconThemeDocument); + collectSelectors(iconThemeDocument.light, '.vs'); + collectSelectors(iconThemeDocument.highContrast, '.hc-black'); + + if (!result.hasFileIcons && !result.hasFolderIcons) { + return result; + } + + let cssRules: string[] = []; + + let fonts = iconThemeDocument.fonts; + if (Array.isArray(fonts)) { + fonts.forEach(font => { + let src = font.src.map(l => `url('${resolvePath(l.path)}') format('${l.format}')`).join(', '); + cssRules.push(`@font-face { src: ${src}; font-family: '${font.id}'; font-weigth: ${font.weight}; font-style: ${font.style}; }`); + }); + cssRules.push(`.show-file-icons .file-icon::before, .show-file-icons .folder-icon::before, .show-file-icons .rootfolder-icon::before { font-family: '${fonts[0].id}'; font-size: ${fonts[0].size || '150%'}}`); + } + + for (let defId in selectorByDefinitionId) { + let selectors = selectorByDefinitionId[defId]; + let definition = iconThemeDocument.iconDefinitions[defId]; + if (definition) { + if (definition.iconPath) { + cssRules.push(`${selectors.join(', ')} { content: ' '; background-image: url("${resolvePath(definition.iconPath)}"); }`); + } + if (definition.fontCharacter || definition.fontColor) { + let body = ''; + if (definition.fontColor) { + body += ` color: ${definition.fontColor};`; + } + if (definition.fontCharacter) { + body += ` content: '${definition.fontCharacter}';`; + } + if (definition.fontSize) { + body += ` font-size: ${definition.fontSize};`; + } + if (definition.fontId) { + body += ` font-family: ${definition.fontId};`; + } + cssRules.push(`${selectors.join(', ')} { ${body} }`); + } + } + } + result.content = cssRules.join('\n'); + return result; +} +function escapeCSS(str: string) { + return window['CSS'].escape(str); +} \ No newline at end of file diff --git a/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.ts b/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.ts new file mode 100644 index 00000000000..a4d110811b9 --- /dev/null +++ b/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.ts @@ -0,0 +1,137 @@ +/*--------------------------------------------------------------------------------------------- + * 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 nls = require('vs/nls'); + +import * as types from 'vs/base/common/types'; +import * as Paths from 'path'; +import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; +import { ExtensionData, IThemeExtensionPoint } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; +import { FileIconThemeData } from 'vs/workbench/services/themes/electron-browser/fileIconThemeData'; + +let iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint('iconThemes', [], { + description: nls.localize('vscode.extension.contributes.iconThemes', 'Contributes file icon themes.'), + type: 'array', + items: { + type: 'object', + defaultSnippets: [{ body: { id: '${1:id}', label: '${2:label}', path: './fileicons/${3:id}-icon-theme.json' } }], + properties: { + id: { + description: nls.localize('vscode.extension.contributes.iconThemes.id', 'Id of the icon theme as used in the user settings.'), + type: 'string' + }, + label: { + description: nls.localize('vscode.extension.contributes.iconThemes.label', 'Label of the icon theme as shown in the UI.'), + type: 'string' + }, + path: { + description: nls.localize('vscode.extension.contributes.iconThemes.path', 'Path of the icon theme definition file. The path is relative to the extension folder and is typically \'./icons/awesome-icon-theme.json\'.'), + type: 'string' + } + }, + required: ['path', 'id'] + } +}); +export class FileIconThemeStore { + + private knownIconThemes: FileIconThemeData[]; + private onDidChangeEmitter: Emitter; + + public get onDidChange(): Event { return this.onDidChangeEmitter.event; } + + constructor( @IExtensionService private extensionService: IExtensionService) { + this.knownIconThemes = []; + this.onDidChangeEmitter = new Emitter(); + this.initialize(); + } + + private initialize() { + iconThemeExtPoint.setHandler((extensions) => { + for (let ext of extensions) { + let extensionData = { + extensionId: ext.description.id, + extensionPublisher: ext.description.publisher, + extensionName: ext.description.name, + extensionIsBuiltin: ext.description.isBuiltin + }; + this.onIconThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); + } + this.onDidChangeEmitter.fire(this.knownIconThemes); + }); + } + + private onIconThemes(extensionFolderPath: string, extensionData: ExtensionData, iconThemes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { + if (!Array.isArray(iconThemes)) { + collector.error(nls.localize( + 'reqarray', + "Extension point `{0}` must be an array.", + iconThemeExtPoint.name + )); + return; + } + iconThemes.forEach(iconTheme => { + if (!iconTheme.path || !types.isString(iconTheme.path)) { + collector.error(nls.localize( + 'reqpath', + "Expected string in `contributes.{0}.path`. Provided value: {1}", + iconThemeExtPoint.name, + String(iconTheme.path) + )); + return; + } + if (!iconTheme.id || !types.isString(iconTheme.id)) { + collector.error(nls.localize( + 'reqid', + "Expected string in `contributes.{0}.id`. Provided value: {1}", + iconThemeExtPoint.name, + String(iconTheme.path) + )); + return; + } + let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, iconTheme.path)); + + if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { + collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", iconThemeExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); + } + + let themeData = FileIconThemeData.fromExtensionTheme(iconTheme, normalizedAbsolutePath, extensionData); + this.knownIconThemes.push(themeData); + }); + + } + + public findThemeData(iconTheme: string): TPromise { + return this.getFileIconThemes().then(allIconSets => { + for (let iconSet of allIconSets) { + if (iconSet.id === iconTheme) { + return iconSet; + } + } + return null; + }); + } + + public findThemeBySettingsId(settingsId: string): TPromise { + return this.getFileIconThemes().then(allIconSets => { + for (let iconSet of allIconSets) { + if (iconSet.settingsId === settingsId) { + return iconSet; + } + } + return null; + }); + } + + public getFileIconThemes(): TPromise { + return this.extensionService.onReady().then(isReady => { + return this.knownIconThemes; + }); + } + +} diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 41aae76275d..0adedb4a6a7 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -5,28 +5,22 @@ 'use strict'; import { TPromise, Promise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; import nls = require('vs/nls'); -import * as Paths from 'path'; -import Json = require('vs/base/common/json'); import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; -import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, DEPRECATED_CUSTOM_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, CUSTOM_EDITOR_SCOPE_COLORS_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, CUSTOM_EDITOR_SCOPE_COLORS_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; import errors = require('vs/base/common/errors'); -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IMessageService } from 'vs/platform/message/common/message'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import Severity from 'vs/base/common/severity'; -import { ColorThemeData, fromStorageData, fromExtensionTheme, createUnloadedTheme } from './colorThemeData'; +import { ColorThemeData } from './colorThemeData'; import { ITheme, Extensions as ThemingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themeService'; import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { Color } from 'vs/base/common/color'; @@ -39,8 +33,10 @@ import pfs = require('vs/base/node/pfs'); import colorThemeSchema = require('vs/workbench/services/themes/common/colorThemeSchema'); import fileIconThemeSchema = require('vs/workbench/services/themes/common/fileIconThemeSchema'); import { IDisposable } from 'vs/base/common/lifecycle'; -import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import { IBroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { ColorThemeStore } from 'vs/workbench/services/themes/electron-browser/colorThemeStore'; +import { FileIconThemeStore } from 'vs/workbench/services/themes/electron-browser/fileIconThemeStore'; +import { FileIconThemeData } from 'vs/workbench/services/themes/electron-browser/fileIconThemeData'; // implementation @@ -55,6 +51,9 @@ const oldDefaultThemeExtensionId = 'vscode-theme-colorful-defaults'; const DEFAULT_ICON_THEME_SETTING_VALUE = 'vs-seti'; const fileIconsEnabledClass = 'file-icons-enabled'; +const colorThemeRulesClassName = 'contributedColorTheme'; +const iconThemeRulesClassName = 'contributedIconTheme'; + const themingRegistry = Registry.as(ThemingExtensions.ThemingContribution); function validateThemeId(theme: string): string { @@ -69,125 +68,14 @@ function validateThemeId(theme: string): string { return theme; } -let themesExtPoint = ExtensionsRegistry.registerExtensionPoint('themes', [], { - description: nls.localize('vscode.extension.contributes.themes', 'Contributes textmate color themes.'), - type: 'array', - items: { - type: 'object', - defaultSnippets: [{ body: { label: '${1:label}', id: '${2:id}', uiTheme: VS_DARK_THEME, path: './themes/${3:id}.tmTheme.' } }], - properties: { - id: { - description: nls.localize('vscode.extension.contributes.themes.id', 'Id of the icon theme as used in the user settings.'), - type: 'string' - }, - label: { - description: nls.localize('vscode.extension.contributes.themes.label', 'Label of the color theme as shown in the UI.'), - type: 'string' - }, - uiTheme: { - description: nls.localize('vscode.extension.contributes.themes.uiTheme', 'Base theme defining the colors around the editor: \'vs\' is the light color theme, \'vs-dark\' is the dark color theme. \'hc-black\' is the dark high contrast theme.'), - enum: [VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME] - }, - path: { - description: nls.localize('vscode.extension.contributes.themes.path', 'Path of the tmTheme file. The path is relative to the extension folder and is typically \'./themes/themeFile.tmTheme\'.'), - type: 'string' - } - }, - required: ['path', 'uiTheme'] - } -}); - -let iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint('iconThemes', [], { - description: nls.localize('vscode.extension.contributes.iconThemes', 'Contributes file icon themes.'), - type: 'array', - items: { - type: 'object', - defaultSnippets: [{ body: { id: '${1:id}', label: '${2:label}', path: './fileicons/${3:id}-icon-theme.json' } }], - properties: { - id: { - description: nls.localize('vscode.extension.contributes.iconThemes.id', 'Id of the icon theme as used in the user settings.'), - type: 'string' - }, - label: { - description: nls.localize('vscode.extension.contributes.iconThemes.label', 'Label of the icon theme as shown in the UI.'), - type: 'string' - }, - path: { - description: nls.localize('vscode.extension.contributes.iconThemes.path', 'Path of the icon theme definition file. The path is relative to the extension folder and is typically \'./icons/awesome-icon-theme.json\'.'), - type: 'string' - } - }, - required: ['path', 'id'] - } -}); - -interface IInternalIconThemeData extends IFileIconTheme { - id: string; - label: string; - settingsId: string; - description?: string; - hasFileIcons?: boolean; - hasFolderIcons?: boolean; - isLoaded: boolean; - path?: string; - styleSheetContent?: string; - extensionData: ExtensionData; -} - -interface IconDefinition { - iconPath: string; - fontColor: string; - fontCharacter: string; - fontSize: string; - fontId: string; -} - -interface FontDefinition { - id: string; - weight: string; - style: string; - size: string; - src: { path: string; format: string; }[]; -} - -interface IconsAssociation { - folder?: string; - file?: string; - folderExpanded?: string; - rootFolder?: string; - rootFolderExpanded?: string; - folderNames?: { [folderName: string]: string; }; - folderNamesExpanded?: { [folderName: string]: string; }; - fileExtensions?: { [extension: string]: string; }; - fileNames?: { [fileName: string]: string; }; - languageIds?: { [languageId: string]: string; }; -} - -interface IconThemeDocument extends IconsAssociation { - iconDefinitions: { [key: string]: IconDefinition }; - fonts: FontDefinition[]; - light?: IconsAssociation; - highContrast?: IconsAssociation; -} - export interface IColorCustomizations { [colorId: string]: string; } -const noFileIconTheme: IFileIconTheme = { - id: '', - label: '', - settingsId: null, - hasFileIcons: false, - hasFolderIcons: false, - isLoaded: true, - extensionData: null -}; - export class WorkbenchThemeService implements IWorkbenchThemeService { _serviceBrand: any; - private extensionsColorThemes: ColorThemeData[]; + private colorThemeStore: ColorThemeStore; private colorCustomizations: IColorCustomizations; private tokenColorCustomizations: ITokenColorCustomizations; private numberOfColorCustomizations: number; @@ -195,7 +83,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { private container: HTMLElement; private onColorThemeChange: Emitter; - private knownIconThemes: IInternalIconThemeData[]; + private iconThemeStore: FileIconThemeStore; private currentIconTheme: IFileIconTheme; private onFileIconThemeChange: Emitter; @@ -204,6 +92,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { constructor( container: HTMLElement, + // @ts-ignore unused injected service @IExtensionService private extensionService: IExtensionService, @IStorageService private storageService: IStorageService, @IBroadcastService private broadcastService: IBroadcastService, @@ -214,11 +103,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { @IInstantiationService private instantiationService: IInstantiationService) { this.container = container; - this.extensionsColorThemes = []; + this.colorThemeStore = new ColorThemeStore(extensionService); this.colorCustomizations = {}; this.tokenColorCustomizations = {}; this.onFileIconThemeChange = new Emitter(); - this.knownIconThemes = []; + this.iconThemeStore = new FileIconThemeStore(extensionService); this.onColorThemeChange = new Emitter(); this.currentIconTheme = { @@ -228,6 +117,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { isLoaded: false, hasFileIcons: false, hasFolderIcons: false, + hidesExplorerArrows: false, extensionData: null }; @@ -239,46 +129,34 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let themeData = null; let persistedThemeData = this.storageService.get(PERSISTED_THEME_STORAGE_KEY); if (persistedThemeData) { - themeData = fromStorageData(persistedThemeData); + themeData = ColorThemeData.fromStorageData(persistedThemeData); } if (!themeData) { let isLightTheme = (Array.prototype.indexOf.call(document.body.classList, 'vs') >= 0); - themeData = createUnloadedTheme(isLightTheme ? VS_LIGHT_THEME : VS_DARK_THEME); + themeData = ColorThemeData.createUnloadedTheme(isLightTheme ? VS_LIGHT_THEME : VS_DARK_THEME); } themeData.setCustomColors(this.colorCustomizations); themeData.setCustomTokenColors(this.tokenColorCustomizations); this.updateDynamicCSSRules(themeData); this.applyTheme(themeData, null, true); - themesExtPoint.setHandler((extensions) => { - for (let ext of extensions) { - let extensionData = { - extensionId: ext.description.id, - extensionPublisher: ext.description.publisher, - extensionName: ext.description.name, - extensionIsBuiltin: ext.description.isBuiltin - }; - this.onThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); - } - }); - - iconThemeExtPoint.setHandler((extensions) => { - for (let ext of extensions) { - let extensionData = { - extensionId: ext.description.id, - extensionPublisher: ext.description.publisher, - extensionName: ext.description.name, - extensionIsBuiltin: ext.description.isBuiltin - }; - this.onIconThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); - } - }); - this.migrate().then(_ => { this.initialize().then(null, errors.onUnexpectedError).then(_ => { this.installConfigurationListener(); }); }); + + // update settings schema setting + this.colorThemeStore.onDidChange(themes => { + colorThemeSettingSchema.enum = themes.map(t => t.settingsId); + colorThemeSettingSchema.enumDescriptions = themes.map(t => themeData.description || ''); + configurationRegistry.notifyConfigurationSchemaUpdated(themeSettingsConfiguration); + }); + this.iconThemeStore.onDidChange(themes => { + iconThemeSettingSchema.enum = [null, ...themes.map(t => t.settingsId)]; + iconThemeSettingSchema.enumDescriptions = [iconThemeSettingSchema.enumDescriptions[0], ...themes.map(t => themeData.description || '')]; + configurationRegistry.notifyConfigurationSchemaUpdated(themeSettingsConfiguration); + }); } public get onDidColorThemeChange(): Event { @@ -301,7 +179,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { }, err => { if (err && err.code === 'ENOENT') { return TPromise.as(null); // ignore, user config file doesn't exist yet - }; + } return TPromise.wrapError(err); }); } @@ -316,7 +194,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let promise = TPromise.as(null); if (!types.isUndefined(legacyColorThemeId)) { this.storageService.remove('workbench.theme', StorageScope.GLOBAL); - promise = this.findThemeData(legacyColorThemeId, DEFAULT_THEME_ID).then(theme => { + promise = this.colorThemeStore.findThemeData(legacyColorThemeId, DEFAULT_THEME_ID).then(theme => { let value = theme ? theme.settingsId : DEFAULT_THEME_SETTING_VALUE; return this.configurationWriter.writeConfiguration(COLOR_THEME_SETTING, value, ConfigurationTarget.USER).then(null, error => null); }); @@ -324,7 +202,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (!types.isUndefined(legacyIconThemeId)) { this.storageService.remove('workbench.iconTheme', StorageScope.GLOBAL); promise = promise.then(_ => { - return this._findIconThemeData(legacyIconThemeId).then(theme => { + return this.iconThemeStore.findThemeData(legacyIconThemeId).then(theme => { let value = theme ? theme.settingsId : null; return this.configurationWriter.writeConfiguration(ICON_THEME_SETTING, value, ConfigurationTarget.USER).then(null, error => null); }); @@ -344,33 +222,33 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.updateColorCustomizations(false); - let colorThemeSetting = this.configurationService.lookup(COLOR_THEME_SETTING).value; - let iconThemeSetting = this.configurationService.lookup(ICON_THEME_SETTING).value || ''; + let colorThemeSetting = this.configurationService.getValue(COLOR_THEME_SETTING); + let iconThemeSetting = this.configurationService.getValue(ICON_THEME_SETTING) || ''; return Promise.join([ - this.findThemeDataBySettingsId(colorThemeSetting, DEFAULT_THEME_ID).then(theme => { + this.colorThemeStore.findThemeDataBySettingsId(colorThemeSetting, DEFAULT_THEME_ID).then(theme => { return this.setColorTheme(theme && theme.id, null); }), - this.findIconThemeBySettingsId(iconThemeSetting).then(theme => { + this.iconThemeStore.findThemeBySettingsId(iconThemeSetting).then(theme => { return this.setFileIconTheme(theme && theme.id, null); }), ]); } private installConfigurationListener() { - this.configurationService.onDidUpdateConfiguration(e => { - let colorThemeSetting = this.configurationService.lookup(COLOR_THEME_SETTING).value; + this.configurationService.onDidChangeConfiguration(e => { + let colorThemeSetting = this.configurationService.getValue(COLOR_THEME_SETTING); if (colorThemeSetting !== this.currentColorTheme.settingsId) { - this.findThemeDataBySettingsId(colorThemeSetting, null).then(theme => { + this.colorThemeStore.findThemeDataBySettingsId(colorThemeSetting, null).then(theme => { if (theme) { this.setColorTheme(theme.id, null); } }); } - let iconThemeSetting = this.configurationService.lookup(ICON_THEME_SETTING).value || ''; + let iconThemeSetting = this.configurationService.getValue(ICON_THEME_SETTING) || ''; if (iconThemeSetting !== this.currentIconTheme.settingsId) { - this.findIconThemeBySettingsId(iconThemeSetting).then(theme => { + this.iconThemeStore.findThemeBySettingsId(iconThemeSetting).then(theme => { this.setFileIconTheme(theme && theme.id, null); }); } @@ -379,6 +257,14 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { }); } + public getColorTheme(): IColorTheme { + return this.currentColorTheme; + } + + public getColorThemes(): TPromise { + return this.colorThemeStore.getColorThemes(); + } + public getTheme(): ITheme { return this.getColorTheme(); } @@ -393,8 +279,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { themeId = validateThemeId(themeId); // migrate theme ids - - return this.findThemeData(themeId, DEFAULT_THEME_ID).then(themeData => { + return this.colorThemeStore.findThemeData(themeId, DEFAULT_THEME_ID).then(themeData => { if (themeData) { return themeData.ensureLoaded(this).then(_ => { if (themeId === this.currentColorTheme.id && !this.currentColorTheme.isLoaded && this.currentColorTheme.hasEqualData(themeData)) { @@ -462,7 +347,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.storageService.store(PERSISTED_THEME_STORAGE_KEY, newTheme.toStorageData()); return this.writeColorThemeConfiguration(settingsTarget); - }; + } private writeColorThemeConfiguration(settingsTarget: ConfigurationTarget): TPromise { if (!types.isUndefinedOrNull(settingsTarget)) { @@ -471,46 +356,6 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return TPromise.as(this.currentColorTheme); } - public getColorTheme(): IColorTheme { - return this.currentColorTheme; - } - - private findThemeData(themeId: string, defaultId?: string): TPromise { - return this.getColorThemes().then(allThemes => { - let defaultTheme: ColorThemeData = void 0; - for (let t of allThemes) { - if (t.id === themeId) { - return t; - } - if (t.id === defaultId) { - defaultTheme = t; - } - } - return defaultTheme; - }); - } - - public findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise { - return this.getColorThemes().then(allThemes => { - let defaultTheme: ColorThemeData = void 0; - for (let t of allThemes) { - if (t.settingsId === settingsId) { - return t; - } - if (t.id === defaultId) { - defaultTheme = t; - } - } - return defaultTheme; - }); - } - - public getColorThemes(): TPromise { - return this.extensionService.onReady().then(isReady => { - return this.extensionsColorThemes; - }); - } - private hasCustomizationChanged(newColorCustomizations: IColorCustomizations, newColorIds: string[], newTokenColorCustomizations: ITokenColorCustomizations): boolean { if (newColorIds.length !== this.numberOfColorCustomizations) { return true; @@ -530,14 +375,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } private updateColorCustomizations(notify = true): void { - let newColorCustomizations = this.configurationService.lookup(CUSTOM_WORKBENCH_COLORS_SETTING).value || {}; + let newColorCustomizations = this.configurationService.getValue(CUSTOM_WORKBENCH_COLORS_SETTING) || {}; let newColorIds = Object.keys(newColorCustomizations); - if (newColorIds.length === 0) { - newColorCustomizations = this.configurationService.lookup(DEPRECATED_CUSTOM_COLORS_SETTING).value || {}; - newColorIds = Object.keys(newColorCustomizations); - } - let newTokenColorCustomizations = this.configurationService.lookup(CUSTOM_EDITOR_COLORS_SETTING).value || {}; + let newTokenColorCustomizations = this.configurationService.getValue(CUSTOM_EDITOR_COLORS_SETTING) || {}; if (this.hasCustomizationChanged(newColorCustomizations, newColorIds, newTokenColorCustomizations)) { this.colorCustomizations = newColorCustomizations; @@ -555,93 +396,20 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } } - private onThemes(extensionFolderPath: string, extensionData: ExtensionData, themes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { - if (!Array.isArray(themes)) { - collector.error(nls.localize( - 'reqarray', - "Extension point `{0}` must be an array.", - themesExtPoint.name - )); - return; - } - themes.forEach(theme => { - if (!theme.path || !types.isString(theme.path)) { - collector.error(nls.localize( - 'reqpath', - "Expected string in `contributes.{0}.path`. Provided value: {1}", - themesExtPoint.name, - String(theme.path) - )); - return; - } - let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, theme.path)); - - if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { - collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", themesExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); - } - let themeData = fromExtensionTheme(theme, normalizedAbsolutePath, extensionData); - this.extensionsColorThemes.push(themeData); - - colorThemeSettingSchema.enum.push(themeData.settingsId); - colorThemeSettingSchema.enumDescriptions.push(themeData.description || ''); - }); - } - - private onIconThemes(extensionFolderPath: string, extensionData: ExtensionData, iconThemes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { - if (!Array.isArray(iconThemes)) { - collector.error(nls.localize( - 'reqarray', - "Extension point `{0}` must be an array.", - themesExtPoint.name - )); - return; - } - iconThemes.forEach(iconTheme => { - if (!iconTheme.path || !types.isString(iconTheme.path)) { - collector.error(nls.localize( - 'reqpath', - "Expected string in `contributes.{0}.path`. Provided value: {1}", - themesExtPoint.name, - String(iconTheme.path) - )); - return; - } - if (!iconTheme.id || !types.isString(iconTheme.id)) { - collector.error(nls.localize( - 'reqid', - "Expected string in `contributes.{0}.id`. Provided value: {1}", - themesExtPoint.name, - String(iconTheme.path) - )); - return; - } - let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, iconTheme.path)); - - if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { - collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", themesExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); - } - - let themeData = { - id: extensionData.extensionId + '-' + iconTheme.id, - label: iconTheme.label || Paths.basename(iconTheme.path), - settingsId: iconTheme.id, - description: iconTheme.description, - path: normalizedAbsolutePath, - extensionData: extensionData, - isLoaded: false - }; - this.knownIconThemes.push(themeData); - - iconThemeSettingSchema.enum.push(themeData.settingsId); - iconThemeSettingSchema.enumDescriptions.push(themeData.description || ''); - }); - } - private themeExtensionsActivated = new Map(); private sendTelemetry(themeId: string, themeData: ExtensionData, themeType: string) { if (themeData) { let key = themeType + themeData.extensionId; if (!this.themeExtensionsActivated.get(key)) { + /* __GDPR__ + "activatePlugin" : { + "id" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "name": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "isBuiltin": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "publisherDisplayName": { "classification": "PublicPersonalData", "purpose": "FeatureInsight" }, + "themeId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ this.telemetryService.publicLog('activatePlugin', { id: themeData.extensionId, name: themeData.extensionName, @@ -655,9 +423,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } public getFileIconThemes(): TPromise { - return this.extensionService.onReady().then(isReady => { - return this.knownIconThemes; - }); + return this.iconThemeStore.getFileIconThemes(); } public getFileIconTheme() { @@ -669,11 +435,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (iconTheme === this.currentIconTheme.id && this.currentIconTheme.isLoaded) { return this.writeFileIconConfiguration(settingsTarget); } - let onApply = (newIconTheme: IInternalIconThemeData) => { + let onApply = (newIconTheme: FileIconThemeData) => { if (newIconTheme) { this.currentIconTheme = newIconTheme; } else { - this.currentIconTheme = noFileIconTheme; + this.currentIconTheme = FileIconThemeData.noIconTheme(); } if (this.container) { @@ -690,7 +456,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return this.writeFileIconConfiguration(settingsTarget); }; - return this._findIconThemeData(iconTheme).then(iconThemeData => { + return this.iconThemeStore.findThemeData(iconTheme).then(iconThemeData => { return _applyIconTheme(iconThemeData, onApply); }); } @@ -709,229 +475,21 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } return this._configurationWriter; } - - private _findIconThemeData(iconTheme: string): TPromise { - return this.getFileIconThemes().then(allIconSets => { - for (let iconSet of allIconSets) { - if (iconSet.id === iconTheme) { - return iconSet; - } - } - return null; - }); - } - - private findIconThemeBySettingsId(settingsId: string): TPromise { - return this.getFileIconThemes().then(allIconSets => { - for (let iconSet of allIconSets) { - if (iconSet.settingsId === settingsId) { - return iconSet; - } - } - return null; - }); - } } -function _applyIconTheme(data: IInternalIconThemeData, onApply: (theme: IInternalIconThemeData) => TPromise): TPromise { +function _applyIconTheme(this: any, data: FileIconThemeData, onApply: (theme: FileIconThemeData) => TPromise): TPromise { if (!data) { _applyRules('', iconThemeRulesClassName); return TPromise.as(onApply(data)); } - - if (data.styleSheetContent) { - _applyRules(data.styleSheetContent, iconThemeRulesClassName); - return TPromise.as(onApply(data)); - } - return _loadIconThemeDocument(data.path).then(iconThemeDocument => { - let result = _processIconThemeDocument(data.id, data.path, iconThemeDocument); - data.styleSheetContent = result.content; - data.hasFileIcons = result.hasFileIcons; - data.hasFolderIcons = result.hasFolderIcons; - data.isLoaded = true; - _applyRules(data.styleSheetContent, iconThemeRulesClassName); + return data.ensureLoaded(this).then(styleSheetContent => { + _applyRules(styleSheetContent, iconThemeRulesClassName); return onApply(data); }, error => { return TPromise.wrapError(new Error(nls.localize('error.cannotloadicontheme', "Unable to load {0}", data.path))); }); } -function _loadIconThemeDocument(fileSetPath: string): TPromise { - return pfs.readFile(fileSetPath).then(content => { - let errors: Json.ParseError[] = []; - let contentValue = Json.parse(content.toString(), errors); - if (errors.length > 0) { - return TPromise.wrapError(new Error(nls.localize('error.cannotparseicontheme', "Problems parsing file icons file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', ')))); - } - return TPromise.as(contentValue); - }); -} - -function _processIconThemeDocument(id: string, iconThemeDocumentPath: string, iconThemeDocument: IconThemeDocument): { content: string; hasFileIcons: boolean; hasFolderIcons: boolean; } { - - let result = { content: '', hasFileIcons: false, hasFolderIcons: false }; - - if (!iconThemeDocument.iconDefinitions) { - return result; - } - let selectorByDefinitionId: { [def: string]: string[] } = {}; - - function resolvePath(path: string) { - const uri = URI.file(Paths.join(Paths.dirname(iconThemeDocumentPath), path)); - return uri.toString(); - } - - function collectSelectors(associations: IconsAssociation, baseThemeClassName?: string) { - function addSelector(selector: string, defId: string) { - if (defId) { - let list = selectorByDefinitionId[defId]; - if (!list) { - list = selectorByDefinitionId[defId] = []; - } - list.push(selector); - } - } - if (associations) { - let qualifier = '.show-file-icons'; - if (baseThemeClassName) { - qualifier = baseThemeClassName + ' ' + qualifier; - } - - let expanded = '.monaco-tree-row.expanded'; // workaround for #11453 - - if (associations.folder) { - addSelector(`${qualifier} .folder-icon::before`, associations.folder); - result.hasFolderIcons = true; - } - - if (associations.folderExpanded) { - addSelector(`${qualifier} ${expanded} .folder-icon::before`, associations.folderExpanded); - result.hasFolderIcons = true; - } - - let rootFolder = associations.rootFolder || associations.folder; - let rootFolderExpanded = associations.rootFolderExpanded || associations.folderExpanded; - - if (rootFolder) { - addSelector(`${qualifier} .rootfolder-icon::before`, rootFolder); - result.hasFolderIcons = true; - } - - if (rootFolderExpanded) { - addSelector(`${qualifier} ${expanded} .rootfolder-icon::before`, rootFolderExpanded); - result.hasFolderIcons = true; - } - - if (associations.file) { - addSelector(`${qualifier} .file-icon::before`, associations.file); - result.hasFileIcons = true; - } - - let folderNames = associations.folderNames; - if (folderNames) { - for (let folderName in folderNames) { - addSelector(`${qualifier} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNames[folderName]); - result.hasFolderIcons = true; - } - } - let folderNamesExpanded = associations.folderNamesExpanded; - if (folderNamesExpanded) { - for (let folderName in folderNamesExpanded) { - addSelector(`${qualifier} ${expanded} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNamesExpanded[folderName]); - result.hasFolderIcons = true; - } - } - - let languageIds = associations.languageIds; - if (languageIds) { - for (let languageId in languageIds) { - addSelector(`${qualifier} .${escapeCSS(languageId)}-lang-file-icon.file-icon::before`, languageIds[languageId]); - result.hasFileIcons = true; - } - } - let fileExtensions = associations.fileExtensions; - if (fileExtensions) { - for (let fileExtension in fileExtensions) { - let selectors: string[] = []; - let segments = fileExtension.toLowerCase().split('.'); - for (let i = 0; i < segments.length; i++) { - selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); - } - addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileExtensions[fileExtension]); - result.hasFileIcons = true; - } - } - let fileNames = associations.fileNames; - if (fileNames) { - for (let fileName in fileNames) { - let selectors: string[] = []; - fileName = fileName.toLowerCase(); - selectors.push(`.${escapeCSS(fileName)}-name-file-icon`); - let segments = fileName.split('.'); - for (let i = 1; i < segments.length; i++) { - selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); - } - addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileNames[fileName]); - result.hasFileIcons = true; - } - } - } - } - collectSelectors(iconThemeDocument); - collectSelectors(iconThemeDocument.light, '.vs'); - collectSelectors(iconThemeDocument.highContrast, '.hc-black'); - - if (!result.hasFileIcons && !result.hasFolderIcons) { - return result; - } - - let cssRules: string[] = []; - - let fonts = iconThemeDocument.fonts; - if (Array.isArray(fonts)) { - fonts.forEach(font => { - let src = font.src.map(l => `url('${resolvePath(l.path)}') format('${l.format}')`).join(', '); - cssRules.push(`@font-face { src: ${src}; font-family: '${font.id}'; font-weigth: ${font.weight}; font-style: ${font.style}; }`); - }); - cssRules.push(`.show-file-icons .file-icon::before, .show-file-icons .folder-icon::before, .show-file-icons .rootfolder-icon::before { font-family: '${fonts[0].id}'; font-size: ${fonts[0].size || '150%'}}`); - } - - for (let defId in selectorByDefinitionId) { - let selectors = selectorByDefinitionId[defId]; - let definition = iconThemeDocument.iconDefinitions[defId]; - if (definition) { - if (definition.iconPath) { - cssRules.push(`${selectors.join(', ')} { content: ' '; background-image: url("${resolvePath(definition.iconPath)}"); }`); - } - if (definition.fontCharacter || definition.fontColor) { - let body = ''; - if (definition.fontColor) { - body += ` color: ${definition.fontColor};`; - } - if (definition.fontCharacter) { - body += ` content: '${definition.fontCharacter}';`; - } - if (definition.fontSize) { - body += ` font-size: ${definition.fontSize};`; - } - if (definition.fontId) { - body += ` font-family: ${definition.fontId};`; - } - cssRules.push(`${selectors.join(', ')} { ${body} }`); - } - } - } - result.content = cssRules.join('\n'); - return result; -} - -function escapeCSS(str: string) { - return window['CSS'].escape(str); -} - -let colorThemeRulesClassName = 'contributedColorTheme'; -let iconThemeRulesClassName = 'contributedIconTheme'; - function _applyRules(styleSheetContent: string, rulesClassName: string) { let themeStyles = document.head.getElementsByClassName(rulesClassName); if (themeStyles.length === 0) { @@ -949,11 +507,11 @@ colorThemeSchema.register(); fileIconThemeSchema.register(); class ConfigurationWriter { - constructor( @IConfigurationService private configurationService: IConfigurationService, @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService) { + constructor( @IConfigurationService private configurationService: IConfigurationService) { } public writeConfiguration(key: string, value: any, settingsTarget: ConfigurationTarget): TPromise { - let settings = this.configurationService.lookup(key); + let settings = this.configurationService.inspect(key); if (settingsTarget === ConfigurationTarget.USER) { if (value === settings.user) { return TPromise.as(null); // nothing to do @@ -968,14 +526,14 @@ class ConfigurationWriter { return TPromise.as(null); // nothing to do } } - return this.configurationEditingService.writeConfiguration(settingsTarget, { key, value }); + return this.configurationService.updateValue(key, value, settingsTarget); } } // Configuration: Themes const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); -const colorThemeSettingSchema: IJSONSchema = { +const colorThemeSettingSchema: IConfigurationPropertySchema = { type: 'string', description: nls.localize('colorTheme', "Specifies the color theme used in the workbench."), default: DEFAULT_THEME_SETTING_VALUE, @@ -983,7 +541,8 @@ const colorThemeSettingSchema: IJSONSchema = { enumDescriptions: [], errorMessage: nls.localize('colorThemeError', "Theme is unknown or not installed."), }; -const iconThemeSettingSchema: IJSONSchema = { + +const iconThemeSettingSchema: IConfigurationPropertySchema = { type: ['string', 'null'], default: DEFAULT_ICON_THEME_SETTING_VALUE, description: nls.localize('iconTheme', "Specifies the icon theme used in the workbench or 'null' to not show any file icons."), @@ -991,10 +550,11 @@ const iconThemeSettingSchema: IJSONSchema = { enumDescriptions: [nls.localize('noIconThemeDesc', 'No file icons')], errorMessage: nls.localize('iconThemeError', "File icon theme is unknown or not installed.") }; -const colorCustomizationsSchema: IJSONSchema = { +const colorCustomizationsSchema: IConfigurationPropertySchema = { type: ['object'], description: nls.localize('workbenchColors', "Overrides colors from the currently selected color theme."), properties: colorThemeSchema.colorsSchema.properties, + additionalProperties: false, default: {}, defaultSnippets: [{ body: { @@ -1005,22 +565,17 @@ const colorCustomizationsSchema: IJSONSchema = { }] }; -const deprecatedColorCustomizationsSchema: IJSONSchema = objects.mixin({ - deprecationMessage: nls.localize('workbenchColors.deprecated', "The setting is no longer experimental and has been renamed to 'workbench.colorCustomizations'"), - description: nls.localize('workbenchColors.deprecatedDescription', "Use 'workbench.colorCustomizations' instead") -}, colorCustomizationsSchema, false); - -configurationRegistry.registerConfiguration({ +const themeSettingsConfiguration: IConfigurationNode = { id: 'workbench', order: 7.1, type: 'object', properties: { [COLOR_THEME_SETTING]: colorThemeSettingSchema, [ICON_THEME_SETTING]: iconThemeSettingSchema, - [CUSTOM_WORKBENCH_COLORS_SETTING]: colorCustomizationsSchema, - [DEPRECATED_CUSTOM_COLORS_SETTING]: deprecatedColorCustomizationsSchema + [CUSTOM_WORKBENCH_COLORS_SETTING]: colorCustomizationsSchema } -}); +}; +configurationRegistry.registerConfiguration(themeSettingsConfiguration); function tokenGroupSettings(description: string) { return { @@ -1029,13 +584,12 @@ function tokenGroupSettings(description: string) { anyOf: [ { type: 'string', - format: 'color', - defaultSnippets: [{ body: '#FF0000' }] + format: 'color-hex' }, colorThemeSchema.tokenColorizationSettingSchema ] }; -}; +} configurationRegistry.registerConfiguration({ id: 'editor', @@ -1045,6 +599,7 @@ configurationRegistry.registerConfiguration({ [CUSTOM_EDITOR_COLORS_SETTING]: { description: nls.localize('editorColors', "Overrides editor colors and font style from the currently selected color theme."), default: {}, + additionalProperties: false, properties: { comments: tokenGroupSettings(nls.localize('editorColors.comments', "Sets the colors and styles for comments")), strings: tokenGroupSettings(nls.localize('editorColors.strings', "Sets the colors and styles for strings literals.")), diff --git a/src/vs/workbench/services/thread/common/threadService.ts b/src/vs/workbench/services/thread/common/threadService.ts index 9c0e152fd52..0fd6a9cd6af 100644 --- a/src/vs/workbench/services/thread/common/threadService.ts +++ b/src/vs/workbench/services/thread/common/threadService.ts @@ -21,6 +21,7 @@ export interface IThreadService { assertRegistered(identifiers: ProxyIdentifier[]): void; } +// @ts-ignore unused generic parameter export class ProxyIdentifier { _proxyIdentifierBrand: void; diff --git a/src/vs/workbench/services/thread/node/abstractThreadService.ts b/src/vs/workbench/services/thread/node/abstractThreadService.ts index e6f11ed4c78..7bc4ba3b38d 100644 --- a/src/vs/workbench/services/thread/node/abstractThreadService.ts +++ b/src/vs/workbench/services/thread/node/abstractThreadService.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDispatcher, RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService'; +import { CharCode } from 'vs/base/common/charCode'; declare var Proxy: any; // TODO@TypeScript @@ -50,8 +51,8 @@ export abstract class AbstractThreadService implements IDispatcher { private _createProxy(proxyId: string): T { let handler = { - get: (target, name) => { - if (!target[name]) { + get: (target, name: string) => { + if (!target[name] && name.charCodeAt(0) === CharCode.DollarSign) { target[name] = (...myArgs: any[]) => { return this._callOnRemote(proxyId, name, myArgs); }; diff --git a/src/vs/workbench/services/timer/common/timerService.ts b/src/vs/workbench/services/timer/common/timerService.ts index a337b25bf27..ef09fe80e4c 100644 --- a/src/vs/workbench/services/timer/common/timerService.ts +++ b/src/vs/workbench/services/timer/common/timerService.ts @@ -8,6 +8,14 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const ITimerService = createDecorator('timerService'); +/* __GDPR__FRAGMENT__ + "IMemoryInfo" : { + "workingSetSize" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "peakWorkingSetSize": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "privateBytes": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "sharedBytes": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } +*/ export interface IMemoryInfo { workingSetSize: number; peakWorkingSetSize: number; @@ -15,6 +23,41 @@ export interface IMemoryInfo { sharedBytes: number; } +/* __GDPR__FRAGMENT__ + "IStartupMetrics" : { + "version" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "ellapsed" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedAppReady" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedWindowLoad" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedWindowLoadToRequire" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedExtensions" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedExtensionsReady" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedRequire" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedViewletRestore" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedEditorRestore" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedWorkbench" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "timers.ellapsedTimersToTimersComputed" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "platform" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "release" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "arch" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "totalmem" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "meminfo" : { "${inline}": [ "${IMemoryInfo}" ] }, + "cpus.count" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "cpus.speed" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "cpus.model" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "initialStartup" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "hasAccessibilitySupport" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "isVMLikelyhood" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "emptyWorkbench" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "loadavg" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "${wildcard}": [ + { + "${prefix}": "timers2.", + "${classification}": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + ] + } +*/ export interface IStartupMetrics { version: number; ellapsed: number; @@ -30,7 +73,6 @@ export interface IStartupMetrics { ellapsedWorkbench: number; ellapsedTimersToTimersComputed: number; }; - timers2: { [name: string]: number }; platform: string; release: string; arch: string; diff --git a/src/vs/workbench/services/timer/node/timerService.ts b/src/vs/workbench/services/timer/node/timerService.ts index df515fb4b84..e140cd95814 100644 --- a/src/vs/workbench/services/timer/node/timerService.ts +++ b/src/vs/workbench/services/timer/node/timerService.ts @@ -6,7 +6,6 @@ import { ITimerService, IStartupMetrics, IInitData, IMemoryInfo } from 'vs/workbench/services/timer/common/timerService'; import { virtualMachineHint } from 'vs/base/node/id'; -import { ticks } from 'vs/base/node/startupTimers'; import * as os from 'os'; @@ -92,12 +91,6 @@ export class TimerService implements ITimerService { console.error(error); // be on the safe side with these hardware method calls } - // fill in startup timers we have until now - const timers2: { [name: string]: number } = Object.create(null); - for (const tick of ticks()) { - timers2[tick.name] = tick.duration; - } - this._startupMetrics = { version: 1, ellapsed: this.workbenchStarted - start, @@ -111,7 +104,6 @@ export class TimerService implements ITimerService { ellapsedWindowLoadToRequire: this.beforeLoadWorkbenchMain - this.windowLoad, ellapsedTimersToTimersComputed: Date.now() - now }, - timers2, platform, release, arch, diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts index 3af0a697b6f..39cc03bd556 100644 --- a/src/vs/workbench/services/viewlet/browser/viewletService.ts +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -25,8 +25,8 @@ export class ViewletService implements IViewletService { private extensionViewletsLoaded: TPromise; private extensionViewletsLoadedPromiseComplete: ValueCallback; - public get onDidViewletOpen(): Event { return this.sidebarPart.onDidViewletOpen; }; - public get onDidViewletClose(): Event { return this.sidebarPart.onDidViewletClose; }; + public get onDidViewletOpen(): Event { return this.sidebarPart.onDidViewletOpen; } + public get onDidViewletClose(): Event { return this.sidebarPart.onDidViewletClose; } constructor( sidebarPart: SidebarPart, diff --git a/src/vs/workbench/services/workspace/common/workspaceEditing.ts b/src/vs/workbench/services/workspace/common/workspaceEditing.ts index f3ed40ee523..3e22bf28ba6 100644 --- a/src/vs/workbench/services/workspace/common/workspaceEditing.ts +++ b/src/vs/workbench/services/workspace/common/workspaceEditing.ts @@ -5,9 +5,9 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import URI from 'vs/base/common/uri'; export const IWorkspaceEditingService = createDecorator('workspaceEditingService'); @@ -16,14 +16,32 @@ export interface IWorkspaceEditingService { _serviceBrand: ServiceIdentifier; /** - * add roots to the existing workspace + * Add folders to the existing workspace. + * When `donotNotifyError` is `true`, error will be bubbled up otherwise, the service handles the error with proper message and action */ - addRoots(roots: URI[]): TPromise; + addFolders(folders: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): TPromise; /** - * remove roots from the existing workspace + * Remove folders from the existing workspace + * When `donotNotifyError` is `true`, error will be bubbled up otherwise, the service handles the error with proper message and action */ - removeRoots(roots: URI[]): TPromise; + removeFolders(folders: URI[], donotNotifyError?: boolean): TPromise; + + /** + * creates a new workspace with the provided folders and opens it. if path is provided + * the workspace will be saved into that location. + */ + createAndEnterWorkspace(folders?: IWorkspaceFolderCreationData[], path?: string): TPromise; + + /** + * saves the workspace to the provided path and opens it. requires a workspace to be opened. + */ + saveAndEnterWorkspace(path: string): TPromise; + + /** + * copies current workspace settings to the target workspace. + */ + copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): TPromise; } export const IWorkspaceMigrationService = createDecorator('workspaceMigrationService'); diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index 33cbf289a08..650625e7483 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -7,94 +7,244 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import URI from 'vs/base/common/uri'; -import { equals, distinct } from 'vs/base/common/arrays'; +import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspacesService, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWindowService, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; +import { IJSONEditingService, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing'; +import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; +import { migrateStorageToMultiRootWorkspace } from 'vs/platform/storage/common/migration'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { StorageService } from 'vs/platform/storage/common/storageService'; +import { ConfigurationScope, IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { IChoiceService, Severity, IMessageService } from 'vs/platform/message/common/message'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { distinct } from 'vs/base/common/arrays'; import { isLinux } from 'vs/base/common/platform'; -import { dirname, relative } from 'path'; -import { isEqualOrParent } from 'vs/base/common/paths'; +import { isEqual } from 'vs/base/common/resources'; +import { Action } from 'vs/base/common/actions'; +import product from 'vs/platform/node/product'; export class WorkspaceEditingService implements IWorkspaceEditingService { public _serviceBrand: any; + private static INFO_MESSAGE_KEY = 'enterWorkspace.message'; + constructor( @IJSONEditingService private jsonEditingService: IJSONEditingService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IEnvironmentService private environmentService: IEnvironmentService, - @IWindowsService private windowsService: IWindowsService, - @IWorkspacesService private workspacesService: IWorkspacesService + @IWorkspaceContextService private contextService: WorkspaceService, + @IWindowService private windowService: IWindowService, + @IWorkspaceConfigurationService private workspaceConfigurationService: IWorkspaceConfigurationService, + @IStorageService private storageService: IStorageService, + @IExtensionService private extensionService: IExtensionService, + @IBackupFileService private backupFileService: IBackupFileService, + @IChoiceService private choiceService: IChoiceService, + @IMessageService private messageService: IMessageService, + @ICommandService private commandService: ICommandService ) { } - public addRoots(rootsToAdd: URI[]): TPromise { - if (!this.isSupported()) { - return TPromise.as(void 0); // we need a workspace to begin with + public addFolders(foldersToAdd: IWorkspaceFolderCreationData[], donotNotifyError: boolean = false): TPromise { + const state = this.contextService.getWorkbenchState(); + + // If we are in no-workspace or single-folder workspace, adding folders has to + // enter a workspace. + if (state !== WorkbenchState.WORKSPACE) { + const newWorkspaceFolders: IWorkspaceFolderCreationData[] = distinct([ + ...this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri } as IWorkspaceFolderCreationData)), + ...foldersToAdd + ] as IWorkspaceFolderCreationData[], folder => isLinux ? folder.uri.toString() : folder.uri.toString().toLowerCase()); + + if (state === WorkbenchState.EMPTY && newWorkspaceFolders.length === 0 || state === WorkbenchState.FOLDER && newWorkspaceFolders.length === 1) { + return TPromise.as(void 0); // return if the operation is a no-op for the current state + } + + return this.createAndEnterWorkspace(newWorkspaceFolders); } - const roots = this.contextService.getWorkspace().roots; - - return this.doSetRoots([...roots, ...rootsToAdd]); + // Delegate addition of folders to workspace service otherwise + return this.contextService.addFolders(foldersToAdd) + .then(() => null, error => donotNotifyError ? TPromise.wrapError(error) : this.handleWorkspaceConfigurationEditingError(error)); } - public removeRoots(rootsToRemove: URI[]): TPromise { - if (!this.isSupported()) { - return TPromise.as(void 0); // we need a workspace to begin with + public removeFolders(foldersToRemove: URI[], donotNotifyError: boolean = false): TPromise { + + // If we are in single-folder state and the opened folder is to be removed, + // we close the workspace and enter the empty workspace state for the window. + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + const workspaceFolder = this.contextService.getWorkspace().folders[0]; + if (foldersToRemove.some(folder => isEqual(folder, workspaceFolder.uri, !isLinux))) { + return this.windowService.closeWorkspace(); + } } - const roots = this.contextService.getWorkspace().roots; - const rootsToRemoveRaw = rootsToRemove.map(root => root.toString()); - - return this.doSetRoots(roots.filter(root => rootsToRemoveRaw.indexOf(root.toString()) === -1)); + // Delegate removal of folders to workspace service otherwise + return this.contextService.removeFolders(foldersToRemove) + .then(() => null, error => donotNotifyError ? TPromise.wrapError(error) : this.handleWorkspaceConfigurationEditingError(error)); } - private isSupported(): boolean { - // TODO@Ben multi root - return ( - this.environmentService.appQuality !== 'stable' // not yet enabled in stable - && this.contextService.hasMultiFolderWorkspace() // we need a multi folder workspace to begin with - ); + public createAndEnterWorkspace(folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { + return this.doEnterWorkspace(() => this.windowService.createAndEnterWorkspace(folders, path)); } - private doSetRoots(newRoots: URI[]): TPromise { - const workspace = this.contextService.getWorkspace(); - const currentWorkspaceRoots = this.contextService.getWorkspace().roots.map(root => root.fsPath); - const newWorkspaceRoots = this.validateRoots(newRoots); + public saveAndEnterWorkspace(path: string): TPromise { + return this.doEnterWorkspace(() => this.windowService.saveAndEnterWorkspace(path)); + } - // See if there are any changes - if (equals(currentWorkspaceRoots, newWorkspaceRoots)) { - return TPromise.as(void 0); + private handleWorkspaceConfigurationEditingError(error: JSONEditingError): TPromise { + switch (error.code) { + case JSONEditingErrorCode.ERROR_INVALID_FILE: + return this.onInvalidWorkspaceConfigurationFileError(); + case JSONEditingErrorCode.ERROR_FILE_DIRTY: + return this.onWorkspaceConfigurationFileDirtyError(); } + this.messageService.show(Severity.Error, error.message); + return TPromise.as(void 0); + } - // Apply to config - if (newWorkspaceRoots.length) { - const workspaceConfigFolder = dirname(workspace.configuration.fsPath); - const value: IStoredWorkspaceFolder[] = newWorkspaceRoots.map(newWorkspaceRoot => { - if (isEqualOrParent(newWorkspaceRoot, workspaceConfigFolder, !isLinux)) { - newWorkspaceRoot = relative(workspaceConfigFolder, newWorkspaceRoot) || '.'; // absolute paths get converted to relative ones to workspace location if possible + private onInvalidWorkspaceConfigurationFileError(): TPromise { + const message = nls.localize('errorInvalidTaskConfiguration', "Unable to write into workspace configuration file. Please open the file to correct errors/warnings in it and try again."); + return this.askToOpenWorkspaceConfigurationFile(message); + } + + private onWorkspaceConfigurationFileDirtyError(): TPromise { + const message = nls.localize('errorWorkspaceConfigurationFileDirty', "Unable to write into workspace configuration file because the file is dirty. Please save it and try again."); + return this.askToOpenWorkspaceConfigurationFile(message); + } + + private askToOpenWorkspaceConfigurationFile(message: string): TPromise { + return this.choiceService.choose(Severity.Error, message, [nls.localize('openWorkspaceConfigurationFile', "Open Workspace Configuration File"), nls.localize('close', "Close")], 1) + .then(option => { + switch (option) { + case 0: + this.commandService.executeCommand('workbench.action.openWorkspaceConfigFile'); + break; } - - return { path: newWorkspaceRoot }; }); - - return this.jsonEditingService.write(workspace.configuration, { key: 'folders', value }, true); - } else { - // TODO: Sandeep - Removing all roots? - } - - return TPromise.as(null); } - private validateRoots(roots: URI[]): string[] { - if (!roots) { - return []; + private doEnterWorkspace(mainSidePromise: () => TPromise): TPromise { + + // Stop the extension host first to give extensions most time to shutdown + this.extensionService.stopExtensionHost(); + + const startExtensionHost = () => { + this.extensionService.startExtensionHost(); + }; + + return mainSidePromise().then(result => { + + // Migrate storage and settings if we are to enter a workspace + if (result) { + return this.migrate(result.workspace).then(() => { + + // Show message to user (once) if entering workspace state + if (this.contextService.getWorkbenchState() !== WorkbenchState.WORKSPACE) { + this.informUserOnce(); // TODO@Ben remove me after a couple of releases + } + + // Reinitialize backup service + const backupFileService = this.backupFileService as BackupFileService; // TODO@Ben ugly cast + backupFileService.initialize(result.backupPath); + + // Reinitialize configuration service + const workspaceImpl = this.contextService as WorkspaceService; // TODO@Ben TODO@Sandeep ugly cast + return workspaceImpl.initialize(result.workspace); + }); + } + + return TPromise.as(void 0); + }).then(startExtensionHost, error => { + startExtensionHost(); // in any case start the extension host again! + + return TPromise.wrapError(error); + }); + } + + private informUserOnce(): void { + if (product.quality !== 'stable') { + return; // only for stable } - // Prevent duplicates - return distinct(roots.map(root => root.fsPath), root => isLinux ? root : root.toLowerCase()); + if (this.storageService.getBoolean(WorkspaceEditingService.INFO_MESSAGE_KEY)) { + return; // user does not want to see it again + } + + const closeAction = new Action( + 'enterWorkspace.close', + nls.localize('enterWorkspace.close', "Close"), + null, + true, + () => TPromise.as(true) + ); + + const dontShowAgainAction = new Action( + 'enterWorkspace.dontShowAgain', + nls.localize('enterWorkspace.dontShowAgain', "Don't Show Again"), + null, + true, + () => { + this.storageService.store(WorkspaceEditingService.INFO_MESSAGE_KEY, true, StorageScope.GLOBAL); + + return TPromise.as(true); + } + ); + const moreInfoAction = new Action( + 'enterWorkspace.moreInfo', + nls.localize('enterWorkspace.moreInfo', "More Information"), + null, + true, + () => { + const uri = URI.parse('https://go.microsoft.com/fwlink/?linkid=861970'); + window.open(uri.toString(true)); + + return TPromise.as(true); + } + ); + + this.messageService.show(Severity.Info, { + message: nls.localize('enterWorkspace.prompt', "Learn more about working with multiple folders in VS Code."), + actions: [moreInfoAction, dontShowAgainAction, closeAction] + }); + } + + private migrate(toWorkspace: IWorkspaceIdentifier): TPromise { + + // Storage (UI State) migration + this.migrateStorage(toWorkspace); + + // Settings migration (only if we come from a folder workspace) + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + return this.copyWorkspaceSettings(toWorkspace); + } + + return TPromise.as(void 0); + } + + private migrateStorage(toWorkspace: IWorkspaceIdentifier): void { + + // TODO@Ben revisit this when we move away from local storage to a file based approach + const storageImpl = this.storageService as StorageService; + const newWorkspaceId = migrateStorageToMultiRootWorkspace(storageImpl.workspaceId, toWorkspace, storageImpl.workspaceStorage); + storageImpl.setWorkspaceId(newWorkspaceId); + } + + public copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): TPromise { + const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); + const targetWorkspaceConfiguration = {}; + for (const key of this.workspaceConfigurationService.keys().workspace) { + if (configurationProperties[key] && !configurationProperties[key].notMultiRootAdopted && configurationProperties[key].scope === ConfigurationScope.WINDOW) { + targetWorkspaceConfiguration[key] = this.workspaceConfigurationService.inspect(key).workspace; + } + } + + return this.jsonEditingService.write(URI.file(toWorkspace.configPath), { key: 'settings', value: targetWorkspaceConfiguration }, true); } } diff --git a/src/vs/workbench/services/workspace/node/workspaceMigrationService.ts b/src/vs/workbench/services/workspace/node/workspaceMigrationService.ts deleted file mode 100644 index 218ccc286d3..00000000000 --- a/src/vs/workbench/services/workspace/node/workspaceMigrationService.ts +++ /dev/null @@ -1,79 +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 { TPromise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; -import { once } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { StorageService } from 'vs/platform/storage/common/storageService'; -import { migrateStorageToMultiRootWorkspace } from 'vs/platform/storage/common/migration'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspaceMigrationService } from 'vs/workbench/services/workspace/common/workspaceEditing'; - -export class WorkspaceMigrationService implements IWorkspaceMigrationService { - - public _serviceBrand: any; - - private shutdownListener: IDisposable; - - constructor( - @IStorageService private storageService: IStorageService, - @IJSONEditingService private jsonEditingService: IJSONEditingService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IConfigurationService private configurationService: IConfigurationService, - @ILifecycleService private lifecycleService: ILifecycleService - ) { - } - - migrate(toWorkspaceId: IWorkspaceIdentifier): TPromise { - this.migrateStorage(toWorkspaceId); - - return this.migrateConfiguration(toWorkspaceId); - } - - migrateStorage(toWorkspaceId: IWorkspaceIdentifier): void { - - // The shutdown sequence could have been stopped due to a veto. Make sure to - // always dispose the shutdown listener if we are called again in the same session. - if (this.shutdownListener) { - this.shutdownListener.dispose(); - this.shutdownListener = void 0; - } - - // Since many components write to storage only on shutdown, we register a shutdown listener - // very late to be called as the last one. - this.shutdownListener = once(this.lifecycleService.onShutdown)(() => { - - // TODO@Ben revisit this when we move away from local storage to a file based approach - const storageImpl = this.storageService as StorageService; - migrateStorageToMultiRootWorkspace(storageImpl.storageId, toWorkspaceId, storageImpl.workspaceStorage); - }); - } - - private migrateConfiguration(toWorkspaceId: IWorkspaceIdentifier): TPromise { - if (!this.contextService.hasFolderWorkspace()) { - return TPromise.as(void 0); // return early if not a folder workspace is opened - } - - const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); - const targetWorkspaceConfiguration = {}; - for (const key of this.configurationService.keys().workspace) { - if (configurationProperties[key] && configurationProperties[key].scope === ConfigurationScope.WINDOW) { - targetWorkspaceConfiguration[key] = this.configurationService.lookup(key).workspace; - } - } - - return this.jsonEditingService.write(URI.file(toWorkspaceId.configPath), { key: 'settings', value: targetWorkspaceConfiguration }, true); - } -} diff --git a/src/vs/workbench/test/browser/actionRegistry.test.ts b/src/vs/workbench/test/browser/actionRegistry.test.ts index 47ab80aa924..2e9e472df7f 100644 --- a/src/vs/workbench/test/browser/actionRegistry.test.ts +++ b/src/vs/workbench/test/browser/actionRegistry.test.ts @@ -6,42 +6,12 @@ 'use strict'; import * as assert from 'assert'; -import * as Platform from 'vs/platform/registry/common/platform'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { Extensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actionRegistry'; import { prepareActions } from 'vs/workbench/browser/actions'; import { Action } from 'vs/base/common/actions'; - -class MyClass extends Action { - constructor(id: string, label: string) { - super(id, label); - } -} - suite('Workbench Action Registry', () => { - test('Workbench Action Registration', function () { - let Registry = Platform.Registry.as(Extensions.WorkbenchActions); - - let d = new SyncActionDescriptor(MyClass, 'id', 'name'); - - let oldActions = Registry.getWorkbenchActions().slice(0); - let oldCount = Registry.getWorkbenchActions().length; - - Registry.registerWorkbenchAction(d, 'My Alias', 'category'); - Registry.registerWorkbenchAction(d, null); - - assert.equal(Registry.getWorkbenchActions().length, 1 + oldCount); - assert.strictEqual(d, Registry.getWorkbenchAction('id')); - - assert.deepEqual(Registry.getAlias(d.id), 'My Alias'); - assert.equal(Registry.getCategory(d.id), 'category'); - - (Registry).setWorkbenchActions(oldActions); - }); - test('Workbench Action Bar prepareActions()', function () { let a1 = new Separator(); let a2 = new Separator(); @@ -57,4 +27,4 @@ suite('Workbench Action Registry', () => { assert(actions[1] === a5); assert(actions[2] === a6); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index 66589da8664..25246bcaa3c 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -6,27 +6,29 @@ 'use strict'; import * as assert from 'assert'; -import { BaseEditor, EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorInput, EditorOptions, Extensions, IEditorRegistry, IEditorInputFactory } from 'vs/workbench/common/editor'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { EditorInput, EditorOptions, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import * as Platform from 'vs/platform/registry/common/platform'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; +import URI from 'vs/base/common/uri'; +import { IEditorRegistry, Extensions, EditorDescriptor } from 'vs/workbench/browser/editor'; const NullThemeService = new TestThemeService(); let EditorRegistry: IEditorRegistry = Platform.Registry.as(Extensions.Editors); +let EditorInputRegistry: IEditorInputFactoryRegistry = Platform.Registry.as(EditorExtensions.EditorInputFactories); export class MyEditor extends BaseEditor { - constructor(id: string, @ITelemetryService telemetryService: ITelemetryService) { - super(id, NullTelemetryService, NullThemeService); + constructor( @ITelemetryService telemetryService: ITelemetryService) { + super('MyEditor', NullTelemetryService, NullThemeService); } getId(): string { @@ -44,8 +46,8 @@ export class MyEditor extends BaseEditor { export class MyOtherEditor extends BaseEditor { - constructor(id: string, @ITelemetryService telemetryService: ITelemetryService) { - super(id, NullTelemetryService, NullThemeService); + constructor( @ITelemetryService telemetryService: ITelemetryService) { + super('myOtherEditor', NullTelemetryService, NullThemeService); } getId(): string { @@ -73,7 +75,7 @@ class MyInputFactory implements IEditorInputFactory { } class MyInput extends EditorInput { - getPreferredEditorId(ids) { + getPreferredEditorId(ids: string[]) { return ids[1]; } @@ -100,7 +102,7 @@ class MyResourceInput extends ResourceEditorInput { } suite('Workbench BaseEditor', () => { test('BaseEditor API', function (done) { - let e = new MyEditor('id', NullTelemetryService); + let e = new MyEditor(NullTelemetryService); let input = new MyOtherInput(); let options = new EditorOptions(); @@ -127,14 +129,14 @@ suite('Workbench BaseEditor', () => { }); test('EditorDescriptor', function () { - let d = new EditorDescriptor('id', 'name', 'vs/workbench/test/browser/parts/editor/baseEditor.test', 'MyClass'); + let d = new EditorDescriptor(MyEditor, 'id', 'name'); assert.strictEqual(d.getId(), 'id'); assert.strictEqual(d.getName(), 'name'); }); test('Editor Registration', function () { - let d1 = new EditorDescriptor('id1', 'name', 'vs/workbench/test/browser/parts/editor/baseEditor.test', 'MyClass'); - let d2 = new EditorDescriptor('id2', 'name', 'vs/workbench/test/browser/parts/editor/baseEditor.test', 'MyOtherClass'); + let d1 = new EditorDescriptor(MyEditor, 'id1', 'name'); + let d2 = new EditorDescriptor(MyOtherEditor, 'id2', 'name'); let oldEditorsCnt = EditorRegistry.getEditors().length; let oldInputCnt = (EditorRegistry).getEditorInputs().length; @@ -153,9 +155,9 @@ suite('Workbench BaseEditor', () => { assert(!EditorRegistry.getEditorById('id3')); }); - test('Editor Lookup favors specific class over superclass (match on specific class)', function (done) { - let d1 = new EditorDescriptor('id1', 'name', 'vs/workbench/test/browser/parts/editor/baseEditor.test', 'MyEditor'); - let d2 = new EditorDescriptor('id2', 'name', 'vs/workbench/test/browser/parts/editor/baseEditor.test', 'MyOtherEditor'); + test('Editor Lookup favors specific class over superclass (match on specific class)', function () { + let d1 = new EditorDescriptor(MyEditor, 'id1', 'name'); + let d2 = new EditorDescriptor(MyOtherEditor, 'id2', 'name'); let oldEditors = EditorRegistry.getEditors(); (EditorRegistry).setEditors([]); @@ -165,19 +167,17 @@ suite('Workbench BaseEditor', () => { let inst = new TestInstantiationService(); - inst.createInstance(EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', '', PLAINTEXT_MODE_ID, false)), 'id').then(editor => { - assert.strictEqual(editor.getId(), 'myEditor'); + const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'))).instantiate(inst); + assert.strictEqual(editor.getId(), 'myEditor'); - return inst.createInstance(EditorRegistry.getEditor(inst.createInstance(ResourceEditorInput, 'fake', '', '', PLAINTEXT_MODE_ID, false)), 'id').then(editor => { - assert.strictEqual(editor.getId(), 'myOtherEditor'); + const otherEditor = EditorRegistry.getEditor(inst.createInstance(ResourceEditorInput, 'fake', '', URI.file('/fake'))).instantiate(inst); + assert.strictEqual(otherEditor.getId(), 'myOtherEditor'); - (EditorRegistry).setEditors(oldEditors); - }); - }).done(() => done()); + (EditorRegistry).setEditors(oldEditors); }); - test('Editor Lookup favors specific class over superclass (match on super class)', function (done) { - let d1 = new EditorDescriptor('id1', 'name', 'vs/workbench/test/browser/parts/editor/baseEditor.test', 'MyOtherEditor'); + test('Editor Lookup favors specific class over superclass (match on super class)', function () { + let d1 = new EditorDescriptor(MyOtherEditor, 'id1', 'name'); let oldEditors = EditorRegistry.getEditors(); (EditorRegistry).setEditors([]); @@ -186,18 +186,17 @@ suite('Workbench BaseEditor', () => { let inst = new TestInstantiationService(); - inst.createInstance(EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', '', PLAINTEXT_MODE_ID, false)), 'id').then(editor => { - assert.strictEqual('myOtherEditor', editor.getId()); + const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'))).instantiate(inst); + assert.strictEqual('myOtherEditor', editor.getId()); - (EditorRegistry).setEditors(oldEditors); - }).done(() => done()); + (EditorRegistry).setEditors(oldEditors); }); test('Editor Input Factory', function () { - EditorRegistry.setInstantiationService(workbenchInstantiationService()); - EditorRegistry.registerEditorInputFactory('myInputId', MyInputFactory); + EditorInputRegistry.setInstantiationService(workbenchInstantiationService()); + EditorInputRegistry.registerEditorInputFactory('myInputId', MyInputFactory); - let factory = EditorRegistry.getEditorInputFactory('myInputId'); + let factory = EditorInputRegistry.getEditorInputFactory('myInputId'); assert(factory); }); diff --git a/src/vs/workbench/test/browser/editorStacksModel.test.ts b/src/vs/workbench/test/browser/parts/editor/editorStacksModel.test.ts similarity index 97% rename from src/vs/workbench/test/browser/editorStacksModel.test.ts rename to src/vs/workbench/test/browser/parts/editor/editorStacksModel.test.ts index 81b2ad1f95e..6308cacd798 100644 --- a/src/vs/workbench/test/browser/editorStacksModel.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/editorStacksModel.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { EditorStacksModel, EditorGroup, EditorCloseEvent } from 'vs/workbench/common/editor/editorStacksModel'; -import { EditorInput, IFileEditorInput, IEditorIdentifier, IEditorGroup, IStacksModelChangeEvent, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, IEditorCloseEvent } from 'vs/workbench/common/editor'; +import { Extensions as EditorExtensions, IEditorInputFactoryRegistry, EditorInput, IFileEditorInput, IEditorIdentifier, IEditorGroup, IStacksModelChangeEvent, IEditorInputFactory, IEditorCloseEvent } from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; import { TestStorageService, TestLifecycleService, TestContextService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -17,12 +17,12 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { Registry } from 'vs/platform/registry/common/platform'; -import { Position, Direction } from 'vs/platform/editor/common/editor'; +import { Position, Direction, IEditorModel } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; -import 'vs/workbench/browser/parts/editor/baseEditor'; +import { TPromise } from 'vs/base/common/winjs.base'; function create(): EditorStacksModel { let inst = new TestInstantiationService(); @@ -61,7 +61,7 @@ interface GroupEvents { } function modelListener(model: EditorStacksModel): ModelEvents { - const modelEvents = { + const modelEvents: ModelEvents = { opened: [], activated: [], closed: [], @@ -87,7 +87,7 @@ function modelListener(model: EditorStacksModel): ModelEvents { } function groupListener(group: EditorGroup): GroupEvents { - const groupEvents = { + const groupEvents: GroupEvents = { opened: [], closed: [], activated: [], @@ -112,7 +112,7 @@ class TestEditorInput extends EditorInput { super(); } public getTypeId() { return 'testEditorInput'; } - public resolve() { return null; } + public resolve(): TPromise { return null; } public matches(other: TestEditorInput): boolean { return other && this.id === other.id && other instanceof TestEditorInput; @@ -132,7 +132,7 @@ class NonSerializableTestEditorInput extends EditorInput { super(); } public getTypeId() { return 'testEditorInput-nonSerializable'; } - public resolve() { return null; } + public resolve(): TPromise { return null; } public matches(other: TestEditorInput): boolean { return other && this.id === other.id && other instanceof NonSerializableTestEditorInput; @@ -145,7 +145,7 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput { super(); } public getTypeId() { return 'testFileEditorInput'; } - public resolve() { return null; } + public resolve(): TPromise { return null; } public matches(other: TestEditorInput): boolean { return other && this.id === other.id && other instanceof TestFileEditorInput; @@ -202,7 +202,7 @@ class TestEditorInputFactory implements IEditorInputFactory { } } -(Registry.as(EditorExtensions.Editors)).registerEditorInputFactory('testEditorInput', TestEditorInputFactory); +(Registry.as(EditorExtensions.EditorInputFactories)).registerEditorInputFactory('testEditorInput', TestEditorInputFactory); suite('Editor Stacks Model', () => { @@ -365,6 +365,7 @@ suite('Editor Stacks Model', () => { model.moveGroup(group3, 1); assert.equal(events.moved.length, 2); + assert.ok(group2); }); test('Groups - Event Aggregation', function () { @@ -1199,7 +1200,7 @@ suite('Editor Stacks Model', () => { config.setUserConfiguration('workbench', { editor: { openPositioning: 'right' } }); inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.Editors)).setInstantiationService(inst); + (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); let model: EditorStacksModel = inst.createInstance(EditorStacksModel, true); let group = model.openGroup('group'); @@ -1244,7 +1245,7 @@ suite('Editor Stacks Model', () => { inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.Editors)).setInstantiationService(inst); + (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); let model: EditorStacksModel = inst.createInstance(EditorStacksModel, true); @@ -1327,7 +1328,7 @@ suite('Editor Stacks Model', () => { inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.Editors)).setInstantiationService(inst); + (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); let model: EditorStacksModel = inst.createInstance(EditorStacksModel, true); @@ -1378,7 +1379,7 @@ suite('Editor Stacks Model', () => { inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.Editors)).setInstantiationService(inst); + (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); let model: EditorStacksModel = inst.createInstance(EditorStacksModel, true); @@ -1419,7 +1420,7 @@ suite('Editor Stacks Model', () => { config.setUserConfiguration('workbench', { editor: { openPositioning: 'right' } }); inst.stub(IConfigurationService, config); - (Registry.as(EditorExtensions.Editors)).setInstantiationService(inst); + (Registry.as(EditorExtensions.EditorInputFactories)).setInstantiationService(inst); let model: EditorStacksModel = inst.createInstance(EditorStacksModel, false); diff --git a/src/vs/workbench/test/browser/quickopen.test.ts b/src/vs/workbench/test/browser/quickopen.test.ts index f960396bed2..221336358c3 100644 --- a/src/vs/workbench/test/browser/quickopen.test.ts +++ b/src/vs/workbench/test/browser/quickopen.test.ts @@ -11,7 +11,7 @@ import { Promise, TPromise } from 'vs/base/common/winjs.base'; import Event from 'vs/base/common/event'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Registry } from 'vs/platform/registry/common/platform'; -import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenAction } from 'vs/workbench/browser/quickopen'; +import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenAction, QuickOpenHandler } from 'vs/workbench/browser/quickopen'; export class TestQuickOpenService implements IQuickOpenService { public _serviceBrand: any; @@ -61,11 +61,15 @@ export class TestQuickOpenService implements IQuickOpenService { suite('Workbench QuickOpen', () => { + class TestHandler extends QuickOpenHandler { + + } + test('QuickOpen Handler and Registry', () => { let registry = (Registry.as(QuickOpenExtensions.Quickopen)); let handler = new QuickOpenHandlerDescriptor( - 'test', - 'TestHandler', + TestHandler, + 'testhandler', ',', 'Handler', null diff --git a/src/vs/workbench/test/browser/viewlet.test.ts b/src/vs/workbench/test/browser/viewlet.test.ts index 34888c95575..f8b54dfda12 100644 --- a/src/vs/workbench/test/browser/viewlet.test.ts +++ b/src/vs/workbench/test/browser/viewlet.test.ts @@ -7,13 +7,24 @@ import * as assert from 'assert'; import * as Platform from 'vs/platform/registry/common/platform'; -import { ViewletDescriptor, Extensions } from 'vs/workbench/browser/viewlet'; +import { ViewletDescriptor, Extensions, Viewlet } from 'vs/workbench/browser/viewlet'; import * as Types from 'vs/base/common/types'; suite('Workbench Viewlet', () => { + class TestViewlet extends Viewlet { + + constructor() { + super('id', null, null); + } + + public layout(dimension: any): void { + throw new Error('Method not implemented.'); + } + } + test('ViewletDescriptor API', function () { - let d = new ViewletDescriptor('moduleId', 'ctorName', 'id', 'name', 'class', 5); + let d = new ViewletDescriptor(TestViewlet, 'id', 'name', 'class', 5); assert.strictEqual(d.id, 'id'); assert.strictEqual(d.name, 'name'); assert.strictEqual(d.cssClass, 'class'); @@ -21,11 +32,11 @@ suite('Workbench Viewlet', () => { }); test('Editor Aware ViewletDescriptor API', function () { - let d = new ViewletDescriptor('moduleId', 'ctorName', 'id', 'name', 'class', 5); + let d = new ViewletDescriptor(TestViewlet, 'id', 'name', 'class', 5); assert.strictEqual(d.id, 'id'); assert.strictEqual(d.name, 'name'); - d = new ViewletDescriptor('moduleId', 'ctorName', 'id', 'name', 'class', 5); + d = new ViewletDescriptor(TestViewlet, 'id', 'name', 'class', 5); assert.strictEqual(d.id, 'id'); assert.strictEqual(d.name, 'name'); }); @@ -36,7 +47,7 @@ suite('Workbench Viewlet', () => { assert(Types.isFunction(Platform.Registry.as(Extensions.Viewlets).getViewlets)); let oldCount = Platform.Registry.as(Extensions.Viewlets).getViewlets().length; - let d = new ViewletDescriptor('moduleId', 'ctorName', 'reg-test-id', 'name'); + let d = new ViewletDescriptor(TestViewlet, 'reg-test-id', 'name'); Platform.Registry.as(Extensions.Viewlets).registerViewlet(d); assert(d === Platform.Registry.as(Extensions.Viewlets).getViewlet('reg-test-id')); diff --git a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts index 432571a2e27..505e26e4b22 100644 --- a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts @@ -6,8 +6,6 @@ 'use strict'; import * as assert from 'assert'; -import { EditorModel } from 'vs/workbench/common/editor'; -import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -21,9 +19,6 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IModel } from 'vs/editor/common/editorCommon'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -class MyEditorModel extends EditorModel { } -class MyTextEditorModel extends BaseTextEditorModel { } - class ServiceAccessor { constructor( @ITextModelService public textModelResolverService: ITextModelService, diff --git a/src/vs/workbench/test/common/editor/rangeDecorations.test.ts b/src/vs/workbench/test/common/editor/rangeDecorations.test.ts index e9677bbdb23..08b419544c3 100644 --- a/src/vs/workbench/test/common/editor/rangeDecorations.test.ts +++ b/src/vs/workbench/test/common/editor/rangeDecorations.test.ts @@ -28,8 +28,11 @@ import { CoreNavigationCommands } from 'vs/editor/common/controller/coreCommands suite('Editor - Range decorations', () => { let instantiationService: TestInstantiationService; + // @ts-ignore unused injected service let editorService: WorkbenchEditorService.IWorkbenchEditorService; + // @ts-ignore unused injected service let modelService: IModelService; + // @ts-ignore unused injected service let modeService: IModeService; let codeEditor: editorCommon.ICommonCodeEditor; let model: Model; diff --git a/src/vs/workbench/test/common/memento.test.ts b/src/vs/workbench/test/common/memento.test.ts index 686250e7b1b..8a3eb9d9219 100644 --- a/src/vs/workbench/test/common/memento.test.ts +++ b/src/vs/workbench/test/common/memento.test.ts @@ -13,8 +13,8 @@ import { StorageService, InMemoryLocalStorage } from 'vs/platform/storage/common import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; suite('Workbench Memento', () => { - let context; - let storage; + let context: Scope = undefined; + let storage: StorageService; setup(() => { storage = new StorageService(new InMemoryLocalStorage(), null, TestWorkspace.id); @@ -70,9 +70,9 @@ suite('Workbench Memento', () => { assert.deepEqual(memento, {}); // Assert the Mementos are also removed from storage - assert.strictEqual(storage.get('memento/memento.test', Scope.GLOBAL, null), null); + assert.strictEqual(storage.get('memento/memento.test', StorageScope.GLOBAL, null), null); - assert.strictEqual(storage.get('memento/memento.test', Scope.WORKSPACE, null), null); + assert.strictEqual(storage.get('memento/memento.test', StorageScope.WORKSPACE, null), null); }); test('Save and Load', () => { diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index f2e905cbb73..812d8bd1ea1 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -131,6 +131,7 @@ suite('ExtHostLanguageFeatureCommands', function () { suiteTeardown(() => { setUnexpectedErrorHandler(originalErrorHandler); model.dispose(); + mainThread.dispose(); }); teardown(function (done) { diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index 8f7c6e4163f..bbe463f0080 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -9,12 +9,13 @@ import * as assert from 'assert'; import URI from 'vs/base/common/uri'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; -import { MainThreadConfigurationShape } from 'vs/workbench/api/node/extHost.protocol'; +import { MainThreadConfigurationShape, IConfigurationInitData } from 'vs/workbench/api/node/extHost.protocol'; import { TPromise } from 'vs/base/common/winjs.base'; -import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditingError } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { TestThreadService } from './testThreadService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; +import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; suite('ExtHostConfiguration', function () { @@ -24,18 +25,23 @@ suite('ExtHostConfiguration', function () { this.lastArgs = [target, key, value]; return TPromise.as(void 0); } - }; + } function createExtHostConfiguration(contents: any = Object.create(null), shape?: MainThreadConfigurationShape) { if (!shape) { shape = new class extends mock() { }; } - return new ExtHostConfiguration(shape, new ExtHostWorkspace(new TestThreadService(), null), { + return new ExtHostConfiguration(shape, new ExtHostWorkspace(new TestThreadService(), null), createConfigurationData(contents)); + } + + function createConfigurationData(contents: any): IConfigurationInitData { + return { defaults: new ConfigurationModel(contents), user: new ConfigurationModel(contents), workspace: new ConfigurationModel(), - folders: Object.create(null) - }); + folders: Object.create(null), + configurationScopes: [] + }; } test('getConfiguration fails regression test 1.7.1 -> 1.8 #15552', function () { @@ -101,7 +107,8 @@ suite('ExtHostConfiguration', function () { } }, ['editor.wordWrap']), workspace: new ConfigurationModel({}, []), - folders: Object.create(null) + folders: Object.create(null), + configurationScopes: [] } ); @@ -131,7 +138,7 @@ suite('ExtHostConfiguration', function () { new class extends mock() { }, new ExtHostWorkspace(new TestThreadService(), { 'id': 'foo', - 'roots': [URI.file('foo')], + 'folders': [aWorkspaceFolder(URI.file('foo'), 0)], 'name': 'foo' }), { @@ -146,7 +153,8 @@ suite('ExtHostConfiguration', function () { } }, ['editor.wordWrap']), workspace, - folders + folders, + configurationScopes: [] } ); @@ -203,7 +211,7 @@ suite('ExtHostConfiguration', function () { new class extends mock() { }, new ExtHostWorkspace(new TestThreadService(), { 'id': 'foo', - 'roots': [firstRoot, secondRoot], + 'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)], 'name': 'foo' }), { @@ -219,7 +227,8 @@ suite('ExtHostConfiguration', function () { } }, ['editor.wordWrap']), workspace, - folders + folders, + configurationScopes: [] } ); @@ -393,7 +402,7 @@ suite('ExtHostConfiguration', function () { const shape = new class extends mock() { $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): TPromise { - return TPromise.wrapError(new ConfigurationEditingError('Unknown Key', ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY)); // something !== OK + return TPromise.wrapError(new Error('Unknown Key')); // something !== OK } }; @@ -402,4 +411,76 @@ suite('ExtHostConfiguration', function () { .update('', true, false) .then(() => assert.ok(false), err => { /* expecting rejection */ }); }); + + test('configuration change event', (done) => { + + const workspaceFolder = aWorkspaceFolder(URI.file('folder1'), 0); + const testObject = new ExtHostConfiguration( + new class extends mock() { }, + new ExtHostWorkspace(new TestThreadService(), { + 'id': 'foo', + 'folders': [workspaceFolder], + 'name': 'foo' + }), + createConfigurationData({ + 'farboo': { + 'config': false, + 'updatedconfig': false + } + }) + ); + + const newConfigData = createConfigurationData({ + 'farboo': { + 'config': false, + 'updatedconfig': true, + 'newConfig': true, + } + }); + const changedConfigurationByResource = Object.create({}); + changedConfigurationByResource[workspaceFolder.uri.toString()] = new ConfigurationModel({ + 'farboo': { + 'newConfig': true, + } + }, ['farboo.newConfig']); + const configEventData = { + changedConfiguration: new ConfigurationModel({ + 'farboo': { + 'updatedConfig': true, + } + }, ['farboo.updatedConfig']), + changedConfigurationByResource + }; + testObject.onDidChangeConfiguration(e => { + + assert.deepEqual(testObject.getConfiguration().get('farboo'), { + 'config': false, + 'updatedconfig': true, + 'newConfig': true, + }); + + assert.ok(e.affectsConfiguration('farboo')); + assert.ok(e.affectsConfiguration('farboo', workspaceFolder.uri)); + assert.ok(e.affectsConfiguration('farboo', URI.file('any'))); + + assert.ok(e.affectsConfiguration('farboo.updatedConfig')); + assert.ok(e.affectsConfiguration('farboo.updatedConfig', workspaceFolder.uri)); + assert.ok(e.affectsConfiguration('farboo.updatedConfig', URI.file('any'))); + + assert.ok(e.affectsConfiguration('farboo.newConfig')); + assert.ok(e.affectsConfiguration('farboo.newConfig', workspaceFolder.uri)); + assert.ok(!e.affectsConfiguration('farboo.newConfig', URI.file('any'))); + + assert.ok(!e.affectsConfiguration('farboo.config')); + assert.ok(!e.affectsConfiguration('farboo.config', workspaceFolder.uri)); + assert.ok(!e.affectsConfiguration('farboo.config', URI.file('any'))); + done(); + }); + + testObject.$acceptConfigurationChanged(newConfigData, configEventData); + }); + + function aWorkspaceFolder(uri: URI, index: number, name: string = ''): IWorkspaceFolder { + return new WorkspaceFolder({ uri, name, index }); + } }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts index 76aa419a4b5..b0fee510b50 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts @@ -24,7 +24,7 @@ suite('ExtHostDiagnostics', () => { $clear(owner: string): TPromise { return TPromise.as(null); } - }; + } test('disposeCheck', function () { @@ -35,6 +35,7 @@ suite('ExtHostDiagnostics', () => { assert.throws(() => collection.name); assert.throws(() => collection.clear()); assert.throws(() => collection.delete(URI.parse('aa:bb'))); + // tslint:disable-next-line:semicolon assert.throws(() => collection.forEach(() => { ; })); assert.throws(() => collection.get(URI.parse('aa:bb'))); assert.throws(() => collection.has(URI.parse('aa:bb'))); diff --git a/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts index d4a3a7a422f..b89cbfe82dd 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts @@ -42,18 +42,18 @@ suite('ExtHostDocumentData', () => { }); test('readonly-ness', function () { - assert.throws(() => (data).document.uri = null); - assert.throws(() => (data).document.fileName = 'foofile'); - assert.throws(() => (data).document.isDirty = false); - assert.throws(() => (data).document.isUntitled = false); - assert.throws(() => (data).document.languageId = 'dddd'); - assert.throws(() => (data).document.lineCount = 9); + assert.throws((): void => (data as any).document.uri = null); + assert.throws(() => (data as any).document.fileName = 'foofile'); + assert.throws(() => (data as any).document.isDirty = false); + assert.throws(() => (data as any).document.isUntitled = false); + assert.throws(() => (data as any).document.languageId = 'dddd'); + assert.throws(() => (data as any).document.lineCount = 9); }); test('save, when disposed', function () { let saved: URI; let data = new ExtHostDocumentData(new class extends mock() { - $trySaveDocument(uri) { + $trySaveDocument(uri: URI) { assert.ok(!saved); saved = uri; return TPromise.as(true); diff --git a/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts index f521f635930..06167349726 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts @@ -10,10 +10,9 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors'; import { TextDocumentSaveReason, TextEdit, Position, EndOfLine } from 'vs/workbench/api/node/extHostTypes'; -import { MainThreadWorkspaceShape } from 'vs/workbench/api/node/extHost.protocol'; +import { MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol'; import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant'; import { OneGetThreadService } from './testThreadService'; -import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import * as vscode from 'vscode'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; @@ -21,7 +20,7 @@ import { mock } from 'vs/workbench/test/electron-browser/api/mock'; suite('ExtHostDocumentSaveParticipant', () => { let resource = URI.parse('foo:bar'); - let workspace = new class extends mock() { }; + let mainThreadEditors = new class extends mock() { }; let documents: ExtHostDocuments; setup(() => { @@ -40,12 +39,12 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('no listeners, no problem', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => assert.ok(true)); }); test('event delivery', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let event: vscode.TextDocumentWillSaveEvent; let sub = participant.onWillSaveTextDocumentEvent(function (e) { @@ -62,7 +61,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, immutable', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let event: vscode.TextDocumentWillSaveEvent; let sub = participant.onWillSaveTextDocumentEvent(function (e) { @@ -78,7 +77,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, bad listener', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let sub = participant.onWillSaveTextDocumentEvent(function (e) { throw new Error('šŸ’€'); @@ -93,7 +92,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, bad listener doesn\'t prevent more events', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let sub1 = participant.onWillSaveTextDocumentEvent(function (e) { throw new Error('šŸ’€'); @@ -112,7 +111,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, in subscriber order', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let counter = 0; let sub1 = participant.onWillSaveTextDocumentEvent(function (event) { @@ -130,7 +129,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, ignore bad listeners', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace, { timeout: 5, errors: 1 }); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors, { timeout: 5, errors: 1 }); let callCount = 0; let sub = participant.onWillSaveTextDocumentEvent(function (event) { @@ -151,7 +150,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, overall timeout', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace, { timeout: 20, errors: 5 }); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors, { timeout: 20, errors: 5 }); let callCount = 0; let sub1 = participant.onWillSaveTextDocumentEvent(function (event) { @@ -179,7 +178,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, waitUntil', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let sub = participant.onWillSaveTextDocumentEvent(function (event) { @@ -195,7 +194,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, waitUntil must be called sync', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let sub = participant.onWillSaveTextDocumentEvent(function (event) { @@ -218,7 +217,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, waitUntil will timeout', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace, { timeout: 5, errors: 3 }); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors, { timeout: 5, errors: 3 }); let sub = participant.onWillSaveTextDocumentEvent(function (event) { event.waitUntil(TPromise.timeout(15)); @@ -233,7 +232,7 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, waitUntil failure handling', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace); + const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors); let sub1 = participant.onWillSaveTextDocumentEvent(function (e) { e.waitUntil(TPromise.wrapError(new Error('dddd'))); @@ -253,9 +252,9 @@ suite('ExtHostDocumentSaveParticipant', () => { test('event delivery, pushEdits sync', () => { - let edits: IResourceEdit[]; - const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock() { - $applyWorkspaceEdit(_edits) { + let edits: IWorkspaceResourceEdit[]; + const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock() { + $tryApplyWorkspaceEdit(_edits: IWorkspaceResourceEdit[]) { edits = _edits; return TPromise.as(true); } @@ -269,15 +268,16 @@ suite('ExtHostDocumentSaveParticipant', () => { return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => { sub.dispose(); - assert.equal(edits.length, 2); + assert.equal(edits.length, 1); + assert.equal(edits[0].edits.length, 2); }); }); test('event delivery, concurrent change', () => { - let edits: IResourceEdit[]; - const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock() { - $applyWorkspaceEdit(_edits) { + let edits: IWorkspaceResourceEdit[]; + const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock() { + $tryApplyWorkspaceEdit(_edits: IWorkspaceResourceEdit[]) { edits = _edits; return TPromise.as(true); } @@ -310,20 +310,23 @@ suite('ExtHostDocumentSaveParticipant', () => { test('event delivery, two listeners -> two document states', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock() { - $applyWorkspaceEdit(_edits: IResourceEdit[]) { + const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock() { + $tryApplyWorkspaceEdit(_edits: IWorkspaceResourceEdit[]) { - for (const { resource, newText, range } of _edits) { - documents.$acceptModelChanged(resource.toString(), { - changes: [{ - range, - rangeLength: undefined, - text: newText - }], - eol: undefined, - versionId: documents.getDocumentData(resource).version + 1 - }, true); + for (const { resource, edits } of _edits) { + for (const { newText, range } of edits) { + documents.$acceptModelChanged(resource.toString(), { + changes: [{ + range, + rangeLength: undefined, + text: newText + }], + eol: undefined, + versionId: documents.getDocumentData(resource).version + 1 + }, true); + } } + return TPromise.as(true); } }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index eda19b59181..49a7be6f3dd 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -118,6 +118,7 @@ suite('ExtHostLanguageFeatures', function () { suiteTeardown(() => { setUnexpectedErrorHandler(originalErrorHandler); model.dispose(); + mainThread.dispose(); }); teardown(function () { @@ -732,6 +733,24 @@ suite('ExtHostLanguageFeatures', function () { // --- rename + test('Rename, evil provider 0/2', function () { + + disposables.push(extHost.registerRenameProvider(defaultSelector, { + provideRenameEdits(): any { + throw new class Foo { }; + } + })); + + return threadService.sync().then(() => { + + return rename(model, new EditorPosition(1, 1), 'newName').then(value => { + throw Error(); + }, err => { + // expected + }); + }); + }); + test('Rename, evil provider 1/2', function () { disposables.push(extHost.registerRenameProvider(defaultSelector, { @@ -743,9 +762,7 @@ suite('ExtHostLanguageFeatures', function () { return threadService.sync().then(() => { return rename(model, new EditorPosition(1, 1), 'newName').then(value => { - throw new Error(''); - }, err => { - // expected + assert.equal(value.rejectReason, 'evil'); }); }); }); @@ -811,7 +828,11 @@ suite('ExtHostLanguageFeatures', function () { disposables.push(extHost.registerSignatureHelpProvider(defaultSelector, { provideSignatureHelp(): vscode.SignatureHelp { - return new types.SignatureHelp(); + return { + signatures: [], + activeParameter: 0, + activeSignature: 0 + }; } }, [])); diff --git a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts index 37c944c5ce9..ed06fa678dc 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -9,22 +9,23 @@ import * as assert from 'assert'; import { Action } from 'vs/base/common/actions'; import { MainThreadMessageService } from 'vs/workbench/api/electron-browser/mainThreadMessageService'; import { TPromise as Promise } from 'vs/base/common/winjs.base'; +import { IMessageService, IChoiceService } from 'vs/platform/message/common/message'; suite('ExtHostMessageService', function () { test('propagte handle on select', function () { - let service = new MainThreadMessageService(null, null, { - show(sev: number, m: { message; actions: Action[] }) { + let service = new MainThreadMessageService(null, { + show(sev: number, m: { actions: Action[] }) { assert.equal(m.actions.length, 1); setImmediate(() => m.actions[0].run()); return () => { }; } - }, { - choose() { + } as IMessageService, { + choose(severity, message, options, modal) { throw new Error('not implemented'); } - }); + } as IChoiceService); return service.$showMessage(1, 'h', {}, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => { assert.equal(handle, 42); @@ -34,15 +35,15 @@ suite('ExtHostMessageService', function () { test('isCloseAffordance', function () { let actions: Action[]; - let service = new MainThreadMessageService(null, null, { - show(sev: number, m: { message; actions: Action[] }) { + let service = new MainThreadMessageService(null, { + show(sev: number, m: { actions: Action[] }) { actions = m.actions; } - }, { - choose() { + } as IMessageService, { + choose(severity, message, options, modal) { throw new Error('not implemented'); } - }); + } as IChoiceService); // default close action service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: false, handle: 0 }]); @@ -62,19 +63,19 @@ suite('ExtHostMessageService', function () { let actions: Action[]; let c: number; - let service = new MainThreadMessageService(null, null, { - show(sev: number, m: { message; actions: Action[] }) { + let service = new MainThreadMessageService(null, { + show(sev: number, m: { actions: Action[] }) { c = 0; actions = m.actions; return () => { c += 1; }; } - }, { - choose() { + } as IMessageService, { + choose(severity, message, options, modal) { throw new Error('not implemented'); } - }); + } as IChoiceService); service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: true, handle: 0 }]); assert.equal(actions.length, 1); @@ -85,11 +86,11 @@ suite('ExtHostMessageService', function () { suite('modal', () => { test('calls choice service', () => { - const service = new MainThreadMessageService(null, null, { - show(sev: number, m: { message; actions: Action[] }) { + const service = new MainThreadMessageService(null, { + show(sev: number, m: { actions: Action[] }) { throw new Error('not implemented'); } - }, { + } as IMessageService, { choose(severity, message, options, modal) { assert.equal(severity, 1); assert.equal(message, 'h'); @@ -97,7 +98,7 @@ suite('ExtHostMessageService', function () { assert.equal(options[1], 'Cancel'); return Promise.as(0); } - }); + } as IChoiceService); return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => { assert.equal(handle, 42); @@ -105,15 +106,15 @@ suite('ExtHostMessageService', function () { }); test('returns undefined when cancelled', () => { - const service = new MainThreadMessageService(null, null, { - show(sev: number, m: { message; actions: Action[] }) { + const service = new MainThreadMessageService(null, { + show(sev: number, m: { actions: Action[] }) { throw new Error('not implemented'); } - }, { + } as IMessageService, { choose(severity, message, options, modal) { return Promise.as(1); } - }); + } as IChoiceService); return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => { assert.equal(handle, undefined); @@ -121,16 +122,16 @@ suite('ExtHostMessageService', function () { }); test('hides Cancel button when not needed', () => { - const service = new MainThreadMessageService(null, null, { - show(sev: number, m: { message; actions: Action[] }) { + const service = new MainThreadMessageService(null, { + show(sev: number, m: { actions: Action[] }) { throw new Error('not implemented'); } - }, { + } as IMessageService, { choose(severity, message, options, modal) { assert.equal(options.length, 1); return Promise.as(0); } - }); + } as IChoiceService); return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => { assert.equal(handle, 42); diff --git a/src/vs/workbench/test/electron-browser/api/extHostTextEditor.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTextEditor.test.ts index 59c4972297b..48d6e46c0c7 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTextEditor.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTextEditor.test.ts @@ -61,9 +61,11 @@ suite('ExtHostTextEditorOptions', () => { $tryShowEditor: undefined, $tryHideEditor: undefined, $trySetDecorations: undefined, + $trySetDecorationsFast: undefined, $tryRevealRange: undefined, $trySetSelections: undefined, $tryApplyEdits: undefined, + $tryApplyWorkspaceEdit: undefined, $tryInsertSnippet: undefined, $getDiffInformation: undefined }; diff --git a/src/vs/workbench/test/electron-browser/api/extHostTextEditors.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTextEditors.test.ts new file mode 100644 index 00000000000..4c012a03b62 --- /dev/null +++ b/src/vs/workbench/test/electron-browser/api/extHostTextEditors.test.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; +import * as extHostTypes from 'vs/workbench/api/node/extHostTypes'; +import { MainContext, MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol'; +import URI from 'vs/base/common/uri'; +import { mock } from 'vs/workbench/test/electron-browser/api/mock'; +import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors'; +import { OneGetThreadService, TestThreadService } from 'vs/workbench/test/electron-browser/api/testThreadService'; +import { ExtHostEditors } from 'vs/workbench/api/node/extHostTextEditors'; + +suite('ExtHostTextEditors.applyWorkspaceEdit', () => { + + const resource = URI.parse('foo:bar'); + let editors: ExtHostEditors; + let workspaceResourceEdits: IWorkspaceResourceEdit[]; + + setup(() => { + workspaceResourceEdits = null; + + let threadService = new TestThreadService(); + threadService.setTestInstance(MainContext.MainThreadEditors, new class extends mock() { + $tryApplyWorkspaceEdit(_workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise { + workspaceResourceEdits = _workspaceResourceEdits; + return TPromise.as(true); + } + }); + const documentsAndEditors = new ExtHostDocumentsAndEditors(OneGetThreadService(null)); + documentsAndEditors.$acceptDocumentsAndEditorsDelta({ + addedDocuments: [{ + isDirty: false, + modeId: 'foo', + url: resource, + versionId: 1337, + lines: ['foo'], + EOL: '\n', + }] + }); + editors = new ExtHostEditors(threadService, documentsAndEditors); + }); + + test('uses version id if document available', () => { + let edit = new extHostTypes.WorkspaceEdit(); + edit.replace(resource, new extHostTypes.Range(0, 0, 0, 0), 'hello'); + return editors.applyWorkspaceEdit(edit).then((result) => { + assert.equal(workspaceResourceEdits.length, 1); + assert.equal(workspaceResourceEdits[0].modelVersionId, 1337); + }); + }); + + test('does not use version id if document is not available', () => { + let edit = new extHostTypes.WorkspaceEdit(); + edit.replace(URI.parse('foo:bar2'), new extHostTypes.Range(0, 0, 0, 0), 'hello'); + return editors.applyWorkspaceEdit(edit).then((result) => { + assert.equal(workspaceResourceEdits.length, 1); + assert.ok(typeof workspaceResourceEdits[0].modelVersionId === 'undefined'); + }); + }); + +}); diff --git a/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts index 1426bcdef75..f1824c5c95d 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts @@ -31,7 +31,7 @@ suite('ExtHostConfiguration', function () { $refresh(viewId: string, itemHandles: number[]): void { this.onRefresh.fire(itemHandles); } - }; + } let testObject: ExtHostTreeViews; let target: RecordingShape; diff --git a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts index af39c3d2e50..73399a9bd37 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -7,72 +7,84 @@ import * as assert from 'assert'; import URI from 'vs/base/common/uri'; +import { basename } from 'path'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { TestThreadService } from './testThreadService'; +import { normalize } from 'vs/base/common/paths'; +import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; suite('ExtHostWorkspace', function () { + function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) { + const actual = workspace.getRelativePath(input, includeWorkspace); + if (actual === expected) { + assert.ok(true); + } else { + assert.equal(actual, normalize(expected, true)); + } + } + test('asRelativePath', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', roots: [URI.file('/Coding/Applications/NewsWoWBot')], name: 'Test' }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }); - assert.equal(ws.getRelativePath('/Coding/Applications/NewsWoWBot/bernd/das/brot'), 'bernd/das/brot'); - assert.equal(ws.getRelativePath('/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart'), + assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot'); + assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart', '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart'); - assert.equal(ws.getRelativePath(''), ''); - assert.equal(ws.getRelativePath('/foo/bar'), '/foo/bar'); - assert.equal(ws.getRelativePath('in/out'), 'in/out'); + assertAsRelativePath(ws, '', ''); + assertAsRelativePath(ws, '/foo/bar', '/foo/bar'); + assertAsRelativePath(ws, 'in/out', 'in/out'); }); test('asRelativePath, same paths, #11402', function () { const root = '/home/aeschli/workspaces/samples/docker'; const input = '/home/aeschli/workspaces/samples/docker'; - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', roots: [URI.file(root)], name: 'Test' }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }); - assert.equal(ws.getRelativePath(input), input); + assertAsRelativePath(ws, (input), input); const input2 = '/home/aeschli/workspaces/samples/docker/a.file'; - assert.equal(ws.getRelativePath(input2), 'a.file'); + assertAsRelativePath(ws, (input2), 'a.file'); }); test('asRelativePath, no workspace', function () { const ws = new ExtHostWorkspace(new TestThreadService(), null); - assert.equal(ws.getRelativePath(''), ''); - assert.equal(ws.getRelativePath('/foo/bar'), '/foo/bar'); + assertAsRelativePath(ws, (''), ''); + assertAsRelativePath(ws, ('/foo/bar'), '/foo/bar'); }); test('asRelativePath, multiple folders', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', roots: [URI.file('/Coding/One'), URI.file('/Coding/Two')], name: 'Test' }); - assert.equal(ws.getRelativePath('/Coding/One/file.txt'), 'One/file.txt'); - assert.equal(ws.getRelativePath('/Coding/Two/files/out.txt'), 'Two/files/out.txt'); - assert.equal(ws.getRelativePath('/Coding/Two2/files/out.txt'), '/Coding/Two2/files/out.txt'); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }); + assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt'); + assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt'); + assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt'); }); test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () { - const mrws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', roots: [URI.file('/Coding/One'), URI.file('/Coding/Two')], name: 'Test' }); + const mrws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }); - assert.equal(mrws.getRelativePath('/Coding/One/file.txt'), 'One/file.txt'); - assert.equal(mrws.getRelativePath('/Coding/One/file.txt', true), 'One/file.txt'); - assert.equal(mrws.getRelativePath('/Coding/One/file.txt', false), 'file.txt'); - assert.equal(mrws.getRelativePath('/Coding/Two/files/out.txt'), 'Two/files/out.txt'); - assert.equal(mrws.getRelativePath('/Coding/Two/files/out.txt', true), 'Two/files/out.txt'); - assert.equal(mrws.getRelativePath('/Coding/Two/files/out.txt', false), 'files/out.txt'); - assert.equal(mrws.getRelativePath('/Coding/Two2/files/out.txt'), '/Coding/Two2/files/out.txt'); - assert.equal(mrws.getRelativePath('/Coding/Two2/files/out.txt', true), '/Coding/Two2/files/out.txt'); - assert.equal(mrws.getRelativePath('/Coding/Two2/files/out.txt', false), '/Coding/Two2/files/out.txt'); + assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt'); + assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true); + assertAsRelativePath(mrws, '/Coding/One/file.txt', 'file.txt', false); + assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt'); + assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt', true); + assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'files/out.txt', false); + assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt'); + assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true); + assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false); - const srws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', roots: [URI.file('/Coding/One')], name: 'Test' }); - assert.equal(srws.getRelativePath('/Coding/One/file.txt'), 'file.txt'); - assert.equal(srws.getRelativePath('/Coding/One/file.txt', false), 'file.txt'); - assert.equal(srws.getRelativePath('/Coding/One/file.txt', true), 'One/file.txt'); - assert.equal(srws.getRelativePath('/Coding/Two2/files/out.txt'), '/Coding/Two2/files/out.txt'); - assert.equal(srws.getRelativePath('/Coding/Two2/files/out.txt', true), '/Coding/Two2/files/out.txt'); - assert.equal(srws.getRelativePath('/Coding/Two2/files/out.txt', false), '/Coding/Two2/files/out.txt'); + const srws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }); + assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt'); + assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false); + assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true); + assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt'); + assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true); + assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false); }); test('getPath, legacy', function () { - let ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [] }); + let ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [] }); assert.equal(ws.getPath(), undefined); ws = new ExtHostWorkspace(new TestThreadService(), null); @@ -81,15 +93,15 @@ suite('ExtHostWorkspace', function () { ws = new ExtHostWorkspace(new TestThreadService(), undefined); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [URI.file('Folder'), URI.file('Another/Folder')] }); + ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }); assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); - ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [URI.file('/Folder')] }); + ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }); assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); }); test('WorkspaceFolder has name and index', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', roots: [URI.file('/Coding/One'), URI.file('/Coding/Two')], name: 'Test' }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }); const [one, two] = ws.getWorkspaceFolders(); @@ -100,7 +112,15 @@ suite('ExtHostWorkspace', function () { }); test('getContainingWorkspaceFolder', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [URI.file('/Coding/One'), URI.file('/Coding/Two'), URI.file('/Coding/Two/Nested')] }); + const ws = new ExtHostWorkspace(new TestThreadService(), { + id: 'foo', + name: 'Test', + folders: [ + aWorkspaceFolderData(URI.file('/Coding/One'), 0), + aWorkspaceFolderData(URI.file('/Coding/Two'), 1), + aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2) + ] + }); let folder = ws.getWorkspaceFolder(URI.file('/foo/bar')); assert.equal(folder, undefined); @@ -120,24 +140,33 @@ suite('ExtHostWorkspace', function () { folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f')); assert.equal(folder.name, 'Nested'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true); assert.equal(folder.name, 'Two'); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true); + assert.equal(folder.name, 'Two'); + + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested')); + assert.equal(folder.name, 'Nested'); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/')); - assert.equal(folder.name, 'Two'); + assert.equal(folder.name, 'Nested'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true); assert.equal(folder, undefined); + + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false); + assert.equal(folder.name, 'Two'); }); test('Multiroot change event should have a delta, #29641', function () { - let ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [] }); + let ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [] }); let sub = ws.onDidChangeWorkspace(e => { assert.deepEqual(e.added, []); assert.deepEqual(e.removed, []); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', roots: [] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] }); sub.dispose(); sub = ws.onDidChangeWorkspace(e => { @@ -145,7 +174,7 @@ suite('ExtHostWorkspace', function () { assert.equal(e.added.length, 1); assert.equal(e.added[0].uri.toString(), 'foo:bar'); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', roots: [URI.parse('foo:bar')] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); sub.dispose(); sub = ws.onDidChangeWorkspace(e => { @@ -153,7 +182,7 @@ suite('ExtHostWorkspace', function () { assert.equal(e.added.length, 1); assert.equal(e.added[0].uri.toString(), 'foo:bar2'); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', roots: [URI.parse('foo:bar'), URI.parse('foo:bar2')] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1)] }); sub.dispose(); sub = ws.onDidChangeWorkspace(e => { @@ -164,13 +193,13 @@ suite('ExtHostWorkspace', function () { assert.equal(e.added.length, 1); assert.equal(e.added[0].uri.toString(), 'foo:bar3'); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', roots: [URI.parse('foo:bar3')] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] }); sub.dispose(); }); test('Multiroot change event is immutable', function () { - let ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [] }); + let ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [] }); let sub = ws.onDidChangeWorkspace(e => { assert.throws(() => { (e).added = []; @@ -179,7 +208,26 @@ suite('ExtHostWorkspace', function () { (e.added)[0] = null; }); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', roots: [] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] }); sub.dispose(); }); + + test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () { + let ws = new ExtHostWorkspace(new TestThreadService(), { + id: 'foo', name: 'Test', folders: [ + aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0) + ] + }); + + assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt'))); + assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt'))); + }); + + function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData { + return { + uri, + index, + name: name || basename(uri.path) + }; + } }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts index effdeecbea4..b91637eeeae 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadConfiguration.test.ts @@ -10,16 +10,14 @@ import * as sinon from 'sinon'; import URI from 'vs/base/common/uri'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { MainThreadConfiguration } from 'vs/workbench/api/electron-browser/mainThreadConfiguration'; -import { ConfigurationTarget, IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService'; import { OneGetThreadService } from './testThreadService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; -suite('ExtHostConfiguration', function () { +suite('MainThreadConfiguration', function () { let instantiationService: TestInstantiationService; let target: sinon.SinonSpy; @@ -47,182 +45,183 @@ suite('ExtHostConfiguration', function () { }); setup(() => { - instantiationService = new TestInstantiationService(); - instantiationService.stub(IConfigurationService, new TestConfigurationService()); - target = sinon.spy(); - instantiationService.stub(IConfigurationEditingService, ConfigurationEditingService); - instantiationService.stub(IConfigurationEditingService, 'writeConfiguration', target); + + instantiationService = new TestInstantiationService(); + instantiationService.stub(IConfigurationService, WorkspaceService); + instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', sinon.mock()); + instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', sinon.mock()); + instantiationService.stub(IConfigurationService, 'updateValue', target); }); test('update resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update resource configuration without configuration target defaults to folder', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.FOLDER, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); test('update configuration with user configuration target', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(ConfigurationTarget.USER, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.USER, target.args[0][0]); + assert.equal(ConfigurationTarget.USER, target.args[0][3]); }); test('update configuration with workspace configuration target', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('update configuration with folder configuration target', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); - testObject.$updateConfigurationOption(ConfigurationTarget.FOLDER, 'extHostConfiguration.window', 'value', URI.file('abc')); + testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE_FOLDER, 'extHostConfiguration.window', 'value', URI.file('abc')); - assert.equal(ConfigurationTarget.FOLDER, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', URI.file('abc')); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => false }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.FOLDER }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', null); - assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE, target.args[0][3]); }); test('remove configuration without configuration target defaults to folder', function () { - instantiationService.stub(IWorkspaceContextService, { hasMultiFolderWorkspace: () => true }); + instantiationService.stub(IWorkspaceContextService, { getWorkbenchState: () => WorkbenchState.WORKSPACE }); const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null)); testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', URI.file('abc')); - assert.equal(ConfigurationTarget.FOLDER, target.args[0][0]); + assert.equal(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]); }); }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts index 7b783062321..f070654bb3a 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts @@ -25,7 +25,6 @@ suite('MainThreadDocumentsAndEditors', () => { let codeEditorService: MockCodeEditorService; let textFileService: ITextFileService; let workbenchEditorService: IWorkbenchEditorService; - let documentAndEditor: MainThreadDocumentsAndEditors; let deltas: IDocumentsAndEditorsDelta[] = []; const hugeModelString = new Array(2 + (50 * 1024 * 1024)).join('-'); @@ -36,7 +35,7 @@ suite('MainThreadDocumentsAndEditors', () => { modelService = new ModelServiceImpl(null, configService); codeEditorService = new MockCodeEditorService(); textFileService = new class extends mock() { - isDirty() { return false; }; + isDirty() { return false; } models = { onModelSaved: Event.None, onModelReverted: Event.None, @@ -49,10 +48,10 @@ suite('MainThreadDocumentsAndEditors', () => { }; const editorGroupService = new class extends mock() { onEditorsChanged = Event.None; - onEditorsMoved = Event.None; + onEditorGroupMoved = Event.None; }; - documentAndEditor = new MainThreadDocumentsAndEditors( + new MainThreadDocumentsAndEditors( OneGetThreadService(new class extends mock() { $acceptDocumentsAndEditorsDelta(delta) { deltas.push(delta); } }), diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts new file mode 100644 index 00000000000..ab9454d1177 --- /dev/null +++ b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts @@ -0,0 +1,112 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors'; +import { OneGetThreadService, TestThreadService } from './testThreadService'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; +import { MockCodeEditorService } from 'vs/editor/test/common/mocks/mockCodeEditorService'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ExtHostDocumentsAndEditorsShape, IWorkspaceResourceEdit, ExtHostContext, ExtHostDocumentsShape } from 'vs/workbench/api/node/extHost.protocol'; +import { mock } from 'vs/workbench/test/electron-browser/api/mock'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import Event from 'vs/base/common/event'; +import { MainThreadEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors'; +import URI from 'vs/base/common/uri'; +import { Range } from 'vs/editor/common/core/range'; +import { Position } from 'vs/editor/common/core/position'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { EditOperation } from 'vs/editor/common/core/editOperation'; + +suite('MainThreadEditors', () => { + + const resource = URI.parse('foo:bar'); + + let modelService: IModelService; + let editors: MainThreadEditors; + + setup(() => { + const configService = new TestConfigurationService(); + modelService = new ModelServiceImpl(null, configService); + const codeEditorService = new MockCodeEditorService(); + const textFileService = new class extends mock() { + isDirty() { return false; } + models = { + onModelSaved: Event.None, + onModelReverted: Event.None, + onModelDirty: Event.None, + }; + }; + const workbenchEditorService = { + getVisibleEditors() { return []; }, + getActiveEditor() { return undefined; } + }; + const editorGroupService = new class extends mock() { + onEditorsChanged = Event.None; + onEditorGroupMoved = Event.None; + }; + + const testThreadService = new TestThreadService(true); + testThreadService.setTestInstance(ExtHostContext.ExtHostDocuments, new class extends mock() { + $acceptModelChanged(): void { + } + }); + testThreadService.setTestInstance(ExtHostContext.ExtHostDocumentsAndEditors, new class extends mock() { + $acceptDocumentsAndEditorsDelta(): void { + } + }); + + const documentAndEditor = new MainThreadDocumentsAndEditors( + testThreadService, + modelService, + textFileService, + workbenchEditorService, + codeEditorService, + null, + null, + null, + null, + editorGroupService, + null + ); + + editors = new MainThreadEditors( + documentAndEditor, + OneGetThreadService(null), + codeEditorService, + workbenchEditorService, + editorGroupService, + null, + null, + null, + modelService + ); + }); + + test(`applyWorkspaceEdit returns false if model is changed by user`, () => { + + let model = modelService.createModel('something', null, resource); + + let workspaceResourceEdit: IWorkspaceResourceEdit = { + resource: resource, + modelVersionId: model.getVersionId(), + edits: [{ + newText: 'asdfg', + range: new Range(1, 1, 1, 1) + }] + }; + + // Act as if the user edited the model + model.applyEdits([EditOperation.insert(new Position(0, 0), 'something')]); + + return editors.$tryApplyWorkspaceEdit([workspaceResourceEdit]).then((result) => { + assert.equal(result, false); + }); + }); +}); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts index 35fc82deda8..e3e90a945e4 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { FinalNewLineParticipant } from 'vs/workbench/api/electron-browser/mainThreadSaveParticipant'; +import { FinalNewLineParticipant, TrimFinalNewLinesParticipant } from 'vs/workbench/api/electron-browser/mainThreadSaveParticipant'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { workbenchInstantiationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices'; import { toResource } from 'vs/base/test/common/utils'; @@ -72,4 +72,44 @@ suite('MainThreadSaveParticipant', function () { done(); }); }); + + test('trim final new lines', function (done) { + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8'); + + model.load().then(() => { + const configService = new TestConfigurationService(); + configService.setUserConfiguration('files', { 'trimFinalNewlines': true }); + + const participant = new TrimFinalNewLinesParticipant(configService, undefined); + + const textContent = 'Trim New Line'; + const eol = `${model.textEditorModel.getEOL()}`; + + // No new line removal if last line is not new line + let lineContent = `${textContent}`; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), lineContent); + + // No new line removal if last line is single new line + lineContent = `${textContent}${eol}`; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), lineContent); + + // Remove new line (single line with two new lines) + lineContent = `${textContent}${eol}${eol}`; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), `${textContent}${eol}`); + + // Remove new lines (multiple lines with multiple new lines) + lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), `${textContent}${eol}${textContent}${eol}`); + + done(); + }); + }); }); diff --git a/src/vs/workbench/test/electron-browser/api/mock.ts b/src/vs/workbench/test/electron-browser/api/mock.ts index 622f52cade3..9e8c56e11bc 100644 --- a/src/vs/workbench/test/electron-browser/api/mock.ts +++ b/src/vs/workbench/test/electron-browser/api/mock.ts @@ -10,5 +10,5 @@ export interface Ctor { } export function mock(): Ctor { - return function () { }; + return function () { } as any; } diff --git a/src/vs/workbench/test/electron-browser/api/testThreadService.ts b/src/vs/workbench/test/electron-browser/api/testThreadService.ts index 5e988c1bd38..901935ee7a9 100644 --- a/src/vs/workbench/test/electron-browser/api/testThreadService.ts +++ b/src/vs/workbench/test/electron-browser/api/testThreadService.ts @@ -76,8 +76,8 @@ export abstract class AbstractTestThreadService { } export class TestThreadService extends AbstractTestThreadService implements IThreadService { - constructor() { - super(false); + constructor(isMainProcess: boolean = false) { + super(isMainProcess); } private _callCountValue: number = 0; diff --git a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts index e9348ede436..e0fc023cb81 100644 --- a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts @@ -7,16 +7,17 @@ import 'vs/workbench/parts/search/browser/search.contribution'; // load contributions import * as assert from 'assert'; -import { IWorkspaceContextService, LegacyWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ISearchService } from 'vs/platform/search/common/search'; import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; +import { IExperimentService, IExperiments } from 'vs/platform/telemetry/common/experiments'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import * as minimist from 'minimist'; import * as path from 'path'; -import { QuickOpenHandler, IQuickOpenRegistry, Extensions } from 'vs/workbench/browser/quickopen'; +import { IQuickOpenRegistry, Extensions } from 'vs/workbench/browser/quickopen'; import { Registry } from 'vs/platform/registry/common/platform'; import { SearchService } from 'vs/workbench/services/search/node/searchService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -29,6 +30,7 @@ import { SimpleConfigurationService } from 'vs/editor/standalone/browser/simpleS import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { IModelService } from 'vs/editor/common/services/modelService'; +import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; namespace Timer { export interface ITimerEvent { @@ -56,7 +58,7 @@ suite('QuickOpen performance (integration)', () => { test('Measure', () => { if (process.env['VSCODE_PID']) { - return; // TODO@Christoph find out why test fails when run from within VS Code + return void 0; // TODO@Christoph find out why test fails when run from within VS Code } const n = 3; @@ -66,12 +68,14 @@ suite('QuickOpen performance (integration)', () => { const testWorkspacePath = testWorkspaceArg ? path.resolve(testWorkspaceArg) : __dirname; const telemetryService = new TestTelemetryService(); + const experimentService = new TestExperimentService(); const configurationService = new SimpleConfigurationService(); const instantiationService = new InstantiationService(new ServiceCollection( [ITelemetryService, telemetryService], + [IExperimentService, experimentService], [IConfigurationService, configurationService], [IModelService, new ModelServiceImpl(null, configurationService)], - [IWorkspaceContextService, new TestContextService(new LegacyWorkspace(URI.file(testWorkspacePath)))], + [IWorkspaceContextService, new TestContextService(testWorkspace(URI.file(testWorkspacePath)))], [IWorkbenchEditorService, new TestEditorService()], [IEditorGroupService, new TestEditorGroupService()], [IEnvironmentService, TestEnvironmentService], @@ -84,35 +88,33 @@ suite('QuickOpen performance (integration)', () => { assert.ok(descriptor); function measure() { - return instantiationService.createInstance(descriptor) - .then((handler: QuickOpenHandler) => { - handler.onOpen(); - return handler.getResults('a').then(result => { - const uncachedEvent = popEvent(); - assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache'); - assert.strictEqual(uncachedEvent.data.files.fromCache, true, 'files.fromCache'); - if (testWorkspaceArg) { - assert.ok(!!uncachedEvent.data.files.joined, 'files.joined'); - } - return uncachedEvent; - }).then(uncachedEvent => { - return handler.getResults('ab').then(result => { - const cachedEvent = popEvent(); - assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache'); - assert.ok(cachedEvent.data.files.fromCache, 'filesFromCache'); - handler.onClose(false); - return [uncachedEvent, cachedEvent]; - }); - }); + const handler = descriptor.instantiate(instantiationService); + handler.onOpen(); + return handler.getResults('a').then(result => { + const uncachedEvent = popEvent(); + assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache'); + assert.strictEqual(uncachedEvent.data.files.fromCache, true, 'files.fromCache'); + if (testWorkspaceArg) { + assert.ok(!!uncachedEvent.data.files.joined, 'files.joined'); + } + return uncachedEvent; + }).then(uncachedEvent => { + return handler.getResults('ab').then(result => { + const cachedEvent = popEvent(); + assert.strictEqual(uncachedEvent.data.symbols.fromCache, false, 'symbols.fromCache'); + assert.ok(cachedEvent.data.files.fromCache, 'filesFromCache'); + handler.onClose(false); + return [uncachedEvent, cachedEvent]; }); + }); } function popEvent() { - const events = telemetryService.events; + const events = telemetryService.events + .filter(event => event.name === 'openAnything'); assert.strictEqual(events.length, 1); const event = events[0]; - events.length = 0; - assert.strictEqual(event.name, 'openAnything'); + telemetryService.events.length = 0; return event; } @@ -176,4 +178,13 @@ class TestTelemetryService implements ITelemetryService { machineId: 'someValue.machineId' }); } -}; +} + +class TestExperimentService implements IExperimentService { + + _serviceBrand: any; + + getExperiments(): IExperiments { + return {}; + } +} diff --git a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts index b5b53cf077e..056f00fdbd0 100644 --- a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts @@ -8,7 +8,7 @@ import 'vs/workbench/parts/search/browser/search.contribution'; // load contributions import * as assert from 'assert'; import * as fs from 'fs'; -import { IWorkspaceContextService, LegacyWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ISearchService, IQueryOptions } from 'vs/platform/search/common/search'; @@ -33,6 +33,7 @@ import { SearchModel } from 'vs/workbench/parts/search/common/searchModel'; import { QueryBuilder } from 'vs/workbench/parts/search/common/queryBuilder'; import Event, * as event from 'vs/base/common/event'; +import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; declare var __dirname: string; @@ -61,7 +62,7 @@ suite('TextSearch performance (integration)', () => { [ITelemetryService, telemetryService], [IConfigurationService, configurationService], [IModelService, new ModelServiceImpl(null, configurationService)], - [IWorkspaceContextService, new TestContextService(new LegacyWorkspace(URI.file(testWorkspacePath)))], + [IWorkspaceContextService, new TestContextService(testWorkspace(URI.file(testWorkspacePath)))], [IWorkbenchEditorService, new TestEditorService()], [IEditorGroupService, new TestEditorGroupService()], [IEnvironmentService, TestEnvironmentService], @@ -165,4 +166,4 @@ class TestTelemetryService implements ITelemetryService { machineId: 'someValue.machineId' }); } -}; +} diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index ad8c2bbd521..69e54166d53 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -15,7 +15,7 @@ import URI from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { StorageService, InMemoryLocalStorage } from 'vs/platform/storage/common/storageService'; -import { IEditorGroup, ConfirmResult } from 'vs/workbench/common/editor'; +import { IEditorGroup, ConfirmResult, IEditorOpeningEvent } from 'vs/workbench/common/editor'; import Event, { Emitter } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -24,17 +24,17 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput, ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput } from 'vs/platform/editor/common/editor'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; -import { ILegacyWorkspace, IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IMessageService, IConfirmation, IConfirmationResult, IChoiceService } from 'vs/platform/message/common/message'; +import { IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; -import { IEditorGroupService, GroupArrangement, GroupOrientation, ITabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService'; +import { IEditorGroupService, GroupArrangement, GroupOrientation, IEditorTabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService'; import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService'; -import { FileOperationEvent, IFileService, IResolveContentOptions, FileOperationError, IFileStat, IResolveFileResult, IImportResult, FileChangesEvent, IResolveFileOptions, IContent, IUpdateContentOptions, IStreamContent } from 'vs/platform/files/common/files'; +import { FileOperationEvent, IFileService, IResolveContentOptions, FileOperationError, IFileStat, IResolveFileResult, IImportResult, FileChangesEvent, IResolveFileOptions, IContent, IUpdateContentOptions, IStreamContent, ICreateFileOptions } from 'vs/platform/files/common/files'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; @@ -44,9 +44,9 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ import { IModeService } from 'vs/editor/common/services/modeService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { IWindowsService, IWindowService, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows'; +import { IWindowsService, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult } from 'vs/platform/windows/common/windows'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { RawTextSource, IRawTextSource } from 'vs/editor/common/model/textSource'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -54,8 +54,13 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { isLinux } from 'vs/base/common/platform'; import { generateUuid } from 'vs/base/common/uuid'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; -import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IRecentlyOpened } from 'vs/platform/history/common/history'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { IPosition } from 'vs/editor/common/core/position'; +import { ICommandAction } from 'vs/platform/actions/common/actions'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; +import { notImplemented } from 'vs/base/common/errors'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, void 0); @@ -67,53 +72,53 @@ export class TestContextService implements IWorkspaceContextService { public _serviceBrand: any; private workspace: IWorkbenchWorkspace; - private id: string; private options: any; private _onDidChangeWorkspaceName: Emitter; - private _onDidChangeWorkspaceRoots: Emitter; + private _onDidChangeWorkspaceFolders: Emitter; + private _onDidChangeWorkbenchState: Emitter; constructor(workspace: any = TestWorkspace, options: any = null) { this.workspace = workspace; - this.id = generateUuid(); this.options = options || Object.create(null); - this._onDidChangeWorkspaceRoots = new Emitter(); + this._onDidChangeWorkspaceFolders = new Emitter(); + this._onDidChangeWorkbenchState = new Emitter(); } public get onDidChangeWorkspaceName(): Event { return this._onDidChangeWorkspaceName.event; } - public get onDidChangeWorkspaceRoots(): Event { - return this._onDidChangeWorkspaceRoots.event; + public get onDidChangeWorkspaceFolders(): Event { + return this._onDidChangeWorkspaceFolders.event; } - public getFolders(): URI[] { - return this.workspace ? this.workspace.roots : []; + public get onDidChangeWorkbenchState(): Event { + return this._onDidChangeWorkbenchState.event; } - public hasWorkspace(): boolean { - return !!this.workspace; + public getFolders(): IWorkspaceFolder[] { + return this.workspace ? this.workspace.folders : []; } - public hasFolderWorkspace(): boolean { - return this.workspace && !this.workspace.configuration; - } + public getWorkbenchState(): WorkbenchState { + if (this.workspace.configuration) { + return WorkbenchState.WORKSPACE; + } - public hasMultiFolderWorkspace(): boolean { - return this.workspace && !!this.workspace.configuration; - } + if (this.workspace.folders.length) { + return WorkbenchState.FOLDER; + } - public getLegacyWorkspace(): ILegacyWorkspace { - return this.workspace ? { resource: this.workspace.roots[0] } : void 0; + return WorkbenchState.EMPTY; } public getWorkspace(): IWorkbenchWorkspace { return this.workspace; } - public getRoot(resource: URI): URI { - return this.isInsideWorkspace(resource) ? this.workspace.roots[0] : null; + public getWorkspaceFolder(resource: URI): IWorkspaceFolder { + return this.isInsideWorkspace(resource) ? this.workspace.folders[0] : null; } public setWorkspace(workspace: any): void { @@ -130,7 +135,7 @@ export class TestContextService implements IWorkspaceContextService { public isInsideWorkspace(resource: URI): boolean { if (resource && this.workspace) { - return paths.isEqualOrParent(resource.fsPath, this.workspace.roots[0].fsPath, !isLinux /* ignorecase */); + return paths.isEqualOrParent(resource.fsPath, this.workspace.folders[0].uri.fsPath, !isLinux /* ignorecase */); } return false; @@ -139,6 +144,19 @@ export class TestContextService implements IWorkspaceContextService { public toResource(workspaceRelativePath: string): URI { return URI.file(paths.join('C:\\', workspaceRelativePath)); } + + public isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean { + return isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && this.pathEquals(this.workspace.folders[0].uri.fsPath, workspaceIdentifier); + } + + private pathEquals(path1: string, path2: string): boolean { + if (!isLinux) { + path1 = path1.toLowerCase(); + path2 = path2.toLowerCase(); + } + + return path1 === path2; + } } export class TestTextFileService extends TextFileService { @@ -207,8 +225,8 @@ export class TestTextFileService extends TextFileService { return this.confirmResult; } - public onConfigurationChange(configuration: any): void { - super.onConfigurationChange(configuration); + public onFilesConfigurationChange(configuration: any): void { + super.onFilesConfigurationChange(configuration); } protected cleanupBackupsBeforeShutdown(): TPromise { @@ -220,7 +238,9 @@ export class TestTextFileService extends TextFileService { export function workbenchInstantiationService(): IInstantiationService { let instantiationService = new TestInstantiationService(new ServiceCollection([ILifecycleService, new TestLifecycleService()])); instantiationService.stub(IWorkspaceContextService, new TestContextService(TestWorkspace)); - instantiationService.stub(IConfigurationService, new TestConfigurationService()); + const configService = new TestConfigurationService(); + instantiationService.stub(IConfigurationService, configService); + instantiationService.stub(ITextResourceConfigurationService, new TestTextResourceConfigurationService(configService)); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); instantiationService.stub(IWorkbenchEditorService, new TestEditorService()); @@ -239,6 +259,12 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); instantiationService.stub(IEnvironmentService, TestEnvironmentService); instantiationService.stub(IThemeService, new TestThemeService()); + instantiationService.stub(IHashService, new TestHashService()); + instantiationService.stub(IChoiceService, { + choose: (severity, message, options, cancelId): TPromise => { + return TPromise.as(cancelId); + } + }); return instantiationService; } @@ -253,15 +279,15 @@ export class TestHistoryService implements IHistoryService { public reopenLastClosedEditor(): void { } - public add(input: IEditorInput, options?: ITextEditorOptions): void { - } - public forward(acrossEditors?: boolean): void { } public back(acrossEditors?: boolean): void { } + public last(): void { + } + public remove(input: IEditorInput | IResourceInput): void { } @@ -272,12 +298,17 @@ export class TestHistoryService implements IHistoryService { return []; } - public getLastActiveWorkspaceRoot(): URI { + public getLastActiveWorkspaceRoot(schemeFilter?: string): URI { return this.root; } + + public getLastActiveFile(): URI { + return void 0; + } } export class TestMessageService implements IMessageService { + public _serviceBrand: any; private counter: number; @@ -300,9 +331,13 @@ export class TestMessageService implements IMessageService { // No-op } - public confirm(confirmation: IConfirmation): boolean { + public confirmSync(confirmation: IConfirmation): boolean { return false; } + + public confirm(confirmation: IConfirmation): Promise { + return TPromise.as({ confirmed: false }); + } } export class TestPartService implements IPartService { @@ -326,10 +361,6 @@ export class TestPartService implements IPartService { return true; } - public joinCreation(): Promise { - return TPromise.as(null); - } - public hasFocus(part): boolean { return false; } @@ -382,6 +413,10 @@ export class TestPartService implements IPartService { return 0; } + public getPanelPosition() { + return 0; + } + public addClass(clazz: string): void { } public removeClass(clazz: string): void { } public getWorkbenchElementId(): string { return ''; } @@ -430,17 +465,19 @@ export class TestEditorGroupService implements IEditorGroupService { private stacksModel: EditorStacksModel; private _onEditorsChanged: Emitter; + private _onEditorOpening: Emitter; private _onEditorOpenFail: Emitter; private _onEditorsMoved: Emitter; private _onGroupOrientationChanged: Emitter; - private _onTabOptionsChanged: Emitter; + private _onTabOptionsChanged: Emitter; constructor(callback?: (method: string) => void) { this._onEditorsMoved = new Emitter(); this._onEditorsChanged = new Emitter(); + this._onEditorOpening = new Emitter(); this._onGroupOrientationChanged = new Emitter(); this._onEditorOpenFail = new Emitter(); - this._onTabOptionsChanged = new Emitter(); + this._onTabOptionsChanged = new Emitter(); let services = new ServiceCollection(); @@ -464,11 +501,15 @@ export class TestEditorGroupService implements IEditorGroupService { return this._onEditorsChanged.event; } + public get onEditorOpening(): Event { + return this._onEditorOpening.event; + } + public get onEditorOpenFail(): Event { return this._onEditorOpenFail.event; } - public get onEditorsMoved(): Event { + public get onEditorGroupMoved(): Event { return this._onEditorsMoved.event; } @@ -476,7 +517,7 @@ export class TestEditorGroupService implements IEditorGroupService { return this._onGroupOrientationChanged.event; } - public get onTabOptionsChanged(): Event { + public get onTabOptionsChanged(): Event { return this._onTabOptionsChanged.event; } @@ -533,9 +574,13 @@ export class TestEditorGroupService implements IEditorGroupService { return this.stacksModel; } - public getTabOptions(): ITabOptions { + public getTabOptions(): IEditorTabOptions { return {}; } + + public invokeWithinEditorContext(fn: (accessor: ServicesAccessor) => T): T { + return fn(null); + } } export class TestEditorService implements IWorkbenchEditorService { @@ -735,7 +780,7 @@ export class TestFileService implements IFileService { return TPromise.as(null); } - createFile(resource: URI, content?: string): TPromise { + createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise { return TPromise.as(null); } @@ -830,7 +875,7 @@ export class TestBackupFileService implements IBackupFileService { public discardAllWorkspaceBackups(): TPromise { return TPromise.as(void 0); } -}; +} export class TestWindowService implements IWindowService { @@ -858,6 +903,10 @@ export class TestWindowService implements IWindowService { return TPromise.as(void 0); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + return TPromise.as(void 0); + } + reloadWindow(): TPromise { return TPromise.as(void 0); } @@ -874,15 +923,11 @@ export class TestWindowService implements IWindowService { return TPromise.as(void 0); } - openWorkspace(): TPromise { + createAndEnterWorkspace(folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { return TPromise.as(void 0); } - createAndOpenWorkspace(folders?: string[], path?: string): TPromise { - return TPromise.as(void 0); - } - - saveAndOpenWorkspace(path: string): TPromise { + saveAndEnterWorkspace(path: string): TPromise { return TPromise.as(void 0); } @@ -930,10 +975,14 @@ export class TestWindowService implements IWindowService { return TPromise.as(void 0); } - showMessageBox(options: Electron.ShowMessageBoxOptions): number { + showMessageBoxSync(options: Electron.MessageBoxOptions): number { return 0; } + showMessageBox(options: Electron.MessageBoxOptions): Promise { + return TPromise.as(void 0); + } + showSaveDialog(options: Electron.SaveDialogOptions, callback?: (fileName: string) => void): string { return void 0; } @@ -941,6 +990,10 @@ export class TestWindowService implements IWindowService { showOpenDialog(options: Electron.OpenDialogOptions, callback?: (fileNames: string[]) => void): string[] { return void 0; } + + updateTouchBar(items: ICommandAction[][]): Promise { + return TPromise.as(void 0); + } } export class TestLifecycleService implements ILifecycleService { @@ -950,10 +1003,12 @@ export class TestLifecycleService implements ILifecycleService { public phase: LifecyclePhase; public startupKind: StartupKind; - private _onDidChangePhase = new Emitter(); private _onWillShutdown = new Emitter(); private _onShutdown = new Emitter(); + when(): Thenable { + throw notImplemented(); + } public fireShutdown(reason = ShutdownReason.QUIT): void { this._onShutdown.fire(reason); @@ -963,10 +1018,6 @@ export class TestLifecycleService implements ILifecycleService { this._onWillShutdown.fire(event); } - public get onDidChangePhase(): Event { - return this._onDidChangePhase.event; - } - public get onWillShutdown(): Event { return this._onWillShutdown.event; } @@ -1002,6 +1053,10 @@ export class TestWindowsService implements IWindowsService { return TPromise.as(void 0); } + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise { + return TPromise.as(void 0); + } + reloadWindow(windowId: number): TPromise { return TPromise.as(void 0); } @@ -1018,15 +1073,11 @@ export class TestWindowsService implements IWindowsService { return TPromise.as(void 0); } - openWorkspace(windowId: number): TPromise { + createAndEnterWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], path?: string): TPromise { return TPromise.as(void 0); } - createAndOpenWorkspace(windowId: number, folders?: string[], path?: string): TPromise { - return TPromise.as(void 0); - } - - saveAndOpenWorkspace(windowId: number, path: string): TPromise { + saveAndEnterWorkspace(windowId: number, path: string): TPromise { return TPromise.as(void 0); } @@ -1127,6 +1178,30 @@ export class TestWindowsService implements IWindowsService { return TPromise.as(void 0); } + showPreviousWindowTab(): Promise { + return TPromise.as(void 0); + } + + showNextWindowTab(): Promise { + return TPromise.as(void 0); + } + + moveWindowTabToNewWindow(): Promise { + return TPromise.as(void 0); + } + + mergeAllWindowTabs(): Promise { + return TPromise.as(void 0); + } + + toggleWindowTabsBar(): Promise { + return TPromise.as(void 0); + } + + updateTouchBar(windowId: number, items: ICommandAction[][]): Promise { + return TPromise.as(void 0); + } + // This needs to be handled from browser process to prevent // foreground ordering issues on Windows openExternal(url: string): TPromise { @@ -1139,3 +1214,33 @@ export class TestWindowsService implements IWindowsService { } } +export class TestTextResourceConfigurationService implements ITextResourceConfigurationService { + + _serviceBrand: any; + + constructor(private configurationService = new TestConfigurationService()) { + } + + public onDidChangeConfiguration() { + return { dispose() { } }; + } + + public getConfiguration(resource: URI, section?: string): any; + public getConfiguration(resource: URI, position?: IPosition, section?: string): any; + public getConfiguration(resource: any, position?: any, section?: any): any; + public getConfiguration(resource: any, position?: any, section?: any): any { + return this.configurationService.getConfiguration(section, { resource }); + } +} + +export class TestHashService implements IHashService { + _serviceBrand: any; + + createSHA1(content: string): string { + return content; + } +} + +export function getRandomTestPath(tmpdir: string, ...segments: string[]): string { + return paths.join(tmpdir, ...segments, generateUuid()); +} diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index d9c253d4709..bfd4680bc86 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -9,6 +9,9 @@ import 'vs/base/common/strings'; import 'vs/base/common/errors'; +// Configuration +import 'vs/workbench/services/configuration/common/configurationExtensionPoint'; + // Editor import 'vs/editor/editor.all'; @@ -16,7 +19,7 @@ import 'vs/editor/editor.all'; import 'vs/platform/actions/electron-browser/menusExtensionPoint'; // Views -import 'vs/workbench/parts/views/browser/viewsExtensionPoint'; +import 'vs/workbench/api/browser/viewsExtensionPoint'; // Workbench import 'vs/workbench/browser/actions/toggleActivityBarVisibility'; @@ -25,9 +28,9 @@ import 'vs/workbench/browser/actions/toggleSidebarVisibility'; import 'vs/workbench/browser/actions/toggleSidebarPosition'; import 'vs/workbench/browser/actions/toggleEditorLayout'; import 'vs/workbench/browser/actions/toggleZenMode'; +import 'vs/workbench/browser/actions/toggleTabsVisibility'; import 'vs/workbench/parts/preferences/browser/preferences.contribution'; import 'vs/workbench/parts/preferences/browser/keybindingsEditorContribution'; -import 'vs/workbench/browser/actions/configureLocale'; import 'vs/workbench/browser/parts/quickopen/quickopen.contribution'; import 'vs/workbench/parts/quickopen/browser/quickopen.contribution'; @@ -73,6 +76,7 @@ import 'vs/workbench/parts/terminal/browser/terminalQuickOpen'; import 'vs/workbench/parts/terminal/electron-browser/terminalPanel'; // can be packaged separately import 'vs/workbench/electron-browser/workbench'; +import 'vs/workbench/electron-browser/configureLocale'; import 'vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution'; @@ -89,6 +93,9 @@ import 'vs/workbench/parts/codeEditor/codeEditor.contribution'; import 'vs/workbench/parts/execution/electron-browser/execution.contribution'; import 'vs/workbench/parts/snippets/electron-browser/snippets.contribution'; +import 'vs/workbench/parts/snippets/electron-browser/snippetsService'; +import 'vs/workbench/parts/snippets/electron-browser/insertSnippet'; +import 'vs/workbench/parts/snippets/electron-browser/tabCompletion'; import 'vs/workbench/parts/themes/electron-browser/themes.contribution'; diff --git a/test/mocha.opts b/test/mocha.opts index a89ace4fc9d..d6b09ce6e07 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -2,4 +2,3 @@ --ui tdd --timeout 10000 test/all.js -extensions/*/server/out/test/*.test.js diff --git a/test/smoke/README.md b/test/smoke/README.md index a22a039e95e..48e4cd60acd 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -1,61 +1,46 @@ -# VS Code Smoke Testing - -``` -npm rum smoketest -- "path/to/code" -``` - -If you want to include 'Data Migration' area tests use: - -``` -npm run smoketest -- "path/to/code" "path/to/codeStable" -``` - -Detailed prerequisites and running steps are described [in our smoke test wiki](https://github.com/Microsoft/vscode/wiki/Smoke-Test#automated-smoke-test). - -# Architecture -* `main.js` is used to prepare all smoke test dependencies (fetching key bindings and 'Express' repository, running `npm install` there). -* `mocha-runner.js` launches Mocha programmatically. It is spawned in Node environment from main.js to ensure that it is possible to listen on `stderr`s (primary `process.stderr` is not readable otherwise). This is accomplished because WebDriverIO command deprecation warnings need to be redirected to a separate log. Those warnings are coming from WebDriverIO because ChromeDriver has not migrated from JsonWire to W3C WebDriver protocol. -* `test.ts` contains the main smoke test suite calling the tests that are bundled in areas and defined in `./tests/`. It includes all tests separated into mocha `describe()` groups that represent each of the areas of [Smoke Test document](https://github.com/Microsoft/vscode/wiki/Smoke-Test). - -* `./areas/` folder contains a `.ts` file per each area of the document. E.g. `'Search'` area goes under `'search.ts'`. Every area file contains a list of methods with the name that represents the action that can be performed in the corresponding test. This reduces the amount of test suite code and means that if the UI changes, the fix need only be applied in one place. The name of the method reflects the action the tester would do if he would perform the test manually. See [Selenium Page Objects Wiki](https://github.com/SeleniumHQ/selenium/wiki/PageObjects) and [Selenium Bot Style Tests Wiki](https://github.com/SeleniumHQ/selenium/wiki/Bot-Style-Tests) for a good explanation of the implementation. Every smoke test area contains methods that are used in a bot-style approach in `main.ts`. -* `./spectron/` wraps the Spectron, with WebDriverIO API wrapped in `client.ts` and instance of Spectron Application is wrapped in `application.ts`. - -* `./test_data/` folder contains temporary data used by smoke test (cloned express repository, temporary user-data-dir/extensions-dir). -* `./test_data/screenshots` has action screenshots captured by a smoke test when performing actions during runtime. Screenshots are split in folders per each test. - -# Adding new area -To contribute a new smoke test area, add `${area}.ts` file under `./areas/`. All related tests to the area should go to the alike named file under `./tests/${area}.ts`. This has to follow the bot-style approach described in the links mentioned above. Methods should be calling WebDriverIO API through `SpectronClient` class. If there is no existing WebDriverIO method, add it to the class. - -# Adding new test -To add new test, `./test/${area}.ts` should be updated. The same instruction-style principle needs to be followed with the called area method names that reflect manual tester's actions. - -# Debugging -1. Add the following configuration to launch.json, specifying binaries in `args`: -```json -{ - "type": "node", - "request": "launch", - "name": "Launch Smoke Test", - "program": "${workspaceRoot}/test/smoke/out/main.js", - "cwd": "${workspaceRoot}/test/smoke", - "timeout": 240000, - "port": 9999, - "args": [ - "-l", - "path/to/Code.exe" - ], - "outFiles": [ - "${cwd}/out/**/*.js" - ] -} -``` -2. In main.js add `--debug-brk=9999` as a first argument to the place where `out/mocha-runner.js` is spawned. - -# Screenshots -Almost on every automated test action it captures a screenshot. These help to determine an issue, if smoke test fails. The normal workflow is that you understand what code is doing and then try to match it up with screenshots obtained from the test. - -# Running "Out of Sources" +# VS Code Smoke Test + +## How to run ``` +# Dev npm run smoketest -``` \ No newline at end of file + +# Specific build +npm run smoketest -- --build "path/to/code" + +# Data Migration tests +npm run smoketest -- --build "path/to/code-insiders" --stable "path/to/code" +``` + +The script calls mocha, so all mocha arguments should work fine. For example, use `-f Git` to only run the `Git` tests. + +By default, screenshots are not captured. To run tests with screenshots use the argument `--screenshots`. + +## Pitfalls + +- Beware of **state**. The tests within a single suite will share the same state. + +- Beware of **singletons**. This evil can, and will, manifest itself under the form of FS paths, TCP ports, IPC handles. Whenever writing a test, or setting up more smoke test architecture, make sure it can run simultaneously with any other tests and even itself. All test suites should be able to run many times in parallel. + +- Beware of **focus**. **Never** depend on DOM elements having focus using `.focused` classes or `:focus` pseudo-classes, since they will lose that state as soon as another window appears on top of the running VS Code window. A safe approach which avoids this problem is to use the `waitForActiveElement` API. Many tests use this whenever they need to wait for a specific element to _have focus_. + +- Beware of **timing**. You need to read from or write to the DOM... yeah I know. But is it the right time to do that? Can you 100% promise that that `input` box will be visible and in the DOM at this point in time? Or are you just hoping that it will be so? Every time you want to interact with the DOM, be absolutely sure that you can. Eg. just because you triggered Quick Open, it doesn't mean that it's open; you must wait for the widget to be in the DOM and for its input field to be the active element. + +- Beware of **waiting**. **Never** wait longer than a couple of seconds for anything, unless it's justified. Think of it as a human using Code. Would a human take 10 minutes to run through the Search viewlet smoke test? Then, the computer should even be faster. **Don't** use `setTimeout` just because. Think about what you should wait for in the DOM to be ready, then wait for that instead. + +## Common Issues + +### Certain keys don't appear in input boxes (eg: Space) + +This is a **waiting** issue. Everytime you send keys to Code, you must be aware that the keybinding service can handle them. Even if you're sure that input box is focused. + +Here's an example: when opening quick open, focus goes from its list to its input. We used to simply wait for the input to have focus and then send some text to be typed, like `Workbench: Show Editor`; yet, only `Workbench:ShowEditor` would be rendered in the input box. This happened due to the fact that the [`ListService` takes 50ms to unset the context key which indicates a list is focused](https://github.com/Microsoft/vscode/blob/c8dee4c016d3a3d475011106e04d8e394d9f138c/src/vs/platform/list/browser/listService.ts#L59). The fix was to [wait 50ms as well on the smoke test](https://github.com/Microsoft/vscode/blob/b82fa8dcb06bbf9c85c1502d0d43322e2e9d1a59/test/smoke/src/areas/quickopen/quickopen.ts#L65). + +### I type in a Monaco editor instance, but the text doesn't appear to be there + +This is a **waiting** issue. When you type in a Monaco editor instance, you're really typing in a `textarea`. The `textarea` is then polled for its contents, then the editor model gets updated and finally the editor view gets updated. It's a good idea to always wait for the text to appear rendered in the editor after you type in it. + +### I type in a Monaco editor instance, but the text appears scrambled + +This is an issue which is **not yet fixed**. Unfortunately this seems to happen whenever the CPU load of the system is high. Rerunning the test will often result in a successful outcome. \ No newline at end of file diff --git a/test/smoke/package.json b/test/smoke/package.json index d7c28fc1f0e..97d8c0b3c3e 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -8,18 +8,23 @@ "mocha": "mocha" }, "devDependencies": { - "@types/electron": "~1.4.37", - "@types/htmlparser2": "^3.7.29", - "@types/mkdirp": "^0.5.1", - "@types/mocha": "^2.2.41", - "@types/node": "^8.0.26", - "@types/rimraf": "^0.0.28", - "@types/webdriverio": "^4.6.1", + "@types/htmlparser2": "3.7.29", + "@types/mkdirp": "0.5.1", + "@types/mocha": "2.2.41", + "@types/ncp": "2.0.1", + "@types/node": "8.0.33", + "@types/rimraf": "2.0.2", + "@types/webdriverio": "4.6.1", + "electron": "1.7.7", "htmlparser2": "^3.9.2", + "mkdirp": "^0.5.1", "mocha": "^3.2.0", + "ncp": "^2.0.0", + "portastic": "^1.0.1", "rimraf": "^2.6.1", - "spectron": "~3.6.4", + "spectron": "^3.7.2", "strip-json-comments": "^2.0.1", - "typescript": "^2.2.2" + "tmp": "0.0.33", + "typescript": "2.5.2" } } \ No newline at end of file diff --git a/test/smoke/src/areas/activitybar/activityBar.ts b/test/smoke/src/areas/activitybar/activityBar.ts index ada2cb9c5b6..894eef36f9f 100644 --- a/test/smoke/src/areas/activitybar/activityBar.ts +++ b/test/smoke/src/areas/activitybar/activityBar.ts @@ -9,7 +9,7 @@ import { SpectronApplication } from '../../spectron/application'; export enum ActivityBarPosition { LEFT = 0, RIGHT = 1 -}; +} export class ActivityBar { diff --git a/test/smoke/src/areas/common.ts b/test/smoke/src/areas/common.ts deleted file mode 100644 index 4a26579b604..00000000000 --- a/test/smoke/src/areas/common.ts +++ /dev/null @@ -1,211 +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 { SpectronApplication } from '../spectron/application'; -import { Util } from '../helpers/utilities'; - -/** - * Contains methods that are commonly used across test areas. - */ -export class CommonActions { - private util: Util; - - constructor(private spectron: SpectronApplication) { - this.util = new Util(); - } - - public async getWindowTitle(): Promise { - return this.spectron.client.getTitle(); - } - - public enter(): Promise { - return this.spectron.client.keys(['Enter', 'NULL']); - } - - public async addSetting(setting: string, value: string): Promise { - await this.openUserSettings(); - await this.spectron.client.keys(['ArrowDown', 'NULL'], false); - await this.spectron.client.waitForElement(`.editable-preferences-editor-container .monaco-editor.focused`); - await this.spectron.client.keys(['ArrowRight', 'NULL'], false); - await this.spectron.client.keys(`"${setting}": "${value}"`); - await this.saveOpenedFile(); - } - - public async openUserSettings(): Promise { - await this.spectron.command('workbench.action.openGlobalSettings'); - await this.spectron.client.waitForElement('.settings-search-input .synthetic-focus'); - } - - public async openKeybindings(): Promise { - await this.spectron.command('workbench.action.openGlobalKeybindings'); - await this.spectron.client.waitForElement('.settings-search-input .synthetic-focus'); - } - - public async newUntitledFile(): Promise { - await this.spectron.command('workbench.action.files.newUntitledFile'); - return this.spectron.wait(); - } - - public closeTab(): Promise { - return this.spectron.client.keys(['Control', 'w', 'NULL']); - } - - public async getTab(tabName: string, active?: boolean): Promise { - await this.closeCurrentNotification(); // close any notification messages that could overlap tabs - - let tabSelector = active ? '.tab.active' : 'div'; - let el = await this.spectron.client.waitForElement(`.tabs-container ${tabSelector}[aria-label="${tabName}, tab"]`); - if (el) { - return el; - } - - return undefined; - } - - public async selectTab(tabName: string): Promise { - await this.closeCurrentNotification(); // close any notification messages that could overlap tabs - await this.spectron.client.waitAndClick(`.tabs-container div[aria-selected="false"][aria-label="${tabName}, tab"]`); - await this.spectron.client.waitForElement(`.tabs-container div[aria-selected="true"][aria-label="${tabName}, tab"]`); - return this.waitForEditorFocus(); - } - - private async waitForEditorFocus(): Promise { - this.spectron.client.waitForElement(`.monaco-editor.focused`); - } - - public async openFirstMatchFile(fileName: string): Promise { - await this.openQuickOpen(); - await this.type(fileName); - await this.spectron.wait(); - await this.enter(); - return this.spectron.wait(); - } - - public async saveOpenedFile(): Promise { - try { - await this.spectron.client.waitForElement('.tabs-container .tab.active.dirty'); - } catch (e) { - // ignore if there is no dirty file - return Promise.resolve(); - } - await this.spectron.command('workbench.action.files.save'); - return this.spectron.client.waitForElement('.tabs-container .tab.active.dirty', element => !element); - } - - public type(text: string): Promise { - let spectron = this.spectron; - - return new Promise(function (res) { - let textSplit = text.split(' '); - - async function type(i: number) { - if (!textSplit[i] || textSplit[i].length <= 0) { - return res(); - } - - const toType = textSplit[i + 1] ? `${textSplit[i]} ` : textSplit[i]; - await spectron.client.keys(toType, false); - await spectron.client.keys(['NULL']); - await type(i + 1); - } - - return type(0); - }); - } - - public showCommands(): Promise { - return this.spectron.command('workbench.action.showCommands'); - } - - public openQuickOpen(): Promise { - return this.spectron.command('workbench.action.quickOpen'); - } - - public closeQuickOpen(): Promise { - return this.spectron.command('workbench.action.closeQuickOpen'); - } - - public selectNextQuickOpenElement(): Promise { - return this.spectron.client.keys(['ArrowDown', 'NULL']); - } - - public async getQuickOpenElements(): Promise { - const elements = await this.spectron.waitFor(this.spectron.client.waitForElements, 'div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties .monaco-tree-row'); - return elements.value.length; - } - - public async openFile(fileName: string, explorer?: boolean): Promise { - let selector = `div[class="monaco-icon-label file-icon ${fileName}-name-file-icon ${this.getExtensionSelector(fileName)}`; - if (explorer) { - selector += ' explorer-item'; - } - selector += '"]'; - - try { - await this.spectron.client.doubleClickAndWait(selector); - await this.spectron.client.waitForElement(`.tabs-container div[aria-label="${fileName}, tab"]`); - await this.spectron.client.waitForElement(`.monaco-editor.focused`); - } catch (e) { - return Promise.reject(`Cannot fine ${fileName} in a viewlet.`); - } - } - - public getExtensionSelector(fileName: string): string { - const extension = fileName.split('.')[1]; - if (extension === 'js') { - return 'js-ext-file-icon javascript-lang-file-icon'; - } else if (extension === 'json') { - return 'json-ext-file-icon json-lang-file-icon'; - } else if (extension === 'md') { - return 'md-ext-file-icon markdown-lang-file-icon'; - } - - throw new Error('No class defined for this file extension'); - } - - public async getEditorFirstLinePlainText(): Promise { - const trials = 3; - let retry = 0; - let error; - - while (retry < trials) { - try { - const span = await this.spectron.client.getText('.view-lines span span'); - if (Array.isArray(span)) { - return span[0]; - } - - return span; - } catch (e) { - error = e; - retry++; - - if (retry < trials) { - await this.spectron.wait(); - } else { - error = e; - } - } - } - - return Promise.reject('Could not obtain text on the first line of an editor: ' + error); - } - - public removeFile(filePath: string): void { - this.util.removeFile(filePath); - } - - public removeDirectory(directory: string): Promise { - try { - return this.util.rimraf(directory); - } catch (e) { - throw new Error(`Failed to remove ${directory} with an error: ${e}`); - } - } - - private closeCurrentNotification(): Promise { - return this.spectron.command('workbench.action.closeMessages'); - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/css.ts b/test/smoke/src/areas/css.ts deleted file mode 100644 index 95a0a6e952e..00000000000 --- a/test/smoke/src/areas/css.ts +++ /dev/null @@ -1,62 +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 { SpectronApplication } from '../spectron/application'; - -export enum CSSProblem { - WARNING = 0, - ERROR = 1 -}; - -export class CSS { - - constructor(private spectron: SpectronApplication) { - // noop - } - - public openQuickOutline(): any { - return this.spectron.command('workbench.action.gotoSymbol'); - } - - public toggleProblemsView(): any { - return this.spectron.command('workbench.actions.view.problems'); - } - - public async getEditorProblem(problemType: CSSProblem): Promise { - let selector; - if (problemType === CSSProblem.WARNING) { - selector = 'greensquiggly'; - } else if (problemType === CSSProblem.ERROR) { - selector = 'redsquiggly'; - } else { - throw new Error('No such problem type defined.'); - } - - let el = await this.spectron.client.waitForElement(`.view-overlays .cdr.${selector}`); - if (el) { - return el; - } - - return undefined; - } - - public async getProblemsViewsProblem(problemType: CSSProblem): Promise { - let selector; - if (problemType === CSSProblem.WARNING) { - selector = 'warning'; - } else if (problemType === CSSProblem.ERROR) { - selector = 'error'; - } else { - throw new Error('No such problem type defined.'); - } - - let el = await this.spectron.client.waitForElement(`div[aria-label="Problems grouped by files"] .icon.${selector}`); - if (el) { - return el; - } - - return undefined; - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/css/css.test.ts b/test/smoke/src/areas/css/css.test.ts index 86e95dbaf9a..4a92af159e1 100644 --- a/test/smoke/src/areas/css/css.test.ts +++ b/test/smoke/src/areas/css/css.test.ts @@ -4,53 +4,52 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; +import { SpectronApplication } from '../../spectron/application'; import { ProblemSeverity, Problems } from '../problems/problems'; -import { QuickOutline } from '../editor/quickoutline'; -import { SettingsEditor } from '../preferences/settings'; describe('CSS', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH]); - return app.start(); + before(function () { + this.app.suiteName = 'CSS'; }); - after(() => app.stop()); it('verifies quick outline', async function () { + const app = this.app as SpectronApplication; await app.workbench.quickopen.openFile('style.css'); - const outline = new QuickOutline(app); - await outline.openSymbols(); - const elements = await app.client.waitForElements(QuickOutline.QUICK_OPEN_ENTRY_SELECTOR, elements => elements.length === 2); - assert.ok(elements, `Did not find two outline elements`); + + await app.workbench.editor.openOutline(); + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 2); }); it('verifies warnings for the empty rule', async function () { + const app = this.app as SpectronApplication; await app.workbench.quickopen.openFile('style.css'); - await app.client.waitForElement(`.monaco-editor.focused`); - await app.type('.foo{}'); + await app.workbench.editor.waitForTypeInEditor('style.css', '.foo{}'); let warning = await app.client.waitForElement(Problems.getSelectorInEditor(ProblemSeverity.WARNING)); + await app.screenCapturer.capture('CSS Warning in editor'); assert.ok(warning, `Warning squiggle is not shown in 'style.css'.`); - const problems = new Problems(app); - await problems.showProblemsView(); + await app.workbench.problems.showProblemsView(); warning = await app.client.waitForElement(Problems.getSelectorInProblemsView(ProblemSeverity.WARNING)); + await app.screenCapturer.capture('CSS Warning in problems view'); assert.ok(warning, 'Warning does not appear in Problems view.'); - await problems.hideProblemsView(); + await app.workbench.problems.hideProblemsView(); }); it('verifies that warning becomes an error once setting changed', async function () { - await new SettingsEditor(app).addUserSetting('css.lint.emptyRules', '"error"'); + const app = this.app as SpectronApplication; + await app.workbench.settingsEditor.addUserSetting('css.lint.emptyRules', '"error"'); await app.workbench.quickopen.openFile('style.css'); - await app.type('.foo{}'); + await app.workbench.editor.waitForTypeInEditor('style.css', '.foo{}'); let error = await app.client.waitForElement(Problems.getSelectorInEditor(ProblemSeverity.ERROR)); + await app.screenCapturer.capture('CSS Error in editor'); assert.ok(error, `Warning squiggle is not shown in 'style.css'.`); const problems = new Problems(app); await problems.showProblemsView(); error = await app.client.waitForElement(Problems.getSelectorInProblemsView(ProblemSeverity.ERROR)); + await app.screenCapturer.capture('CSS Error in probles view'); assert.ok(error, 'Warning does not appear in Problems view.'); await problems.hideProblemsView(); }); diff --git a/test/smoke/src/areas/data-loss.ts b/test/smoke/src/areas/data-loss.ts deleted file mode 100644 index ef7f53b483d..00000000000 --- a/test/smoke/src/areas/data-loss.ts +++ /dev/null @@ -1,26 +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 { SpectronApplication } from '../spectron/application'; - -export class DataLoss { - - constructor(private spectron: SpectronApplication) { - } - - public openExplorerViewlet(): Promise { - return this.spectron.command('workbench.view.explorer'); - } - - public async verifyTabIsDirty(tabName: string, active?: boolean): Promise { - let activeSelector = active ? '.active' : ''; - let el = await this.spectron.client.waitForElement(`.tabs-container .tab.dirty${activeSelector}[aria-label="${tabName}, tab"]`); - if (el) { - return el; - } - - return undefined; - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/debug/debug.test.ts b/test/smoke/src/areas/debug/debug.test.ts new file mode 100644 index 00000000000..7ccef119531 --- /dev/null +++ b/test/smoke/src/areas/debug/debug.test.ts @@ -0,0 +1,154 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as http from 'http'; +import * as os from 'os'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as stripJsonComments from 'strip-json-comments'; +import { SpectronApplication, Quality } from '../../spectron/application'; + +describe('Debug', () => { + + before(async function () { + const app = this.app as SpectronApplication; + + if (app.quality === Quality.Dev) { + const extensionsPath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions'); + + const debugPath = path.join(extensionsPath, 'vscode-node-debug'); + const debugExists = fs.existsSync(debugPath); + + const debug2Path = path.join(extensionsPath, 'vscode-node-debug2'); + const debug2Exists = fs.existsSync(debug2Path); + + if (!debugExists) { + console.warn(`Skipping debug tests because vscode-node-debug extension was not found in ${extensionsPath}`); + return; + } + + if (!debug2Exists) { + console.warn(`Skipping debug tests because vscode-node-debug2 extension was not found in ${extensionsPath}`); + return; + } + + await new Promise((c, e) => fs.symlink(debugPath, path.join(app.extensionsPath, 'vscode-node-debug'), err => err ? e(err) : c())); + await new Promise((c, e) => fs.symlink(debug2Path, path.join(app.extensionsPath, 'vscode-node-debug2'), err => err ? e(err) : c())); + await app.reload(); + } + + this.app.suiteName = 'Debug'; + }); + + it('configure launch json', async function () { + const app = this.app as SpectronApplication; + + await app.workbench.debug.openDebugViewlet(); + await app.workbench.quickopen.openFile('app.js'); + await app.workbench.debug.configure(); + + const launchJsonPath = path.join(app.workspacePath, '.vscode', 'launch.json'); + const content = fs.readFileSync(launchJsonPath, 'utf8'); + const config = JSON.parse(stripJsonComments(content)); + config.configurations[0].protocol = 'inspector'; + fs.writeFileSync(launchJsonPath, JSON.stringify(config, undefined, 4), 'utf8'); + + await app.workbench.editor.waitForEditorContents('launch.json', contents => /"protocol": "inspector"/.test(contents)); + await app.screenCapturer.capture('launch.json file'); + + assert.equal(config.configurations[0].request, 'launch'); + assert.equal(config.configurations[0].type, 'node'); + if (process.platform === 'win32') { + assert.equal(config.configurations[0].program, '${workspaceFolder}\\bin\\www'); + } else { + assert.equal(config.configurations[0].program, '${workspaceFolder}/bin/www'); + } + }); + + it('breakpoints', async function () { + const app = this.app as SpectronApplication; + + await app.workbench.quickopen.openFile('index.js'); + await app.workbench.debug.setBreakpointOnLine(6); + await app.screenCapturer.capture('breakpoints are set'); + }); + + let port: number; + it('start debugging', async function () { + const app = this.app as SpectronApplication; + + port = await app.workbench.debug.startDebugging(); + await app.screenCapturer.capture('debugging has started'); + + await new Promise((c, e) => { + const request = http.get(`http://localhost:${port}`); + request.on('error', e); + app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6, 'looking for index.js and line 6').then(c, e); + }); + + await app.screenCapturer.capture('debugging is paused'); + }); + + it('focus stack frames and variables', async function () { + const app = this.app as SpectronApplication; + + await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 4, 'there should be 4 local variables'); + + await app.workbench.debug.focusStackFrame('layer.js', 'looking for layer.js'); + await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 5, 'there should be 5 local variables'); + + await app.workbench.debug.focusStackFrame('route.js', 'looking for route.js'); + await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 3, 'there should be 3 local variables'); + + await app.workbench.debug.focusStackFrame('index.js', 'looking for index.js'); + await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 4, 'there should be 4 local variables'); + }); + + it('stepOver, stepIn, stepOut', async function () { + const app = this.app as SpectronApplication; + + await app.workbench.debug.stepIn(); + await app.screenCapturer.capture('debugging has stepped in'); + + const first = await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js', 'looking for response.js'); + await app.workbench.debug.stepOver(); + await app.screenCapturer.capture('debugging has stepped over'); + + await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js' && sf.lineNumber === first.lineNumber + 1, `looking for response.js and line ${first.lineNumber + 1}`); + await app.workbench.debug.stepOut(); + await app.screenCapturer.capture('debugging has stepped out'); + + await app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 7, `looking for index.js and line 7`); + }); + + it('continue', async function () { + const app = this.app as SpectronApplication; + + await app.workbench.debug.continue(); + await app.screenCapturer.capture('debugging has continued'); + + await new Promise((c, e) => { + const request = http.get(`http://localhost:${port}`); + request.on('error', e); + app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6, `looking for index.js and line 6`).then(c, e); + }); + + await app.screenCapturer.capture('debugging is paused'); + }); + + it('debug console', async function () { + const app = this.app as SpectronApplication; + + await app.workbench.debug.waitForReplCommand('2 + 2', r => r === '4'); + }); + + it('stop debugging', async function () { + const app = this.app as SpectronApplication; + + await app.workbench.debug.stopDebugging(); + await app.screenCapturer.capture('debugging has stopped'); + }); +}); diff --git a/test/smoke/src/areas/debug/debug.ts b/test/smoke/src/areas/debug/debug.ts new file mode 100644 index 00000000000..7537ca1e69a --- /dev/null +++ b/test/smoke/src/areas/debug/debug.ts @@ -0,0 +1,171 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { SpectronApplication } from '../../spectron/application'; +import { Viewlet } from '../workbench/viewlet'; + +const VIEWLET = 'div[id="workbench.view.debug"]'; +const DEBUG_VIEW = `${VIEWLET} .debug-view-content`; +const CONFIGURE = `div[id="workbench.parts.sidebar"] .actions-container .configure`; +const START = `.icon[title="Start Debugging"]`; +const STOP = `.debug-actions-widget .debug-action.stop`; +const STEP_OVER = `.debug-actions-widget .debug-action.step-over`; +const STEP_IN = `.debug-actions-widget .debug-action.step-into`; +const STEP_OUT = `.debug-actions-widget .debug-action.step-out`; +const CONTINUE = `.debug-actions-widget .debug-action.continue`; +const GLYPH_AREA = '.margin-view-overlays>:nth-child'; +const BREAKPOINT_GLYPH = '.debug-breakpoint-glyph'; +const PAUSE = `.debug-actions-widget .debug-action.pause`; +const DEBUG_STATUS_BAR = `.statusbar.debugging`; +const NOT_DEBUG_STATUS_BAR = `.statusbar:not(debugging)`; +const TOOLBAR_HIDDEN = `.debug-actions-widget.builder-hidden`; +const STACK_FRAME = `${VIEWLET} .monaco-tree-row .stack-frame`; +const VARIABLE = `${VIEWLET} .debug-variables .monaco-tree-row .expression`; +const CONSOLE_OUTPUT = `.repl .output.expression`; +const CONSOLE_INPUT_OUTPUT = `.repl .input-output-pair .output.expression .value`; + +const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor textarea'; + +export interface IStackFrame { + id: string; + name: string; + lineNumber: number; +} + +export class Debug extends Viewlet { + + constructor(spectron: SpectronApplication) { + super(spectron); + } + + async openDebugViewlet(): Promise { + await this.spectron.runCommand('workbench.view.debug'); + await this.spectron.client.waitForElement(DEBUG_VIEW); + } + + async configure(): Promise { + await this.spectron.client.waitAndClick(CONFIGURE); + await this.spectron.workbench.waitForEditorFocus('launch.json'); + } + + async setBreakpointOnLine(lineNumber: number): Promise { + await this.spectron.client.waitForElement(`${GLYPH_AREA}(${lineNumber})`); + await this.spectron.client.leftClick(`${GLYPH_AREA}(${lineNumber})`, 5, 5); + await this.spectron.client.waitForElement(BREAKPOINT_GLYPH); + } + + async startDebugging(): Promise { + await this.spectron.client.waitAndClick(START); + await this.spectron.client.waitForElement(PAUSE); + await this.spectron.client.waitForElement(DEBUG_STATUS_BAR); + const portPrefix = 'Port: '; + await this.spectron.client.waitFor(async () => { + const output = await this.getConsoleOutput(); + return output.join(''); + }, text => !!text && text.indexOf(portPrefix) >= 0); + const output = await this.getConsoleOutput(); + const lastOutput = output.pop(); + + return lastOutput ? parseInt(lastOutput.substr(portPrefix.length)) : 3000; + } + + async stepOver(): Promise { + await this.spectron.client.waitAndClick(STEP_OVER); + } + + async stepIn(): Promise { + await this.spectron.client.waitAndClick(STEP_IN); + } + + async stepOut(): Promise { + await this.spectron.client.waitAndClick(STEP_OUT); + } + + async continue(): Promise { + await this.spectron.client.waitAndClick(CONTINUE); + await this.waitForStackFrameLength(0); + } + + async stopDebugging(): Promise { + await this.spectron.client.waitAndClick(STOP); + await this.spectron.client.waitForElement(TOOLBAR_HIDDEN); + await this.spectron.client.waitForElement(NOT_DEBUG_STATUS_BAR); + } + + async waitForStackFrame(func: (stackFrame: IStackFrame) => boolean, message: string): Promise { + return await this.spectron.client.waitFor(async () => { + const stackFrames = await this.getStackFrames(); + return stackFrames.filter(func)[0]; + }, void 0, `Waiting for Stack Frame: ${message}`); + } + + async waitForStackFrameLength(length: number): Promise { + return await this.spectron.client.waitFor(() => this.getStackFrames(), stackFrames => stackFrames.length === length); + } + + async focusStackFrame(name: string, message: string): Promise { + const stackFrame = await this.waitForStackFrame(sf => sf.name === name, message); + await this.spectron.client.spectron.client.elementIdClick(stackFrame.id); + await this.spectron.workbench.waitForTab(name); + } + + async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise { + await this.spectron.workbench.quickopen.runCommand('Debug: Focus Debug Console'); + await this.spectron.client.waitForActiveElement(REPL_FOCUSED); + await this.spectron.client.setValue(REPL_FOCUSED, text); + + // Wait for the keys to be picked up by the editor model such that repl evalutes what just got typed + await this.spectron.workbench.editor.waitForEditorContents('debug:input', s => s.indexOf(text) >= 0); + await this.spectron.client.keys(['Enter', 'NULL']); + await this.spectron.client.waitForElement(CONSOLE_INPUT_OUTPUT); + await this.spectron.client.waitFor(async () => { + const result = await this.getConsoleOutput(); + return result[result.length - 1] || ''; + }, accept); + } + + async getLocalVariableCount(): Promise { + return await this.spectron.webclient.selectorExecute(VARIABLE, div => (Array.isArray(div) ? div : [div]).length); + } + + async getStackFramesLength(): Promise { + const stackFrames = await this.getStackFrames(); + return stackFrames.length; + } + + private async getStackFrames(): Promise { + const result = await this.spectron.webclient.selectorExecute(STACK_FRAME, + div => (Array.isArray(div) ? div : [div]).map(element => { + const name = element.querySelector('.file-name') as HTMLElement; + const line = element.querySelector('.line-number') as HTMLElement; + const lineNumber = line.textContent ? parseInt(line.textContent.split(':').shift() || '0') : 0; + + return { + name: name.textContent, + lineNumber, + element + }; + }) + ); + + if (!Array.isArray(result)) { + return []; + } + + return result + .map(({ name, lineNumber, element }) => ({ name, lineNumber, id: element.ELEMENT })); + } + + private async getConsoleOutput(): Promise { + const result = await this.spectron.webclient.selectorExecute(CONSOLE_OUTPUT, + div => (Array.isArray(div) ? div : [div]).map(element => { + const value = element.querySelector('.value') as HTMLElement; + return value && value.textContent; + }).filter(line => !!line) + ); + + return result; + } +} diff --git a/test/smoke/src/areas/editor/editor.test.ts b/test/smoke/src/areas/editor/editor.test.ts new file mode 100644 index 00000000000..c6d588076ed --- /dev/null +++ b/test/smoke/src/areas/editor/editor.test.ts @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { SpectronApplication } from '../../spectron/application'; + +describe('Editor', () => { + before(function () { + this.app.suiteName = 'Editor'; + }); + + it('shows correct quick outline', async function () { + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openFile('www'); + + await app.workbench.editor.openOutline(); + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length >= 6); + }); + + it(`finds 'All References' to 'app'`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openFile('www'); + + const references = await app.workbench.editor.findReferences('app', 7); + + await references.waitForReferencesCountInTitle(3); + await references.waitForReferencesCount(3); + await references.close(); + }); + + it(`renames local 'app' variable`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openFile('www'); + await app.workbench.editor.rename('www', 7, 'app', 'newApp'); + await app.workbench.editor.waitForEditorContents('www', contents => contents.indexOf('newApp') > -1); + await app.screenCapturer.capture('Rename result'); + }); + + // it('folds/unfolds the code correctly', async function () { + // await app.workbench.quickopen.openFile('www'); + + // // Fold + // await app.workbench.editor.foldAtLine(3); + // await app.workbench.editor.waitUntilShown(3); + // await app.workbench.editor.waitUntilHidden(4); + // await app.workbench.editor.waitUntilHidden(5); + + // // Unfold + // await app.workbench.editor.unfoldAtLine(3); + // await app.workbench.editor.waitUntilShown(3); + // await app.workbench.editor.waitUntilShown(4); + // await app.workbench.editor.waitUntilShown(5); + // }); + + it(`verifies that 'Go To Definition' works`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openFile('app.js'); + + await app.workbench.editor.gotoDefinition('express', 11); + + await app.workbench.waitForActiveTab('index.d.ts'); + }); + + it(`verifies that 'Peek Definition' works`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openFile('app.js'); + + const peek = await app.workbench.editor.peekDefinition('express', 11); + + await peek.waitForFile('index.d.ts'); + }); +}); \ No newline at end of file diff --git a/test/smoke/src/areas/editor/editor.ts b/test/smoke/src/areas/editor/editor.ts index aa5f631af6e..499f0fe6196 100644 --- a/test/smoke/src/areas/editor/editor.ts +++ b/test/smoke/src/areas/editor/editor.ts @@ -4,28 +4,191 @@ *--------------------------------------------------------------------------------------------*/ import { SpectronApplication } from '../../spectron/application'; +import { QuickOutline } from './quickoutline'; +import { References } from './peek'; + +const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box'; +const RENAME_INPUT = `${RENAME_BOX} .rename-input`; export class Editor { + private static VIEW_LINES = '.monaco-editor .view-lines'; + private static LINE_NUMBERS = '.monaco-editor .margin .margin-view-overlays .line-numbers'; + private static FOLDING_EXPANDED = '.monaco-editor .margin .margin-view-overlays>:nth-child(${INDEX}) .folding'; + private static FOLDING_COLLAPSED = `${Editor.FOLDING_EXPANDED}.collapsed`; + constructor(private spectron: SpectronApplication) { } - public async getEditorFirstLineText(): Promise { - const result = await this.spectron.client.waitForText('.monaco-editor.focused .view-lines span span:nth-child(1)'); - return Array.isArray(result) ? result.join() : result; + async openOutline(): Promise { + const outline = new QuickOutline(this.spectron); + await outline.open(); + return outline; } - public async waitForHighlightingLine(line: number): Promise { - const currentLineIndex = await this.spectron.client.waitFor(async () => { - const lineNumbers = await this.spectron.webclient.selectorExecute(`.monaco-editor .line-numbers`, - elements => (Array.isArray(elements) ? elements : [elements]).map(element => element.textContent)); - for (let index = 0; index < lineNumbers.length; index++) { - if (lineNumbers[index] === `${line}`) { - return index + 1; - } + async findReferences(term: string, line: number): Promise { + await this.clickOnTerm(term, line); + await this.spectron.workbench.quickopen.runCommand('Find All References'); + const references = new References(this.spectron); + await references.waitUntilOpen(); + return references; + } + + async rename(filename: string, line: number, from: string, to: string): Promise { + await this.clickOnTerm(from, line); + await this.spectron.workbench.quickopen.runCommand('Rename Symbol'); + + await this.spectron.client.waitForActiveElement(RENAME_INPUT); + await this.spectron.client.setValue(RENAME_INPUT, to); + + await this.spectron.client.keys(['Enter', 'NULL']); + } + + async gotoDefinition(term: string, line: number): Promise { + await this.clickOnTerm(term, line); + await this.spectron.workbench.quickopen.runCommand('Go to Definition'); + } + + async peekDefinition(term: string, line: number): Promise { + await this.clickOnTerm(term, line); + await this.spectron.workbench.quickopen.runCommand('Peek Definition'); + const peek = new References(this.spectron); + await peek.waitUntilOpen(); + return peek; + } + + async waitForHighlightingLine(line: number): Promise { + const currentLineIndex = await this.getViewLineIndex(line); + if (currentLineIndex) { + await this.spectron.client.waitForElement(`.monaco-editor .view-overlays>:nth-child(${currentLineIndex}) .current-line`); + return; + } + throw new Error('Cannot find line ' + line); + } + + async getSelector(term: string, line: number): Promise { + const lineIndex = await this.getViewLineIndex(line); + const classNames = await this.spectron.client.waitFor(() => this.getClassSelectors(term, lineIndex), classNames => classNames && !!classNames.length, 'Getting class names for editor lines'); + return `${Editor.VIEW_LINES}>:nth-child(${lineIndex}) span span.${classNames[0]}`; + } + + async foldAtLine(line: number): Promise { + const lineIndex = await this.getViewLineIndex(line); + await this.spectron.client.waitAndClick(Editor.FOLDING_EXPANDED.replace('${INDEX}', '' + lineIndex)); + await this.spectron.client.waitForElement(Editor.FOLDING_COLLAPSED.replace('${INDEX}', '' + lineIndex)); + } + + async unfoldAtLine(line: number): Promise { + const lineIndex = await this.getViewLineIndex(line); + await this.spectron.client.waitAndClick(Editor.FOLDING_COLLAPSED.replace('${INDEX}', '' + lineIndex)); + await this.spectron.client.waitForElement(Editor.FOLDING_EXPANDED.replace('${INDEX}', '' + lineIndex)); + } + + async waitUntilHidden(line: number): Promise { + await this.spectron.client.waitFor(() => this.getViewLineIndexWithoutWait(line), lineNumber => lineNumber === undefined, 'Waiting until line number is hidden'); + } + + async waitUntilShown(line: number): Promise { + await this.getViewLineIndex(line); + } + + async clickOnTerm(term: string, line: number): Promise { + const selector = await this.getSelector(term, line); + await this.spectron.client.waitAndClick(selector); + } + + async waitForTypeInEditor(filename: string, text: string, selectorPrefix = ''): Promise { + const editor = [ + selectorPrefix || '', + `.monaco-editor[data-uri$="${filename}"]` + ].join(' '); + + await this.spectron.client.element(editor); + + const textarea = `${editor} textarea`; + await this.spectron.client.waitForActiveElement(textarea); + + // https://github.com/Microsoft/vscode/issues/34203#issuecomment-334441786 + await this.spectron.client.spectron.client.selectorExecute(textarea, (elements, text) => { + const textarea = (Array.isArray(elements) ? elements : [elements])[0] as HTMLTextAreaElement; + const start = textarea.selectionStart; + const newStart = start + text.length; + const value = textarea.value; + const newValue = value.substr(0, start) + text + value.substr(start); + + textarea.value = newValue; + textarea.setSelectionRange(newStart, newStart); + + const event = new Event('input', { 'bubbles': true, 'cancelable': true }); + textarea.dispatchEvent(event); + }, text); + + await this.waitForEditorContents(filename, c => c.indexOf(text) > -1, selectorPrefix); + } + + async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise { + const selector = [ + selectorPrefix || '', + `.monaco-editor[data-uri$="${filename}"] .view-lines` + ].join(' '); + + return this.spectron.client.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' '))); + } + + async waitForActiveEditor(filename: string): Promise { + const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`; + return this.spectron.client.waitForActiveElement(selector); + } + + // async waitForActiveEditorFirstLineText(filename: string): Promise { + // const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`; + // const result = await this.spectron.client.waitFor( + // () => this.spectron.client.spectron.client.execute(s => { + // if (!document.activeElement.matches(s)) { + // return undefined; + // } + + // let element: Element | null = document.activeElement; + // while (element && !/monaco-editor/.test(element.className) && element !== document.body) { + // element = element.parentElement; + // } + + // if (element && /monaco-editor/.test(element.className)) { + // const firstLine = element.querySelector('.view-lines span span:nth-child(1)'); + + // if (firstLine) { + // return (firstLine.textContent || '').replace(/\u00a0/g, ' '); // DAMN + // } + // } + + // return undefined; + // }, selector), + // r => typeof r.value === 'string', + // `wait for active editor first line: ${selector}` + // ); + + // return result.value; + // } + + private async getClassSelectors(term: string, viewline: number): Promise { + const result: { text: string, className: string }[] = await this.spectron.webclient.selectorExecute(`${Editor.VIEW_LINES}>:nth-child(${viewline}) span span`, + elements => (Array.isArray(elements) ? elements : [elements]) + .map(element => ({ text: element.textContent, className: element.className }))); + return result.filter(r => r.text === term).map(({ className }) => className); + } + + private async getViewLineIndex(line: number): Promise { + return await this.spectron.client.waitFor(() => this.getViewLineIndexWithoutWait(line), void 0, 'Getting line index'); + } + + private async getViewLineIndexWithoutWait(line: number): Promise { + const lineNumbers = await this.spectron.webclient.selectorExecute(Editor.LINE_NUMBERS, + elements => (Array.isArray(elements) ? elements : [elements]).map(element => element.textContent)); + for (let index = 0; index < lineNumbers.length; index++) { + if (lineNumbers[index] === `${line}`) { + return index + 1; } - return undefined; - }); - await this.spectron.client.waitForElement(`.monaco-editor .view-overlays>:nth-child(${currentLineIndex}) .current-line`); + } + return undefined; } } \ No newline at end of file diff --git a/test/smoke/src/areas/editor/peek.ts b/test/smoke/src/areas/editor/peek.ts new file mode 100644 index 00000000000..24e472c17ef --- /dev/null +++ b/test/smoke/src/areas/editor/peek.ts @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { SpectronApplication } from '../../spectron/application'; + +export class References { + + private static REFERENCES_WIDGET = '.monaco-editor .zone-widget .zone-widget-container.peekview-widget.reference-zone-widget.results-loaded'; + private static REFERENCES_TITLE_FILE_NAME = `${References.REFERENCES_WIDGET} .head .peekview-title .filename`; + private static REFERENCES_TITLE_COUNT = `${References.REFERENCES_WIDGET} .head .peekview-title .meta`; + private static REFERENCES = `${References.REFERENCES_WIDGET} .body .ref-tree.inline .monaco-tree-row .reference`; + + constructor(private spectron: SpectronApplication) { + } + + public async waitUntilOpen(): Promise { + await this.spectron.client.waitForElement(References.REFERENCES_WIDGET); + } + + public async waitForReferencesCountInTitle(count: number): Promise { + await this.spectron.client.waitForText(References.REFERENCES_TITLE_COUNT, void 0, titleCount => { + const matches = titleCount.match(/\d+/); + return matches ? parseInt(matches[0]) === count : false; + }); + } + + public async waitForReferencesCount(count: number): Promise { + await this.spectron.client.waitForElements(References.REFERENCES, result => result && result.length === count); + } + + public async waitForFile(file: string): Promise { + await this.spectron.client.waitForText(References.REFERENCES_TITLE_FILE_NAME, file); + } + + public async close(): Promise { + await this.spectron.client.keys(['Escape', 'NULL']); + await this.spectron.client.waitForElement(References.REFERENCES_WIDGET, element => !element); + } +} \ No newline at end of file diff --git a/test/smoke/src/areas/editor/quickoutline.ts b/test/smoke/src/areas/editor/quickoutline.ts index a766072a543..852bd8b9145 100644 --- a/test/smoke/src/areas/editor/quickoutline.ts +++ b/test/smoke/src/areas/editor/quickoutline.ts @@ -12,14 +12,17 @@ export class QuickOutline extends QuickOpen { super(spectron); } - public async openSymbols(): Promise { + public async open(): Promise { await this.spectron.client.waitFor(async () => { - await this.spectron.command('workbench.action.gotoSymbol'); - const element = await this.spectron.client.element('div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties div.monaco-tree-row[aria-label="body, symbols, picker"] .quick-open-entry'); - if (element) { - return element; + await this.spectron.runCommand('workbench.action.gotoSymbol'); + const entry = await this.spectron.client.element('div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties div.monaco-tree-row .quick-open-entry'); + if (entry) { + const text = await this.spectron.client.getText('div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties div.monaco-tree-row .quick-open-entry .monaco-icon-label .label-name .monaco-highlighted-label span'); + if (text !== 'No symbol information for the file') { + return entry; + } } await this.closeQuickOpen(); - }); + }, undefined, 'Opening Outline'); } } diff --git a/test/smoke/src/areas/explorer/explorer.test.ts b/test/smoke/src/areas/explorer/explorer.test.ts index 64de1373ceb..edf0088cf20 100644 --- a/test/smoke/src/areas/explorer/explorer.test.ts +++ b/test/smoke/src/areas/explorer/explorer.test.ts @@ -3,33 +3,40 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; +import { SpectronApplication } from '../../spectron/application'; describe('Explorer', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH]); - return app.start(); + before(function () { + this.app.suiteName = 'Explorer'; }); - after(() => app.stop()); it('quick open search produces correct result', async function () { - await app.workbench.quickopen.openQuickOpen(); - await app.client.type('.js'); - const elements = await app.workbench.quickopen.getQuickOpenElements(); - await app.client.keys(['Escape', 'NULL']); + const app = this.app as SpectronApplication; + const expectedNames = [ + '.eslintrc.json', + 'tasks.json', + 'app.js', + 'index.js', + 'users.js', + 'package.json', + 'jsconfig.json' + ]; - assert.equal(elements.length, 7, 'There are 7 elements in quick open'); + await app.workbench.quickopen.openQuickOpen('.js'); + await app.workbench.quickopen.waitForQuickOpenElements(names => expectedNames.every(n => names.some(m => n === m))); + await app.client.keys(['Escape', 'NULL']); }); it('quick open respects fuzzy matching', async function () { - await app.workbench.quickopen.openQuickOpen(); - await app.client.type('a.s'); + const app = this.app as SpectronApplication; + const expectedNames = [ + 'tasks.json', + 'app.js', + 'package.json' + ]; - const elements = await app.workbench.quickopen.getQuickOpenElements(); + await app.workbench.quickopen.openQuickOpen('a.s'); + await app.workbench.quickopen.waitForQuickOpenElements(names => expectedNames.every(n => names.some(m => n === m))); await app.client.keys(['Escape', 'NULL']); - - assert.equal(elements.length, 3, 'There are 3 elements in quick open'); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/explorer/explorer.ts b/test/smoke/src/areas/explorer/explorer.ts index b452123f22e..1dd454462ac 100644 --- a/test/smoke/src/areas/explorer/explorer.ts +++ b/test/smoke/src/areas/explorer/explorer.ts @@ -4,35 +4,39 @@ *--------------------------------------------------------------------------------------------*/ import { SpectronApplication } from '../../spectron/application'; +import { Viewlet } from '../workbench/viewlet'; -export class Explorer { - constructor(private spectron: SpectronApplication) { +export class Explorer extends Viewlet { + + private static EXPLORER_VIEWLET = 'div[id="workbench.view.explorer"]'; + private static OPEN_EDITORS_VIEW = `${Explorer.EXPLORER_VIEWLET} .split-view-view:nth-child(1) .title`; + + constructor(spectron: SpectronApplication) { + super(spectron); } public openExplorerView(): Promise { - return this.spectron.command('workbench.view.explorer'); + return this.spectron.runCommand('workbench.view.explorer'); + } + + public getOpenEditorsViewTitle(): Promise { + return this.spectron.client.waitForText(Explorer.OPEN_EDITORS_VIEW); } public async openFile(fileName: string): Promise { - let selector = `div[class="monaco-icon-label file-icon ${fileName}-name-file-icon ${this.getExtensionSelector(fileName)} explorer-item"]`; - try { - await this.spectron.client.doubleClickAndWait(selector); - await this.spectron.client.waitForElement(`.tabs-container div[aria-label="${fileName}, tab"]`); - await this.spectron.client.waitForElement(`.monaco-editor.focused`); - } catch (e) { - return Promise.reject(`Cannot fine ${fileName} in a viewlet.`); - } + await this.spectron.client.doubleClickAndWait(`div[class="monaco-icon-label file-icon ${fileName}-name-file-icon ${this.getExtensionSelector(fileName)} explorer-item"]`); + await this.spectron.workbench.waitForEditorFocus(fileName); } public getExtensionSelector(fileName: string): string { const extension = fileName.split('.')[1]; if (extension === 'js') { - return 'js-ext-file-icon javascript-lang-file-icon'; + return 'js-ext-file-icon ext-file-icon javascript-lang-file-icon'; } else if (extension === 'json') { - return 'json-ext-file-icon json-lang-file-icon'; + return 'json-ext-file-icon ext-file-icon json-lang-file-icon'; } else if (extension === 'md') { - return 'md-ext-file-icon markdown-lang-file-icon'; + return 'md-ext-file-icon ext-file-icon markdown-lang-file-icon'; } throw new Error('No class defined for this file extension'); } diff --git a/test/smoke/src/areas/extensions.ts b/test/smoke/src/areas/extensions.ts deleted file mode 100644 index 2b84b62598e..00000000000 --- a/test/smoke/src/areas/extensions.ts +++ /dev/null @@ -1,112 +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 { SpectronApplication } from '../spectron/application'; -import { CommonActions } from './common'; - -var htmlparser = require('htmlparser2'); - -export class Extensions { - - private readonly extensionsViewletSelector = 'div[id="workbench.view.extensions"]'; - private viewletExtensionIndex: number; - - constructor(private spectron: SpectronApplication, private common: CommonActions) { - } - - public async openExtensionsViewlet(): Promise { - await this.spectron.command('workbench.view.extensions'); - return this.spectron.wait(); - } - - public async searchForExtension(name: string): Promise { - const searchBoxSelector = `${this.extensionsViewletSelector} .search-box`; - - await this.spectron.client.clearElement(searchBoxSelector); - try { - await this.spectron.client.waitAndClick(searchBoxSelector); - } catch (e) { - return Promise.reject('Failed to click on search box in extensions viewlet.'); - } - await this.spectron.client.keys(name); - - return this.spectron.client.keys(['NULL', 'Enter', 'NULL']); - } - - public async installExtension(name: string): Promise { - const extensionListSelector = `${this.extensionsViewletSelector} .monaco-list-rows`; - this.viewletExtensionIndex = await this.getExtensionIndex(name, extensionListSelector); - - try { - return this.spectron.client.waitAndClick(`${extensionListSelector}>:nth-child(${this.viewletExtensionIndex}) .extension .extension-action.install`); - } catch (e) { - return Promise.reject('Failed to click on install button for selected extension.'); - } - } - - public getExtensionReloadText(): Promise { - try { - return this.spectron.waitFor(this.spectron.client.getText, `${this.extensionsViewletSelector} .monaco-list-rows>:nth-child(${this.viewletExtensionIndex}) .extension .extension-action.reload`); - } catch (e) { - return Promise.reject('Reload was not prompted for an installed extension.'); - } - } - - public async activateExtension(): Promise { - await this.common.showCommands(); - await this.common.type('Smoke Test Check'); - await this.spectron.wait(); - return this.common.enter(); - } - - public verifyStatusbarItem(): Promise { - try { - return this.spectron.waitFor(this.spectron.client.getText, '.statusbar-item.statusbar-entry span[title="smoke test"]'); - } catch (e) { - return Promise.reject('Failed to validate extension contribution.'); - } - } - - private getExtensionIndex(name: string, extensionListSelector: string): Promise { - return this.spectron.waitFor(this.spectron.client.waitForHTML, extensionListSelector).then(html => { - return new Promise((res, rej) => { - let extensionIndex: number = 0; - let extension: boolean; - let tags: string[] = []; - let parser = new htmlparser.Parser({ - onopentag: function (name, attribs) { - if (name === 'div' && attribs.class === 'extension') { - extensionIndex++; - extension = true; - } - if (extension) { - tags.push(name); - } - }, - ontext: function (text) { - if (extension && text === name) { - parser.end(); - } - }, - onclosetag: function (name) { - if (extension) { - tags.pop(); - } - if (extension && tags.length === 0) { - extension = false; - } - }, - onend: function () { - if (extensionIndex === 0) { - return rej(`${name} extension was not found.`); - } - return res(extensionIndex); - } - }); - parser.write(html); - }); - }); - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/extensions/extensions.test.ts b/test/smoke/src/areas/extensions/extensions.test.ts index 560bfe90677..135b87403c3 100644 --- a/test/smoke/src/areas/extensions/extensions.test.ts +++ b/test/smoke/src/areas/extensions/extensions.test.ts @@ -4,33 +4,33 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; +import { SpectronApplication, Quality } from '../../spectron/application'; describe('Extensions', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH]); - return app.start(); + before(function () { + this.app.suiteName = 'Extensions'; }); - after(() => app.stop()); it(`install and activate vscode-smoketest-check extension`, async function () { - if (app.inDevMode) { + const app = this.app as SpectronApplication; + + if (app.quality === Quality.Dev) { + this.skip(); return; } + const extensionName = 'vscode-smoketest-check'; await app.workbench.extensions.openExtensionsViewlet(); const installed = await app.workbench.extensions.installExtension(extensionName); - assert.ok(installed); await app.reload(); await app.workbench.extensions.waitForExtensionsViewlet(); - await app.workbench.commandPallette.runCommand('Smoke Test Check'); - + await app.workbench.quickopen.runCommand('Smoke Test Check'); const statusbarText = await app.workbench.statusbar.getStatusbarTextByTitle('smoke test'); + await app.screenCapturer.capture('Statusbar'); assert.equal(statusbarText, 'VS Code Smoke Test Check'); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/extensions/extensions.ts b/test/smoke/src/areas/extensions/extensions.ts index b565be22180..d0c3f97320d 100644 --- a/test/smoke/src/areas/extensions/extensions.ts +++ b/test/smoke/src/areas/extensions/extensions.ts @@ -4,34 +4,38 @@ *--------------------------------------------------------------------------------------------*/ import { SpectronApplication } from '../../spectron/application'; +import { Viewlet } from '../workbench/viewlet'; -export class Extensions { +const SEARCH_BOX = 'div.extensions-viewlet[id="workbench.view.extensions"] input.search-box'; - constructor(private spectron: SpectronApplication) { +export class Extensions extends Viewlet { + + constructor(spectron: SpectronApplication) { + super(spectron); } - public async openExtensionsViewlet(): Promise { - await this.spectron.command('workbench.view.extensions'); + async openExtensionsViewlet(): Promise { + await this.spectron.runCommand('workbench.view.extensions'); await this.waitForExtensionsViewlet(); } - public async waitForExtensionsViewlet(): Promise { - await this.spectron.client.waitForElement('div.extensions-viewlet[id="workbench.view.extensions"] .search-box.synthetic-focus[placeholder="Search Extensions in Marketplace"]'); + async waitForExtensionsViewlet(): Promise { + await this.spectron.client.waitForActiveElement(SEARCH_BOX); } - public async searchForExtension(name: string): Promise { - const searchBoxSelector = 'div.extensions-viewlet[id="workbench.view.extensions"] .search-box[placeholder="Search Extensions in Marketplace"]'; - - await this.spectron.client.clearElement(searchBoxSelector); - await this.spectron.client.click(searchBoxSelector); - await this.spectron.client.waitForElement('div.extensions-viewlet[id="workbench.view.extensions"] .search-box.synthetic-focus[placeholder="Search Extensions in Marketplace"]'); - await this.spectron.client.keys(name); - + async searchForExtension(name: string): Promise { + await this.spectron.client.click(SEARCH_BOX); + await this.spectron.client.waitForActiveElement(SEARCH_BOX); + await this.spectron.client.setValue(SEARCH_BOX, name); } - public async installExtension(name: string): Promise { + async installExtension(name: string): Promise { await this.searchForExtension(name); - await this.spectron.client.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[aria-label="${name}"] .extension li[class='action-item'] .extension-action.install`); + + // we might want to wait for a while longer since the Marketplace can be slow + // a minute should do + await this.spectron.client.waitFor(() => this.spectron.client.click(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[aria-label="${name}"] .extension li[class='action-item'] .extension-action.install`), void 0, 'waiting for install button', 600); + await this.spectron.client.waitForElement(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[aria-label="${name}"] .extension li[class='action-item'] .extension-action.reload`); return true; } diff --git a/test/smoke/src/areas/git/git.test.ts b/test/smoke/src/areas/git/git.test.ts index 9bebc99a0fc..d64a72f7d43 100644 --- a/test/smoke/src/areas/git/git.test.ts +++ b/test/smoke/src/areas/git/git.test.ts @@ -4,33 +4,34 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; +import * as cp from 'child_process'; +import { SpectronApplication } from '../../spectron/application'; const DIFF_EDITOR_LINE_INSERT = '.monaco-diff-editor .editor.modified .line-insert'; const SYNC_STATUSBAR = 'div[id="workbench.parts.statusbar"] .statusbar-entry a[title$="Synchronize Changes"]'; describe('Git', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH]); - return app.start(); + before(function () { + this.app.suiteName = 'Git'; }); - after(() => app.stop()); it('reflects working tree changes', async function () { + const app = this.app as SpectronApplication; + await app.workbench.scm.openSCMViewlet(); - await app.workbench.openFile('app.js'); - await app.type('.foo{}'); + await app.workbench.quickopen.openFile('app.js'); + await app.workbench.editor.waitForTypeInEditor('app.js', '.foo{}'); await app.workbench.saveOpenedFile(); - await app.workbench.openFile('index.jade'); - await app.type('hello world'); + await app.workbench.quickopen.openFile('index.jade'); + await app.workbench.editor.waitForTypeInEditor('index.jade', 'hello world'); await app.workbench.saveOpenedFile(); await app.workbench.scm.refreshSCMViewlet(); const appJs = await app.workbench.scm.waitForChange(c => c.name === 'app.js'); const indexJade = await app.workbench.scm.waitForChange(c => c.name === 'index.jade'); + await app.screenCapturer.capture('changes'); assert.equal(appJs.name, 'app.js'); assert.equal(appJs.type, 'Modified'); @@ -40,6 +41,8 @@ describe('Git', () => { }); it('opens diff editor', async function () { + const app = this.app as SpectronApplication; + await app.workbench.scm.openSCMViewlet(); const appJs = await app.workbench.scm.waitForChange(c => c.name === 'app.js'); await app.workbench.scm.openChange(appJs); @@ -47,6 +50,14 @@ describe('Git', () => { }); it('stages correctly', async function () { + const app = this.app as SpectronApplication; + + // TODO@joao get these working once joh fixes scm viewlet + if (!false) { + this.skip(); + return; + } + await app.workbench.scm.openSCMViewlet(); const appJs = await app.workbench.scm.waitForChange(c => c.name === 'app.js' && c.type === 'Modified'); @@ -58,14 +69,31 @@ describe('Git', () => { await app.workbench.scm.waitForChange(c => c.name === 'app.js' && c.type === 'Modified'); }); - it(`stages, commits change to 'app.js' locally and verifies outgoing change`, async function () { + it(`stages, commits changes and verifies outgoing change`, async function () { + const app = this.app as SpectronApplication; + + // TODO@joao get these working once joh fixes scm viewlet + if (!false) { + cp.execSync('git reset --hard origin/master', { cwd: app.workspacePath }); + this.skip(); + return; + } + await app.workbench.scm.openSCMViewlet(); const appJs = await app.workbench.scm.waitForChange(c => c.name === 'app.js' && c.type === 'Modified'); await app.workbench.scm.stage(appJs); await app.workbench.scm.waitForChange(c => c.name === 'app.js' && c.type === 'Index Modified'); - await app.workbench.scm.commit('hello world'); + await app.workbench.scm.commit('first commit'); await app.client.waitForText(SYNC_STATUSBAR, ' 0↓ 1↑'); + + await app.workbench.quickopen.runCommand('Git: Stage All Changes'); + await app.workbench.scm.waitForChange(c => c.name === 'index.jade' && c.type === 'Index Modified'); + + await app.workbench.scm.commit('second commit'); + await app.client.waitForText(SYNC_STATUSBAR, ' 0↓ 2↑'); + + cp.execSync('git reset --hard origin/master', { cwd: app.workspacePath }); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/git/scm.ts b/test/smoke/src/areas/git/scm.ts index 6a2ba046a08..bc99619478a 100644 --- a/test/smoke/src/areas/git/scm.ts +++ b/test/smoke/src/areas/git/scm.ts @@ -5,13 +5,16 @@ import * as assert from 'assert'; import { SpectronApplication } from '../../spectron/application'; +import { Viewlet } from '../workbench/viewlet'; const VIEWLET = 'div[id="workbench.view.scm"]'; const SCM_INPUT = `${VIEWLET} .scm-editor textarea`; const SCM_RESOURCE = `${VIEWLET} .monaco-list-row > .resource`; +const SCM_RESOURCE_GROUP = `${VIEWLET} .monaco-list-row > .resource-group`; const REFRESH_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[title="Refresh"]`; const COMMIT_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[title="Commit"]`; const SCM_RESOURCE_CLICK = name => `${SCM_RESOURCE} .monaco-icon-label[title$="${name}"]`; +const SCM_RESOURCE_GROUP_COMMAND_CLICK = name => `${SCM_RESOURCE_GROUP} .actions .action-label[title="${name}"]`; export interface Change { id: string; @@ -20,31 +23,22 @@ export interface Change { actions: { id: string, title: string; }[]; } -export class SCM { +export class SCM extends Viewlet { - // private editorChangeIndex: number; - - constructor(private spectron: SpectronApplication) { - // noop + constructor(spectron: SpectronApplication) { + super(spectron); } async openSCMViewlet(): Promise { - await this.spectron.command('workbench.view.scm'); + await this.spectron.runCommand('workbench.view.scm'); await this.spectron.client.waitForElement(SCM_INPUT); } async waitForChange(func: (change: Change) => boolean): Promise { return await this.spectron.client.waitFor(async () => { const changes = await this.getChanges(); - - for (const change of changes) { - if (func(change)) { - return change; - } - } - - return undefined; - }); + return changes.filter(func)[0]; + }, void 0, 'Getting changes'); } async refreshSCMViewlet(): Promise { @@ -55,7 +49,7 @@ export class SCM { const result = await this.spectron.webclient.selectorExecute(SCM_RESOURCE, div => (Array.isArray(div) ? div : [div]).map(element => { const name = element.querySelector('.label-name') as HTMLElement; - const icon = element.querySelector('.decoration-icon') as HTMLElement; + const icon = element.querySelector('.monaco-icon-label') as HTMLElement; const actionElementList = element.querySelectorAll('.actions .action-label'); const actionElements: any[] = []; @@ -63,9 +57,10 @@ export class SCM { const element = actionElementList.item(i) as HTMLElement; actionElements.push({ element, title: element.title }); } + return { name: name.textContent, - type: icon.title, + type: (icon.title || '').replace(/^([^,]+),.*$/, '$1'), element, actionElements }; @@ -89,6 +84,10 @@ export class SCM { await this.spectron.client.spectron.client.elementIdClick(action.id); } + async stageAll(): Promise { + await this.spectron.client.waitAndClick(SCM_RESOURCE_GROUP_COMMAND_CLICK('Stage All Changes')); + } + async unstage(change: Change): Promise { const action = change.actions.filter(a => a.title === 'Unstage Changes')[0]; assert(action); @@ -96,155 +95,9 @@ export class SCM { } async commit(message: string): Promise { - await this.spectron.client.click(SCM_INPUT); - await this.spectron.type(message); - await this.spectron.client.click(COMMIT_COMMAND); + await this.spectron.client.waitAndClick(SCM_INPUT); + await this.spectron.client.waitForActiveElement(SCM_INPUT); + await this.spectron.client.setValue(SCM_INPUT, message); + await this.spectron.client.waitAndClick(COMMIT_COMMAND); } - - // async getChanges(expectedCount: number): Promise { - // await this.spectron.client.waitForElements(SCM_RESOURCE, r => r.length === expectedCount); - - // } - - // public async verifyScmChange(fileName: string): Promise { - // let el; - // try { - // el = await this.spectron.client.waitForElement(`div[class="monaco-icon-label file-icon ${fileName}-name-file-icon ${this.commonActions.getExtensionSelector(fileName)}"]`); - // } catch (e) { - // return Promise.reject(`${fileName} change is not present in SCM viewlet.`); - // } - - // if (el.status === 0) { - // return el; - // } - - // return undefined; - // } - - // public async getOriginalAppJsBodyVarName(): Promise { - // this.editorChangeIndex = await this.getFirstChangeIndex('cdr line-delete', '.editor.original .view-overlays'); - // return this.spectron.waitFor(this.spectron.client.getText, `.editor.original .view-lines>:nth-child(${this.editorChangeIndex}) .mtk11`); - // } - - // public getModifiedAppJsBodyVarName(): Promise { - // return this.spectron.waitFor(this.spectron.client.getText, `.editor.modified .view-lines>:nth-child(${this.editorChangeIndex}) .mtk11`); - // } - - // public async stageFile(fileName: string): Promise { - // try { - // await this.spectron.client.moveToObject(`div[class="monaco-icon-label file-icon ${fileName}-name-file-icon ${this.commonActions.getExtensionSelector(fileName)}"`); - // } catch (e) { - // return Promise.reject(`${fileName} was not found in SCM viewlet`); - // } - - // await this.spectron.wait(); - - // try { - // await this.spectron.client.waitAndClick('.action-label.icon.contrib-cmd-icon-4'); - // } catch (e) { - // return Promise.reject('Stage button was not found'); - // } - // return this.spectron.wait(); - // } - - // public async unstageFile(fileName: string): Promise { - // try { - // await this.spectron.client.moveToObject(`div[class="monaco-icon-label file-icon ${fileName}-name-file-icon ${this.commonActions.getExtensionSelector(fileName)}"`); - // } catch (e) { - // return Promise.reject(`${fileName} was not found in SCM viewlet`); - // } - - // try { - // await this.spectron.client.waitAndClick('.action-label.icon.contrib-cmd-icon-6'); - // } catch (e) { - // return Promise.reject('Unstage button was not found.'); - // } - // return this.spectron.wait(); - // } - - // public async getStagedCount(): Promise { - // let scmHeaders: Array; - // try { - // scmHeaders = await this.spectron.waitFor(this.spectron.client.getText, '.scm-status.show-file-icons .monaco-list-rows .name'); // get all headers - // } - // catch (e) { - // return Promise.reject('No row names in SCM viewlet were found.'); - // } - - // const stagedTitle = scmHeaders.find((val) => { - // return val.match(/staged/i) ? true : false; - // }); - - // if (!stagedTitle) { - // return Promise.reject(`No 'Staged' header title found in SCM viewlet`); - // } - - // const monacoRowIndex = scmHeaders.indexOf(stagedTitle); - // try { - // return this.spectron.waitFor(this.spectron.client.getText, `.scm-status.show-file-icons .monaco-list-rows>:nth-child(${monacoRowIndex + 1}) .monaco-count-badge`); - // } catch (e) { - // return Promise.reject('Stage count badge cannot be found'); - // } - // } - - // public focusOnCommitBox(): Promise { - // try { - // return this.spectron.client.waitAndClick('div[id="workbench.view.scm"] textarea'); - // } catch (e) { - // return Promise.reject('Failed to focus on commit box: ' + e); - // } - // } - - // public async pressCommit(): Promise { - // try { - // await this.spectron.client.waitAndClick('.action-label.icon.contrib-cmd-icon-10'); - // } catch (e) { - // return Promise.reject('Failed to press commit: ' + e); - // } - - // return this.spectron.wait(); - // } - - // public getOutgoingChanges(): Promise { - // try { - // return this.spectron.client.getText('a[title="Synchronize Changes"]'); - // } catch (e) { - // return Promise.reject(`Failed to obtain 'synchronize changes' title value from the status bar.`); - // } - // } - - // private getFirstChangeIndex(changeClass: string, selector: string): Promise { - // return this.spectron.waitFor(this.spectron.client.waitForHTML, selector).then(html => { - // return new Promise((res, rej) => { - // let lineIndex: number = 0; - // let changeFound: boolean; - // let tags: string[] = []; - // let parser = new htmlparser.Parser({ - // onopentag: function (name: string, attribs: any) { - // tags.push(name); - // if (name === 'div' && !attribs.class) { - // lineIndex++; - // } else if (name === 'div' && attribs.class === changeClass) { - // changeFound = true; - // parser.end(); - // } - // }, - // onclosetag: function (name) { - // // Terminate once last tag is closed - // tags.pop(); - // if (!changeFound && tags.length === 0) { - // parser.end(); - // } - // }, - // onend: function () { - // if (!changeFound) { - // return rej(`No changes in the diff found.`); - // } - // return res(lineIndex); - // } - // }); - // parser.write(html); - // }); - // }); - // } } \ No newline at end of file diff --git a/test/smoke/src/areas/integrated-terminal.ts b/test/smoke/src/areas/integrated-terminal.ts deleted file mode 100644 index 1ceb5a8ebeb..00000000000 --- a/test/smoke/src/areas/integrated-terminal.ts +++ /dev/null @@ -1,54 +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 { SpectronApplication } from '../spectron/application'; -import { CommonActions } from './common'; - -export class IntegratedTerminal { - - public static terminalSelector = 'div[id="workbench.panel.terminal"]'; - public static terminalRowsSelector = 'div[id="workbench.panel.terminal"] .xterm-rows'; - - constructor(private spectron: SpectronApplication) { - // noop - } - - public async openTerminal(commonActions: CommonActions): Promise { - // Backquote dispatching does not work in OS X - if (process.platform === 'darwin') { - await commonActions.showCommands(); - await commonActions.type('Toggle Integrated Terminal'); - return commonActions.enter(); - } - - await this.spectron.command('workbench.action.terminal.toggleTerminal'); - - // If no terminal panel was opened, try triggering terminal from quick open - try { - await this.spectron.client.waitForHTML(IntegratedTerminal.terminalSelector); - } catch (e) { - await commonActions.openQuickOpen(); - await this.spectron.client.keys('>Toggle Integrated Terminal'); - await this.spectron.client.keys(['Enter', 'NULL']); - } - } - - public async commandOutputHas(result: string): Promise { - const rows = await this.spectron.client.waitForElements(`${IntegratedTerminal.terminalRowsSelector} div`); - for (let i = 0; i < rows.length; i++) { - let rowText; - try { - rowText = await this.spectron.client.getText(`${IntegratedTerminal.terminalRowsSelector}>:nth-child(${i + 1})`); - } catch (e) { - return Promise.reject(`Failed to obtain text from line ${i + 1} from the terminal.`); - } - if (rowText.trim() === result) { - return true; - } - } - - return false; - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/javascript-debug.ts b/test/smoke/src/areas/javascript-debug.ts deleted file mode 100644 index bfd7a59d941..00000000000 --- a/test/smoke/src/areas/javascript-debug.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 { SpectronApplication } from '../spectron/application'; -var stripJsonComments = require('strip-json-comments'); - -export class JavaScriptDebug { - private readonly sidebarSelector = '.margin-view-overlays'; - - constructor(private spectron: SpectronApplication) { - // noop - } - - public openDebugViewlet(): Promise { - return this.spectron.command('workbench.view.debug'); - } - - public async pressConfigureLaunchJson(): Promise { - try { - await this.spectron.waitFor(this.spectron.client.waitAndClick, 'ul[aria-label="Debug actions"] .action-label.icon.debug-action.configure'); - } catch (e) { - return Promise.reject('Clicking on debug configuration gear failed.'); - } - await this.spectron.wait(); - await this.spectron.client.keys(['ArrowDown', 'NULL', 'Enter']); - return this.spectron.wait(); - } - - public async getProgramConfigValue(): Promise { - const lines = stripJsonComments(await this.spectron.client.getText('.view-lines')); - const json = JSON.parse(lines); - return json.configurations[0].program; - } - - public setBreakpointOnLine(lineNumber: number): Promise { - try { - return this.spectron.client.leftClick(`${this.sidebarSelector}>:nth-child(${lineNumber})`, 5, 5); - } catch (e) { - return Promise.reject('Setting breakpoint failed: ' + e); - } - } - - public async verifyBreakpointOnLine(lineNumber: number): Promise { - let el = await this.spectron.client.waitForElement(`${this.sidebarSelector}>:nth-child(${lineNumber}) .cgmr.debug-breakpoint-glyph`); - if (el) { - return el; - } - - return undefined; - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/javascript.ts b/test/smoke/src/areas/javascript.ts deleted file mode 100644 index 1493ddc552f..00000000000 --- a/test/smoke/src/areas/javascript.ts +++ /dev/null @@ -1,186 +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 { SpectronApplication } from '../spectron/application'; - -var htmlparser = require('htmlparser2'); - -export class JavaScript { - private appVarSelector: string; - private expressVarSelector: string; - - private foldSelector: string; - private foldLine: number; - - constructor(private spectron: SpectronApplication) { - // noop - } - - public openQuickOutline(): Promise { - return this.spectron.command('workbench.action.gotoSymbol'); - } - - public async findAppReferences(): Promise { - await this.setAppVarSelector(); - try { - await this.spectron.client.waitAndClick(this.appVarSelector); - } catch (e) { - return Promise.reject(`Failed to select 'app' variable.`); - } - - return this.spectron.command('editor.action.referenceSearch.trigger'); - } - - public async getTitleReferencesCount(): Promise { - const meta = await this.spectron.client.getText('.reference-zone-widget.results-loaded .peekview-title .meta'); - - return meta.match(/\d+/)[0]; - } - - public async getTreeReferencesCount(): Promise { - const treeElems = await this.spectron.client.waitForElements('.reference-zone-widget.results-loaded .ref-tree.inline .show-twisties .monaco-tree-row'); - - return treeElems.length; - } - - public async renameApp(newValue: string): Promise { - await this.setAppVarSelector(); - - try { - await this.spectron.client.waitAndClick(this.appVarSelector); - } catch (e) { - return Promise.reject(`Failed to select 'app' variable.`); - } - await this.spectron.command('editor.action.rename'); - await this.spectron.wait(); - return this.spectron.client.keys(newValue, false); - } - - public async getNewAppName(): Promise { - return this.spectron.client.getText(this.appVarSelector); - } - - public async toggleFirstCommentFold(): Promise { - this.foldLine = await this.getLineIndexOfFirstFoldableElement(`.margin-view-overlays`); - this.foldSelector = `.margin-view-overlays>:nth-child(${this.foldLine})`; - - try { - return this.spectron.client.waitAndClick(`${this.foldSelector} .cldr.folding`); - } catch (e) { - return Promise.reject('Clicking on fold element failed ' + e); - } - } - - public async getFirstCommentFoldedIcon(): Promise { - if (!this.foldSelector) { - return Promise.reject('No code folding happened to be able to check for a folded icon.'); - } - - return this.spectron.client.waitForHTML(`${this.foldSelector} .cldr.folding.collapsed`); - } - - public async getNextLineNumberAfterFold(): Promise { - if (!this.foldLine) { - return Promise.reject('Folded line was not set, most likely because fold was not toggled initially.'); - } - - return this.spectron.client.getText(`.margin-view-overlays>:nth-child(${this.foldLine + 1}) .line-numbers`); - } - - public async goToExpressDefinition(): Promise { - await this.setExpressVarSelector(); - try { - await this.spectron.client.waitAndClick(this.expressVarSelector); - } catch (e) { - return Promise.reject(`Clicking on express variable failed: ` + e); - } - - return this.spectron.command('editor.action.goToDeclaration'); - } - - public async peekExpressDefinition(): Promise { - await this.setExpressVarSelector(); - try { - await this.spectron.client.waitAndClick(this.expressVarSelector); - } catch (e) { - return Promise.reject('Clicking on express variable failed: ' + e); - } - - return this.spectron.command('editor.action.previewDeclaration'); - } - - public async getPeekExpressResultName(): Promise { - return this.spectron.client.getText('.reference-zone-widget.results-loaded .filename'); - } - - private async setAppVarSelector(): Promise { - if (!this.appVarSelector) { - const lineIndex = await this.getLineIndexOfFirst('app', '.view-lines'); - this.appVarSelector = `.view-lines>:nth-child(${lineIndex}) .mtk11`; - } - } - - private async setExpressVarSelector(): Promise { - if (!this.expressVarSelector) { - const lineIndex = await this.getLineIndexOfFirst('express', '.view-lines'); - this.expressVarSelector = `.view-lines>:nth-child(${lineIndex}) .mtk10`; - } - } - - private getLineIndexOfFirst(string: string, selector: string): Promise { - return this.spectron.waitFor(this.spectron.client.waitForHTML, selector).then(html => { - return new Promise((res, rej) => { - let lineIndex: number = 0; - let stringFound: boolean; - let parser = new htmlparser.Parser({ - onopentag: function (name: string, attribs: any) { - if (name === 'div' && attribs.class === 'view-line') { - lineIndex++; - } - }, - ontext: function (text) { - if (!stringFound && text === string) { - stringFound = true; - parser.end(); - } - }, - onend: function () { - if (!stringFound) { - return rej(`No ${string} in editor found.`); - } - return res(lineIndex); - } - }); - parser.write(html); - }); - }); - } - - private getLineIndexOfFirstFoldableElement(selector: string): Promise { - return this.spectron.waitFor(this.spectron.client.waitForHTML, selector).then(html => { - return new Promise((res, rej) => { - let lineIndex: number = 0; - let foldFound: boolean; - let parser = new htmlparser.Parser({ - onopentag: function (name: string, attribs: any) { - if (name === 'div' && !attribs.class) { - lineIndex++; - } else if (name === 'div' && attribs.class.indexOf('cldr folding') !== -1) { - foldFound = true; - parser.end(); - } - }, - onend: function () { - if (!foldFound) { - return rej(`No foldable elements found.`); - } - return res(lineIndex); - } - }); - parser.write(html); - }); - }); - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/localization.ts b/test/smoke/src/areas/localization.ts deleted file mode 100644 index 43205d3447c..00000000000 --- a/test/smoke/src/areas/localization.ts +++ /dev/null @@ -1,70 +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 { SpectronApplication } from '../spectron/application'; - -export enum ViewletType { - SEARCH = 0, - SCM = 1, - DEBUG = 2, - EXTENSIONS = 3 -} - -export class Localization { - - constructor(private spectron: SpectronApplication) { - // noop - } - - public async getOpenEditorsText(): Promise { - let explorerTitles; - try { - explorerTitles = await this.spectron.client.getText('div[id="workbench.view.explorer"] .title span'); - } catch (e) { - return Promise.reject('Failed to get span of title in explorer viewlet.'); - } - - return explorerTitles[0]; - } - - public async openViewlet(type: ViewletType): Promise { - let command; - - switch (type) { - case ViewletType.SEARCH: - command = 'workbench.view.search'; - break; - case ViewletType.SCM: - command = 'workbench.view.scm'; - break; - case ViewletType.DEBUG: - command = 'workbench.view.debug'; - break; - case ViewletType.EXTENSIONS: - command = 'workbench.view.extensions'; - break; - } - - await this.spectron.command(command, false); - return this.spectron.wait(); - } - - public getOpenedViewletTitle(): Promise { - try { - return this.spectron.client.getText('div[id="workbench.parts.sidebar"] .title-label span'); - } catch (e) { - return Promise.reject('Failed to get span of title label in explorer viewlet.'); - } - } - - public getExtensionsSearchPlaceholder(): Promise { - try { - return this.spectron.client.getAttribute('div[id="workbench.view.extensions"] .search-box', 'placeholder'); - } catch (e) { - return Promise.reject('Failed to get extension viewlet search box placeholder.'); - } - } - -} diff --git a/test/smoke/src/areas/multiroot/multiroot.test.ts b/test/smoke/src/areas/multiroot/multiroot.test.ts index 5a6cecf712d..9529fe3c324 100644 --- a/test/smoke/src/areas/multiroot/multiroot.test.ts +++ b/test/smoke/src/areas/multiroot/multiroot.test.ts @@ -4,28 +4,34 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, CODE_WORKSPACE_PATH } from '../../spectron/application'; -import { QuickOpen } from '../quickopen/quickopen'; -import { Window } from '../window'; +import { SpectronApplication } from '../../spectron/application'; -describe('Multi Root', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [CODE_WORKSPACE_PATH]); - return app.start(); +describe('Multiroot', () => { + + before(async function () { + this.app.suiteName = 'Multiroot'; + + const app = this.app as SpectronApplication; + + await app.restart([app.workspaceFilePath]); + + // for some reason Code opens 2 windows at this point + // so let's select the last one + await app.client.windowByIndex(2); }); - after(() => app.stop()); it('shows results from all folders', async function () { - let quickOpen = new QuickOpen(app); - await quickOpen.openQuickOpen(); - await app.type('*.*'); - const elements = await quickOpen.getQuickOpenElements(); - assert.equal(elements.length, 6); + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openQuickOpen('*.*'); + + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length >= 6); + await app.workbench.quickopen.closeQuickOpen(); }); it('shows workspace name in title', async function () { - const title = await new Window(app).getTitle(); + const app = this.app as SpectronApplication; + const title = await app.client.getTitle(); + await app.screenCapturer.capture('window title'); assert.ok(title.indexOf('smoketest (Workspace)') >= 0); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/preferences/keybindings.ts b/test/smoke/src/areas/preferences/keybindings.ts index 2981ff13bfa..1de2eba3470 100644 --- a/test/smoke/src/areas/preferences/keybindings.ts +++ b/test/smoke/src/areas/preferences/keybindings.ts @@ -5,36 +5,24 @@ import { SpectronApplication } from '../../spectron/application'; +const SEARCH_INPUT = '.settings-search-input input'; + export class KeybindingsEditor { - constructor(private spectron: SpectronApplication) { - // noop - } + constructor(private spectron: SpectronApplication) { } - public async openKeybindings(): Promise { - await this.spectron.command('workbench.action.openGlobalKeybindings'); - await this.spectron.client.waitForElement('.settings-search-input .synthetic-focus'); - } + async updateKeybinding(command: string, keys: string[], ariaLabel: string): Promise { + await this.spectron.runCommand('workbench.action.openGlobalKeybindings'); + await this.spectron.client.waitForActiveElement(SEARCH_INPUT); + await this.spectron.client.setValue(SEARCH_INPUT, command); - public async search(text: string, select: boolean = false): Promise { - await this.spectron.type(text); - if (select) { - await this.spectron.client.waitAndClick('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item'); - await this.spectron.client.waitForElement('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item.focused.selected'); - } - } + await this.spectron.client.waitAndClick('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item'); + await this.spectron.client.waitForElement('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item.focused.selected'); - public async openDefineKeybindingDialog(): Promise { await this.spectron.client.waitAndClick('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item .action-item .icon.add'); - return this.spectron.client.waitForElement('.defineKeybindingWidget .monaco-inputbox.synthetic-focus'); - } + await this.spectron.client.waitForElement('.defineKeybindingWidget .monaco-inputbox.synthetic-focus'); - public async updateKeybinding(command: string, keys: string[], ariaLabel: string): Promise { - await this.search(command, true); - await this.openDefineKeybindingDialog(); - await this.spectron.client.keys(keys); - await this.spectron.client.keys(['Enter', 'NULL']); + await this.spectron.client.keys([...keys, 'NULL', 'Enter', 'NULL']); await this.spectron.client.waitForElement(`div[aria-label="Keybindings"] div[aria-label="Keybinding is ${ariaLabel}."]`); } - } \ No newline at end of file diff --git a/test/smoke/src/areas/preferences/preferences.test.ts b/test/smoke/src/areas/preferences/preferences.test.ts index f3cb02035d9..139997dfa82 100644 --- a/test/smoke/src/areas/preferences/preferences.test.ts +++ b/test/smoke/src/areas/preferences/preferences.test.ts @@ -5,41 +5,42 @@ import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; +import { SpectronApplication } from '../../spectron/application'; import { ActivityBarPosition } from '../activitybar/activityBar'; describe('Preferences', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH]); - return app.start(); + before(function () { + this.app.suiteName = 'Preferences'; }); - after(() => app.stop()); it('turns off editor line numbers and verifies the live change', async function () { + const app = this.app as SpectronApplication; + await app.workbench.explorer.openFile('app.js'); let lineNumbers = await app.client.waitForElements('.line-numbers'); + await app.screenCapturer.capture('app.js has line numbers'); assert.ok(!!lineNumbers.length, 'Line numbers are not present in the editor before disabling them.'); - await app.workbench.settingsEditor.openUserSettings(); - await app.workbench.settingsEditor.focusEditableSettings(); - await app.client.keys(`"editor.lineNumbers": "off"`); - await app.workbench.saveOpenedFile(); - + await app.workbench.settingsEditor.addUserSetting('editor.lineNumbers', '"off"'); await app.workbench.selectTab('app.js'); lineNumbers = await app.client.waitForElements('.line-numbers', result => !result || result.length === 0); + + await app.screenCapturer.capture('line numbers hidden'); assert.ok(!lineNumbers.length, 'Line numbers are still present in the editor after disabling them.'); }); it(`changes 'workbench.action.toggleSidebarPosition' command key binding and verifies it`, async function () { - let activityBarElement = await app.workbench.activitybar.getActivityBar(ActivityBarPosition.LEFT); - assert.ok(activityBarElement, 'Activity bar should be positioned on the left.'); + const app = this.app as SpectronApplication; + assert.ok(await app.workbench.activitybar.getActivityBar(ActivityBarPosition.LEFT), 'Activity bar should be positioned on the left.'); - await app.workbench.keybindingsEditor.openKeybindings(); - await app.workbench.keybindingsEditor.updateKeybinding('workbench.action.toggleSidebarPosition', ['Control', 'u', 'NULL'], 'Control+U'); + await app.workbench.keybindingsEditor.updateKeybinding('workbench.action.toggleSidebarPosition', ['Control', 'u'], 'Control+U'); await app.client.keys(['Control', 'u', 'NULL']); - activityBarElement = await app.workbench.activitybar.getActivityBar(ActivityBarPosition.RIGHT); - assert.ok(activityBarElement, 'Activity bar was not moved to right after toggling its position.'); + assert.ok(await app.workbench.activitybar.getActivityBar(ActivityBarPosition.RIGHT), 'Activity bar was not moved to right after toggling its position.'); + }); + + after(async function () { + const app = this.app as SpectronApplication; + await app.workbench.settingsEditor.clearUserSettings(); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/preferences/settings.ts b/test/smoke/src/areas/preferences/settings.ts index 8e62c210e12..657d71357e9 100644 --- a/test/smoke/src/areas/preferences/settings.ts +++ b/test/smoke/src/areas/preferences/settings.ts @@ -3,37 +3,43 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as fs from 'fs'; +import * as path from 'path'; import { SpectronApplication } from '../../spectron/application'; -import { Element } from 'webdriverio'; export enum ActivityBarPosition { LEFT = 0, RIGHT = 1 -}; +} + +const SEARCH_INPUT = '.settings-search-input input'; +const EDITOR = '.editable-preferences-editor-container .monaco-editor textarea'; export class SettingsEditor { - constructor(private spectron: SpectronApplication) { - // noop - } + constructor(private spectron: SpectronApplication) { } - public async openUserSettings(): Promise { - await this.spectron.command('workbench.action.openGlobalSettings'); - return this.spectron.client.waitForElement('.settings-search-input input:focus'); - } + async addUserSetting(setting: string, value: string): Promise { + await this.spectron.runCommand('workbench.action.openGlobalSettings'); + await this.spectron.client.waitAndClick(SEARCH_INPUT); + await this.spectron.client.waitForActiveElement(SEARCH_INPUT); - public async focusEditableSettings(): Promise { - await this.spectron.client.keys(['ArrowDown', 'NULL'], false); - await this.spectron.client.waitForElement(`.editable-preferences-editor-container .monaco-editor.focused`); - await this.spectron.client.keys(['ArrowRight', 'NULL'], false); - } + await this.spectron.client.keys(['ArrowDown', 'NULL']); + await this.spectron.client.waitForActiveElement(EDITOR); - public async addUserSetting(setting: string, value: string): Promise { - await this.openUserSettings(); + await this.spectron.client.keys(['ArrowRight', 'NULL']); + await this.spectron.screenCapturer.capture('user settings is open and focused'); - // await this.spectron.wait(1); - await this.focusEditableSettings(); - await this.spectron.client.keys(`"${setting}": ${value}`); + await this.spectron.workbench.editor.waitForTypeInEditor('settings.json', `"${setting}": ${value}`, '.editable-preferences-editor-container'); await this.spectron.workbench.saveOpenedFile(); + + await this.spectron.screenCapturer.capture('user settings has changed'); + } + + async clearUserSettings(): Promise { + const settingsPath = path.join(this.spectron.userDataPath, 'User', 'settings.json'); + await new Promise((c, e) => fs.writeFile(settingsPath, '{}', 'utf8', err => err ? e(err) : c())); + + await this.spectron.workbench.editor.waitForEditorContents('settings.json', c => c.length === 0, '.editable-preferences-editor-container'); } } \ No newline at end of file diff --git a/test/smoke/src/areas/problems/problems.ts b/test/smoke/src/areas/problems/problems.ts index ec05cd4a025..f28697e5e81 100644 --- a/test/smoke/src/areas/problems/problems.ts +++ b/test/smoke/src/areas/problems/problems.ts @@ -8,7 +8,7 @@ import { SpectronApplication } from '../../spectron/application'; export enum ProblemSeverity { WARNING = 0, ERROR = 1 -}; +} export class Problems { @@ -20,14 +20,14 @@ export class Problems { public async showProblemsView(): Promise { if (!await this.isVisible()) { - await this.spectron.command('workbench.actions.view.problems'); - await this.spectron.client.waitForElement(Problems.PROBLEMS_VIEW_SELECTOR); + await this.spectron.runCommand('workbench.actions.view.problems'); + await this.waitForProblemsView(); } } public async hideProblemsView(): Promise { if (await this.isVisible()) { - await this.spectron.command('workbench.actions.view.problems'); + await this.spectron.runCommand('workbench.actions.view.problems'); await this.spectron.client.waitForElement(Problems.PROBLEMS_VIEW_SELECTOR, el => !el); } } @@ -37,13 +37,17 @@ export class Problems { return !!element; } + public async waitForProblemsView(): Promise { + await this.spectron.client.waitForElement(Problems.PROBLEMS_VIEW_SELECTOR); + } + public static getSelectorInProblemsView(problemType: ProblemSeverity): string { let selector = problemType === ProblemSeverity.WARNING ? 'warning' : 'error'; return `div[aria-label="Problems grouped by files"] .icon.${selector}`; } public static getSelectorInEditor(problemType: ProblemSeverity): string { - let selector = problemType === ProblemSeverity.WARNING ? 'greensquiggly' : 'redsquiggly'; + let selector = problemType === ProblemSeverity.WARNING ? 'warningsquiggly' : 'errorsquiggly'; return `.view-overlays .cdr.${selector}`; } } \ No newline at end of file diff --git a/test/smoke/src/areas/quickopen/quickopen.ts b/test/smoke/src/areas/quickopen/quickopen.ts index 74700ce823a..4f70d280c11 100644 --- a/test/smoke/src/areas/quickopen/quickopen.ts +++ b/test/smoke/src/areas/quickopen/quickopen.ts @@ -4,65 +4,88 @@ *--------------------------------------------------------------------------------------------*/ import { SpectronApplication } from '../../spectron/application'; -import { Element } from 'webdriverio'; export class QuickOpen { + static QUICK_OPEN_HIDDEN = 'div.quick-open-widget[aria-hidden="true"]'; + static QUICK_OPEN = 'div.quick-open-widget[aria-hidden="false"]'; + static QUICK_OPEN_INPUT = `${QuickOpen.QUICK_OPEN} .quick-open-input input`; + static QUICK_OPEN_FOCUSED_ELEMENT = `${QuickOpen.QUICK_OPEN} .quick-open-tree .monaco-tree-row.focused .monaco-highlighted-label`; static QUICK_OPEN_ENTRY_SELECTOR = 'div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties .monaco-tree-row .quick-open-entry'; - constructor(readonly spectron: SpectronApplication) { - } + constructor(readonly spectron: SpectronApplication) { } - public async openQuickOpen(): Promise { - await this.spectron.command('workbench.action.quickOpen'); + async openQuickOpen(value: string): Promise { + await this.spectron.runCommand('workbench.action.quickOpen'); await this.waitForQuickOpenOpened(); + + if (value) { + await this.spectron.client.setValue(QuickOpen.QUICK_OPEN_INPUT, value); + } } - public async closeQuickOpen(): Promise { - await this.spectron.command('workbench.action.closeQuickOpen'); + async closeQuickOpen(): Promise { + await this.spectron.runCommand('workbench.action.closeQuickOpen'); await this.waitForQuickOpenClosed(); } - public async getQuickOpenElements(): Promise { - return this.spectron.client.waitForElements(QuickOpen.QUICK_OPEN_ENTRY_SELECTOR); - } + async openFile(fileName: string): Promise { + await this.openQuickOpen(fileName); - public async openFile(fileName: string): Promise { - await this.openQuickOpen(); - await this.spectron.type(fileName); - await this.getQuickOpenElements(); + await this.waitForQuickOpenElements(names => names.some(n => n === fileName)); await this.spectron.client.keys(['Enter', 'NULL']); - await this.spectron.client.waitForElement(`.tabs-container div[aria-selected="true"][aria-label="${fileName}, tab"]`); - await this.spectron.client.waitForElement(`div.editor-container[aria-label="${fileName}. Text file editor., Group 1."]`); + await this.spectron.workbench.waitForActiveTab(fileName); await this.spectron.workbench.waitForEditorFocus(fileName); } - protected waitForQuickOpenOpened(): Promise { - return this.spectron.client.waitForElement('div.quick-open-widget[aria-hidden="false"]'); + async runCommand(commandText: string): Promise { + await this.openQuickOpen(`> ${commandText}`); + + // wait for best choice to be focused + await this.spectron.client.waitForTextContent(QuickOpen.QUICK_OPEN_FOCUSED_ELEMENT, commandText); + + // wait and click on best choice + await this.spectron.client.waitAndClick(QuickOpen.QUICK_OPEN_FOCUSED_ELEMENT); } - protected waitForQuickOpenClosed(): Promise { - return this.spectron.client.waitForElement('div.quick-open-widget[aria-hidden="true"]'); + async waitForQuickOpenOpened(): Promise { + await this.spectron.client.waitForActiveElement(QuickOpen.QUICK_OPEN_INPUT); + + // we gotta wait 50 milliseconds due to https://github.com/Microsoft/vscode/blob/master/src/vs/platform/list/browser/listService.ts#L59 + await new Promise(c => setTimeout(c, 50)); } - public async isQuickOpenVisible(): Promise { - await this.waitForQuickOpenOpened(); - return true; + private async waitForQuickOpenClosed(): Promise { + await this.spectron.client.waitForElement(QuickOpen.QUICK_OPEN_HIDDEN); } - public async submit(text: string): Promise { - await this.spectron.type(text); + async submit(text: string): Promise { + await this.spectron.client.setValue(QuickOpen.QUICK_OPEN_INPUT, text); await this.spectron.client.keys(['Enter', 'NULL']); await this.waitForQuickOpenClosed(); } - public async selectQuickOpenElement(index: number): Promise { + async selectQuickOpenElement(index: number): Promise { await this.waitForQuickOpenOpened(); for (let from = 0; from < index; from++) { await this.spectron.client.keys(['ArrowDown', 'NULL']); - this.spectron.wait(3); } await this.spectron.client.keys(['Enter', 'NULL']); await this.waitForQuickOpenClosed(); } + + async waitForQuickOpenElements(accept: (names: string[]) => boolean): Promise { + await this.spectron.client.waitFor(() => this.getQuickOpenElements(), accept); + } + + private async getQuickOpenElements(): Promise { + const result = await this.spectron.webclient.selectorExecute(QuickOpen.QUICK_OPEN_ENTRY_SELECTOR, + div => (Array.isArray(div) ? div : [div]).map(element => { + const name = element.querySelector('.label-name') as HTMLElement; + return name.textContent; + }) + ); + + return Array.isArray(result) ? result : []; + } } diff --git a/test/smoke/src/areas/search/search.test.ts b/test/smoke/src/areas/search/search.test.ts index 08956ee48de..6f43bbab341 100644 --- a/test/smoke/src/areas/search/search.test.ts +++ b/test/smoke/src/areas/search/search.test.ts @@ -3,58 +3,54 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; +import { SpectronApplication } from '../../spectron/application'; describe('Search', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH]); - return app.start(); + before(function () { + this.app.suiteName = 'Search'; }); - after(() => app.stop()); it('searches for body & checks for correct result number', async function () { + const app = this.app as SpectronApplication; await app.workbench.search.openSearchViewlet(); await app.workbench.search.searchFor('body'); - const result = await app.workbench.search.getResultText(); - assert.equal(result, '7 results in 4 files'); + + await app.workbench.search.waitForResultText('7 results in 4 files'); }); it('searches only for *.js files & checks for correct result number', async function () { - await app.workbench.search.openSearchViewlet(); + const app = this.app as SpectronApplication; await app.workbench.search.searchFor('body'); await app.workbench.search.showQueryDetails(); - await app.workbench.search.setFilesToIncludeTextAndSearch('*.js'); - + await app.workbench.search.setFilesToIncludeText('*.js'); await app.workbench.search.submitSearch(); - const results = await app.workbench.search.getResultText(); - await app.workbench.search.setFilesToIncludeTextAndSearch(''); + await app.workbench.search.waitForResultText('4 results in 1 file'); + await app.workbench.search.setFilesToIncludeText(''); await app.workbench.search.hideQueryDetails(); - - assert.equal(results, '4 results in 1 file'); }); it('dismisses result & checks for correct result number', async function () { - await app.workbench.search.openSearchViewlet(); + const app = this.app as SpectronApplication; await app.workbench.search.searchFor('body'); - await app.workbench.search.removeFileMatch(1); - - const result = await app.workbench.search.getResultText(); - assert.equal(result, '3 results in 3 files', 'Result number after dismissal does not match to expected.'); + await app.workbench.search.waitForResultText('3 results in 3 files'); }); it('replaces first search result with a replace term', async function () { - await app.workbench.search.openSearchViewlet(); - await app.workbench.search.searchFor('body'); + const app = this.app as SpectronApplication; + await app.workbench.search.searchFor('body'); + await app.workbench.search.expandReplace(); await app.workbench.search.setReplaceText('ydob'); await app.workbench.search.replaceFileMatch(1); await app.workbench.saveOpenedFile(); - const result = await app.workbench.search.getResultText(); - assert.equal(result, '3 results in 3 files', 'Result number after replacemenet does not match to expected.'); + await app.workbench.search.waitForResultText('3 results in 3 files'); + + await app.workbench.search.searchFor('ydob'); + await app.workbench.search.setReplaceText('body'); + await app.workbench.search.replaceFileMatch(1); + await app.workbench.saveOpenedFile(); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/search/search.ts b/test/smoke/src/areas/search/search.ts index 3e7d859f67b..dbd995bcd72 100644 --- a/test/smoke/src/areas/search/search.ts +++ b/test/smoke/src/areas/search/search.ts @@ -4,93 +4,84 @@ *--------------------------------------------------------------------------------------------*/ import { SpectronApplication } from '../../spectron/application'; +import { Viewlet } from '../workbench/viewlet'; -export class Search { +const VIEWLET = 'div[id="workbench.view.search"] .search-viewlet'; +const INPUT = `${VIEWLET} .search-widget .search-container .monaco-inputbox input`; +const INCLUDE_INPUT = `${VIEWLET} .query-details .monaco-inputbox input[aria-label="Search Include Patterns"]`; - static SEARCH_VIEWLET_XPATH = 'div[id="workbench.view.search"] .search-viewlet'; +export class Search extends Viewlet { - constructor(private spectron: SpectronApplication) { - // noop + constructor(spectron: SpectronApplication) { + super(spectron); } - public async openSearchViewlet(): Promise { - if (!await this.isSearchViewletFocused()) { - await this.spectron.command('workbench.view.search'); - await this.spectron.client.waitForElement(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .monaco-inputbox.synthetic-focus input[placeholder="Search"]`); - } + async openSearchViewlet(): Promise { + await this.spectron.runCommand('workbench.view.search'); + await this.spectron.client.waitForActiveElement(INPUT); } - public async isSearchViewletFocused(): Promise { - const element = await this.spectron.client.element(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .monaco-inputbox.synthetic-focus input[placeholder="Search"]`); - return !!element; - } - - public async searchFor(text: string): Promise { - const searchBoxSelector = `${Search.SEARCH_VIEWLET_XPATH} .search-widget .search-container .monaco-inputbox input[placeholder="Search"]`; - - await this.spectron.client.clearElement(searchBoxSelector); - await this.spectron.client.click(searchBoxSelector); - await this.spectron.client.element(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .search-container .monaco-inputbox.synthetic-focus input[placeholder="Search"]`); - - await this.spectron.client.keys(text); - + async searchFor(text: string): Promise { + await this.spectron.client.click(INPUT); + await this.spectron.client.waitForActiveElement(INPUT); + await this.spectron.client.setValue(INPUT, text); await this.submitSearch(); } - public async submitSearch(): Promise { - await this.spectron.client.click(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .search-container .monaco-inputbox input[placeholder="Search"]`); - await this.spectron.client.element(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .search-container .monaco-inputbox.synthetic-focus input[placeholder="Search"]`); - await this.spectron.client.keys(['NULL', 'Enter', 'NULL'], false); - await this.spectron.client.element(`${Search.SEARCH_VIEWLET_XPATH} .messages[aria-hidden="false"]`); + async submitSearch(): Promise { + await this.spectron.client.click(INPUT); + await this.spectron.client.waitForActiveElement(INPUT); + + await this.spectron.client.keys(['Enter', 'NULL']); + await this.spectron.client.element(`${VIEWLET} .messages[aria-hidden="false"]`); } - public async setFilesToIncludeTextAndSearch(text: string): Promise { - await this.spectron.client.click(`${Search.SEARCH_VIEWLET_XPATH} .query-details .monaco-inputbox input[aria-label="Search Include Patterns"]`); - await this.spectron.client.element(`${Search.SEARCH_VIEWLET_XPATH} .query-details .monaco-inputbox.synthetic-focus input[aria-label="Search Include Patterns"]`); - await this.spectron.client.clearElement(`${Search.SEARCH_VIEWLET_XPATH} .query-details .monaco-inputbox.synthetic-focus input[aria-label="Search Include Patterns"]`); - - if (text) { - await this.spectron.client.keys(text); - } + async setFilesToIncludeText(text: string): Promise { + await this.spectron.client.click(INCLUDE_INPUT); + await this.spectron.client.waitForActiveElement(INCLUDE_INPUT); + await this.spectron.client.setValue(INCLUDE_INPUT, text || ''); } - public async showQueryDetails(): Promise { + async showQueryDetails(): Promise { if (!await this.areDetailsVisible()) { - await this.spectron.client.waitAndClick(`${Search.SEARCH_VIEWLET_XPATH} .query-details .more`); + await this.spectron.client.waitAndClick(`${VIEWLET} .query-details .more`); } } - public async hideQueryDetails(): Promise { + async hideQueryDetails(): Promise { if (await this.areDetailsVisible()) { - await this.spectron.client.waitAndClick(`${Search.SEARCH_VIEWLET_XPATH} .query-details.more .more`); + await this.spectron.client.waitAndClick(`${VIEWLET} .query-details.more .more`); } } - public async areDetailsVisible(): Promise { - const element = await this.spectron.client.element(`${Search.SEARCH_VIEWLET_XPATH} .query-details.more`); + async areDetailsVisible(): Promise { + const element = await this.spectron.client.element(`${VIEWLET} .query-details.more`); return !!element; } - public async removeFileMatch(index: number): Promise { - await this.spectron.client.waitAndmoveToObject(`${Search.SEARCH_VIEWLET_XPATH} .results .monaco-tree-rows>:nth-child(${index}) .filematch`); - const file = await this.spectron.client.waitForText(`${Search.SEARCH_VIEWLET_XPATH} .results .monaco-tree-rows>:nth-child(${index}) .filematch a.label-name`); - await this.spectron.client.click(`${Search.SEARCH_VIEWLET_XPATH} .results .monaco-tree-rows>:nth-child(${index}) .filematch .action-label.icon.action-remove`); - await this.spectron.client.waitForText(`${Search.SEARCH_VIEWLET_XPATH} .results .monaco-tree-rows>:nth-child(${index}) .filematch a.label-name`, void 0, result => result !== file); + async removeFileMatch(index: number): Promise { + await this.spectron.client.waitAndMoveToObject(`${VIEWLET} .results .monaco-tree-rows>:nth-child(${index}) .filematch`); + const file = await this.spectron.client.waitForText(`${VIEWLET} .results .monaco-tree-rows>:nth-child(${index}) .filematch a.label-name`); + await this.spectron.client.waitAndClick(`${VIEWLET} .results .monaco-tree-rows>:nth-child(${index}) .filematch .action-label.icon.action-remove`); + await this.spectron.client.waitForText(`${VIEWLET} .results .monaco-tree-rows>:nth-child(${index}) .filematch a.label-name`, void 0, result => result !== file); } - public async setReplaceText(text: string): Promise { - await this.spectron.client.waitAndClick(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .monaco-button.toggle-replace-button.collapse`); - await this.spectron.client.waitAndClick(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .replace-container .monaco-inputbox input[title="Replace"]`); - await this.spectron.client.element(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .replace-container .monaco-inputbox.synthetic-focus input[title="Replace"]`); - await this.spectron.client.setValue(`${Search.SEARCH_VIEWLET_XPATH} .search-widget .replace-container .monaco-inputbox.synthetic-focus input[title="Replace"]`, text); + async expandReplace(): Promise { + await this.spectron.client.waitAndClick(`${VIEWLET} .search-widget .monaco-button.toggle-replace-button.collapse`); } - public async replaceFileMatch(index: number): Promise { - await this.spectron.client.waitAndmoveToObject(`${Search.SEARCH_VIEWLET_XPATH} .results .monaco-tree-rows>:nth-child(${index}) .filematch`); - await this.spectron.client.click(`${Search.SEARCH_VIEWLET_XPATH} .results .monaco-tree-rows>:nth-child(${index}) .filematch .action-label.icon.action-replace-all`); + async setReplaceText(text: string): Promise { + await this.spectron.client.waitAndClick(`${VIEWLET} .search-widget .replace-container .monaco-inputbox input[title="Replace"]`); + await this.spectron.client.element(`${VIEWLET} .search-widget .replace-container .monaco-inputbox.synthetic-focus input[title="Replace"]`); + await this.spectron.client.setValue(`${VIEWLET} .search-widget .replace-container .monaco-inputbox.synthetic-focus input[title="Replace"]`, text); } - public async getResultText(): Promise { - return this.spectron.client.waitForText(`${Search.SEARCH_VIEWLET_XPATH} .messages[aria-hidden="false"] .message>p`); + async replaceFileMatch(index: number): Promise { + await this.spectron.client.waitAndMoveToObject(`${VIEWLET} .results .monaco-tree-rows>:nth-child(${index}) .filematch`); + await this.spectron.client.click(`${VIEWLET} .results .monaco-tree-rows>:nth-child(${index}) .filematch .action-label.icon.action-replace-all`); + } + + async waitForResultText(text: string): Promise { + await this.spectron.client.waitForText(`${VIEWLET} .messages[aria-hidden="false"] .message>p`, text); } } \ No newline at end of file diff --git a/test/smoke/src/areas/statusbar/statusbar.test.ts b/test/smoke/src/areas/statusbar/statusbar.test.ts index dcc9fcbb30d..d4bff75312a 100644 --- a/test/smoke/src/areas/statusbar/statusbar.test.ts +++ b/test/smoke/src/areas/statusbar/statusbar.test.ts @@ -5,82 +5,93 @@ import * as assert from 'assert'; -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; +import { SpectronApplication, Quality } from '../../spectron/application'; import { StatusBarElement } from './statusbar'; - describe('Statusbar', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH]); - return app.start(); + before(function () { + this.app.suiteName = 'Statusbar'; }); - after(() => app.stop()); it('verifies presence of all default status bar elements', async function () { - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.BRANCH_STATUS), 'Branch indicator is not visible.'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.FEEDBACK_ICON), 'Feedback icon is not visible.'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.SYNC_STATUS), 'Sync indicator is not visible.'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.PROBLEMS_STATUS), 'Problems indicator is not visible.'); + const app = this.app as SpectronApplication; + + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.BRANCH_STATUS); + if (app.quality !== Quality.Dev) { + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.FEEDBACK_ICON); + } + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.SYNC_STATUS); + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.PROBLEMS_STATUS); await app.workbench.quickopen.openFile('app.js'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.ENCODING_STATUS), 'Encoding indicator is not visible.'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.EOL_STATUS), 'EOL indicator is not visible.'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.INDENTATION_STATUS), 'Indentation indicator is not visible.'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.LANGUAGE_STATUS), 'Language indicator is not visible.'); - assert.ok(app.workbench.statusbar.isVisible(StatusBarElement.SELECTION_STATUS), 'Selection indicator is not visible.'); + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.ENCODING_STATUS); + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.EOL_STATUS); + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.INDENTATION_STATUS); + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.LANGUAGE_STATUS); + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.SELECTION_STATUS); }); it(`verifies that 'quick open' opens when clicking on status bar elements`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.statusbar.clickOn(StatusBarElement.BRANCH_STATUS); - assert.ok(await app.workbench.quickopen.isQuickOpenVisible(), 'Quick open is not opened for branch indicator.'); + await app.workbench.quickopen.waitForQuickOpenOpened(); await app.workbench.quickopen.closeQuickOpen(); await app.workbench.quickopen.openFile('app.js'); await app.workbench.statusbar.clickOn(StatusBarElement.INDENTATION_STATUS); - assert.ok(await app.workbench.quickopen.isQuickOpenVisible(), 'Quick open is not opened for indentation indicator.'); + await app.workbench.quickopen.waitForQuickOpenOpened(); await app.workbench.quickopen.closeQuickOpen(); await app.workbench.statusbar.clickOn(StatusBarElement.ENCODING_STATUS); - assert.ok(await app.workbench.quickopen.isQuickOpenVisible(), 'Quick open is not opened for encoding indicator.'); + await app.workbench.quickopen.waitForQuickOpenOpened(); await app.workbench.quickopen.closeQuickOpen(); await app.workbench.statusbar.clickOn(StatusBarElement.EOL_STATUS); - assert.ok(await app.workbench.quickopen.isQuickOpenVisible(), 'Quick open is not opened for EOL indicator.'); + await app.workbench.quickopen.waitForQuickOpenOpened(); await app.workbench.quickopen.closeQuickOpen(); await app.workbench.statusbar.clickOn(StatusBarElement.LANGUAGE_STATUS); - assert.ok(await app.workbench.quickopen.isQuickOpenVisible(), 'Quick open is not opened for language indicator.'); + await app.workbench.quickopen.waitForQuickOpenOpened(); await app.workbench.quickopen.closeQuickOpen(); }); it(`verifies that 'Problems View' appears when clicking on 'Problems' status element`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.statusbar.clickOn(StatusBarElement.PROBLEMS_STATUS); - assert.ok(await app.workbench.problems.isVisible()); + await app.workbench.problems.waitForProblemsView(); }); it(`verifies that 'Tweet us feedback' pop-up appears when clicking on 'Feedback' icon`, async function () { - if (app.inDevMode) { - return; + const app = this.app as SpectronApplication; + + if (app.quality === Quality.Dev) { + return this.skip(); } + await app.workbench.statusbar.clickOn(StatusBarElement.FEEDBACK_ICON); assert.ok(!!await app.client.waitForElement('.feedback-form')); }); it(`checks if 'Go to Line' works if called from the status bar`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openFile('app.js'); await app.workbench.statusbar.clickOn(StatusBarElement.SELECTION_STATUS); - assert.ok(await app.workbench.quickopen.isQuickOpenVisible(), 'Quick open is not opened line number selection.'); + await app.workbench.quickopen.waitForQuickOpenOpened(); - await app.workbench.quickopen.submit('15'); + await app.workbench.quickopen.submit(':15'); await app.workbench.editor.waitForHighlightingLine(15); }); it(`verifies if changing EOL is reflected in the status bar`, async function () { + const app = this.app as SpectronApplication; + await app.workbench.quickopen.openFile('app.js'); await app.workbench.statusbar.clickOn(StatusBarElement.EOL_STATUS); - assert.ok(await app.workbench.quickopen.isQuickOpenVisible(), 'Quick open is not opened line number selection.'); + await app.workbench.quickopen.waitForQuickOpenOpened(); + await app.workbench.quickopen.selectQuickOpenElement(1); - app.workbench.quickopen.selectQuickOpenElement(1); await app.workbench.statusbar.waitForEOL('CRLF'); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/statusbar/statusbar.ts b/test/smoke/src/areas/statusbar/statusbar.ts index af0fe719097..18714e4eecc 100644 --- a/test/smoke/src/areas/statusbar/statusbar.ts +++ b/test/smoke/src/areas/statusbar/statusbar.ts @@ -19,14 +19,15 @@ export enum StatusBarElement { export class StatusBar { - // private selectorsMap: Map; private readonly mainSelector = 'div[id="workbench.parts.statusbar"]'; + private readonly leftSelector = '.statusbar-item.left'; + private readonly rightSelector = '.statusbar-item.right'; constructor(private spectron: SpectronApplication) { } - public async isVisible(element: StatusBarElement): Promise { - return this.spectron.client.isVisible(this.getSelector(element)); + public async waitForStatusbarElement(element: StatusBarElement): Promise { + await this.spectron.client.waitForElement(this.getSelector(element)); } public async clickOn(element: StatusBarElement): Promise { @@ -44,23 +45,23 @@ export class StatusBar { private getSelector(element: StatusBarElement): string { switch (element) { case StatusBarElement.BRANCH_STATUS: - return `${this.mainSelector} .octicon.octicon-git-branch`; + return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-git-branch`; case StatusBarElement.SYNC_STATUS: - return `${this.mainSelector} .octicon.octicon-sync`; + return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-sync`; case StatusBarElement.PROBLEMS_STATUS: - return `${this.mainSelector} .task-statusbar-item[title="Problems"]`; + return `${this.mainSelector} ${this.leftSelector} .task-statusbar-item[title="Problems"]`; case StatusBarElement.SELECTION_STATUS: - return `${this.mainSelector} .editor-status-selection`; + return `${this.mainSelector} ${this.rightSelector} .editor-status-selection`; case StatusBarElement.INDENTATION_STATUS: - return `${this.mainSelector} .editor-status-indentation`; + return `${this.mainSelector} ${this.rightSelector} .editor-status-indentation`; case StatusBarElement.ENCODING_STATUS: - return `${this.mainSelector} .editor-status-encoding`; + return `${this.mainSelector} ${this.rightSelector} .editor-status-encoding`; case StatusBarElement.EOL_STATUS: - return `${this.mainSelector} .editor-status-eol`; + return `${this.mainSelector} ${this.rightSelector} .editor-status-eol`; case StatusBarElement.LANGUAGE_STATUS: - return `${this.mainSelector} .editor-status-mode`; + return `${this.mainSelector} ${this.rightSelector} .editor-status-mode`; case StatusBarElement.FEEDBACK_ICON: - return `${this.mainSelector} .dropdown.send-feedback`; + return `${this.mainSelector} ${this.rightSelector} .dropdown.send-feedback`; default: throw new Error(element); } diff --git a/test/smoke/src/areas/tasks.ts b/test/smoke/src/areas/tasks.ts deleted file mode 100644 index 91785678f8b..00000000000 --- a/test/smoke/src/areas/tasks.ts +++ /dev/null @@ -1,89 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { SpectronApplication } from '../spectron/application'; -import { IntegratedTerminal } from './integrated-terminal'; - -export class Tasks { - - private readonly outputViewSelector = IntegratedTerminal.terminalRowsSelector; - private readonly workbenchPanelSelector = 'div[id="workbench.parts.panel"]'; - private readonly problemsViewSelector = 'div[id="workbench.panel.markers"] .monaco-tree-row.expanded'; - - constructor(private spectron: SpectronApplication) { - // noop - } - - public async build(): Promise { - await this.spectron.command('workbench.action.tasks.build'); - await this.spectron.wait(); // wait for build to finish - - // Validate that it has finished - let trial = 0; - while (trial < 3) { - // Determine build status based on the statusbar indicator, don't continue until task has been terminated - try { - return await this.spectron.client.getValue('.task-statusbar-item-progress.builder-hidden'); - } catch (e) { - await this.spectron.wait(); - trial++; - } - } - - return Promise.reject('Could not determine if the task was terminated based on status bar progress spinner.'); - } - - public openProblemsView(): Promise { - return this.spectron.command('workbench.actions.view.problems'); - } - - public async outputContains(string: string): Promise { - const output: string = await this.spectron.waitFor(this.spectron.client.getText, this.outputViewSelector); - - if (output.indexOf(string) !== -1) { - return true; - } - - return false; - } - - public async selectOutputViewType(type: string): Promise { - await this.openOutputView(); - - try { - return this.spectron.client.selectByValue(`${this.workbenchPanelSelector} .select-box`, type); - } catch (e) { - return Promise.reject(`Failed to select ${type} as workbench panel output.`); - } - } - - public getOutputViewType(): Promise { - return this.spectron.client.getValue(`${this.workbenchPanelSelector} .select-box`); - } - - public getProblemsViewFirstElementName(): Promise { - try { - return this.spectron.waitFor(this.spectron.client.getText, `${this.problemsViewSelector} .label-name`); - } catch (e) { - return Promise.reject('Failed to get problem label from Problems view: ' + e); - } - } - - public getProblemsViewFirstElementCount(): Promise { - try { - return this.spectron.waitFor(this.spectron.client.getText, `${this.problemsViewSelector} .monaco-count-badge`); - } catch (e) { - return Promise.reject('Failed to get problem count from Problems view: ' + e); - } - } - - private openOutputView(): Promise { - try { - return this.spectron.command('workbench.action.output.toggleOutput'); - } catch (e) { - return Promise.reject('Failed to toggle output view'); - } - } -} \ No newline at end of file diff --git a/test/smoke/src/areas/terminal/terminal.test.ts b/test/smoke/src/areas/terminal/terminal.test.ts new file mode 100644 index 00000000000..abbb77e61d5 --- /dev/null +++ b/test/smoke/src/areas/terminal/terminal.test.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// import { SpectronApplication } from '../../spectron/application'; + +describe('Terminal', () => { + // let app: SpectronApplication; + // before(() => { app = new SpectronApplication(); return app.start('Terminal'); }); + // after(() => app.stop()); + + // it(`opens terminal, runs 'echo' and verifies the output`, async function () { + // const expected = new Date().getTime().toString(); + // await app.workbench.terminal.showTerminal(); + + // await app.workbench.terminal.runCommand(`echo ${expected}`); + + // await app.workbench.terminal.waitForTerminalText(terminalText => { + // // Last line will not contain the output + // for (let index = terminalText.length - 2; index >= 0; index--) { + // if (!!terminalText[index] && terminalText[index].trim() === expected) { + // return true; + // } + // } + // return false; + // }); + // }); +}); \ No newline at end of file diff --git a/test/smoke/src/areas/terminal/terminal.ts b/test/smoke/src/areas/terminal/terminal.ts new file mode 100644 index 00000000000..951497edccf --- /dev/null +++ b/test/smoke/src/areas/terminal/terminal.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { SpectronApplication } from '../../spectron/application'; + +const PANEL_SELECTOR = 'div[id="workbench.panel.terminal"]'; +const XTERM_SELECTOR = `${PANEL_SELECTOR} .terminal-wrapper`; + +export class Terminal { + + constructor(private spectron: SpectronApplication) { } + + async showTerminal(): Promise { + if (!await this.isVisible()) { + await this.spectron.workbench.quickopen.runCommand('View: Toggle Integrated Terminal'); + await this.spectron.client.waitForElement(XTERM_SELECTOR); + await this.waitForTerminalText(text => text.length > 0, 'Waiting for Terminal to be ready'); + } + } + + async isVisible(): Promise { + const element = await this.spectron.client.element(PANEL_SELECTOR); + return !!element; + } + + async runCommand(commandText: string): Promise { + // TODO@Tyriar fix this. we should not use type but setValue + // await this.spectron.client.type(commandText); + await this.spectron.client.keys(['Enter', 'NULL']); + } + + async waitForTerminalText(fn: (text: string[]) => boolean, timeOutDescription: string = 'Getting Terminal Text'): Promise { + return this.spectron.client.waitFor(async () => { + const terminalText = await this.getTerminalText(); + if (fn(terminalText)) { + return terminalText; + } + return undefined; + }, void 0, timeOutDescription); + } + + getCurrentLineNumber(): Promise { + return this.getTerminalText().then(text => text.length); + } + + private async getTerminalText(): Promise { + return await this.spectron.webclient.selectorExecute(XTERM_SELECTOR, + div => { + const xterm = ((Array.isArray(div) ? div[0] : div)).xterm; + const buffer = xterm.buffer; + const lines: string[] = []; + for (let i = 0; i < buffer.lines.length; i++) { + lines.push(buffer.translateBufferLineToString(i, true)); + } + return lines; + } + ); + } +} \ No newline at end of file diff --git a/test/smoke/src/areas/workbench/commandPallette.ts b/test/smoke/src/areas/workbench/commandPallette.ts deleted file mode 100644 index 14ea3c88a2a..00000000000 --- a/test/smoke/src/areas/workbench/commandPallette.ts +++ /dev/null @@ -1,22 +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 { SpectronApplication } from '../../spectron/application'; -import { QuickOpen } from '../quickopen/quickopen'; - -export class CommandPallette extends QuickOpen { - - constructor(spectron: SpectronApplication) { - super(spectron); - } - - public async runCommand(commandText: string): Promise { - await this.spectron.command('workbench.action.showCommands'); - await this.waitForQuickOpenOpened(); - await this.spectron.type(commandText); - await this.spectron.client.waitForText(`div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties div.monaco-tree-row:nth-child(1) .quick-open-entry a.label-name span.monaco-highlighted-label span.highlight`, commandText); - await this.spectron.client.waitAndClick(`div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties div.monaco-tree-row:nth-child(1) .quick-open-entry`); - } -} diff --git a/test/smoke/src/areas/workbench/data-loss.test.ts b/test/smoke/src/areas/workbench/data-loss.test.ts index fceeba0f725..6f5131c49c8 100644 --- a/test/smoke/src/areas/workbench/data-loss.test.ts +++ b/test/smoke/src/areas/workbench/data-loss.test.ts @@ -3,34 +3,38 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as assert from 'assert'; -import { SpectronApplication, USER_DIR, LATEST_PATH, WORKSPACE_PATH } from '../../spectron/application'; -import * as path from 'path'; +import { SpectronApplication } from '../../spectron/application'; describe('Dataloss', () => { - let app: SpectronApplication; - before(() => { - app = new SpectronApplication(LATEST_PATH, '', 0, [WORKSPACE_PATH], [`--user-data-dir=${path.join(USER_DIR, new Date().getTime().toString(), 'dataloss')}`]); - return app.start(); + before(function () { + this.app.suiteName = 'Dataloss'; }); - after(() => app.stop()); it(`verifies that 'hot exit' works for dirty files`, async function () { - const textToType = 'Hello, Code', textToTypeInUntitled = 'Hello, Unitled Code', fileName = 'readme.md', untitled = 'Untitled-1'; + const app = this.app as SpectronApplication; await app.workbench.newUntitledFile(); - await app.client.type(textToTypeInUntitled); - await app.workbench.explorer.openFile(fileName); - await app.client.type(textToType); + + const untitled = 'Untitled-1'; + const textToTypeInUntitled = 'Hello, Unitled Code'; + await app.workbench.editor.waitForTypeInEditor(untitled, textToTypeInUntitled); + await app.screenCapturer.capture('Untitled file before reload'); + + const readmeMd = 'readme.md'; + const textToType = 'Hello, Code'; + await app.workbench.explorer.openFile(readmeMd); + await app.workbench.editor.waitForTypeInEditor(readmeMd, textToType); + await app.screenCapturer.capture(`${readmeMd} before reload`); await app.reload(); + await app.screenCapturer.capture('After reload'); - assert.ok(await app.workbench.waitForActiveOpen(fileName, true), `${fileName} tab is not present or is not active after reopening.`); - let actual = await app.workbench.editor.getEditorFirstLineText(); - assert.ok(actual.startsWith(textToType), `${actual} did not start with ${textToType}`); + await app.workbench.waitForActiveTab(readmeMd, true); + await app.screenCapturer.capture(`${readmeMd} after reload`); + await app.workbench.editor.waitForEditorContents(readmeMd, c => c.indexOf(textToType) > -1); - assert.ok(await app.workbench.waitForOpen(untitled, true), `${untitled} tab is not present after reopening.`); - await app.workbench.selectTab('Untitled-1', true); - actual = await app.workbench.editor.getEditorFirstLineText(); - assert.ok(actual.startsWith(textToTypeInUntitled), `${actual} did not start with ${textToTypeInUntitled}`); + await app.workbench.waitForTab(untitled, true); + await app.workbench.selectTab(untitled, true); + await app.screenCapturer.capture('Untitled file after reload'); + await app.workbench.editor.waitForEditorContents(untitled, c => c.indexOf(textToTypeInUntitled) > -1); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/workbench/data-migration.test.ts b/test/smoke/src/areas/workbench/data-migration.test.ts index cd806be2524..98213b85803 100644 --- a/test/smoke/src/areas/workbench/data-migration.test.ts +++ b/test/smoke/src/areas/workbench/data-migration.test.ts @@ -3,99 +3,85 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as assert from 'assert'; +// import * as assert from 'assert'; -import { SpectronApplication, USER_DIR, STABLE_PATH, LATEST_PATH, WORKSPACE_PATH, EXTENSIONS_DIR } from '../../spectron/application'; -import { Util } from '../../helpers/utilities'; +// import { SpectronApplication, STABLE_PATH, LATEST_PATH } from '../../spectron/application'; +// import { Util } from '../../helpers/utilities'; -let app: SpectronApplication; +// describe('Data Migration', () => { -export function testDataMigration() { - if (!STABLE_PATH) { - return; - } +// if (!STABLE_PATH) { +// return; +// } - describe('Data Migration', () => { +// let app: SpectronApplication; +// afterEach(() => app.stop()); - afterEach(async function () { - await app.stop(); - await Util.rimraf(USER_DIR); - return await Util.rimraf(EXTENSIONS_DIR); - }); +// it('checks if the Untitled file is restored migrating from stable to latest', async function () { +// const textToType = 'Very dirty file'; - function setupSpectron(context: Mocha.ITestCallbackContext, appPath: string, args?: string[]): void { - if (!args) { - args = []; - } - args.push(`--extensions-dir=${EXTENSIONS_DIR}`); +// // Setting up stable version +// let app = new SpectronApplication(STABLE_PATH); +// await app.start('Data Migration'); - app = new SpectronApplication(appPath, context.test.fullTitle(), context.test.currentRetry(), args, [`--user-data-dir=${USER_DIR}`]); - } +// await app.workbench.newUntitledFile(); +// await app.workbench.editor.waitForTypeInEditor('Untitled-1', textToType); - it('checks if the Untitled file is restored migrating from stable to latest', async function () { - const textToType = 'Very dirty file'; +// await app.stop(); +// await new Promise(c => setTimeout(c, 500)); // wait until all resources are released (e.g. locked local storage) +// // Checking latest version for the restored state - // Setting up stable version - setupSpectron(this, STABLE_PATH); - await app.start(); +// app = new SpectronApplication(LATEST_PATH); +// await app.start('Data Migration'); - await app.workbench.newUntitledFile(); - await app.type(textToType); +// assert.ok(await app.workbench.waitForActiveTab('Untitled-1', true), `Untitled-1 tab is not present after migration.`); - await app.stop(); - await app.wait(.5); // wait until all resources are released (e.g. locked local storage) - // Checking latest version for the restored state - setupSpectron(this, LATEST_PATH); - await app.start(); +// await app.workbench.editor.waitForEditorContents('Untitled-1', c => c.indexOf(textToType) > -1); +// await app.screenCapturer.capture('Untitled file text'); +// }); - assert.ok(await app.workbench.waitForActiveOpen('Untitled-1', true), `Untitled-1 tab is not present after migration.`); - const actual = await app.workbench.editor.getEditorFirstLineText(); - assert.ok(actual.startsWith(textToType), `${actual} did not start with ${textToType}`); - }); +// it('checks if the newly created dirty file is restored migrating from stable to latest', async function () { +// const fileName = 'test_data/plainFile', +// firstTextPart = 'This is going to be an unsaved file', secondTextPart = '_that is dirty.'; - it('checks if the newly created dirty file is restored migrating from stable to latest', async function () { - const fileName = 'test_data/plainFile', - firstTextPart = 'This is going to be an unsaved file', secondTextPart = '_that is dirty.'; +// // Setting up stable version +// let app = new SpectronApplication(STABLE_PATH, fileName); +// await Util.removeFile(`${fileName}`); +// await app.start('Data Migration'); - // Setting up stable version - setupSpectron(this, STABLE_PATH, [fileName]); - await Util.removeFile(`${fileName}`); - await app.start(); +// await app.workbench.editor.waitForTypeInEditor('plainFile', firstTextPart); +// await app.workbench.saveOpenedFile(); +// await app.workbench.editor.waitForTypeInEditor('plainFile', secondTextPart); - await app.workbench.waitForActiveOpen(fileName); - await app.type(firstTextPart); - await app.workbench.saveOpenedFile(); - await app.type(secondTextPart); +// await app.stop(); +// await new Promise(c => setTimeout(c, 1000)); // wait until all resources are released (e.g. locked local storage) - await app.stop(); - await app.wait(); // wait until all resources are released (e.g. locked local storage) - // Checking latest version for the restored state - setupSpectron(this, LATEST_PATH); - await app.start(); +// // Checking latest version for the restored state +// app = new SpectronApplication(LATEST_PATH); +// await app.start('Data Migration'); - assert.ok(await app.workbench.waitForActiveOpen(fileName.split('/')[1]), `Untitled-1 tab is not present after migration.`); - const actual = await app.workbench.editor.getEditorFirstLineText(); - assert.ok(actual.startsWith(firstTextPart.concat(secondTextPart)), `${actual} did not start with ${firstTextPart.concat(secondTextPart)}`); +// const filename = fileName.split('/')[1]; +// assert.ok(await app.workbench.waitForActiveTab(filename), `Untitled-1 tab is not present after migration.`); +// await app.workbench.editor.waitForEditorContents(filename, c => c.indexOf(firstTextPart + secondTextPart) > -1); - await Util.removeFile(`${fileName}`); - }); +// await Util.removeFile(`${fileName}`); +// }); - it('cheks if opened tabs are restored migrating from stable to latest', async function () { - const fileName1 = 'app.js', fileName2 = 'jsconfig.json', fileName3 = 'readme.md'; - setupSpectron(this, STABLE_PATH, [WORKSPACE_PATH]); - await app.start(); +// it('cheks if opened tabs are restored migrating from stable to latest', async function () { +// const fileName1 = 'app.js', fileName2 = 'jsconfig.json', fileName3 = 'readme.md'; +// let app = new SpectronApplication(STABLE_PATH); +// await app.start('Data Migration'); - await app.workbench.quickopen.openFile(fileName1); - await app.workbench.quickopen.openFile(fileName2); - await app.workbench.quickopen.openFile(fileName3); - await app.stop(); +// await app.workbench.quickopen.openFile(fileName1); +// await app.workbench.quickopen.openFile(fileName2); +// await app.workbench.quickopen.openFile(fileName3); +// await app.stop(); - setupSpectron(this, LATEST_PATH, [WORKSPACE_PATH]); - await app.start(); +// app = new SpectronApplication(LATEST_PATH); +// await app.start('Data Migration'); - assert.ok(await app.workbench.waitForOpen(fileName1), `${fileName1} tab was not restored after migration.`); - assert.ok(await app.workbench.waitForOpen(fileName2), `${fileName2} tab was not restored after migration.`); - assert.ok(await app.workbench.waitForOpen(fileName3), `${fileName3} tab was not restored after migration.`); - }); - }); -} \ No newline at end of file +// assert.ok(await app.workbench.waitForTab(fileName1), `${fileName1} tab was not restored after migration.`); +// assert.ok(await app.workbench.waitForTab(fileName2), `${fileName2} tab was not restored after migration.`); +// assert.ok(await app.workbench.waitForTab(fileName3), `${fileName3} tab was not restored after migration.`); +// }); +// }); \ No newline at end of file diff --git a/test/smoke/src/areas/workbench/localization.test.ts b/test/smoke/src/areas/workbench/localization.test.ts new file mode 100644 index 00000000000..a259e8d52d3 --- /dev/null +++ b/test/smoke/src/areas/workbench/localization.test.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; + +import { SpectronApplication, Quality } from '../../spectron/application'; + +describe('Localization', () => { + before(async function () { + const app = this.app as SpectronApplication; + this.app.suiteName = 'Localization'; + + if (app.quality === Quality.Dev) { + return; + } + + await app.restart(['--locale=DE']); + }); + + it(`starts with 'DE' locale and verifies title and viewlets text is in German`, async function () { + const app = this.app as SpectronApplication; + + if (app.quality === Quality.Dev) { + this.skip(); + return; + } + + let text = await app.workbench.explorer.getOpenEditorsViewTitle(); + await app.screenCapturer.capture('Open editors title'); + assert(/geƶffnete editoren/i.test(text)); + + await app.workbench.search.openSearchViewlet(); + text = await app.workbench.search.getTitle(); + await app.screenCapturer.capture('Search title'); + assert(/suchen/i.test(text)); + + await app.workbench.scm.openSCMViewlet(); + text = await app.workbench.scm.getTitle(); + await app.screenCapturer.capture('Scm title'); + assert(/quellcodeverwaltung/i.test(text)); + + await app.workbench.debug.openDebugViewlet(); + text = await app.workbench.debug.getTitle(); + await app.screenCapturer.capture('Debug title'); + assert(/debuggen/i.test(text)); + + await app.workbench.extensions.openExtensionsViewlet(); + text = await app.workbench.extensions.getTitle(); + await app.screenCapturer.capture('Extensions title'); + assert(/erweiterungen/i.test(text)); + }); +}); \ No newline at end of file diff --git a/test/smoke/src/areas/first-experience.ts b/test/smoke/src/areas/workbench/viewlet.ts similarity index 52% rename from test/smoke/src/areas/first-experience.ts rename to test/smoke/src/areas/workbench/viewlet.ts index 11df1a44f80..7eb114edaaf 100644 --- a/test/smoke/src/areas/first-experience.ts +++ b/test/smoke/src/areas/workbench/viewlet.ts @@ -3,19 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SpectronApplication } from '../spectron/application'; +import { SpectronApplication } from '../../spectron/application'; -export class FirstExperience { - constructor(private spectron: SpectronApplication) { +export abstract class Viewlet { + + constructor(protected spectron: SpectronApplication) { // noop } - public async getWelcomeTab(): Promise { - let el = await this.spectron.client.waitForElement('.vs_code_welcome_page-name-file-icon'); - if (el) { - return el; - } - - return undefined; + public async getTitle(): Promise { + return this.spectron.client.waitForText('.monaco-workbench-container .part.sidebar > .title > .title-label > span'); } + } \ No newline at end of file diff --git a/test/smoke/src/areas/workbench/workbench.ts b/test/smoke/src/areas/workbench/workbench.ts index 18cf8bb484d..08a3204d1eb 100644 --- a/test/smoke/src/areas/workbench/workbench.ts +++ b/test/smoke/src/areas/workbench/workbench.ts @@ -6,46 +6,48 @@ import { SpectronApplication } from '../../spectron/application'; import { Explorer } from '../explorer/explorer'; import { ActivityBar } from '../activitybar/activityBar'; -import { Element } from 'webdriverio'; import { QuickOpen } from '../quickopen/quickopen'; import { Extensions } from '../extensions/extensions'; -import { CommandPallette } from './commandPallette'; import { Search } from '../search/search'; import { Editor } from '../editor/editor'; import { SCM } from '../git/scm'; +import { Debug } from '../debug/debug'; import { StatusBar } from '../statusbar/statusbar'; import { Problems } from '../problems/problems'; import { SettingsEditor } from '../preferences/settings'; import { KeybindingsEditor } from '../preferences/keybindings'; +import { Terminal } from '../terminal/terminal'; export class Workbench { readonly explorer: Explorer; readonly activitybar: ActivityBar; - readonly commandPallette: CommandPallette; readonly quickopen: QuickOpen; readonly search: Search; readonly extensions: Extensions; readonly editor: Editor; readonly scm: SCM; + readonly debug: Debug; readonly statusbar: StatusBar; readonly problems: Problems; readonly settingsEditor: SettingsEditor; readonly keybindingsEditor: KeybindingsEditor; + readonly terminal: Terminal; constructor(private spectron: SpectronApplication) { this.explorer = new Explorer(spectron); this.activitybar = new ActivityBar(spectron); this.quickopen = new QuickOpen(spectron); - this.commandPallette = new CommandPallette(spectron); this.search = new Search(spectron); this.extensions = new Extensions(spectron); this.editor = new Editor(spectron); this.scm = new SCM(spectron); + this.debug = new Debug(spectron); this.statusbar = new StatusBar(spectron); this.problems = new Problems(spectron); this.settingsEditor = new SettingsEditor(spectron); this.keybindingsEditor = new KeybindingsEditor(spectron); + this.terminal = new Terminal(spectron); } public async saveOpenedFile(): Promise { @@ -55,36 +57,30 @@ export class Workbench { // ignore if there is no dirty file return Promise.resolve(); } - await this.spectron.command('workbench.action.files.save'); + await this.spectron.runCommand('workbench.action.files.save'); return this.spectron.client.waitForElement('.tabs-container div.tab.active.dirty', element => !element); } - public async selectTab(tabName: string, untitled: boolean = false): Promise { + public async selectTab(tabName: string, untitled: boolean = false): Promise { await this.spectron.client.waitAndClick(`.tabs-container div.tab[aria-label="${tabName}, tab"]`); - await this.waitForActiveOpen(tabName); - return this.waitForEditorFocus(tabName, untitled); + await this.waitForEditorFocus(tabName, untitled); } - public async waitForEditorFocus(fileName: string, untitled: boolean = false): Promise { - return this.spectron.client.waitForElement(`.editor-container[aria-label="${fileName}. ${untitled ? 'Untitled file text editor.' : 'Text file editor.'}, Group 1."] .monaco-editor.focused`); + public async waitForEditorFocus(fileName: string, untitled: boolean = false): Promise { + await this.waitForActiveTab(fileName); + await this.editor.waitForActiveEditor(fileName); } - public async waitForActiveOpen(fileName: string, isDirty: boolean = false): Promise { - return this.spectron.client.waitForElement(`.tabs-container div.tab.active${isDirty ? '.dirty' : ''}[aria-selected="true"][aria-label="${fileName}, tab"]`).then(() => true); + public async waitForActiveTab(fileName: string, isDirty: boolean = false): Promise { + return this.spectron.client.waitForElement(`.tabs-container div.tab.active${isDirty ? '.dirty' : ''}[aria-selected="true"][aria-label="${fileName}, tab"]`); } - public async waitForOpen(fileName: string, isDirty: boolean = false): Promise { + public async waitForTab(fileName: string, isDirty: boolean = false): Promise { return this.spectron.client.waitForElement(`.tabs-container div.tab${isDirty ? '.dirty' : ''}[aria-label="${fileName}, tab"]`).then(() => true); } - public async newUntitledFile(): Promise { - await this.spectron.command('workbench.action.files.newUntitledFile'); - await this.waitForActiveOpen('Untitled-1'); + public async newUntitledFile(): Promise { + await this.spectron.runCommand('workbench.action.files.newUntitledFile'); await this.waitForEditorFocus('Untitled-1', true); } - - async openFile(fileName: string): Promise { - await this.quickopen.openFile(fileName); - await this.spectron.client.waitForElement(`.monaco-editor.focused`); - } } diff --git a/test/smoke/src/helpers/screenshot.ts b/test/smoke/src/helpers/screenshot.ts index 9f30b6a2cb0..18a068ec388 100644 --- a/test/smoke/src/helpers/screenshot.ts +++ b/test/smoke/src/helpers/screenshot.ts @@ -3,51 +3,35 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SpectronApplication } from '../spectron/application'; -var fs = require('fs'); +import * as path from 'path'; +import * as fs from 'fs'; +import * as mkdirp from 'mkdirp'; +import { Application } from 'spectron'; +import { sanitize } from './utilities'; -const __testTime = new Date().toISOString(); +export class ScreenCapturer { -export interface IScreenshot { - capture(): Promise; -} + private static counter = 0; -export class Screenshot implements IScreenshot { + constructor( + private application: Application, + public suiteName: string, + private screenshotsDirPath: string | undefined, + ) { } - private index: number = 0; - private testPath: string; + async capture(name: string): Promise { + if (!this.screenshotsDirPath) { + return; + } - constructor(private spectron: SpectronApplication, testName: string, testRetry: number) { - const testTime = this.sanitizeFolderName(__testTime); - testName = this.sanitizeFolderName(testName); + const screenshotPath = path.join( + this.screenshotsDirPath, + sanitize(this.suiteName), + `${ScreenCapturer.counter++}-${sanitize(name)}.png` + ); - this.testPath = `test_data/screenshots/${testTime}/${testName}/${testRetry}`; - this.createFolder(this.testPath); - } - - public async capture(): Promise { - const image = await this.spectron.app.browserWindow.capturePage(); - await new Promise((c, e) => fs.writeFile(`${this.testPath}/${this.index++}.png`, image, err => err ? e(err) : c())); - } - - private createFolder(name: string): void { - name.split('/').forEach((folderName, i, fullPath) => { - const folder = fullPath.slice(0, i + 1).join('/'); - if (!fs.existsSync(folder)) { - fs.mkdirSync(folder); - } - }); - } - - private sanitizeFolderName(name: string): string { - return name.replace(/[&*:\/]/g, ''); + const image = await this.application.browserWindow.capturePage(); + await new Promise((c, e) => mkdirp(path.dirname(screenshotPath), err => err ? e(err) : c())); + await new Promise((c, e) => fs.writeFile(screenshotPath, image, err => err ? e(err) : c())); } } - -export class NullScreenshot implements IScreenshot { - - public async capture(): Promise { - return Promise.resolve(); - } - -} \ No newline at end of file diff --git a/test/smoke/src/helpers/utilities.ts b/test/smoke/src/helpers/utilities.ts index e53e0845008..bde4dde38b7 100644 --- a/test/smoke/src/helpers/utilities.ts +++ b/test/smoke/src/helpers/utilities.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -var fs = require('fs'); -var rimraf = require('rimraf'); +import * as fs from 'fs'; +import { dirname } from 'path'; /** * Contains methods that are commonly used across test areas. @@ -24,28 +24,6 @@ export class Util { } } - public rimraf(directory: string): Promise { - return new Promise((res, rej) => { - rimraf(directory, (err) => { - if (err) { - rej(err); - } - res(); - }); - }); - } - - public static rimraf(directory: string): Promise { - return new Promise((res, rej) => { - rimraf(directory, (err) => { - if (err) { - rej(err); - } - res(); - }); - }); - } - public static removeFile(filePath: string): void { try { fs.unlinkSync(`${filePath}`); @@ -55,4 +33,50 @@ export class Util { } } } +} + +export function nfcall(fn: Function, ...args): Promise { + return new Promise((c, e) => fn(...args, (err, r) => err ? e(err) : c(r))); +} + +export async function mkdirp(path: string, mode?: number): Promise { + const mkdir = async () => { + try { + await nfcall(fs.mkdir, path, mode); + } catch (err) { + if (err.code === 'EEXIST') { + const stat = await nfcall(fs.stat, path); + + if (stat.isDirectory) { + return; + } + + throw new Error(`'${path}' exists and is not a directory.`); + } + + throw err; + } + }; + + // is root? + if (path === dirname(path)) { + return true; + } + + try { + await mkdir(); + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + + await mkdirp(dirname(path), mode); + await mkdir(); + } + + return true; +} + +export function sanitize(name: string): string { + return name.replace(/[&*:\/]/g, ''); } \ No newline at end of file diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index f35de669b53..8c71329b907 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -7,17 +7,34 @@ import * as fs from 'fs'; import * as https from 'https'; import * as cp from 'child_process'; import * as path from 'path'; -import * as mkdirp from 'mkdirp'; import * as minimist from 'minimist'; +import * as tmp from 'tmp'; +import * as rimraf from 'rimraf'; +import * as mkdirp from 'mkdirp'; +import { SpectronApplication, Quality } from './spectron/application'; + +const tmpDir = tmp.dirSync({ prefix: 't' }) as { name: string; removeCallback: Function; }; +const testDataPath = tmpDir.name; +process.once('exit', () => rimraf.sync(testDataPath)); const [, , ...args] = process.argv; -const opts = minimist(args, { string: ['build', 'stable-build'] }); +const opts = minimist(args, { + string: [ + 'build', + 'stable-build', + 'log', + 'wait-time' + ] +}); -const testDataPath = path.join(__dirname, '..', 'test_data'); -const workspacePath = path.join(testDataPath, 'smoketest.code-workspace'); +const artifactsPath = opts.log || ''; + +const workspaceFilePath = path.join(testDataPath, 'smoketest.code-workspace'); const testRepoUrl = 'https://github.com/Microsoft/vscode-smoketest-express'; -const testRepoLocalDir = path.join(testDataPath, 'vscode-smoketest-express'); -mkdirp.sync(testDataPath); +const workspacePath = path.join(testDataPath, 'vscode-smoketest-express'); +const keybindingsPath = path.join(testDataPath, 'keybindings.json'); +const extensionsPath = path.join(testDataPath, 'extensions-dir'); +mkdirp.sync(extensionsPath); function fail(errorMessage): void { console.error(errorMessage); @@ -46,32 +63,56 @@ function getDevElectronPath(): string { } } +function getBuildElectronPath(root: string): string { + switch (process.platform) { + case 'darwin': + return path.join(root, 'Contents', 'MacOS', 'Electron'); + case 'linux': { + const product = require(path.join(root, 'resources', 'app', 'product.json')); + return path.join(root, product.applicationName); + } + case 'win32': { + const product = require(path.join(root, 'resources', 'app', 'product.json')); + return path.join(root, `${product.nameShort}.exe`); + } + default: + throw new Error('Unsupported platform.'); + } +} + let testCodePath = opts.build; let stableCodePath = opts['stable-build']; +let electronPath: string; if (testCodePath) { - process.env.VSCODE_PATH = testCodePath; + electronPath = getBuildElectronPath(testCodePath); if (stableCodePath) { - process.env.VSCODE_STABLE_PATH = stableCodePath; + process.env.VSCODE_STABLE_PATH = getBuildElectronPath(stableCodePath); } } else { testCodePath = getDevElectronPath(); - process.env.VSCODE_PATH = testCodePath; + electronPath = testCodePath; process.env.VSCODE_REPOSITORY = repoPath; process.env.VSCODE_DEV = '1'; process.env.VSCODE_CLI = '1'; } -if (!fs.existsSync(testCodePath)) { - fail(`Can't find Code at ${testCodePath}.`); +if (!fs.existsSync(electronPath || '')) { + fail(`Can't find Code at ${electronPath}.`); } -process.env.SMOKETEST_REPO = testRepoLocalDir; -process.env.VSCODE_WORKSPACE_PATH = workspacePath; +const userDataDir = path.join(testDataPath, 'd'); +// process.env.VSCODE_WORKSPACE_PATH = workspaceFilePath; +process.env.VSCODE_KEYBINDINGS_PATH = keybindingsPath; -if ((testCodePath.indexOf('Code - Insiders') /* macOS/Windows */ || testCodePath.indexOf('code-insiders') /* Linux */) >= 0) { - process.env.VSCODE_EDITION = 'insiders'; +let quality: Quality; +if (process.env.VSCODE_DEV === '1') { + quality = Quality.Dev; +} else if ((testCodePath.indexOf('Code - Insiders') /* macOS/Windows */ || testCodePath.indexOf('code-insiders') /* Linux */) >= 0) { + quality = Quality.Insiders; +} else { + quality = Quality.Stable; } function getKeybindingPlatform(): string { @@ -84,13 +125,14 @@ function getKeybindingPlatform(): string { function toUri(path: string): string { if (process.platform === 'win32') { - return `file:///${path.replace(/\\/g, '/')}`; + return `${path.replace(/\\/g, '/')}`; } - return `file://${path}`; + return `${path}`; } -async function main(): Promise { +async function setup(): Promise { + console.log('*** Test data:', testDataPath); console.log('*** Preparing smoketest setup...'); const keybindingsUrl = `https://raw.githubusercontent.com/Microsoft/vscode-docs/master/scripts/keybindings/doc.keybindings.${getKeybindingPlatform()}.json`; @@ -98,7 +140,7 @@ async function main(): Promise { await new Promise((c, e) => { https.get(keybindingsUrl, res => { - const output = fs.createWriteStream(path.join(testDataPath, 'keybindings.json')); + const output = fs.createWriteStream(keybindingsPath); res.on('error', e); output.on('error', e); output.on('close', c); @@ -106,32 +148,37 @@ async function main(): Promise { }).on('error', e); }); - if (!fs.existsSync(workspacePath)) { + if (!fs.existsSync(workspaceFilePath)) { console.log('*** Creating workspace file...'); const workspace = { - id: (Date.now() + Math.round(Math.random() * 1000)).toString(), folders: [ - toUri(path.join(testRepoLocalDir, 'public')), - toUri(path.join(testRepoLocalDir, 'routes')), - toUri(path.join(testRepoLocalDir, 'views')) + { + path: toUri(path.join(workspacePath, 'public')) + }, + { + path: toUri(path.join(workspacePath, 'routes')) + }, + { + path: toUri(path.join(workspacePath, 'views')) + } ] }; - fs.writeFileSync(workspacePath, JSON.stringify(workspace, null, '\t')); + fs.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, '\t')); } - if (!fs.existsSync(testRepoLocalDir)) { + if (!fs.existsSync(workspacePath)) { console.log('*** Cloning test project repository...'); - cp.spawnSync('git', ['clone', testRepoUrl, testRepoLocalDir]); + cp.spawnSync('git', ['clone', testRepoUrl, workspacePath]); } else { console.log('*** Cleaning test project repository...'); - cp.spawnSync('git', ['fetch'], { cwd: testRepoLocalDir }); - cp.spawnSync('git', ['reset', '--hard', 'FETCH_HEAD'], { cwd: testRepoLocalDir }); - cp.spawnSync('git', ['clean', '-xdf'], { cwd: testRepoLocalDir }); + cp.spawnSync('git', ['fetch'], { cwd: workspacePath }); + cp.spawnSync('git', ['reset', '--hard', 'FETCH_HEAD'], { cwd: workspacePath }); + cp.spawnSync('git', ['clean', '-xdf'], { cwd: workspacePath }); } console.log('*** Running npm install...'); - // cp.execSync('npm install', { cwd: testRepoLocalDir, stdio: 'inherit' }); + cp.execSync('npm install', { cwd: workspacePath, stdio: 'inherit' }); console.log('*** Smoketest setup done!\n'); } @@ -156,15 +203,42 @@ console.warn = function suppressWebdriverWarnings(message) { warn.apply(console, arguments); }; -before(async () => main()); +before(async function () { + // allow two minutes for setup + this.timeout(2 * 60 * 1000); + await setup(); -import './areas/css/css.test'; + const app = new SpectronApplication({ + quality, + electronPath, + workspacePath, + userDataDir, + extensionsPath, + artifactsPath, + workspaceFilePath, + waitTime: parseInt(opts['wait-time'] || '0') || 20 + }); + + await app.start(); + this.app = app; +}); + +after(async function () { + await this.app.stop(); + await new Promise((c, e) => rimraf(testDataPath, { maxBusyTries: 10 }, err => err ? e(err) : c())); +}); + +// import './areas/workbench/data-migration.test'; +import './areas/workbench/data-loss.test'; import './areas/explorer/explorer.test'; import './areas/preferences/preferences.test'; -import './areas/multiroot/multiroot.test'; -import './areas/extensions/extensions.test'; import './areas/search/search.test'; -import './areas/workbench/data-loss.test'; +import './areas/css/css.test'; +import './areas/editor/editor.test'; +import './areas/debug/debug.test'; import './areas/git/git.test'; +// import './areas/terminal/terminal.test'; import './areas/statusbar/statusbar.test'; -// import './areas/workbench/data-migration.test'; \ No newline at end of file +import './areas/extensions/extensions.test'; +import './areas/multiroot/multiroot.test'; +import './areas/workbench/localization.test'; \ No newline at end of file diff --git a/test/smoke/src/spectron/application.ts b/test/smoke/src/spectron/application.ts index 8c98220c6bc..22c1c23010d 100644 --- a/test/smoke/src/spectron/application.ts +++ b/test/smoke/src/spectron/application.ts @@ -4,174 +4,307 @@ *--------------------------------------------------------------------------------------------*/ import { Application, SpectronClient as WebClient } from 'spectron'; +import { test as testPort } from 'portastic'; import { SpectronClient } from './client'; -import { NullScreenshot, IScreenshot, Screenshot } from '../helpers/screenshot'; +import { ScreenCapturer } from '../helpers/screenshot'; import { Workbench } from '../areas/workbench/workbench'; import * as fs from 'fs'; +import * as cp from 'child_process'; import * as path from 'path'; +import * as mkdirp from 'mkdirp'; +import { sanitize } from '../helpers/utilities'; -export const LATEST_PATH = process.env.VSCODE_PATH || ''; -export const STABLE_PATH = process.env.VSCODE_STABLE_PATH || ''; -export const WORKSPACE_PATH = process.env.SMOKETEST_REPO || ''; -export const CODE_WORKSPACE_PATH = process.env.VSCODE_WORKSPACE_PATH || ''; -export const USER_DIR = path.join(__dirname, '../../test_data/temp_user_dir'); -export const EXTENSIONS_DIR = path.join(__dirname, 'test_data/temp_extensions_dir'); +// Just hope random helps us here, cross your fingers! +export async function findFreePort(): Promise { + for (let i = 0; i < 10; i++) { + const port = 10000 + Math.round(Math.random() * 10000); + + if (await testPort(port)) { + return port; + } + } + + throw new Error('Could not find free port!'); +} + +export enum Quality { + Dev, + Insiders, + Stable +} + +export interface SpectronApplicationOptions { + quality: Quality; + electronPath: string; + workspacePath: string; + userDataDir: string; + extensionsPath: string; + artifactsPath: string; + workspaceFilePath: string; + waitTime: number; +} /** * Wraps Spectron's Application instance with its used methods. */ export class SpectronApplication { - public readonly client: SpectronClient; - public readonly workbench: Workbench; + private static count = 0; - private spectron: Application; - private keybindings: any[]; - private screenshot: IScreenshot; + private _client: SpectronClient; + private _workbench: Workbench; + private _screenCapturer: ScreenCapturer; + private spectron: Application | undefined; + private keybindings: any[]; private stopLogCollection: (() => Promise) | undefined; - private readonly sampleExtensionsDir: string = path.join(EXTENSIONS_DIR, new Date().getTime().toString()); - private readonly pollTrials = 50; - private readonly pollTimeout = 1; // in secs + constructor( + private options: SpectronApplicationOptions + ) { } - constructor(electronPath: string, testName: string, private testRetry: number, args: string[] = [], chromeDriverArgs: string[] = []) { - // Prevent 'Getting Started' web page from opening on clean user-data-dir - args.push('--skip-getting-started'); - - // Ensure that running over custom extensions directory, rather than picking up the one that was used by a tester previously - let extensionDirIsSet = false; - for (let arg of args) { - if (arg.startsWith('--extensions-dir')) { - extensionDirIsSet = true; - break; - } - } - if (!extensionDirIsSet) { - args.push(`--extensions-dir=${this.sampleExtensionsDir}`); - } - let userDataDirIsSet = false; - for (let arg of chromeDriverArgs) { - if (arg.startsWith('--user-data-dir')) { - userDataDirIsSet = true; - break; - } - } - if (!userDataDirIsSet) { - chromeDriverArgs.push(`--user-data-dir=${path.join(USER_DIR, new Date().getTime().toString())}`); - } - - const repo = process.env.VSCODE_REPOSITORY; - if (repo) { - args = [repo, ...args]; - } - - this.spectron = new Application({ - path: electronPath, - args: args, - chromeDriverArgs: chromeDriverArgs, - startTimeout: 10000, - requireName: 'nodeRequire' - }); - this.testRetry += 1; // avoid multiplication by 0 for wait times - this.screenshot = args.indexOf('--no-screenshot') === -1 ? new NullScreenshot() : new Screenshot(this, testName, testRetry); - this.client = new SpectronClient(this.spectron, this.screenshot); - this.retrieveKeybindings(); - - this.workbench = new Workbench(this); + get quality(): Quality { + return this.options.quality; } - public get inDevMode(): boolean { - return process.env.VSCODE_DEV === '1'; + get client(): SpectronClient { + return this._client; } - public get app(): Application { - return this.spectron; - } + get webclient(): WebClient { + if (!this.spectron) { + throw new Error('Application not started'); + } - public get webclient(): WebClient { return this.spectron.client; } - public async start(): Promise { - await this.spectron.start(); - await this.focusOnWindow(1); // focuses on main renderer window + get screenCapturer(): ScreenCapturer { + return this._screenCapturer; + } + + get workbench(): Workbench { + return this._workbench; + } + + get workspacePath(): string { + return this.options.workspacePath; + } + + get extensionsPath(): string { + return this.options.extensionsPath; + } + + get userDataPath(): string { + return this.options.userDataDir; + } + + get workspaceFilePath(): string { + return this.options.workspaceFilePath; + } + + private _suiteName: string = 'Init'; + + set suiteName(suiteName: string) { + this._suiteName = suiteName; + this._screenCapturer.suiteName = suiteName; + } + + async start(): Promise { + await this._start(); + await this.waitForWelcome(); + } + + async restart(codeArgs: string[] = []): Promise { + await this.stop(); + await new Promise(c => setTimeout(c, 1000)); + await this._start(codeArgs); + } + + private async _start(codeArgs: string[] = []): Promise { + await this.retrieveKeybindings(); + cp.execSync('git checkout .', { cwd: this.options.workspacePath }); + await this.startApplication(codeArgs); await this.checkWindowReady(); } - public async reload(): Promise { - await this.workbench.commandPallette.runCommand('Reload Window'); + async reload(): Promise { + await this.workbench.quickopen.runCommand('Reload Window'); // TODO @sandy: Find a proper condition to wait for reload - await this.wait(.5); - await this.client.waitForHTML('[id="workbench.main.container"]'); + await new Promise(c => setTimeout(c, 500)); + await this.checkWindowReady(); } - public async stop(): Promise { + async stop(): Promise { + if (this.stopLogCollection) { + await this.stopLogCollection(); + this.stopLogCollection = undefined; + } + if (this.spectron && this.spectron.isRunning()) { - return await this.spectron.stop(); + await this.spectron.stop(); + this.spectron = undefined; } } - public waitFor(func: (...args: any[]) => any, args: any): Promise { - return this.callClientAPI(func, args); - } + private async startApplication(codeArgs: string[] = []): Promise { - public wait(seconds: number = this.testRetry * this.pollTimeout): Promise { - return new Promise(resolve => setTimeout(resolve, seconds * 1000)); - } + let args: string[] = []; + let chromeDriverArgs: string[] = []; - public focusOnWindow(index: number): Promise { - return this.client.windowByIndex(index); + if (process.env.VSCODE_REPOSITORY) { + args.push(process.env.VSCODE_REPOSITORY as string); + } + + args.push(this.options.workspacePath); + + // Prevent 'Getting Started' web page from opening on clean user-data-dir + args.push('--skip-getting-started'); + + // Prevent Quick Open from closing when focus is stolen, this allows concurrent smoketest suite running + args.push('--sticky-quickopen'); + + // Disable telemetry + args.push('--disable-telemetry'); + + // Disable updates + args.push('--disable-updates'); + + // Disable crash reporter + // This seems to be the fix for the strange hangups in which Code stays unresponsive + // and tests finish badly with timeouts, leaving Code running in the background forever + args.push('--disable-crash-reporter'); + + // Ensure that running over custom extensions directory, rather than picking up the one that was used by a tester previously + args.push(`--extensions-dir=${this.options.extensionsPath}`); + + args.push(...codeArgs); + + chromeDriverArgs.push(`--user-data-dir=${this.options.userDataDir}`); + + // Spectron always uses the same port number for the chrome driver + // and it handles gracefully when two instances use the same port number + // This works, but when one of the instances quits, it takes down + // chrome driver with it, leaving the other instance in DISPAIR!!! :( + const port = await findFreePort(); + + // We must get a different port for debugging the smoketest express app + // otherwise concurrent test runs will clash on those ports + const env = { PORT: String(await findFreePort()), ...process.env }; + + const opts: any = { + path: this.options.electronPath, + port, + args, + env, + chromeDriverArgs, + startTimeout: 10000, + requireName: 'nodeRequire' + }; + + const runName = String(SpectronApplication.count++); + let testsuiteRootPath: string | undefined = undefined; + let screenshotsDirPath: string | undefined = undefined; + + if (this.options.artifactsPath) { + testsuiteRootPath = path.join(this.options.artifactsPath, sanitize(runName)); + mkdirp.sync(testsuiteRootPath); + + // Collect screenshots + screenshotsDirPath = path.join(testsuiteRootPath, 'screenshots'); + mkdirp.sync(screenshotsDirPath); + + // Collect chromedriver logs + const chromedriverLogPath = path.join(testsuiteRootPath, 'chromedriver.log'); + opts.chromeDriverLogPath = chromedriverLogPath; + + // Collect webdriver logs + const webdriverLogsPath = path.join(testsuiteRootPath, 'webdriver'); + mkdirp.sync(webdriverLogsPath); + opts.webdriverLogPath = webdriverLogsPath; + } + + this.spectron = new Application(opts); + await this.spectron.start(); + + if (testsuiteRootPath) { + // Collect logs + const mainProcessLogPath = path.join(testsuiteRootPath, 'main.log'); + const rendererProcessLogPath = path.join(testsuiteRootPath, 'renderer.log'); + + const flush = async () => { + if (!this.spectron) { + return; + } + + const mainLogs = await this.spectron.client.getMainProcessLogs(); + await new Promise((c, e) => fs.appendFile(mainProcessLogPath, mainLogs.join('\n'), { encoding: 'utf8' }, err => err ? e(err) : c())); + + const rendererLogs = (await this.spectron.client.getRenderProcessLogs()).map(m => `${m.timestamp} - ${m.level} - ${m.message}`); + await new Promise((c, e) => fs.appendFile(rendererProcessLogPath, rendererLogs.join('\n'), { encoding: 'utf8' }, err => err ? e(err) : c())); + }; + + let running = true; + const loopFlush = async () => { + while (true) { + await flush(); + + if (!running) { + return; + } + + await new Promise(c => setTimeout(c, 1000)); + } + }; + + const loopPromise = loopFlush(); + this.stopLogCollection = () => { + running = false; + return loopPromise; + }; + } + + this._screenCapturer = new ScreenCapturer(this.spectron, this._suiteName, screenshotsDirPath); + this._client = new SpectronClient(this.spectron, this, this.options.waitTime); + this._workbench = new Workbench(this); } private async checkWindowReady(): Promise { + await this.webclient.waitUntilWindowLoaded(); + // Spectron opens multiple terminals in Windows platform + // Workaround to focus the right window - https://github.com/electron/spectron/issues/60 + await this.client.windowByIndex(1); + // await this.app.browserWindow.focus(); await this.client.waitForHTML('[id="workbench.main.container"]'); + } + + private async waitForWelcome(): Promise { await this.client.waitForElement('.explorer-folders-view'); await this.client.waitForElement(`.editor-container[id="workbench.editor.walkThroughPart"] .welcomePage`); } - private retrieveKeybindings() { - fs.readFile(path.join(__dirname, '../../test_data/keybindings.json'), 'utf8', (err, data) => { - if (err) { - throw err; - } - try { - this.keybindings = JSON.parse(data); - } catch (e) { - throw new Error(`Error parsing keybindings JSON: ${e}`); - } + private retrieveKeybindings(): Promise { + return new Promise((c, e) => { + fs.readFile(process.env.VSCODE_KEYBINDINGS_PATH as string, 'utf8', (err, data) => { + if (err) { + throw err; + } + try { + this.keybindings = JSON.parse(data); + c(); + } catch (e) { + throw new Error(`Error parsing keybindings JSON: ${e}`); + } + }); }); } - private async callClientAPI(func: (...args: any[]) => Promise, args: any): Promise { - let trial = 1; - - while (true) { - if (trial > this.pollTrials) { - throw new Error(`Could not retrieve the element in ${this.testRetry * this.pollTrials * this.pollTimeout} seconds.`); - } - - let result; - try { - result = await func.call(this.client, args, false); - } catch (e) { } - - if (result && result !== '') { - await this.screenshot.capture(); - return result; - } - - await this.wait(); - trial++; - } - } - /** * Retrieves the command from keybindings file and executes it with WebdriverIO client API * @param command command (e.g. 'workbench.action.files.newUntitledFile') */ - public command(command: string, capture?: boolean): Promise { + runCommand(command: string): Promise { const binding = this.keybindings.find(x => x['command'] === command); if (!binding) { - return this.workbench.commandPallette.runCommand(command); + return this.workbench.quickopen.runCommand(command); } const keys: string = binding.key; @@ -184,7 +317,7 @@ export class SpectronApplication { keysToPress.push('NULL'); }); - return this.client.keys(keysToPress, capture); + return this.client.keys(keysToPress); } /** @@ -199,26 +332,6 @@ export class SpectronApplication { return 'Meta'; default: return key.length === 1 ? key : key.charAt(0).toUpperCase() + key.slice(1); - }; - } - - // TODO: Sandy remove this - public type(text: string): Promise { - return new Promise((res) => { - let textSplit = text.split(' '); - - const type = async (i: number) => { - if (!textSplit[i] || textSplit[i].length <= 0) { - return res(); - } - - const toType = textSplit[i + 1] ? `${textSplit[i]} ` : textSplit[i]; - await this.client.keys(toType, false); - await this.client.keys(['NULL']); - await type(i + 1); - }; - - return type(0); - }); + } } } diff --git a/test/smoke/src/spectron/client.ts b/test/smoke/src/spectron/client.ts index 168cc3fbcbc..9ec19afd2f5 100644 --- a/test/smoke/src/spectron/client.ts +++ b/test/smoke/src/spectron/client.ts @@ -4,202 +4,209 @@ *--------------------------------------------------------------------------------------------*/ import { Application } from 'spectron'; -import { IScreenshot } from '../helpers/screenshot'; import { RawResult, Element } from 'webdriverio'; +import { SpectronApplication } from './application'; /** * Abstracts the Spectron's WebdriverIO managed client property on the created Application instances. */ export class SpectronClient { - private readonly retryCount = 50; + // waitFor calls should not take more than 200 * 100 = 20 seconds to complete, excluding + // the time it takes for the actual retry call to complete + private retryCount: number; private readonly retryDuration = 100; // in milliseconds - constructor(public spectron: Application, private shot: IScreenshot) { + constructor( + readonly spectron: Application, + private application: SpectronApplication, + waitTime: number + ) { + this.retryCount = (waitTime * 1000) / this.retryDuration; } - public windowByIndex(index: number): Promise { + windowByIndex(index: number): Promise { return this.spectron.client.windowByIndex(index); } - public async keys(keys: string[] | string, capture: boolean = true): Promise { - await this.screenshot(capture); - return this.spectron.client.keys(keys); + keys(keys: string[]): Promise { + this.spectron.client.keys(keys); + return Promise.resolve(); } - public async getText(selector: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async getText(selector: string, capture: boolean = true): Promise { return this.spectron.client.getText(selector); } - public async waitForText(selector: string, text?: string, accept?: (result: string) => boolean): Promise { - await this.screenshot(); + async waitForText(selector: string, text?: string, accept?: (result: string) => boolean): Promise { accept = accept ? accept : result => text !== void 0 ? text === result : !!result; return this.waitFor(() => this.spectron.client.getText(selector), accept, `getText with selector ${selector}`); } - public async waitForHTML(selector: string, accept: (result: string) => boolean = (result: string) => !!result): Promise { - await this.screenshot(); + async waitForTextContent(selector: string, textContent?: string, accept?: (result: string) => boolean): Promise { + accept = accept ? accept : (result => textContent !== void 0 ? textContent === result : !!result); + const fn = async () => await this.spectron.client.selectorExecute(selector, div => Array.isArray(div) ? div[0].textContent : div.textContent); + return this.waitFor(fn, s => accept!(typeof s === 'string' ? s : ''), `getTextContent with selector ${selector}`); + } + + async waitForValue(selector: string, value?: string, accept?: (result: string) => boolean): Promise { + accept = accept ? accept : result => value !== void 0 ? value === result : !!result; + return this.waitFor(() => this.spectron.client.getValue(selector), accept, `getValue with selector ${selector}`); + } + + async waitForHTML(selector: string, accept: (result: string) => boolean = (result: string) => !!result): Promise { return this.waitFor(() => this.spectron.client.getHTML(selector), accept, `getHTML with selector ${selector}`); } - public async waitAndClick(selector: string): Promise { - await this.screenshot(); + async waitAndClick(selector: string): Promise { return this.waitFor(() => this.spectron.client.click(selector), void 0, `click with selector ${selector}`); } - public async click(selector: string): Promise { - await this.screenshot(); + async click(selector: string): Promise { return this.spectron.client.click(selector); } - public async doubleClickAndWait(selector: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async doubleClickAndWait(selector: string, capture: boolean = true): Promise { return this.waitFor(() => this.spectron.client.doubleClick(selector), void 0, `doubleClick with selector ${selector}`); } - public async leftClick(selector: string, xoffset: number, yoffset: number, capture: boolean = true): Promise { - await this.screenshot(capture); + async leftClick(selector: string, xoffset: number, yoffset: number, capture: boolean = true): Promise { return this.spectron.client.leftClick(selector, xoffset, yoffset); } - public async rightClick(selector: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async rightClick(selector: string, capture: boolean = true): Promise { return this.spectron.client.rightClick(selector); } - public async moveToObject(selector: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async moveToObject(selector: string, capture: boolean = true): Promise { return this.spectron.client.moveToObject(selector); } - public async waitAndmoveToObject(selector: string): Promise { - await this.screenshot(); + async waitAndMoveToObject(selector: string): Promise { return this.waitFor(() => this.spectron.client.moveToObject(selector), void 0, `move to object with selector ${selector}`); } - public async setValue(selector: string, text: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async setValue(selector: string, text: string, capture: boolean = true): Promise { return this.spectron.client.setValue(selector, text); } - public async waitForElements(selector: string, accept: (result: Element[]) => boolean = result => result.length > 0): Promise { - await this.screenshot(true); + async waitForElements(selector: string, accept: (result: Element[]) => boolean = result => result.length > 0): Promise { return this.waitFor>(() => this.spectron.client.elements(selector), result => accept(result.value), `elements with selector ${selector}`) .then(result => result.value); } - public async waitForElement(selector: string, accept: (result: Element | undefined) => boolean = result => !!result): Promise { - await this.screenshot(); + async waitForElement(selector: string, accept: (result: Element | undefined) => boolean = result => !!result): Promise { return this.waitFor>(() => this.spectron.client.element(selector), result => accept(result ? result.value : void 0), `element with selector ${selector}`) .then(result => result.value); } - public async element(selector: string): Promise { - await this.screenshot(); + async waitForVisibility(selector: string, accept: (result: boolean) => boolean = result => result): Promise { + return this.waitFor(() => this.spectron.client.isVisible(selector), accept, `isVisible with selector ${selector}`); + } + + async element(selector: string): Promise { return this.spectron.client.element(selector) .then(result => result.value); } - public async waitForActiveElement(accept: (result: Element | undefined) => boolean = result => !!result): Promise { - await this.screenshot(); - return this.waitFor>(() => this.spectron.client.elementActive(), result => accept(result ? result.value : void 0), `elementActive`); + async waitForActiveElement(selector: string): Promise { + return this.waitFor( + () => this.spectron.client.execute(s => document.activeElement.matches(s), selector), + r => r.value, + `wait for active element: ${selector}` + ); } - public async waitForAttribute(selector: string, attribute: string, accept: (result: string) => boolean = result => !!result): Promise { - await this.screenshot(); + async waitForAttribute(selector: string, attribute: string, accept: (result: string) => boolean = result => !!result): Promise { return this.waitFor(() => this.spectron.client.getAttribute(selector), accept, `attribute with selector ${selector}`); } - public async dragAndDrop(sourceElem: string, destinationElem: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async dragAndDrop(sourceElem: string, destinationElem: string, capture: boolean = true): Promise { return this.spectron.client.dragAndDrop(sourceElem, destinationElem); } - public async selectByValue(selector: string, value: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async selectByValue(selector: string, value: string, capture: boolean = true): Promise { return this.spectron.client.selectByValue(selector, value); } - public async getValue(selector: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async getValue(selector: string, capture: boolean = true): Promise { return this.spectron.client.getValue(selector); } - public async getAttribute(selector: string, attribute: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async getAttribute(selector: string, attribute: string, capture: boolean = true): Promise { return Promise.resolve(this.spectron.client.getAttribute(selector, attribute)); } - public clearElement(selector: string): any { - return this.spectron.client.clearElement(selector); - } - - public buttonDown(): any { + buttonDown(): any { return this.spectron.client.buttonDown(); } - public buttonUp(): any { + buttonUp(): any { return this.spectron.client.buttonUp(); } - public async isVisible(selector: string, capture: boolean = true): Promise { - await this.screenshot(capture); + async isVisible(selector: string, capture: boolean = true): Promise { return this.spectron.client.isVisible(selector); } - public async getTitle(): Promise { + async getTitle(): Promise { return this.spectron.client.getTitle(); } - private async screenshot(capture: boolean = true): Promise { + private running = false; + async waitFor(func: () => T | Promise, accept?: (result: T) => boolean | Promise, timeoutMessage?: string, retryCount?: number): Promise; + async waitFor(func: () => T | Promise, accept: (result: T) => boolean | Promise = result => !!result, timeoutMessage?: string, retryCount?: number): Promise { + if (this.running) { + throw new Error('Not allowed to run nested waitFor calls!'); + } + + this.running = true; + try { - await this.shot.capture(); - } catch (e) { - throw new Error(`Screenshot could not be captured: ${e}`); - } - } + let trial = 1; + retryCount = typeof retryCount === 'number' ? retryCount : this.retryCount; - public async waitFor(func: () => T | Promise, accept?: (result: T) => boolean | Promise, timeoutMessage?: string): Promise; - public async waitFor(func: () => T | Promise, accept: (result: T) => boolean | Promise = result => !!result, timeoutMessage?: string): Promise { - let trial = 1; - - while (true) { - if (trial > this.retryCount) { - throw new Error(`${timeoutMessage}: Timed out after ${this.retryCount * this.retryDuration} seconds.`); - } - - let result; - try { - result = await func(); - } catch (e) { - } - - if (accept(result)) { - return result; - } - - await new Promise(resolve => setTimeout(resolve, this.retryDuration)); - trial++; - } - } - - public type(text: string): Promise { - return new Promise((res) => { - let textSplit = text.split(' '); - - const type = async (i: number) => { - if (!textSplit[i] || textSplit[i].length <= 0) { - return res(); + while (true) { + if (trial > retryCount) { + await this.application.screenCapturer.capture('timeout'); + throw new Error(`${timeoutMessage}: Timed out after ${(retryCount * this.retryDuration) / 1000} seconds.`); } - const toType = textSplit[i + 1] ? `${textSplit[i]} ` : textSplit[i]; - await this.keys(toType, false); - await this.keys(['NULL']); - await type(i + 1); - }; + let result; + try { + result = await func(); + } catch (e) { + // console.log(e); + } - return type(0); - }); + if (accept(result)) { + return result; + } + + await new Promise(resolve => setTimeout(resolve, this.retryDuration)); + trial++; + } + } finally { + this.running = false; + } } + + // type(text: string): Promise { + // return new Promise((res) => { + // let textSplit = text.split(' '); + + // const type = async (i: number) => { + // if (!textSplit[i] || textSplit[i].length <= 0) { + // return res(); + // } + + // const toType = textSplit[i + 1] ? `${textSplit[i]} ` : textSplit[i]; + // await this.keys(toType); + // await this.keys(['NULL']); + // await type(i + 1); + // }; + + // return type(0); + // }); + // } } \ No newline at end of file diff --git a/test/smoke/src/tests/data-migration.ts b/test/smoke/src/tests/data-migration.ts deleted file mode 100644 index 9beae4ca03f..00000000000 --- a/test/smoke/src/tests/data-migration.ts +++ /dev/null @@ -1,105 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; - -import { SpectronApplication, USER_DIR, STABLE_PATH, LATEST_PATH, WORKSPACE_PATH, EXTENSIONS_DIR } from '../spectron/application'; -import { CommonActions } from '../areas/common'; - -let app: SpectronApplication; -let common: CommonActions; - -export function testDataMigration() { - if (!STABLE_PATH) { - return; - } - - describe('Data Migration', () => { - - afterEach(async function () { - await app.stop(); - await common.removeDirectory(USER_DIR); - return await common.removeDirectory(EXTENSIONS_DIR); - }); - - function setupSpectron(context: Mocha.ITestCallbackContext, appPath: string, args?: string[]): void { - if (!args) { - args = []; - } - args.push(`--extensions-dir=${EXTENSIONS_DIR}`); - - app = new SpectronApplication(appPath, context.test.fullTitle(), context.test.currentRetry(), args, [`--user-data-dir=${USER_DIR}`]); - common = new CommonActions(app); - } - - it('checks if the Untitled file is restored migrating from stable to latest', async function () { - const textToType = 'Very dirty file'; - - // Setting up stable version - setupSpectron(this, STABLE_PATH); - await app.start(); - - await common.newUntitledFile(); - await common.type(textToType); - await app.stop(); - - await app.wait(); // wait until all resources are released (e.g. locked local storage) - - // Checking latest version for the restored state - setupSpectron(this, LATEST_PATH); - await app.start(); - - assert.ok(await common.getTab('Untitled-1'), 'Untitled-1 tab was not restored after migration.'); - await common.selectTab('Untitled-1'); - const editorText = await common.getEditorFirstLinePlainText(); - assert.equal(editorText, textToType, 'Typed editor text does not match to the one after migration.'); - }); - - it('checks if the newly created dirty file is restored migrating from stable to latest', async function () { - const fileName = 'test_data/plainFile', - firstTextPart = 'This is going to be an unsaved file', secondTextPart = '_that is dirty.'; - - // Setting up stable version - setupSpectron(this, STABLE_PATH, [fileName]); - await common.removeFile(`${fileName}`); - await app.start(); - - await common.type(firstTextPart); - await common.saveOpenedFile(); - await app.wait(); - await common.type(secondTextPart); - - await app.stop(); - await app.wait(); // wait until all resources are released (e.g. locked local storage) - - // Checking latest version for the restored state - setupSpectron(this, LATEST_PATH); - await app.start(); - assert.ok(await common.getTab(fileName.split('/')[1]), `${fileName} was not restored after migration.`); - await common.selectTab(fileName.split('/')[1]); - const editorText = await common.getEditorFirstLinePlainText(); - assert.equal(editorText, firstTextPart.concat(secondTextPart), 'Entered text was not correctly restored after migration.'); - - // Cleanup - await common.removeFile(`${fileName}`); - }); - - it('cheks if opened tabs are restored migrating from stable to latest', async function () { - const fileName1 = 'app.js', fileName2 = 'jsconfig.json', fileName3 = 'readme.md'; - setupSpectron(this, STABLE_PATH, [WORKSPACE_PATH]); - await app.start(); - await common.openFile(fileName1, true); - await common.openFile(fileName2, true); - await common.openFile(fileName3, true); - await app.stop(); - - setupSpectron(this, LATEST_PATH, [WORKSPACE_PATH]); - await app.start(); - assert.ok(await common.getTab(fileName1), `${fileName1} tab was not restored after migration.`); - assert.ok(await common.getTab(fileName2), `${fileName2} tab was not restored after migration.`); - assert.ok(await common.getTab(fileName3), `${fileName3} tab was not restored after migration.`); - }); - }); -} \ No newline at end of file diff --git a/test/smoke/src/tests/integrated-terminal.ts b/test/smoke/src/tests/integrated-terminal.ts deleted file mode 100644 index c9bd388fb01..00000000000 --- a/test/smoke/src/tests/integrated-terminal.ts +++ /dev/null @@ -1,40 +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 assert from 'assert'; - -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../spectron/application'; -import { CommonActions } from '../areas/common'; -import { IntegratedTerminal } from '../areas/integrated-terminal'; - -let app: SpectronApplication; -let common: CommonActions; - -export function testIntegratedTerminal() { - describe('Integrated Terminal', () => { - let terminal: IntegratedTerminal; - - beforeEach(async function () { - app = new SpectronApplication(LATEST_PATH, this.currentTest.fullTitle(), (this.currentTest as any).currentRetry(), [WORKSPACE_PATH]); - common = new CommonActions(app); - terminal = new IntegratedTerminal(app); - - return await app.start(); - }); - afterEach(async function () { - return await app.stop(); - }); - - it(`opens terminal, runs 'echo' and verifies the output`, async function () { - const command = 'echo test'; - await terminal.openTerminal(common); - await app.wait(); - await common.type(command); - await common.enter(); - await app.wait(); - assert.ok(await terminal.commandOutputHas('test'), 'Terminal output does not contain echo.'); - }); - }); -} \ No newline at end of file diff --git a/test/smoke/src/tests/javascript-debug.ts b/test/smoke/src/tests/javascript-debug.ts deleted file mode 100644 index d0d247d5671..00000000000 --- a/test/smoke/src/tests/javascript-debug.ts +++ /dev/null @@ -1,44 +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 assert from 'assert'; - -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../spectron/application'; -import { CommonActions } from '../areas/common'; -import { JavaScriptDebug } from '../areas/javascript-debug'; - -let app: SpectronApplication; -let common: CommonActions; - -export function testJavaScriptDebug() { - describe('Debugging JavaScript', () => { - let jsDebug: JavaScriptDebug; - - beforeEach(async function () { - app = new SpectronApplication(LATEST_PATH, this.currentTest.fullTitle(), (this.currentTest as any).currentRetry(), [WORKSPACE_PATH]); - common = new CommonActions(app); - jsDebug = new JavaScriptDebug(app); - - return await app.start(); - }); - afterEach(async function () { - return await app.stop(); - }); - - it('autodetects program attribute for launch.json', async function () { - await jsDebug.openDebugViewlet(); - await jsDebug.pressConfigureLaunchJson(); - const value = await jsDebug.getProgramConfigValue(); - process.platform === 'win32' ? assert.equal(value, '${workspaceRoot}\\bin\\www') : assert.equal(value, '${workspaceRoot}/bin/www'); - }); - - it(`can set a breakpoint and verify if it's set`, async function () { - await common.openFirstMatchFile('index.js'); - await jsDebug.setBreakpointOnLine(6); - const breakpoint = await jsDebug.verifyBreakpointOnLine(6); - assert.ok(breakpoint, 'Breakpoint was not found on line 6.'); - }); - }); -} \ No newline at end of file diff --git a/test/smoke/src/tests/javascript.ts b/test/smoke/src/tests/javascript.ts deleted file mode 100644 index 431086e20c8..00000000000 --- a/test/smoke/src/tests/javascript.ts +++ /dev/null @@ -1,87 +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 assert from 'assert'; - -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../spectron/application'; -import { CommonActions } from '../areas/common'; -import { JavaScript } from '../areas/javascript'; - -let app: SpectronApplication; -let common: CommonActions; - -export function testJavaScript() { - describe('JavaScript', () => { - let js: JavaScript; - - beforeEach(async function () { - app = new SpectronApplication(LATEST_PATH, this.currentTest.fullTitle(), (this.currentTest as any).currentRetry(), [WORKSPACE_PATH]); - common = new CommonActions(app); - js = new JavaScript(app); - - return await app.start(); - }); - afterEach(async function () { - return await app.stop(); - }); - - it('shows correct quick outline', async function () { - await common.openFirstMatchFile('bin/www'); - await js.openQuickOutline(); - await app.wait(); - const symbols = await common.getQuickOpenElements(); - assert.equal(symbols, 12, 'Quick outline elements count does not match to expected.'); - }); - - it(`finds 'All References' to 'app'`, async function () { - await common.openFirstMatchFile('bin/www'); - await js.findAppReferences(); - await app.wait(); - const titleCount = await js.getTitleReferencesCount(); - assert.equal(titleCount, 3, 'References count in widget title is not as expected.'); - const treeCount = await js.getTreeReferencesCount(); - assert.equal(treeCount, 3, 'References count in tree is not as expected.'); - }); - - it(`renames local 'app' variable`, async function () { - await common.openFirstMatchFile('bin/www'); - - const newVarName = 'newApp'; - await js.renameApp(newVarName); - await common.enter(); - const newName = await js.getNewAppName(); - assert.equal(newName, newVarName); - }); - - it('folds/unfolds the code correctly', async function () { - await common.openFirstMatchFile('bin/www'); - // Fold - await js.toggleFirstCommentFold(); - const foldedIcon = await js.getFirstCommentFoldedIcon(); - assert.ok(foldedIcon, 'Folded icon was not found in the margin.'); - let nextLineNumber = await js.getNextLineNumberAfterFold(); - assert.equal(nextLineNumber, 7, 'Line number after folded code is wrong.'); - // Unfold - await js.toggleFirstCommentFold(); - nextLineNumber = await js.getNextLineNumberAfterFold(); - assert.equal(nextLineNumber, 4, 'Line number with unfolded code is wrong.'); - }); - - it(`verifies that 'Go To Definition' works`, async function () { - await common.openFirstMatchFile('app.js'); - await js.goToExpressDefinition(); - await app.wait(); - assert.ok(await common.getTab('index.d.ts'), 'Tab opened when navigating to definition is not as expected.'); - }); - - it(`verifies that 'Peek Definition' works`, async function () { - await common.openFirstMatchFile('app.js'); - await js.peekExpressDefinition(); - await app.wait(); - const definitionFilename = await js.getPeekExpressResultName(); - assert.equal(definitionFilename, 'index.d.ts', 'Peek result is not as expected.'); - }); - }); -} \ No newline at end of file diff --git a/test/smoke/src/tests/localization.ts b/test/smoke/src/tests/localization.ts deleted file mode 100644 index bf0951f47d8..00000000000 --- a/test/smoke/src/tests/localization.ts +++ /dev/null @@ -1,50 +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 assert from 'assert'; - -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH, USER_DIR } from '../spectron/application'; -import { CommonActions } from '../areas/common'; -import { Localization, ViewletType } from '../areas/localization'; - -let app: SpectronApplication; -let common: CommonActions; - -export function testLocalization() { - describe('Localization', () => { - afterEach(async function () { - return await app.stop(); - }); - - it(`starts with 'DE' locale and verifies title and viewlets text is in German`, async function () { - app = new SpectronApplication(LATEST_PATH, this.test.fullTitle(), this.test.currentRetry(), [WORKSPACE_PATH, '--locale=DE'], [`--user-data-dir=${USER_DIR}`]); - common = new CommonActions(app); - const locale = new Localization(app); - common.removeDirectory(USER_DIR); - - await app.start(); - - let text = await locale.getOpenEditorsText(); - assert.equal(text.toLowerCase(), 'geƶffnete editoren'); - - await locale.openViewlet(ViewletType.SEARCH); - text = await locale.getOpenedViewletTitle(); - assert.equal(text.toLowerCase(), 'suchen'); - - await locale.openViewlet(ViewletType.SCM); - await app.wait(); // wait until git extension is loaded - text = await locale.getOpenedViewletTitle(); - assert.equal(text.toLowerCase(), 'quellcodeverwaltung: git'); - - await locale.openViewlet(ViewletType.DEBUG); - text = await locale.getOpenedViewletTitle(); - assert.equal(text.toLowerCase(), 'debuggen'); - - await locale.openViewlet(ViewletType.EXTENSIONS); - text = await locale.getExtensionsSearchPlaceholder(); - assert.equal(text.toLowerCase(), 'nach erweiterungen im marketplace suchen'); - }); - }); -} \ No newline at end of file diff --git a/test/smoke/src/tests/tasks.ts b/test/smoke/src/tests/tasks.ts deleted file mode 100644 index f77bce27eb8..00000000000 --- a/test/smoke/src/tests/tasks.ts +++ /dev/null @@ -1,56 +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 assert from 'assert'; - -import { SpectronApplication, LATEST_PATH, WORKSPACE_PATH } from '../spectron/application'; -import { Tasks } from '../areas/tasks'; - -let app: SpectronApplication; - -export function testTasks() { - describe('Tasks', () => { - let tasks: Tasks; - - beforeEach(async function () { - app = new SpectronApplication(LATEST_PATH, this.currentTest.fullTitle(), (this.currentTest as any).currentRetry(), [WORKSPACE_PATH]); - tasks = new Tasks(app); - - return await app.start(); - }); - afterEach(async function () { - return await app.stop(); - }); - - it('verifies that eslint task results in 1 problem', async function () { - const expectedOutput = '1 problem (0 errors, 1 warning)'; - await tasks.build(); - const actualOutput = await tasks.outputContains(expectedOutput); - assert.ok(actualOutput, `Output does not contain the following string: '${expectedOutput}'`); - }); - - it(`is able to select 'Git' output`, async function () { - await tasks.build(); - await app.wait(); - await tasks.selectOutputViewType('Git'); - const viewType = await tasks.getOutputViewType(); - assert.equal(viewType, 'Git'); - }); - - it('ensures that build task produces no-unused-vars message', async function () { - await tasks.build(); - assert.ok(await tasks.outputContains(`'next' is defined but never used`), `Output does not contain no-unused-vars message`); - }); - - it(`verifies build error is reflected in 'Problems View'`, async function () { - await tasks.build(); - await tasks.openProblemsView(); - const problemName = await tasks.getProblemsViewFirstElementName(); - assert.equal(problemName, 'index.js', `'index.js' is not a build error.`); - const problemsCount = await tasks.getProblemsViewFirstElementCount(); - assert.equal(problemsCount, '1', `Problem count is different to expected.`); - }); - }); -} \ No newline at end of file diff --git a/test/smoke/test/mocha.opts b/test/smoke/test/mocha.opts index f7385dc1642..102d5b65ade 100644 --- a/test/smoke/test/mocha.opts +++ b/test/smoke/test/mocha.opts @@ -1,3 +1,3 @@ --timeout 60000 ---slow 10000 +--slow 20000 out/main.js \ No newline at end of file diff --git a/tslint.json b/tslint.json index 6bcc49e7bd9..e5f6005ed78 100644 --- a/tslint.json +++ b/tslint.json @@ -6,10 +6,11 @@ "no-string-throw": true, "no-unused-expression": true, "no-duplicate-variable": true, - "no-unused-variable": true, + // "no-unused-variable": true, // requires type information in tslint > v4 "curly": true, "class-name": true, "semicolon": [ + true, "always" ], "triple-equals": true, @@ -348,15 +349,52 @@ ] }, { - "target": "**/vs/workbench/services/**", + "target": "**/vs/workbench/services/**/common/**", "restrictions": [ "vs/nls", "vs/css!./**/*", - "**/vs/base/**", - "**/vs/platform/**", - "**/vs/editor/**", + "**/vs/base/**/common/**", + "**/vs/platform/**/common/**", + "**/vs/editor/common/**", + "**/vs/workbench/common/**", + "**/vs/workbench/services/**/common/**" + ] + }, + { + "target": "**/vs/workbench/services/**/browser/**", + "restrictions": [ + "vs/nls", + "vs/css!./**/*", + "**/vs/base/**/{common,browser}/**", + "**/vs/platform/**/{common,browser}/**", + "**/vs/editor/{common,browser}/**", + "**/vs/workbench/{common,browser}/**", + "**/vs/workbench/services/**/{common,browser}/**" + ] + }, + { + "target": "**/vs/workbench/services/**/node/**", + "restrictions": [ + "vs/nls", + "vs/css!./**/*", + "**/vs/base/**/{common,node}/**", + "**/vs/platform/**/{common,node}/**", + "**/vs/editor/{common,node}/**", + "**/vs/workbench/{common,node}/**", + "**/vs/workbench/services/**/{common,node}/**", + "*" // node modules + ] + }, + { + "target": "**/vs/workbench/services/**/electron-browser/**", + "restrictions": [ + "vs/nls", + "vs/css!./**/*", + "**/vs/base/**/{common,browser,node,electron-browser}/**", + "**/vs/platform/**/{common,browser,node,electron-browser}/**", + "**/vs/editor/**/{common,browser,node,electron-browser}/**", "**/vs/workbench/{common,browser,node,electron-browser,api}/**", - "**/vs/workbench/services/**", + "**/vs/workbench/services/**/{common,browser,node,electron-browser}/**", "*" // node modules ] }, @@ -391,16 +429,7 @@ } ], "duplicate-imports": true, - "allow-async": [ - true, - [ - "node", - "electron-main", - "electron-browser", - "extensions", - "smoke" - ] - ], "translation-remind": true - } + }, + "defaultSeverity": "warning" } \ No newline at end of file